Release 961102
[wine] / controls / combo.c
1 /*
2  * Combo controls
3  * 
4  * Copyright 1993 Martin Ayotte
5  * Copyright 1995 Bernd Schmidt
6  * Copyright 1996 Albrecht Kleine  [some fixes]
7  * 
8  */
9
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/types.h>
14 #include <sys/stat.h>
15
16 #include "windows.h"
17 #include "sysmetrics.h"
18 #include "win.h"
19 #include "combo.h"
20 #include "user.h"
21 #include "graphics.h"
22 #include "heap.h"
23 #include "listbox.h"
24 #include "dos_fs.h"
25 #include "drive.h"
26 #include "stddebug.h"
27 #include "debug.h"
28 #include "xmalloc.h"
29
30  /*
31   * Note: Combos are probably implemented in a different way by Windows.
32   * Using a message spy for Windows, you can see some undocumented
33   * messages being passed between ComboBox and ComboLBox.
34   * I hope no programs rely on the implementation of combos.
35   */
36
37 #define ID_EDIT  1
38 #define ID_CLB   2
39 #define CBLMM_EDGE   4    /* distance inside box which is same as moving mouse
40                              outside box, to trigger scrolling of CBL */
41
42 static BOOL CBCheckSize(HWND hwnd);
43 static BOOL CBLCheckSize(HWND hwnd);
44
45 static HBITMAP16 hComboBit = 0;
46 static WORD CBitHeight, CBitWidth;
47
48 static int COMBO_Init()
49 {
50   BITMAP16 bm;
51   
52   dprintf_combo(stddeb, "COMBO_Init\n");
53   hComboBit = LoadBitmap16(0, MAKEINTRESOURCE(OBM_COMBO));
54   GetObject16( hComboBit, sizeof(bm), &bm );
55   CBitHeight = bm.bmHeight;
56   CBitWidth = bm.bmWidth;
57   return 0;
58 }
59
60 LPHEADCOMBO ComboGetStorageHeader(HWND hwnd)
61 {
62   return (LPHEADCOMBO)GetWindowLong32A(hwnd,4);
63 }
64
65 LPHEADLIST ComboGetListHeader(HWND hwnd)
66 {
67   return (LPHEADLIST)GetWindowLong32A(hwnd,0);
68 }
69
70 int CreateComboStruct(HWND hwnd, LONG style)
71 {
72   LPHEADCOMBO lphc;
73
74   lphc = (LPHEADCOMBO)xmalloc(sizeof(HEADCOMBO));
75   SetWindowLong32A(hwnd,4,(LONG)lphc);
76   lphc->hWndEdit = 0;
77   lphc->hWndLBox = 0;
78   lphc->dwState = 0;
79   lphc->LastSel = -1;
80   lphc->dwStyle = style; 
81   lphc->DropDownVisible = FALSE;
82   return TRUE;
83 }
84
85 void ComboUpdateWindow(HWND hwnd, LPHEADLIST lphl, LPHEADCOMBO lphc, BOOL repaint)
86 {
87   WND *wndPtr = WIN_FindWndPtr(hwnd);
88
89   if (wndPtr->dwStyle & WS_VSCROLL) 
90     SetScrollRange32(lphc->hWndLBox,SB_VERT,0,ListMaxFirstVisible(lphl),TRUE);
91   if (repaint && lphl->bRedrawFlag) InvalidateRect32( hwnd, NULL, TRUE );
92 }
93
94 /***********************************************************************
95  *           CBNCCreate
96  */
97 static LRESULT CBNCCreate(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
98 {
99   CREATESTRUCT16 *createStruct;
100
101   if (!hComboBit) COMBO_Init();
102
103   createStruct = (CREATESTRUCT16 *)PTR_SEG_TO_LIN(lParam);
104   createStruct->style |= WS_BORDER;
105   SetWindowLong32A(hwnd, GWL_STYLE, createStruct->style);
106
107   dprintf_combo(stddeb,"ComboBox WM_NCCREATE!\n");
108   return DefWindowProc16(hwnd, WM_NCCREATE, wParam, lParam);
109
110 }
111
112 /***********************************************************************
113  *           CBCreate
114  */
115 static LRESULT CBCreate(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
116 {
117   LPHEADLIST   lphl;
118   LPHEADCOMBO  lphc;
119   LONG         style = 0;
120   LONG         cstyle = GetWindowLong32A(hwnd,GWL_STYLE);
121   RECT16       rect,lboxrect;
122   WND*         wndPtr = WIN_FindWndPtr(hwnd);
123   char className[] = "COMBOLBOX";  /* Hack so that class names are > 0x10000 */
124   char editName[] = "EDIT";
125   HWND hwndp=0;
126
127   /* translate combo into listbox styles */
128   cstyle |= WS_BORDER;
129   if (cstyle & CBS_OWNERDRAWFIXED) style |= LBS_OWNERDRAWFIXED;
130   if (cstyle & CBS_OWNERDRAWVARIABLE) style |= LBS_OWNERDRAWVARIABLE;
131   if (cstyle & CBS_SORT) style |= LBS_SORT;
132   if (cstyle & CBS_HASSTRINGS) style |= LBS_HASSTRINGS;
133   style |= LBS_NOTIFY;
134   CreateListBoxStruct(hwnd, ODT_COMBOBOX, style, GetParent16(hwnd));
135   CreateComboStruct(hwnd,cstyle);
136
137   lphl = ComboGetListHeader(hwnd);
138   lphc = ComboGetStorageHeader(hwnd);
139
140   GetClientRect16(hwnd,&rect);
141   lphc->LBoxTop = lphl->StdItemHeight;
142
143   switch(cstyle & 3) 
144   {
145    case CBS_SIMPLE:            /* edit control, list always visible  */
146      lboxrect=rect;    
147      dprintf_combo(stddeb,"CBS_SIMPLE\n");
148      style= WS_BORDER |  WS_CHILD | WS_VISIBLE | WS_VSCROLL;
149      SetRectEmpty16(&lphc->RectButton);
150      hwndp=hwnd;
151      break;
152
153    case CBS_DROPDOWNLIST:      /* static control, dropdown listbox   */
154    case CBS_DROPDOWN:          /* edit control, dropdown listbox     */
155      GetWindowRect16(hwnd,&lboxrect);
156      style = WS_POPUP | WS_BORDER | WS_VSCROLL;
157      /* FIXME: WinSight says these should be CHILD windows with the TOPMOST flag
158       * set. Wine doesn't support TOPMOST, and simply setting the WS_CHILD
159       * flag doesn't work. */
160      lphc->RectButton = rect;
161      lphc->RectButton.left = lphc->RectButton.right - 6 - CBitWidth;
162      lphc->RectButton.bottom = lphc->RectButton.top + lphl->StdItemHeight;
163      SetWindowPos(hwnd, 0, 0, 0, rect.right -rect.left + 2*SYSMETRICS_CXBORDER,
164                  lphl->StdItemHeight + 2*SYSMETRICS_CYBORDER,
165                  SWP_NOMOVE | SWP_NOZORDER | SWP_NOSENDCHANGING | SWP_NOACTIVATE);
166      dprintf_combo(stddeb,(cstyle & 3)==CBS_DROPDOWN ? "CBS_DROPDOWN\n": "CBS_DROPDOWNLIST\n");
167      break;
168      
169    default: fprintf(stderr,"COMBOBOX error: bad class style!\n");
170      return 0;
171   }
172
173   if ((cstyle & 3) != CBS_DROPDOWNLIST)
174       lphc->hWndEdit = CreateWindow16( editName, NULL,
175                                   WS_CHILD | WS_CLIPCHILDREN | WS_VISIBLE | ES_LEFT,
176                                   0, 0, rect.right-6-CBitWidth,
177                                   lphl->StdItemHeight+2*SYSMETRICS_CYBORDER,
178                                   hwnd, (HMENU16)ID_EDIT, WIN_GetWindowInstance(hwnd), NULL );
179                                   
180   lboxrect.top+=lphc->LBoxTop;
181   lphc->hWndLBox = CreateWindow16( className, NULL, style |
182                                 ((cstyle & WS_HSCROLL)? WS_HSCROLL : 0) |
183                                 ((cstyle & WS_VSCROLL)? WS_VSCROLL : 0),
184                                 lboxrect.left, lboxrect.top,
185                                 lboxrect.right - lboxrect.left, 
186                                 lboxrect.bottom - lboxrect.top,
187                                 hwndp,(HMENU16)ID_CLB, WIN_GetWindowInstance(hwnd),
188                                 (LPVOID)(HWND32)hwnd );
189
190    wndPtr->dwStyle &= ~(WS_VSCROLL | WS_HSCROLL);
191
192    dprintf_combo( stddeb, "Combo Creation hwnd=%04x  LBox=%04x  Edit=%04x\n",
193                   hwnd, lphc->hWndLBox, lphc->hWndEdit);
194    dprintf_combo( stddeb, "  lbox %d,%d-%d,%d     button %d,%d-%d,%d\n",
195                   lboxrect.left, lboxrect.top, lboxrect.right, lboxrect.bottom,
196                   lphc->RectButton.left, lphc->RectButton.top,
197                   lphc->RectButton.right, lphc->RectButton.bottom );
198    dprintf_combo( stddeb, "   client %d,%d-%d,%d     window %d,%d-%d,%d\n",
199                   wndPtr->rectClient.left, wndPtr->rectClient.top,
200                   wndPtr->rectClient.right, wndPtr->rectClient.bottom,
201                   wndPtr->rectWindow.left, wndPtr->rectWindow.top,
202                   wndPtr->rectWindow.right, wndPtr->rectWindow.bottom );
203    return 0;
204 }
205
206 /***********************************************************************
207  *           CBDestroy
208  */
209 static LRESULT CBDestroy(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
210 {
211   LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
212
213   if (lphc->hWndEdit) DestroyWindow( lphc->hWndEdit );
214   if (lphc->hWndLBox) DestroyWindow( lphc->hWndLBox );
215   return 0;
216 }
217
218 /***********************************************************************
219  *           CBPaint
220  */
221 static LRESULT CBPaint(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
222 {
223   LPHEADLIST lphl = ComboGetListHeader(hwnd);
224   LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
225   LPLISTSTRUCT lpls;
226   PAINTSTRUCT16  ps;
227   HBRUSH32 hBrush;
228   HFONT32 hOldFont;
229   HDC16 hdc;
230   RECT16 rect;
231   
232   hdc = BeginPaint16(hwnd, &ps);
233
234   GetClientRect16(hwnd, &rect);
235   CBCheckSize(hwnd);
236   /* 1 for button border */
237   rect.right = lphc->RectButton.left - 1;
238
239   if (hComboBit != 0 && !IsRectEmpty16(&lphc->RectButton))
240   {
241     Rectangle32(hdc,lphc->RectButton.left-1,lphc->RectButton.top-1,
242                 lphc->RectButton.right+1,lphc->RectButton.bottom+1);
243     {
244         RECT32 r;
245         CONV_RECT16TO32( &lphc->RectButton, &r );
246         GRAPH_DrawReliefRect(hdc, &r, 2, 2, FALSE);
247     }
248     GRAPH_DrawBitmap(hdc, hComboBit,
249                      lphc->RectButton.left + 2,lphc->RectButton.top + 2,
250                      0, 0, CBitWidth, CBitHeight );
251   }
252   if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag 
253       || (lphc->dwStyle & 3) != CBS_DROPDOWNLIST) 
254   {
255     /* we don't want to draw an entry when there is an edit control */
256     EndPaint16(hwnd, &ps);
257     return 0;
258   }
259
260   hOldFont = SelectObject32(hdc, lphl->hFont);
261
262   hBrush = SendMessage32A( lphl->hParent, WM_CTLCOLORLISTBOX, hdc, hwnd );
263   if (hBrush == 0) hBrush = GetStockObject32(WHITE_BRUSH);
264
265   lpls = ListBoxGetItem(lphl,lphl->ItemFocused);
266   if (lpls != NULL) {  
267     FillRect16(hdc, &rect, hBrush);
268     ListBoxDrawItem (hwnd, lphl, hdc, lpls, &rect, ODA_DRAWENTIRE, 0);
269     if (GetFocus32() == hwnd)
270     ListBoxDrawItem (hwnd,lphl, hdc, lpls, &rect, ODA_FOCUS, ODS_FOCUS);
271   }
272   else FillRect16(hdc, &rect, hBrush);
273   SelectObject32(hdc,hOldFont);
274   EndPaint16(hwnd, &ps);
275   return 0;
276 }
277
278 /***********************************************************************
279  *           CBGetDlgCode
280  */
281 static LRESULT CBGetDlgCode(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
282 {
283   return DLGC_WANTARROWS | DLGC_WANTCHARS;
284 }
285
286 /***********************************************************************
287  *           CBLButtonDown
288  */
289 static LRESULT CBLButtonDown(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
290 {
291   LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
292   SendMessage16(hwnd,CB_SHOWDROPDOWN,!lphc->DropDownVisible,0);
293   return 0;
294 }
295
296 /***********************************************************************
297  *           CBKeyDown
298  */
299 static LRESULT CBKeyDown(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
300 {
301   LPHEADLIST lphl = ComboGetListHeader(hwnd);
302   WORD       newFocused = lphl->ItemFocused;
303
304   switch(wParam) {
305   case VK_HOME:
306     newFocused = 0;
307     break;
308   case VK_END:
309     newFocused = lphl->ItemsCount - 1;
310     break;
311   case VK_UP:
312     if (newFocused > 0) newFocused--;
313     break;
314   case VK_DOWN:
315     newFocused++;
316     break;
317   default:
318     return 0;
319   }
320
321   if (newFocused >= lphl->ItemsCount)
322     newFocused = lphl->ItemsCount - 1;
323   
324   ListBoxSetCurSel(lphl, newFocused);
325   SendMessage16(hwnd, WM_COMMAND,ID_CLB,MAKELONG(0,CBN_SELCHANGE));
326   ListBoxSendNotification(lphl, CBN_SELCHANGE);
327
328   lphl->ItemFocused = newFocused;
329   ListBoxScrollToFocus(lphl);
330 /*  SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
331   InvalidateRect32( hwnd, NULL, TRUE );
332
333   return 0;
334 }
335
336 /***********************************************************************
337  *           CBChar
338  */
339 static LRESULT CBChar(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
340 {
341   LPHEADLIST lphl = ComboGetListHeader(hwnd);
342   WORD       newFocused;
343
344   newFocused = ListBoxFindNextMatch(lphl, wParam);
345   if (newFocused == (WORD)LB_ERR) return 0;
346
347   if (newFocused >= lphl->ItemsCount)
348     newFocused = lphl->ItemsCount - 1;
349   
350   ListBoxSetCurSel(lphl, newFocused);
351   SendMessage16(hwnd, WM_COMMAND,ID_CLB,MAKELONG(0,CBN_SELCHANGE));
352   ListBoxSendNotification(lphl, CBN_SELCHANGE);
353   lphl->ItemFocused = newFocused;
354   ListBoxScrollToFocus(lphl);
355   
356 /*  SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
357   InvalidateRect32( hwnd, NULL, TRUE );
358
359   return 0;
360 }
361
362 /***********************************************************************
363  *           CBKillFocus
364  */
365 static LRESULT CBKillFocus(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
366 {
367   return 0;
368 }
369
370 /***********************************************************************
371  *           CBSetFocus
372  */
373 static LRESULT CBSetFocus(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
374 {
375   return 0;
376 }
377
378 /***********************************************************************
379  *           CBResetContent
380  */
381 static LRESULT CBResetContent(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
382 {
383   LPHEADLIST lphl = ComboGetListHeader(hwnd);
384   LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
385
386   ListBoxResetContent(lphl);
387   ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
388   return 0;
389 }
390
391 /***********************************************************************
392  *           CBDir
393  */
394 static LRESULT CBDir(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
395 {
396   WORD wRet;
397   LPHEADLIST lphl = ComboGetListHeader(hwnd);
398   LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
399
400   wRet = ListBoxDirectory(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
401   ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
402   return wRet;
403 }
404
405 /***********************************************************************
406  *           CBInsertString
407  */
408 static LRESULT CBInsertString(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
409 {
410   WORD  wRet;
411   LPHEADLIST lphl = ComboGetListHeader(hwnd);
412   LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
413
414   if (lphl->HasStrings)
415     wRet = ListBoxInsertString(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
416   else
417     wRet = ListBoxInsertString(lphl, wParam, (LPSTR)lParam);
418   ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
419   return wRet;
420 }
421
422 /***********************************************************************
423  *           CBAddString
424  */
425 static LRESULT CBAddString(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
426 {
427   WORD  wRet;
428   LPHEADLIST lphl = ComboGetListHeader(hwnd);
429   LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
430
431   wRet = ListBoxAddString(lphl, (SEGPTR)lParam);
432
433   ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
434   return wRet;
435 }
436
437 /***********************************************************************
438  *           CBDeleteString
439  */
440 static LRESULT CBDeleteString(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
441 {
442   LPHEADLIST lphl = ComboGetListHeader(hwnd);
443   LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
444   LONG lRet = ListBoxDeleteString(lphl,wParam);
445   
446   ComboUpdateWindow(hwnd, lphl, lphc, TRUE);
447   return lRet;
448 }
449
450 /***********************************************************************
451  *           CBSelectString
452  */
453 static LRESULT CBSelectString(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
454 {
455   LPHEADLIST lphl = ComboGetListHeader(hwnd);
456   WORD  wRet;
457
458   wRet = ListBoxFindString(lphl, wParam, (SEGPTR)lParam);
459
460   /* XXX add functionality here */
461
462   return 0;
463 }
464
465 /***********************************************************************
466  *           CBFindString
467  */
468 static LRESULT CBFindString(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
469 {
470   LPHEADLIST lphl = ComboGetListHeader(hwnd);
471   return ListBoxFindString(lphl, wParam, (SEGPTR)lParam);
472 }
473
474 /***********************************************************************
475  *           CBFindStringExact
476  */
477 static LRESULT CBFindStringExact(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
478 {
479   LPHEADLIST lphl = ComboGetListHeader(hwnd);
480   return ListBoxFindStringExact(lphl, wParam, (SEGPTR)lParam);
481 }
482
483 /***********************************************************************
484  *           CBGetCount
485  */
486 static LRESULT CBGetCount(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
487 {
488   LPHEADLIST lphl = ComboGetListHeader(hwnd);
489   return lphl->ItemsCount;
490 }
491
492 /***********************************************************************
493  *           CBSetCurSel
494  */
495 static LRESULT CBSetCurSel(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
496 {
497   LPHEADLIST lphl = ComboGetListHeader(hwnd);
498   WORD  wRet;
499
500   wRet = ListBoxSetCurSel(lphl, wParam);
501
502   dprintf_combo(stddeb,"CBSetCurSel: hwnd %04x wp %x lp %lx wRet %d\n",
503                 hwnd,wParam,lParam,wRet);
504 /*  SetScrollPos(hwnd, SB_VERT, lphl->FirstVisible, TRUE);*/
505   InvalidateRect32( hwnd, NULL, TRUE );
506
507   return wRet;
508 }
509
510 /***********************************************************************
511  *           CBGetCurSel
512  */
513 static LRESULT CBGetCurSel(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
514 {
515   LPHEADLIST lphl = ComboGetListHeader(hwnd);
516   return lphl->ItemFocused;
517 }
518
519 /***********************************************************************
520  *           CBGetItemHeight
521  */
522 static LRESULT CBGetItemHeight(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
523 {
524   LPHEADLIST lphl = ComboGetListHeader(hwnd);
525   LPLISTSTRUCT lpls = ListBoxGetItem (lphl, wParam);
526
527   if (lpls == NULL) return LB_ERR;
528   return lpls->mis.itemHeight;
529 }
530
531 /***********************************************************************
532  *           CBSetItemHeight
533  */
534 static LRESULT CBSetItemHeight(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
535 {
536   LPHEADLIST lphl = ComboGetListHeader(hwnd);
537   return ListBoxSetItemHeight(lphl, wParam, lParam);
538 }
539
540 /***********************************************************************
541  *           CBSetRedraw
542  */
543 static LRESULT CBSetRedraw(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
544 {
545   LPHEADLIST lphl = ComboGetListHeader(hwnd);
546   lphl->bRedrawFlag = wParam;
547   return 0;
548 }
549
550 /***********************************************************************
551  *           CBSetFont
552  */
553 static LRESULT CBSetFont(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
554 {
555   LPHEADLIST  lphl = ComboGetListHeader(hwnd);
556   LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
557   
558   if (wParam == 0)
559     lphl->hFont = GetStockObject32(SYSTEM_FONT);
560   else
561     lphl->hFont = (HFONT16)wParam;
562   if (lphc->hWndEdit)
563      SendMessage16(lphc->hWndEdit,WM_SETFONT,lphl->hFont,0); 
564   return 0;
565 }
566
567 /***********************************************************************
568  *           CBGetLBTextLen
569  */
570 static LRESULT CBGetLBTextLen(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
571 {
572   LPHEADLIST   lphl = ComboGetListHeader(hwnd);
573   LPLISTSTRUCT lpls = ListBoxGetItem(lphl,wParam);
574
575   if (lpls == NULL || !lphl->HasStrings) return LB_ERR;
576   return strlen(lpls->itemText);
577 }
578
579 /***********************************************************************
580  *           CBGetLBText
581  */
582 static LRESULT CBGetLBText(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
583 {
584   LPHEADLIST lphl = ComboGetListHeader(hwnd);
585   return ListBoxGetText(lphl, wParam, (LPSTR)PTR_SEG_TO_LIN(lParam));
586 }
587
588 /***********************************************************************
589  *           CBGetItemData
590  */
591 static LRESULT CBGetItemData(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
592 {
593   LPHEADLIST lphl = ComboGetListHeader(hwnd);
594   return ListBoxGetItemData(lphl, wParam);
595 }
596
597 /***********************************************************************
598  *           CBSetItemData
599  */
600 static LRESULT CBSetItemData(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
601 {
602   LPHEADLIST lphl = ComboGetListHeader(hwnd);
603   return ListBoxSetItemData(lphl, wParam, lParam);
604 }
605
606 /***********************************************************************
607  *           CBShowDropDown
608  */
609 static LRESULT CBShowDropDown(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
610 {
611   LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
612   RECT32 rect;
613   
614   if ((lphc->dwStyle & 3) == CBS_SIMPLE) return LB_ERR;
615   
616   wParam = !!wParam;
617   if (wParam != lphc->DropDownVisible) {
618     lphc->DropDownVisible = wParam;
619     GetWindowRect32(hwnd,&rect);
620     SetWindowPos(lphc->hWndLBox, 0, rect.left, rect.top+lphc->LBoxTop, 0, 0,
621                  SWP_NOSIZE | SWP_NOACTIVATE |
622                  (wParam ? SWP_SHOWWINDOW : SWP_HIDEWINDOW));
623     if (!wParam) SetFocus32(hwnd);
624   }
625   return 0;
626 }
627
628
629 /***********************************************************************
630  *             CBCheckSize
631  */
632 static BOOL CBCheckSize(HWND hwnd)
633 {
634   LPHEADCOMBO  lphc = ComboGetStorageHeader(hwnd);
635   LPHEADLIST   lphl = ComboGetListHeader(hwnd);
636   LONG         cstyle = GetWindowLong32A(hwnd,GWL_STYLE);
637   RECT16       cRect, wRect;
638
639   if (lphc->hWndLBox == 0) return FALSE;
640
641   GetClientRect16(hwnd,&cRect);
642   GetWindowRect16(hwnd,&wRect);
643
644   dprintf_combo(stddeb,
645          "CBCheckSize: hwnd %04x Rect %d,%d-%d,%d  wRect %d,%d-%d,%d\n", 
646                 hwnd,cRect.left,cRect.top,cRect.right,cRect.bottom,
647                 wRect.left,wRect.top,wRect.right,wRect.bottom);
648   if ((cstyle & 3) == CBS_SIMPLE) return TRUE;
649
650   if ((cRect.bottom - cRect.top) >
651       (lphl->StdItemHeight + 2*SYSMETRICS_CYBORDER)) {
652     SetWindowPos(hwnd, 0, 0, 0, 
653                  cRect.right-cRect.left,
654                  lphl->StdItemHeight+2*SYSMETRICS_CYBORDER, 
655                  SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE );
656     GetClientRect16(hwnd,&cRect);
657     GetWindowRect16(hwnd,&wRect);
658
659     lphc->RectButton.right = cRect.right;
660     lphc->RectButton.left = cRect.right - 2*SYSMETRICS_CXBORDER - 4 
661                             - CBitWidth;
662     lphc->RectButton.top = cRect.top;
663     lphc->RectButton.bottom = cRect.bottom;
664   }
665
666   if (cRect.right < lphc->RectButton.left) {
667     /* if the button is outside the window move it in */
668     if ((wRect.right - wRect.left - 2*SYSMETRICS_CXBORDER) == (cRect.right - cRect.left)) {
669       lphc->RectButton.right = cRect.right;
670       lphc->RectButton.left = cRect.right - 2*SYSMETRICS_CXBORDER - 4 
671                                - CBitWidth;
672       lphc->RectButton.top = cRect.top;
673       lphc->RectButton.bottom = cRect.bottom;
674     }
675     /* otherwise we need to make the client include the button */
676     else
677       SetWindowPos(hwnd, 0, 0, 0, lphc->RectButton.right,
678                    lphl->StdItemHeight+2*SYSMETRICS_CYBORDER,
679                    SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE);
680
681       if ((lphc->dwStyle & 3) != CBS_DROPDOWNLIST)
682         SetWindowPos(lphc->hWndEdit, 0, 0, 0, lphc->RectButton.left,
683                      lphl->StdItemHeight,
684                      SWP_NOACTIVATE | SWP_NOMOVE | SWP_NOZORDER );
685   }
686
687   CBLCheckSize(hwnd);
688   return TRUE;
689 }
690
691 /***********************************************************************
692  *           CBCommand        
693  */
694 static LRESULT CBCommand(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
695 {
696   LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
697   LPHEADLIST lphl = ComboGetListHeader(hwnd);
698   char       buffer[256];
699   WORD       newFocused;
700   WORD       id;
701   if (lphc->hWndEdit)  /* interdependence only used for CBS_SIMPLE and CBS_DROPDOWN styles */
702   {
703    switch (wParam)
704    {
705     case ID_CLB:                                        /* update EDIT window */
706                 if (HIWORD(lParam)==CBN_SELCHANGE)
707                  if (lphl->HasStrings)
708                  { 
709                   ListBoxGetText(lphl,lphl->ItemFocused, buffer);
710                   dprintf_combo(stddeb,"CBCommand: update Edit: %s\n",buffer);
711                   SetWindowText32A( lphc->hWndEdit, buffer );
712                  }
713                 break;
714     case ID_EDIT:                                      /* update LISTBOX window */
715                  id=GetWindowWord(hwnd,GWW_ID);
716                  switch (HIWORD(lParam))
717                  {
718                   case EN_UPDATE:GetWindowText32A(lphc->hWndEdit,buffer,255);
719                                  if (*buffer)
720                                  {
721                                   char *str = SEGPTR_STRDUP(buffer);
722                                   newFocused=ListBoxFindString(lphl, -1, SEGPTR_GET(str));
723                                   SEGPTR_FREE(str);
724                                   dprintf_combo(stddeb,"CBCommand: new selection #%d is= %s\n",
725                                                 newFocused,buffer);
726                                   if (newFocused != (WORD)LB_ERR)
727                                   {                             /* if found something */
728                                    ListBoxSetCurSel(lphl, newFocused);
729                                    ListBoxSendNotification(lphl, CBN_SELCHANGE);
730                                    InvalidateRect32(hwnd, NULL, TRUE); 
731                                   }
732                                  }
733                                  SendMessage16(GetParent16(hwnd),WM_COMMAND,id,
734                                          MAKELONG(hwnd, CBN_EDITUPDATE));
735                                  break;
736                   case EN_CHANGE:SendMessage16(GetParent16(hwnd),WM_COMMAND,id,
737                                          MAKELONG(hwnd, CBN_EDITCHANGE));
738                                  break;
739                   case EN_ERRSPACE:SendMessage16(GetParent16(hwnd),WM_COMMAND,id,
740                                          MAKELONG(hwnd, CBN_ERRSPACE));
741                                  break;
742                 }
743                 break;        
744    }
745   } 
746   return 0;
747 }
748
749
750 /***********************************************************************
751  *           CBGetEditSel
752  * Look out! Under Win32, the parameter packing is very different.
753  */
754 static LRESULT CBGetEditSel(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
755 {
756     LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
757
758     if ((lphc->dwStyle & 3) == CBS_DROPDOWNLIST)
759       return CB_ERR;    /* err, documented for CBSetEditSel */
760     return SendMessage16(lphc->hWndEdit, EM_GETSEL, 0, 0);
761 }
762
763
764 /***********************************************************************
765  *           CBSetEditSel
766  * Look out! Under Win32, the parameter packing is very different.
767  */
768 static LRESULT CBSetEditSel(HWND hwnd, WPARAM16 wParam, LPARAM lParam)
769 {
770     LPHEADCOMBO lphc = ComboGetStorageHeader(hwnd);
771
772     if ((lphc->dwStyle & 3) == CBS_DROPDOWNLIST)
773       return CB_ERR;
774     return SendMessage16(lphc->hWndEdit, EM_SETSEL, 0, lParam);
775 }
776
777
778 /***********************************************************************
779  *           ComboWndProc
780  */
781 LRESULT ComboBoxWndProc(HWND hwnd, UINT message, WPARAM16 wParam, LPARAM lParam)
782 {
783     switch(message) {   
784      case WM_NCCREATE: return CBNCCreate(hwnd, wParam, lParam);
785      case WM_CREATE: return CBCreate(hwnd, wParam, lParam);
786      case WM_DESTROY: return CBDestroy(hwnd, wParam, lParam);
787      case WM_GETDLGCODE: return CBGetDlgCode(hwnd, wParam, lParam);
788      case WM_KEYDOWN: return CBKeyDown(hwnd, wParam, lParam);
789      case WM_CHAR: return CBChar(hwnd, wParam, lParam);
790      case WM_SETFONT: return CBSetFont(hwnd, wParam, lParam);
791      case WM_SETREDRAW: return CBSetRedraw(hwnd, wParam, lParam);
792      case WM_PAINT: return CBPaint(hwnd, wParam, lParam);
793      case WM_LBUTTONDOWN: return CBLButtonDown(hwnd, wParam, lParam);
794      case WM_SETFOCUS: return CBSetFocus(hwnd, wParam, lParam);
795      case WM_KILLFOCUS: return CBKillFocus(hwnd, wParam, lParam);
796      case WM_SIZE: return CBCheckSize(hwnd);
797      case WM_COMMAND: return CBCommand(hwnd, wParam, lParam);
798      case CB_RESETCONTENT: return CBResetContent(hwnd, wParam, lParam);
799      case CB_DIR: return CBDir(hwnd, wParam, lParam);
800      case CB_ADDSTRING: return CBAddString(hwnd, wParam, lParam);
801      case CB_INSERTSTRING: return CBInsertString(hwnd, wParam, lParam);
802      case CB_DELETESTRING: return CBDeleteString(hwnd, wParam, lParam);
803      case CB_FINDSTRING: return CBFindString(hwnd, wParam, lParam);
804      case CB_GETCOUNT: return CBGetCount(hwnd, wParam, lParam);
805      case CB_GETCURSEL: return CBGetCurSel(hwnd, wParam, lParam);
806      case CB_GETITEMDATA: return CBGetItemData(hwnd, wParam, lParam);
807      case CB_GETITEMHEIGHT: return CBGetItemHeight(hwnd, wParam, lParam);
808      case CB_GETLBTEXT: return CBGetLBText(hwnd, wParam, lParam);
809      case CB_GETLBTEXTLEN: return CBGetLBTextLen(hwnd, wParam, lParam);
810      case CB_SELECTSTRING: return CBSelectString(hwnd, wParam, lParam);
811      case CB_SETITEMDATA: return CBSetItemData(hwnd, wParam, lParam);
812      case CB_SETCURSEL: return CBSetCurSel(hwnd, wParam, lParam);
813      case CB_SETITEMHEIGHT: return CBSetItemHeight(hwnd, wParam, lParam);
814      case CB_SHOWDROPDOWN: return CBShowDropDown(hwnd, wParam, lParam);
815      case CB_GETEDITSEL: return CBGetEditSel(hwnd, wParam, lParam);
816      case CB_SETEDITSEL: return CBSetEditSel(hwnd, wParam, lParam);
817      case CB_FINDSTRINGEXACT: return CBFindStringExact(hwnd, wParam, lParam);
818     }
819     return DefWindowProc16(hwnd, message, wParam, lParam);
820 }
821
822 /*--------------------------------------------------------------------*/
823 /* ComboLBox code starts here */
824
825 HWND CLBoxGetCombo(HWND hwnd)
826 {
827   return (HWND)GetWindowLong32A(hwnd,0);
828 }
829
830 LPHEADLIST CLBoxGetListHeader(HWND hwnd)
831 {
832   return ComboGetListHeader(CLBoxGetCombo(hwnd));
833 }
834
835 /***********************************************************************
836  *           CBLCreate
837  */
838 static LRESULT CBLCreate( HWND hwnd, WPARAM16 wParam, LPARAM lParam )
839 {
840   CREATESTRUCT16 *createStruct = (CREATESTRUCT16 *)PTR_SEG_TO_LIN(lParam);
841   SetWindowLong32A(hwnd,0,(LONG)createStruct->lpCreateParams);
842   return 0;
843 }
844
845 /***********************************************************************
846  *           CBLGetDlgCode
847  */
848 static LRESULT CBLGetDlgCode( HWND hwnd, WPARAM16 wParam, LPARAM lParam )
849 {
850   return DLGC_WANTARROWS | DLGC_WANTCHARS;
851 }
852
853 /***********************************************************************
854  *           CBLKeyDown
855  */
856 static LRESULT CBLKeyDown( HWND hwnd, WPARAM16 wParam, LPARAM lParam ) 
857 {
858   LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
859   WORD newFocused = lphl->ItemFocused;
860
861   switch(wParam) {
862   case VK_HOME:
863     newFocused = 0;
864     break;
865   case VK_END:
866     newFocused = lphl->ItemsCount - 1;
867     break;
868   case VK_UP:
869     if (newFocused > 0) newFocused--;
870     break;
871   case VK_DOWN:
872     newFocused++;
873     break;
874   case VK_PRIOR:
875     if (newFocused > lphl->ItemsVisible) {
876       newFocused -= lphl->ItemsVisible;
877     } else {
878       newFocused = 0;
879     }
880     break;
881   case VK_NEXT:
882     newFocused += lphl->ItemsVisible;
883     break;
884   default:
885     return 0;
886   }
887
888   if (newFocused >= lphl->ItemsCount)
889     newFocused = lphl->ItemsCount - 1;
890   
891   ListBoxSetCurSel(lphl, newFocused);
892   ListBoxSendNotification(lphl, CBN_SELCHANGE);
893   SendMessage16(GetParent16(hwnd), WM_COMMAND,ID_CLB,MAKELONG(0,CBN_SELCHANGE));
894   lphl->ItemFocused = newFocused;
895   ListBoxScrollToFocus(lphl);
896   SetScrollPos32(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
897   InvalidateRect32( hwnd, NULL, TRUE );
898   return 0;
899 }
900
901 /***********************************************************************
902  *           CBLChar
903  */
904 static LRESULT CBLChar( HWND hwnd, WPARAM16 wParam, LPARAM lParam )
905 {
906   return 0;
907 }
908
909 /***********************************************************************
910  *           CBLPaint
911  */
912 static LRESULT CBLPaint( HWND hwnd, WPARAM16 wParam, LPARAM lParam )
913 {
914   LPHEADLIST   lphl = CLBoxGetListHeader(hwnd);
915   LPLISTSTRUCT lpls;
916   PAINTSTRUCT16  ps;
917   HBRUSH32 hBrush;
918   HFONT32 hOldFont;
919   WND * wndPtr = WIN_FindWndPtr(hwnd);
920   HWND  combohwnd = CLBoxGetCombo(hwnd);
921   HDC16 hdc;
922   RECT16 rect;
923   int   i, top, height;
924
925   top = 0;
926   hdc = BeginPaint16( hwnd, &ps );
927
928   if (!IsWindowVisible(hwnd) || !lphl->bRedrawFlag) {
929     EndPaint16(hwnd, &ps);
930     return 0;
931   }
932
933   hOldFont = SelectObject32(hdc, lphl->hFont);
934   /* listboxes should be white */
935   hBrush = GetStockObject32(WHITE_BRUSH);
936
937   GetClientRect16(hwnd, &rect);
938   FillRect16(hdc, &rect, hBrush);
939   CBLCheckSize(hwnd);
940
941   lpls = lphl->lpFirst;
942
943   lphl->ItemsVisible = 0;
944   for(i = 0; i < lphl->ItemsCount; i++) {
945     if (lpls == NULL) break;
946
947     if (i >= lphl->FirstVisible) {
948       height = lpls->mis.itemHeight;
949       /* must have enough room to draw entire item */
950       if (top > (rect.bottom-height+1)) break;
951
952       lpls->itemRect.top    = top;
953       lpls->itemRect.bottom = top + height;
954       lpls->itemRect.left   = rect.left;
955       lpls->itemRect.right  = rect.right;
956
957       dprintf_listbox(stddeb,"drawing item: %d %d %d %d %d\n",
958                       rect.left,top,rect.right,top+height,lpls->itemState);
959       if (lphl->OwnerDrawn) {
960         ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE, 0);
961         if (lpls->itemState)
962           ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_SELECT, ODS_SELECTED);
963       } else {
964         ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_DRAWENTIRE, 
965                          lpls->itemState);
966       }
967       if ((lphl->ItemFocused == i) && GetFocus32() == hwnd)
968         ListBoxDrawItem (combohwnd, lphl, hdc, lpls, &lpls->itemRect, ODA_FOCUS, ODS_FOCUS);
969
970       top += height;
971       lphl->ItemsVisible++;
972     }
973
974     lpls = lpls->lpNext;
975   }
976
977   if (wndPtr->dwStyle & WS_VSCROLL) 
978       SetScrollRange32(hwnd, SB_VERT, 0, ListMaxFirstVisible(lphl), TRUE);
979
980   SelectObject32(hdc,hOldFont);
981   EndPaint16( hwnd, &ps );
982   return 0;
983
984 }
985
986 /***********************************************************************
987  *           CBLKillFocus
988  */
989 static LRESULT CBLKillFocus( HWND hwnd, WPARAM16 wParam, LPARAM lParam )
990 {
991 /*  SendMessage16(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);*/
992   return 0;
993 }
994
995 /***********************************************************************
996  *           CBLActivate
997  */
998 static LRESULT CBLActivate( HWND hwnd, WPARAM16 wParam, LPARAM lParam )
999 {
1000   if (wParam == WA_INACTIVE)
1001     SendMessage16(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);
1002   return 0;
1003 }
1004
1005 /***********************************************************************
1006  *           CBLLButtonDown
1007  */
1008 static LRESULT CBLLButtonDown( HWND hwnd, WPARAM16 wParam, LPARAM lParam )
1009 {
1010   LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
1011   int        y;
1012   RECT16     rectsel;
1013
1014 /*  SetFocus32(hwnd); */
1015   SetCapture32(hwnd);
1016
1017   lphl->PrevFocused = lphl->ItemFocused;
1018
1019   y = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
1020   if (y == -1)
1021     return 0;
1022
1023   ListBoxSetCurSel(lphl, y);
1024   ListBoxGetItemRect(lphl, y, &rectsel);
1025
1026   InvalidateRect32( hwnd, NULL, TRUE );
1027   return 0;
1028 }
1029
1030 /***********************************************************************
1031  *           CBLLButtonUp
1032  */
1033 static LRESULT CBLLButtonUp( HWND hwnd, WPARAM16 wParam, LPARAM lParam )
1034 {
1035   LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
1036
1037   if (GetCapture32() == hwnd) ReleaseCapture();
1038
1039   if(!lphl)
1040      {
1041       fprintf(stdnimp,"CBLLButtonUp: CLBoxGetListHeader returned NULL!\n");
1042      }
1043   else if (lphl->PrevFocused != lphl->ItemFocused) 
1044           {
1045                 SendMessage16(CLBoxGetCombo(hwnd),CB_SETCURSEL,lphl->ItemFocused,0);
1046                 SendMessage16(GetParent16(hwnd), WM_COMMAND,ID_CLB,MAKELONG(0,CBN_SELCHANGE));
1047                 ListBoxSendNotification(lphl, CBN_SELCHANGE);
1048           }
1049
1050   SendMessage16(CLBoxGetCombo(hwnd),CB_SHOWDROPDOWN,0,0);
1051
1052   return 0;
1053 }
1054
1055 /***********************************************************************
1056  *           CBLMouseMove
1057  */
1058 static LRESULT CBLMouseMove( HWND hwnd, WPARAM16 wParam, LPARAM lParam )
1059 {
1060   LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
1061   short y;
1062   WORD wRet;
1063   RECT16 rect, rectsel;
1064
1065   y = SHIWORD(lParam);
1066   wRet = ListBoxFindMouse(lphl, LOWORD(lParam), HIWORD(lParam));
1067   ListBoxGetItemRect(lphl, wRet, &rectsel);
1068   GetClientRect16(hwnd, &rect);
1069
1070   dprintf_combo(stddeb,"CBLMouseMove: hwnd %04x wp %x lp %lx  y %d  if %d wret %d %d,%d-%d,%d\n",
1071 hwnd,wParam,lParam,y,lphl->ItemFocused,wRet,rectsel.left,rectsel.top,rectsel.right,rectsel.bottom);
1072   
1073   if ((wParam & MK_LBUTTON) != 0) {
1074     if (y < CBLMM_EDGE) {
1075       if (lphl->FirstVisible > 0) {
1076         lphl->FirstVisible--;
1077         SetScrollPos32(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1078         ListBoxSetCurSel(lphl, wRet);
1079         InvalidateRect32( hwnd, NULL, TRUE );
1080         return 0;
1081       }
1082     }
1083     else if (y >= (rect.bottom-CBLMM_EDGE)) {
1084       if (lphl->FirstVisible < ListMaxFirstVisible(lphl)) {
1085         lphl->FirstVisible++;
1086         SetScrollPos32(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1087         ListBoxSetCurSel(lphl, wRet);
1088         InvalidateRect32( hwnd, NULL, TRUE );
1089         return 0;
1090       }
1091     }
1092     else {
1093       if ((short) wRet == lphl->ItemFocused) return 0;
1094       ListBoxSetCurSel(lphl, wRet);
1095       InvalidateRect32( hwnd, NULL, TRUE );
1096     }
1097   }
1098
1099   return 0;
1100 }
1101
1102 /***********************************************************************
1103  *           CBLVScroll
1104  */
1105 static LRESULT CBLVScroll( HWND hwnd, WPARAM16 wParam, LPARAM lParam )
1106 {
1107   LPHEADLIST lphl = CLBoxGetListHeader(hwnd);
1108   int  y;
1109
1110   y = lphl->FirstVisible;
1111
1112   switch(wParam) {
1113   case SB_LINEUP:
1114     if (lphl->FirstVisible > 0)
1115       lphl->FirstVisible--;
1116     break;
1117
1118   case SB_LINEDOWN:
1119     lphl->FirstVisible++;
1120     break;
1121
1122   case SB_PAGEUP:
1123     if (lphl->FirstVisible > lphl->ItemsVisible) {
1124       lphl->FirstVisible -= lphl->ItemsVisible;
1125     } else {
1126       lphl->FirstVisible = 0;
1127     }
1128     break;
1129
1130   case SB_PAGEDOWN:
1131     lphl->FirstVisible += lphl->ItemsVisible;
1132     break;
1133
1134   case SB_THUMBTRACK:
1135     lphl->FirstVisible = LOWORD(lParam);
1136     break;
1137   }
1138
1139   if (lphl->FirstVisible > ListMaxFirstVisible(lphl))
1140     lphl->FirstVisible = ListMaxFirstVisible(lphl);
1141
1142   if (y != lphl->FirstVisible) {
1143     SetScrollPos32(hwnd, SB_VERT, lphl->FirstVisible, TRUE);
1144     InvalidateRect32( hwnd, NULL, TRUE );
1145   }
1146
1147   return 0;
1148 }
1149
1150
1151 /***********************************************************************
1152  *             CBLCheckSize
1153  */
1154 static BOOL CBLCheckSize(HWND hwnd)
1155 {
1156   LPHEADCOMBO  lphc = ComboGetStorageHeader(hwnd);
1157   LPHEADLIST   lphl = ComboGetListHeader(hwnd);
1158   LPLISTSTRUCT lpls;
1159   HWND         hWndLBox;
1160   RECT16 cRect,wRect,lRect,lwRect;
1161   int totheight,dw;
1162   char className[80];
1163
1164   GetClassName32A(hwnd,className,80);
1165   fflush(stddeb);
1166   if (strncmp(className,"COMBOBOX",8)) return FALSE;
1167   if ((hWndLBox = lphc->hWndLBox) == 0) return FALSE;
1168   dprintf_combo(stddeb,"CBLCheckSize headers hw %04x  lb %04x  name %s\n",
1169                 hwnd,hWndLBox,className);
1170
1171   GetClientRect16(hwnd,&cRect);
1172   GetWindowRect16(hwnd,&wRect);
1173   GetClientRect16(hWndLBox,&lRect);
1174   GetWindowRect16(hWndLBox,&lwRect);
1175
1176   dprintf_combo(stddeb,"CBLCheckSize: init cRect %d,%d-%d,%d  wRect %d,%d-%d,%d\n",
1177                 cRect.left,cRect.top,cRect.right,cRect.bottom,
1178                 wRect.left,wRect.top,wRect.right,wRect.bottom);
1179   dprintf_combo(stddeb,"                   lRect %d,%d-%d,%d  lwRect %d,%d-%d,%d\n",
1180               lRect.left,lRect.top,lRect.right,lRect.bottom,
1181               lwRect.left,lwRect.top,lwRect.right,lwRect.bottom);
1182   fflush(stddeb);
1183   
1184   totheight = 0;
1185   for (lpls=lphl->lpFirst; lpls != NULL; lpls=lpls->lpNext)
1186     totheight += lpls->mis.itemHeight;
1187
1188   dw = cRect.right-cRect.left+2*SYSMETRICS_CXBORDER+SYSMETRICS_CXVSCROLL;
1189   dw -= lwRect.right-lwRect.left;
1190   dw -= SYSMETRICS_CXVSCROLL;
1191
1192   /* TODO: This isn't really what windows does */
1193   if ((lRect.bottom-lRect.top < 3*lphl->StdItemHeight) || dw) {
1194     dprintf_combo(stddeb,"    Changing; totHeight %d  StdItemHght %d  dw %d\n",
1195                   totheight,lphl->StdItemHeight,dw);
1196     SetWindowPos(hWndLBox, 0, lRect.left, lRect.top, 
1197                  lwRect.right-lwRect.left+dw, totheight+2*SYSMETRICS_CYBORDER, 
1198                  SWP_NOMOVE | SWP_NOZORDER | SWP_NOREDRAW | SWP_NOACTIVATE );
1199   }
1200   return TRUE;
1201 }
1202
1203
1204 /***********************************************************************
1205  *           ComboLBoxWndProc
1206  */
1207 LRESULT ComboLBoxWndProc(HWND hwnd, UINT message, WPARAM16 wParam, LPARAM lParam)
1208 {
1209     switch(message) {   
1210      case WM_CREATE: return CBLCreate(hwnd, wParam, lParam);
1211      case WM_GETDLGCODE: return CBLGetDlgCode(hwnd, wParam, lParam);
1212      case WM_KEYDOWN: return CBLKeyDown(hwnd, wParam, lParam);
1213      case WM_CHAR: return CBLChar(hwnd, wParam, lParam);
1214      case WM_PAINT: return CBLPaint(hwnd, wParam, lParam);
1215      case WM_KILLFOCUS: return CBLKillFocus(hwnd, wParam, lParam);
1216      case WM_ACTIVATE: return CBLActivate(hwnd, wParam, lParam);
1217      case WM_LBUTTONDOWN: return CBLLButtonDown(hwnd, wParam, lParam);
1218      case WM_LBUTTONUP: return CBLLButtonUp(hwnd, wParam, lParam);
1219      case WM_MOUSEMOVE: return CBLMouseMove(hwnd, wParam, lParam);
1220      case WM_VSCROLL: return CBLVScroll(hwnd, wParam, lParam);
1221      case WM_SIZE: return CBLCheckSize(hwnd);
1222      case WM_MOUSEACTIVATE:  /* We don't want to be activated */
1223         return MA_NOACTIVATE;
1224     }
1225     return DefWindowProc16(hwnd, message, wParam, lParam);
1226 }
1227
1228 /************************************************************************
1229  *                              DlgDirSelectComboBox    [USER.194]
1230  */
1231 BOOL DlgDirSelectComboBox(HWND hDlg, LPSTR lpStr, INT nIDLBox)
1232 {
1233         fprintf(stdnimp,"DlgDirSelectComboBox(%04x, '%s', %d) \n",
1234                                 hDlg, lpStr, nIDLBox);
1235         return TRUE;
1236 }
1237
1238 static INT32 COMBO_DlgDirList( HWND32 hDlg, LPARAM path, INT32 idCBox,
1239                                INT32 idStatic, UINT32 wType, BOOL32 unicode )
1240 {
1241     LRESULT res = 0;
1242
1243     if (idCBox)
1244     {
1245         SendDlgItemMessage32A( hDlg, idCBox, CB_RESETCONTENT, 0, 0 );
1246         if (unicode)
1247             res = SendDlgItemMessage32W( hDlg, idCBox, CB_DIR, wType, path );
1248         else
1249             res = SendDlgItemMessage32A( hDlg, idCBox, CB_DIR, wType, path );
1250     }
1251     if (idStatic)
1252     {
1253         char temp[512] = "A:\\";
1254         int drive = DRIVE_GetCurrentDrive();
1255         temp[0] += drive;
1256         lstrcpyn32A( temp + 3, DRIVE_GetDosCwd(drive), sizeof(temp)-3 );
1257         AnsiLower( temp );
1258         SetDlgItemText32A( hDlg, idStatic, temp );
1259     } 
1260     return (res >= 0);
1261 }
1262
1263
1264 /***********************************************************************
1265  *           DlgDirListComboBox16   (USER.195)
1266  */
1267 INT16 DlgDirListComboBox16( HWND16 hDlg, SEGPTR path, INT16 idCBox,
1268                             INT16 idStatic, UINT16 wType )
1269 {
1270     dprintf_combo( stddeb,"DlgDirListComboBox16(%04x,%08x,%d,%d,%04x)\n",
1271                    hDlg, (UINT32)path, idCBox, idStatic, wType );
1272     return COMBO_DlgDirList( hDlg, (LPARAM)path, idCBox,
1273                              idStatic, wType, FALSE );
1274 }
1275
1276
1277 /***********************************************************************
1278  *           DlgDirListComboBox32A   (USER32.143)
1279  */
1280 INT32 DlgDirListComboBox32A( HWND32 hDlg, LPCSTR path, INT32 idCBox,
1281                              INT32 idStatic, UINT32 wType )
1282 {
1283     dprintf_combo( stddeb,"DlgDirListComboBox32A(%08x,'%s',%d,%d,%08X)\n",
1284                    hDlg, path, idCBox, idStatic, wType );
1285     return COMBO_DlgDirList( hDlg, (LPARAM)path, idCBox,
1286                              idStatic, wType, FALSE );
1287 }
1288
1289
1290 /***********************************************************************
1291  *           DlgDirListComboBox32W   (USER32.144)
1292  */
1293 INT32 DlgDirListComboBox32W( HWND32 hDlg, LPCWSTR path, INT32 idCBox,
1294                              INT32 idStatic, UINT32 wType )
1295 {
1296     dprintf_combo( stddeb,"DlgDirListComboBox32W(%08x,%p,%d,%d,%08X)\n",
1297                    hDlg, path, idCBox, idStatic, wType );
1298     return COMBO_DlgDirList( hDlg, (LPARAM)path, idCBox,
1299                              idStatic, wType, TRUE );
1300 }