Release 980822
[wine/multimedia.git] / controls / combo.c
blob1b8e1d73033cfe274f6dfce8c11e3333e10e607f
1 /*
2 * Combo controls
3 *
4 * Copyright 1997 Alex Korobka
5 *
6 * FIXME: roll up in Netscape 3.01.
7 */
9 #include <string.h>
11 #include "windows.h"
12 #include "sysmetrics.h"
13 #include "win.h"
14 #include "spy.h"
15 #include "user.h"
16 #include "graphics.h"
17 #include "heap.h"
18 #include "combo.h"
19 #include "drive.h"
20 #include "debug.h"
22 /* bits in the dwKeyData */
23 #define KEYDATA_ALT 0x2000
24 #define KEYDATA_PREVSTATE 0x4000
27 * Additional combo box definitions
30 #define CB_GETPTR( wnd ) (*(LPHEADCOMBO*)((wnd)->wExtra))
31 #define CB_NOTIFY( lphc, code ) \
32 (SendMessage32A( (lphc)->owner, WM_COMMAND, \
33 MAKEWPARAM((lphc)->self->wIDmenu, (code)), (lphc)->self->hwndSelf))
34 #define CB_GETEDITTEXTLENGTH( lphc ) \
35 (SendMessage32A( (lphc)->hWndEdit, WM_GETTEXTLENGTH, 0, 0 ))
37 static HBITMAP32 hComboBmp = 0;
38 static UINT32 CBitHeight, CBitWidth;
39 static UINT32 CBitOffset = 8;
41 /***********************************************************************
42 * COMBO_Init
44 * Load combo button bitmap.
46 static BOOL32 COMBO_Init()
48 HDC32 hDC;
50 if( hComboBmp ) return TRUE;
51 if( (hDC = CreateCompatibleDC32(0)) )
53 BOOL32 bRet = FALSE;
54 if( (hComboBmp = LoadBitmap32A(0, MAKEINTRESOURCE32A(OBM_COMBO))) )
56 BITMAP32 bm;
57 HBITMAP32 hPrevB;
58 RECT32 r;
60 GetObject32A( hComboBmp, sizeof(bm), &bm );
61 CBitHeight = bm.bmHeight;
62 CBitWidth = bm.bmWidth;
64 TRACE(combo, "combo bitmap [%i,%i]\n", CBitWidth, CBitHeight );
66 hPrevB = SelectObject16( hDC, hComboBmp);
67 SetRect32( &r, 0, 0, CBitWidth, CBitHeight );
68 InvertRect32( hDC, &r );
69 SelectObject32( hDC, hPrevB );
70 bRet = TRUE;
72 DeleteDC32( hDC );
73 return bRet;
75 return FALSE;
78 /***********************************************************************
79 * COMBO_NCCreate
81 static LRESULT COMBO_NCCreate(WND* wnd, LPARAM lParam)
83 LPHEADCOMBO lphc;
85 if ( wnd && COMBO_Init() &&
86 (lphc = HeapAlloc(GetProcessHeap(), 0, sizeof(HEADCOMBO))) )
88 LPCREATESTRUCT32A lpcs = (CREATESTRUCT32A*)lParam;
90 memset( lphc, 0, sizeof(HEADCOMBO) );
91 *(LPHEADCOMBO*)wnd->wExtra = lphc;
93 /* some braindead apps do try to use scrollbar/border flags */
95 lphc->dwStyle = (lpcs->style & ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL));
96 wnd->dwStyle &= ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL);
98 if( !(lpcs->style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) )
99 lphc->dwStyle |= CBS_HASSTRINGS;
100 if( !(wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) )
101 lphc->wState |= CBF_NOTIFY;
103 TRACE(combo, "[0x%08x], style = %08x\n",
104 (UINT32)lphc, lphc->dwStyle );
106 return (LRESULT)(UINT32)wnd->hwndSelf;
108 return (LRESULT)FALSE;
111 /***********************************************************************
112 * COMBO_NCDestroy
114 static LRESULT COMBO_NCDestroy( LPHEADCOMBO lphc )
117 if( lphc )
119 WND* wnd = lphc->self;
121 TRACE(combo,"[%04x]: freeing storage\n", CB_HWND(lphc));
123 if( (CB_GETTYPE(lphc) != CBS_SIMPLE) && lphc->hWndLBox )
124 DestroyWindow32( lphc->hWndLBox );
126 HeapFree( GetProcessHeap(), 0, lphc );
127 wnd->wExtra[0] = 0;
129 return 0;
132 /***********************************************************************
133 * CBCalcPlacement
135 * Set up component coordinates given valid lphc->RectCombo.
137 static void CBCalcPlacement( LPHEADCOMBO lphc, LPRECT32 lprEdit,
138 LPRECT32 lprButton, LPRECT32 lprLB )
140 RECT32 rect = lphc->RectCombo;
141 SIZE32 size;
143 /* get combo height and width */
145 if( lphc->editHeight )
146 size.cy = lphc->editHeight;
147 else
149 HDC32 hDC = GetDC32( lphc->self->hwndSelf );
150 HFONT32 hPrevFont = 0;
152 if( lphc->hFont ) hPrevFont = SelectObject32( hDC, lphc->hFont );
154 GetTextExtentPoint32A( hDC, "0", 1, &size);
156 size.cy += size.cy / 4 + 4 * SYSMETRICS_CYBORDER;
158 if( hPrevFont ) SelectObject32( hDC, hPrevFont );
159 ReleaseDC32( lphc->self->hwndSelf, hDC );
161 size.cx = rect.right - rect.left;
163 if( CB_OWNERDRAWN(lphc) )
165 UINT32 u = lphc->RectEdit.bottom - lphc->RectEdit.top;
167 if( lphc->wState & CBF_MEASUREITEM ) /* first initialization */
169 MEASUREITEMSTRUCT32 mi32;
171 lphc->wState &= ~CBF_MEASUREITEM;
172 mi32.CtlType = ODT_COMBOBOX;
173 mi32.CtlID = lphc->self->wIDmenu;
174 mi32.itemID = -1;
175 mi32.itemWidth = size.cx;
176 mi32.itemHeight = size.cy - 6; /* ownerdrawn cb is taller */
177 mi32.itemData = 0;
178 SendMessage32A(lphc->owner, WM_MEASUREITEM,
179 (WPARAM32)mi32.CtlID, (LPARAM)&mi32);
180 u = 6 + (UINT16)mi32.itemHeight;
182 size.cy = u;
185 /* calculate text and button placement */
187 lprEdit->left = lprEdit->top = lprButton->top = 0;
188 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) /* no button */
189 lprButton->left = lprButton->right = lprButton->bottom = 0;
190 else
192 INT32 i = size.cx - CBitWidth - 10; /* seems ok */
194 lprButton->right = size.cx;
195 lprButton->left = (INT16)i;
196 lprButton->bottom = lprButton->top + size.cy;
198 if( i < 0 ) size.cx = 0;
199 else size.cx = i;
202 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
204 size.cx -= CBitOffset;
205 if( size.cx < 0 ) size.cx = 0;
208 lprEdit->right = size.cx; lprEdit->bottom = size.cy;
210 /* listbox placement */
212 lprLB->left = ( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) ? 0 : CBitOffset;
213 lprLB->top = lprEdit->bottom - SYSMETRICS_CYBORDER;
214 lprLB->right = rect.right - rect.left;
215 lprLB->bottom = rect.bottom - rect.top;
217 if( lphc->droppedWidth > (lprLB->right - lprLB->left) )
218 lprLB->right = lprLB->left + lphc->droppedWidth;
220 TRACE(combo,"[%04x]: (%i,%i-%i,%i) placement\n",
221 CB_HWND(lphc), lphc->RectCombo.left, lphc->RectCombo.top,
222 lphc->RectCombo.right, lphc->RectCombo.bottom);
224 TRACE(combo,"\ttext\t= (%i,%i-%i,%i)\n",
225 lprEdit->left, lprEdit->top, lprEdit->right, lprEdit->bottom);
227 TRACE(combo,"\tbutton\t= (%i,%i-%i,%i)\n",
228 lprButton->left, lprButton->top, lprButton->right, lprButton->bottom);
230 TRACE(combo,"\tlbox\t= (%i,%i-%i,%i)\n",
231 lprLB->left, lprLB->top, lprLB->right, lprLB->bottom );
234 /***********************************************************************
235 * CBGetDroppedControlRect32
237 static void CBGetDroppedControlRect32( LPHEADCOMBO lphc, LPRECT32 lpRect)
239 lpRect->left = lphc->RectCombo.left +
240 (lphc->wState & CBF_EDIT) ? CBitOffset : 0;
241 lpRect->top = lphc->RectCombo.top + lphc->RectEdit.bottom -
242 SYSMETRICS_CYBORDER;
243 lpRect->right = lphc->RectCombo.right;
244 lpRect->bottom = lphc->RectCombo.bottom - SYSMETRICS_CYBORDER;
247 /***********************************************************************
248 * COMBO_Create
250 static LRESULT COMBO_Create( LPHEADCOMBO lphc, WND* wnd, LPARAM lParam)
252 static char clbName[] = "ComboLBox";
253 static char editName[] = "Edit";
255 LPCREATESTRUCT32A lpcs = (CREATESTRUCT32A*)lParam;
257 if( !CB_GETTYPE(lphc) ) lphc->dwStyle |= CBS_SIMPLE;
258 else if( CB_GETTYPE(lphc) != CBS_DROPDOWNLIST ) lphc->wState |= CBF_EDIT;
260 lphc->self = wnd;
261 lphc->owner = lpcs->hwndParent;
263 /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */
265 if( lphc->owner || !(lpcs->style & WS_VISIBLE) )
267 UINT32 lbeStyle;
268 RECT32 editRect, btnRect, lbRect;
270 GetWindowRect32( wnd->hwndSelf, &lphc->RectCombo );
272 lphc->wState |= CBF_MEASUREITEM;
273 CBCalcPlacement( lphc, &editRect, &btnRect, &lbRect );
274 lphc->RectButton = btnRect;
275 lphc->droppedWidth = lphc->editHeight = 0;
277 /* create listbox popup */
279 lbeStyle = (LBS_NOTIFY | WS_BORDER | WS_CLIPSIBLINGS) |
280 (lpcs->style & (WS_VSCROLL | CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE));
282 if( lphc->dwStyle & CBS_SORT )
283 lbeStyle |= LBS_SORT;
284 if( lphc->dwStyle & CBS_HASSTRINGS )
285 lbeStyle |= LBS_HASSTRINGS;
286 if( lphc->dwStyle & CBS_NOINTEGRALHEIGHT )
287 lbeStyle |= LBS_NOINTEGRALHEIGHT;
288 if( lphc->dwStyle & CBS_DISABLENOSCROLL )
289 lbeStyle |= LBS_DISABLENOSCROLL;
291 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) /* child listbox */
292 lbeStyle |= WS_CHILD | WS_VISIBLE;
293 else /* popup listbox */
295 lbeStyle |= WS_POPUP;
296 OffsetRect32( &lbRect, lphc->RectCombo.left, lphc->RectCombo.top );
299 /* Dropdown ComboLBox is not a child window and we cannot pass
300 * ID_CB_LISTBOX directly because it will be treated as a menu handle.
303 lphc->hWndLBox = CreateWindowEx32A( 0, clbName, NULL, lbeStyle,
304 lbRect.left + SYSMETRICS_CXBORDER,
305 lbRect.top + SYSMETRICS_CYBORDER,
306 lbRect.right - lbRect.left - 2 * SYSMETRICS_CXBORDER,
307 lbRect.bottom - lbRect.top - 2 * SYSMETRICS_CYBORDER,
308 lphc->self->hwndSelf,
309 (lphc->dwStyle & CBS_DROPDOWN)? (HMENU32)0 : (HMENU32)ID_CB_LISTBOX,
310 lphc->self->hInstance, (LPVOID)lphc );
311 if( lphc->hWndLBox )
313 BOOL32 bEdit = TRUE;
314 lbeStyle = WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NOHIDESEL | ES_LEFT;
315 if( lphc->wState & CBF_EDIT )
317 if( lphc->dwStyle & CBS_OEMCONVERT )
318 lbeStyle |= ES_OEMCONVERT;
319 if( lphc->dwStyle & CBS_AUTOHSCROLL )
320 lbeStyle |= ES_AUTOHSCROLL;
321 if( lphc->dwStyle & CBS_LOWERCASE )
322 lbeStyle |= ES_LOWERCASE;
323 else if( lphc->dwStyle & CBS_UPPERCASE )
324 lbeStyle |= ES_UPPERCASE;
325 lphc->hWndEdit = CreateWindowEx32A( 0, editName, NULL, lbeStyle,
326 editRect.left, editRect.top, editRect.right - editRect.left,
327 editRect.bottom - editRect.top, lphc->self->hwndSelf,
328 (HMENU32)ID_CB_EDIT, lphc->self->hInstance, NULL );
329 if( !lphc->hWndEdit ) bEdit = FALSE;
332 if( bEdit )
334 lphc->RectEdit = editRect;
335 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
337 lphc->wState |= CBF_NORESIZE;
338 SetWindowPos32( wnd->hwndSelf, 0, 0, 0,
339 lphc->RectCombo.right - lphc->RectCombo.left,
340 lphc->RectEdit.bottom - lphc->RectEdit.top,
341 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
342 lphc->wState &= ~CBF_NORESIZE;
344 TRACE(combo,"init done\n");
345 return wnd->hwndSelf;
347 ERR(combo, "edit control failure.\n");
348 } else ERR(combo, "listbox failure.\n");
349 } else ERR(combo, "no owner for visible combo.\n");
351 /* CreateWindow() will send WM_NCDESTROY to cleanup */
353 return -1;
356 /***********************************************************************
357 * CBPaintButton
359 * Paint combo button (normal, pressed, and disabled states).
361 static void CBPaintButton(LPHEADCOMBO lphc, HDC32 hdc)
363 RECT32 r;
364 HBRUSH32 hPrevBrush;
365 UINT32 x, y;
366 BOOL32 bBool;
368 if( lphc->wState & CBF_NOREDRAW ) return;
370 hPrevBrush = (HBRUSH32)SelectObject32(hdc, GetSysColorBrush32(COLOR_BTNFACE));
371 CONV_RECT16TO32( &lphc->RectButton, &r );
373 Rectangle32(hdc, r.left, r.top, r.right, r.bottom );
374 InflateRect32( &r, -1, -1 );
375 if( (bBool = lphc->wState & CBF_BUTTONDOWN) )
377 GRAPH_DrawReliefRect(hdc, &r, 1, 0, TRUE);
378 OffsetRect32( &r, 1, 1 );
379 } else GRAPH_DrawReliefRect(hdc, &r, 1, 2, FALSE);
381 x = (r.left + r.right - CBitWidth) >> 1;
382 y = (r.top + r.bottom - CBitHeight) >> 1;
384 InflateRect32( &r, -3, -3 );
385 if( (bBool = CB_DISABLED(lphc)) )
387 GRAPH_SelectClipMask(hdc, hComboBmp, x + 1, y + 1 );
388 FillRect32(hdc, &r, (HBRUSH32)GetStockObject32(WHITE_BRUSH));
391 GRAPH_SelectClipMask(hdc, hComboBmp, x, y );
392 FillRect32(hdc, &r, (HBRUSH32)GetStockObject32((bBool) ? GRAY_BRUSH : BLACK_BRUSH));
394 GRAPH_SelectClipMask(hdc, (HBITMAP32)0, 0, 0);
395 SelectObject32( hdc, hPrevBrush );
398 /***********************************************************************
399 * CBPaintText
401 * Paint CBS_DROPDOWNLIST text field / update edit control contents.
403 static void CBPaintText(LPHEADCOMBO lphc, HDC32 hdc)
405 INT32 id, size = 0;
406 LPSTR pText = NULL;
408 if( lphc->wState & CBF_NOREDRAW ) return;
410 /* follow Windows combobox that sends a bunch of text
411 * inquiries to its listbox while processing WM_PAINT. */
413 if( (id = SendMessage32A(lphc->hWndLBox, LB_GETCURSEL32, 0, 0) ) != LB_ERR )
415 size = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, id, 0);
416 if( (pText = HeapAlloc( GetProcessHeap(), 0, size + 1)) )
418 SendMessage32A( lphc->hWndLBox, LB_GETTEXT32, (WPARAM32)id, (LPARAM)pText );
419 pText[size] = '\0'; /* just in case */
420 } else return;
423 if( lphc->wState & CBF_EDIT )
425 if( CB_HASSTRINGS(lphc) ) SetWindowText32A( lphc->hWndEdit, pText );
426 if( lphc->wState & CBF_FOCUSED )
427 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1));
429 else /* paint text field ourselves */
431 HBRUSH32 hPrevBrush = 0;
432 HDC32 hDC = hdc;
434 if( !hDC )
436 if ((hDC = GetDC32(lphc->self->hwndSelf)))
438 HBRUSH32 hBrush = SendMessage32A( lphc->owner,
439 WM_CTLCOLORLISTBOX,
440 hDC, lphc->self->hwndSelf );
441 hPrevBrush = SelectObject32( hDC,
442 (hBrush) ? hBrush : GetStockObject32(WHITE_BRUSH) );
445 if( hDC )
447 RECT32 rect;
448 UINT32 itemState;
449 HFONT32 hPrevFont = (lphc->hFont) ? SelectObject32(hDC, lphc->hFont) : 0;
451 PatBlt32( hDC, (rect.left = lphc->RectEdit.left + SYSMETRICS_CXBORDER),
452 (rect.top = lphc->RectEdit.top + SYSMETRICS_CYBORDER),
453 (rect.right = lphc->RectEdit.right - SYSMETRICS_CXBORDER),
454 (rect.bottom = lphc->RectEdit.bottom - SYSMETRICS_CYBORDER) - 1, PATCOPY );
455 InflateRect32( &rect, -1, -1 );
457 if( lphc->wState & CBF_FOCUSED &&
458 !(lphc->wState & CBF_DROPPED) )
460 /* highlight */
462 FillRect32( hDC, &rect, GetSysColorBrush32(COLOR_HIGHLIGHT) );
463 SetBkColor32( hDC, GetSysColor32( COLOR_HIGHLIGHT ) );
464 SetTextColor32( hDC, GetSysColor32( COLOR_HIGHLIGHTTEXT ) );
465 itemState = ODS_SELECTED | ODS_FOCUS;
466 } else itemState = 0;
468 if( CB_OWNERDRAWN(lphc) )
470 DRAWITEMSTRUCT32 dis;
472 if( lphc->self->dwStyle & WS_DISABLED ) itemState |= ODS_DISABLED;
474 dis.CtlType = ODT_COMBOBOX;
475 dis.CtlID = lphc->self->wIDmenu;
476 dis.hwndItem = lphc->self->hwndSelf;
477 dis.itemAction = ODA_DRAWENTIRE;
478 dis.itemID = id;
479 dis.itemState = itemState;
480 dis.hDC = hDC;
481 dis.rcItem = rect;
482 dis.itemData = SendMessage32A( lphc->hWndLBox, LB_GETITEMDATA32,
483 (WPARAM32)id, 0 );
484 SendMessage32A( lphc->owner, WM_DRAWITEM,
485 lphc->self->wIDmenu, (LPARAM)&dis );
487 else
489 ExtTextOut32A( hDC, rect.left + 1, rect.top + 1,
490 ETO_OPAQUE | ETO_CLIPPED, &rect,
491 (pText) ? pText : "" , size, NULL );
492 if(lphc->wState & CBF_FOCUSED && !(lphc->wState & CBF_DROPPED))
493 DrawFocusRect32( hDC, &rect );
496 if( hPrevFont ) SelectObject32(hDC, hPrevFont );
497 if( !hdc )
499 if( hPrevBrush ) SelectObject32( hDC, hPrevBrush );
500 ReleaseDC32( lphc->self->hwndSelf, hDC );
504 HeapFree( GetProcessHeap(), 0, pText );
507 /***********************************************************************
508 * COMBO_Paint
510 static LRESULT COMBO_Paint(LPHEADCOMBO lphc, HDC32 hParamDC)
512 PAINTSTRUCT32 ps;
513 HDC32 hDC;
515 hDC = (hParamDC) ? hParamDC
516 : BeginPaint32( lphc->self->hwndSelf, &ps);
517 if( hDC && !(lphc->wState & CBF_NOREDRAW) )
519 HBRUSH32 hPrevBrush, hBkgBrush;
521 hBkgBrush = SendMessage32A( lphc->owner, WM_CTLCOLORLISTBOX,
522 hDC, lphc->self->hwndSelf );
523 if( !hBkgBrush ) hBkgBrush = GetStockObject32(WHITE_BRUSH);
525 hPrevBrush = SelectObject32( hDC, hBkgBrush );
526 if( !IsRectEmpty32(&lphc->RectButton) )
528 /* paint everything to the right of the text field */
530 PatBlt32( hDC, lphc->RectEdit.right, lphc->RectEdit.top,
531 lphc->RectButton.right - lphc->RectEdit.right,
532 lphc->RectEdit.bottom - lphc->RectEdit.top, PATCOPY );
533 CBPaintButton( lphc, hDC );
536 if( !(lphc->wState & CBF_EDIT) )
538 /* paint text field */
540 GRAPH_DrawRectangle( hDC, lphc->RectEdit.left, lphc->RectEdit.top,
541 lphc->RectEdit.right - lphc->RectEdit.left,
542 lphc->RectButton.bottom - lphc->RectButton.top,
543 GetSysColorPen32(COLOR_WINDOWFRAME) );
544 CBPaintText( lphc, hDC );
546 if( hPrevBrush ) SelectObject32( hDC, hPrevBrush );
548 if( !hParamDC ) EndPaint32(lphc->self->hwndSelf, &ps);
549 return 0;
552 /***********************************************************************
553 * CBUpdateLBox
555 * Select listbox entry according to the contents of the edit control.
557 static INT32 CBUpdateLBox( LPHEADCOMBO lphc )
559 INT32 length, idx, ret;
560 LPSTR pText = NULL;
562 idx = ret = LB_ERR;
563 length = CB_GETEDITTEXTLENGTH( lphc );
565 if( length > 0 )
566 pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1);
568 TRACE(combo,"\t edit text length %i\n", length );
570 if( pText )
572 if( length ) GetWindowText32A( lphc->hWndEdit, pText, length + 1);
573 else pText[0] = '\0';
574 idx = SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32,
575 (WPARAM32)(-1), (LPARAM)pText );
576 if( idx == LB_ERR ) idx = 0; /* select first item */
577 else ret = idx;
578 HeapFree( GetProcessHeap(), 0, pText );
581 /* select entry */
583 SendMessage32A( lphc->hWndLBox, LB_SETCURSEL32, (WPARAM32)idx, 0 );
585 if( idx >= 0 )
587 SendMessage32A( lphc->hWndLBox, LB_SETTOPINDEX32, (WPARAM32)idx, 0 );
588 /* probably superfluous but Windows sends this too */
589 SendMessage32A( lphc->hWndLBox, LB_SETCARETINDEX32, (WPARAM32)idx, 0 );
591 return ret;
594 /***********************************************************************
595 * CBUpdateEdit
597 * Copy a listbox entry to the edit control.
599 static void CBUpdateEdit( LPHEADCOMBO lphc , INT32 index )
601 INT32 length;
602 LPSTR pText = NULL;
604 TRACE(combo,"\t %i\n", index );
606 if( index == -1 )
608 length = CB_GETEDITTEXTLENGTH( lphc );
609 if( length )
611 if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) )
613 GetWindowText32A( lphc->hWndEdit, pText, length + 1 );
614 index = SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32,
615 (WPARAM32)(-1), (LPARAM)pText );
616 HeapFree( GetProcessHeap(), 0, pText );
621 if( index >= 0 ) /* got an entry */
623 length = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, (WPARAM32)index, 0);
624 if( length )
626 if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) )
628 SendMessage32A( lphc->hWndLBox, LB_GETTEXT32,
629 (WPARAM32)index, (LPARAM)pText );
630 SendMessage32A( lphc->hWndEdit, WM_SETTEXT, 0, (LPARAM)pText );
631 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1) );
632 HeapFree( GetProcessHeap(), 0, pText );
638 /***********************************************************************
639 * CBDropDown
641 * Show listbox popup.
643 static void CBDropDown( LPHEADCOMBO lphc )
645 INT32 index;
646 RECT32 rect;
647 LPRECT32 pRect = NULL;
649 TRACE(combo,"[%04x]: drop down\n", CB_HWND(lphc));
651 CB_NOTIFY( lphc, CBN_DROPDOWN );
653 /* set selection */
655 lphc->wState |= CBF_DROPPED;
656 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
658 index = CBUpdateLBox( lphc );
659 if( !(lphc->wState & CBF_CAPTURE) ) CBUpdateEdit( lphc, index );
661 else
663 index = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 );
664 if( index == LB_ERR ) index = 0;
665 SendMessage32A( lphc->hWndLBox, LB_SETTOPINDEX32, (WPARAM32)index, 0 );
666 SendMessage32A( lphc->hWndLBox, LB_CARETON32, 0, 0 );
667 pRect = &lphc->RectEdit;
670 /* now set popup position */
672 GetWindowRect32( lphc->self->hwndSelf, &rect );
674 rect.top += lphc->RectEdit.bottom - lphc->RectEdit.top - SYSMETRICS_CYBORDER;
675 rect.bottom = rect.top + lphc->RectCombo.bottom -
676 lphc->RectCombo.top - SYSMETRICS_CYBORDER;
677 rect.right = rect.left + lphc->RectCombo.right - lphc->RectCombo.left;
678 rect.left += ( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) ? 0 : CBitOffset;
680 SetWindowPos32( lphc->hWndLBox, HWND_TOP, rect.left, rect.top,
681 rect.right - rect.left, rect.bottom - rect.top,
682 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOREDRAW);
684 if( !(lphc->wState & CBF_NOREDRAW) )
685 if( pRect )
686 RedrawWindow32( lphc->self->hwndSelf, pRect, 0, RDW_INVALIDATE |
687 RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
688 ShowWindow32( lphc->hWndLBox, SW_SHOWNA );
691 /***********************************************************************
692 * CBRollUp
694 * Hide listbox popup.
696 static void CBRollUp( LPHEADCOMBO lphc, BOOL32 ok, BOOL32 bButton )
698 HWND32 hWnd = lphc->self->hwndSelf;
700 CB_NOTIFY( lphc, (ok) ? CBN_SELENDOK : CBN_SELENDCANCEL );
702 if( IsWindow32( hWnd ) && CB_GETTYPE(lphc) != CBS_SIMPLE )
705 TRACE(combo,"[%04x]: roll up [%i]\n", CB_HWND(lphc), (INT32)ok );
707 /* always send WM_LBUTTONUP? */
708 SendMessage32A( lphc->hWndLBox, WM_LBUTTONUP, 0, (LPARAM)(-1) );
710 if( lphc->wState & CBF_DROPPED )
712 RECT32 rect;
714 lphc->wState &= ~CBF_DROPPED;
715 ShowWindow32( lphc->hWndLBox, SW_HIDE );
717 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
719 INT32 index = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 );
720 CBUpdateEdit( lphc, index );
721 rect = lphc->RectButton;
723 else
725 if( bButton )
726 UnionRect32( &rect, &lphc->RectButton,
727 &lphc->RectEdit );
728 else
729 rect = lphc->RectEdit;
730 bButton = TRUE;
733 if( bButton && !(lphc->wState & CBF_NOREDRAW) )
734 RedrawWindow32( hWnd, &rect, 0, RDW_INVALIDATE |
735 RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
736 CB_NOTIFY( lphc, CBN_CLOSEUP );
741 /***********************************************************************
742 * COMBO_FlipListbox
744 * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
746 BOOL32 COMBO_FlipListbox( LPHEADCOMBO lphc, BOOL32 bRedrawButton )
748 if( lphc->wState & CBF_DROPPED )
750 CBRollUp( lphc, TRUE, bRedrawButton );
751 return FALSE;
754 CBDropDown( lphc );
755 return TRUE;
758 /***********************************************************************
759 * COMBO_GetLBWindow
761 * Edit control helper.
763 HWND32 COMBO_GetLBWindow( WND* pWnd )
765 LPHEADCOMBO lphc = CB_GETPTR(pWnd);
766 if( lphc ) return lphc->hWndLBox;
767 return 0;
771 /***********************************************************************
772 * CBRepaintButton
774 static void CBRepaintButton( LPHEADCOMBO lphc )
776 HDC32 hDC = GetDC32( lphc->self->hwndSelf );
778 if( hDC )
780 CBPaintButton( lphc, hDC );
781 ReleaseDC32( lphc->self->hwndSelf, hDC );
785 /***********************************************************************
786 * COMBO_SetFocus
788 static void COMBO_SetFocus( LPHEADCOMBO lphc )
790 if( !(lphc->wState & CBF_FOCUSED) )
792 if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
793 SendMessage32A( lphc->hWndLBox, LB_CARETON32, 0, 0 );
795 if( lphc->wState & CBF_EDIT )
796 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1) );
797 lphc->wState |= CBF_FOCUSED;
798 if( !(lphc->wState & CBF_EDIT) ) CBPaintText( lphc, 0 );
800 CB_NOTIFY( lphc, CBN_SETFOCUS );
804 /***********************************************************************
805 * COMBO_KillFocus
807 static void COMBO_KillFocus( LPHEADCOMBO lphc )
809 HWND32 hWnd = lphc->self->hwndSelf;
811 if( lphc->wState & CBF_FOCUSED )
813 SendMessage32A( hWnd, WM_LBUTTONUP, 0, (LPARAM)(-1) );
815 CBRollUp( lphc, FALSE, TRUE );
816 if( IsWindow32( hWnd ) )
818 if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
819 SendMessage32A( lphc->hWndLBox, LB_CARETOFF32, 0, 0 );
821 lphc->wState &= ~CBF_FOCUSED;
823 /* redraw text */
824 if( lphc->wState & CBF_EDIT )
825 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, (WPARAM32)(-1), 0 );
826 else CBPaintText( lphc, 0 );
828 CB_NOTIFY( lphc, CBN_KILLFOCUS );
833 /***********************************************************************
834 * COMBO_Command
836 static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM32 wParam, HWND32 hWnd )
838 if( lphc->wState & CBF_EDIT && lphc->hWndEdit == hWnd )
840 /* ">> 8" makes gcc generate jump-table instead of cmp ladder */
842 switch( HIWORD(wParam) >> 8 )
844 case (EN_SETFOCUS >> 8):
846 TRACE(combo,"[%04x]: edit [%04x] got focus\n",
847 CB_HWND(lphc), lphc->hWndEdit );
849 if( !(lphc->wState & CBF_FOCUSED) ) COMBO_SetFocus( lphc );
850 break;
852 case (EN_KILLFOCUS >> 8):
854 TRACE(combo,"[%04x]: edit [%04x] lost focus\n",
855 CB_HWND(lphc), lphc->hWndEdit );
857 /* NOTE: it seems that Windows' edit control sends an
858 * undocumented message WM_USER + 0x1B instead of this
859 * notification (only when it happens to be a part of
860 * the combo). ?? - AK.
863 COMBO_KillFocus( lphc );
864 break;
867 case (EN_CHANGE >> 8):
868 CB_NOTIFY( lphc, CBN_EDITCHANGE );
869 CBUpdateLBox( lphc );
870 break;
872 case (EN_UPDATE >> 8):
873 CB_NOTIFY( lphc, CBN_EDITUPDATE );
874 break;
876 case (EN_ERRSPACE >> 8):
877 CB_NOTIFY( lphc, CBN_ERRSPACE );
880 else if( lphc->hWndLBox == hWnd )
882 switch( HIWORD(wParam) )
884 case LBN_ERRSPACE:
885 CB_NOTIFY( lphc, CBN_ERRSPACE );
886 break;
888 case LBN_DBLCLK:
889 CB_NOTIFY( lphc, CBN_DBLCLK );
890 break;
892 case LBN_SELCHANGE:
893 case LBN_SELCANCEL:
895 TRACE(combo,"[%04x]: lbox selection change [%04x]\n",
896 CB_HWND(lphc), lphc->wState );
898 /* do not roll up if selection is being tracked
899 * by arrowkeys in the dropdown listbox */
901 if( (lphc->wState & CBF_DROPPED) && !(lphc->wState & CBF_NOROLLUP) )
902 CBRollUp( lphc, (HIWORD(wParam) == LBN_SELCHANGE), TRUE );
903 else lphc->wState &= ~CBF_NOROLLUP;
905 CB_NOTIFY( lphc, CBN_SELCHANGE );
906 CBPaintText( lphc, 0 );
907 /* fall through */
909 case LBN_SETFOCUS:
910 case LBN_KILLFOCUS:
911 /* nothing to do here since ComboLBox always resets the focus to its
912 * combo/edit counterpart */
913 break;
916 return 0;
919 /***********************************************************************
920 * COMBO_ItemOp
922 * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
924 static LRESULT COMBO_ItemOp32( LPHEADCOMBO lphc, UINT32 msg,
925 WPARAM32 wParam, LPARAM lParam )
927 HWND32 hWnd = lphc->self->hwndSelf;
929 TRACE(combo,"[%04x]: ownerdraw op %04x\n", CB_HWND(lphc), msg );
931 #define lpIS ((LPDELETEITEMSTRUCT32)lParam)
933 /* two first items are the same in all 4 structs */
934 lpIS->CtlType = ODT_COMBOBOX;
935 lpIS->CtlID = lphc->self->wIDmenu;
937 switch( msg ) /* patch window handle */
939 case WM_DELETEITEM:
940 lpIS->hwndItem = hWnd;
941 #undef lpIS
942 break;
943 case WM_DRAWITEM:
944 #define lpIS ((LPDRAWITEMSTRUCT32)lParam)
945 lpIS->hwndItem = hWnd;
946 #undef lpIS
947 break;
948 case WM_COMPAREITEM:
949 #define lpIS ((LPCOMPAREITEMSTRUCT32)lParam)
950 lpIS->hwndItem = hWnd;
951 #undef lpIS
952 break;
955 return SendMessage32A( lphc->owner, msg, lphc->self->wIDmenu, lParam );
958 /***********************************************************************
959 * COMBO_GetText
961 static LRESULT COMBO_GetText( LPHEADCOMBO lphc, UINT32 N, LPSTR lpText)
963 if( lphc->wState & CBF_EDIT )
964 return SendMessage32A( lphc->hWndEdit, WM_GETTEXT,
965 (WPARAM32)N, (LPARAM)lpText );
967 /* get it from the listbox */
969 if( lphc->hWndLBox )
971 INT32 idx = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 );
972 if( idx != LB_ERR )
974 LPSTR lpBuffer;
975 INT32 length = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32,
976 (WPARAM32)idx, 0 );
978 /* 'length' is without the terminating character */
979 if( length >= N )
980 lpBuffer = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1 );
981 else
982 lpBuffer = lpText;
984 if( lpBuffer )
986 INT32 n = SendMessage32A( lphc->hWndLBox, LB_GETTEXT32,
987 (WPARAM32)idx, (LPARAM)lpText );
989 /* truncate if buffer is too short */
991 if( length >= N )
993 if( n != LB_ERR ) memcpy( lpText, lpBuffer, (N>n) ? n+1 : N-1 );
994 lpText[N - 1] = '\0';
995 HeapFree( GetProcessHeap(), 0, lpBuffer );
997 return (LRESULT)n;
1001 return 0;
1005 /***********************************************************************
1006 * CBResetPos
1008 * This function sets window positions according to the updated
1009 * component placement struct.
1011 static void CBResetPos( LPHEADCOMBO lphc, LPRECT32 lbRect, BOOL32 bRedraw )
1013 BOOL32 bDrop = (CB_GETTYPE(lphc) != CBS_SIMPLE);
1015 /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
1016 * sizing messages */
1018 if( lphc->wState & CBF_EDIT )
1019 SetWindowPos32( lphc->hWndEdit, 0, lphc->RectEdit.left, lphc->RectEdit.top,
1020 lphc->RectEdit.right - lphc->RectEdit.left,
1021 lphc->RectEdit.bottom - lphc->RectEdit.top,
1022 SWP_NOZORDER | SWP_NOACTIVATE | ((bDrop) ? SWP_NOREDRAW : 0) );
1024 if( bDrop )
1025 OffsetRect32( lbRect, lphc->RectCombo.left, lphc->RectCombo.top );
1027 lbRect->right -= lbRect->left; /* convert to width */
1028 lbRect->bottom -= lbRect->top;
1029 SetWindowPos32( lphc->hWndLBox, 0, lbRect->left, lbRect->top,
1030 lbRect->right, lbRect->bottom,
1031 SWP_NOACTIVATE | SWP_NOZORDER | ((bDrop) ? SWP_NOREDRAW : 0) );
1033 if( bDrop )
1035 if( lphc->wState & CBF_DROPPED )
1037 lphc->wState &= ~CBF_DROPPED;
1038 ShowWindow32( lphc->hWndLBox, SW_HIDE );
1041 lphc->wState |= CBF_NORESIZE;
1042 SetWindowPos32( lphc->self->hwndSelf, 0, 0, 0,
1043 lphc->RectCombo.right - lphc->RectCombo.left,
1044 lphc->RectEdit.bottom - lphc->RectEdit.top,
1045 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW );
1046 lphc->wState &= ~CBF_NORESIZE;
1048 if( bRedraw && !(lphc->wState & CBF_NOREDRAW) )
1049 RedrawWindow32( lphc->self->hwndSelf, NULL, 0,
1050 RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
1055 /***********************************************************************
1056 * COMBO_Size
1058 static void COMBO_Size( LPHEADCOMBO lphc )
1060 RECT32 rect;
1061 INT32 w, h;
1063 GetWindowRect32( lphc->self->hwndSelf, &rect );
1064 w = rect.right - rect.left; h = rect.bottom - rect.top;
1066 TRACE(combo,"w = %i, h = %i\n", w, h );
1068 /* CreateWindow() may send a bogus WM_SIZE, ignore it */
1070 if( w == (lphc->RectCombo.right - lphc->RectCombo.left) )
1071 if( (CB_GETTYPE(lphc) == CBS_SIMPLE) &&
1072 (h == (lphc->RectCombo.bottom - lphc->RectCombo.top)) )
1073 return;
1074 else if( (lphc->dwStyle & CBS_DROPDOWN) &&
1075 (h == (lphc->RectEdit.bottom - lphc->RectEdit.top)) )
1076 return;
1078 lphc->RectCombo = rect;
1079 CBCalcPlacement( lphc, &lphc->RectEdit, &lphc->RectButton, &rect );
1080 CBResetPos( lphc, &rect, TRUE );
1084 /***********************************************************************
1085 * COMBO_Font
1087 static void COMBO_Font( LPHEADCOMBO lphc, HFONT32 hFont, BOOL32 bRedraw )
1089 RECT32 rect;
1091 lphc->hFont = hFont;
1093 if( lphc->wState & CBF_EDIT )
1094 SendMessage32A( lphc->hWndEdit, WM_SETFONT, (WPARAM32)hFont, bRedraw );
1095 SendMessage32A( lphc->hWndLBox, WM_SETFONT, (WPARAM32)hFont, bRedraw );
1097 GetWindowRect32( lphc->self->hwndSelf, &rect );
1098 OffsetRect32( &lphc->RectCombo, rect.left - lphc->RectCombo.left,
1099 rect.top - lphc->RectCombo.top );
1100 CBCalcPlacement( lphc, &lphc->RectEdit,
1101 &lphc->RectButton, &rect );
1102 CBResetPos( lphc, &rect, bRedraw );
1106 /***********************************************************************
1107 * COMBO_SetItemHeight
1109 static LRESULT COMBO_SetItemHeight( LPHEADCOMBO lphc, INT32 index, INT32 height )
1111 LRESULT lRet = CB_ERR;
1113 if( index == -1 ) /* set text field height */
1115 if( height < 32768 )
1117 RECT32 rect;
1119 lphc->editHeight = height;
1120 GetWindowRect32( lphc->self->hwndSelf, &rect );
1121 OffsetRect32( &lphc->RectCombo, rect.left - lphc->RectCombo.left,
1122 rect.top - lphc->RectCombo.top );
1123 CBCalcPlacement( lphc, &lphc->RectEdit,
1124 &lphc->RectButton, &rect );
1125 CBResetPos( lphc, &rect, TRUE );
1126 lRet = height;
1129 else if ( CB_OWNERDRAWN(lphc) ) /* set listbox item height */
1130 lRet = SendMessage32A( lphc->hWndLBox, LB_SETITEMHEIGHT32,
1131 (WPARAM32)index, (LPARAM)height );
1132 return lRet;
1135 /***********************************************************************
1136 * COMBO_SelectString
1138 static LRESULT COMBO_SelectString( LPHEADCOMBO lphc, INT32 start, LPCSTR pText )
1140 INT32 index = SendMessage32A( lphc->hWndLBox, LB_SELECTSTRING32,
1141 (WPARAM32)start, (LPARAM)pText );
1142 if( index >= 0 )
1143 if( lphc->wState & CBF_EDIT )
1144 CBUpdateEdit( lphc, index );
1145 else
1146 CBPaintText( lphc, 0 );
1147 return (LRESULT)index;
1150 /***********************************************************************
1151 * COMBO_LButtonDown
1153 static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam )
1155 POINT32 pt = { LOWORD(lParam), HIWORD(lParam) };
1156 BOOL32 bButton = PtInRect32(&lphc->RectButton, pt);
1157 HWND32 hWnd = lphc->self->hwndSelf;
1159 if( (CB_GETTYPE(lphc) == CBS_DROPDOWNLIST) ||
1160 (bButton && (CB_GETTYPE(lphc) == CBS_DROPDOWN)) )
1162 lphc->wState |= CBF_BUTTONDOWN;
1163 if( lphc->wState & CBF_DROPPED )
1165 /* got a click to cancel selection */
1167 CBRollUp( lphc, TRUE, FALSE );
1168 if( !IsWindow32( hWnd ) ) return;
1170 if( lphc->wState & CBF_CAPTURE )
1172 lphc->wState &= ~CBF_CAPTURE;
1173 ReleaseCapture();
1175 lphc->wState &= ~CBF_BUTTONDOWN;
1177 else
1179 /* drop down the listbox and start tracking */
1181 lphc->wState |= CBF_CAPTURE;
1182 CBDropDown( lphc );
1183 SetCapture32( hWnd );
1185 if( bButton ) CBRepaintButton( lphc );
1189 /***********************************************************************
1190 * COMBO_LButtonUp
1192 * Release capture and stop tracking if needed.
1194 static void COMBO_LButtonUp( LPHEADCOMBO lphc, LPARAM lParam )
1196 if( lphc->wState & CBF_CAPTURE )
1198 lphc->wState &= ~CBF_CAPTURE;
1199 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
1201 INT32 index = CBUpdateLBox( lphc );
1202 CBUpdateEdit( lphc, index );
1204 ReleaseCapture();
1207 if( lphc->wState & CBF_BUTTONDOWN )
1209 lphc->wState &= ~CBF_BUTTONDOWN;
1210 CBRepaintButton( lphc );
1214 /***********************************************************************
1215 * COMBO_MouseMove
1217 * Two things to do - track combo button and release capture when
1218 * pointer goes into the listbox.
1220 static void COMBO_MouseMove( LPHEADCOMBO lphc, WPARAM32 wParam, LPARAM lParam )
1222 POINT32 pt = { LOWORD(lParam), HIWORD(lParam) };
1223 RECT32 lbRect;
1225 if( lphc->wState & CBF_BUTTONDOWN )
1227 BOOL32 bButton = PtInRect32(&lphc->RectButton, pt);
1229 if( !bButton )
1231 lphc->wState &= ~CBF_BUTTONDOWN;
1232 CBRepaintButton( lphc );
1236 GetClientRect32( lphc->hWndLBox, &lbRect );
1237 MapWindowPoints32( lphc->self->hwndSelf, lphc->hWndLBox, &pt, 1 );
1238 if( PtInRect32(&lbRect, pt) )
1240 lphc->wState &= ~CBF_CAPTURE;
1241 ReleaseCapture();
1242 if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) CBUpdateLBox( lphc );
1244 /* hand over pointer tracking */
1245 SendMessage32A( lphc->hWndLBox, WM_LBUTTONDOWN, wParam, lParam );
1250 /***********************************************************************
1251 * ComboWndProc
1253 * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/ctrl/src/combobox_15.htm
1255 LRESULT WINAPI ComboWndProc( HWND32 hwnd, UINT32 message,
1256 WPARAM32 wParam, LPARAM lParam )
1258 WND* pWnd = WIN_FindWndPtr(hwnd);
1260 if( pWnd )
1262 LPHEADCOMBO lphc = CB_GETPTR(pWnd);
1264 TRACE(combo, "[%04x]: msg %s wp %08x lp %08lx\n",
1265 pWnd->hwndSelf, SPY_GetMsgName(message), wParam, lParam );
1267 if( lphc || message == WM_NCCREATE )
1268 switch(message)
1271 /* System messages */
1273 case WM_NCCREATE:
1274 return COMBO_NCCreate(pWnd, lParam);
1276 case WM_NCDESTROY:
1277 COMBO_NCDestroy(lphc);
1278 break;
1280 case WM_CREATE:
1281 return COMBO_Create(lphc, pWnd, lParam);
1283 case WM_PAINT:
1284 /* wParam may contain a valid HDC! */
1285 return COMBO_Paint(lphc, wParam);
1287 case WM_ERASEBKGND:
1288 return TRUE;
1290 case WM_GETDLGCODE:
1291 return (LRESULT)(DLGC_WANTARROWS | DLGC_WANTCHARS);
1293 case WM_SIZE:
1294 if( lphc->hWndLBox &&
1295 !(lphc->wState & CBF_NORESIZE) ) COMBO_Size( lphc );
1296 return TRUE;
1298 case WM_SETFONT:
1299 COMBO_Font( lphc, (HFONT16)wParam, (BOOL32)lParam );
1300 return TRUE;
1302 case WM_GETFONT:
1303 return (LRESULT)lphc->hFont;
1305 case WM_SETFOCUS:
1306 if( lphc->wState & CBF_EDIT )
1307 SetFocus32( lphc->hWndEdit );
1308 else
1309 COMBO_SetFocus( lphc );
1310 return TRUE;
1312 case WM_KILLFOCUS:
1313 #define hwndFocus ((HWND16)wParam)
1314 if( !hwndFocus ||
1315 (hwndFocus != lphc->hWndEdit && hwndFocus != lphc->hWndLBox ))
1316 COMBO_KillFocus( lphc );
1317 #undef hwndFocus
1318 return TRUE;
1320 case WM_COMMAND:
1321 return COMBO_Command( lphc, wParam, (HWND32)lParam );
1323 case WM_GETTEXT:
1324 return COMBO_GetText( lphc, (UINT32)wParam, (LPSTR)lParam );
1326 case WM_SETTEXT:
1327 case WM_GETTEXTLENGTH:
1328 case WM_CLEAR:
1329 case WM_CUT:
1330 case WM_PASTE:
1331 case WM_COPY:
1332 if( lphc->wState & CBF_EDIT )
1333 return SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1334 return CB_ERR;
1336 case WM_DRAWITEM:
1337 case WM_DELETEITEM:
1338 case WM_COMPAREITEM:
1339 case WM_MEASUREITEM:
1340 return COMBO_ItemOp32( lphc, message, wParam, lParam );
1342 case WM_ENABLE:
1343 if( lphc->wState & CBF_EDIT )
1344 EnableWindow32( lphc->hWndEdit, (BOOL32)wParam );
1345 EnableWindow32( lphc->hWndLBox, (BOOL32)wParam );
1346 return TRUE;
1348 case WM_SETREDRAW:
1349 if( wParam )
1350 lphc->wState &= ~CBF_NOREDRAW;
1351 else
1352 lphc->wState |= CBF_NOREDRAW;
1354 if( lphc->wState & CBF_EDIT )
1355 SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1356 SendMessage32A( lphc->hWndLBox, message, wParam, lParam );
1357 return 0;
1359 case WM_SYSKEYDOWN:
1360 if( KEYDATA_ALT & HIWORD(lParam) )
1361 if( wParam == VK_UP || wParam == VK_DOWN )
1362 COMBO_FlipListbox( lphc, TRUE );
1363 break;
1365 case WM_CHAR:
1366 case WM_KEYDOWN:
1367 if( lphc->wState & CBF_EDIT )
1368 return SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1369 else
1370 return SendMessage32A( lphc->hWndLBox, message, wParam, lParam );
1372 case WM_LBUTTONDOWN:
1373 if( !(lphc->wState & CBF_FOCUSED) ) SetFocus32( lphc->self->hwndSelf );
1374 if( lphc->wState & CBF_FOCUSED ) COMBO_LButtonDown( lphc, lParam );
1375 return TRUE;
1377 case WM_LBUTTONUP:
1378 COMBO_LButtonUp( lphc, lParam );
1379 return TRUE;
1381 case WM_MOUSEMOVE:
1382 if( lphc->wState & CBF_CAPTURE )
1383 COMBO_MouseMove( lphc, wParam, lParam );
1384 return TRUE;
1386 /* Combo messages */
1388 case CB_ADDSTRING16:
1389 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1390 case CB_ADDSTRING32:
1391 return SendMessage32A( lphc->hWndLBox, LB_ADDSTRING32, 0, lParam);
1393 case CB_INSERTSTRING16:
1394 wParam = (INT32)(INT16)wParam;
1395 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1396 case CB_INSERTSTRING32:
1397 return SendMessage32A( lphc->hWndLBox, LB_INSERTSTRING32, wParam, lParam);
1399 case CB_DELETESTRING16:
1400 case CB_DELETESTRING32:
1401 return SendMessage32A( lphc->hWndLBox, LB_DELETESTRING32, wParam, 0);
1403 case CB_SELECTSTRING16:
1404 wParam = (INT32)(INT16)wParam;
1405 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1406 case CB_SELECTSTRING32:
1407 return COMBO_SelectString( lphc, (INT32)wParam, (LPSTR)lParam );
1409 case CB_FINDSTRING16:
1410 wParam = (INT32)(INT16)wParam;
1411 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1412 case CB_FINDSTRING32:
1413 return SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32, wParam, lParam);
1415 case CB_FINDSTRINGEXACT16:
1416 wParam = (INT32)(INT16)wParam;
1417 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1418 case CB_FINDSTRINGEXACT32:
1419 return SendMessage32A( lphc->hWndLBox, LB_FINDSTRINGEXACT32,
1420 wParam, lParam );
1421 case CB_SETITEMHEIGHT16:
1422 wParam = (INT32)(INT16)wParam;
1423 case CB_SETITEMHEIGHT32:
1424 return COMBO_SetItemHeight( lphc, (INT32)wParam, (INT32)lParam);
1426 case CB_RESETCONTENT16:
1427 case CB_RESETCONTENT32:
1428 SendMessage32A( lphc->hWndLBox, LB_RESETCONTENT32, 0, 0 );
1429 CBPaintText( lphc, 0 );
1430 return TRUE;
1432 case CB_INITSTORAGE32:
1433 return SendMessage32A( lphc->hWndLBox, LB_INITSTORAGE32, wParam, lParam);
1435 case CB_GETHORIZONTALEXTENT32:
1436 return SendMessage32A( lphc->hWndLBox, LB_GETHORIZONTALEXTENT32, 0, 0);
1438 case CB_SETHORIZONTALEXTENT32:
1439 return SendMessage32A( lphc->hWndLBox, LB_SETHORIZONTALEXTENT32, wParam, 0);
1441 case CB_GETTOPINDEX32:
1442 return SendMessage32A( lphc->hWndLBox, LB_GETTOPINDEX32, 0, 0);
1444 case CB_GETLOCALE32:
1445 return SendMessage32A( lphc->hWndLBox, LB_GETLOCALE32, 0, 0);
1447 case CB_SETLOCALE32:
1448 return SendMessage32A( lphc->hWndLBox, LB_SETLOCALE32, wParam, 0);
1450 case CB_GETDROPPEDWIDTH32:
1451 if( lphc->droppedWidth )
1452 return lphc->droppedWidth;
1453 return lphc->RectCombo.right - lphc->RectCombo.left -
1454 (lphc->wState & CBF_EDIT) ? CBitOffset : 0;
1456 case CB_SETDROPPEDWIDTH32:
1457 if( (CB_GETTYPE(lphc) != CBS_SIMPLE) &&
1458 (INT32)wParam < 32768 ) lphc->droppedWidth = (INT32)wParam;
1459 return CB_ERR;
1461 case CB_GETDROPPEDCONTROLRECT16:
1462 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1463 if( lParam )
1465 RECT32 r;
1466 CBGetDroppedControlRect32( lphc, &r );
1467 CONV_RECT32TO16( &r, (LPRECT16)lParam );
1469 return CB_OKAY;
1471 case CB_GETDROPPEDCONTROLRECT32:
1472 if( lParam ) CBGetDroppedControlRect32(lphc, (LPRECT32)lParam );
1473 return CB_OKAY;
1475 case CB_GETDROPPEDSTATE16:
1476 case CB_GETDROPPEDSTATE32:
1477 return (lphc->wState & CBF_DROPPED) ? TRUE : FALSE;
1479 case CB_DIR16:
1480 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1481 /* fall through */
1482 case CB_DIR32:
1483 return COMBO_Directory( lphc, (UINT32)wParam,
1484 (LPSTR)lParam, (message == CB_DIR32));
1485 case CB_SHOWDROPDOWN16:
1486 case CB_SHOWDROPDOWN32:
1487 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
1488 if( wParam )
1490 if( !(lphc->wState & CBF_DROPPED) )
1491 CBDropDown( lphc );
1493 else
1494 if( lphc->wState & CBF_DROPPED )
1495 CBRollUp( lphc, FALSE, TRUE );
1496 return TRUE;
1498 case CB_GETCOUNT16:
1499 case CB_GETCOUNT32:
1500 return SendMessage32A( lphc->hWndLBox, LB_GETCOUNT32, 0, 0);
1502 case CB_GETCURSEL16:
1503 case CB_GETCURSEL32:
1504 return SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0);
1506 case CB_SETCURSEL16:
1507 wParam = (INT32)(INT16)wParam;
1508 case CB_SETCURSEL32:
1509 return SendMessage32A( lphc->hWndLBox, LB_SETCURSEL32, wParam, 0);
1511 case CB_GETLBTEXT16:
1512 wParam = (INT32)(INT16)wParam;
1513 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1514 case CB_GETLBTEXT32:
1515 return SendMessage32A( lphc->hWndLBox, LB_GETTEXT32, wParam, lParam);
1517 case CB_GETLBTEXTLEN16:
1518 wParam = (INT32)(INT16)wParam;
1519 case CB_GETLBTEXTLEN32:
1520 return SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, wParam, 0);
1522 case CB_GETITEMDATA16:
1523 wParam = (INT32)(INT16)wParam;
1524 case CB_GETITEMDATA32:
1525 return SendMessage32A( lphc->hWndLBox, LB_GETITEMDATA32, wParam, 0);
1527 case CB_SETITEMDATA16:
1528 wParam = (INT32)(INT16)wParam;
1529 case CB_SETITEMDATA32:
1530 return SendMessage32A( lphc->hWndLBox, LB_SETITEMDATA32, wParam, lParam);
1532 case CB_GETEDITSEL16:
1533 wParam = lParam = 0; /* just in case */
1534 case CB_GETEDITSEL32:
1535 if( lphc->wState & CBF_EDIT )
1537 INT32 a, b;
1539 return SendMessage32A( lphc->hWndEdit, EM_GETSEL32,
1540 (wParam) ? wParam : (WPARAM32)&a,
1541 (lParam) ? lParam : (LPARAM)&b );
1543 return CB_ERR;
1545 case CB_SETEDITSEL16:
1546 case CB_SETEDITSEL32:
1547 if( lphc->wState & CBF_EDIT )
1548 return SendMessage32A( lphc->hWndEdit, EM_SETSEL32,
1549 (INT32)(INT16)LOWORD(lParam), (INT32)(INT16)HIWORD(lParam) );
1550 return CB_ERR;
1552 case CB_SETEXTENDEDUI16:
1553 case CB_SETEXTENDEDUI32:
1554 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) return CB_ERR;
1556 if( wParam )
1557 lphc->wState |= CBF_EUI;
1558 else lphc->wState &= ~CBF_EUI;
1559 return CB_OKAY;
1561 case CB_GETEXTENDEDUI16:
1562 case CB_GETEXTENDEDUI32:
1563 return (lphc->wState & CBF_EUI) ? TRUE : FALSE;
1565 case (WM_USER + 0x1B):
1566 WARN(combo, "[%04x]: undocumented msg!\n", hwnd );
1568 return DefWindowProc32A(hwnd, message, wParam, lParam);
1570 return CB_ERR;