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