Replace GRAPH_ functions with Win SDK equivalents.
[wine/multimedia.git] / controls / combo.c
blob8276351559475be5a7389dad615c71d04bedde8d
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 "heap.h"
17 #include "combo.h"
18 #include "drive.h"
19 #include "debug.h"
21 /* bits in the dwKeyData */
22 #define KEYDATA_ALT 0x2000
23 #define KEYDATA_PREVSTATE 0x4000
26 * Additional combo box definitions
29 #define CB_GETPTR( wnd ) (*(LPHEADCOMBO*)((wnd)->wExtra))
30 #define CB_NOTIFY( lphc, code ) \
31 (SendMessage32A( (lphc)->owner, WM_COMMAND, \
32 MAKEWPARAM((lphc)->self->wIDmenu, (code)), (lphc)->self->hwndSelf))
33 #define CB_GETEDITTEXTLENGTH( lphc ) \
34 (SendMessage32A( (lphc)->hWndEdit, WM_GETTEXTLENGTH, 0, 0 ))
36 static HBITMAP32 hComboBmp = 0;
37 static UINT32 CBitHeight, CBitWidth;
38 static UINT32 CBitOffset = 8;
40 /***********************************************************************
41 * COMBO_Init
43 * Load combo button bitmap.
45 static BOOL32 COMBO_Init()
47 HDC32 hDC;
49 if( hComboBmp ) return TRUE;
50 if( (hDC = CreateCompatibleDC32(0)) )
52 BOOL32 bRet = FALSE;
53 if( (hComboBmp = LoadBitmap32A(0, MAKEINTRESOURCE32A(OBM_COMBO))) )
55 BITMAP32 bm;
56 HBITMAP32 hPrevB;
57 RECT32 r;
59 GetObject32A( hComboBmp, sizeof(bm), &bm );
60 CBitHeight = bm.bmHeight;
61 CBitWidth = bm.bmWidth;
63 TRACE(combo, "combo bitmap [%i,%i]\n", CBitWidth, CBitHeight );
65 hPrevB = SelectObject16( hDC, hComboBmp);
66 SetRect32( &r, 0, 0, CBitWidth, CBitHeight );
67 InvertRect32( hDC, &r );
68 SelectObject32( hDC, hPrevB );
69 bRet = TRUE;
71 DeleteDC32( hDC );
72 return bRet;
74 return FALSE;
77 /***********************************************************************
78 * COMBO_NCCreate
80 static LRESULT COMBO_NCCreate(WND* wnd, LPARAM lParam)
82 LPHEADCOMBO lphc;
84 if ( wnd && COMBO_Init() &&
85 (lphc = HeapAlloc(GetProcessHeap(), 0, sizeof(HEADCOMBO))) )
87 LPCREATESTRUCT32A lpcs = (CREATESTRUCT32A*)lParam;
89 memset( lphc, 0, sizeof(HEADCOMBO) );
90 *(LPHEADCOMBO*)wnd->wExtra = lphc;
92 /* some braindead apps do try to use scrollbar/border flags */
94 lphc->dwStyle = (lpcs->style & ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL));
95 wnd->dwStyle &= ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL);
97 if( !(lpcs->style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) )
98 lphc->dwStyle |= CBS_HASSTRINGS;
99 if( !(wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) )
100 lphc->wState |= CBF_NOTIFY;
102 TRACE(combo, "[0x%08x], style = %08x\n",
103 (UINT32)lphc, lphc->dwStyle );
105 return (LRESULT)(UINT32)wnd->hwndSelf;
107 return (LRESULT)FALSE;
110 /***********************************************************************
111 * COMBO_NCDestroy
113 static LRESULT COMBO_NCDestroy( LPHEADCOMBO lphc )
116 if( lphc )
118 WND* wnd = lphc->self;
120 TRACE(combo,"[%04x]: freeing storage\n", CB_HWND(lphc));
122 if( (CB_GETTYPE(lphc) != CBS_SIMPLE) && lphc->hWndLBox )
123 DestroyWindow32( lphc->hWndLBox );
125 HeapFree( GetProcessHeap(), 0, lphc );
126 wnd->wExtra[0] = 0;
128 return 0;
131 /***********************************************************************
132 * CBGetDefaultTextHeight
134 static void CBGetDefaultTextHeight( LPHEADCOMBO lphc, LPSIZE32 lpSize )
136 if( lphc->editHeight ) /* explicitly set height */
137 lpSize->cy = lphc->editHeight;
138 else
140 HDC32 hDC = GetDC32( lphc->self->hwndSelf );
141 HFONT32 hPrevFont = 0;
143 if( lphc->hFont ) hPrevFont = SelectObject32( hDC, lphc->hFont );
145 GetTextExtentPoint32A( hDC, "0", 1, lpSize);
147 lpSize->cy += lpSize->cy / 4 + 4 * SYSMETRICS_CYBORDER;
149 if( hPrevFont ) SelectObject32( hDC, hPrevFont );
150 ReleaseDC32( lphc->self->hwndSelf, hDC );
152 lpSize->cx = lphc->RectCombo.right - lphc->RectCombo.left;
156 /***********************************************************************
157 * CBCalcPlacement
159 * Set up component coordinates given valid lphc->RectCombo.
161 static void CBCalcPlacement( LPHEADCOMBO lphc, LPRECT32 lprEdit,
162 LPRECT32 lprButton, LPRECT32 lprLB )
164 RECT32 rect = lphc->RectCombo;
165 SIZE32 size;
167 /* get combo height and width */
169 if( CB_OWNERDRAWN(lphc) )
171 UINT32 u = lphc->RectEdit.bottom - lphc->RectEdit.top;
173 if( lphc->wState & CBF_MEASUREITEM ) /* first initialization */
175 MEASUREITEMSTRUCT32 mi32;
177 /* calculate defaults before sending WM_MEASUREITEM */
179 CBGetDefaultTextHeight( lphc, &size );
181 lphc->wState &= ~CBF_MEASUREITEM;
183 mi32.CtlType = ODT_COMBOBOX;
184 mi32.CtlID = lphc->self->wIDmenu;
185 mi32.itemID = -1;
186 mi32.itemWidth = size.cx;
187 mi32.itemHeight = size.cy - 6; /* ownerdrawn cb is taller */
188 mi32.itemData = 0;
189 SendMessage32A(lphc->owner, WM_MEASUREITEM,
190 (WPARAM32)mi32.CtlID, (LPARAM)&mi32);
191 u = 6 + (UINT16)mi32.itemHeight;
193 else
194 size.cx = rect.right - rect.left;
195 size.cy = u;
197 else
198 CBGetDefaultTextHeight( lphc, &size );
200 /* calculate text and button placement */
202 lprEdit->left = lprEdit->top = lprButton->top = 0;
203 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) /* no button */
204 lprButton->left = lprButton->right = lprButton->bottom = 0;
205 else
207 INT32 i = size.cx - CBitWidth - 10; /* seems ok */
209 lprButton->right = size.cx;
210 lprButton->left = (INT16)i;
211 lprButton->bottom = lprButton->top + size.cy;
213 if( i < 0 ) size.cx = 0;
214 else size.cx = i;
217 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
219 size.cx -= CBitOffset;
220 if( size.cx < 0 ) size.cx = 0;
223 lprEdit->right = size.cx; lprEdit->bottom = size.cy;
225 /* listbox placement */
227 lprLB->left = ( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) ? 0 : CBitOffset;
228 lprLB->top = lprEdit->bottom - SYSMETRICS_CYBORDER;
229 lprLB->right = rect.right - rect.left;
230 lprLB->bottom = rect.bottom - rect.top;
232 if( lphc->droppedWidth > (lprLB->right - lprLB->left) )
233 lprLB->right = lprLB->left + lphc->droppedWidth;
235 TRACE(combo,"[%04x]: (%i,%i-%i,%i) placement\n",
236 CB_HWND(lphc), lphc->RectCombo.left, lphc->RectCombo.top,
237 lphc->RectCombo.right, lphc->RectCombo.bottom);
239 TRACE(combo,"\ttext\t= (%i,%i-%i,%i)\n",
240 lprEdit->left, lprEdit->top, lprEdit->right, lprEdit->bottom);
242 TRACE(combo,"\tbutton\t= (%i,%i-%i,%i)\n",
243 lprButton->left, lprButton->top, lprButton->right, lprButton->bottom);
245 TRACE(combo,"\tlbox\t= (%i,%i-%i,%i)\n",
246 lprLB->left, lprLB->top, lprLB->right, lprLB->bottom );
249 /***********************************************************************
250 * CBGetDroppedControlRect32
252 static void CBGetDroppedControlRect32( LPHEADCOMBO lphc, LPRECT32 lpRect)
254 lpRect->left = lphc->RectCombo.left +
255 (lphc->wState & CBF_EDIT) ? CBitOffset : 0;
256 lpRect->top = lphc->RectCombo.top + lphc->RectEdit.bottom -
257 SYSMETRICS_CYBORDER;
258 lpRect->right = lphc->RectCombo.right;
259 lpRect->bottom = lphc->RectCombo.bottom - SYSMETRICS_CYBORDER;
262 /***********************************************************************
263 * COMBO_Create
265 static LRESULT COMBO_Create( LPHEADCOMBO lphc, WND* wnd, LPARAM lParam)
267 static char clbName[] = "ComboLBox";
268 static char editName[] = "Edit";
270 LPCREATESTRUCT32A lpcs = (CREATESTRUCT32A*)lParam;
272 if( !CB_GETTYPE(lphc) ) lphc->dwStyle |= CBS_SIMPLE;
273 else if( CB_GETTYPE(lphc) != CBS_DROPDOWNLIST ) lphc->wState |= CBF_EDIT;
275 lphc->self = wnd;
276 lphc->owner = lpcs->hwndParent;
278 /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */
280 if( lphc->owner || !(lpcs->style & WS_VISIBLE) )
282 UINT32 lbeStyle;
283 RECT32 editRect, btnRect, lbRect;
285 GetWindowRect32( wnd->hwndSelf, &lphc->RectCombo );
287 lphc->wState |= CBF_MEASUREITEM;
288 CBCalcPlacement( lphc, &editRect, &btnRect, &lbRect );
289 lphc->RectButton = btnRect;
290 lphc->droppedWidth = lphc->editHeight = 0;
292 /* create listbox popup */
294 lbeStyle = (LBS_NOTIFY | WS_BORDER | WS_CLIPSIBLINGS) |
295 (lpcs->style & (WS_VSCROLL | CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE));
297 if( lphc->dwStyle & CBS_SORT )
298 lbeStyle |= LBS_SORT;
299 if( lphc->dwStyle & CBS_HASSTRINGS )
300 lbeStyle |= LBS_HASSTRINGS;
301 if( lphc->dwStyle & CBS_NOINTEGRALHEIGHT )
302 lbeStyle |= LBS_NOINTEGRALHEIGHT;
303 if( lphc->dwStyle & CBS_DISABLENOSCROLL )
304 lbeStyle |= LBS_DISABLENOSCROLL;
306 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) /* child listbox */
307 lbeStyle |= WS_CHILD | WS_VISIBLE;
308 else /* popup listbox */
310 lbeStyle |= WS_POPUP;
311 OffsetRect32( &lbRect, lphc->RectCombo.left, lphc->RectCombo.top );
314 /* Dropdown ComboLBox is not a child window and we cannot pass
315 * ID_CB_LISTBOX directly because it will be treated as a menu handle.
318 lphc->hWndLBox = CreateWindowEx32A( 0, clbName, NULL, lbeStyle,
319 lbRect.left + SYSMETRICS_CXBORDER,
320 lbRect.top + SYSMETRICS_CYBORDER,
321 lbRect.right - lbRect.left - 2 * SYSMETRICS_CXBORDER,
322 lbRect.bottom - lbRect.top - 2 * SYSMETRICS_CYBORDER,
323 lphc->self->hwndSelf,
324 (lphc->dwStyle & CBS_DROPDOWN)? (HMENU32)0 : (HMENU32)ID_CB_LISTBOX,
325 lphc->self->hInstance, (LPVOID)lphc );
326 if( lphc->hWndLBox )
328 BOOL32 bEdit = TRUE;
329 lbeStyle = WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NOHIDESEL | ES_LEFT;
330 if( lphc->wState & CBF_EDIT )
332 if( lphc->dwStyle & CBS_OEMCONVERT )
333 lbeStyle |= ES_OEMCONVERT;
334 if( lphc->dwStyle & CBS_AUTOHSCROLL )
335 lbeStyle |= ES_AUTOHSCROLL;
336 if( lphc->dwStyle & CBS_LOWERCASE )
337 lbeStyle |= ES_LOWERCASE;
338 else if( lphc->dwStyle & CBS_UPPERCASE )
339 lbeStyle |= ES_UPPERCASE;
340 lphc->hWndEdit = CreateWindowEx32A( 0, editName, NULL, lbeStyle,
341 editRect.left, editRect.top, editRect.right - editRect.left,
342 editRect.bottom - editRect.top, lphc->self->hwndSelf,
343 (HMENU32)ID_CB_EDIT, lphc->self->hInstance, NULL );
344 if( !lphc->hWndEdit ) bEdit = FALSE;
347 if( bEdit )
349 lphc->RectEdit = editRect;
350 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
352 lphc->wState |= CBF_NORESIZE;
353 SetWindowPos32( wnd->hwndSelf, 0, 0, 0,
354 lphc->RectCombo.right - lphc->RectCombo.left,
355 lphc->RectEdit.bottom - lphc->RectEdit.top,
356 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
357 lphc->wState &= ~CBF_NORESIZE;
359 TRACE(combo,"init done\n");
360 return wnd->hwndSelf;
362 ERR(combo, "edit control failure.\n");
363 } else ERR(combo, "listbox failure.\n");
364 } else ERR(combo, "no owner for visible combo.\n");
366 /* CreateWindow() will send WM_NCDESTROY to cleanup */
368 return -1;
371 /***********************************************************************
372 * CBPaintButton
374 * Paint combo button (normal, pressed, and disabled states).
376 static void CBPaintButton(LPHEADCOMBO lphc, HDC32 hdc)
378 RECT32 r;
379 UINT32 x, y;
380 BOOL32 bBool;
381 HDC32 hMemDC;
382 HBRUSH32 hPrevBrush;
383 COLORREF oldTextColor, oldBkColor;
385 if( lphc->wState & CBF_NOREDRAW ) return;
387 hPrevBrush = SelectObject32(hdc, GetSysColorBrush32(COLOR_BTNFACE));
388 CONV_RECT16TO32( &lphc->RectButton, &r );
390 Rectangle32(hdc, r.left, r.top, r.right, r.bottom );
391 if( (bBool = lphc->wState & CBF_BUTTONDOWN) )
393 DrawEdge32( hdc, &r, EDGE_SUNKEN, BF_RECT );
394 OffsetRect32( &r, 1, 1 );
395 } else {
396 r.top++, r.left++;
397 DrawEdge32( hdc, &r, EDGE_RAISED, BF_RECT );
398 r.top--, r.left--;
401 InflateRect32( &r, -1, -1 );
403 x = (r.left + r.right - CBitWidth) >> 1;
404 y = (r.top + r.bottom - CBitHeight) >> 1;
406 InflateRect32( &r, -3, -3 );
408 hMemDC = CreateCompatibleDC32( hdc );
409 SelectObject32( hMemDC, hComboBmp );
410 oldTextColor = SetTextColor32( hdc, GetSysColor32(COLOR_BTNFACE) );
411 oldBkColor = SetBkColor32( hdc, CB_DISABLED(lphc) ? RGB(128,128,128) :
412 RGB(0,0,0) );
413 BitBlt32( hdc, x, y, 8, 8, hMemDC, 0, 0, SRCCOPY );
414 SetBkColor32( hdc, oldBkColor );
415 SetTextColor32( hdc, oldTextColor );
416 DeleteDC32( hMemDC );
417 SelectObject32( hdc, hPrevBrush );
420 /***********************************************************************
421 * CBPaintText
423 * Paint CBS_DROPDOWNLIST text field / update edit control contents.
425 static void CBPaintText(LPHEADCOMBO lphc, HDC32 hdc)
427 INT32 id, size = 0;
428 LPSTR pText = NULL;
430 if( lphc->wState & CBF_NOREDRAW ) return;
432 /* follow Windows combobox that sends a bunch of text
433 * inquiries to its listbox while processing WM_PAINT. */
435 if( (id = SendMessage32A(lphc->hWndLBox, LB_GETCURSEL32, 0, 0) ) != LB_ERR )
437 size = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, id, 0);
438 if( (pText = HeapAlloc( GetProcessHeap(), 0, size + 1)) )
440 SendMessage32A( lphc->hWndLBox, LB_GETTEXT32, (WPARAM32)id, (LPARAM)pText );
441 pText[size] = '\0'; /* just in case */
442 } else return;
445 if( lphc->wState & CBF_EDIT )
447 if( CB_HASSTRINGS(lphc) ) SetWindowText32A( lphc->hWndEdit, pText ? pText : "" );
448 if( lphc->wState & CBF_FOCUSED )
449 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1));
451 else /* paint text field ourselves */
453 HBRUSH32 hPrevBrush = 0;
454 HDC32 hDC = hdc;
456 if( !hDC )
458 if ((hDC = GetDC32(lphc->self->hwndSelf)))
460 HBRUSH32 hBrush = SendMessage32A( lphc->owner,
461 WM_CTLCOLORLISTBOX,
462 hDC, lphc->self->hwndSelf );
463 hPrevBrush = SelectObject32( hDC,
464 (hBrush) ? hBrush : GetStockObject32(WHITE_BRUSH) );
467 if( hDC )
469 RECT32 rect;
470 UINT32 itemState;
471 HFONT32 hPrevFont = (lphc->hFont) ? SelectObject32(hDC, lphc->hFont) : 0;
473 PatBlt32( hDC, (rect.left = lphc->RectEdit.left + SYSMETRICS_CXBORDER),
474 (rect.top = lphc->RectEdit.top + SYSMETRICS_CYBORDER),
475 (rect.right = lphc->RectEdit.right - SYSMETRICS_CXBORDER),
476 (rect.bottom = lphc->RectEdit.bottom - SYSMETRICS_CYBORDER) - 1, PATCOPY );
477 InflateRect32( &rect, -1, -1 );
479 if( lphc->wState & CBF_FOCUSED &&
480 !(lphc->wState & CBF_DROPPED) )
482 /* highlight */
484 FillRect32( hDC, &rect, GetSysColorBrush32(COLOR_HIGHLIGHT) );
485 SetBkColor32( hDC, GetSysColor32( COLOR_HIGHLIGHT ) );
486 SetTextColor32( hDC, GetSysColor32( COLOR_HIGHLIGHTTEXT ) );
487 itemState = ODS_SELECTED | ODS_FOCUS;
488 } else itemState = 0;
490 if( CB_OWNERDRAWN(lphc) )
492 DRAWITEMSTRUCT32 dis;
494 if( lphc->self->dwStyle & WS_DISABLED ) itemState |= ODS_DISABLED;
496 dis.CtlType = ODT_COMBOBOX;
497 dis.CtlID = lphc->self->wIDmenu;
498 dis.hwndItem = lphc->self->hwndSelf;
499 dis.itemAction = ODA_DRAWENTIRE;
500 dis.itemID = id;
501 dis.itemState = itemState;
502 dis.hDC = hDC;
503 dis.rcItem = rect;
504 dis.itemData = SendMessage32A( lphc->hWndLBox, LB_GETITEMDATA32,
505 (WPARAM32)id, 0 );
506 SendMessage32A( lphc->owner, WM_DRAWITEM,
507 lphc->self->wIDmenu, (LPARAM)&dis );
509 else
511 ExtTextOut32A( hDC, rect.left + 1, rect.top + 1,
512 ETO_OPAQUE | ETO_CLIPPED, &rect,
513 pText ? pText : "" , size, NULL );
514 if(lphc->wState & CBF_FOCUSED && !(lphc->wState & CBF_DROPPED))
515 DrawFocusRect32( hDC, &rect );
518 if( hPrevFont ) SelectObject32(hDC, hPrevFont );
519 if( !hdc )
521 if( hPrevBrush ) SelectObject32( hDC, hPrevBrush );
522 ReleaseDC32( lphc->self->hwndSelf, hDC );
526 if (pText)
527 HeapFree( GetProcessHeap(), 0, pText );
530 /***********************************************************************
531 * COMBO_Paint
533 static LRESULT COMBO_Paint(LPHEADCOMBO lphc, HDC32 hParamDC)
535 PAINTSTRUCT32 ps;
536 HDC32 hDC;
538 hDC = (hParamDC) ? hParamDC
539 : BeginPaint32( lphc->self->hwndSelf, &ps);
540 if( hDC && !(lphc->wState & CBF_NOREDRAW) )
542 HBRUSH32 hPrevBrush, hBkgBrush;
544 hBkgBrush = SendMessage32A( lphc->owner, WM_CTLCOLORLISTBOX,
545 hDC, lphc->self->hwndSelf );
546 if( !hBkgBrush ) hBkgBrush = GetStockObject32(WHITE_BRUSH);
548 hPrevBrush = SelectObject32( hDC, hBkgBrush );
549 if( !IsRectEmpty32(&lphc->RectButton) )
551 /* paint everything to the right of the text field */
553 PatBlt32( hDC, lphc->RectEdit.right, lphc->RectEdit.top,
554 lphc->RectButton.right - lphc->RectEdit.right,
555 lphc->RectEdit.bottom - lphc->RectEdit.top, PATCOPY );
556 CBPaintButton( lphc, hDC );
559 if( !(lphc->wState & CBF_EDIT) )
561 /* paint text field */
563 HPEN32 hPrevPen = SelectObject32( hDC, GetSysColorPen32(
564 COLOR_WINDOWFRAME) );
566 Rectangle32( hDC, lphc->RectEdit.left, lphc->RectEdit.top,
567 lphc->RectEdit.right, lphc->RectButton.bottom );
568 SelectObject32( hDC, hPrevPen );
569 CBPaintText( lphc, hDC );
571 if( hPrevBrush ) SelectObject32( hDC, hPrevBrush );
573 if( !hParamDC ) EndPaint32(lphc->self->hwndSelf, &ps);
574 return 0;
577 /***********************************************************************
578 * CBUpdateLBox
580 * Select listbox entry according to the contents of the edit control.
582 static INT32 CBUpdateLBox( LPHEADCOMBO lphc )
584 INT32 length, idx, ret;
585 LPSTR pText = NULL;
587 idx = ret = LB_ERR;
588 length = CB_GETEDITTEXTLENGTH( lphc );
590 if( length > 0 )
591 pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1);
593 TRACE(combo,"\t edit text length %i\n", length );
595 if( pText )
597 if( length ) GetWindowText32A( lphc->hWndEdit, pText, length + 1);
598 else pText[0] = '\0';
599 idx = SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32,
600 (WPARAM32)(-1), (LPARAM)pText );
601 if( idx == LB_ERR ) idx = 0; /* select first item */
602 else ret = idx;
603 HeapFree( GetProcessHeap(), 0, pText );
606 /* select entry */
608 SendMessage32A( lphc->hWndLBox, LB_SETCURSEL32, (WPARAM32)idx, 0 );
610 if( idx >= 0 )
612 SendMessage32A( lphc->hWndLBox, LB_SETTOPINDEX32, (WPARAM32)idx, 0 );
613 /* probably superfluous but Windows sends this too */
614 SendMessage32A( lphc->hWndLBox, LB_SETCARETINDEX32, (WPARAM32)idx, 0 );
616 return ret;
619 /***********************************************************************
620 * CBUpdateEdit
622 * Copy a listbox entry to the edit control.
624 static void CBUpdateEdit( LPHEADCOMBO lphc , INT32 index )
626 INT32 length;
627 LPSTR pText = NULL;
629 TRACE(combo,"\t %i\n", index );
631 if( index == -1 )
633 length = CB_GETEDITTEXTLENGTH( lphc );
634 if( length )
636 if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) )
638 GetWindowText32A( lphc->hWndEdit, pText, length + 1 );
639 index = SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32,
640 (WPARAM32)(-1), (LPARAM)pText );
641 HeapFree( GetProcessHeap(), 0, pText );
646 if( index >= 0 ) /* got an entry */
648 length = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, (WPARAM32)index, 0);
649 if( length )
651 if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) )
653 SendMessage32A( lphc->hWndLBox, LB_GETTEXT32,
654 (WPARAM32)index, (LPARAM)pText );
655 SendMessage32A( lphc->hWndEdit, WM_SETTEXT, 0, (LPARAM)pText );
656 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1) );
657 HeapFree( GetProcessHeap(), 0, pText );
663 /***********************************************************************
664 * CBDropDown
666 * Show listbox popup.
668 static void CBDropDown( LPHEADCOMBO lphc )
670 INT32 index;
671 RECT32 rect;
672 LPRECT32 pRect = NULL;
674 TRACE(combo,"[%04x]: drop down\n", CB_HWND(lphc));
676 CB_NOTIFY( lphc, CBN_DROPDOWN );
678 /* set selection */
680 lphc->wState |= CBF_DROPPED;
681 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
683 index = CBUpdateLBox( lphc );
684 if( !(lphc->wState & CBF_CAPTURE) ) CBUpdateEdit( lphc, index );
686 else
688 index = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 );
689 if( index == LB_ERR ) index = 0;
690 SendMessage32A( lphc->hWndLBox, LB_SETTOPINDEX32, (WPARAM32)index, 0 );
691 SendMessage32A( lphc->hWndLBox, LB_CARETON32, 0, 0 );
692 pRect = &lphc->RectEdit;
695 /* now set popup position */
697 GetWindowRect32( lphc->self->hwndSelf, &rect );
699 rect.top += lphc->RectEdit.bottom - lphc->RectEdit.top - SYSMETRICS_CYBORDER;
700 rect.bottom = rect.top + lphc->RectCombo.bottom -
701 lphc->RectCombo.top - SYSMETRICS_CYBORDER;
702 rect.right = rect.left + lphc->RectCombo.right - lphc->RectCombo.left;
703 rect.left += ( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) ? 0 : CBitOffset;
705 SetWindowPos32( lphc->hWndLBox, HWND_TOP, rect.left, rect.top,
706 rect.right - rect.left, rect.bottom - rect.top,
707 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOREDRAW);
709 if( !(lphc->wState & CBF_NOREDRAW) )
710 if( pRect )
711 RedrawWindow32( lphc->self->hwndSelf, pRect, 0, RDW_INVALIDATE |
712 RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
713 ShowWindow32( lphc->hWndLBox, SW_SHOWNA );
716 /***********************************************************************
717 * CBRollUp
719 * Hide listbox popup.
721 static void CBRollUp( LPHEADCOMBO lphc, BOOL32 ok, BOOL32 bButton )
723 HWND32 hWnd = lphc->self->hwndSelf;
725 CB_NOTIFY( lphc, (ok) ? CBN_SELENDOK : CBN_SELENDCANCEL );
727 if( IsWindow32( hWnd ) && CB_GETTYPE(lphc) != CBS_SIMPLE )
730 TRACE(combo,"[%04x]: roll up [%i]\n", CB_HWND(lphc), (INT32)ok );
732 /* always send WM_LBUTTONUP? */
733 SendMessage32A( lphc->hWndLBox, WM_LBUTTONUP, 0, (LPARAM)(-1) );
735 if( lphc->wState & CBF_DROPPED )
737 RECT32 rect;
739 lphc->wState &= ~CBF_DROPPED;
740 ShowWindow32( lphc->hWndLBox, SW_HIDE );
742 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
744 INT32 index = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 );
745 CBUpdateEdit( lphc, index );
746 rect = lphc->RectButton;
748 else
750 if( bButton )
751 UnionRect32( &rect, &lphc->RectButton,
752 &lphc->RectEdit );
753 else
754 rect = lphc->RectEdit;
755 bButton = TRUE;
758 if( bButton && !(lphc->wState & CBF_NOREDRAW) )
759 RedrawWindow32( hWnd, &rect, 0, RDW_INVALIDATE |
760 RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
761 CB_NOTIFY( lphc, CBN_CLOSEUP );
766 /***********************************************************************
767 * COMBO_FlipListbox
769 * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
771 BOOL32 COMBO_FlipListbox( LPHEADCOMBO lphc, BOOL32 bRedrawButton )
773 if( lphc->wState & CBF_DROPPED )
775 CBRollUp( lphc, TRUE, bRedrawButton );
776 return FALSE;
779 CBDropDown( lphc );
780 return TRUE;
783 /***********************************************************************
784 * COMBO_GetLBWindow
786 * Edit control helper.
788 HWND32 COMBO_GetLBWindow( WND* pWnd )
790 LPHEADCOMBO lphc = CB_GETPTR(pWnd);
791 if( lphc ) return lphc->hWndLBox;
792 return 0;
796 /***********************************************************************
797 * CBRepaintButton
799 static void CBRepaintButton( LPHEADCOMBO lphc )
801 HDC32 hDC = GetDC32( lphc->self->hwndSelf );
803 if( hDC )
805 CBPaintButton( lphc, hDC );
806 ReleaseDC32( lphc->self->hwndSelf, hDC );
810 /***********************************************************************
811 * COMBO_SetFocus
813 static void COMBO_SetFocus( LPHEADCOMBO lphc )
815 if( !(lphc->wState & CBF_FOCUSED) )
817 if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
818 SendMessage32A( lphc->hWndLBox, LB_CARETON32, 0, 0 );
820 if( lphc->wState & CBF_EDIT )
821 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1) );
822 lphc->wState |= CBF_FOCUSED;
823 if( !(lphc->wState & CBF_EDIT) ) CBPaintText( lphc, 0 );
825 CB_NOTIFY( lphc, CBN_SETFOCUS );
829 /***********************************************************************
830 * COMBO_KillFocus
832 static void COMBO_KillFocus( LPHEADCOMBO lphc )
834 HWND32 hWnd = lphc->self->hwndSelf;
836 if( lphc->wState & CBF_FOCUSED )
838 SendMessage32A( hWnd, WM_LBUTTONUP, 0, (LPARAM)(-1) );
840 CBRollUp( lphc, FALSE, TRUE );
841 if( IsWindow32( hWnd ) )
843 if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
844 SendMessage32A( lphc->hWndLBox, LB_CARETOFF32, 0, 0 );
846 lphc->wState &= ~CBF_FOCUSED;
848 /* redraw text */
849 if( lphc->wState & CBF_EDIT )
850 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, (WPARAM32)(-1), 0 );
851 else CBPaintText( lphc, 0 );
853 CB_NOTIFY( lphc, CBN_KILLFOCUS );
858 /***********************************************************************
859 * COMBO_Command
861 static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM32 wParam, HWND32 hWnd )
863 if( lphc->wState & CBF_EDIT && lphc->hWndEdit == hWnd )
865 /* ">> 8" makes gcc generate jump-table instead of cmp ladder */
867 switch( HIWORD(wParam) >> 8 )
869 case (EN_SETFOCUS >> 8):
871 TRACE(combo,"[%04x]: edit [%04x] got focus\n",
872 CB_HWND(lphc), lphc->hWndEdit );
874 if( !(lphc->wState & CBF_FOCUSED) ) COMBO_SetFocus( lphc );
875 break;
877 case (EN_KILLFOCUS >> 8):
879 TRACE(combo,"[%04x]: edit [%04x] lost focus\n",
880 CB_HWND(lphc), lphc->hWndEdit );
882 /* NOTE: it seems that Windows' edit control sends an
883 * undocumented message WM_USER + 0x1B instead of this
884 * notification (only when it happens to be a part of
885 * the combo). ?? - AK.
888 COMBO_KillFocus( lphc );
889 break;
892 case (EN_CHANGE >> 8):
893 CB_NOTIFY( lphc, CBN_EDITCHANGE );
894 CBUpdateLBox( lphc );
895 break;
897 case (EN_UPDATE >> 8):
898 CB_NOTIFY( lphc, CBN_EDITUPDATE );
899 break;
901 case (EN_ERRSPACE >> 8):
902 CB_NOTIFY( lphc, CBN_ERRSPACE );
905 else if( lphc->hWndLBox == hWnd )
907 switch( HIWORD(wParam) )
909 case LBN_ERRSPACE:
910 CB_NOTIFY( lphc, CBN_ERRSPACE );
911 break;
913 case LBN_DBLCLK:
914 CB_NOTIFY( lphc, CBN_DBLCLK );
915 break;
917 case LBN_SELCHANGE:
918 case LBN_SELCANCEL:
920 TRACE(combo,"[%04x]: lbox selection change [%04x]\n",
921 CB_HWND(lphc), lphc->wState );
923 /* do not roll up if selection is being tracked
924 * by arrowkeys in the dropdown listbox */
926 if( (lphc->wState & CBF_DROPPED) && !(lphc->wState & CBF_NOROLLUP) )
927 CBRollUp( lphc, (HIWORD(wParam) == LBN_SELCHANGE), TRUE );
928 else lphc->wState &= ~CBF_NOROLLUP;
930 CB_NOTIFY( lphc, CBN_SELCHANGE );
931 CBPaintText( lphc, 0 );
932 /* fall through */
934 case LBN_SETFOCUS:
935 case LBN_KILLFOCUS:
936 /* nothing to do here since ComboLBox always resets the focus to its
937 * combo/edit counterpart */
938 break;
941 return 0;
944 /***********************************************************************
945 * COMBO_ItemOp
947 * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
949 static LRESULT COMBO_ItemOp32( LPHEADCOMBO lphc, UINT32 msg,
950 WPARAM32 wParam, LPARAM lParam )
952 HWND32 hWnd = lphc->self->hwndSelf;
954 TRACE(combo,"[%04x]: ownerdraw op %04x\n", CB_HWND(lphc), msg );
956 #define lpIS ((LPDELETEITEMSTRUCT32)lParam)
958 /* two first items are the same in all 4 structs */
959 lpIS->CtlType = ODT_COMBOBOX;
960 lpIS->CtlID = lphc->self->wIDmenu;
962 switch( msg ) /* patch window handle */
964 case WM_DELETEITEM:
965 lpIS->hwndItem = hWnd;
966 #undef lpIS
967 break;
968 case WM_DRAWITEM:
969 #define lpIS ((LPDRAWITEMSTRUCT32)lParam)
970 lpIS->hwndItem = hWnd;
971 #undef lpIS
972 break;
973 case WM_COMPAREITEM:
974 #define lpIS ((LPCOMPAREITEMSTRUCT32)lParam)
975 lpIS->hwndItem = hWnd;
976 #undef lpIS
977 break;
980 return SendMessage32A( lphc->owner, msg, lphc->self->wIDmenu, lParam );
983 /***********************************************************************
984 * COMBO_GetText
986 static LRESULT COMBO_GetText( LPHEADCOMBO lphc, UINT32 N, LPSTR lpText)
988 if( lphc->wState & CBF_EDIT )
989 return SendMessage32A( lphc->hWndEdit, WM_GETTEXT,
990 (WPARAM32)N, (LPARAM)lpText );
992 /* get it from the listbox */
994 if( lphc->hWndLBox )
996 INT32 idx = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 );
997 if( idx != LB_ERR )
999 LPSTR lpBuffer;
1000 INT32 length = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32,
1001 (WPARAM32)idx, 0 );
1003 /* 'length' is without the terminating character */
1004 if( length >= N )
1005 lpBuffer = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1 );
1006 else
1007 lpBuffer = lpText;
1009 if( lpBuffer )
1011 INT32 n = SendMessage32A( lphc->hWndLBox, LB_GETTEXT32,
1012 (WPARAM32)idx, (LPARAM)lpBuffer );
1014 /* truncate if buffer is too short */
1016 if( length >= N )
1018 if (N && lpText) {
1019 if( n != LB_ERR ) memcpy( lpText, lpBuffer, (N>n) ? n+1 : N-1 );
1020 lpText[N - 1] = '\0';
1022 HeapFree( GetProcessHeap(), 0, lpBuffer );
1024 return (LRESULT)n;
1028 return 0;
1032 /***********************************************************************
1033 * CBResetPos
1035 * This function sets window positions according to the updated
1036 * component placement struct.
1038 static void CBResetPos( LPHEADCOMBO lphc, LPRECT32 lbRect, BOOL32 bRedraw )
1040 BOOL32 bDrop = (CB_GETTYPE(lphc) != CBS_SIMPLE);
1042 /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
1043 * sizing messages */
1045 if( lphc->wState & CBF_EDIT )
1046 SetWindowPos32( lphc->hWndEdit, 0, lphc->RectEdit.left, lphc->RectEdit.top,
1047 lphc->RectEdit.right - lphc->RectEdit.left,
1048 lphc->RectEdit.bottom - lphc->RectEdit.top,
1049 SWP_NOZORDER | SWP_NOACTIVATE | ((bDrop) ? SWP_NOREDRAW : 0) );
1051 if( bDrop )
1052 OffsetRect32( lbRect, lphc->RectCombo.left, lphc->RectCombo.top );
1054 lbRect->right -= lbRect->left; /* convert to width */
1055 lbRect->bottom -= lbRect->top;
1056 SetWindowPos32( lphc->hWndLBox, 0, lbRect->left, lbRect->top,
1057 lbRect->right, lbRect->bottom,
1058 SWP_NOACTIVATE | SWP_NOZORDER | ((bDrop) ? SWP_NOREDRAW : 0) );
1060 if( bDrop )
1062 if( lphc->wState & CBF_DROPPED )
1064 lphc->wState &= ~CBF_DROPPED;
1065 ShowWindow32( lphc->hWndLBox, SW_HIDE );
1068 lphc->wState |= CBF_NORESIZE;
1069 SetWindowPos32( lphc->self->hwndSelf, 0, 0, 0,
1070 lphc->RectCombo.right - lphc->RectCombo.left,
1071 lphc->RectEdit.bottom - lphc->RectEdit.top,
1072 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW );
1073 lphc->wState &= ~CBF_NORESIZE;
1075 if( bRedraw && !(lphc->wState & CBF_NOREDRAW) )
1076 RedrawWindow32( lphc->self->hwndSelf, NULL, 0,
1077 RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
1082 /***********************************************************************
1083 * COMBO_Size
1085 static void COMBO_Size( LPHEADCOMBO lphc )
1087 RECT32 rect;
1088 INT32 w, h;
1090 GetWindowRect32( lphc->self->hwndSelf, &rect );
1091 w = rect.right - rect.left; h = rect.bottom - rect.top;
1093 TRACE(combo,"w = %i, h = %i\n", w, h );
1095 /* CreateWindow() may send a bogus WM_SIZE, ignore it */
1097 if( w == (lphc->RectCombo.right - lphc->RectCombo.left) )
1099 if( (CB_GETTYPE(lphc) == CBS_SIMPLE) &&
1100 (h == (lphc->RectCombo.bottom - lphc->RectCombo.top)) )
1101 return;
1102 else if( (lphc->dwStyle & CBS_DROPDOWN) &&
1103 (h == (lphc->RectEdit.bottom - lphc->RectEdit.top)) )
1104 return;
1106 lphc->RectCombo = rect;
1107 CBCalcPlacement( lphc, &lphc->RectEdit, &lphc->RectButton, &rect );
1108 CBResetPos( lphc, &rect, TRUE );
1112 /***********************************************************************
1113 * COMBO_Font
1115 static void COMBO_Font( LPHEADCOMBO lphc, HFONT32 hFont, BOOL32 bRedraw )
1117 RECT32 rect;
1119 lphc->hFont = hFont;
1121 if( lphc->wState & CBF_EDIT )
1122 SendMessage32A( lphc->hWndEdit, WM_SETFONT, (WPARAM32)hFont, bRedraw );
1123 SendMessage32A( lphc->hWndLBox, WM_SETFONT, (WPARAM32)hFont, bRedraw );
1125 GetWindowRect32( lphc->self->hwndSelf, &rect );
1126 OffsetRect32( &lphc->RectCombo, rect.left - lphc->RectCombo.left,
1127 rect.top - lphc->RectCombo.top );
1128 CBCalcPlacement( lphc, &lphc->RectEdit,
1129 &lphc->RectButton, &rect );
1130 CBResetPos( lphc, &rect, bRedraw );
1134 /***********************************************************************
1135 * COMBO_SetItemHeight
1137 static LRESULT COMBO_SetItemHeight( LPHEADCOMBO lphc, INT32 index, INT32 height )
1139 LRESULT lRet = CB_ERR;
1141 if( index == -1 ) /* set text field height */
1143 if( height < 32768 )
1145 RECT32 rect;
1147 lphc->editHeight = height;
1148 GetWindowRect32( lphc->self->hwndSelf, &rect );
1149 OffsetRect32( &lphc->RectCombo, rect.left - lphc->RectCombo.left,
1150 rect.top - lphc->RectCombo.top );
1151 CBCalcPlacement( lphc, &lphc->RectEdit,
1152 &lphc->RectButton, &rect );
1153 CBResetPos( lphc, &rect, TRUE );
1154 lRet = height;
1157 else if ( CB_OWNERDRAWN(lphc) ) /* set listbox item height */
1158 lRet = SendMessage32A( lphc->hWndLBox, LB_SETITEMHEIGHT32,
1159 (WPARAM32)index, (LPARAM)height );
1160 return lRet;
1163 /***********************************************************************
1164 * COMBO_SelectString
1166 static LRESULT COMBO_SelectString( LPHEADCOMBO lphc, INT32 start, LPCSTR pText )
1168 INT32 index = SendMessage32A( lphc->hWndLBox, LB_SELECTSTRING32,
1169 (WPARAM32)start, (LPARAM)pText );
1170 if( index >= 0 )
1172 if( lphc->wState & CBF_EDIT )
1173 CBUpdateEdit( lphc, index );
1174 else
1175 CBPaintText( lphc, 0 );
1177 return (LRESULT)index;
1180 /***********************************************************************
1181 * COMBO_LButtonDown
1183 static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam )
1185 POINT32 pt = { LOWORD(lParam), HIWORD(lParam) };
1186 BOOL32 bButton = PtInRect32(&lphc->RectButton, pt);
1187 HWND32 hWnd = lphc->self->hwndSelf;
1189 if( (CB_GETTYPE(lphc) == CBS_DROPDOWNLIST) ||
1190 (bButton && (CB_GETTYPE(lphc) == CBS_DROPDOWN)) )
1192 lphc->wState |= CBF_BUTTONDOWN;
1193 if( lphc->wState & CBF_DROPPED )
1195 /* got a click to cancel selection */
1197 CBRollUp( lphc, TRUE, FALSE );
1198 if( !IsWindow32( hWnd ) ) return;
1200 if( lphc->wState & CBF_CAPTURE )
1202 lphc->wState &= ~CBF_CAPTURE;
1203 ReleaseCapture();
1205 lphc->wState &= ~CBF_BUTTONDOWN;
1207 else
1209 /* drop down the listbox and start tracking */
1211 lphc->wState |= CBF_CAPTURE;
1212 CBDropDown( lphc );
1213 SetCapture32( hWnd );
1215 if( bButton ) CBRepaintButton( lphc );
1219 /***********************************************************************
1220 * COMBO_LButtonUp
1222 * Release capture and stop tracking if needed.
1224 static void COMBO_LButtonUp( LPHEADCOMBO lphc, LPARAM lParam )
1226 if( lphc->wState & CBF_CAPTURE )
1228 lphc->wState &= ~CBF_CAPTURE;
1229 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
1231 INT32 index = CBUpdateLBox( lphc );
1232 CBUpdateEdit( lphc, index );
1234 ReleaseCapture();
1237 if( lphc->wState & CBF_BUTTONDOWN )
1239 lphc->wState &= ~CBF_BUTTONDOWN;
1240 CBRepaintButton( lphc );
1244 /***********************************************************************
1245 * COMBO_MouseMove
1247 * Two things to do - track combo button and release capture when
1248 * pointer goes into the listbox.
1250 static void COMBO_MouseMove( LPHEADCOMBO lphc, WPARAM32 wParam, LPARAM lParam )
1252 POINT32 pt = { LOWORD(lParam), HIWORD(lParam) };
1253 RECT32 lbRect;
1255 if( lphc->wState & CBF_BUTTONDOWN )
1257 BOOL32 bButton = PtInRect32(&lphc->RectButton, pt);
1259 if( !bButton )
1261 lphc->wState &= ~CBF_BUTTONDOWN;
1262 CBRepaintButton( lphc );
1266 GetClientRect32( lphc->hWndLBox, &lbRect );
1267 MapWindowPoints32( lphc->self->hwndSelf, lphc->hWndLBox, &pt, 1 );
1268 if( PtInRect32(&lbRect, pt) )
1270 lphc->wState &= ~CBF_CAPTURE;
1271 ReleaseCapture();
1272 if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) CBUpdateLBox( lphc );
1274 /* hand over pointer tracking */
1275 SendMessage32A( lphc->hWndLBox, WM_LBUTTONDOWN, wParam, lParam );
1280 /***********************************************************************
1281 * ComboWndProc
1283 * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/ctrl/src/combobox_15.htm
1285 LRESULT WINAPI ComboWndProc( HWND32 hwnd, UINT32 message,
1286 WPARAM32 wParam, LPARAM lParam )
1288 WND* pWnd = WIN_FindWndPtr(hwnd);
1290 if( pWnd )
1292 LPHEADCOMBO lphc = CB_GETPTR(pWnd);
1294 TRACE(combo, "[%04x]: msg %s wp %08x lp %08lx\n",
1295 pWnd->hwndSelf, SPY_GetMsgName(message), wParam, lParam );
1297 if( lphc || message == WM_NCCREATE )
1298 switch(message)
1301 /* System messages */
1303 case WM_NCCREATE:
1304 return COMBO_NCCreate(pWnd, lParam);
1306 case WM_NCDESTROY:
1307 COMBO_NCDestroy(lphc);
1308 break;
1310 case WM_CREATE:
1311 return COMBO_Create(lphc, pWnd, lParam);
1313 case WM_PAINT:
1314 /* wParam may contain a valid HDC! */
1315 return COMBO_Paint(lphc, wParam);
1317 case WM_ERASEBKGND:
1318 return TRUE;
1320 case WM_GETDLGCODE:
1321 return (LRESULT)(DLGC_WANTARROWS | DLGC_WANTCHARS);
1323 case WM_SIZE:
1324 if( lphc->hWndLBox &&
1325 !(lphc->wState & CBF_NORESIZE) ) COMBO_Size( lphc );
1326 return TRUE;
1328 case WM_SETFONT:
1329 COMBO_Font( lphc, (HFONT16)wParam, (BOOL32)lParam );
1330 return TRUE;
1332 case WM_GETFONT:
1333 return (LRESULT)lphc->hFont;
1335 case WM_SETFOCUS:
1336 if( lphc->wState & CBF_EDIT )
1337 SetFocus32( lphc->hWndEdit );
1338 else
1339 COMBO_SetFocus( lphc );
1340 return TRUE;
1342 case WM_KILLFOCUS:
1343 #define hwndFocus ((HWND16)wParam)
1344 if( !hwndFocus ||
1345 (hwndFocus != lphc->hWndEdit && hwndFocus != lphc->hWndLBox ))
1346 COMBO_KillFocus( lphc );
1347 #undef hwndFocus
1348 return TRUE;
1350 case WM_COMMAND:
1351 return COMBO_Command( lphc, wParam, (HWND32)lParam );
1353 case WM_GETTEXT:
1354 return COMBO_GetText( lphc, (UINT32)wParam, (LPSTR)lParam );
1356 case WM_SETTEXT:
1357 case WM_GETTEXTLENGTH:
1358 case WM_CLEAR:
1359 case WM_CUT:
1360 case WM_PASTE:
1361 case WM_COPY:
1362 if( lphc->wState & CBF_EDIT )
1363 return SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1364 return CB_ERR;
1366 case WM_DRAWITEM:
1367 case WM_DELETEITEM:
1368 case WM_COMPAREITEM:
1369 case WM_MEASUREITEM:
1370 return COMBO_ItemOp32( lphc, message, wParam, lParam );
1372 case WM_ENABLE:
1373 if( lphc->wState & CBF_EDIT )
1374 EnableWindow32( lphc->hWndEdit, (BOOL32)wParam );
1375 EnableWindow32( lphc->hWndLBox, (BOOL32)wParam );
1376 return TRUE;
1378 case WM_SETREDRAW:
1379 if( wParam )
1380 lphc->wState &= ~CBF_NOREDRAW;
1381 else
1382 lphc->wState |= CBF_NOREDRAW;
1384 if( lphc->wState & CBF_EDIT )
1385 SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1386 SendMessage32A( lphc->hWndLBox, message, wParam, lParam );
1387 return 0;
1389 case WM_SYSKEYDOWN:
1390 if( KEYDATA_ALT & HIWORD(lParam) )
1391 if( wParam == VK_UP || wParam == VK_DOWN )
1392 COMBO_FlipListbox( lphc, TRUE );
1393 break;
1395 case WM_CHAR:
1396 case WM_KEYDOWN:
1397 if( lphc->wState & CBF_EDIT )
1398 return SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1399 else
1400 return SendMessage32A( lphc->hWndLBox, message, wParam, lParam );
1402 case WM_LBUTTONDOWN:
1403 if( !(lphc->wState & CBF_FOCUSED) ) SetFocus32( lphc->self->hwndSelf );
1404 if( lphc->wState & CBF_FOCUSED ) COMBO_LButtonDown( lphc, lParam );
1405 return TRUE;
1407 case WM_LBUTTONUP:
1408 COMBO_LButtonUp( lphc, lParam );
1409 return TRUE;
1411 case WM_MOUSEMOVE:
1412 if( lphc->wState & CBF_CAPTURE )
1413 COMBO_MouseMove( lphc, wParam, lParam );
1414 return TRUE;
1416 /* Combo messages */
1418 case CB_ADDSTRING16:
1419 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1420 case CB_ADDSTRING32:
1421 return SendMessage32A( lphc->hWndLBox, LB_ADDSTRING32, 0, lParam);
1423 case CB_INSERTSTRING16:
1424 wParam = (INT32)(INT16)wParam;
1425 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1426 case CB_INSERTSTRING32:
1427 return SendMessage32A( lphc->hWndLBox, LB_INSERTSTRING32, wParam, lParam);
1429 case CB_DELETESTRING16:
1430 case CB_DELETESTRING32:
1431 return SendMessage32A( lphc->hWndLBox, LB_DELETESTRING32, wParam, 0);
1433 case CB_SELECTSTRING16:
1434 wParam = (INT32)(INT16)wParam;
1435 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1436 case CB_SELECTSTRING32:
1437 return COMBO_SelectString( lphc, (INT32)wParam, (LPSTR)lParam );
1439 case CB_FINDSTRING16:
1440 wParam = (INT32)(INT16)wParam;
1441 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1442 case CB_FINDSTRING32:
1443 return SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32, wParam, lParam);
1445 case CB_FINDSTRINGEXACT16:
1446 wParam = (INT32)(INT16)wParam;
1447 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1448 case CB_FINDSTRINGEXACT32:
1449 return SendMessage32A( lphc->hWndLBox, LB_FINDSTRINGEXACT32,
1450 wParam, lParam );
1451 case CB_SETITEMHEIGHT16:
1452 wParam = (INT32)(INT16)wParam; /* signed integer */
1453 case CB_SETITEMHEIGHT32:
1454 return COMBO_SetItemHeight( lphc, (INT32)wParam, (INT32)lParam);
1456 case CB_GETITEMHEIGHT16:
1457 wParam = (INT32)(INT16)wParam;
1458 case CB_GETITEMHEIGHT32:
1459 if( (INT32)wParam >= 0 ) /* listbox item */
1460 return SendMessage32A( lphc->hWndLBox, LB_GETITEMHEIGHT32, wParam, 0);
1461 return (lphc->RectEdit.bottom - lphc->RectEdit.top);
1463 case CB_RESETCONTENT16:
1464 case CB_RESETCONTENT32:
1465 SendMessage32A( lphc->hWndLBox, LB_RESETCONTENT32, 0, 0 );
1466 CBPaintText( lphc, 0 );
1467 return TRUE;
1469 case CB_INITSTORAGE32:
1470 return SendMessage32A( lphc->hWndLBox, LB_INITSTORAGE32, wParam, lParam);
1472 case CB_GETHORIZONTALEXTENT32:
1473 return SendMessage32A( lphc->hWndLBox, LB_GETHORIZONTALEXTENT32, 0, 0);
1475 case CB_SETHORIZONTALEXTENT32:
1476 return SendMessage32A( lphc->hWndLBox, LB_SETHORIZONTALEXTENT32, wParam, 0);
1478 case CB_GETTOPINDEX32:
1479 return SendMessage32A( lphc->hWndLBox, LB_GETTOPINDEX32, 0, 0);
1481 case CB_GETLOCALE32:
1482 return SendMessage32A( lphc->hWndLBox, LB_GETLOCALE32, 0, 0);
1484 case CB_SETLOCALE32:
1485 return SendMessage32A( lphc->hWndLBox, LB_SETLOCALE32, wParam, 0);
1487 case CB_GETDROPPEDWIDTH32:
1488 if( lphc->droppedWidth )
1489 return lphc->droppedWidth;
1490 return lphc->RectCombo.right - lphc->RectCombo.left -
1491 (lphc->wState & CBF_EDIT) ? CBitOffset : 0;
1493 case CB_SETDROPPEDWIDTH32:
1494 if( (CB_GETTYPE(lphc) != CBS_SIMPLE) &&
1495 (INT32)wParam < 32768 ) lphc->droppedWidth = (INT32)wParam;
1496 return CB_ERR;
1498 case CB_GETDROPPEDCONTROLRECT16:
1499 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1500 if( lParam )
1502 RECT32 r;
1503 CBGetDroppedControlRect32( lphc, &r );
1504 CONV_RECT32TO16( &r, (LPRECT16)lParam );
1506 return CB_OKAY;
1508 case CB_GETDROPPEDCONTROLRECT32:
1509 if( lParam ) CBGetDroppedControlRect32(lphc, (LPRECT32)lParam );
1510 return CB_OKAY;
1512 case CB_GETDROPPEDSTATE16:
1513 case CB_GETDROPPEDSTATE32:
1514 return (lphc->wState & CBF_DROPPED) ? TRUE : FALSE;
1516 case CB_DIR16:
1517 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1518 /* fall through */
1519 case CB_DIR32:
1520 return COMBO_Directory( lphc, (UINT32)wParam,
1521 (LPSTR)lParam, (message == CB_DIR32));
1522 case CB_SHOWDROPDOWN16:
1523 case CB_SHOWDROPDOWN32:
1524 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
1526 if( wParam )
1528 if( !(lphc->wState & CBF_DROPPED) )
1529 CBDropDown( lphc );
1531 else
1532 if( lphc->wState & CBF_DROPPED )
1533 CBRollUp( lphc, FALSE, TRUE );
1535 return TRUE;
1537 case CB_GETCOUNT16:
1538 case CB_GETCOUNT32:
1539 return SendMessage32A( lphc->hWndLBox, LB_GETCOUNT32, 0, 0);
1541 case CB_GETCURSEL16:
1542 case CB_GETCURSEL32:
1543 return SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0);
1545 case CB_SETCURSEL16:
1546 wParam = (INT32)(INT16)wParam;
1547 case CB_SETCURSEL32:
1548 return SendMessage32A( lphc->hWndLBox, LB_SETCURSEL32, wParam, 0);
1550 case CB_GETLBTEXT16:
1551 wParam = (INT32)(INT16)wParam;
1552 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1553 case CB_GETLBTEXT32:
1554 return SendMessage32A( lphc->hWndLBox, LB_GETTEXT32, wParam, lParam);
1556 case CB_GETLBTEXTLEN16:
1557 wParam = (INT32)(INT16)wParam;
1558 case CB_GETLBTEXTLEN32:
1559 return SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, wParam, 0);
1561 case CB_GETITEMDATA16:
1562 wParam = (INT32)(INT16)wParam;
1563 case CB_GETITEMDATA32:
1564 return SendMessage32A( lphc->hWndLBox, LB_GETITEMDATA32, wParam, 0);
1566 case CB_SETITEMDATA16:
1567 wParam = (INT32)(INT16)wParam;
1568 case CB_SETITEMDATA32:
1569 return SendMessage32A( lphc->hWndLBox, LB_SETITEMDATA32, wParam, lParam);
1571 case CB_GETEDITSEL16:
1572 wParam = lParam = 0; /* just in case */
1573 case CB_GETEDITSEL32:
1574 if( lphc->wState & CBF_EDIT )
1576 INT32 a, b;
1578 return SendMessage32A( lphc->hWndEdit, EM_GETSEL32,
1579 (wParam) ? wParam : (WPARAM32)&a,
1580 (lParam) ? lParam : (LPARAM)&b );
1582 return CB_ERR;
1584 case CB_SETEDITSEL16:
1585 case CB_SETEDITSEL32:
1586 if( lphc->wState & CBF_EDIT )
1587 return SendMessage32A( lphc->hWndEdit, EM_SETSEL32,
1588 (INT32)(INT16)LOWORD(lParam), (INT32)(INT16)HIWORD(lParam) );
1589 return CB_ERR;
1591 case CB_SETEXTENDEDUI16:
1592 case CB_SETEXTENDEDUI32:
1593 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) return CB_ERR;
1595 if( wParam )
1596 lphc->wState |= CBF_EUI;
1597 else lphc->wState &= ~CBF_EUI;
1598 return CB_OKAY;
1600 case CB_GETEXTENDEDUI16:
1601 case CB_GETEXTENDEDUI32:
1602 return (lphc->wState & CBF_EUI) ? TRUE : FALSE;
1604 case (WM_USER + 0x1B):
1605 WARN(combo, "[%04x]: undocumented msg!\n", hwnd );
1607 return DefWindowProc32A(hwnd, message, wParam, lParam);
1609 return CB_ERR;