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