Release 980201
[wine/multimedia.git] / controls / combo.c
blobaf61d6321ed2ece8fb6d2d050554e7002674319d
1 /*
2 * Combo controls
3 *
4 * Copyright 1997 Alex Korobka
5 *
6 * FIXME: roll up in Netscape 3.01.
7 */
9 #include <stdio.h>
10 #include <string.h>
12 #include "windows.h"
13 #include "sysmetrics.h"
14 #include "win.h"
15 #include "spy.h"
16 #include "user.h"
17 #include "graphics.h"
18 #include "heap.h"
19 #include "combo.h"
20 #include "drive.h"
21 #include "stddebug.h"
22 #include "debug.h"
24 /* bits in the dwKeyData */
25 #define KEYDATA_ALT 0x2000
26 #define KEYDATA_PREVSTATE 0x4000
29 * Additional combo box definitions
32 #define CB_GETPTR( wnd ) (*(LPHEADCOMBO*)((wnd)->wExtra))
33 #define CB_NOTIFY( lphc, code ) \
34 (SendMessage32A( (lphc)->owner, WM_COMMAND, \
35 MAKEWPARAM((lphc)->self->wIDmenu, (code)), (lphc)->self->hwndSelf))
36 #define CB_GETEDITTEXTLENGTH( lphc ) \
37 (SendMessage32A( (lphc)->hWndEdit, WM_GETTEXTLENGTH, 0, 0 ))
39 static HBITMAP16 hComboBmp = 0;
40 static UINT16 CBitHeight, CBitWidth;
41 static UINT16 CBitOffset = 8;
43 /***********************************************************************
44 * COMBO_Init
46 * Load combo button bitmap.
48 static BOOL32 COMBO_Init()
50 HDC16 hDC;
52 if( hComboBmp ) return TRUE;
53 if( (hDC = CreateCompatibleDC16(0)) )
55 BOOL32 bRet = FALSE;
56 if( (hComboBmp = LoadBitmap16(0, MAKEINTRESOURCE(OBM_COMBO))) )
58 BITMAP16 bm;
59 HBITMAP16 hPrevB;
60 RECT16 r;
62 GetObject16( hComboBmp, sizeof(bm), &bm );
63 CBitHeight = bm.bmHeight;
64 CBitWidth = bm.bmWidth;
66 dprintf_combo(stddeb, "combo bitmap [%i,%i]\n", CBitWidth, CBitHeight );
68 hPrevB = SelectObject16( hDC, hComboBmp);
69 SetRect16( &r, 0, 0, CBitWidth, CBitHeight );
70 InvertRect16( hDC, &r );
71 SelectObject16( hDC, hPrevB );
72 bRet = TRUE;
74 DeleteDC16( hDC );
75 return bRet;
77 return FALSE;
80 /***********************************************************************
81 * COMBO_NCCreate
83 static LRESULT COMBO_NCCreate(WND* wnd, LPARAM lParam)
85 LPHEADCOMBO lphc;
87 if ( wnd && COMBO_Init() &&
88 (lphc = HeapAlloc(GetProcessHeap(), 0, sizeof(HEADCOMBO))) )
90 LPCREATESTRUCT32A lpcs = (CREATESTRUCT32A*)lParam;
92 memset( lphc, 0, sizeof(HEADCOMBO) );
93 *(LPHEADCOMBO*)wnd->wExtra = lphc;
95 /* some braindead apps do try to use scrollbar/border flags */
97 lphc->dwStyle = (lpcs->style & ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL));
98 wnd->dwStyle &= ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL);
100 if( !(lpcs->style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) )
101 lphc->dwStyle |= CBS_HASSTRINGS;
102 if( !(wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) )
103 lphc->wState |= CBF_NOTIFY;
105 dprintf_combo(stddeb, "COMBO_NCCreate: [0x%08x], style = %08x\n",
106 (UINT32)lphc, lphc->dwStyle );
108 return (LRESULT)(UINT32)wnd->hwndSelf;
110 return (LRESULT)FALSE;
113 /***********************************************************************
114 * COMBO_NCDestroy
116 static LRESULT COMBO_NCDestroy( LPHEADCOMBO lphc )
119 if( lphc )
121 WND* wnd = lphc->self;
123 dprintf_combo(stddeb,"Combo [%04x]: freeing storage\n", CB_HWND(lphc));
125 if( (CB_GETTYPE(lphc) != CBS_SIMPLE) && lphc->hWndLBox )
126 DestroyWindow32( lphc->hWndLBox );
128 HeapFree( GetProcessHeap(), 0, lphc );
129 wnd->wExtra[0] = 0;
131 return 0;
134 /***********************************************************************
135 * CBCalcPlacement
137 * Set up component coordinates given valid lphc->RectCombo.
139 static void CBCalcPlacement( LPHEADCOMBO lphc,
140 LPRECT16 lprEdit, LPRECT16 lprButton, LPRECT16 lprLB )
142 RECT16 rect = lphc->RectCombo;
143 SIZE16 size;
145 /* get combo height and width */
147 if( lphc->editHeight )
148 size.cy = (INT16)lphc->editHeight;
149 else
151 HDC16 hDC = GetDC16( lphc->self->hwndSelf );
152 HFONT16 hPrevFont = (HFONT16)0;
154 if( lphc->hFont ) hPrevFont = SelectObject16( hDC, lphc->hFont );
156 GetTextExtentPoint16( hDC, "0", 1, &size);
158 size.cy += size.cy / 4 + 4 * SYSMETRICS_CYBORDER;
160 if( hPrevFont ) SelectObject16( hDC, hPrevFont );
161 ReleaseDC16( lphc->self->hwndSelf, hDC );
163 size.cx = rect.right - rect.left;
165 if( CB_OWNERDRAWN(lphc) )
167 UINT16 u = lphc->RectEdit.bottom - lphc->RectEdit.top;
169 if( lphc->wState & CBF_MEASUREITEM ) /* first initialization */
171 MEASUREITEMSTRUCT32 mi32;
173 lphc->wState &= ~CBF_MEASUREITEM;
174 mi32.CtlType = ODT_COMBOBOX;
175 mi32.CtlID = lphc->self->wIDmenu;
176 mi32.itemID = -1;
177 mi32.itemWidth = size.cx;
178 mi32.itemHeight = size.cy - 6; /* ownerdrawn cb is taller */
179 mi32.itemData = 0;
180 SendMessage32A(lphc->owner, WM_MEASUREITEM,
181 (WPARAM32)mi32.CtlID, (LPARAM)&mi32);
182 u = 6 + (UINT16)mi32.itemHeight;
184 size.cy = u;
187 /* calculate text and button placement */
189 lprEdit->left = lprEdit->top = lprButton->top = 0;
190 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) /* no button */
191 lprButton->left = lprButton->right = lprButton->bottom = 0;
192 else
194 INT32 i = size.cx - CBitWidth - 10; /* seems ok */
196 lprButton->right = size.cx;
197 lprButton->left = (INT16)i;
198 lprButton->bottom = lprButton->top + size.cy;
200 if( i < 0 ) size.cx = 0;
201 else size.cx = (INT16)i;
204 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
206 size.cx -= CBitOffset;
207 if( size.cx < 0 ) size.cx = 0;
210 lprEdit->right = size.cx; lprEdit->bottom = size.cy;
212 /* listbox placement */
214 lprLB->left = ( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) ? 0 : CBitOffset;
215 lprLB->top = lprEdit->bottom - SYSMETRICS_CYBORDER;
216 lprLB->right = rect.right - rect.left;
217 lprLB->bottom = rect.bottom - rect.top;
219 if( lphc->droppedWidth > (lprLB->right - lprLB->left) )
220 lprLB->right = lprLB->left + (INT16)lphc->droppedWidth;
222 dprintf_combo(stddeb,"Combo [%04x]: (%i,%i-%i,%i) placement\n\ttext\t= (%i,%i-%i,%i)\
223 \n\tbutton\t= (%i,%i-%i,%i)\n\tlbox\t= (%i,%i-%i,%i)\n", CB_HWND(lphc),
224 lphc->RectCombo.left, lphc->RectCombo.top, lphc->RectCombo.right, lphc->RectCombo.bottom,
225 lprEdit->left, lprEdit->top, lprEdit->right, lprEdit->bottom,
226 lprButton->left, lprButton->top, lprButton->right, lprButton->bottom,
227 lprLB->left, lprLB->top, lprLB->right, lprLB->bottom );
231 /***********************************************************************
232 * CBGetDroppedControlRect32
234 static void CBGetDroppedControlRect32( LPHEADCOMBO lphc, LPRECT32 lpRect)
236 lpRect->left = lphc->RectCombo.left +
237 (lphc->wState & CBF_EDIT) ? CBitOffset : 0;
238 lpRect->top = lphc->RectCombo.top + lphc->RectEdit.bottom -
239 SYSMETRICS_CYBORDER;
240 lpRect->right = lphc->RectCombo.right;
241 lpRect->bottom = lphc->RectCombo.bottom - SYSMETRICS_CYBORDER;
244 /***********************************************************************
245 * COMBO_Create
247 static LRESULT COMBO_Create( LPHEADCOMBO lphc, WND* wnd, LPARAM lParam)
249 static char clbName[] = "ComboLBox";
250 static char editName[] = "Edit";
252 LPCREATESTRUCT32A lpcs = (CREATESTRUCT32A*)lParam;
254 if( !CB_GETTYPE(lphc) ) lphc->dwStyle |= CBS_SIMPLE;
255 else if( CB_GETTYPE(lphc) != CBS_DROPDOWNLIST ) lphc->wState |= CBF_EDIT;
257 lphc->self = wnd;
258 lphc->owner = lpcs->hwndParent;
260 /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */
262 if( lphc->owner || !(lpcs->style & WS_VISIBLE) )
264 UINT32 lbeStyle;
265 RECT16 editRect, btnRect, lbRect;
267 GetWindowRect16( wnd->hwndSelf, &lphc->RectCombo );
269 lphc->wState |= CBF_MEASUREITEM;
270 CBCalcPlacement( lphc, &editRect, &btnRect, &lbRect );
271 lphc->RectButton = btnRect;
272 lphc->droppedWidth = lphc->editHeight = 0;
274 /* create listbox popup */
276 lbeStyle = (LBS_NOTIFY | WS_BORDER | WS_CLIPSIBLINGS) |
277 (lpcs->style & (WS_VSCROLL | CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE));
279 if( lphc->dwStyle & CBS_SORT )
280 lbeStyle |= LBS_SORT;
281 if( lphc->dwStyle & CBS_HASSTRINGS )
282 lbeStyle |= LBS_HASSTRINGS;
283 if( lphc->dwStyle & CBS_NOINTEGRALHEIGHT )
284 lbeStyle |= LBS_NOINTEGRALHEIGHT;
285 if( lphc->dwStyle & CBS_DISABLENOSCROLL )
286 lbeStyle |= LBS_DISABLENOSCROLL;
288 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) /* child listbox */
289 lbeStyle |= WS_CHILD | WS_VISIBLE;
290 else /* popup listbox */
292 lbeStyle |= WS_POPUP;
293 OffsetRect16( &lbRect, lphc->RectCombo.left, lphc->RectCombo.top );
296 /* Dropdown ComboLBox is not a child window and we cannot pass
297 * ID_CB_LISTBOX directly because it will be treated as a menu handle.
300 lphc->hWndLBox = CreateWindowEx32A( 0, clbName, NULL, lbeStyle,
301 lbRect.left + SYSMETRICS_CXBORDER,
302 lbRect.top + SYSMETRICS_CYBORDER,
303 lbRect.right - lbRect.left - 2 * SYSMETRICS_CXBORDER,
304 lbRect.bottom - lbRect.top - 2 * SYSMETRICS_CYBORDER,
305 lphc->self->hwndSelf,
306 (lphc->dwStyle & CBS_DROPDOWN)? (HMENU32)0 : (HMENU32)ID_CB_LISTBOX,
307 lphc->self->hInstance, (LPVOID)lphc );
308 if( lphc->hWndLBox )
310 BOOL32 bEdit = TRUE;
311 lbeStyle = WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NOHIDESEL | ES_LEFT;
312 if( lphc->wState & CBF_EDIT )
314 if( lphc->dwStyle & CBS_OEMCONVERT )
315 lbeStyle |= ES_OEMCONVERT;
316 if( lphc->dwStyle & CBS_AUTOHSCROLL )
317 lbeStyle |= ES_AUTOHSCROLL;
318 if( lphc->dwStyle & CBS_LOWERCASE )
319 lbeStyle |= ES_LOWERCASE;
320 else if( lphc->dwStyle & CBS_UPPERCASE )
321 lbeStyle |= ES_UPPERCASE;
322 lphc->hWndEdit = CreateWindowEx32A( 0, editName, NULL, lbeStyle,
323 editRect.left, editRect.top, editRect.right - editRect.left,
324 editRect.bottom - editRect.top, lphc->self->hwndSelf,
325 (HMENU32)ID_CB_EDIT, lphc->self->hInstance, NULL );
326 if( !lphc->hWndEdit ) bEdit = FALSE;
329 if( bEdit )
331 lphc->RectEdit = editRect;
332 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
334 lphc->wState |= CBF_NORESIZE;
335 SetWindowPos32( wnd->hwndSelf, 0, 0, 0,
336 lphc->RectCombo.right - lphc->RectCombo.left,
337 lphc->RectEdit.bottom - lphc->RectEdit.top,
338 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
339 lphc->wState &= ~CBF_NORESIZE;
341 dprintf_combo(stddeb,"COMBO_Create: init done\n");
342 return wnd->hwndSelf;
344 dprintf_combo(stderr, "COMBO_Create: edit control failure.\n");
345 } else dprintf_combo(stderr, "COMBO_Create: listbox failure.\n");
346 } else dprintf_combo(stderr, "COMBO_Create: no owner for visible combo.\n");
348 /* CreateWindow() will send WM_NCDESTROY to cleanup */
350 return -1;
353 /***********************************************************************
354 * CBPaintButton
356 * Paint combo button (normal, pressed, and disabled states).
358 static void CBPaintButton(LPHEADCOMBO lphc, HDC16 hdc)
360 RECT32 r;
361 HBRUSH32 hPrevBrush;
362 UINT32 x, y;
363 BOOL32 bBool;
365 if( lphc->wState & CBF_NOREDRAW ) return;
367 hPrevBrush = (HBRUSH32)SelectObject32(hdc, GetSysColorBrush32(COLOR_BTNFACE));
368 CONV_RECT16TO32( &lphc->RectButton, &r );
370 Rectangle32(hdc, r.left, r.top, r.right, r.bottom );
371 InflateRect32( &r, -1, -1 );
372 if( (bBool = lphc->wState & CBF_BUTTONDOWN) )
374 GRAPH_DrawReliefRect(hdc, &r, 1, 0, TRUE);
375 OffsetRect32( &r, 1, 1 );
376 } else GRAPH_DrawReliefRect(hdc, &r, 1, 2, FALSE);
378 x = (r.left + r.right - CBitWidth) >> 1;
379 y = (r.top + r.bottom - CBitHeight) >> 1;
381 InflateRect32( &r, -3, -3 );
382 if( (bBool = CB_DISABLED(lphc)) )
384 GRAPH_SelectClipMask(hdc, hComboBmp, x + 1, y + 1 );
385 FillRect32(hdc, &r, (HBRUSH32)GetStockObject32(WHITE_BRUSH));
388 GRAPH_SelectClipMask(hdc, hComboBmp, x, y );
389 FillRect32(hdc, &r, (HBRUSH32)GetStockObject32((bBool) ? GRAY_BRUSH : BLACK_BRUSH));
391 GRAPH_SelectClipMask(hdc, (HBITMAP32)0, 0, 0);
392 SelectObject32( hdc, hPrevBrush );
395 /***********************************************************************
396 * CBPaintText
398 * Paint CBS_DROPDOWNLIST text field / update edit control contents.
400 static void CBPaintText(LPHEADCOMBO lphc, HDC16 hdc)
402 INT32 id, size = 0;
403 LPSTR pText = NULL;
405 if( lphc->wState & CBF_NOREDRAW ) return;
407 /* follow Windows combobox that sends a bunch of text
408 * inquiries to its listbox while processing WM_PAINT. */
410 if( (id = SendMessage32A(lphc->hWndLBox, LB_GETCURSEL32, 0, 0) ) != LB_ERR )
412 size = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, id, 0);
413 if( (pText = HeapAlloc( GetProcessHeap(), 0, size + 1)) )
415 SendMessage32A( lphc->hWndLBox, LB_GETTEXT32, (WPARAM32)id, (LPARAM)pText );
416 pText[size] = '\0'; /* just in case */
417 } else return;
420 if( lphc->wState & CBF_EDIT )
422 if( CB_HASSTRINGS(lphc) ) SetWindowText32A( lphc->hWndEdit, pText );
423 if( lphc->wState & CBF_FOCUSED )
424 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1));
426 else /* paint text field ourselves */
428 HBRUSH32 hPrevBrush = 0;
429 HDC32 hDC = hdc;
431 if( !hDC )
433 if ((hDC = GetDC32(lphc->self->hwndSelf)))
435 HBRUSH32 hBrush = SendMessage32A( lphc->owner,
436 WM_CTLCOLORLISTBOX,
437 hDC, lphc->self->hwndSelf );
438 hPrevBrush = SelectObject32( hDC,
439 (hBrush) ? hBrush : GetStockObject32(WHITE_BRUSH) );
442 if( hDC )
444 RECT32 rect;
445 UINT16 itemState;
446 HFONT32 hPrevFont = (lphc->hFont) ? SelectObject32(hDC, lphc->hFont) : 0;
448 PatBlt32( hDC, (rect.left = lphc->RectEdit.left + SYSMETRICS_CXBORDER),
449 (rect.top = lphc->RectEdit.top + SYSMETRICS_CYBORDER),
450 (rect.right = lphc->RectEdit.right - SYSMETRICS_CXBORDER),
451 (rect.bottom = lphc->RectEdit.bottom - SYSMETRICS_CYBORDER) - 1, PATCOPY );
452 InflateRect32( &rect, -1, -1 );
454 if( lphc->wState & CBF_FOCUSED &&
455 !(lphc->wState & CBF_DROPPED) )
457 /* highlight */
459 FillRect32( hDC, &rect, GetSysColorBrush32(COLOR_HIGHLIGHT) );
460 SetBkColor32( hDC, GetSysColor32( COLOR_HIGHLIGHT ) );
461 SetTextColor32( hDC, GetSysColor32( COLOR_HIGHLIGHTTEXT ) );
462 itemState = ODS_SELECTED | ODS_FOCUS;
463 } else itemState = 0;
465 if( CB_OWNERDRAWN(lphc) )
467 DRAWITEMSTRUCT32 dis;
469 if( lphc->self->dwStyle & WS_DISABLED ) itemState |= ODS_DISABLED;
471 dis.CtlType = ODT_COMBOBOX;
472 dis.CtlID = lphc->self->wIDmenu;
473 dis.hwndItem = lphc->self->hwndSelf;
474 dis.itemAction = ODA_DRAWENTIRE;
475 dis.itemID = id;
476 dis.itemState = itemState;
477 dis.hDC = hDC;
478 dis.rcItem = rect;
479 dis.itemData = SendMessage32A( lphc->hWndLBox, LB_GETITEMDATA32,
480 (WPARAM32)id, 0 );
481 SendMessage32A( lphc->owner, WM_DRAWITEM,
482 lphc->self->wIDmenu, (LPARAM)&dis );
484 else
486 ExtTextOut32A( hDC, rect.left + 1, rect.top + 1,
487 ETO_OPAQUE | ETO_CLIPPED, &rect,
488 (pText) ? pText : "" , size, NULL );
489 if(lphc->wState & CBF_FOCUSED && !(lphc->wState & CBF_DROPPED))
490 DrawFocusRect32( hDC, &rect );
493 if( hPrevFont ) SelectObject32(hDC, hPrevFont );
494 if( !hdc )
496 if( hPrevBrush ) SelectObject32( hDC, hPrevBrush );
497 ReleaseDC32( lphc->self->hwndSelf, hDC );
501 HeapFree( GetProcessHeap(), 0, pText );
504 /***********************************************************************
505 * COMBO_Paint
507 static LRESULT COMBO_Paint(LPHEADCOMBO lphc, HDC16 hParamDC)
509 PAINTSTRUCT16 ps;
510 HDC16 hDC;
512 hDC = (hParamDC) ? hParamDC
513 : BeginPaint16( lphc->self->hwndSelf, &ps);
514 if( hDC && !(lphc->wState & CBF_NOREDRAW) )
516 HBRUSH32 hPrevBrush, hBkgBrush;
518 hBkgBrush = SendMessage32A( lphc->owner, WM_CTLCOLORLISTBOX,
519 hDC, lphc->self->hwndSelf );
520 if( !hBkgBrush ) hBkgBrush = GetStockObject32(WHITE_BRUSH);
522 hPrevBrush = SelectObject32( hDC, hBkgBrush );
523 if( !IsRectEmpty16(&lphc->RectButton) )
525 /* paint everything to the right of the text field */
527 PatBlt32( hDC, lphc->RectEdit.right, lphc->RectEdit.top,
528 lphc->RectButton.right - lphc->RectEdit.right,
529 lphc->RectEdit.bottom - lphc->RectEdit.top, PATCOPY );
530 CBPaintButton( lphc, hDC );
533 if( !(lphc->wState & CBF_EDIT) )
535 /* paint text field */
537 GRAPH_DrawRectangle( hDC, lphc->RectEdit.left, lphc->RectEdit.top,
538 lphc->RectEdit.right - lphc->RectEdit.left,
539 lphc->RectButton.bottom - lphc->RectButton.top,
540 GetSysColorPen32(COLOR_WINDOWFRAME) );
541 CBPaintText( lphc, hDC );
543 if( hPrevBrush ) SelectObject32( hDC, hPrevBrush );
545 if( !hParamDC ) EndPaint16(lphc->self->hwndSelf, &ps);
546 return 0;
549 /***********************************************************************
550 * CBUpdateLBox
552 * Select listbox entry according to the contents of the edit control.
554 static INT32 CBUpdateLBox( LPHEADCOMBO lphc )
556 INT32 length, idx, ret;
557 LPSTR pText = NULL;
559 idx = ret = LB_ERR;
560 length = CB_GETEDITTEXTLENGTH( lphc );
562 if( length > 0 )
563 pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1);
565 dprintf_combo(stddeb,"\tCBUpdateLBox: edit text length %i\n", length );
567 if( pText )
569 if( length ) GetWindowText32A( lphc->hWndEdit, pText, length + 1);
570 else pText[0] = '\0';
571 idx = SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32,
572 (WPARAM32)(-1), (LPARAM)pText );
573 if( idx == LB_ERR ) idx = 0; /* select first item */
574 else ret = idx;
575 HeapFree( GetProcessHeap(), 0, pText );
578 /* select entry */
580 SendMessage32A( lphc->hWndLBox, LB_SETCURSEL32, (WPARAM32)idx, 0 );
582 if( idx >= 0 )
584 SendMessage32A( lphc->hWndLBox, LB_SETTOPINDEX32, (WPARAM32)idx, 0 );
585 /* probably superfluous but Windows sends this too */
586 SendMessage32A( lphc->hWndLBox, LB_SETCARETINDEX32, (WPARAM32)idx, 0 );
588 return ret;
591 /***********************************************************************
592 * CBUpdateEdit
594 * Copy a listbox entry to the edit control.
596 static void CBUpdateEdit( LPHEADCOMBO lphc , INT32 index )
598 INT32 length;
599 LPSTR pText = NULL;
601 dprintf_combo(stddeb,"\tCBUpdateEdit: %i\n", index );
603 if( index == -1 )
605 length = CB_GETEDITTEXTLENGTH( lphc );
606 if( length )
608 if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) )
610 GetWindowText32A( lphc->hWndEdit, pText, length + 1 );
611 index = SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32,
612 (WPARAM32)(-1), (LPARAM)pText );
613 HeapFree( GetProcessHeap(), 0, pText );
618 if( index >= 0 ) /* got an entry */
620 length = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, (WPARAM32)index, 0);
621 if( length )
623 if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) )
625 SendMessage32A( lphc->hWndLBox, LB_GETTEXT32,
626 (WPARAM32)index, (LPARAM)pText );
627 SendMessage32A( lphc->hWndEdit, WM_SETTEXT, 0, (LPARAM)pText );
628 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1) );
629 HeapFree( GetProcessHeap(), 0, pText );
635 /***********************************************************************
636 * CBDropDown
638 * Show listbox popup.
640 static void CBDropDown( LPHEADCOMBO lphc )
642 INT32 index;
643 RECT16 rect;
644 LPRECT16 pRect = NULL;
646 dprintf_combo(stddeb,"Combo [%04x]: drop down\n", CB_HWND(lphc));
648 CB_NOTIFY( lphc, CBN_DROPDOWN );
650 /* set selection */
652 lphc->wState |= CBF_DROPPED;
653 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
655 index = CBUpdateLBox( lphc );
656 if( !(lphc->wState & CBF_CAPTURE) ) CBUpdateEdit( lphc, index );
658 else
660 index = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 );
661 if( index == LB_ERR ) index = 0;
662 SendMessage32A( lphc->hWndLBox, LB_SETTOPINDEX32, (WPARAM32)index, 0 );
663 SendMessage32A( lphc->hWndLBox, LB_CARETON32, 0, 0 );
664 pRect = &lphc->RectEdit;
667 /* now set popup position */
669 GetWindowRect16( lphc->self->hwndSelf, &rect );
671 rect.top += lphc->RectEdit.bottom - lphc->RectEdit.top - SYSMETRICS_CYBORDER;
672 rect.bottom = rect.top + lphc->RectCombo.bottom -
673 lphc->RectCombo.top - SYSMETRICS_CYBORDER;
674 rect.right = rect.left + lphc->RectCombo.right - lphc->RectCombo.left;
675 rect.left += ( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) ? 0 : CBitOffset;
677 SetWindowPos32( lphc->hWndLBox, HWND_TOP, rect.left, rect.top,
678 rect.right - rect.left, rect.bottom - rect.top,
679 SWP_NOACTIVATE | SWP_NOSIZE | SWP_NOREDRAW);
681 if( !(lphc->wState & CBF_NOREDRAW) )
682 if( pRect )
683 RedrawWindow16( lphc->self->hwndSelf, pRect, 0, RDW_INVALIDATE |
684 RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
685 ShowWindow32( lphc->hWndLBox, SW_SHOWNA );
688 /***********************************************************************
689 * CBRollUp
691 * Hide listbox popup.
693 static void CBRollUp( LPHEADCOMBO lphc, BOOL32 ok, BOOL32 bButton )
695 HWND32 hWnd = lphc->self->hwndSelf;
697 CB_NOTIFY( lphc, (ok) ? CBN_SELENDOK : CBN_SELENDCANCEL );
699 if( IsWindow32( hWnd ) && CB_GETTYPE(lphc) != CBS_SIMPLE )
702 dprintf_combo(stddeb,"Combo [%04x]: roll up [%i]\n", CB_HWND(lphc), (INT32)ok );
704 /* always send WM_LBUTTONUP? */
705 SendMessage32A( lphc->hWndLBox, WM_LBUTTONUP, 0, (LPARAM)(-1) );
707 if( lphc->wState & CBF_DROPPED )
709 RECT16 rect;
711 lphc->wState &= ~CBF_DROPPED;
712 ShowWindow32( lphc->hWndLBox, SW_HIDE );
714 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
716 INT32 index = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 );
717 CBUpdateEdit( lphc, index );
718 rect = lphc->RectButton;
720 else
722 if( bButton )
723 UnionRect16( &rect, &lphc->RectButton,
724 &lphc->RectEdit );
725 else
726 rect = lphc->RectEdit;
727 bButton = TRUE;
730 if( bButton && !(lphc->wState & CBF_NOREDRAW) )
731 RedrawWindow16( hWnd, &rect, 0, RDW_INVALIDATE |
732 RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
733 CB_NOTIFY( lphc, CBN_CLOSEUP );
738 /***********************************************************************
739 * COMBO_FlipListbox
741 * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
743 BOOL32 COMBO_FlipListbox( LPHEADCOMBO lphc, BOOL32 bRedrawButton )
745 if( lphc->wState & CBF_DROPPED )
747 CBRollUp( lphc, TRUE, bRedrawButton );
748 return FALSE;
751 CBDropDown( lphc );
752 return TRUE;
755 /***********************************************************************
756 * COMBO_GetLBWindow
758 * Edit control helper.
760 HWND32 COMBO_GetLBWindow( WND* pWnd )
762 LPHEADCOMBO lphc = CB_GETPTR(pWnd);
763 if( lphc ) return lphc->hWndLBox;
764 return 0;
768 /***********************************************************************
769 * CBRepaintButton
771 static void CBRepaintButton( LPHEADCOMBO lphc )
773 HDC32 hDC = GetDC32( lphc->self->hwndSelf );
775 if( hDC )
777 CBPaintButton( lphc, (HDC16)hDC );
778 ReleaseDC32( lphc->self->hwndSelf, hDC );
782 /***********************************************************************
783 * COMBO_SetFocus
785 static void COMBO_SetFocus( LPHEADCOMBO lphc )
787 if( !(lphc->wState & CBF_FOCUSED) )
789 if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
790 SendMessage32A( lphc->hWndLBox, LB_CARETON32, 0, 0 );
792 if( lphc->wState & CBF_EDIT )
793 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1) );
794 lphc->wState |= CBF_FOCUSED;
795 if( !(lphc->wState & CBF_EDIT) ) CBPaintText( lphc, 0 );
797 CB_NOTIFY( lphc, CBN_SETFOCUS );
801 /***********************************************************************
802 * COMBO_KillFocus
804 static void COMBO_KillFocus( LPHEADCOMBO lphc )
806 HWND32 hWnd = lphc->self->hwndSelf;
808 if( lphc->wState & CBF_FOCUSED )
810 SendMessage32A( hWnd, WM_LBUTTONUP, 0, (LPARAM)(-1) );
812 CBRollUp( lphc, FALSE, TRUE );
813 if( IsWindow32( hWnd ) )
815 if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
816 SendMessage32A( lphc->hWndLBox, LB_CARETOFF32, 0, 0 );
818 lphc->wState &= ~CBF_FOCUSED;
820 /* redraw text */
821 if( lphc->wState & CBF_EDIT )
822 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, (WPARAM32)(-1), 0 );
823 else CBPaintText( lphc, 0 );
825 CB_NOTIFY( lphc, CBN_KILLFOCUS );
830 /***********************************************************************
831 * COMBO_Command
833 static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM32 wParam, HWND32 hWnd )
835 if( lphc->wState & CBF_EDIT && lphc->hWndEdit == hWnd )
837 /* ">> 8" makes gcc generate jump-table instead of cmp ladder */
839 switch( HIWORD(wParam) >> 8 )
841 case (EN_SETFOCUS >> 8):
843 dprintf_combo(stddeb,"Combo [%04x]: edit [%04x] got focus\n",
844 CB_HWND(lphc), (HWND16)lphc->hWndEdit );
846 if( !(lphc->wState & CBF_FOCUSED) ) COMBO_SetFocus( lphc );
847 break;
849 case (EN_KILLFOCUS >> 8):
851 dprintf_combo(stddeb,"Combo [%04x]: edit [%04x] lost focus\n",
852 CB_HWND(lphc), (HWND16)lphc->hWndEdit );
854 /* NOTE: it seems that Windows' edit control sends an
855 * undocumented message WM_USER + 0x1B instead of this
856 * notification (only when it happens to be a part of
857 * the combo). ?? - AK.
860 COMBO_KillFocus( lphc );
861 break;
864 case (EN_CHANGE >> 8):
865 CB_NOTIFY( lphc, CBN_EDITCHANGE );
866 CBUpdateLBox( lphc );
867 break;
869 case (EN_UPDATE >> 8):
870 CB_NOTIFY( lphc, CBN_EDITUPDATE );
871 break;
873 case (EN_ERRSPACE >> 8):
874 CB_NOTIFY( lphc, CBN_ERRSPACE );
877 else if( lphc->hWndLBox == hWnd )
879 switch( HIWORD(wParam) )
881 case LBN_ERRSPACE:
882 CB_NOTIFY( lphc, CBN_ERRSPACE );
883 break;
885 case LBN_DBLCLK:
886 CB_NOTIFY( lphc, CBN_DBLCLK );
887 break;
889 case LBN_SELCHANGE:
890 case LBN_SELCANCEL:
892 dprintf_combo(stddeb,"Combo [%04x]: lbox selection change [%04x]\n",
893 CB_HWND(lphc), lphc->wState );
895 /* do not roll up if selection is being tracked
896 * by arrowkeys in the dropdown listbox */
898 if( (lphc->wState & CBF_DROPPED) && !(lphc->wState & CBF_NOROLLUP) )
899 CBRollUp( lphc, (HIWORD(wParam) == LBN_SELCHANGE), TRUE );
900 else lphc->wState &= ~CBF_NOROLLUP;
902 CB_NOTIFY( lphc, CBN_SELCHANGE );
903 CBPaintText( lphc, 0 );
904 /* fall through */
906 case LBN_SETFOCUS:
907 case LBN_KILLFOCUS:
908 /* nothing to do here since ComboLBox always resets the focus to its
909 * combo/edit counterpart */
910 break;
913 return 0;
916 /***********************************************************************
917 * COMBO_ItemOp
919 * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
921 static LRESULT COMBO_ItemOp32( LPHEADCOMBO lphc, UINT32 msg,
922 WPARAM32 wParam, LPARAM lParam )
924 HWND32 hWnd = lphc->self->hwndSelf;
926 dprintf_combo(stddeb,"Combo [%04x]: ownerdraw op %04x\n",
927 CB_HWND(lphc), (UINT16)msg );
929 #define lpIS ((LPDELETEITEMSTRUCT32)lParam)
931 /* two first items are the same in all 4 structs */
932 lpIS->CtlType = ODT_COMBOBOX;
933 lpIS->CtlID = lphc->self->wIDmenu;
935 switch( msg ) /* patch window handle */
937 case WM_DELETEITEM:
938 lpIS->hwndItem = hWnd;
939 #undef lpIS
940 break;
941 case WM_DRAWITEM:
942 #define lpIS ((LPDRAWITEMSTRUCT32)lParam)
943 lpIS->hwndItem = hWnd;
944 #undef lpIS
945 break;
946 case WM_COMPAREITEM:
947 #define lpIS ((LPCOMPAREITEMSTRUCT32)lParam)
948 lpIS->hwndItem = hWnd;
949 #undef lpIS
950 break;
953 return SendMessage32A( lphc->owner, msg, lphc->self->wIDmenu, lParam );
956 /***********************************************************************
957 * COMBO_GetText
959 static LRESULT COMBO_GetText( LPHEADCOMBO lphc, UINT32 N, LPSTR lpText)
961 if( lphc->wState & CBF_EDIT )
962 return SendMessage32A( lphc->hWndEdit, WM_GETTEXT,
963 (WPARAM32)N, (LPARAM)lpText );
965 /* get it from the listbox */
967 if( lphc->hWndLBox )
969 INT32 idx = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 );
970 if( idx != LB_ERR )
972 LPSTR lpBuffer;
973 INT32 length = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32,
974 (WPARAM32)idx, 0 );
976 /* 'length' is without the terminating character */
977 if( length >= N )
978 lpBuffer = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1 );
979 else
980 lpBuffer = lpText;
982 if( lpBuffer )
984 INT32 n = SendMessage32A( lphc->hWndLBox, LB_GETTEXT32,
985 (WPARAM32)idx, (LPARAM)lpText );
987 /* truncate if buffer is too short */
989 if( length >= N )
991 if( n != LB_ERR ) memcpy( lpText, lpBuffer, (N>n) ? n+1 : N-1 );
992 lpText[N - 1] = '\0';
993 HeapFree( GetProcessHeap(), 0, lpBuffer );
995 return (LRESULT)n;
999 return 0;
1003 /***********************************************************************
1004 * CBResetPos
1006 * This function sets window positions according to the updated
1007 * component placement struct.
1009 static void CBResetPos( LPHEADCOMBO lphc, LPRECT16 lbRect, BOOL32 bRedraw )
1011 BOOL32 bDrop = (CB_GETTYPE(lphc) != CBS_SIMPLE);
1013 /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
1014 * sizing messages */
1016 if( lphc->wState & CBF_EDIT )
1017 SetWindowPos32( lphc->hWndEdit, 0, lphc->RectEdit.left, lphc->RectEdit.top,
1018 lphc->RectEdit.right - lphc->RectEdit.left,
1019 lphc->RectEdit.bottom - lphc->RectEdit.top,
1020 SWP_NOZORDER | SWP_NOACTIVATE | ((bDrop) ? SWP_NOREDRAW : 0) );
1022 if( bDrop )
1023 OffsetRect16( lbRect, lphc->RectCombo.left, lphc->RectCombo.top );
1025 lbRect->right -= lbRect->left; /* convert to width */
1026 lbRect->bottom -= lbRect->top;
1027 SetWindowPos32( lphc->hWndLBox, 0, lbRect->left, lbRect->top,
1028 lbRect->right, lbRect->bottom,
1029 SWP_NOACTIVATE | SWP_NOZORDER | ((bDrop) ? SWP_NOREDRAW : 0) );
1031 if( bDrop )
1033 if( lphc->wState & CBF_DROPPED )
1035 lphc->wState &= ~CBF_DROPPED;
1036 ShowWindow32( lphc->hWndLBox, SW_HIDE );
1039 lphc->wState |= CBF_NORESIZE;
1040 SetWindowPos32( lphc->self->hwndSelf, 0, 0, 0,
1041 lphc->RectCombo.right - lphc->RectCombo.left,
1042 lphc->RectEdit.bottom - lphc->RectEdit.top,
1043 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW );
1044 lphc->wState &= ~CBF_NORESIZE;
1046 if( bRedraw && !(lphc->wState & CBF_NOREDRAW) )
1047 RedrawWindow32( lphc->self->hwndSelf, NULL, 0,
1048 RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
1053 /***********************************************************************
1054 * COMBO_Size
1056 static void COMBO_Size( LPHEADCOMBO lphc )
1058 RECT16 rect;
1059 INT16 w, h;
1061 GetWindowRect16( lphc->self->hwndSelf, &rect );
1062 w = rect.right - rect.left; h = rect.bottom - rect.top;
1064 dprintf_combo(stddeb,"COMBO_Size: w = %i, h = %i\n", w, h );
1066 /* CreateWindow() may send a bogus WM_SIZE, ignore it */
1068 if( w == (lphc->RectCombo.right - lphc->RectCombo.left) )
1069 if( (CB_GETTYPE(lphc) == CBS_SIMPLE) &&
1070 (h == (lphc->RectCombo.bottom - lphc->RectCombo.top)) )
1071 return;
1072 else if( (lphc->dwStyle & CBS_DROPDOWN) &&
1073 (h == (lphc->RectEdit.bottom - lphc->RectEdit.top)) )
1074 return;
1076 lphc->RectCombo = rect;
1077 CBCalcPlacement( lphc, &lphc->RectEdit, &lphc->RectButton, &rect );
1078 CBResetPos( lphc, &rect, TRUE );
1082 /***********************************************************************
1083 * COMBO_Font
1085 static void COMBO_Font( LPHEADCOMBO lphc, HFONT16 hFont, BOOL32 bRedraw )
1087 RECT16 rect;
1089 lphc->hFont = hFont;
1091 if( lphc->wState & CBF_EDIT )
1092 SendMessage32A( lphc->hWndEdit, WM_SETFONT, (WPARAM32)hFont, bRedraw );
1093 SendMessage32A( lphc->hWndLBox, WM_SETFONT, (WPARAM32)hFont, bRedraw );
1095 GetWindowRect16( lphc->self->hwndSelf, &rect );
1096 OffsetRect16( &lphc->RectCombo, rect.left - lphc->RectCombo.left,
1097 rect.top - lphc->RectCombo.top );
1098 CBCalcPlacement( lphc, &lphc->RectEdit,
1099 &lphc->RectButton, &rect );
1100 CBResetPos( lphc, &rect, bRedraw );
1104 /***********************************************************************
1105 * COMBO_SetItemHeight
1107 static LRESULT COMBO_SetItemHeight( LPHEADCOMBO lphc, INT32 index, INT32 height )
1109 LRESULT lRet = CB_ERR;
1111 if( index == -1 ) /* set text field height */
1113 if( height < 32768 )
1115 RECT16 rect;
1117 lphc->editHeight = height;
1118 GetWindowRect16( lphc->self->hwndSelf, &rect );
1119 OffsetRect16( &lphc->RectCombo, rect.left - lphc->RectCombo.left,
1120 rect.top - lphc->RectCombo.top );
1121 CBCalcPlacement( lphc, &lphc->RectEdit,
1122 &lphc->RectButton, &rect );
1123 CBResetPos( lphc, &rect, TRUE );
1124 lRet = height;
1127 else if ( CB_OWNERDRAWN(lphc) ) /* set listbox item height */
1128 lRet = SendMessage32A( lphc->hWndLBox, LB_SETITEMHEIGHT32,
1129 (WPARAM32)index, (LPARAM)height );
1130 return lRet;
1133 /***********************************************************************
1134 * COMBO_SelectString
1136 static LRESULT COMBO_SelectString( LPHEADCOMBO lphc, INT32 start, LPCSTR pText )
1138 INT32 index = SendMessage32A( lphc->hWndLBox, LB_SELECTSTRING32,
1139 (WPARAM32)start, (LPARAM)pText );
1140 if( index >= 0 )
1141 if( lphc->wState & CBF_EDIT )
1142 CBUpdateEdit( lphc, index );
1143 else
1144 CBPaintText( lphc, 0 );
1145 return (LRESULT)index;
1148 /***********************************************************************
1149 * COMBO_LButtonDown
1151 static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam )
1153 BOOL32 bButton = PtInRect16(&lphc->RectButton, MAKEPOINT16(lParam));
1154 HWND32 hWnd = lphc->self->hwndSelf;
1156 if( (CB_GETTYPE(lphc) == CBS_DROPDOWNLIST) ||
1157 (bButton && (CB_GETTYPE(lphc) == CBS_DROPDOWN)) )
1159 lphc->wState |= CBF_BUTTONDOWN;
1160 if( lphc->wState & CBF_DROPPED )
1162 /* got a click to cancel selection */
1164 CBRollUp( lphc, TRUE, FALSE );
1165 if( !IsWindow32( hWnd ) ) return;
1167 if( lphc->wState & CBF_CAPTURE )
1169 lphc->wState &= ~CBF_CAPTURE;
1170 ReleaseCapture();
1172 lphc->wState &= ~CBF_BUTTONDOWN;
1174 else
1176 /* drop down the listbox and start tracking */
1178 lphc->wState |= CBF_CAPTURE;
1179 CBDropDown( lphc );
1180 SetCapture32( hWnd );
1182 if( bButton ) CBRepaintButton( lphc );
1186 /***********************************************************************
1187 * COMBO_LButtonUp
1189 * Release capture and stop tracking if needed.
1191 static void COMBO_LButtonUp( LPHEADCOMBO lphc, LPARAM lParam )
1193 if( lphc->wState & CBF_CAPTURE )
1195 lphc->wState &= ~CBF_CAPTURE;
1196 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
1198 INT32 index = CBUpdateLBox( lphc );
1199 CBUpdateEdit( lphc, index );
1201 ReleaseCapture();
1204 if( lphc->wState & CBF_BUTTONDOWN )
1206 lphc->wState &= ~CBF_BUTTONDOWN;
1207 CBRepaintButton( lphc );
1211 /***********************************************************************
1212 * COMBO_MouseMove
1214 * Two things to do - track combo button and release capture when
1215 * pointer goes into the listbox.
1217 static void COMBO_MouseMove( LPHEADCOMBO lphc, WPARAM32 wParam, LPARAM lParam )
1219 RECT16 lbRect;
1221 if( lphc->wState & CBF_BUTTONDOWN )
1223 BOOL32 bButton = PtInRect16(&lphc->RectButton, MAKEPOINT16(lParam));
1225 if( !bButton )
1227 lphc->wState &= ~CBF_BUTTONDOWN;
1228 CBRepaintButton( lphc );
1232 GetClientRect16( lphc->hWndLBox, &lbRect );
1233 MapWindowPoints16( lphc->self->hwndSelf,
1234 lphc->hWndLBox, (LPPOINT16)&lParam, 1 );
1235 if( PtInRect16(&lbRect, MAKEPOINT16(lParam)) )
1237 lphc->wState &= ~CBF_CAPTURE;
1238 ReleaseCapture();
1239 if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) CBUpdateLBox( lphc );
1241 /* hand over pointer tracking */
1242 SendMessage32A( lphc->hWndLBox, WM_LBUTTONDOWN, wParam, lParam );
1247 /***********************************************************************
1248 * ComboWndProc
1250 * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/ctrl/src/combobox_15.htm
1252 LRESULT WINAPI ComboWndProc( HWND32 hwnd, UINT32 message,
1253 WPARAM32 wParam, LPARAM lParam )
1255 WND* pWnd = WIN_FindWndPtr(hwnd);
1257 if( pWnd )
1259 LPHEADCOMBO lphc = CB_GETPTR(pWnd);
1261 dprintf_combo( stddeb, "Combo [%04x]: msg %s wp %08x lp %08lx\n",
1262 pWnd->hwndSelf, SPY_GetMsgName(message), wParam, lParam );
1264 if( lphc || message == WM_NCCREATE )
1265 switch(message)
1268 /* System messages */
1270 case WM_NCCREATE:
1271 return COMBO_NCCreate(pWnd, lParam);
1273 case WM_NCDESTROY:
1274 COMBO_NCDestroy(lphc);
1275 break;
1277 case WM_CREATE:
1278 return COMBO_Create(lphc, pWnd, lParam);
1280 case WM_PAINT:
1281 /* wParam may contain a valid HDC! */
1282 return COMBO_Paint(lphc, (HDC16)wParam);
1284 case WM_ERASEBKGND:
1285 return TRUE;
1287 case WM_GETDLGCODE:
1288 return (LRESULT)(DLGC_WANTARROWS | DLGC_WANTCHARS);
1290 case WM_SIZE:
1291 if( lphc->hWndLBox &&
1292 !(lphc->wState & CBF_NORESIZE) ) COMBO_Size( lphc );
1293 return TRUE;
1295 case WM_SETFONT:
1296 COMBO_Font( lphc, (HFONT16)wParam, (BOOL32)lParam );
1297 return TRUE;
1299 case WM_GETFONT:
1300 return (LRESULT)lphc->hFont;
1302 case WM_SETFOCUS:
1303 if( lphc->wState & CBF_EDIT )
1304 SetFocus32( lphc->hWndEdit );
1305 else
1306 COMBO_SetFocus( lphc );
1307 return TRUE;
1309 case WM_KILLFOCUS:
1310 #define hwndFocus ((HWND16)wParam)
1311 if( !hwndFocus ||
1312 (hwndFocus != lphc->hWndEdit && hwndFocus != lphc->hWndLBox ))
1313 COMBO_KillFocus( lphc );
1314 #undef hwndFocus
1315 return TRUE;
1317 case WM_COMMAND:
1318 return COMBO_Command( lphc, wParam, (HWND32)lParam );
1320 case WM_GETTEXT:
1321 return COMBO_GetText( lphc, (UINT32)wParam, (LPSTR)lParam );
1323 case WM_SETTEXT:
1324 case WM_GETTEXTLENGTH:
1325 case WM_CLEAR:
1326 case WM_CUT:
1327 case WM_PASTE:
1328 case WM_COPY:
1329 if( lphc->wState & CBF_EDIT )
1330 return SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1331 return CB_ERR;
1333 case WM_DRAWITEM:
1334 case WM_DELETEITEM:
1335 case WM_COMPAREITEM:
1336 case WM_MEASUREITEM:
1337 return COMBO_ItemOp32( lphc, message, wParam, lParam );
1339 case WM_ENABLE:
1340 if( lphc->wState & CBF_EDIT )
1341 EnableWindow32( lphc->hWndEdit, (BOOL32)wParam );
1342 EnableWindow32( lphc->hWndLBox, (BOOL32)wParam );
1343 return TRUE;
1345 case WM_SETREDRAW:
1346 if( wParam )
1347 lphc->wState &= ~CBF_NOREDRAW;
1348 else
1349 lphc->wState |= CBF_NOREDRAW;
1351 if( lphc->wState & CBF_EDIT )
1352 SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1353 SendMessage32A( lphc->hWndLBox, message, wParam, lParam );
1354 return 0;
1356 case WM_SYSKEYDOWN:
1357 if( KEYDATA_ALT & HIWORD(lParam) )
1358 if( wParam == VK_UP || wParam == VK_DOWN )
1359 COMBO_FlipListbox( lphc, TRUE );
1360 break;
1362 case WM_CHAR:
1363 case WM_KEYDOWN:
1364 if( lphc->wState & CBF_EDIT )
1365 return SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1366 else
1367 return SendMessage32A( lphc->hWndLBox, message, wParam, lParam );
1369 case WM_LBUTTONDOWN:
1370 if( !(lphc->wState & CBF_FOCUSED) ) SetFocus32( lphc->self->hwndSelf );
1371 if( lphc->wState & CBF_FOCUSED ) COMBO_LButtonDown( lphc, lParam );
1372 return TRUE;
1374 case WM_LBUTTONUP:
1375 COMBO_LButtonUp( lphc, lParam );
1376 return TRUE;
1378 case WM_MOUSEMOVE:
1379 if( lphc->wState & CBF_CAPTURE )
1380 COMBO_MouseMove( lphc, wParam, lParam );
1381 return TRUE;
1383 /* Combo messages */
1385 case CB_ADDSTRING16:
1386 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1387 case CB_ADDSTRING32:
1388 return SendMessage32A( lphc->hWndLBox, LB_ADDSTRING32, 0, lParam);
1390 case CB_INSERTSTRING16:
1391 wParam = (INT32)(INT16)wParam;
1392 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1393 case CB_INSERTSTRING32:
1394 return SendMessage32A( lphc->hWndLBox, LB_INSERTSTRING32, wParam, lParam);
1396 case CB_DELETESTRING16:
1397 case CB_DELETESTRING32:
1398 return SendMessage32A( lphc->hWndLBox, LB_DELETESTRING32, wParam, 0);
1400 case CB_SELECTSTRING16:
1401 wParam = (INT32)(INT16)wParam;
1402 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1403 case CB_SELECTSTRING32:
1404 return COMBO_SelectString( lphc, (INT32)wParam, (LPSTR)lParam );
1406 case CB_FINDSTRING16:
1407 wParam = (INT32)(INT16)wParam;
1408 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1409 case CB_FINDSTRING32:
1410 return SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32, wParam, lParam);
1412 case CB_FINDSTRINGEXACT16:
1413 wParam = (INT32)(INT16)wParam;
1414 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1415 case CB_FINDSTRINGEXACT32:
1416 return SendMessage32A( lphc->hWndLBox, LB_FINDSTRINGEXACT32,
1417 wParam, lParam );
1418 case CB_SETITEMHEIGHT16:
1419 wParam = (INT32)(INT16)wParam;
1420 case CB_SETITEMHEIGHT32:
1421 return COMBO_SetItemHeight( lphc, (INT32)wParam, (INT32)lParam);
1423 case CB_RESETCONTENT16:
1424 case CB_RESETCONTENT32:
1425 SendMessage32A( lphc->hWndLBox, LB_RESETCONTENT32, 0, 0 );
1426 CBPaintText( lphc, 0 );
1427 return TRUE;
1429 case CB_INITSTORAGE32:
1430 return SendMessage32A( lphc->hWndLBox, LB_INITSTORAGE32, wParam, lParam);
1432 case CB_GETHORIZONTALEXTENT32:
1433 return SendMessage32A( lphc->hWndLBox, LB_GETHORIZONTALEXTENT32, 0, 0);
1435 case CB_SETHORIZONTALEXTENT32:
1436 return SendMessage32A( lphc->hWndLBox, LB_SETHORIZONTALEXTENT32, wParam, 0);
1438 case CB_GETTOPINDEX32:
1439 return SendMessage32A( lphc->hWndLBox, LB_GETTOPINDEX32, 0, 0);
1441 case CB_GETLOCALE32:
1442 return SendMessage32A( lphc->hWndLBox, LB_GETLOCALE32, 0, 0);
1444 case CB_SETLOCALE32:
1445 return SendMessage32A( lphc->hWndLBox, LB_SETLOCALE32, wParam, 0);
1447 case CB_GETDROPPEDWIDTH32:
1448 if( lphc->droppedWidth )
1449 return lphc->droppedWidth;
1450 return lphc->RectCombo.right - lphc->RectCombo.left -
1451 (lphc->wState & CBF_EDIT) ? CBitOffset : 0;
1453 case CB_SETDROPPEDWIDTH32:
1454 if( (CB_GETTYPE(lphc) != CBS_SIMPLE) &&
1455 (INT32)wParam < 32768 ) lphc->droppedWidth = (INT32)wParam;
1456 return CB_ERR;
1458 case CB_GETDROPPEDCONTROLRECT16:
1459 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1460 if( lParam )
1462 RECT32 r;
1463 CBGetDroppedControlRect32( lphc, &r );
1464 CONV_RECT32TO16( &r, (LPRECT16)lParam );
1466 return CB_OKAY;
1468 case CB_GETDROPPEDCONTROLRECT32:
1469 if( lParam ) CBGetDroppedControlRect32(lphc, (LPRECT32)lParam );
1470 return CB_OKAY;
1472 case CB_GETDROPPEDSTATE16:
1473 case CB_GETDROPPEDSTATE32:
1474 return (lphc->wState & CBF_DROPPED) ? TRUE : FALSE;
1476 case CB_DIR16:
1477 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1478 /* fall through */
1479 case CB_DIR32:
1480 return COMBO_Directory( lphc, (UINT32)wParam,
1481 (LPSTR)lParam, (message == CB_DIR32));
1482 case CB_SHOWDROPDOWN16:
1483 case CB_SHOWDROPDOWN32:
1484 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
1485 if( wParam )
1487 if( !(lphc->wState & CBF_DROPPED) )
1488 CBDropDown( lphc );
1490 else
1491 if( lphc->wState & CBF_DROPPED )
1492 CBRollUp( lphc, FALSE, TRUE );
1493 return TRUE;
1495 case CB_GETCOUNT16:
1496 case CB_GETCOUNT32:
1497 return SendMessage32A( lphc->hWndLBox, LB_GETCOUNT32, 0, 0);
1499 case CB_GETCURSEL16:
1500 case CB_GETCURSEL32:
1501 return SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0);
1503 case CB_SETCURSEL16:
1504 wParam = (INT32)(INT16)wParam;
1505 case CB_SETCURSEL32:
1506 return SendMessage32A( lphc->hWndLBox, LB_SETCURSEL32, wParam, 0);
1508 case CB_GETLBTEXT16:
1509 wParam = (INT32)(INT16)wParam;
1510 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1511 case CB_GETLBTEXT32:
1512 return SendMessage32A( lphc->hWndLBox, LB_GETTEXT32, wParam, lParam);
1514 case CB_GETLBTEXTLEN16:
1515 wParam = (INT32)(INT16)wParam;
1516 case CB_GETLBTEXTLEN32:
1517 return SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, wParam, 0);
1519 case CB_GETITEMDATA16:
1520 wParam = (INT32)(INT16)wParam;
1521 case CB_GETITEMDATA32:
1522 return SendMessage32A( lphc->hWndLBox, LB_GETITEMDATA32, wParam, 0);
1524 case CB_SETITEMDATA16:
1525 wParam = (INT32)(INT16)wParam;
1526 case CB_SETITEMDATA32:
1527 return SendMessage32A( lphc->hWndLBox, LB_SETITEMDATA32, wParam, lParam);
1529 case CB_GETEDITSEL16:
1530 wParam = lParam = 0; /* just in case */
1531 case CB_GETEDITSEL32:
1532 if( lphc->wState & CBF_EDIT )
1534 INT32 a, b;
1536 return SendMessage32A( lphc->hWndEdit, EM_GETSEL32,
1537 (wParam) ? wParam : (WPARAM32)&a,
1538 (lParam) ? lParam : (LPARAM)&b );
1540 return CB_ERR;
1542 case CB_SETEDITSEL16:
1543 case CB_SETEDITSEL32:
1544 if( lphc->wState & CBF_EDIT )
1545 return SendMessage32A( lphc->hWndEdit, EM_SETSEL32,
1546 (INT32)(INT16)LOWORD(lParam), (INT32)(INT16)HIWORD(lParam) );
1547 return CB_ERR;
1549 case CB_SETEXTENDEDUI16:
1550 case CB_SETEXTENDEDUI32:
1551 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) return CB_ERR;
1553 if( wParam )
1554 lphc->wState |= CBF_EUI;
1555 else lphc->wState &= ~CBF_EUI;
1556 return CB_OKAY;
1558 case CB_GETEXTENDEDUI16:
1559 case CB_GETEXTENDEDUI32:
1560 return (lphc->wState & CBF_EUI) ? TRUE : FALSE;
1562 case (WM_USER + 0x1B):
1563 dprintf_combo(stddeb,"Combo [%04x]: undocumented msg!\n", (HWND16)hwnd );
1565 return DefWindowProc32A(hwnd, message, wParam, lParam);
1567 return CB_ERR;