Small fixes.
[wine/multimedia.git] / controls / combo.c
blob70c78990f840f77e085ce70ee272e201cad7789a
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 * CBGetDefaultTextHeight
135 static void CBGetDefaultTextHeight( LPHEADCOMBO lphc, LPSIZE32 lpSize )
137 if( lphc->editHeight ) /* explicitly set height */
138 lpSize->cy = lphc->editHeight;
139 else
141 HDC32 hDC = GetDC32( lphc->self->hwndSelf );
142 HFONT32 hPrevFont = 0;
144 if( lphc->hFont ) hPrevFont = SelectObject32( hDC, lphc->hFont );
146 GetTextExtentPoint32A( hDC, "0", 1, lpSize);
148 lpSize->cy += lpSize->cy / 4 + 4 * SYSMETRICS_CYBORDER;
150 if( hPrevFont ) SelectObject32( hDC, hPrevFont );
151 ReleaseDC32( lphc->self->hwndSelf, hDC );
153 lpSize->cx = lphc->RectCombo.right - lphc->RectCombo.left;
157 /***********************************************************************
158 * CBCalcPlacement
160 * Set up component coordinates given valid lphc->RectCombo.
162 static void CBCalcPlacement( LPHEADCOMBO lphc, LPRECT32 lprEdit,
163 LPRECT32 lprButton, LPRECT32 lprLB )
165 RECT32 rect = lphc->RectCombo;
166 SIZE32 size;
168 /* get combo height and width */
170 if( CB_OWNERDRAWN(lphc) )
172 UINT32 u = lphc->RectEdit.bottom - lphc->RectEdit.top;
174 if( lphc->wState & CBF_MEASUREITEM ) /* first initialization */
176 MEASUREITEMSTRUCT32 mi32;
178 /* calculate defaults before sending WM_MEASUREITEM */
180 CBGetDefaultTextHeight( lphc, &size );
182 lphc->wState &= ~CBF_MEASUREITEM;
184 mi32.CtlType = ODT_COMBOBOX;
185 mi32.CtlID = lphc->self->wIDmenu;
186 mi32.itemID = -1;
187 mi32.itemWidth = size.cx;
188 mi32.itemHeight = size.cy - 6; /* ownerdrawn cb is taller */
189 mi32.itemData = 0;
190 SendMessage32A(lphc->owner, WM_MEASUREITEM,
191 (WPARAM32)mi32.CtlID, (LPARAM)&mi32);
192 u = 6 + (UINT16)mi32.itemHeight;
194 else
195 size.cx = rect.right - rect.left;
196 size.cy = u;
198 else
199 CBGetDefaultTextHeight( lphc, &size );
201 /* calculate text and button placement */
203 lprEdit->left = lprEdit->top = lprButton->top = 0;
204 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) /* no button */
205 lprButton->left = lprButton->right = lprButton->bottom = 0;
206 else
208 INT32 i = size.cx - CBitWidth - 10; /* seems ok */
210 lprButton->right = size.cx;
211 lprButton->left = (INT16)i;
212 lprButton->bottom = lprButton->top + size.cy;
214 if( i < 0 ) size.cx = 0;
215 else size.cx = i;
218 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
220 size.cx -= CBitOffset;
221 if( size.cx < 0 ) size.cx = 0;
224 lprEdit->right = size.cx; lprEdit->bottom = size.cy;
226 /* listbox placement */
228 lprLB->left = ( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) ? 0 : CBitOffset;
229 lprLB->top = lprEdit->bottom - SYSMETRICS_CYBORDER;
230 lprLB->right = rect.right - rect.left;
231 lprLB->bottom = rect.bottom - rect.top;
233 if( lphc->droppedWidth > (lprLB->right - lprLB->left) )
234 lprLB->right = lprLB->left + lphc->droppedWidth;
236 TRACE(combo,"[%04x]: (%i,%i-%i,%i) placement\n",
237 CB_HWND(lphc), lphc->RectCombo.left, lphc->RectCombo.top,
238 lphc->RectCombo.right, lphc->RectCombo.bottom);
240 TRACE(combo,"\ttext\t= (%i,%i-%i,%i)\n",
241 lprEdit->left, lprEdit->top, lprEdit->right, lprEdit->bottom);
243 TRACE(combo,"\tbutton\t= (%i,%i-%i,%i)\n",
244 lprButton->left, lprButton->top, lprButton->right, lprButton->bottom);
246 TRACE(combo,"\tlbox\t= (%i,%i-%i,%i)\n",
247 lprLB->left, lprLB->top, lprLB->right, lprLB->bottom );
250 /***********************************************************************
251 * CBGetDroppedControlRect32
253 static void CBGetDroppedControlRect32( LPHEADCOMBO lphc, LPRECT32 lpRect)
255 lpRect->left = lphc->RectCombo.left +
256 (lphc->wState & CBF_EDIT) ? CBitOffset : 0;
257 lpRect->top = lphc->RectCombo.top + lphc->RectEdit.bottom -
258 SYSMETRICS_CYBORDER;
259 lpRect->right = lphc->RectCombo.right;
260 lpRect->bottom = lphc->RectCombo.bottom - SYSMETRICS_CYBORDER;
263 /***********************************************************************
264 * COMBO_Create
266 static LRESULT COMBO_Create( LPHEADCOMBO lphc, WND* wnd, LPARAM lParam)
268 static char clbName[] = "ComboLBox";
269 static char editName[] = "Edit";
271 LPCREATESTRUCT32A lpcs = (CREATESTRUCT32A*)lParam;
273 if( !CB_GETTYPE(lphc) ) lphc->dwStyle |= CBS_SIMPLE;
274 else if( CB_GETTYPE(lphc) != CBS_DROPDOWNLIST ) lphc->wState |= CBF_EDIT;
276 lphc->self = wnd;
277 lphc->owner = lpcs->hwndParent;
279 /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */
281 if( lphc->owner || !(lpcs->style & WS_VISIBLE) )
283 UINT32 lbeStyle;
284 RECT32 editRect, btnRect, lbRect;
286 GetWindowRect32( wnd->hwndSelf, &lphc->RectCombo );
288 lphc->wState |= CBF_MEASUREITEM;
289 CBCalcPlacement( lphc, &editRect, &btnRect, &lbRect );
290 lphc->RectButton = btnRect;
291 lphc->droppedWidth = lphc->editHeight = 0;
293 /* create listbox popup */
295 lbeStyle = (LBS_NOTIFY | WS_BORDER | WS_CLIPSIBLINGS) |
296 (lpcs->style & (WS_VSCROLL | CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE));
298 if( lphc->dwStyle & CBS_SORT )
299 lbeStyle |= LBS_SORT;
300 if( lphc->dwStyle & CBS_HASSTRINGS )
301 lbeStyle |= LBS_HASSTRINGS;
302 if( lphc->dwStyle & CBS_NOINTEGRALHEIGHT )
303 lbeStyle |= LBS_NOINTEGRALHEIGHT;
304 if( lphc->dwStyle & CBS_DISABLENOSCROLL )
305 lbeStyle |= LBS_DISABLENOSCROLL;
307 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) /* child listbox */
308 lbeStyle |= WS_CHILD | WS_VISIBLE;
309 else /* popup listbox */
311 lbeStyle |= WS_POPUP;
312 OffsetRect32( &lbRect, lphc->RectCombo.left, lphc->RectCombo.top );
315 /* Dropdown ComboLBox is not a child window and we cannot pass
316 * ID_CB_LISTBOX directly because it will be treated as a menu handle.
319 lphc->hWndLBox = CreateWindowEx32A( 0, clbName, NULL, lbeStyle,
320 lbRect.left + SYSMETRICS_CXBORDER,
321 lbRect.top + SYSMETRICS_CYBORDER,
322 lbRect.right - lbRect.left - 2 * SYSMETRICS_CXBORDER,
323 lbRect.bottom - lbRect.top - 2 * SYSMETRICS_CYBORDER,
324 lphc->self->hwndSelf,
325 (lphc->dwStyle & CBS_DROPDOWN)? (HMENU32)0 : (HMENU32)ID_CB_LISTBOX,
326 lphc->self->hInstance, (LPVOID)lphc );
327 if( lphc->hWndLBox )
329 BOOL32 bEdit = TRUE;
330 lbeStyle = WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NOHIDESEL | ES_LEFT;
331 if( lphc->wState & CBF_EDIT )
333 if( lphc->dwStyle & CBS_OEMCONVERT )
334 lbeStyle |= ES_OEMCONVERT;
335 if( lphc->dwStyle & CBS_AUTOHSCROLL )
336 lbeStyle |= ES_AUTOHSCROLL;
337 if( lphc->dwStyle & CBS_LOWERCASE )
338 lbeStyle |= ES_LOWERCASE;
339 else if( lphc->dwStyle & CBS_UPPERCASE )
340 lbeStyle |= ES_UPPERCASE;
341 lphc->hWndEdit = CreateWindowEx32A( 0, editName, NULL, lbeStyle,
342 editRect.left, editRect.top, editRect.right - editRect.left,
343 editRect.bottom - editRect.top, lphc->self->hwndSelf,
344 (HMENU32)ID_CB_EDIT, lphc->self->hInstance, NULL );
345 if( !lphc->hWndEdit ) bEdit = FALSE;
348 if( bEdit )
350 lphc->RectEdit = editRect;
351 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
353 lphc->wState |= CBF_NORESIZE;
354 SetWindowPos32( wnd->hwndSelf, 0, 0, 0,
355 lphc->RectCombo.right - lphc->RectCombo.left,
356 lphc->RectEdit.bottom - lphc->RectEdit.top,
357 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
358 lphc->wState &= ~CBF_NORESIZE;
360 TRACE(combo,"init done\n");
361 return wnd->hwndSelf;
363 ERR(combo, "edit control failure.\n");
364 } else ERR(combo, "listbox failure.\n");
365 } else ERR(combo, "no owner for visible combo.\n");
367 /* CreateWindow() will send WM_NCDESTROY to cleanup */
369 return -1;
372 /***********************************************************************
373 * CBPaintButton
375 * Paint combo button (normal, pressed, and disabled states).
377 static void CBPaintButton(LPHEADCOMBO lphc, HDC32 hdc)
379 RECT32 r;
380 HBRUSH32 hPrevBrush;
381 UINT32 x, y;
382 BOOL32 bBool;
384 if( lphc->wState & CBF_NOREDRAW ) return;
386 hPrevBrush = (HBRUSH32)SelectObject32(hdc, GetSysColorBrush32(COLOR_BTNFACE));
387 CONV_RECT16TO32( &lphc->RectButton, &r );
389 Rectangle32(hdc, r.left, r.top, r.right, r.bottom );
390 InflateRect32( &r, -1, -1 );
391 if( (bBool = lphc->wState & CBF_BUTTONDOWN) )
393 GRAPH_DrawReliefRect(hdc, &r, 1, 0, TRUE);
394 OffsetRect32( &r, 1, 1 );
395 } else GRAPH_DrawReliefRect(hdc, &r, 1, 2, FALSE);
397 x = (r.left + r.right - CBitWidth) >> 1;
398 y = (r.top + r.bottom - CBitHeight) >> 1;
400 InflateRect32( &r, -3, -3 );
401 if( (bBool = CB_DISABLED(lphc)) )
403 GRAPH_SelectClipMask(hdc, hComboBmp, x + 1, y + 1 );
404 FillRect32(hdc, &r, (HBRUSH32)GetStockObject32(WHITE_BRUSH));
407 GRAPH_SelectClipMask(hdc, hComboBmp, x, y );
408 FillRect32(hdc, &r, (HBRUSH32)GetStockObject32((bBool) ? GRAY_BRUSH : BLACK_BRUSH));
410 GRAPH_SelectClipMask(hdc, (HBITMAP32)0, 0, 0);
411 SelectObject32( hdc, hPrevBrush );
414 /***********************************************************************
415 * CBPaintText
417 * Paint CBS_DROPDOWNLIST text field / update edit control contents.
419 static void CBPaintText(LPHEADCOMBO lphc, HDC32 hdc)
421 INT32 id, size = 0;
422 LPSTR pText = NULL;
424 if( lphc->wState & CBF_NOREDRAW ) return;
426 /* follow Windows combobox that sends a bunch of text
427 * inquiries to its listbox while processing WM_PAINT. */
429 if( (id = SendMessage32A(lphc->hWndLBox, LB_GETCURSEL32, 0, 0) ) != LB_ERR )
431 size = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, id, 0);
432 if( (pText = HeapAlloc( GetProcessHeap(), 0, size + 1)) )
434 SendMessage32A( lphc->hWndLBox, LB_GETTEXT32, (WPARAM32)id, (LPARAM)pText );
435 pText[size] = '\0'; /* just in case */
436 } else return;
439 if( lphc->wState & CBF_EDIT )
441 if( CB_HASSTRINGS(lphc) ) SetWindowText32A( lphc->hWndEdit, pText ? pText : "" );
442 if( lphc->wState & CBF_FOCUSED )
443 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1));
445 else /* paint text field ourselves */
447 HBRUSH32 hPrevBrush = 0;
448 HDC32 hDC = hdc;
450 if( !hDC )
452 if ((hDC = GetDC32(lphc->self->hwndSelf)))
454 HBRUSH32 hBrush = SendMessage32A( lphc->owner,
455 WM_CTLCOLORLISTBOX,
456 hDC, lphc->self->hwndSelf );
457 hPrevBrush = SelectObject32( hDC,
458 (hBrush) ? hBrush : GetStockObject32(WHITE_BRUSH) );
461 if( hDC )
463 RECT32 rect;
464 UINT32 itemState;
465 HFONT32 hPrevFont = (lphc->hFont) ? SelectObject32(hDC, lphc->hFont) : 0;
467 PatBlt32( hDC, (rect.left = lphc->RectEdit.left + SYSMETRICS_CXBORDER),
468 (rect.top = lphc->RectEdit.top + SYSMETRICS_CYBORDER),
469 (rect.right = lphc->RectEdit.right - SYSMETRICS_CXBORDER),
470 (rect.bottom = lphc->RectEdit.bottom - SYSMETRICS_CYBORDER) - 1, PATCOPY );
471 InflateRect32( &rect, -1, -1 );
473 if( lphc->wState & CBF_FOCUSED &&
474 !(lphc->wState & CBF_DROPPED) )
476 /* highlight */
478 FillRect32( hDC, &rect, GetSysColorBrush32(COLOR_HIGHLIGHT) );
479 SetBkColor32( hDC, GetSysColor32( COLOR_HIGHLIGHT ) );
480 SetTextColor32( hDC, GetSysColor32( COLOR_HIGHLIGHTTEXT ) );
481 itemState = ODS_SELECTED | ODS_FOCUS;
482 } else itemState = 0;
484 if( CB_OWNERDRAWN(lphc) )
486 DRAWITEMSTRUCT32 dis;
488 if( lphc->self->dwStyle & WS_DISABLED ) itemState |= ODS_DISABLED;
490 dis.CtlType = ODT_COMBOBOX;
491 dis.CtlID = lphc->self->wIDmenu;
492 dis.hwndItem = lphc->self->hwndSelf;
493 dis.itemAction = ODA_DRAWENTIRE;
494 dis.itemID = id;
495 dis.itemState = itemState;
496 dis.hDC = hDC;
497 dis.rcItem = rect;
498 dis.itemData = SendMessage32A( lphc->hWndLBox, LB_GETITEMDATA32,
499 (WPARAM32)id, 0 );
500 SendMessage32A( lphc->owner, WM_DRAWITEM,
501 lphc->self->wIDmenu, (LPARAM)&dis );
503 else
505 ExtTextOut32A( hDC, rect.left + 1, rect.top + 1,
506 ETO_OPAQUE | ETO_CLIPPED, &rect,
507 pText ? pText : "" , size, NULL );
508 if(lphc->wState & CBF_FOCUSED && !(lphc->wState & CBF_DROPPED))
509 DrawFocusRect32( hDC, &rect );
512 if( hPrevFont ) SelectObject32(hDC, hPrevFont );
513 if( !hdc )
515 if( hPrevBrush ) SelectObject32( hDC, hPrevBrush );
516 ReleaseDC32( lphc->self->hwndSelf, hDC );
520 if (pText)
521 HeapFree( GetProcessHeap(), 0, pText );
524 /***********************************************************************
525 * COMBO_Paint
527 static LRESULT COMBO_Paint(LPHEADCOMBO lphc, HDC32 hParamDC)
529 PAINTSTRUCT32 ps;
530 HDC32 hDC;
532 hDC = (hParamDC) ? hParamDC
533 : BeginPaint32( lphc->self->hwndSelf, &ps);
534 if( hDC && !(lphc->wState & CBF_NOREDRAW) )
536 HBRUSH32 hPrevBrush, hBkgBrush;
538 hBkgBrush = SendMessage32A( lphc->owner, WM_CTLCOLORLISTBOX,
539 hDC, lphc->self->hwndSelf );
540 if( !hBkgBrush ) hBkgBrush = GetStockObject32(WHITE_BRUSH);
542 hPrevBrush = SelectObject32( hDC, hBkgBrush );
543 if( !IsRectEmpty32(&lphc->RectButton) )
545 /* paint everything to the right of the text field */
547 PatBlt32( hDC, lphc->RectEdit.right, lphc->RectEdit.top,
548 lphc->RectButton.right - lphc->RectEdit.right,
549 lphc->RectEdit.bottom - lphc->RectEdit.top, PATCOPY );
550 CBPaintButton( lphc, hDC );
553 if( !(lphc->wState & CBF_EDIT) )
555 /* paint text field */
557 GRAPH_DrawRectangle( hDC, lphc->RectEdit.left, lphc->RectEdit.top,
558 lphc->RectEdit.right - lphc->RectEdit.left,
559 lphc->RectButton.bottom - lphc->RectButton.top,
560 GetSysColorPen32(COLOR_WINDOWFRAME) );
561 CBPaintText( lphc, hDC );
563 if( hPrevBrush ) SelectObject32( hDC, hPrevBrush );
565 if( !hParamDC ) EndPaint32(lphc->self->hwndSelf, &ps);
566 return 0;
569 /***********************************************************************
570 * CBUpdateLBox
572 * Select listbox entry according to the contents of the edit control.
574 static INT32 CBUpdateLBox( LPHEADCOMBO lphc )
576 INT32 length, idx, ret;
577 LPSTR pText = NULL;
579 idx = ret = LB_ERR;
580 length = CB_GETEDITTEXTLENGTH( lphc );
582 if( length > 0 )
583 pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1);
585 TRACE(combo,"\t edit text length %i\n", length );
587 if( pText )
589 if( length ) GetWindowText32A( lphc->hWndEdit, pText, length + 1);
590 else pText[0] = '\0';
591 idx = SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32,
592 (WPARAM32)(-1), (LPARAM)pText );
593 if( idx == LB_ERR ) idx = 0; /* select first item */
594 else ret = idx;
595 HeapFree( GetProcessHeap(), 0, pText );
598 /* select entry */
600 SendMessage32A( lphc->hWndLBox, LB_SETCURSEL32, (WPARAM32)idx, 0 );
602 if( idx >= 0 )
604 SendMessage32A( lphc->hWndLBox, LB_SETTOPINDEX32, (WPARAM32)idx, 0 );
605 /* probably superfluous but Windows sends this too */
606 SendMessage32A( lphc->hWndLBox, LB_SETCARETINDEX32, (WPARAM32)idx, 0 );
608 return ret;
611 /***********************************************************************
612 * CBUpdateEdit
614 * Copy a listbox entry to the edit control.
616 static void CBUpdateEdit( LPHEADCOMBO lphc , INT32 index )
618 INT32 length;
619 LPSTR pText = NULL;
621 TRACE(combo,"\t %i\n", index );
623 if( index == -1 )
625 length = CB_GETEDITTEXTLENGTH( lphc );
626 if( length )
628 if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) )
630 GetWindowText32A( lphc->hWndEdit, pText, length + 1 );
631 index = SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32,
632 (WPARAM32)(-1), (LPARAM)pText );
633 HeapFree( GetProcessHeap(), 0, pText );
638 if( index >= 0 ) /* got an entry */
640 length = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, (WPARAM32)index, 0);
641 if( length )
643 if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) )
645 SendMessage32A( lphc->hWndLBox, LB_GETTEXT32,
646 (WPARAM32)index, (LPARAM)pText );
647 SendMessage32A( lphc->hWndEdit, WM_SETTEXT, 0, (LPARAM)pText );
648 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1) );
649 HeapFree( GetProcessHeap(), 0, pText );
655 /***********************************************************************
656 * CBDropDown
658 * Show listbox popup.
660 static void CBDropDown( LPHEADCOMBO lphc )
662 INT32 index;
663 RECT32 rect;
664 LPRECT32 pRect = NULL;
666 TRACE(combo,"[%04x]: drop down\n", CB_HWND(lphc));
668 CB_NOTIFY( lphc, CBN_DROPDOWN );
670 /* set selection */
672 lphc->wState |= CBF_DROPPED;
673 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
675 index = CBUpdateLBox( lphc );
676 if( !(lphc->wState & CBF_CAPTURE) ) CBUpdateEdit( lphc, index );
678 else
680 index = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 );
681 if( index == LB_ERR ) index = 0;
682 SendMessage32A( lphc->hWndLBox, LB_SETTOPINDEX32, (WPARAM32)index, 0 );
683 SendMessage32A( lphc->hWndLBox, LB_CARETON32, 0, 0 );
684 pRect = &lphc->RectEdit;
687 /* now set popup position */
689 GetWindowRect32( lphc->self->hwndSelf, &rect );
691 rect.top += lphc->RectEdit.bottom - lphc->RectEdit.top - SYSMETRICS_CYBORDER;
692 rect.bottom = rect.top + lphc->RectCombo.bottom -
693 lphc->RectCombo.top - SYSMETRICS_CYBORDER;
694 rect.right = rect.left + lphc->RectCombo.right - lphc->RectCombo.left;
695 rect.left += ( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) ? 0 : CBitOffset;
697 SetWindowPos32( lphc->hWndLBox, HWND_TOP, rect.left, rect.top,
698 rect.right - rect.left, rect.bottom - rect.top,
699 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOREDRAW);
701 if( !(lphc->wState & CBF_NOREDRAW) )
702 if( pRect )
703 RedrawWindow32( lphc->self->hwndSelf, pRect, 0, RDW_INVALIDATE |
704 RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
705 ShowWindow32( lphc->hWndLBox, SW_SHOWNA );
708 /***********************************************************************
709 * CBRollUp
711 * Hide listbox popup.
713 static void CBRollUp( LPHEADCOMBO lphc, BOOL32 ok, BOOL32 bButton )
715 HWND32 hWnd = lphc->self->hwndSelf;
717 CB_NOTIFY( lphc, (ok) ? CBN_SELENDOK : CBN_SELENDCANCEL );
719 if( IsWindow32( hWnd ) && CB_GETTYPE(lphc) != CBS_SIMPLE )
722 TRACE(combo,"[%04x]: roll up [%i]\n", CB_HWND(lphc), (INT32)ok );
724 /* always send WM_LBUTTONUP? */
725 SendMessage32A( lphc->hWndLBox, WM_LBUTTONUP, 0, (LPARAM)(-1) );
727 if( lphc->wState & CBF_DROPPED )
729 RECT32 rect;
731 lphc->wState &= ~CBF_DROPPED;
732 ShowWindow32( lphc->hWndLBox, SW_HIDE );
734 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
736 INT32 index = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 );
737 CBUpdateEdit( lphc, index );
738 rect = lphc->RectButton;
740 else
742 if( bButton )
743 UnionRect32( &rect, &lphc->RectButton,
744 &lphc->RectEdit );
745 else
746 rect = lphc->RectEdit;
747 bButton = TRUE;
750 if( bButton && !(lphc->wState & CBF_NOREDRAW) )
751 RedrawWindow32( hWnd, &rect, 0, RDW_INVALIDATE |
752 RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
753 CB_NOTIFY( lphc, CBN_CLOSEUP );
758 /***********************************************************************
759 * COMBO_FlipListbox
761 * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
763 BOOL32 COMBO_FlipListbox( LPHEADCOMBO lphc, BOOL32 bRedrawButton )
765 if( lphc->wState & CBF_DROPPED )
767 CBRollUp( lphc, TRUE, bRedrawButton );
768 return FALSE;
771 CBDropDown( lphc );
772 return TRUE;
775 /***********************************************************************
776 * COMBO_GetLBWindow
778 * Edit control helper.
780 HWND32 COMBO_GetLBWindow( WND* pWnd )
782 LPHEADCOMBO lphc = CB_GETPTR(pWnd);
783 if( lphc ) return lphc->hWndLBox;
784 return 0;
788 /***********************************************************************
789 * CBRepaintButton
791 static void CBRepaintButton( LPHEADCOMBO lphc )
793 HDC32 hDC = GetDC32( lphc->self->hwndSelf );
795 if( hDC )
797 CBPaintButton( lphc, hDC );
798 ReleaseDC32( lphc->self->hwndSelf, hDC );
802 /***********************************************************************
803 * COMBO_SetFocus
805 static void COMBO_SetFocus( LPHEADCOMBO lphc )
807 if( !(lphc->wState & CBF_FOCUSED) )
809 if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
810 SendMessage32A( lphc->hWndLBox, LB_CARETON32, 0, 0 );
812 if( lphc->wState & CBF_EDIT )
813 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1) );
814 lphc->wState |= CBF_FOCUSED;
815 if( !(lphc->wState & CBF_EDIT) ) CBPaintText( lphc, 0 );
817 CB_NOTIFY( lphc, CBN_SETFOCUS );
821 /***********************************************************************
822 * COMBO_KillFocus
824 static void COMBO_KillFocus( LPHEADCOMBO lphc )
826 HWND32 hWnd = lphc->self->hwndSelf;
828 if( lphc->wState & CBF_FOCUSED )
830 SendMessage32A( hWnd, WM_LBUTTONUP, 0, (LPARAM)(-1) );
832 CBRollUp( lphc, FALSE, TRUE );
833 if( IsWindow32( hWnd ) )
835 if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
836 SendMessage32A( lphc->hWndLBox, LB_CARETOFF32, 0, 0 );
838 lphc->wState &= ~CBF_FOCUSED;
840 /* redraw text */
841 if( lphc->wState & CBF_EDIT )
842 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, (WPARAM32)(-1), 0 );
843 else CBPaintText( lphc, 0 );
845 CB_NOTIFY( lphc, CBN_KILLFOCUS );
850 /***********************************************************************
851 * COMBO_Command
853 static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM32 wParam, HWND32 hWnd )
855 if( lphc->wState & CBF_EDIT && lphc->hWndEdit == hWnd )
857 /* ">> 8" makes gcc generate jump-table instead of cmp ladder */
859 switch( HIWORD(wParam) >> 8 )
861 case (EN_SETFOCUS >> 8):
863 TRACE(combo,"[%04x]: edit [%04x] got focus\n",
864 CB_HWND(lphc), lphc->hWndEdit );
866 if( !(lphc->wState & CBF_FOCUSED) ) COMBO_SetFocus( lphc );
867 break;
869 case (EN_KILLFOCUS >> 8):
871 TRACE(combo,"[%04x]: edit [%04x] lost focus\n",
872 CB_HWND(lphc), lphc->hWndEdit );
874 /* NOTE: it seems that Windows' edit control sends an
875 * undocumented message WM_USER + 0x1B instead of this
876 * notification (only when it happens to be a part of
877 * the combo). ?? - AK.
880 COMBO_KillFocus( lphc );
881 break;
884 case (EN_CHANGE >> 8):
885 CB_NOTIFY( lphc, CBN_EDITCHANGE );
886 CBUpdateLBox( lphc );
887 break;
889 case (EN_UPDATE >> 8):
890 CB_NOTIFY( lphc, CBN_EDITUPDATE );
891 break;
893 case (EN_ERRSPACE >> 8):
894 CB_NOTIFY( lphc, CBN_ERRSPACE );
897 else if( lphc->hWndLBox == hWnd )
899 switch( HIWORD(wParam) )
901 case LBN_ERRSPACE:
902 CB_NOTIFY( lphc, CBN_ERRSPACE );
903 break;
905 case LBN_DBLCLK:
906 CB_NOTIFY( lphc, CBN_DBLCLK );
907 break;
909 case LBN_SELCHANGE:
910 case LBN_SELCANCEL:
912 TRACE(combo,"[%04x]: lbox selection change [%04x]\n",
913 CB_HWND(lphc), lphc->wState );
915 /* do not roll up if selection is being tracked
916 * by arrowkeys in the dropdown listbox */
918 if( (lphc->wState & CBF_DROPPED) && !(lphc->wState & CBF_NOROLLUP) )
919 CBRollUp( lphc, (HIWORD(wParam) == LBN_SELCHANGE), TRUE );
920 else lphc->wState &= ~CBF_NOROLLUP;
922 CB_NOTIFY( lphc, CBN_SELCHANGE );
923 CBPaintText( lphc, 0 );
924 /* fall through */
926 case LBN_SETFOCUS:
927 case LBN_KILLFOCUS:
928 /* nothing to do here since ComboLBox always resets the focus to its
929 * combo/edit counterpart */
930 break;
933 return 0;
936 /***********************************************************************
937 * COMBO_ItemOp
939 * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
941 static LRESULT COMBO_ItemOp32( LPHEADCOMBO lphc, UINT32 msg,
942 WPARAM32 wParam, LPARAM lParam )
944 HWND32 hWnd = lphc->self->hwndSelf;
946 TRACE(combo,"[%04x]: ownerdraw op %04x\n", CB_HWND(lphc), msg );
948 #define lpIS ((LPDELETEITEMSTRUCT32)lParam)
950 /* two first items are the same in all 4 structs */
951 lpIS->CtlType = ODT_COMBOBOX;
952 lpIS->CtlID = lphc->self->wIDmenu;
954 switch( msg ) /* patch window handle */
956 case WM_DELETEITEM:
957 lpIS->hwndItem = hWnd;
958 #undef lpIS
959 break;
960 case WM_DRAWITEM:
961 #define lpIS ((LPDRAWITEMSTRUCT32)lParam)
962 lpIS->hwndItem = hWnd;
963 #undef lpIS
964 break;
965 case WM_COMPAREITEM:
966 #define lpIS ((LPCOMPAREITEMSTRUCT32)lParam)
967 lpIS->hwndItem = hWnd;
968 #undef lpIS
969 break;
972 return SendMessage32A( lphc->owner, msg, lphc->self->wIDmenu, lParam );
975 /***********************************************************************
976 * COMBO_GetText
978 static LRESULT COMBO_GetText( LPHEADCOMBO lphc, UINT32 N, LPSTR lpText)
980 if( lphc->wState & CBF_EDIT )
981 return SendMessage32A( lphc->hWndEdit, WM_GETTEXT,
982 (WPARAM32)N, (LPARAM)lpText );
984 /* get it from the listbox */
986 if( lphc->hWndLBox )
988 INT32 idx = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 );
989 if( idx != LB_ERR )
991 LPSTR lpBuffer;
992 INT32 length = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32,
993 (WPARAM32)idx, 0 );
995 /* 'length' is without the terminating character */
996 if( length >= N )
997 lpBuffer = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1 );
998 else
999 lpBuffer = lpText;
1001 if( lpBuffer )
1003 INT32 n = SendMessage32A( lphc->hWndLBox, LB_GETTEXT32,
1004 (WPARAM32)idx, (LPARAM)lpText );
1006 /* truncate if buffer is too short */
1008 if( length >= N )
1010 if( n != LB_ERR ) memcpy( lpText, lpBuffer, (N>n) ? n+1 : N-1 );
1011 lpText[N - 1] = '\0';
1012 HeapFree( GetProcessHeap(), 0, lpBuffer );
1014 return (LRESULT)n;
1018 return 0;
1022 /***********************************************************************
1023 * CBResetPos
1025 * This function sets window positions according to the updated
1026 * component placement struct.
1028 static void CBResetPos( LPHEADCOMBO lphc, LPRECT32 lbRect, BOOL32 bRedraw )
1030 BOOL32 bDrop = (CB_GETTYPE(lphc) != CBS_SIMPLE);
1032 /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
1033 * sizing messages */
1035 if( lphc->wState & CBF_EDIT )
1036 SetWindowPos32( lphc->hWndEdit, 0, lphc->RectEdit.left, lphc->RectEdit.top,
1037 lphc->RectEdit.right - lphc->RectEdit.left,
1038 lphc->RectEdit.bottom - lphc->RectEdit.top,
1039 SWP_NOZORDER | SWP_NOACTIVATE | ((bDrop) ? SWP_NOREDRAW : 0) );
1041 if( bDrop )
1042 OffsetRect32( lbRect, lphc->RectCombo.left, lphc->RectCombo.top );
1044 lbRect->right -= lbRect->left; /* convert to width */
1045 lbRect->bottom -= lbRect->top;
1046 SetWindowPos32( lphc->hWndLBox, 0, lbRect->left, lbRect->top,
1047 lbRect->right, lbRect->bottom,
1048 SWP_NOACTIVATE | SWP_NOZORDER | ((bDrop) ? SWP_NOREDRAW : 0) );
1050 if( bDrop )
1052 if( lphc->wState & CBF_DROPPED )
1054 lphc->wState &= ~CBF_DROPPED;
1055 ShowWindow32( lphc->hWndLBox, SW_HIDE );
1058 lphc->wState |= CBF_NORESIZE;
1059 SetWindowPos32( lphc->self->hwndSelf, 0, 0, 0,
1060 lphc->RectCombo.right - lphc->RectCombo.left,
1061 lphc->RectEdit.bottom - lphc->RectEdit.top,
1062 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW );
1063 lphc->wState &= ~CBF_NORESIZE;
1065 if( bRedraw && !(lphc->wState & CBF_NOREDRAW) )
1066 RedrawWindow32( lphc->self->hwndSelf, NULL, 0,
1067 RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
1072 /***********************************************************************
1073 * COMBO_Size
1075 static void COMBO_Size( LPHEADCOMBO lphc )
1077 RECT32 rect;
1078 INT32 w, h;
1080 GetWindowRect32( lphc->self->hwndSelf, &rect );
1081 w = rect.right - rect.left; h = rect.bottom - rect.top;
1083 TRACE(combo,"w = %i, h = %i\n", w, h );
1085 /* CreateWindow() may send a bogus WM_SIZE, ignore it */
1087 if( w == (lphc->RectCombo.right - lphc->RectCombo.left) )
1089 if( (CB_GETTYPE(lphc) == CBS_SIMPLE) &&
1090 (h == (lphc->RectCombo.bottom - lphc->RectCombo.top)) )
1091 return;
1092 else if( (lphc->dwStyle & CBS_DROPDOWN) &&
1093 (h == (lphc->RectEdit.bottom - lphc->RectEdit.top)) )
1094 return;
1096 lphc->RectCombo = rect;
1097 CBCalcPlacement( lphc, &lphc->RectEdit, &lphc->RectButton, &rect );
1098 CBResetPos( lphc, &rect, TRUE );
1102 /***********************************************************************
1103 * COMBO_Font
1105 static void COMBO_Font( LPHEADCOMBO lphc, HFONT32 hFont, BOOL32 bRedraw )
1107 RECT32 rect;
1109 lphc->hFont = hFont;
1111 if( lphc->wState & CBF_EDIT )
1112 SendMessage32A( lphc->hWndEdit, WM_SETFONT, (WPARAM32)hFont, bRedraw );
1113 SendMessage32A( lphc->hWndLBox, WM_SETFONT, (WPARAM32)hFont, bRedraw );
1115 GetWindowRect32( lphc->self->hwndSelf, &rect );
1116 OffsetRect32( &lphc->RectCombo, rect.left - lphc->RectCombo.left,
1117 rect.top - lphc->RectCombo.top );
1118 CBCalcPlacement( lphc, &lphc->RectEdit,
1119 &lphc->RectButton, &rect );
1120 CBResetPos( lphc, &rect, bRedraw );
1124 /***********************************************************************
1125 * COMBO_SetItemHeight
1127 static LRESULT COMBO_SetItemHeight( LPHEADCOMBO lphc, INT32 index, INT32 height )
1129 LRESULT lRet = CB_ERR;
1131 if( index == -1 ) /* set text field height */
1133 if( height < 32768 )
1135 RECT32 rect;
1137 lphc->editHeight = height;
1138 GetWindowRect32( lphc->self->hwndSelf, &rect );
1139 OffsetRect32( &lphc->RectCombo, rect.left - lphc->RectCombo.left,
1140 rect.top - lphc->RectCombo.top );
1141 CBCalcPlacement( lphc, &lphc->RectEdit,
1142 &lphc->RectButton, &rect );
1143 CBResetPos( lphc, &rect, TRUE );
1144 lRet = height;
1147 else if ( CB_OWNERDRAWN(lphc) ) /* set listbox item height */
1148 lRet = SendMessage32A( lphc->hWndLBox, LB_SETITEMHEIGHT32,
1149 (WPARAM32)index, (LPARAM)height );
1150 return lRet;
1153 /***********************************************************************
1154 * COMBO_SelectString
1156 static LRESULT COMBO_SelectString( LPHEADCOMBO lphc, INT32 start, LPCSTR pText )
1158 INT32 index = SendMessage32A( lphc->hWndLBox, LB_SELECTSTRING32,
1159 (WPARAM32)start, (LPARAM)pText );
1160 if( index >= 0 )
1162 if( lphc->wState & CBF_EDIT )
1163 CBUpdateEdit( lphc, index );
1164 else
1165 CBPaintText( lphc, 0 );
1167 return (LRESULT)index;
1170 /***********************************************************************
1171 * COMBO_LButtonDown
1173 static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam )
1175 POINT32 pt = { LOWORD(lParam), HIWORD(lParam) };
1176 BOOL32 bButton = PtInRect32(&lphc->RectButton, pt);
1177 HWND32 hWnd = lphc->self->hwndSelf;
1179 if( (CB_GETTYPE(lphc) == CBS_DROPDOWNLIST) ||
1180 (bButton && (CB_GETTYPE(lphc) == CBS_DROPDOWN)) )
1182 lphc->wState |= CBF_BUTTONDOWN;
1183 if( lphc->wState & CBF_DROPPED )
1185 /* got a click to cancel selection */
1187 CBRollUp( lphc, TRUE, FALSE );
1188 if( !IsWindow32( hWnd ) ) return;
1190 if( lphc->wState & CBF_CAPTURE )
1192 lphc->wState &= ~CBF_CAPTURE;
1193 ReleaseCapture();
1195 lphc->wState &= ~CBF_BUTTONDOWN;
1197 else
1199 /* drop down the listbox and start tracking */
1201 lphc->wState |= CBF_CAPTURE;
1202 CBDropDown( lphc );
1203 SetCapture32( hWnd );
1205 if( bButton ) CBRepaintButton( lphc );
1209 /***********************************************************************
1210 * COMBO_LButtonUp
1212 * Release capture and stop tracking if needed.
1214 static void COMBO_LButtonUp( LPHEADCOMBO lphc, LPARAM lParam )
1216 if( lphc->wState & CBF_CAPTURE )
1218 lphc->wState &= ~CBF_CAPTURE;
1219 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
1221 INT32 index = CBUpdateLBox( lphc );
1222 CBUpdateEdit( lphc, index );
1224 ReleaseCapture();
1227 if( lphc->wState & CBF_BUTTONDOWN )
1229 lphc->wState &= ~CBF_BUTTONDOWN;
1230 CBRepaintButton( lphc );
1234 /***********************************************************************
1235 * COMBO_MouseMove
1237 * Two things to do - track combo button and release capture when
1238 * pointer goes into the listbox.
1240 static void COMBO_MouseMove( LPHEADCOMBO lphc, WPARAM32 wParam, LPARAM lParam )
1242 POINT32 pt = { LOWORD(lParam), HIWORD(lParam) };
1243 RECT32 lbRect;
1245 if( lphc->wState & CBF_BUTTONDOWN )
1247 BOOL32 bButton = PtInRect32(&lphc->RectButton, pt);
1249 if( !bButton )
1251 lphc->wState &= ~CBF_BUTTONDOWN;
1252 CBRepaintButton( lphc );
1256 GetClientRect32( lphc->hWndLBox, &lbRect );
1257 MapWindowPoints32( lphc->self->hwndSelf, lphc->hWndLBox, &pt, 1 );
1258 if( PtInRect32(&lbRect, pt) )
1260 lphc->wState &= ~CBF_CAPTURE;
1261 ReleaseCapture();
1262 if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) CBUpdateLBox( lphc );
1264 /* hand over pointer tracking */
1265 SendMessage32A( lphc->hWndLBox, WM_LBUTTONDOWN, wParam, lParam );
1270 /***********************************************************************
1271 * ComboWndProc
1273 * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/ctrl/src/combobox_15.htm
1275 LRESULT WINAPI ComboWndProc( HWND32 hwnd, UINT32 message,
1276 WPARAM32 wParam, LPARAM lParam )
1278 WND* pWnd = WIN_FindWndPtr(hwnd);
1280 if( pWnd )
1282 LPHEADCOMBO lphc = CB_GETPTR(pWnd);
1284 TRACE(combo, "[%04x]: msg %s wp %08x lp %08lx\n",
1285 pWnd->hwndSelf, SPY_GetMsgName(message), wParam, lParam );
1287 if( lphc || message == WM_NCCREATE )
1288 switch(message)
1291 /* System messages */
1293 case WM_NCCREATE:
1294 return COMBO_NCCreate(pWnd, lParam);
1296 case WM_NCDESTROY:
1297 COMBO_NCDestroy(lphc);
1298 break;
1300 case WM_CREATE:
1301 return COMBO_Create(lphc, pWnd, lParam);
1303 case WM_PAINT:
1304 /* wParam may contain a valid HDC! */
1305 return COMBO_Paint(lphc, wParam);
1307 case WM_ERASEBKGND:
1308 return TRUE;
1310 case WM_GETDLGCODE:
1311 return (LRESULT)(DLGC_WANTARROWS | DLGC_WANTCHARS);
1313 case WM_SIZE:
1314 if( lphc->hWndLBox &&
1315 !(lphc->wState & CBF_NORESIZE) ) COMBO_Size( lphc );
1316 return TRUE;
1318 case WM_SETFONT:
1319 COMBO_Font( lphc, (HFONT16)wParam, (BOOL32)lParam );
1320 return TRUE;
1322 case WM_GETFONT:
1323 return (LRESULT)lphc->hFont;
1325 case WM_SETFOCUS:
1326 if( lphc->wState & CBF_EDIT )
1327 SetFocus32( lphc->hWndEdit );
1328 else
1329 COMBO_SetFocus( lphc );
1330 return TRUE;
1332 case WM_KILLFOCUS:
1333 #define hwndFocus ((HWND16)wParam)
1334 if( !hwndFocus ||
1335 (hwndFocus != lphc->hWndEdit && hwndFocus != lphc->hWndLBox ))
1336 COMBO_KillFocus( lphc );
1337 #undef hwndFocus
1338 return TRUE;
1340 case WM_COMMAND:
1341 return COMBO_Command( lphc, wParam, (HWND32)lParam );
1343 case WM_GETTEXT:
1344 return COMBO_GetText( lphc, (UINT32)wParam, (LPSTR)lParam );
1346 case WM_SETTEXT:
1347 case WM_GETTEXTLENGTH:
1348 case WM_CLEAR:
1349 case WM_CUT:
1350 case WM_PASTE:
1351 case WM_COPY:
1352 if( lphc->wState & CBF_EDIT )
1353 return SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1354 return CB_ERR;
1356 case WM_DRAWITEM:
1357 case WM_DELETEITEM:
1358 case WM_COMPAREITEM:
1359 case WM_MEASUREITEM:
1360 return COMBO_ItemOp32( lphc, message, wParam, lParam );
1362 case WM_ENABLE:
1363 if( lphc->wState & CBF_EDIT )
1364 EnableWindow32( lphc->hWndEdit, (BOOL32)wParam );
1365 EnableWindow32( lphc->hWndLBox, (BOOL32)wParam );
1366 return TRUE;
1368 case WM_SETREDRAW:
1369 if( wParam )
1370 lphc->wState &= ~CBF_NOREDRAW;
1371 else
1372 lphc->wState |= CBF_NOREDRAW;
1374 if( lphc->wState & CBF_EDIT )
1375 SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1376 SendMessage32A( lphc->hWndLBox, message, wParam, lParam );
1377 return 0;
1379 case WM_SYSKEYDOWN:
1380 if( KEYDATA_ALT & HIWORD(lParam) )
1381 if( wParam == VK_UP || wParam == VK_DOWN )
1382 COMBO_FlipListbox( lphc, TRUE );
1383 break;
1385 case WM_CHAR:
1386 case WM_KEYDOWN:
1387 if( lphc->wState & CBF_EDIT )
1388 return SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1389 else
1390 return SendMessage32A( lphc->hWndLBox, message, wParam, lParam );
1392 case WM_LBUTTONDOWN:
1393 if( !(lphc->wState & CBF_FOCUSED) ) SetFocus32( lphc->self->hwndSelf );
1394 if( lphc->wState & CBF_FOCUSED ) COMBO_LButtonDown( lphc, lParam );
1395 return TRUE;
1397 case WM_LBUTTONUP:
1398 COMBO_LButtonUp( lphc, lParam );
1399 return TRUE;
1401 case WM_MOUSEMOVE:
1402 if( lphc->wState & CBF_CAPTURE )
1403 COMBO_MouseMove( lphc, wParam, lParam );
1404 return TRUE;
1406 /* Combo messages */
1408 case CB_ADDSTRING16:
1409 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1410 case CB_ADDSTRING32:
1411 return SendMessage32A( lphc->hWndLBox, LB_ADDSTRING32, 0, lParam);
1413 case CB_INSERTSTRING16:
1414 wParam = (INT32)(INT16)wParam;
1415 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1416 case CB_INSERTSTRING32:
1417 return SendMessage32A( lphc->hWndLBox, LB_INSERTSTRING32, wParam, lParam);
1419 case CB_DELETESTRING16:
1420 case CB_DELETESTRING32:
1421 return SendMessage32A( lphc->hWndLBox, LB_DELETESTRING32, wParam, 0);
1423 case CB_SELECTSTRING16:
1424 wParam = (INT32)(INT16)wParam;
1425 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1426 case CB_SELECTSTRING32:
1427 return COMBO_SelectString( lphc, (INT32)wParam, (LPSTR)lParam );
1429 case CB_FINDSTRING16:
1430 wParam = (INT32)(INT16)wParam;
1431 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1432 case CB_FINDSTRING32:
1433 return SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32, wParam, lParam);
1435 case CB_FINDSTRINGEXACT16:
1436 wParam = (INT32)(INT16)wParam;
1437 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1438 case CB_FINDSTRINGEXACT32:
1439 return SendMessage32A( lphc->hWndLBox, LB_FINDSTRINGEXACT32,
1440 wParam, lParam );
1441 case CB_SETITEMHEIGHT16:
1442 wParam = (INT32)(INT16)wParam; /* signed integer */
1443 case CB_SETITEMHEIGHT32:
1444 return COMBO_SetItemHeight( lphc, (INT32)wParam, (INT32)lParam);
1446 case CB_GETITEMHEIGHT16:
1447 wParam = (INT32)(INT16)wParam;
1448 case CB_GETITEMHEIGHT32:
1449 if( (INT32)wParam >= 0 ) /* listbox item */
1450 return SendMessage32A( lphc->hWndLBox, LB_GETITEMHEIGHT32, wParam, 0);
1451 return (lphc->RectEdit.bottom - lphc->RectEdit.top);
1453 case CB_RESETCONTENT16:
1454 case CB_RESETCONTENT32:
1455 SendMessage32A( lphc->hWndLBox, LB_RESETCONTENT32, 0, 0 );
1456 CBPaintText( lphc, 0 );
1457 return TRUE;
1459 case CB_INITSTORAGE32:
1460 return SendMessage32A( lphc->hWndLBox, LB_INITSTORAGE32, wParam, lParam);
1462 case CB_GETHORIZONTALEXTENT32:
1463 return SendMessage32A( lphc->hWndLBox, LB_GETHORIZONTALEXTENT32, 0, 0);
1465 case CB_SETHORIZONTALEXTENT32:
1466 return SendMessage32A( lphc->hWndLBox, LB_SETHORIZONTALEXTENT32, wParam, 0);
1468 case CB_GETTOPINDEX32:
1469 return SendMessage32A( lphc->hWndLBox, LB_GETTOPINDEX32, 0, 0);
1471 case CB_GETLOCALE32:
1472 return SendMessage32A( lphc->hWndLBox, LB_GETLOCALE32, 0, 0);
1474 case CB_SETLOCALE32:
1475 return SendMessage32A( lphc->hWndLBox, LB_SETLOCALE32, wParam, 0);
1477 case CB_GETDROPPEDWIDTH32:
1478 if( lphc->droppedWidth )
1479 return lphc->droppedWidth;
1480 return lphc->RectCombo.right - lphc->RectCombo.left -
1481 (lphc->wState & CBF_EDIT) ? CBitOffset : 0;
1483 case CB_SETDROPPEDWIDTH32:
1484 if( (CB_GETTYPE(lphc) != CBS_SIMPLE) &&
1485 (INT32)wParam < 32768 ) lphc->droppedWidth = (INT32)wParam;
1486 return CB_ERR;
1488 case CB_GETDROPPEDCONTROLRECT16:
1489 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1490 if( lParam )
1492 RECT32 r;
1493 CBGetDroppedControlRect32( lphc, &r );
1494 CONV_RECT32TO16( &r, (LPRECT16)lParam );
1496 return CB_OKAY;
1498 case CB_GETDROPPEDCONTROLRECT32:
1499 if( lParam ) CBGetDroppedControlRect32(lphc, (LPRECT32)lParam );
1500 return CB_OKAY;
1502 case CB_GETDROPPEDSTATE16:
1503 case CB_GETDROPPEDSTATE32:
1504 return (lphc->wState & CBF_DROPPED) ? TRUE : FALSE;
1506 case CB_DIR16:
1507 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1508 /* fall through */
1509 case CB_DIR32:
1510 return COMBO_Directory( lphc, (UINT32)wParam,
1511 (LPSTR)lParam, (message == CB_DIR32));
1512 case CB_SHOWDROPDOWN16:
1513 case CB_SHOWDROPDOWN32:
1514 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
1516 if( wParam )
1518 if( !(lphc->wState & CBF_DROPPED) )
1519 CBDropDown( lphc );
1521 else
1522 if( lphc->wState & CBF_DROPPED )
1523 CBRollUp( lphc, FALSE, TRUE );
1525 return TRUE;
1527 case CB_GETCOUNT16:
1528 case CB_GETCOUNT32:
1529 return SendMessage32A( lphc->hWndLBox, LB_GETCOUNT32, 0, 0);
1531 case CB_GETCURSEL16:
1532 case CB_GETCURSEL32:
1533 return SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0);
1535 case CB_SETCURSEL16:
1536 wParam = (INT32)(INT16)wParam;
1537 case CB_SETCURSEL32:
1538 return SendMessage32A( lphc->hWndLBox, LB_SETCURSEL32, wParam, 0);
1540 case CB_GETLBTEXT16:
1541 wParam = (INT32)(INT16)wParam;
1542 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1543 case CB_GETLBTEXT32:
1544 return SendMessage32A( lphc->hWndLBox, LB_GETTEXT32, wParam, lParam);
1546 case CB_GETLBTEXTLEN16:
1547 wParam = (INT32)(INT16)wParam;
1548 case CB_GETLBTEXTLEN32:
1549 return SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, wParam, 0);
1551 case CB_GETITEMDATA16:
1552 wParam = (INT32)(INT16)wParam;
1553 case CB_GETITEMDATA32:
1554 return SendMessage32A( lphc->hWndLBox, LB_GETITEMDATA32, wParam, 0);
1556 case CB_SETITEMDATA16:
1557 wParam = (INT32)(INT16)wParam;
1558 case CB_SETITEMDATA32:
1559 return SendMessage32A( lphc->hWndLBox, LB_SETITEMDATA32, wParam, lParam);
1561 case CB_GETEDITSEL16:
1562 wParam = lParam = 0; /* just in case */
1563 case CB_GETEDITSEL32:
1564 if( lphc->wState & CBF_EDIT )
1566 INT32 a, b;
1568 return SendMessage32A( lphc->hWndEdit, EM_GETSEL32,
1569 (wParam) ? wParam : (WPARAM32)&a,
1570 (lParam) ? lParam : (LPARAM)&b );
1572 return CB_ERR;
1574 case CB_SETEDITSEL16:
1575 case CB_SETEDITSEL32:
1576 if( lphc->wState & CBF_EDIT )
1577 return SendMessage32A( lphc->hWndEdit, EM_SETSEL32,
1578 (INT32)(INT16)LOWORD(lParam), (INT32)(INT16)HIWORD(lParam) );
1579 return CB_ERR;
1581 case CB_SETEXTENDEDUI16:
1582 case CB_SETEXTENDEDUI32:
1583 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) return CB_ERR;
1585 if( wParam )
1586 lphc->wState |= CBF_EUI;
1587 else lphc->wState &= ~CBF_EUI;
1588 return CB_OKAY;
1590 case CB_GETEXTENDEDUI16:
1591 case CB_GETEXTENDEDUI32:
1592 return (lphc->wState & CBF_EUI) ? TRUE : FALSE;
1594 case (WM_USER + 0x1B):
1595 WARN(combo, "[%04x]: undocumented msg!\n", hwnd );
1597 return DefWindowProc32A(hwnd, message, wParam, lParam);
1599 return CB_ERR;