Release 980329
[wine/multimedia.git] / controls / combo.c
blob3001b5b7b9bb976b35d6f394861619c5affbb035
1 /*
2 * Combo controls
3 *
4 * Copyright 1997 Alex Korobka
5 *
6 * FIXME: roll up in Netscape 3.01.
7 */
9 #include <stdio.h>
10 #include <string.h>
12 #include "windows.h"
13 #include "sysmetrics.h"
14 #include "win.h"
15 #include "spy.h"
16 #include "user.h"
17 #include "graphics.h"
18 #include "heap.h"
19 #include "combo.h"
20 #include "drive.h"
21 #include "debug.h"
23 /* bits in the dwKeyData */
24 #define KEYDATA_ALT 0x2000
25 #define KEYDATA_PREVSTATE 0x4000
28 * Additional combo box definitions
31 #define CB_GETPTR( wnd ) (*(LPHEADCOMBO*)((wnd)->wExtra))
32 #define CB_NOTIFY( lphc, code ) \
33 (SendMessage32A( (lphc)->owner, WM_COMMAND, \
34 MAKEWPARAM((lphc)->self->wIDmenu, (code)), (lphc)->self->hwndSelf))
35 #define CB_GETEDITTEXTLENGTH( lphc ) \
36 (SendMessage32A( (lphc)->hWndEdit, WM_GETTEXTLENGTH, 0, 0 ))
38 static HBITMAP32 hComboBmp = 0;
39 static UINT32 CBitHeight, CBitWidth;
40 static UINT32 CBitOffset = 8;
42 /***********************************************************************
43 * COMBO_Init
45 * Load combo button bitmap.
47 static BOOL32 COMBO_Init()
49 HDC32 hDC;
51 if( hComboBmp ) return TRUE;
52 if( (hDC = CreateCompatibleDC32(0)) )
54 BOOL32 bRet = FALSE;
55 if( (hComboBmp = LoadBitmap32A(0, MAKEINTRESOURCE(OBM_COMBO))) )
57 BITMAP32 bm;
58 HBITMAP32 hPrevB;
59 RECT32 r;
61 GetObject32A( hComboBmp, sizeof(bm), &bm );
62 CBitHeight = bm.bmHeight;
63 CBitWidth = bm.bmWidth;
65 TRACE(combo, "combo bitmap [%i,%i]\n", CBitWidth, CBitHeight );
67 hPrevB = SelectObject16( hDC, hComboBmp);
68 SetRect32( &r, 0, 0, CBitWidth, CBitHeight );
69 InvertRect32( hDC, &r );
70 SelectObject32( hDC, hPrevB );
71 bRet = TRUE;
73 DeleteDC32( hDC );
74 return bRet;
76 return FALSE;
79 /***********************************************************************
80 * COMBO_NCCreate
82 static LRESULT COMBO_NCCreate(WND* wnd, LPARAM lParam)
84 LPHEADCOMBO lphc;
86 if ( wnd && COMBO_Init() &&
87 (lphc = HeapAlloc(GetProcessHeap(), 0, sizeof(HEADCOMBO))) )
89 LPCREATESTRUCT32A lpcs = (CREATESTRUCT32A*)lParam;
91 memset( lphc, 0, sizeof(HEADCOMBO) );
92 *(LPHEADCOMBO*)wnd->wExtra = lphc;
94 /* some braindead apps do try to use scrollbar/border flags */
96 lphc->dwStyle = (lpcs->style & ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL));
97 wnd->dwStyle &= ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL);
99 if( !(lpcs->style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) )
100 lphc->dwStyle |= CBS_HASSTRINGS;
101 if( !(wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) )
102 lphc->wState |= CBF_NOTIFY;
104 TRACE(combo, "[0x%08x], style = %08x\n",
105 (UINT32)lphc, lphc->dwStyle );
107 return (LRESULT)(UINT32)wnd->hwndSelf;
109 return (LRESULT)FALSE;
112 /***********************************************************************
113 * COMBO_NCDestroy
115 static LRESULT COMBO_NCDestroy( LPHEADCOMBO lphc )
118 if( lphc )
120 WND* wnd = lphc->self;
122 TRACE(combo,"[%04x]: freeing storage\n", CB_HWND(lphc));
124 if( (CB_GETTYPE(lphc) != CBS_SIMPLE) && lphc->hWndLBox )
125 DestroyWindow32( lphc->hWndLBox );
127 HeapFree( GetProcessHeap(), 0, lphc );
128 wnd->wExtra[0] = 0;
130 return 0;
133 /***********************************************************************
134 * CBCalcPlacement
136 * Set up component coordinates given valid lphc->RectCombo.
138 static void CBCalcPlacement( LPHEADCOMBO lphc, LPRECT32 lprEdit,
139 LPRECT32 lprButton, LPRECT32 lprLB )
141 RECT32 rect = lphc->RectCombo;
142 SIZE32 size;
144 /* get combo height and width */
146 if( lphc->editHeight )
147 size.cy = lphc->editHeight;
148 else
150 HDC32 hDC = GetDC32( lphc->self->hwndSelf );
151 HFONT32 hPrevFont = 0;
153 if( lphc->hFont ) hPrevFont = SelectObject32( hDC, lphc->hFont );
155 GetTextExtentPoint32A( hDC, "0", 1, &size);
157 size.cy += size.cy / 4 + 4 * SYSMETRICS_CYBORDER;
159 if( hPrevFont ) SelectObject32( hDC, hPrevFont );
160 ReleaseDC32( lphc->self->hwndSelf, hDC );
162 size.cx = rect.right - rect.left;
164 if( CB_OWNERDRAWN(lphc) )
166 UINT32 u = lphc->RectEdit.bottom - lphc->RectEdit.top;
168 if( lphc->wState & CBF_MEASUREITEM ) /* first initialization */
170 MEASUREITEMSTRUCT32 mi32;
172 lphc->wState &= ~CBF_MEASUREITEM;
173 mi32.CtlType = ODT_COMBOBOX;
174 mi32.CtlID = lphc->self->wIDmenu;
175 mi32.itemID = -1;
176 mi32.itemWidth = size.cx;
177 mi32.itemHeight = size.cy - 6; /* ownerdrawn cb is taller */
178 mi32.itemData = 0;
179 SendMessage32A(lphc->owner, WM_MEASUREITEM,
180 (WPARAM32)mi32.CtlID, (LPARAM)&mi32);
181 u = 6 + (UINT16)mi32.itemHeight;
183 size.cy = u;
186 /* calculate text and button placement */
188 lprEdit->left = lprEdit->top = lprButton->top = 0;
189 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) /* no button */
190 lprButton->left = lprButton->right = lprButton->bottom = 0;
191 else
193 INT32 i = size.cx - CBitWidth - 10; /* seems ok */
195 lprButton->right = size.cx;
196 lprButton->left = (INT16)i;
197 lprButton->bottom = lprButton->top + size.cy;
199 if( i < 0 ) size.cx = 0;
200 else size.cx = i;
203 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
205 size.cx -= CBitOffset;
206 if( size.cx < 0 ) size.cx = 0;
209 lprEdit->right = size.cx; lprEdit->bottom = size.cy;
211 /* listbox placement */
213 lprLB->left = ( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) ? 0 : CBitOffset;
214 lprLB->top = lprEdit->bottom - SYSMETRICS_CYBORDER;
215 lprLB->right = rect.right - rect.left;
216 lprLB->bottom = rect.bottom - rect.top;
218 if( lphc->droppedWidth > (lprLB->right - lprLB->left) )
219 lprLB->right = lprLB->left + lphc->droppedWidth;
221 TRACE(combo,"[%04x]: (%i,%i-%i,%i) placement\n",
222 CB_HWND(lphc), lphc->RectCombo.left, lphc->RectCombo.top,
223 lphc->RectCombo.right, lphc->RectCombo.bottom);
225 TRACE(combo,"\ttext\t= (%i,%i-%i,%i)\n",
226 lprEdit->left, lprEdit->top, lprEdit->right, lprEdit->bottom);
228 TRACE(combo,"\tbutton\t= (%i,%i-%i,%i)\n",
229 lprButton->left, lprButton->top, lprButton->right, lprButton->bottom);
231 TRACE(combo,"\tlbox\t= (%i,%i-%i,%i)\n",
232 lprLB->left, lprLB->top, lprLB->right, lprLB->bottom );
235 /***********************************************************************
236 * CBGetDroppedControlRect32
238 static void CBGetDroppedControlRect32( LPHEADCOMBO lphc, LPRECT32 lpRect)
240 lpRect->left = lphc->RectCombo.left +
241 (lphc->wState & CBF_EDIT) ? CBitOffset : 0;
242 lpRect->top = lphc->RectCombo.top + lphc->RectEdit.bottom -
243 SYSMETRICS_CYBORDER;
244 lpRect->right = lphc->RectCombo.right;
245 lpRect->bottom = lphc->RectCombo.bottom - SYSMETRICS_CYBORDER;
248 /***********************************************************************
249 * COMBO_Create
251 static LRESULT COMBO_Create( LPHEADCOMBO lphc, WND* wnd, LPARAM lParam)
253 static char clbName[] = "ComboLBox";
254 static char editName[] = "Edit";
256 LPCREATESTRUCT32A lpcs = (CREATESTRUCT32A*)lParam;
258 if( !CB_GETTYPE(lphc) ) lphc->dwStyle |= CBS_SIMPLE;
259 else if( CB_GETTYPE(lphc) != CBS_DROPDOWNLIST ) lphc->wState |= CBF_EDIT;
261 lphc->self = wnd;
262 lphc->owner = lpcs->hwndParent;
264 /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */
266 if( lphc->owner || !(lpcs->style & WS_VISIBLE) )
268 UINT32 lbeStyle;
269 RECT32 editRect, btnRect, lbRect;
271 GetWindowRect32( wnd->hwndSelf, &lphc->RectCombo );
273 lphc->wState |= CBF_MEASUREITEM;
274 CBCalcPlacement( lphc, &editRect, &btnRect, &lbRect );
275 lphc->RectButton = btnRect;
276 lphc->droppedWidth = lphc->editHeight = 0;
278 /* create listbox popup */
280 lbeStyle = (LBS_NOTIFY | WS_BORDER | WS_CLIPSIBLINGS) |
281 (lpcs->style & (WS_VSCROLL | CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE));
283 if( lphc->dwStyle & CBS_SORT )
284 lbeStyle |= LBS_SORT;
285 if( lphc->dwStyle & CBS_HASSTRINGS )
286 lbeStyle |= LBS_HASSTRINGS;
287 if( lphc->dwStyle & CBS_NOINTEGRALHEIGHT )
288 lbeStyle |= LBS_NOINTEGRALHEIGHT;
289 if( lphc->dwStyle & CBS_DISABLENOSCROLL )
290 lbeStyle |= LBS_DISABLENOSCROLL;
292 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) /* child listbox */
293 lbeStyle |= WS_CHILD | WS_VISIBLE;
294 else /* popup listbox */
296 lbeStyle |= WS_POPUP;
297 OffsetRect32( &lbRect, lphc->RectCombo.left, lphc->RectCombo.top );
300 /* Dropdown ComboLBox is not a child window and we cannot pass
301 * ID_CB_LISTBOX directly because it will be treated as a menu handle.
304 lphc->hWndLBox = CreateWindowEx32A( 0, clbName, NULL, lbeStyle,
305 lbRect.left + SYSMETRICS_CXBORDER,
306 lbRect.top + SYSMETRICS_CYBORDER,
307 lbRect.right - lbRect.left - 2 * SYSMETRICS_CXBORDER,
308 lbRect.bottom - lbRect.top - 2 * SYSMETRICS_CYBORDER,
309 lphc->self->hwndSelf,
310 (lphc->dwStyle & CBS_DROPDOWN)? (HMENU32)0 : (HMENU32)ID_CB_LISTBOX,
311 lphc->self->hInstance, (LPVOID)lphc );
312 if( lphc->hWndLBox )
314 BOOL32 bEdit = TRUE;
315 lbeStyle = WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NOHIDESEL | ES_LEFT;
316 if( lphc->wState & CBF_EDIT )
318 if( lphc->dwStyle & CBS_OEMCONVERT )
319 lbeStyle |= ES_OEMCONVERT;
320 if( lphc->dwStyle & CBS_AUTOHSCROLL )
321 lbeStyle |= ES_AUTOHSCROLL;
322 if( lphc->dwStyle & CBS_LOWERCASE )
323 lbeStyle |= ES_LOWERCASE;
324 else if( lphc->dwStyle & CBS_UPPERCASE )
325 lbeStyle |= ES_UPPERCASE;
326 lphc->hWndEdit = CreateWindowEx32A( 0, editName, NULL, lbeStyle,
327 editRect.left, editRect.top, editRect.right - editRect.left,
328 editRect.bottom - editRect.top, lphc->self->hwndSelf,
329 (HMENU32)ID_CB_EDIT, lphc->self->hInstance, NULL );
330 if( !lphc->hWndEdit ) bEdit = FALSE;
333 if( bEdit )
335 lphc->RectEdit = editRect;
336 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
338 lphc->wState |= CBF_NORESIZE;
339 SetWindowPos32( wnd->hwndSelf, 0, 0, 0,
340 lphc->RectCombo.right - lphc->RectCombo.left,
341 lphc->RectEdit.bottom - lphc->RectEdit.top,
342 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
343 lphc->wState &= ~CBF_NORESIZE;
345 TRACE(combo,"init done\n");
346 return wnd->hwndSelf;
348 ERR(combo, "edit control failure.\n");
349 } else ERR(combo, "listbox failure.\n");
350 } else ERR(combo, "no owner for visible combo.\n");
352 /* CreateWindow() will send WM_NCDESTROY to cleanup */
354 return -1;
357 /***********************************************************************
358 * CBPaintButton
360 * Paint combo button (normal, pressed, and disabled states).
362 static void CBPaintButton(LPHEADCOMBO lphc, HDC32 hdc)
364 RECT32 r;
365 HBRUSH32 hPrevBrush;
366 UINT32 x, y;
367 BOOL32 bBool;
369 if( lphc->wState & CBF_NOREDRAW ) return;
371 hPrevBrush = (HBRUSH32)SelectObject32(hdc, GetSysColorBrush32(COLOR_BTNFACE));
372 CONV_RECT16TO32( &lphc->RectButton, &r );
374 Rectangle32(hdc, r.left, r.top, r.right, r.bottom );
375 InflateRect32( &r, -1, -1 );
376 if( (bBool = lphc->wState & CBF_BUTTONDOWN) )
378 GRAPH_DrawReliefRect(hdc, &r, 1, 0, TRUE);
379 OffsetRect32( &r, 1, 1 );
380 } else GRAPH_DrawReliefRect(hdc, &r, 1, 2, FALSE);
382 x = (r.left + r.right - CBitWidth) >> 1;
383 y = (r.top + r.bottom - CBitHeight) >> 1;
385 InflateRect32( &r, -3, -3 );
386 if( (bBool = CB_DISABLED(lphc)) )
388 GRAPH_SelectClipMask(hdc, hComboBmp, x + 1, y + 1 );
389 FillRect32(hdc, &r, (HBRUSH32)GetStockObject32(WHITE_BRUSH));
392 GRAPH_SelectClipMask(hdc, hComboBmp, x, y );
393 FillRect32(hdc, &r, (HBRUSH32)GetStockObject32((bBool) ? GRAY_BRUSH : BLACK_BRUSH));
395 GRAPH_SelectClipMask(hdc, (HBITMAP32)0, 0, 0);
396 SelectObject32( hdc, hPrevBrush );
399 /***********************************************************************
400 * CBPaintText
402 * Paint CBS_DROPDOWNLIST text field / update edit control contents.
404 static void CBPaintText(LPHEADCOMBO lphc, HDC32 hdc)
406 INT32 id, size = 0;
407 LPSTR pText = NULL;
409 if( lphc->wState & CBF_NOREDRAW ) return;
411 /* follow Windows combobox that sends a bunch of text
412 * inquiries to its listbox while processing WM_PAINT. */
414 if( (id = SendMessage32A(lphc->hWndLBox, LB_GETCURSEL32, 0, 0) ) != LB_ERR )
416 size = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, id, 0);
417 if( (pText = HeapAlloc( GetProcessHeap(), 0, size + 1)) )
419 SendMessage32A( lphc->hWndLBox, LB_GETTEXT32, (WPARAM32)id, (LPARAM)pText );
420 pText[size] = '\0'; /* just in case */
421 } else return;
424 if( lphc->wState & CBF_EDIT )
426 if( CB_HASSTRINGS(lphc) ) SetWindowText32A( lphc->hWndEdit, pText );
427 if( lphc->wState & CBF_FOCUSED )
428 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1));
430 else /* paint text field ourselves */
432 HBRUSH32 hPrevBrush = 0;
433 HDC32 hDC = hdc;
435 if( !hDC )
437 if ((hDC = GetDC32(lphc->self->hwndSelf)))
439 HBRUSH32 hBrush = SendMessage32A( lphc->owner,
440 WM_CTLCOLORLISTBOX,
441 hDC, lphc->self->hwndSelf );
442 hPrevBrush = SelectObject32( hDC,
443 (hBrush) ? hBrush : GetStockObject32(WHITE_BRUSH) );
446 if( hDC )
448 RECT32 rect;
449 UINT32 itemState;
450 HFONT32 hPrevFont = (lphc->hFont) ? SelectObject32(hDC, lphc->hFont) : 0;
452 PatBlt32( hDC, (rect.left = lphc->RectEdit.left + SYSMETRICS_CXBORDER),
453 (rect.top = lphc->RectEdit.top + SYSMETRICS_CYBORDER),
454 (rect.right = lphc->RectEdit.right - SYSMETRICS_CXBORDER),
455 (rect.bottom = lphc->RectEdit.bottom - SYSMETRICS_CYBORDER) - 1, PATCOPY );
456 InflateRect32( &rect, -1, -1 );
458 if( lphc->wState & CBF_FOCUSED &&
459 !(lphc->wState & CBF_DROPPED) )
461 /* highlight */
463 FillRect32( hDC, &rect, GetSysColorBrush32(COLOR_HIGHLIGHT) );
464 SetBkColor32( hDC, GetSysColor32( COLOR_HIGHLIGHT ) );
465 SetTextColor32( hDC, GetSysColor32( COLOR_HIGHLIGHTTEXT ) );
466 itemState = ODS_SELECTED | ODS_FOCUS;
467 } else itemState = 0;
469 if( CB_OWNERDRAWN(lphc) )
471 DRAWITEMSTRUCT32 dis;
473 if( lphc->self->dwStyle & WS_DISABLED ) itemState |= ODS_DISABLED;
475 dis.CtlType = ODT_COMBOBOX;
476 dis.CtlID = lphc->self->wIDmenu;
477 dis.hwndItem = lphc->self->hwndSelf;
478 dis.itemAction = ODA_DRAWENTIRE;
479 dis.itemID = id;
480 dis.itemState = itemState;
481 dis.hDC = hDC;
482 dis.rcItem = rect;
483 dis.itemData = SendMessage32A( lphc->hWndLBox, LB_GETITEMDATA32,
484 (WPARAM32)id, 0 );
485 SendMessage32A( lphc->owner, WM_DRAWITEM,
486 lphc->self->wIDmenu, (LPARAM)&dis );
488 else
490 ExtTextOut32A( hDC, rect.left + 1, rect.top + 1,
491 ETO_OPAQUE | ETO_CLIPPED, &rect,
492 (pText) ? pText : "" , size, NULL );
493 if(lphc->wState & CBF_FOCUSED && !(lphc->wState & CBF_DROPPED))
494 DrawFocusRect32( hDC, &rect );
497 if( hPrevFont ) SelectObject32(hDC, hPrevFont );
498 if( !hdc )
500 if( hPrevBrush ) SelectObject32( hDC, hPrevBrush );
501 ReleaseDC32( lphc->self->hwndSelf, hDC );
505 HeapFree( GetProcessHeap(), 0, pText );
508 /***********************************************************************
509 * COMBO_Paint
511 static LRESULT COMBO_Paint(LPHEADCOMBO lphc, HDC32 hParamDC)
513 PAINTSTRUCT32 ps;
514 HDC32 hDC;
516 hDC = (hParamDC) ? hParamDC
517 : BeginPaint32( lphc->self->hwndSelf, &ps);
518 if( hDC && !(lphc->wState & CBF_NOREDRAW) )
520 HBRUSH32 hPrevBrush, hBkgBrush;
522 hBkgBrush = SendMessage32A( lphc->owner, WM_CTLCOLORLISTBOX,
523 hDC, lphc->self->hwndSelf );
524 if( !hBkgBrush ) hBkgBrush = GetStockObject32(WHITE_BRUSH);
526 hPrevBrush = SelectObject32( hDC, hBkgBrush );
527 if( !IsRectEmpty32(&lphc->RectButton) )
529 /* paint everything to the right of the text field */
531 PatBlt32( hDC, lphc->RectEdit.right, lphc->RectEdit.top,
532 lphc->RectButton.right - lphc->RectEdit.right,
533 lphc->RectEdit.bottom - lphc->RectEdit.top, PATCOPY );
534 CBPaintButton( lphc, hDC );
537 if( !(lphc->wState & CBF_EDIT) )
539 /* paint text field */
541 GRAPH_DrawRectangle( hDC, lphc->RectEdit.left, lphc->RectEdit.top,
542 lphc->RectEdit.right - lphc->RectEdit.left,
543 lphc->RectButton.bottom - lphc->RectButton.top,
544 GetSysColorPen32(COLOR_WINDOWFRAME) );
545 CBPaintText( lphc, hDC );
547 if( hPrevBrush ) SelectObject32( hDC, hPrevBrush );
549 if( !hParamDC ) EndPaint32(lphc->self->hwndSelf, &ps);
550 return 0;
553 /***********************************************************************
554 * CBUpdateLBox
556 * Select listbox entry according to the contents of the edit control.
558 static INT32 CBUpdateLBox( LPHEADCOMBO lphc )
560 INT32 length, idx, ret;
561 LPSTR pText = NULL;
563 idx = ret = LB_ERR;
564 length = CB_GETEDITTEXTLENGTH( lphc );
566 if( length > 0 )
567 pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1);
569 TRACE(combo,"\t edit text length %i\n", length );
571 if( pText )
573 if( length ) GetWindowText32A( lphc->hWndEdit, pText, length + 1);
574 else pText[0] = '\0';
575 idx = SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32,
576 (WPARAM32)(-1), (LPARAM)pText );
577 if( idx == LB_ERR ) idx = 0; /* select first item */
578 else ret = idx;
579 HeapFree( GetProcessHeap(), 0, pText );
582 /* select entry */
584 SendMessage32A( lphc->hWndLBox, LB_SETCURSEL32, (WPARAM32)idx, 0 );
586 if( idx >= 0 )
588 SendMessage32A( lphc->hWndLBox, LB_SETTOPINDEX32, (WPARAM32)idx, 0 );
589 /* probably superfluous but Windows sends this too */
590 SendMessage32A( lphc->hWndLBox, LB_SETCARETINDEX32, (WPARAM32)idx, 0 );
592 return ret;
595 /***********************************************************************
596 * CBUpdateEdit
598 * Copy a listbox entry to the edit control.
600 static void CBUpdateEdit( LPHEADCOMBO lphc , INT32 index )
602 INT32 length;
603 LPSTR pText = NULL;
605 TRACE(combo,"\t %i\n", index );
607 if( index == -1 )
609 length = CB_GETEDITTEXTLENGTH( lphc );
610 if( length )
612 if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) )
614 GetWindowText32A( lphc->hWndEdit, pText, length + 1 );
615 index = SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32,
616 (WPARAM32)(-1), (LPARAM)pText );
617 HeapFree( GetProcessHeap(), 0, pText );
622 if( index >= 0 ) /* got an entry */
624 length = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, (WPARAM32)index, 0);
625 if( length )
627 if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) )
629 SendMessage32A( lphc->hWndLBox, LB_GETTEXT32,
630 (WPARAM32)index, (LPARAM)pText );
631 SendMessage32A( lphc->hWndEdit, WM_SETTEXT, 0, (LPARAM)pText );
632 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1) );
633 HeapFree( GetProcessHeap(), 0, pText );
639 /***********************************************************************
640 * CBDropDown
642 * Show listbox popup.
644 static void CBDropDown( LPHEADCOMBO lphc )
646 INT32 index;
647 RECT32 rect;
648 LPRECT32 pRect = NULL;
650 TRACE(combo,"[%04x]: drop down\n", CB_HWND(lphc));
652 CB_NOTIFY( lphc, CBN_DROPDOWN );
654 /* set selection */
656 lphc->wState |= CBF_DROPPED;
657 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
659 index = CBUpdateLBox( lphc );
660 if( !(lphc->wState & CBF_CAPTURE) ) CBUpdateEdit( lphc, index );
662 else
664 index = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 );
665 if( index == LB_ERR ) index = 0;
666 SendMessage32A( lphc->hWndLBox, LB_SETTOPINDEX32, (WPARAM32)index, 0 );
667 SendMessage32A( lphc->hWndLBox, LB_CARETON32, 0, 0 );
668 pRect = &lphc->RectEdit;
671 /* now set popup position */
673 GetWindowRect32( lphc->self->hwndSelf, &rect );
675 rect.top += lphc->RectEdit.bottom - lphc->RectEdit.top - SYSMETRICS_CYBORDER;
676 rect.bottom = rect.top + lphc->RectCombo.bottom -
677 lphc->RectCombo.top - SYSMETRICS_CYBORDER;
678 rect.right = rect.left + lphc->RectCombo.right - lphc->RectCombo.left;
679 rect.left += ( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) ? 0 : CBitOffset;
681 SetWindowPos32( lphc->hWndLBox, HWND_TOP, rect.left, rect.top,
682 rect.right - rect.left, rect.bottom - rect.top,
683 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOREDRAW);
685 if( !(lphc->wState & CBF_NOREDRAW) )
686 if( pRect )
687 RedrawWindow32( lphc->self->hwndSelf, pRect, 0, RDW_INVALIDATE |
688 RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
689 ShowWindow32( lphc->hWndLBox, SW_SHOWNA );
692 /***********************************************************************
693 * CBRollUp
695 * Hide listbox popup.
697 static void CBRollUp( LPHEADCOMBO lphc, BOOL32 ok, BOOL32 bButton )
699 HWND32 hWnd = lphc->self->hwndSelf;
701 CB_NOTIFY( lphc, (ok) ? CBN_SELENDOK : CBN_SELENDCANCEL );
703 if( IsWindow32( hWnd ) && CB_GETTYPE(lphc) != CBS_SIMPLE )
706 TRACE(combo,"[%04x]: roll up [%i]\n", CB_HWND(lphc), (INT32)ok );
708 /* always send WM_LBUTTONUP? */
709 SendMessage32A( lphc->hWndLBox, WM_LBUTTONUP, 0, (LPARAM)(-1) );
711 if( lphc->wState & CBF_DROPPED )
713 RECT32 rect;
715 lphc->wState &= ~CBF_DROPPED;
716 ShowWindow32( lphc->hWndLBox, SW_HIDE );
718 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
720 INT32 index = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 );
721 CBUpdateEdit( lphc, index );
722 rect = lphc->RectButton;
724 else
726 if( bButton )
727 UnionRect32( &rect, &lphc->RectButton,
728 &lphc->RectEdit );
729 else
730 rect = lphc->RectEdit;
731 bButton = TRUE;
734 if( bButton && !(lphc->wState & CBF_NOREDRAW) )
735 RedrawWindow32( hWnd, &rect, 0, RDW_INVALIDATE |
736 RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
737 CB_NOTIFY( lphc, CBN_CLOSEUP );
742 /***********************************************************************
743 * COMBO_FlipListbox
745 * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
747 BOOL32 COMBO_FlipListbox( LPHEADCOMBO lphc, BOOL32 bRedrawButton )
749 if( lphc->wState & CBF_DROPPED )
751 CBRollUp( lphc, TRUE, bRedrawButton );
752 return FALSE;
755 CBDropDown( lphc );
756 return TRUE;
759 /***********************************************************************
760 * COMBO_GetLBWindow
762 * Edit control helper.
764 HWND32 COMBO_GetLBWindow( WND* pWnd )
766 LPHEADCOMBO lphc = CB_GETPTR(pWnd);
767 if( lphc ) return lphc->hWndLBox;
768 return 0;
772 /***********************************************************************
773 * CBRepaintButton
775 static void CBRepaintButton( LPHEADCOMBO lphc )
777 HDC32 hDC = GetDC32( lphc->self->hwndSelf );
779 if( hDC )
781 CBPaintButton( lphc, hDC );
782 ReleaseDC32( lphc->self->hwndSelf, hDC );
786 /***********************************************************************
787 * COMBO_SetFocus
789 static void COMBO_SetFocus( LPHEADCOMBO lphc )
791 if( !(lphc->wState & CBF_FOCUSED) )
793 if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
794 SendMessage32A( lphc->hWndLBox, LB_CARETON32, 0, 0 );
796 if( lphc->wState & CBF_EDIT )
797 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1) );
798 lphc->wState |= CBF_FOCUSED;
799 if( !(lphc->wState & CBF_EDIT) ) CBPaintText( lphc, 0 );
801 CB_NOTIFY( lphc, CBN_SETFOCUS );
805 /***********************************************************************
806 * COMBO_KillFocus
808 static void COMBO_KillFocus( LPHEADCOMBO lphc )
810 HWND32 hWnd = lphc->self->hwndSelf;
812 if( lphc->wState & CBF_FOCUSED )
814 SendMessage32A( hWnd, WM_LBUTTONUP, 0, (LPARAM)(-1) );
816 CBRollUp( lphc, FALSE, TRUE );
817 if( IsWindow32( hWnd ) )
819 if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
820 SendMessage32A( lphc->hWndLBox, LB_CARETOFF32, 0, 0 );
822 lphc->wState &= ~CBF_FOCUSED;
824 /* redraw text */
825 if( lphc->wState & CBF_EDIT )
826 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, (WPARAM32)(-1), 0 );
827 else CBPaintText( lphc, 0 );
829 CB_NOTIFY( lphc, CBN_KILLFOCUS );
834 /***********************************************************************
835 * COMBO_Command
837 static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM32 wParam, HWND32 hWnd )
839 if( lphc->wState & CBF_EDIT && lphc->hWndEdit == hWnd )
841 /* ">> 8" makes gcc generate jump-table instead of cmp ladder */
843 switch( HIWORD(wParam) >> 8 )
845 case (EN_SETFOCUS >> 8):
847 TRACE(combo,"[%04x]: edit [%04x] got focus\n",
848 CB_HWND(lphc), lphc->hWndEdit );
850 if( !(lphc->wState & CBF_FOCUSED) ) COMBO_SetFocus( lphc );
851 break;
853 case (EN_KILLFOCUS >> 8):
855 TRACE(combo,"[%04x]: edit [%04x] lost focus\n",
856 CB_HWND(lphc), lphc->hWndEdit );
858 /* NOTE: it seems that Windows' edit control sends an
859 * undocumented message WM_USER + 0x1B instead of this
860 * notification (only when it happens to be a part of
861 * the combo). ?? - AK.
864 COMBO_KillFocus( lphc );
865 break;
868 case (EN_CHANGE >> 8):
869 CB_NOTIFY( lphc, CBN_EDITCHANGE );
870 CBUpdateLBox( lphc );
871 break;
873 case (EN_UPDATE >> 8):
874 CB_NOTIFY( lphc, CBN_EDITUPDATE );
875 break;
877 case (EN_ERRSPACE >> 8):
878 CB_NOTIFY( lphc, CBN_ERRSPACE );
881 else if( lphc->hWndLBox == hWnd )
883 switch( HIWORD(wParam) )
885 case LBN_ERRSPACE:
886 CB_NOTIFY( lphc, CBN_ERRSPACE );
887 break;
889 case LBN_DBLCLK:
890 CB_NOTIFY( lphc, CBN_DBLCLK );
891 break;
893 case LBN_SELCHANGE:
894 case LBN_SELCANCEL:
896 TRACE(combo,"[%04x]: lbox selection change [%04x]\n",
897 CB_HWND(lphc), lphc->wState );
899 /* do not roll up if selection is being tracked
900 * by arrowkeys in the dropdown listbox */
902 if( (lphc->wState & CBF_DROPPED) && !(lphc->wState & CBF_NOROLLUP) )
903 CBRollUp( lphc, (HIWORD(wParam) == LBN_SELCHANGE), TRUE );
904 else lphc->wState &= ~CBF_NOROLLUP;
906 CB_NOTIFY( lphc, CBN_SELCHANGE );
907 CBPaintText( lphc, 0 );
908 /* fall through */
910 case LBN_SETFOCUS:
911 case LBN_KILLFOCUS:
912 /* nothing to do here since ComboLBox always resets the focus to its
913 * combo/edit counterpart */
914 break;
917 return 0;
920 /***********************************************************************
921 * COMBO_ItemOp
923 * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
925 static LRESULT COMBO_ItemOp32( LPHEADCOMBO lphc, UINT32 msg,
926 WPARAM32 wParam, LPARAM lParam )
928 HWND32 hWnd = lphc->self->hwndSelf;
930 TRACE(combo,"[%04x]: ownerdraw op %04x\n", CB_HWND(lphc), msg );
932 #define lpIS ((LPDELETEITEMSTRUCT32)lParam)
934 /* two first items are the same in all 4 structs */
935 lpIS->CtlType = ODT_COMBOBOX;
936 lpIS->CtlID = lphc->self->wIDmenu;
938 switch( msg ) /* patch window handle */
940 case WM_DELETEITEM:
941 lpIS->hwndItem = hWnd;
942 #undef lpIS
943 break;
944 case WM_DRAWITEM:
945 #define lpIS ((LPDRAWITEMSTRUCT32)lParam)
946 lpIS->hwndItem = hWnd;
947 #undef lpIS
948 break;
949 case WM_COMPAREITEM:
950 #define lpIS ((LPCOMPAREITEMSTRUCT32)lParam)
951 lpIS->hwndItem = hWnd;
952 #undef lpIS
953 break;
956 return SendMessage32A( lphc->owner, msg, lphc->self->wIDmenu, lParam );
959 /***********************************************************************
960 * COMBO_GetText
962 static LRESULT COMBO_GetText( LPHEADCOMBO lphc, UINT32 N, LPSTR lpText)
964 if( lphc->wState & CBF_EDIT )
965 return SendMessage32A( lphc->hWndEdit, WM_GETTEXT,
966 (WPARAM32)N, (LPARAM)lpText );
968 /* get it from the listbox */
970 if( lphc->hWndLBox )
972 INT32 idx = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 );
973 if( idx != LB_ERR )
975 LPSTR lpBuffer;
976 INT32 length = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32,
977 (WPARAM32)idx, 0 );
979 /* 'length' is without the terminating character */
980 if( length >= N )
981 lpBuffer = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1 );
982 else
983 lpBuffer = lpText;
985 if( lpBuffer )
987 INT32 n = SendMessage32A( lphc->hWndLBox, LB_GETTEXT32,
988 (WPARAM32)idx, (LPARAM)lpText );
990 /* truncate if buffer is too short */
992 if( length >= N )
994 if( n != LB_ERR ) memcpy( lpText, lpBuffer, (N>n) ? n+1 : N-1 );
995 lpText[N - 1] = '\0';
996 HeapFree( GetProcessHeap(), 0, lpBuffer );
998 return (LRESULT)n;
1002 return 0;
1006 /***********************************************************************
1007 * CBResetPos
1009 * This function sets window positions according to the updated
1010 * component placement struct.
1012 static void CBResetPos( LPHEADCOMBO lphc, LPRECT32 lbRect, BOOL32 bRedraw )
1014 BOOL32 bDrop = (CB_GETTYPE(lphc) != CBS_SIMPLE);
1016 /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
1017 * sizing messages */
1019 if( lphc->wState & CBF_EDIT )
1020 SetWindowPos32( lphc->hWndEdit, 0, lphc->RectEdit.left, lphc->RectEdit.top,
1021 lphc->RectEdit.right - lphc->RectEdit.left,
1022 lphc->RectEdit.bottom - lphc->RectEdit.top,
1023 SWP_NOZORDER | SWP_NOACTIVATE | ((bDrop) ? SWP_NOREDRAW : 0) );
1025 if( bDrop )
1026 OffsetRect32( lbRect, lphc->RectCombo.left, lphc->RectCombo.top );
1028 lbRect->right -= lbRect->left; /* convert to width */
1029 lbRect->bottom -= lbRect->top;
1030 SetWindowPos32( lphc->hWndLBox, 0, lbRect->left, lbRect->top,
1031 lbRect->right, lbRect->bottom,
1032 SWP_NOACTIVATE | SWP_NOZORDER | ((bDrop) ? SWP_NOREDRAW : 0) );
1034 if( bDrop )
1036 if( lphc->wState & CBF_DROPPED )
1038 lphc->wState &= ~CBF_DROPPED;
1039 ShowWindow32( lphc->hWndLBox, SW_HIDE );
1042 lphc->wState |= CBF_NORESIZE;
1043 SetWindowPos32( lphc->self->hwndSelf, 0, 0, 0,
1044 lphc->RectCombo.right - lphc->RectCombo.left,
1045 lphc->RectEdit.bottom - lphc->RectEdit.top,
1046 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW );
1047 lphc->wState &= ~CBF_NORESIZE;
1049 if( bRedraw && !(lphc->wState & CBF_NOREDRAW) )
1050 RedrawWindow32( lphc->self->hwndSelf, NULL, 0,
1051 RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
1056 /***********************************************************************
1057 * COMBO_Size
1059 static void COMBO_Size( LPHEADCOMBO lphc )
1061 RECT32 rect;
1062 INT32 w, h;
1064 GetWindowRect32( lphc->self->hwndSelf, &rect );
1065 w = rect.right - rect.left; h = rect.bottom - rect.top;
1067 TRACE(combo,"w = %i, h = %i\n", w, h );
1069 /* CreateWindow() may send a bogus WM_SIZE, ignore it */
1071 if( w == (lphc->RectCombo.right - lphc->RectCombo.left) )
1072 if( (CB_GETTYPE(lphc) == CBS_SIMPLE) &&
1073 (h == (lphc->RectCombo.bottom - lphc->RectCombo.top)) )
1074 return;
1075 else if( (lphc->dwStyle & CBS_DROPDOWN) &&
1076 (h == (lphc->RectEdit.bottom - lphc->RectEdit.top)) )
1077 return;
1079 lphc->RectCombo = rect;
1080 CBCalcPlacement( lphc, &lphc->RectEdit, &lphc->RectButton, &rect );
1081 CBResetPos( lphc, &rect, TRUE );
1085 /***********************************************************************
1086 * COMBO_Font
1088 static void COMBO_Font( LPHEADCOMBO lphc, HFONT32 hFont, BOOL32 bRedraw )
1090 RECT32 rect;
1092 lphc->hFont = hFont;
1094 if( lphc->wState & CBF_EDIT )
1095 SendMessage32A( lphc->hWndEdit, WM_SETFONT, (WPARAM32)hFont, bRedraw );
1096 SendMessage32A( lphc->hWndLBox, WM_SETFONT, (WPARAM32)hFont, bRedraw );
1098 GetWindowRect32( lphc->self->hwndSelf, &rect );
1099 OffsetRect32( &lphc->RectCombo, rect.left - lphc->RectCombo.left,
1100 rect.top - lphc->RectCombo.top );
1101 CBCalcPlacement( lphc, &lphc->RectEdit,
1102 &lphc->RectButton, &rect );
1103 CBResetPos( lphc, &rect, bRedraw );
1107 /***********************************************************************
1108 * COMBO_SetItemHeight
1110 static LRESULT COMBO_SetItemHeight( LPHEADCOMBO lphc, INT32 index, INT32 height )
1112 LRESULT lRet = CB_ERR;
1114 if( index == -1 ) /* set text field height */
1116 if( height < 32768 )
1118 RECT32 rect;
1120 lphc->editHeight = height;
1121 GetWindowRect32( lphc->self->hwndSelf, &rect );
1122 OffsetRect32( &lphc->RectCombo, rect.left - lphc->RectCombo.left,
1123 rect.top - lphc->RectCombo.top );
1124 CBCalcPlacement( lphc, &lphc->RectEdit,
1125 &lphc->RectButton, &rect );
1126 CBResetPos( lphc, &rect, TRUE );
1127 lRet = height;
1130 else if ( CB_OWNERDRAWN(lphc) ) /* set listbox item height */
1131 lRet = SendMessage32A( lphc->hWndLBox, LB_SETITEMHEIGHT32,
1132 (WPARAM32)index, (LPARAM)height );
1133 return lRet;
1136 /***********************************************************************
1137 * COMBO_SelectString
1139 static LRESULT COMBO_SelectString( LPHEADCOMBO lphc, INT32 start, LPCSTR pText )
1141 INT32 index = SendMessage32A( lphc->hWndLBox, LB_SELECTSTRING32,
1142 (WPARAM32)start, (LPARAM)pText );
1143 if( index >= 0 )
1144 if( lphc->wState & CBF_EDIT )
1145 CBUpdateEdit( lphc, index );
1146 else
1147 CBPaintText( lphc, 0 );
1148 return (LRESULT)index;
1151 /***********************************************************************
1152 * COMBO_LButtonDown
1154 static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam )
1156 POINT32 pt = { LOWORD(lParam), HIWORD(lParam) };
1157 BOOL32 bButton = PtInRect32(&lphc->RectButton, pt);
1158 HWND32 hWnd = lphc->self->hwndSelf;
1160 if( (CB_GETTYPE(lphc) == CBS_DROPDOWNLIST) ||
1161 (bButton && (CB_GETTYPE(lphc) == CBS_DROPDOWN)) )
1163 lphc->wState |= CBF_BUTTONDOWN;
1164 if( lphc->wState & CBF_DROPPED )
1166 /* got a click to cancel selection */
1168 CBRollUp( lphc, TRUE, FALSE );
1169 if( !IsWindow32( hWnd ) ) return;
1171 if( lphc->wState & CBF_CAPTURE )
1173 lphc->wState &= ~CBF_CAPTURE;
1174 ReleaseCapture();
1176 lphc->wState &= ~CBF_BUTTONDOWN;
1178 else
1180 /* drop down the listbox and start tracking */
1182 lphc->wState |= CBF_CAPTURE;
1183 CBDropDown( lphc );
1184 SetCapture32( hWnd );
1186 if( bButton ) CBRepaintButton( lphc );
1190 /***********************************************************************
1191 * COMBO_LButtonUp
1193 * Release capture and stop tracking if needed.
1195 static void COMBO_LButtonUp( LPHEADCOMBO lphc, LPARAM lParam )
1197 if( lphc->wState & CBF_CAPTURE )
1199 lphc->wState &= ~CBF_CAPTURE;
1200 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
1202 INT32 index = CBUpdateLBox( lphc );
1203 CBUpdateEdit( lphc, index );
1205 ReleaseCapture();
1208 if( lphc->wState & CBF_BUTTONDOWN )
1210 lphc->wState &= ~CBF_BUTTONDOWN;
1211 CBRepaintButton( lphc );
1215 /***********************************************************************
1216 * COMBO_MouseMove
1218 * Two things to do - track combo button and release capture when
1219 * pointer goes into the listbox.
1221 static void COMBO_MouseMove( LPHEADCOMBO lphc, WPARAM32 wParam, LPARAM lParam )
1223 POINT32 pt = { LOWORD(lParam), HIWORD(lParam) };
1224 RECT32 lbRect;
1226 if( lphc->wState & CBF_BUTTONDOWN )
1228 BOOL32 bButton = PtInRect32(&lphc->RectButton, pt);
1230 if( !bButton )
1232 lphc->wState &= ~CBF_BUTTONDOWN;
1233 CBRepaintButton( lphc );
1237 GetClientRect32( lphc->hWndLBox, &lbRect );
1238 MapWindowPoints32( lphc->self->hwndSelf, lphc->hWndLBox, &pt, 1 );
1239 if( PtInRect32(&lbRect, pt) )
1241 lphc->wState &= ~CBF_CAPTURE;
1242 ReleaseCapture();
1243 if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) CBUpdateLBox( lphc );
1245 /* hand over pointer tracking */
1246 SendMessage32A( lphc->hWndLBox, WM_LBUTTONDOWN, wParam, lParam );
1251 /***********************************************************************
1252 * ComboWndProc
1254 * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/ctrl/src/combobox_15.htm
1256 LRESULT WINAPI ComboWndProc( HWND32 hwnd, UINT32 message,
1257 WPARAM32 wParam, LPARAM lParam )
1259 WND* pWnd = WIN_FindWndPtr(hwnd);
1261 if( pWnd )
1263 LPHEADCOMBO lphc = CB_GETPTR(pWnd);
1265 TRACE(combo, "[%04x]: msg %s wp %08x lp %08lx\n",
1266 pWnd->hwndSelf, SPY_GetMsgName(message), wParam, lParam );
1268 if( lphc || message == WM_NCCREATE )
1269 switch(message)
1272 /* System messages */
1274 case WM_NCCREATE:
1275 return COMBO_NCCreate(pWnd, lParam);
1277 case WM_NCDESTROY:
1278 COMBO_NCDestroy(lphc);
1279 break;
1281 case WM_CREATE:
1282 return COMBO_Create(lphc, pWnd, lParam);
1284 case WM_PAINT:
1285 /* wParam may contain a valid HDC! */
1286 return COMBO_Paint(lphc, wParam);
1288 case WM_ERASEBKGND:
1289 return TRUE;
1291 case WM_GETDLGCODE:
1292 return (LRESULT)(DLGC_WANTARROWS | DLGC_WANTCHARS);
1294 case WM_SIZE:
1295 if( lphc->hWndLBox &&
1296 !(lphc->wState & CBF_NORESIZE) ) COMBO_Size( lphc );
1297 return TRUE;
1299 case WM_SETFONT:
1300 COMBO_Font( lphc, (HFONT16)wParam, (BOOL32)lParam );
1301 return TRUE;
1303 case WM_GETFONT:
1304 return (LRESULT)lphc->hFont;
1306 case WM_SETFOCUS:
1307 if( lphc->wState & CBF_EDIT )
1308 SetFocus32( lphc->hWndEdit );
1309 else
1310 COMBO_SetFocus( lphc );
1311 return TRUE;
1313 case WM_KILLFOCUS:
1314 #define hwndFocus ((HWND16)wParam)
1315 if( !hwndFocus ||
1316 (hwndFocus != lphc->hWndEdit && hwndFocus != lphc->hWndLBox ))
1317 COMBO_KillFocus( lphc );
1318 #undef hwndFocus
1319 return TRUE;
1321 case WM_COMMAND:
1322 return COMBO_Command( lphc, wParam, (HWND32)lParam );
1324 case WM_GETTEXT:
1325 return COMBO_GetText( lphc, (UINT32)wParam, (LPSTR)lParam );
1327 case WM_SETTEXT:
1328 case WM_GETTEXTLENGTH:
1329 case WM_CLEAR:
1330 case WM_CUT:
1331 case WM_PASTE:
1332 case WM_COPY:
1333 if( lphc->wState & CBF_EDIT )
1334 return SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1335 return CB_ERR;
1337 case WM_DRAWITEM:
1338 case WM_DELETEITEM:
1339 case WM_COMPAREITEM:
1340 case WM_MEASUREITEM:
1341 return COMBO_ItemOp32( lphc, message, wParam, lParam );
1343 case WM_ENABLE:
1344 if( lphc->wState & CBF_EDIT )
1345 EnableWindow32( lphc->hWndEdit, (BOOL32)wParam );
1346 EnableWindow32( lphc->hWndLBox, (BOOL32)wParam );
1347 return TRUE;
1349 case WM_SETREDRAW:
1350 if( wParam )
1351 lphc->wState &= ~CBF_NOREDRAW;
1352 else
1353 lphc->wState |= CBF_NOREDRAW;
1355 if( lphc->wState & CBF_EDIT )
1356 SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1357 SendMessage32A( lphc->hWndLBox, message, wParam, lParam );
1358 return 0;
1360 case WM_SYSKEYDOWN:
1361 if( KEYDATA_ALT & HIWORD(lParam) )
1362 if( wParam == VK_UP || wParam == VK_DOWN )
1363 COMBO_FlipListbox( lphc, TRUE );
1364 break;
1366 case WM_CHAR:
1367 case WM_KEYDOWN:
1368 if( lphc->wState & CBF_EDIT )
1369 return SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1370 else
1371 return SendMessage32A( lphc->hWndLBox, message, wParam, lParam );
1373 case WM_LBUTTONDOWN:
1374 if( !(lphc->wState & CBF_FOCUSED) ) SetFocus32( lphc->self->hwndSelf );
1375 if( lphc->wState & CBF_FOCUSED ) COMBO_LButtonDown( lphc, lParam );
1376 return TRUE;
1378 case WM_LBUTTONUP:
1379 COMBO_LButtonUp( lphc, lParam );
1380 return TRUE;
1382 case WM_MOUSEMOVE:
1383 if( lphc->wState & CBF_CAPTURE )
1384 COMBO_MouseMove( lphc, wParam, lParam );
1385 return TRUE;
1387 /* Combo messages */
1389 case CB_ADDSTRING16:
1390 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1391 case CB_ADDSTRING32:
1392 return SendMessage32A( lphc->hWndLBox, LB_ADDSTRING32, 0, lParam);
1394 case CB_INSERTSTRING16:
1395 wParam = (INT32)(INT16)wParam;
1396 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1397 case CB_INSERTSTRING32:
1398 return SendMessage32A( lphc->hWndLBox, LB_INSERTSTRING32, wParam, lParam);
1400 case CB_DELETESTRING16:
1401 case CB_DELETESTRING32:
1402 return SendMessage32A( lphc->hWndLBox, LB_DELETESTRING32, wParam, 0);
1404 case CB_SELECTSTRING16:
1405 wParam = (INT32)(INT16)wParam;
1406 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1407 case CB_SELECTSTRING32:
1408 return COMBO_SelectString( lphc, (INT32)wParam, (LPSTR)lParam );
1410 case CB_FINDSTRING16:
1411 wParam = (INT32)(INT16)wParam;
1412 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1413 case CB_FINDSTRING32:
1414 return SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32, wParam, lParam);
1416 case CB_FINDSTRINGEXACT16:
1417 wParam = (INT32)(INT16)wParam;
1418 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1419 case CB_FINDSTRINGEXACT32:
1420 return SendMessage32A( lphc->hWndLBox, LB_FINDSTRINGEXACT32,
1421 wParam, lParam );
1422 case CB_SETITEMHEIGHT16:
1423 wParam = (INT32)(INT16)wParam;
1424 case CB_SETITEMHEIGHT32:
1425 return COMBO_SetItemHeight( lphc, (INT32)wParam, (INT32)lParam);
1427 case CB_RESETCONTENT16:
1428 case CB_RESETCONTENT32:
1429 SendMessage32A( lphc->hWndLBox, LB_RESETCONTENT32, 0, 0 );
1430 CBPaintText( lphc, 0 );
1431 return TRUE;
1433 case CB_INITSTORAGE32:
1434 return SendMessage32A( lphc->hWndLBox, LB_INITSTORAGE32, wParam, lParam);
1436 case CB_GETHORIZONTALEXTENT32:
1437 return SendMessage32A( lphc->hWndLBox, LB_GETHORIZONTALEXTENT32, 0, 0);
1439 case CB_SETHORIZONTALEXTENT32:
1440 return SendMessage32A( lphc->hWndLBox, LB_SETHORIZONTALEXTENT32, wParam, 0);
1442 case CB_GETTOPINDEX32:
1443 return SendMessage32A( lphc->hWndLBox, LB_GETTOPINDEX32, 0, 0);
1445 case CB_GETLOCALE32:
1446 return SendMessage32A( lphc->hWndLBox, LB_GETLOCALE32, 0, 0);
1448 case CB_SETLOCALE32:
1449 return SendMessage32A( lphc->hWndLBox, LB_SETLOCALE32, wParam, 0);
1451 case CB_GETDROPPEDWIDTH32:
1452 if( lphc->droppedWidth )
1453 return lphc->droppedWidth;
1454 return lphc->RectCombo.right - lphc->RectCombo.left -
1455 (lphc->wState & CBF_EDIT) ? CBitOffset : 0;
1457 case CB_SETDROPPEDWIDTH32:
1458 if( (CB_GETTYPE(lphc) != CBS_SIMPLE) &&
1459 (INT32)wParam < 32768 ) lphc->droppedWidth = (INT32)wParam;
1460 return CB_ERR;
1462 case CB_GETDROPPEDCONTROLRECT16:
1463 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1464 if( lParam )
1466 RECT32 r;
1467 CBGetDroppedControlRect32( lphc, &r );
1468 CONV_RECT32TO16( &r, (LPRECT16)lParam );
1470 return CB_OKAY;
1472 case CB_GETDROPPEDCONTROLRECT32:
1473 if( lParam ) CBGetDroppedControlRect32(lphc, (LPRECT32)lParam );
1474 return CB_OKAY;
1476 case CB_GETDROPPEDSTATE16:
1477 case CB_GETDROPPEDSTATE32:
1478 return (lphc->wState & CBF_DROPPED) ? TRUE : FALSE;
1480 case CB_DIR16:
1481 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1482 /* fall through */
1483 case CB_DIR32:
1484 return COMBO_Directory( lphc, (UINT32)wParam,
1485 (LPSTR)lParam, (message == CB_DIR32));
1486 case CB_SHOWDROPDOWN16:
1487 case CB_SHOWDROPDOWN32:
1488 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
1489 if( wParam )
1491 if( !(lphc->wState & CBF_DROPPED) )
1492 CBDropDown( lphc );
1494 else
1495 if( lphc->wState & CBF_DROPPED )
1496 CBRollUp( lphc, FALSE, TRUE );
1497 return TRUE;
1499 case CB_GETCOUNT16:
1500 case CB_GETCOUNT32:
1501 return SendMessage32A( lphc->hWndLBox, LB_GETCOUNT32, 0, 0);
1503 case CB_GETCURSEL16:
1504 case CB_GETCURSEL32:
1505 return SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0);
1507 case CB_SETCURSEL16:
1508 wParam = (INT32)(INT16)wParam;
1509 case CB_SETCURSEL32:
1510 return SendMessage32A( lphc->hWndLBox, LB_SETCURSEL32, wParam, 0);
1512 case CB_GETLBTEXT16:
1513 wParam = (INT32)(INT16)wParam;
1514 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1515 case CB_GETLBTEXT32:
1516 return SendMessage32A( lphc->hWndLBox, LB_GETTEXT32, wParam, lParam);
1518 case CB_GETLBTEXTLEN16:
1519 wParam = (INT32)(INT16)wParam;
1520 case CB_GETLBTEXTLEN32:
1521 return SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, wParam, 0);
1523 case CB_GETITEMDATA16:
1524 wParam = (INT32)(INT16)wParam;
1525 case CB_GETITEMDATA32:
1526 return SendMessage32A( lphc->hWndLBox, LB_GETITEMDATA32, wParam, 0);
1528 case CB_SETITEMDATA16:
1529 wParam = (INT32)(INT16)wParam;
1530 case CB_SETITEMDATA32:
1531 return SendMessage32A( lphc->hWndLBox, LB_SETITEMDATA32, wParam, lParam);
1533 case CB_GETEDITSEL16:
1534 wParam = lParam = 0; /* just in case */
1535 case CB_GETEDITSEL32:
1536 if( lphc->wState & CBF_EDIT )
1538 INT32 a, b;
1540 return SendMessage32A( lphc->hWndEdit, EM_GETSEL32,
1541 (wParam) ? wParam : (WPARAM32)&a,
1542 (lParam) ? lParam : (LPARAM)&b );
1544 return CB_ERR;
1546 case CB_SETEDITSEL16:
1547 case CB_SETEDITSEL32:
1548 if( lphc->wState & CBF_EDIT )
1549 return SendMessage32A( lphc->hWndEdit, EM_SETSEL32,
1550 (INT32)(INT16)LOWORD(lParam), (INT32)(INT16)HIWORD(lParam) );
1551 return CB_ERR;
1553 case CB_SETEXTENDEDUI16:
1554 case CB_SETEXTENDEDUI32:
1555 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) return CB_ERR;
1557 if( wParam )
1558 lphc->wState |= CBF_EUI;
1559 else lphc->wState &= ~CBF_EUI;
1560 return CB_OKAY;
1562 case CB_GETEXTENDEDUI16:
1563 case CB_GETEXTENDEDUI32:
1564 return (lphc->wState & CBF_EUI) ? TRUE : FALSE;
1566 case (WM_USER + 0x1B):
1567 WARN(combo, "[%04x]: undocumented msg!\n", hwnd );
1569 return DefWindowProc32A(hwnd, message, wParam, lParam);
1571 return CB_ERR;