CB_GETTEXT: Use lpBuffer instead of lpText for LB_GETTEXT32, handle 0
[wine/multimedia.git] / controls / combo.c
blobfc5aade87e752edf855e889b473924d877cb4665
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)lpBuffer );
1006 /* truncate if buffer is too short */
1008 if( length >= N )
1010 if (N && lpText) {
1011 if( n != LB_ERR ) memcpy( lpText, lpBuffer, (N>n) ? n+1 : N-1 );
1012 lpText[N - 1] = '\0';
1014 HeapFree( GetProcessHeap(), 0, lpBuffer );
1016 return (LRESULT)n;
1020 return 0;
1024 /***********************************************************************
1025 * CBResetPos
1027 * This function sets window positions according to the updated
1028 * component placement struct.
1030 static void CBResetPos( LPHEADCOMBO lphc, LPRECT32 lbRect, BOOL32 bRedraw )
1032 BOOL32 bDrop = (CB_GETTYPE(lphc) != CBS_SIMPLE);
1034 /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
1035 * sizing messages */
1037 if( lphc->wState & CBF_EDIT )
1038 SetWindowPos32( lphc->hWndEdit, 0, lphc->RectEdit.left, lphc->RectEdit.top,
1039 lphc->RectEdit.right - lphc->RectEdit.left,
1040 lphc->RectEdit.bottom - lphc->RectEdit.top,
1041 SWP_NOZORDER | SWP_NOACTIVATE | ((bDrop) ? SWP_NOREDRAW : 0) );
1043 if( bDrop )
1044 OffsetRect32( lbRect, lphc->RectCombo.left, lphc->RectCombo.top );
1046 lbRect->right -= lbRect->left; /* convert to width */
1047 lbRect->bottom -= lbRect->top;
1048 SetWindowPos32( lphc->hWndLBox, 0, lbRect->left, lbRect->top,
1049 lbRect->right, lbRect->bottom,
1050 SWP_NOACTIVATE | SWP_NOZORDER | ((bDrop) ? SWP_NOREDRAW : 0) );
1052 if( bDrop )
1054 if( lphc->wState & CBF_DROPPED )
1056 lphc->wState &= ~CBF_DROPPED;
1057 ShowWindow32( lphc->hWndLBox, SW_HIDE );
1060 lphc->wState |= CBF_NORESIZE;
1061 SetWindowPos32( lphc->self->hwndSelf, 0, 0, 0,
1062 lphc->RectCombo.right - lphc->RectCombo.left,
1063 lphc->RectEdit.bottom - lphc->RectEdit.top,
1064 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW );
1065 lphc->wState &= ~CBF_NORESIZE;
1067 if( bRedraw && !(lphc->wState & CBF_NOREDRAW) )
1068 RedrawWindow32( lphc->self->hwndSelf, NULL, 0,
1069 RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
1074 /***********************************************************************
1075 * COMBO_Size
1077 static void COMBO_Size( LPHEADCOMBO lphc )
1079 RECT32 rect;
1080 INT32 w, h;
1082 GetWindowRect32( lphc->self->hwndSelf, &rect );
1083 w = rect.right - rect.left; h = rect.bottom - rect.top;
1085 TRACE(combo,"w = %i, h = %i\n", w, h );
1087 /* CreateWindow() may send a bogus WM_SIZE, ignore it */
1089 if( w == (lphc->RectCombo.right - lphc->RectCombo.left) )
1091 if( (CB_GETTYPE(lphc) == CBS_SIMPLE) &&
1092 (h == (lphc->RectCombo.bottom - lphc->RectCombo.top)) )
1093 return;
1094 else if( (lphc->dwStyle & CBS_DROPDOWN) &&
1095 (h == (lphc->RectEdit.bottom - lphc->RectEdit.top)) )
1096 return;
1098 lphc->RectCombo = rect;
1099 CBCalcPlacement( lphc, &lphc->RectEdit, &lphc->RectButton, &rect );
1100 CBResetPos( lphc, &rect, TRUE );
1104 /***********************************************************************
1105 * COMBO_Font
1107 static void COMBO_Font( LPHEADCOMBO lphc, HFONT32 hFont, BOOL32 bRedraw )
1109 RECT32 rect;
1111 lphc->hFont = hFont;
1113 if( lphc->wState & CBF_EDIT )
1114 SendMessage32A( lphc->hWndEdit, WM_SETFONT, (WPARAM32)hFont, bRedraw );
1115 SendMessage32A( lphc->hWndLBox, WM_SETFONT, (WPARAM32)hFont, bRedraw );
1117 GetWindowRect32( lphc->self->hwndSelf, &rect );
1118 OffsetRect32( &lphc->RectCombo, rect.left - lphc->RectCombo.left,
1119 rect.top - lphc->RectCombo.top );
1120 CBCalcPlacement( lphc, &lphc->RectEdit,
1121 &lphc->RectButton, &rect );
1122 CBResetPos( lphc, &rect, bRedraw );
1126 /***********************************************************************
1127 * COMBO_SetItemHeight
1129 static LRESULT COMBO_SetItemHeight( LPHEADCOMBO lphc, INT32 index, INT32 height )
1131 LRESULT lRet = CB_ERR;
1133 if( index == -1 ) /* set text field height */
1135 if( height < 32768 )
1137 RECT32 rect;
1139 lphc->editHeight = height;
1140 GetWindowRect32( lphc->self->hwndSelf, &rect );
1141 OffsetRect32( &lphc->RectCombo, rect.left - lphc->RectCombo.left,
1142 rect.top - lphc->RectCombo.top );
1143 CBCalcPlacement( lphc, &lphc->RectEdit,
1144 &lphc->RectButton, &rect );
1145 CBResetPos( lphc, &rect, TRUE );
1146 lRet = height;
1149 else if ( CB_OWNERDRAWN(lphc) ) /* set listbox item height */
1150 lRet = SendMessage32A( lphc->hWndLBox, LB_SETITEMHEIGHT32,
1151 (WPARAM32)index, (LPARAM)height );
1152 return lRet;
1155 /***********************************************************************
1156 * COMBO_SelectString
1158 static LRESULT COMBO_SelectString( LPHEADCOMBO lphc, INT32 start, LPCSTR pText )
1160 INT32 index = SendMessage32A( lphc->hWndLBox, LB_SELECTSTRING32,
1161 (WPARAM32)start, (LPARAM)pText );
1162 if( index >= 0 )
1164 if( lphc->wState & CBF_EDIT )
1165 CBUpdateEdit( lphc, index );
1166 else
1167 CBPaintText( lphc, 0 );
1169 return (LRESULT)index;
1172 /***********************************************************************
1173 * COMBO_LButtonDown
1175 static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam )
1177 POINT32 pt = { LOWORD(lParam), HIWORD(lParam) };
1178 BOOL32 bButton = PtInRect32(&lphc->RectButton, pt);
1179 HWND32 hWnd = lphc->self->hwndSelf;
1181 if( (CB_GETTYPE(lphc) == CBS_DROPDOWNLIST) ||
1182 (bButton && (CB_GETTYPE(lphc) == CBS_DROPDOWN)) )
1184 lphc->wState |= CBF_BUTTONDOWN;
1185 if( lphc->wState & CBF_DROPPED )
1187 /* got a click to cancel selection */
1189 CBRollUp( lphc, TRUE, FALSE );
1190 if( !IsWindow32( hWnd ) ) return;
1192 if( lphc->wState & CBF_CAPTURE )
1194 lphc->wState &= ~CBF_CAPTURE;
1195 ReleaseCapture();
1197 lphc->wState &= ~CBF_BUTTONDOWN;
1199 else
1201 /* drop down the listbox and start tracking */
1203 lphc->wState |= CBF_CAPTURE;
1204 CBDropDown( lphc );
1205 SetCapture32( hWnd );
1207 if( bButton ) CBRepaintButton( lphc );
1211 /***********************************************************************
1212 * COMBO_LButtonUp
1214 * Release capture and stop tracking if needed.
1216 static void COMBO_LButtonUp( LPHEADCOMBO lphc, LPARAM lParam )
1218 if( lphc->wState & CBF_CAPTURE )
1220 lphc->wState &= ~CBF_CAPTURE;
1221 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
1223 INT32 index = CBUpdateLBox( lphc );
1224 CBUpdateEdit( lphc, index );
1226 ReleaseCapture();
1229 if( lphc->wState & CBF_BUTTONDOWN )
1231 lphc->wState &= ~CBF_BUTTONDOWN;
1232 CBRepaintButton( lphc );
1236 /***********************************************************************
1237 * COMBO_MouseMove
1239 * Two things to do - track combo button and release capture when
1240 * pointer goes into the listbox.
1242 static void COMBO_MouseMove( LPHEADCOMBO lphc, WPARAM32 wParam, LPARAM lParam )
1244 POINT32 pt = { LOWORD(lParam), HIWORD(lParam) };
1245 RECT32 lbRect;
1247 if( lphc->wState & CBF_BUTTONDOWN )
1249 BOOL32 bButton = PtInRect32(&lphc->RectButton, pt);
1251 if( !bButton )
1253 lphc->wState &= ~CBF_BUTTONDOWN;
1254 CBRepaintButton( lphc );
1258 GetClientRect32( lphc->hWndLBox, &lbRect );
1259 MapWindowPoints32( lphc->self->hwndSelf, lphc->hWndLBox, &pt, 1 );
1260 if( PtInRect32(&lbRect, pt) )
1262 lphc->wState &= ~CBF_CAPTURE;
1263 ReleaseCapture();
1264 if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) CBUpdateLBox( lphc );
1266 /* hand over pointer tracking */
1267 SendMessage32A( lphc->hWndLBox, WM_LBUTTONDOWN, wParam, lParam );
1272 /***********************************************************************
1273 * ComboWndProc
1275 * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/ctrl/src/combobox_15.htm
1277 LRESULT WINAPI ComboWndProc( HWND32 hwnd, UINT32 message,
1278 WPARAM32 wParam, LPARAM lParam )
1280 WND* pWnd = WIN_FindWndPtr(hwnd);
1282 if( pWnd )
1284 LPHEADCOMBO lphc = CB_GETPTR(pWnd);
1286 TRACE(combo, "[%04x]: msg %s wp %08x lp %08lx\n",
1287 pWnd->hwndSelf, SPY_GetMsgName(message), wParam, lParam );
1289 if( lphc || message == WM_NCCREATE )
1290 switch(message)
1293 /* System messages */
1295 case WM_NCCREATE:
1296 return COMBO_NCCreate(pWnd, lParam);
1298 case WM_NCDESTROY:
1299 COMBO_NCDestroy(lphc);
1300 break;
1302 case WM_CREATE:
1303 return COMBO_Create(lphc, pWnd, lParam);
1305 case WM_PAINT:
1306 /* wParam may contain a valid HDC! */
1307 return COMBO_Paint(lphc, wParam);
1309 case WM_ERASEBKGND:
1310 return TRUE;
1312 case WM_GETDLGCODE:
1313 return (LRESULT)(DLGC_WANTARROWS | DLGC_WANTCHARS);
1315 case WM_SIZE:
1316 if( lphc->hWndLBox &&
1317 !(lphc->wState & CBF_NORESIZE) ) COMBO_Size( lphc );
1318 return TRUE;
1320 case WM_SETFONT:
1321 COMBO_Font( lphc, (HFONT16)wParam, (BOOL32)lParam );
1322 return TRUE;
1324 case WM_GETFONT:
1325 return (LRESULT)lphc->hFont;
1327 case WM_SETFOCUS:
1328 if( lphc->wState & CBF_EDIT )
1329 SetFocus32( lphc->hWndEdit );
1330 else
1331 COMBO_SetFocus( lphc );
1332 return TRUE;
1334 case WM_KILLFOCUS:
1335 #define hwndFocus ((HWND16)wParam)
1336 if( !hwndFocus ||
1337 (hwndFocus != lphc->hWndEdit && hwndFocus != lphc->hWndLBox ))
1338 COMBO_KillFocus( lphc );
1339 #undef hwndFocus
1340 return TRUE;
1342 case WM_COMMAND:
1343 return COMBO_Command( lphc, wParam, (HWND32)lParam );
1345 case WM_GETTEXT:
1346 return COMBO_GetText( lphc, (UINT32)wParam, (LPSTR)lParam );
1348 case WM_SETTEXT:
1349 case WM_GETTEXTLENGTH:
1350 case WM_CLEAR:
1351 case WM_CUT:
1352 case WM_PASTE:
1353 case WM_COPY:
1354 if( lphc->wState & CBF_EDIT )
1355 return SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1356 return CB_ERR;
1358 case WM_DRAWITEM:
1359 case WM_DELETEITEM:
1360 case WM_COMPAREITEM:
1361 case WM_MEASUREITEM:
1362 return COMBO_ItemOp32( lphc, message, wParam, lParam );
1364 case WM_ENABLE:
1365 if( lphc->wState & CBF_EDIT )
1366 EnableWindow32( lphc->hWndEdit, (BOOL32)wParam );
1367 EnableWindow32( lphc->hWndLBox, (BOOL32)wParam );
1368 return TRUE;
1370 case WM_SETREDRAW:
1371 if( wParam )
1372 lphc->wState &= ~CBF_NOREDRAW;
1373 else
1374 lphc->wState |= CBF_NOREDRAW;
1376 if( lphc->wState & CBF_EDIT )
1377 SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1378 SendMessage32A( lphc->hWndLBox, message, wParam, lParam );
1379 return 0;
1381 case WM_SYSKEYDOWN:
1382 if( KEYDATA_ALT & HIWORD(lParam) )
1383 if( wParam == VK_UP || wParam == VK_DOWN )
1384 COMBO_FlipListbox( lphc, TRUE );
1385 break;
1387 case WM_CHAR:
1388 case WM_KEYDOWN:
1389 if( lphc->wState & CBF_EDIT )
1390 return SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1391 else
1392 return SendMessage32A( lphc->hWndLBox, message, wParam, lParam );
1394 case WM_LBUTTONDOWN:
1395 if( !(lphc->wState & CBF_FOCUSED) ) SetFocus32( lphc->self->hwndSelf );
1396 if( lphc->wState & CBF_FOCUSED ) COMBO_LButtonDown( lphc, lParam );
1397 return TRUE;
1399 case WM_LBUTTONUP:
1400 COMBO_LButtonUp( lphc, lParam );
1401 return TRUE;
1403 case WM_MOUSEMOVE:
1404 if( lphc->wState & CBF_CAPTURE )
1405 COMBO_MouseMove( lphc, wParam, lParam );
1406 return TRUE;
1408 /* Combo messages */
1410 case CB_ADDSTRING16:
1411 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1412 case CB_ADDSTRING32:
1413 return SendMessage32A( lphc->hWndLBox, LB_ADDSTRING32, 0, lParam);
1415 case CB_INSERTSTRING16:
1416 wParam = (INT32)(INT16)wParam;
1417 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1418 case CB_INSERTSTRING32:
1419 return SendMessage32A( lphc->hWndLBox, LB_INSERTSTRING32, wParam, lParam);
1421 case CB_DELETESTRING16:
1422 case CB_DELETESTRING32:
1423 return SendMessage32A( lphc->hWndLBox, LB_DELETESTRING32, wParam, 0);
1425 case CB_SELECTSTRING16:
1426 wParam = (INT32)(INT16)wParam;
1427 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1428 case CB_SELECTSTRING32:
1429 return COMBO_SelectString( lphc, (INT32)wParam, (LPSTR)lParam );
1431 case CB_FINDSTRING16:
1432 wParam = (INT32)(INT16)wParam;
1433 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1434 case CB_FINDSTRING32:
1435 return SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32, wParam, lParam);
1437 case CB_FINDSTRINGEXACT16:
1438 wParam = (INT32)(INT16)wParam;
1439 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1440 case CB_FINDSTRINGEXACT32:
1441 return SendMessage32A( lphc->hWndLBox, LB_FINDSTRINGEXACT32,
1442 wParam, lParam );
1443 case CB_SETITEMHEIGHT16:
1444 wParam = (INT32)(INT16)wParam; /* signed integer */
1445 case CB_SETITEMHEIGHT32:
1446 return COMBO_SetItemHeight( lphc, (INT32)wParam, (INT32)lParam);
1448 case CB_GETITEMHEIGHT16:
1449 wParam = (INT32)(INT16)wParam;
1450 case CB_GETITEMHEIGHT32:
1451 if( (INT32)wParam >= 0 ) /* listbox item */
1452 return SendMessage32A( lphc->hWndLBox, LB_GETITEMHEIGHT32, wParam, 0);
1453 return (lphc->RectEdit.bottom - lphc->RectEdit.top);
1455 case CB_RESETCONTENT16:
1456 case CB_RESETCONTENT32:
1457 SendMessage32A( lphc->hWndLBox, LB_RESETCONTENT32, 0, 0 );
1458 CBPaintText( lphc, 0 );
1459 return TRUE;
1461 case CB_INITSTORAGE32:
1462 return SendMessage32A( lphc->hWndLBox, LB_INITSTORAGE32, wParam, lParam);
1464 case CB_GETHORIZONTALEXTENT32:
1465 return SendMessage32A( lphc->hWndLBox, LB_GETHORIZONTALEXTENT32, 0, 0);
1467 case CB_SETHORIZONTALEXTENT32:
1468 return SendMessage32A( lphc->hWndLBox, LB_SETHORIZONTALEXTENT32, wParam, 0);
1470 case CB_GETTOPINDEX32:
1471 return SendMessage32A( lphc->hWndLBox, LB_GETTOPINDEX32, 0, 0);
1473 case CB_GETLOCALE32:
1474 return SendMessage32A( lphc->hWndLBox, LB_GETLOCALE32, 0, 0);
1476 case CB_SETLOCALE32:
1477 return SendMessage32A( lphc->hWndLBox, LB_SETLOCALE32, wParam, 0);
1479 case CB_GETDROPPEDWIDTH32:
1480 if( lphc->droppedWidth )
1481 return lphc->droppedWidth;
1482 return lphc->RectCombo.right - lphc->RectCombo.left -
1483 (lphc->wState & CBF_EDIT) ? CBitOffset : 0;
1485 case CB_SETDROPPEDWIDTH32:
1486 if( (CB_GETTYPE(lphc) != CBS_SIMPLE) &&
1487 (INT32)wParam < 32768 ) lphc->droppedWidth = (INT32)wParam;
1488 return CB_ERR;
1490 case CB_GETDROPPEDCONTROLRECT16:
1491 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1492 if( lParam )
1494 RECT32 r;
1495 CBGetDroppedControlRect32( lphc, &r );
1496 CONV_RECT32TO16( &r, (LPRECT16)lParam );
1498 return CB_OKAY;
1500 case CB_GETDROPPEDCONTROLRECT32:
1501 if( lParam ) CBGetDroppedControlRect32(lphc, (LPRECT32)lParam );
1502 return CB_OKAY;
1504 case CB_GETDROPPEDSTATE16:
1505 case CB_GETDROPPEDSTATE32:
1506 return (lphc->wState & CBF_DROPPED) ? TRUE : FALSE;
1508 case CB_DIR16:
1509 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1510 /* fall through */
1511 case CB_DIR32:
1512 return COMBO_Directory( lphc, (UINT32)wParam,
1513 (LPSTR)lParam, (message == CB_DIR32));
1514 case CB_SHOWDROPDOWN16:
1515 case CB_SHOWDROPDOWN32:
1516 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
1518 if( wParam )
1520 if( !(lphc->wState & CBF_DROPPED) )
1521 CBDropDown( lphc );
1523 else
1524 if( lphc->wState & CBF_DROPPED )
1525 CBRollUp( lphc, FALSE, TRUE );
1527 return TRUE;
1529 case CB_GETCOUNT16:
1530 case CB_GETCOUNT32:
1531 return SendMessage32A( lphc->hWndLBox, LB_GETCOUNT32, 0, 0);
1533 case CB_GETCURSEL16:
1534 case CB_GETCURSEL32:
1535 return SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0);
1537 case CB_SETCURSEL16:
1538 wParam = (INT32)(INT16)wParam;
1539 case CB_SETCURSEL32:
1540 return SendMessage32A( lphc->hWndLBox, LB_SETCURSEL32, wParam, 0);
1542 case CB_GETLBTEXT16:
1543 wParam = (INT32)(INT16)wParam;
1544 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1545 case CB_GETLBTEXT32:
1546 return SendMessage32A( lphc->hWndLBox, LB_GETTEXT32, wParam, lParam);
1548 case CB_GETLBTEXTLEN16:
1549 wParam = (INT32)(INT16)wParam;
1550 case CB_GETLBTEXTLEN32:
1551 return SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, wParam, 0);
1553 case CB_GETITEMDATA16:
1554 wParam = (INT32)(INT16)wParam;
1555 case CB_GETITEMDATA32:
1556 return SendMessage32A( lphc->hWndLBox, LB_GETITEMDATA32, wParam, 0);
1558 case CB_SETITEMDATA16:
1559 wParam = (INT32)(INT16)wParam;
1560 case CB_SETITEMDATA32:
1561 return SendMessage32A( lphc->hWndLBox, LB_SETITEMDATA32, wParam, lParam);
1563 case CB_GETEDITSEL16:
1564 wParam = lParam = 0; /* just in case */
1565 case CB_GETEDITSEL32:
1566 if( lphc->wState & CBF_EDIT )
1568 INT32 a, b;
1570 return SendMessage32A( lphc->hWndEdit, EM_GETSEL32,
1571 (wParam) ? wParam : (WPARAM32)&a,
1572 (lParam) ? lParam : (LPARAM)&b );
1574 return CB_ERR;
1576 case CB_SETEDITSEL16:
1577 case CB_SETEDITSEL32:
1578 if( lphc->wState & CBF_EDIT )
1579 return SendMessage32A( lphc->hWndEdit, EM_SETSEL32,
1580 (INT32)(INT16)LOWORD(lParam), (INT32)(INT16)HIWORD(lParam) );
1581 return CB_ERR;
1583 case CB_SETEXTENDEDUI16:
1584 case CB_SETEXTENDEDUI32:
1585 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) return CB_ERR;
1587 if( wParam )
1588 lphc->wState |= CBF_EUI;
1589 else lphc->wState &= ~CBF_EUI;
1590 return CB_OKAY;
1592 case CB_GETEXTENDEDUI16:
1593 case CB_GETEXTENDEDUI32:
1594 return (lphc->wState & CBF_EUI) ? TRUE : FALSE;
1596 case (WM_USER + 0x1B):
1597 WARN(combo, "[%04x]: undocumented msg!\n", hwnd );
1599 return DefWindowProc32A(hwnd, message, wParam, lParam);
1601 return CB_ERR;