Release 970509
[wine/multimedia.git] / controls / combo.c
blobcd1a6b5eb1f948821f4ceac0c66b851b36dd4440
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 "syscolor.h"
15 #include "win.h"
16 #include "spy.h"
17 #include "user.h"
18 #include "graphics.h"
19 #include "heap.h"
20 #include "combo.h"
21 #include "drive.h"
22 #include "stddebug.h"
23 #include "debug.h"
25 /* bits in the dwKeyData */
26 #define KEYDATA_ALT 0x2000
27 #define KEYDATA_PREVSTATE 0x4000
30 * Additional combo box definitions
33 #define CB_GETPTR( wnd ) (*(LPHEADCOMBO*)((wnd)->wExtra))
34 #define CB_NOTIFY( lphc, code ) \
35 (SendMessage32A( (lphc)->owner, WM_COMMAND, \
36 MAKEWPARAM((lphc)->self->wIDmenu, (code)), (lphc)->self->hwndSelf))
37 #define CB_GETEDITTEXTLENGTH( lphc ) \
38 (SendMessage32A( (lphc)->hWndEdit, WM_GETTEXTLENGTH, 0, 0 ))
40 static HBITMAP16 hComboBmp = 0;
41 static UINT16 CBitHeight, CBitWidth;
42 static UINT16 CBitOffset = 8;
44 /***********************************************************************
45 * COMBO_Init
47 * Load combo button bitmap.
49 static BOOL32 COMBO_Init()
51 HDC16 hDC;
53 if( hComboBmp ) return TRUE;
54 if( (hDC = CreateCompatibleDC16(0)) )
56 BOOL32 bRet = FALSE;
57 if( (hComboBmp = LoadBitmap16(0, MAKEINTRESOURCE(OBM_COMBO))) )
59 BITMAP16 bm;
60 HBITMAP16 hPrevB;
61 RECT16 r;
63 GetObject16( hComboBmp, sizeof(bm), &bm );
64 CBitHeight = bm.bmHeight;
65 CBitWidth = bm.bmWidth;
67 dprintf_combo(stddeb, "combo bitmap [%i,%i]\n", CBitWidth, CBitHeight );
69 hPrevB = SelectObject16( hDC, hComboBmp);
70 SetRect16( &r, 0, 0, CBitWidth, CBitHeight );
71 InvertRect16( hDC, &r );
72 SelectObject16( hDC, hPrevB );
73 bRet = TRUE;
75 DeleteDC16( hDC );
76 return bRet;
78 return FALSE;
81 /***********************************************************************
82 * COMBO_NCCreate
84 static LRESULT COMBO_NCCreate(WND* wnd, LPARAM lParam)
86 LPHEADCOMBO lphc;
88 if ( wnd && COMBO_Init() &&
89 (lphc = HeapAlloc(GetProcessHeap(), 0, sizeof(HEADCOMBO))) )
91 LPCREATESTRUCT32A lpcs = (CREATESTRUCT32A*)lParam;
93 memset( lphc, 0, sizeof(HEADCOMBO) );
94 *(LPHEADCOMBO*)wnd->wExtra = lphc;
96 /* some braindead apps do try to use scrollbar/border flags */
98 lphc->dwStyle = (lpcs->style & ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL));
99 wnd->dwStyle &= ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL);
101 if( !(lpcs->style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) )
102 lphc->dwStyle |= CBS_HASSTRINGS;
104 dprintf_combo(stddeb, "COMBO_NCCreate: [0x%08x], style = %08x\n",
105 (UINT32)lphc, lphc->dwStyle );
107 return (LRESULT)(UINT32)wnd->hwndSelf;
109 return (LRESULT)FALSE;
112 /***********************************************************************
113 * COMBO_NCDestroy
115 static LRESULT COMBO_NCDestroy( LPHEADCOMBO lphc )
118 if( lphc )
120 WND* wnd = lphc->self;
122 dprintf_combo(stddeb,"Combo [%04x]: freeing storage\n", CB_HWND(lphc));
124 if( (CB_GETTYPE(lphc) != CBS_SIMPLE) && lphc->hWndLBox )
125 DestroyWindow32( lphc->hWndLBox );
127 HeapFree( GetProcessHeap(), 0, lphc );
128 wnd->wExtra[0] = 0;
130 return 0;
133 /***********************************************************************
134 * CBCalcPlacement
136 * Set up component coordinates given valid lphc->RectCombo.
138 static void CBCalcPlacement( LPHEADCOMBO lphc,
139 LPRECT16 lprEdit, LPRECT16 lprButton, LPRECT16 lprLB )
141 RECT16 rect = lphc->RectCombo;
142 SIZE16 size;
144 /* get combo height and width */
146 if( lphc->editHeight )
147 size.cy = (INT16)lphc->editHeight;
148 else
150 HDC16 hDC = GetDC16( lphc->self->hwndSelf );
151 HFONT16 hPrevFont = (HFONT16)0;
153 if( lphc->hFont ) hPrevFont = SelectObject16( hDC, lphc->hFont );
155 GetTextExtentPoint16( hDC, "X", 1, &size);
156 size.cy += size.cy / 4 + 4 * SYSMETRICS_CYBORDER;
158 if( hPrevFont ) SelectObject16( hDC, hPrevFont );
159 ReleaseDC16( lphc->self->hwndSelf, hDC );
161 size.cx = rect.right - rect.left;
163 if( CB_OWNERDRAWN(lphc) )
165 UINT16 u = lphc->RectEdit.bottom - lphc->RectEdit.top;
167 if( lphc->wState & CBF_MEASUREITEM ) /* first initialization */
169 MEASUREITEMSTRUCT32 mi32;
171 lphc->wState &= ~CBF_MEASUREITEM;
172 mi32.CtlType = ODT_COMBOBOX;
173 mi32.CtlID = lphc->self->wIDmenu;
174 mi32.itemID = -1;
175 mi32.itemWidth = size.cx;
176 mi32.itemHeight = size.cy - 6; /* ownerdrawn cb is taller */
177 mi32.itemData = 0;
178 SendMessage32A(lphc->owner, WM_MEASUREITEM,
179 (WPARAM32)mi32.CtlID, (LPARAM)&mi32);
180 u = 6 + (UINT16)mi32.itemHeight;
182 size.cy = u;
185 /* calculate text and button placement */
187 lprEdit->left = lprEdit->top = lprButton->top = 0;
188 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) /* no button */
189 lprButton->left = lprButton->right = lprButton->bottom = 0;
190 else
192 INT32 i = size.cx - CBitWidth - 10; /* seems ok */
194 lprButton->right = size.cx;
195 lprButton->left = (INT16)i;
196 lprButton->bottom = lprButton->top + size.cy;
198 if( i < 0 ) size.cx = 0;
199 else size.cx = (INT16)i;
202 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
204 size.cx -= CBitOffset;
205 if( size.cx < 0 ) size.cx = 0;
208 lprEdit->right = size.cx; lprEdit->bottom = size.cy;
210 /* listbox placement */
212 lprLB->left = ( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) ? 0 : CBitOffset;
213 lprLB->top = lprEdit->bottom - SYSMETRICS_CYBORDER;
214 lprLB->right = rect.right - rect.left;
215 lprLB->bottom = rect.bottom - rect.top;
217 if( lphc->droppedWidth > (lprLB->right - lprLB->left) )
218 lprLB->right = lprLB->left + (INT16)lphc->droppedWidth;
220 dprintf_combo(stddeb,"Combo [%04x]: (%i,%i-%i,%i) placement\n\ttext\t= (%i,%i-%i,%i)\
221 \n\tbutton\t= (%i,%i-%i,%i)\n\tlbox\t= (%i,%i-%i,%i)\n", CB_HWND(lphc),
222 lphc->RectCombo.left, lphc->RectCombo.top, lphc->RectCombo.right, lphc->RectCombo.bottom,
223 lprEdit->left, lprEdit->top, lprEdit->right, lprEdit->bottom,
224 lprButton->left, lprButton->top, lprButton->right, lprButton->bottom,
225 lprLB->left, lprLB->top, lprLB->right, lprLB->bottom );
229 /***********************************************************************
230 * CBGetDroppedControlRect32
232 static void CBGetDroppedControlRect32( LPHEADCOMBO lphc, LPRECT32 lpRect)
234 lpRect->left = lphc->RectCombo.left +
235 (lphc->wState & CBF_EDIT) ? CBitOffset : 0;
236 lpRect->top = lphc->RectCombo.top + lphc->RectEdit.bottom -
237 SYSMETRICS_CYBORDER;
238 lpRect->right = lphc->RectCombo.right;
239 lpRect->bottom = lphc->RectCombo.bottom - SYSMETRICS_CYBORDER;
242 /***********************************************************************
243 * COMBO_Create
245 static LRESULT COMBO_Create( LPHEADCOMBO lphc, WND* wnd, LPARAM lParam)
247 static char clbName[] = "ComboLBox";
248 static char editName[] = "Edit";
250 LPCREATESTRUCT32A lpcs = (CREATESTRUCT32A*)lParam;
252 if( !CB_GETTYPE(lphc) ) lphc->dwStyle |= CBS_SIMPLE;
253 else if( CB_GETTYPE(lphc) != CBS_DROPDOWNLIST ) lphc->wState |= CBF_EDIT;
255 lphc->self = wnd;
256 lphc->owner = lpcs->hwndParent;
258 /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */
260 if( lphc->owner || !(lpcs->style & WS_VISIBLE) )
262 UINT32 lbeStyle;
263 RECT16 editRect, btnRect, lbRect;
265 GetWindowRect16( wnd->hwndSelf, &lphc->RectCombo );
267 lphc->wState |= CBF_MEASUREITEM;
268 CBCalcPlacement( lphc, &editRect, &btnRect, &lbRect );
269 lphc->RectButton = btnRect;
270 lphc->droppedWidth = lphc->editHeight = 0;
272 /* create listbox popup */
274 lbeStyle = (LBS_NOTIFY | WS_BORDER | WS_CLIPSIBLINGS) |
275 (lpcs->style & (WS_VSCROLL | CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE));
277 if( lphc->dwStyle & CBS_SORT )
278 lbeStyle |= LBS_SORT;
279 if( lphc->dwStyle & CBS_HASSTRINGS )
280 lbeStyle |= LBS_HASSTRINGS;
281 if( lphc->dwStyle & CBS_NOINTEGRALHEIGHT )
282 lbeStyle |= LBS_NOINTEGRALHEIGHT;
283 if( lphc->dwStyle & CBS_DISABLENOSCROLL )
284 lbeStyle |= LBS_DISABLENOSCROLL;
286 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) /* child listbox */
287 lbeStyle |= WS_CHILD | WS_VISIBLE;
288 else /* popup listbox */
290 lbeStyle |= WS_POPUP;
291 OffsetRect16( &lbRect, lphc->RectCombo.left, lphc->RectCombo.top );
294 /* Dropdown ComboLBox is not a child window and we cannot pass
295 * ID_CB_LISTBOX directly because it will be treated as a menu handle.
298 lphc->hWndLBox = CreateWindowEx32A( 0, clbName, NULL, lbeStyle,
299 lbRect.left + SYSMETRICS_CXBORDER,
300 lbRect.top + SYSMETRICS_CYBORDER,
301 lbRect.right - lbRect.left - 2 * SYSMETRICS_CXBORDER,
302 lbRect.bottom - lbRect.top - 2 * SYSMETRICS_CYBORDER,
303 lphc->self->hwndSelf,
304 (lphc->dwStyle & CBS_DROPDOWN)? (HMENU32)0 : (HMENU32)ID_CB_LISTBOX,
305 lphc->self->hInstance, (LPVOID)lphc );
306 if( lphc->hWndLBox )
308 BOOL32 bEdit = TRUE;
309 lbeStyle = WS_CHILD | WS_VISIBLE | WS_BORDER | ES_NOHIDESEL | ES_LEFT;
310 if( lphc->wState & CBF_EDIT )
312 if( lphc->dwStyle & CBS_OEMCONVERT )
313 lbeStyle |= ES_OEMCONVERT;
314 if( lphc->dwStyle & CBS_AUTOHSCROLL )
315 lbeStyle |= ES_AUTOHSCROLL;
316 if( lphc->dwStyle & CBS_LOWERCASE )
317 lbeStyle |= ES_LOWERCASE;
318 else if( lphc->dwStyle & CBS_UPPERCASE )
319 lbeStyle |= ES_UPPERCASE;
320 lphc->hWndEdit = CreateWindowEx32A( 0, editName, NULL, lbeStyle,
321 editRect.left, editRect.top, editRect.right - editRect.left,
322 editRect.bottom - editRect.top, lphc->self->hwndSelf,
323 (HMENU32)ID_CB_EDIT, lphc->self->hInstance, NULL );
324 if( !lphc->hWndEdit ) bEdit = FALSE;
327 if( bEdit )
329 lphc->RectEdit = editRect;
330 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
332 lphc->wState |= CBF_NORESIZE;
333 SetWindowPos32( wnd->hwndSelf, 0, 0, 0,
334 lphc->RectCombo.right - lphc->RectCombo.left,
335 lphc->RectEdit.bottom - lphc->RectEdit.top,
336 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
337 lphc->wState &= ~CBF_NORESIZE;
339 dprintf_combo(stddeb,"COMBO_Create: init done\n");
340 return wnd->hwndSelf;
342 dprintf_combo(stderr, "COMBO_Create: edit control failure.\n");
343 } else dprintf_combo(stderr, "COMBO_Create: listbox failure.\n");
344 } else dprintf_combo(stderr, "COMBO_Create: no owner for visible combo.\n");
346 /* CreateWindow() will send WM_NCDESTROY to cleanup */
348 return -1;
351 /***********************************************************************
352 * CBPaintButton
354 * Paint combo button (normal, pressed, and disabled states).
356 static void CBPaintButton(LPHEADCOMBO lphc, HDC16 hdc)
358 RECT32 r;
359 HBRUSH32 hPrevBrush;
360 UINT32 x, y;
361 BOOL32 bBool;
363 hPrevBrush = (HBRUSH32)SelectObject32(hdc, sysColorObjects.hbrushBtnFace);
364 CONV_RECT16TO32( &lphc->RectButton, &r );
366 Rectangle32(hdc, r.left, r.top, r.right, r.bottom );
367 InflateRect32( &r, -1, -1 );
368 if( (bBool = lphc->wState & CBF_BUTTONDOWN) )
370 GRAPH_DrawReliefRect(hdc, &r, 1, 0, TRUE);
371 OffsetRect32( &r, 1, 1 );
372 } else GRAPH_DrawReliefRect(hdc, &r, 1, 2, FALSE);
374 x = (r.left + r.right - CBitWidth) >> 1;
375 y = (r.top + r.bottom - CBitHeight) >> 1;
377 InflateRect32( &r, -3, -3 );
378 if( (bBool = CB_DISABLED(lphc)) )
380 GRAPH_SelectClipMask(hdc, hComboBmp, x + 1, y + 1 );
381 FillRect32(hdc, &r, (HBRUSH32)GetStockObject32(WHITE_BRUSH));
384 GRAPH_SelectClipMask(hdc, hComboBmp, x, y );
385 FillRect32(hdc, &r, (HBRUSH32)GetStockObject32((bBool) ? GRAY_BRUSH : BLACK_BRUSH));
387 GRAPH_SelectClipMask(hdc, (HBITMAP32)0, 0, 0);
388 SelectObject32( hdc, hPrevBrush );
391 /***********************************************************************
392 * CBPaintText
394 * Paint CBS_DROPDOWNLIST text field / update edit control contents.
396 static void CBPaintText(LPHEADCOMBO lphc, HDC16 hdc)
398 INT32 id, size = 0;
399 LPSTR pText = NULL;
401 /* follow Windows combobox that sends a bunch of text
402 * inquiries to its listbox while processing WM_PAINT. */
404 if( (id = SendMessage32A(lphc->hWndLBox, LB_GETCURSEL32, 0, 0) ) != LB_ERR )
406 size = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, id, 0);
407 if( (pText = HeapAlloc( GetProcessHeap(), 0, size + 1)) )
409 SendMessage32A( lphc->hWndLBox, LB_GETTEXT32, (WPARAM32)id, (LPARAM)pText );
410 pText[size] = '\0'; /* just in case */
411 } else return;
414 if( lphc->wState & CBF_EDIT )
416 if( CB_HASSTRINGS(lphc) ) SetWindowText32A( lphc->hWndEdit, pText );
417 if( lphc->wState & CBF_FOCUSED )
418 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1));
420 else /* paint text field ourselves */
422 HBRUSH32 hPrevBrush = 0;
423 HDC32 hDC = hdc;
425 if( !hDC )
427 if ((hDC = GetDC32(lphc->self->hwndSelf)))
429 HBRUSH32 hBrush = SendMessage32A( lphc->owner,
430 WM_CTLCOLORLISTBOX,
431 hDC, lphc->self->hwndSelf );
432 hPrevBrush = SelectObject32( hDC,
433 (hBrush) ? hBrush : GetStockObject32(WHITE_BRUSH) );
436 if( hDC )
438 RECT32 rect;
439 UINT16 itemState;
440 HFONT32 hPrevFont = (lphc->hFont) ? SelectObject32(hDC, lphc->hFont) : 0;
442 PatBlt32( hDC, (rect.left = lphc->RectEdit.left + SYSMETRICS_CXBORDER),
443 (rect.top = lphc->RectEdit.top + SYSMETRICS_CYBORDER),
444 (rect.right = lphc->RectEdit.right - SYSMETRICS_CXBORDER),
445 (rect.bottom = lphc->RectEdit.bottom - SYSMETRICS_CYBORDER) - 1, PATCOPY );
446 InflateRect32( &rect, -1, -1 );
448 if( lphc->wState & CBF_FOCUSED &&
449 !(lphc->wState & CBF_DROPPED) )
451 /* highlight */
453 FillRect32( hDC, &rect, sysColorObjects.hbrushHighlight );
454 SetBkColor32( hDC, GetSysColor32( COLOR_HIGHLIGHT ) );
455 SetTextColor32( hDC, GetSysColor32( COLOR_HIGHLIGHTTEXT ) );
456 itemState = ODS_SELECTED | ODS_FOCUS;
457 } else itemState = 0;
459 if( CB_OWNERDRAWN(lphc) )
461 DRAWITEMSTRUCT32 dis;
463 if( lphc->self->dwStyle & WS_DISABLED ) itemState |= ODS_DISABLED;
465 dis.CtlType = ODT_COMBOBOX;
466 dis.CtlID = lphc->self->wIDmenu;
467 dis.hwndItem = lphc->self->hwndSelf;
468 dis.itemAction = ODA_DRAWENTIRE;
469 dis.itemID = id;
470 dis.itemState = itemState;
471 dis.hDC = hDC;
472 dis.rcItem = rect;
473 dis.itemData = SendMessage32A( lphc->hWndLBox, LB_GETITEMDATA32,
474 (WPARAM32)id, 0 );
475 SendMessage32A( lphc->owner, WM_DRAWITEM,
476 lphc->self->wIDmenu, (LPARAM)&dis );
478 else
480 ExtTextOut32A( hDC, rect.left + 1, rect.top + 1,
481 ETO_OPAQUE | ETO_CLIPPED, &rect,
482 (pText) ? pText : "" , size, NULL );
483 if(lphc->wState & CBF_FOCUSED && !(lphc->wState & CBF_DROPPED))
484 DrawFocusRect32( hDC, &rect );
487 if( hPrevFont ) SelectObject32(hDC, hPrevFont );
488 if( !hdc )
490 if( hPrevBrush ) SelectObject32( hDC, hPrevBrush );
491 ReleaseDC32( lphc->self->hwndSelf, hDC );
495 HeapFree( GetProcessHeap(), 0, pText );
498 /***********************************************************************
499 * COMBO_Paint
501 static LRESULT COMBO_Paint(LPHEADCOMBO lphc, HDC16 hParamDC)
503 PAINTSTRUCT16 ps;
504 HDC16 hDC;
506 hDC = (hParamDC) ? hParamDC
507 : BeginPaint16( lphc->self->hwndSelf, &ps);
508 if( hDC && !(lphc->self->flags & WIN_NO_REDRAW) )
510 HBRUSH32 hPrevBrush, hBkgBrush;
512 hBkgBrush = SendMessage32A( lphc->owner, WM_CTLCOLORLISTBOX,
513 hDC, lphc->self->hwndSelf );
514 if( !hBkgBrush ) hBkgBrush = GetStockObject32(WHITE_BRUSH);
516 hPrevBrush = SelectObject32( hDC, hBkgBrush );
517 if( !IsRectEmpty16(&lphc->RectButton) )
519 /* paint everything to the right of the text field */
521 PatBlt32( hDC, lphc->RectEdit.right, lphc->RectEdit.top,
522 lphc->RectButton.right - lphc->RectEdit.right,
523 lphc->RectEdit.bottom - lphc->RectEdit.top, PATCOPY );
524 CBPaintButton( lphc, hDC );
527 if( !(lphc->wState & CBF_EDIT) )
529 /* paint text field */
531 GRAPH_DrawRectangle( hDC, lphc->RectEdit.left, lphc->RectEdit.top,
532 lphc->RectEdit.right - lphc->RectEdit.left,
533 lphc->RectButton.bottom - lphc->RectButton.top,
534 sysColorObjects.hpenWindowFrame );
535 CBPaintText( lphc, hDC );
537 if( hPrevBrush ) SelectObject32( hDC, hPrevBrush );
539 if( !hParamDC ) EndPaint16(lphc->self->hwndSelf, &ps);
540 return 0;
543 /***********************************************************************
544 * CBUpdateLBox
546 * Select listbox entry according to the contents of the edit control.
548 static INT32 CBUpdateLBox( LPHEADCOMBO lphc )
550 INT32 length, idx, ret;
551 LPSTR pText = NULL;
553 idx = ret = LB_ERR;
554 length = CB_GETEDITTEXTLENGTH( lphc );
556 if( length > 0 )
557 pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1);
559 dprintf_combo(stddeb,"\tCBUpdateLBox: edit text length %i\n", length );
561 if( pText )
563 if( length ) GetWindowText32A( lphc->hWndEdit, pText, length + 1);
564 else pText[0] = '\0';
565 idx = SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32,
566 (WPARAM32)(-1), (LPARAM)pText );
567 if( idx == LB_ERR ) idx = 0; /* select first item */
568 else ret = idx;
569 HeapFree( GetProcessHeap(), 0, pText );
572 /* select entry */
574 SendMessage32A( lphc->hWndLBox, LB_SETCURSEL32, (WPARAM32)idx, 0 );
576 if( idx >= 0 )
578 SendMessage32A( lphc->hWndLBox, LB_SETTOPINDEX32, (WPARAM32)idx, 0 );
579 /* probably superfluous but Windows sends this too */
580 SendMessage32A( lphc->hWndLBox, LB_SETCARETINDEX32, (WPARAM32)idx, 0 );
582 return ret;
585 /***********************************************************************
586 * CBUpdateEdit
588 * Copy a listbox entry to the edit control.
590 static void CBUpdateEdit( LPHEADCOMBO lphc , INT32 index )
592 INT32 length;
593 LPSTR pText = NULL;
595 dprintf_combo(stddeb,"\tCBUpdateEdit: %i\n", index );
597 if( index == -1 )
599 length = CB_GETEDITTEXTLENGTH( lphc );
600 if( length )
602 if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) )
604 GetWindowText32A( lphc->hWndEdit, pText, length + 1 );
605 index = SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32,
606 (WPARAM32)(-1), (LPARAM)pText );
607 HeapFree( GetProcessHeap(), 0, pText );
612 if( index >= 0 ) /* got an entry */
614 length = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, (WPARAM32)index, 0);
615 if( length )
617 if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) )
619 SendMessage32A( lphc->hWndLBox, LB_GETTEXT32,
620 (WPARAM32)index, (LPARAM)pText );
621 SendMessage32A( lphc->hWndEdit, WM_SETTEXT, 0, (LPARAM)pText );
622 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1) );
623 HeapFree( GetProcessHeap(), 0, pText );
629 /***********************************************************************
630 * CBDropDown
632 * Show listbox popup.
634 static void CBDropDown( LPHEADCOMBO lphc )
636 INT32 index;
637 RECT16 rect;
638 LPRECT16 pRect = NULL;
640 dprintf_combo(stddeb,"Combo [%04x]: drop down\n", CB_HWND(lphc));
642 CB_NOTIFY( lphc, CBN_DROPDOWN );
644 /* set selection */
646 lphc->wState |= CBF_DROPPED;
647 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
649 index = CBUpdateLBox( lphc );
650 if( !(lphc->wState & CBF_CAPTURE) ) CBUpdateEdit( lphc, index );
652 else
654 index = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 );
655 if( index == LB_ERR ) index = 0;
656 SendMessage32A( lphc->hWndLBox, LB_SETTOPINDEX32, (WPARAM32)index, 0 );
657 SendMessage32A( lphc->hWndLBox, LB_CARETON32, 0, 0 );
658 pRect = &lphc->RectEdit;
661 /* now set popup position */
663 GetWindowRect16( lphc->self->hwndSelf, &rect );
665 rect.top += lphc->RectEdit.bottom - lphc->RectEdit.top - SYSMETRICS_CYBORDER;
666 rect.bottom = rect.top + lphc->RectCombo.bottom -
667 lphc->RectCombo.top - SYSMETRICS_CYBORDER;
668 rect.right = rect.left + lphc->RectCombo.right - lphc->RectCombo.left;
669 rect.left += ( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST ) ? 0 : CBitOffset;
671 SetWindowPos32( lphc->hWndLBox, HWND_TOP, rect.left, rect.top,
672 rect.right - rect.left, rect.bottom - rect.top,
673 SWP_NOACTIVATE | SWP_NOSIZE );
674 if( pRect )
675 RedrawWindow16( lphc->self->hwndSelf, pRect, 0, RDW_INVALIDATE |
676 RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
677 ShowWindow32( lphc->hWndLBox, SW_SHOWNA );
680 /***********************************************************************
681 * CBRollUp
683 * Hide listbox popup.
685 static void CBRollUp( LPHEADCOMBO lphc, BOOL32 ok, BOOL32 bButton )
687 HWND32 hWnd = lphc->self->hwndSelf;
689 CB_NOTIFY( lphc, (ok) ? CBN_SELENDOK : CBN_SELENDCANCEL );
691 if( IsWindow32( hWnd ) && CB_GETTYPE(lphc) != CBS_SIMPLE )
694 dprintf_combo(stddeb,"Combo [%04x]: roll up [%i]\n", CB_HWND(lphc), (INT32)ok );
696 /* always send WM_LBUTTONUP? */
697 SendMessage32A( lphc->hWndLBox, WM_LBUTTONUP, 0, (LPARAM)(-1) );
699 if( lphc->wState & CBF_DROPPED )
701 RECT16 rect;
703 lphc->wState &= ~CBF_DROPPED;
704 ShowWindow32( lphc->hWndLBox, SW_HIDE );
706 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
708 INT32 index = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 );
709 CBUpdateEdit( lphc, index );
710 rect = lphc->RectButton;
712 else
714 if( bButton )
715 UnionRect16( &rect, &lphc->RectButton,
716 &lphc->RectEdit );
717 else
718 rect = lphc->RectEdit;
719 bButton = TRUE;
722 if( bButton )
723 RedrawWindow16( hWnd, &rect, 0, RDW_INVALIDATE |
724 RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
725 CB_NOTIFY( lphc, CBN_CLOSEUP );
730 /***********************************************************************
731 * COMBO_FlipListbox
733 * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
735 BOOL32 COMBO_FlipListbox( LPHEADCOMBO lphc, BOOL32 bRedrawButton )
737 if( lphc->wState & CBF_DROPPED )
739 CBRollUp( lphc, TRUE, bRedrawButton );
740 return FALSE;
743 CBDropDown( lphc );
744 return TRUE;
747 /***********************************************************************
748 * COMBO_GetLBWindow
750 * Edit control helper.
752 HWND32 COMBO_GetLBWindow( WND* pWnd )
754 LPHEADCOMBO lphc = CB_GETPTR(pWnd);
755 if( lphc ) return lphc->hWndLBox;
756 return 0;
760 /***********************************************************************
761 * CBRepaintButton
763 static void CBRepaintButton( LPHEADCOMBO lphc )
765 HDC32 hDC = GetDC32( lphc->self->hwndSelf );
767 if( hDC )
769 CBPaintButton( lphc, (HDC16)hDC );
770 ReleaseDC32( lphc->self->hwndSelf, hDC );
774 /***********************************************************************
775 * COMBO_SetFocus
777 static void COMBO_SetFocus( LPHEADCOMBO lphc )
779 if( !(lphc->wState & CBF_FOCUSED) )
781 if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
782 SendMessage32A( lphc->hWndLBox, LB_CARETON32, 0, 0 );
784 if( lphc->wState & CBF_EDIT )
785 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, 0, (LPARAM)(-1) );
786 lphc->wState |= CBF_FOCUSED;
787 if( !(lphc->wState & CBF_EDIT) ) CBPaintText( lphc, 0 );
789 CB_NOTIFY( lphc, CBN_SETFOCUS );
793 /***********************************************************************
794 * COMBO_KillFocus
796 static void COMBO_KillFocus( LPHEADCOMBO lphc )
798 HWND32 hWnd = lphc->self->hwndSelf;
800 if( lphc->wState & CBF_FOCUSED )
802 SendMessage32A( hWnd, WM_LBUTTONUP, 0, (LPARAM)(-1) );
804 CBRollUp( lphc, FALSE, TRUE );
805 if( IsWindow32( hWnd ) )
807 if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
808 SendMessage32A( lphc->hWndLBox, LB_CARETOFF32, 0, 0 );
810 lphc->wState &= ~CBF_FOCUSED;
812 /* redraw text */
813 if( lphc->wState & CBF_EDIT )
814 SendMessage32A( lphc->hWndEdit, EM_SETSEL32, (WPARAM32)(-1), 0 );
815 else CBPaintText( lphc, 0 );
817 CB_NOTIFY( lphc, CBN_KILLFOCUS );
822 /***********************************************************************
823 * COMBO_Command
825 static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM32 wParam, HWND32 hWnd )
827 if( lphc->wState & CBF_EDIT && lphc->hWndEdit == hWnd )
829 /* ">> 8" makes gcc generate jump-table instead of cmp ladder */
831 switch( HIWORD(wParam) >> 8 )
833 case (EN_SETFOCUS >> 8):
835 dprintf_combo(stddeb,"Combo [%04x]: edit [%04x] got focus\n",
836 CB_HWND(lphc), (HWND16)lphc->hWndEdit );
838 if( !(lphc->wState & CBF_FOCUSED) ) COMBO_SetFocus( lphc );
839 break;
841 case (EN_KILLFOCUS >> 8):
843 dprintf_combo(stddeb,"Combo [%04x]: edit [%04x] lost focus\n",
844 CB_HWND(lphc), (HWND16)lphc->hWndEdit );
846 /* NOTE: it seems that Windows' edit control sends an
847 * undocumented message WM_USER + 0x1B instead of this
848 * notification (only when it happens to be a part of
849 * the combo). ?? - AK.
852 COMBO_KillFocus( lphc );
853 break;
856 case (EN_CHANGE >> 8):
857 CB_NOTIFY( lphc, CBN_EDITCHANGE );
858 CBUpdateLBox( lphc );
859 break;
861 case (EN_UPDATE >> 8):
862 CB_NOTIFY( lphc, CBN_EDITUPDATE );
863 break;
865 case (EN_ERRSPACE >> 8):
866 CB_NOTIFY( lphc, CBN_ERRSPACE );
869 else if( lphc->hWndLBox == hWnd )
871 switch( HIWORD(wParam) )
873 case LBN_ERRSPACE:
874 CB_NOTIFY( lphc, CBN_ERRSPACE );
875 break;
877 case LBN_DBLCLK:
878 CB_NOTIFY( lphc, CBN_DBLCLK );
879 break;
881 case LBN_SELCHANGE:
882 case LBN_SELCANCEL:
884 dprintf_combo(stddeb,"Combo [%04x]: lbox selection change [%04x]\n",
885 CB_HWND(lphc), lphc->wState );
887 /* do not roll up if selection is being tracked
888 * by arrowkeys in the dropdown listbox */
890 if( (lphc->wState & CBF_DROPPED) && !(lphc->wState & CBF_NOROLLUP) )
891 CBRollUp( lphc, (HIWORD(wParam) == LBN_SELCHANGE), TRUE );
892 else lphc->wState &= ~CBF_NOROLLUP;
894 CB_NOTIFY( lphc, CBN_SELCHANGE );
895 CBPaintText( lphc, 0 );
896 /* fall through */
898 case LBN_SETFOCUS:
899 case LBN_KILLFOCUS:
900 /* nothing to do here since ComboLBox always resets the focus to its
901 * combo/edit counterpart */
904 return 0;
907 /***********************************************************************
908 * COMBO_ItemOp
910 * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
912 static LRESULT COMBO_ItemOp32( LPHEADCOMBO lphc, UINT32 msg,
913 WPARAM32 wParam, LPARAM lParam )
915 HWND32 hWnd = lphc->self->hwndSelf;
917 dprintf_combo(stddeb,"Combo [%04x]: ownerdraw op %04x\n",
918 CB_HWND(lphc), (UINT16)msg );
920 #define lpIS ((LPDELETEITEMSTRUCT32)lParam)
922 /* two first items are the same in all 4 structs */
923 lpIS->CtlType = ODT_COMBOBOX;
924 lpIS->CtlID = lphc->self->wIDmenu;
926 switch( msg ) /* patch window handle */
928 case WM_DELETEITEM:
929 lpIS->hwndItem = hWnd;
930 #undef lpIS
931 break;
932 case WM_DRAWITEM:
933 #define lpIS ((LPDRAWITEMSTRUCT32)lParam)
934 lpIS->hwndItem = hWnd;
935 #undef lpIS
936 break;
937 case WM_COMPAREITEM:
938 #define lpIS ((LPCOMPAREITEMSTRUCT32)lParam)
939 lpIS->hwndItem = hWnd;
940 #undef lpIS
941 break;
944 return SendMessage32A( lphc->owner, msg, lphc->self->wIDmenu, lParam );
947 /***********************************************************************
948 * COMBO_GetText
950 static LRESULT COMBO_GetText( LPHEADCOMBO lphc, UINT32 N, LPSTR lpText)
952 INT32 idx;
954 if( lphc->wState & CBF_EDIT )
955 return SendMessage32A( lphc->hWndEdit, WM_GETTEXT,
956 (WPARAM32)N, (LPARAM)lpText );
958 /* get it from the listbox */
960 idx = SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0 );
961 if( idx != LB_ERR )
963 LPSTR lpBuffer;
964 INT32 length = SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32,
965 (WPARAM32)idx, 0 );
967 /* 'length' is without the terminating character */
968 if( length >= N )
969 lpBuffer = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1 );
970 else
971 lpBuffer = lpText;
973 if( lpBuffer )
975 INT32 n = SendMessage32A( lphc->hWndLBox, LB_GETTEXT32,
976 (WPARAM32)idx, (LPARAM)lpText );
978 /* truncate if buffer is too short */
980 if( length >= N )
982 if( n != LB_ERR ) memcpy( lpText, lpBuffer, (N>n) ? n+1 : N-1 );
983 lpText[N - 1] = '\0';
984 HeapFree( GetProcessHeap(), 0, lpBuffer );
986 return (LRESULT)n;
989 return 0;
993 /***********************************************************************
994 * CBResetPos
996 * This function sets window positions according to the updated
997 * component placement struct.
999 static void CBResetPos( LPHEADCOMBO lphc, LPRECT16 lbRect, BOOL32 bRedraw )
1001 BOOL32 bDrop = (CB_GETTYPE(lphc) != CBS_SIMPLE);
1003 /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
1004 * sizing messages */
1006 if( lphc->wState & CBF_EDIT )
1007 SetWindowPos32( lphc->hWndEdit, 0, lphc->RectEdit.left, lphc->RectEdit.top,
1008 lphc->RectEdit.right - lphc->RectEdit.left,
1009 lphc->RectEdit.bottom - lphc->RectEdit.top,
1010 SWP_NOZORDER | SWP_NOACTIVATE | ((bDrop) ? SWP_NOREDRAW : 0) );
1012 if( bDrop )
1013 OffsetRect16( lbRect, lphc->RectCombo.left, lphc->RectCombo.top );
1015 lbRect->right -= lbRect->left; /* convert to width */
1016 lbRect->bottom -= lbRect->top;
1017 SetWindowPos32( lphc->hWndLBox, 0, lbRect->left, lbRect->top,
1018 lbRect->right, lbRect->bottom,
1019 SWP_NOACTIVATE | SWP_NOZORDER | ((bDrop) ? SWP_NOREDRAW : 0) );
1021 if( bDrop )
1023 if( lphc->wState & CBF_DROPPED )
1025 lphc->wState &= ~CBF_DROPPED;
1026 ShowWindow32( lphc->hWndLBox, SW_HIDE );
1029 lphc->wState |= CBF_NORESIZE;
1030 SetWindowPos32( lphc->self->hwndSelf, 0, 0, 0,
1031 lphc->RectCombo.right - lphc->RectCombo.left,
1032 lphc->RectEdit.bottom - lphc->RectEdit.top,
1033 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOREDRAW );
1034 lphc->wState &= ~CBF_NORESIZE;
1035 if( bRedraw )
1036 RedrawWindow32( lphc->self->hwndSelf, NULL, 0,
1037 RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
1042 /***********************************************************************
1043 * COMBO_Size
1045 static void COMBO_Size( LPHEADCOMBO lphc )
1047 RECT16 rect;
1048 INT16 w, h;
1050 GetWindowRect16( lphc->self->hwndSelf, &rect );
1051 w = rect.right - rect.left; h = rect.bottom - rect.top;
1053 dprintf_combo(stddeb,"COMBO_Size: w = %i, h = %i\n", w, h );
1055 /* CreateWindow() may send a bogus WM_SIZE, ignore it */
1057 if( w == (lphc->RectCombo.right - lphc->RectCombo.left) )
1058 if( (CB_GETTYPE(lphc) == CBS_SIMPLE) &&
1059 (h == (lphc->RectCombo.bottom - lphc->RectCombo.top)) )
1060 return;
1061 else if( (lphc->dwStyle & CBS_DROPDOWN) &&
1062 (h == (lphc->RectEdit.bottom - lphc->RectEdit.top)) )
1063 return;
1065 lphc->RectCombo = rect;
1066 CBCalcPlacement( lphc, &lphc->RectEdit, &lphc->RectButton, &rect );
1067 CBResetPos( lphc, &rect, TRUE );
1071 /***********************************************************************
1072 * COMBO_Font
1074 static void COMBO_Font( LPHEADCOMBO lphc, HFONT16 hFont, BOOL32 bRedraw )
1076 RECT16 rect;
1078 lphc->hFont = hFont;
1080 if( lphc->wState & CBF_EDIT )
1081 SendMessage32A( lphc->hWndEdit, WM_SETFONT, (WPARAM32)hFont, bRedraw );
1082 SendMessage32A( lphc->hWndLBox, WM_SETFONT, (WPARAM32)hFont, bRedraw );
1084 GetWindowRect16( lphc->self->hwndSelf, &rect );
1085 OffsetRect16( &lphc->RectCombo, rect.left - lphc->RectCombo.left,
1086 rect.top - lphc->RectCombo.top );
1087 CBCalcPlacement( lphc, &lphc->RectEdit,
1088 &lphc->RectButton, &rect );
1089 CBResetPos( lphc, &rect, bRedraw );
1093 /***********************************************************************
1094 * COMBO_SetItemHeight
1096 static LRESULT COMBO_SetItemHeight( LPHEADCOMBO lphc, INT32 index, INT32 height )
1098 LRESULT lRet = CB_ERR;
1100 if( index == -1 ) /* set text field height */
1102 if( height < 32768 )
1104 RECT16 rect;
1106 lphc->editHeight = height;
1107 GetWindowRect16( lphc->self->hwndSelf, &rect );
1108 OffsetRect16( &lphc->RectCombo, rect.left - lphc->RectCombo.left,
1109 rect.top - lphc->RectCombo.top );
1110 CBCalcPlacement( lphc, &lphc->RectEdit,
1111 &lphc->RectButton, &rect );
1112 CBResetPos( lphc, &rect, TRUE );
1113 lRet = height;
1116 else if ( CB_OWNERDRAWN(lphc) ) /* set listbox item height */
1117 lRet = SendMessage32A( lphc->hWndLBox, LB_SETITEMHEIGHT32,
1118 (WPARAM32)index, (LPARAM)height );
1119 return lRet;
1122 /***********************************************************************
1123 * COMBO_SelectString
1125 static LRESULT COMBO_SelectString( LPHEADCOMBO lphc, INT32 start, LPCSTR pText )
1127 INT32 index = SendMessage32A( lphc->hWndLBox, CB_SELECTSTRING32,
1128 (WPARAM32)start, (LPARAM)pText );
1129 if( index >= 0 )
1130 if( lphc->wState & CBF_EDIT )
1131 CBUpdateEdit( lphc, index );
1132 else
1133 CBPaintText( lphc, 0 );
1134 return (LRESULT)index;
1137 /***********************************************************************
1138 * COMBO_LButtonDown
1140 static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam )
1142 BOOL32 bButton = PtInRect16(&lphc->RectButton, MAKEPOINT16(lParam));
1143 HWND32 hWnd = lphc->self->hwndSelf;
1145 if( (CB_GETTYPE(lphc) == CBS_DROPDOWNLIST) ||
1146 (bButton && (CB_GETTYPE(lphc) == CBS_DROPDOWN)) )
1148 lphc->wState |= CBF_BUTTONDOWN;
1149 if( lphc->wState & CBF_DROPPED )
1151 /* got a click to cancel selection */
1153 CBRollUp( lphc, TRUE, FALSE );
1154 if( !IsWindow32( hWnd ) ) return;
1156 if( lphc->wState & CBF_CAPTURE )
1158 lphc->wState &= ~CBF_CAPTURE;
1159 ReleaseCapture();
1161 lphc->wState &= ~CBF_BUTTONDOWN;
1163 else
1165 /* drop down the listbox and start tracking */
1167 lphc->wState |= CBF_CAPTURE;
1168 CBDropDown( lphc );
1169 SetCapture32( hWnd );
1171 if( bButton ) CBRepaintButton( lphc );
1175 /***********************************************************************
1176 * COMBO_LButtonUp
1178 * Release capture and stop tracking if needed.
1180 static void COMBO_LButtonUp( LPHEADCOMBO lphc, LPARAM lParam )
1182 if( lphc->wState & CBF_CAPTURE )
1184 lphc->wState &= ~CBF_CAPTURE;
1185 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
1187 INT32 index = CBUpdateLBox( lphc );
1188 CBUpdateEdit( lphc, index );
1190 ReleaseCapture();
1193 if( lphc->wState & CBF_BUTTONDOWN )
1195 lphc->wState &= ~CBF_BUTTONDOWN;
1196 CBRepaintButton( lphc );
1200 /***********************************************************************
1201 * COMBO_MouseMove
1203 * Two things to do - track combo button and release capture when
1204 * pointer goes into the listbox.
1206 static void COMBO_MouseMove( LPHEADCOMBO lphc, WPARAM32 wParam, LPARAM lParam )
1208 RECT16 lbRect;
1210 if( lphc->wState & CBF_BUTTONDOWN )
1212 BOOL32 bButton = PtInRect16(&lphc->RectButton, MAKEPOINT16(lParam));
1214 if( !bButton )
1216 lphc->wState &= ~CBF_BUTTONDOWN;
1217 CBRepaintButton( lphc );
1221 GetClientRect16( lphc->hWndLBox, &lbRect );
1222 MapWindowPoints16( lphc->self->hwndSelf,
1223 lphc->hWndLBox, (LPPOINT16)&lParam, 1 );
1224 if( PtInRect16(&lbRect, MAKEPOINT16(lParam)) )
1226 lphc->wState &= ~CBF_CAPTURE;
1227 ReleaseCapture();
1228 if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) CBUpdateLBox( lphc );
1230 /* hand over pointer tracking */
1231 SendMessage32A( lphc->hWndLBox, WM_LBUTTONDOWN, wParam, lParam );
1236 /***********************************************************************
1237 * ComboWndProc
1239 * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/ctrl/src/combobox_15.htm
1241 LRESULT ComboWndProc(HWND32 hwnd, UINT32 message, WPARAM32 wParam, LPARAM lParam)
1243 WND* pWnd = WIN_FindWndPtr(hwnd);
1245 if( pWnd )
1247 LPHEADCOMBO lphc = CB_GETPTR(pWnd);
1249 dprintf_combo( stddeb, "Combo [%04x]: msg %s wp %08x lp %08lx\n",
1250 pWnd->hwndSelf, SPY_GetMsgName(message), wParam, lParam );
1252 if( lphc || message == WM_NCCREATE )
1253 switch(message)
1256 /* System messages */
1258 case WM_NCCREATE:
1259 return COMBO_NCCreate(pWnd, lParam);
1261 case WM_NCDESTROY:
1262 COMBO_NCDestroy(lphc);
1263 break;
1265 case WM_CREATE:
1266 return COMBO_Create(lphc, pWnd, lParam);
1268 case WM_PAINT:
1269 /* wParam may contain a valid HDC! */
1270 return COMBO_Paint(lphc, (HDC16)wParam);
1272 case WM_ERASEBKGND:
1273 return TRUE;
1275 case WM_GETDLGCODE:
1276 return (LRESULT)(DLGC_WANTARROWS | DLGC_WANTCHARS);
1278 case WM_SIZE:
1279 if( lphc->hWndLBox &&
1280 !(lphc->wState & CBF_NORESIZE) ) COMBO_Size( lphc );
1281 return TRUE;
1283 case WM_SETFONT:
1284 COMBO_Font( lphc, (HFONT16)wParam, (BOOL32)lParam );
1285 return TRUE;
1287 case WM_GETFONT:
1288 return (LRESULT)lphc->hFont;
1290 case WM_SETFOCUS:
1291 if( lphc->wState & CBF_EDIT )
1292 SetFocus32( lphc->hWndEdit );
1293 else
1294 COMBO_SetFocus( lphc );
1295 return TRUE;
1297 case WM_KILLFOCUS:
1298 #define hwndFocus ((HWND16)wParam)
1299 if( !hwndFocus ||
1300 (hwndFocus != lphc->hWndEdit && hwndFocus != lphc->hWndLBox ))
1301 COMBO_KillFocus( lphc );
1302 #undef hwndFocus
1303 return TRUE;
1305 case WM_COMMAND:
1306 return COMBO_Command( lphc, wParam, (HWND32)lParam );
1308 case WM_GETTEXT:
1309 return COMBO_GetText( lphc, (UINT32)wParam, (LPSTR)lParam );
1311 case WM_SETTEXT:
1312 case WM_GETTEXTLENGTH:
1313 case WM_CLEAR:
1314 case WM_CUT:
1315 case WM_PASTE:
1316 case WM_COPY:
1317 if( lphc->wState & CBF_EDIT )
1318 return SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1319 return CB_ERR;
1321 case WM_DRAWITEM:
1322 case WM_DELETEITEM:
1323 case WM_COMPAREITEM:
1324 case WM_MEASUREITEM:
1325 return COMBO_ItemOp32( lphc, message, wParam, lParam );
1327 case WM_ENABLE:
1328 if( lphc->wState & CBF_EDIT )
1329 EnableWindow32( lphc->hWndEdit, (BOOL32)wParam );
1330 EnableWindow32( lphc->hWndLBox, (BOOL32)wParam );
1331 return TRUE;
1333 case WM_SETREDRAW:
1334 if( lphc->wState & CBF_EDIT )
1335 SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1336 SendMessage32A( lphc->hWndLBox, message, wParam, lParam );
1337 break;
1339 case WM_SYSKEYDOWN:
1340 if( KEYDATA_ALT & HIWORD(lParam) )
1341 if( wParam == VK_UP || wParam == VK_DOWN )
1342 COMBO_FlipListbox( lphc, TRUE );
1343 break;
1345 case WM_CHAR:
1346 case WM_KEYDOWN:
1347 if( lphc->wState & CBF_EDIT )
1348 return SendMessage32A( lphc->hWndEdit, message, wParam, lParam );
1349 else
1350 return SendMessage32A( lphc->hWndLBox, message, wParam, lParam );
1352 case WM_LBUTTONDOWN:
1353 if( !(lphc->wState & CBF_FOCUSED) ) SetFocus32( lphc->self->hwndSelf );
1354 if( lphc->wState & CBF_FOCUSED ) COMBO_LButtonDown( lphc, lParam );
1355 return TRUE;
1357 case WM_LBUTTONUP:
1358 COMBO_LButtonUp( lphc, lParam );
1359 return TRUE;
1361 case WM_MOUSEMOVE:
1362 if( lphc->wState & CBF_CAPTURE )
1363 COMBO_MouseMove( lphc, wParam, lParam );
1364 return TRUE;
1366 /* Combo messages */
1368 case CB_ADDSTRING16:
1369 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1370 case CB_ADDSTRING32:
1371 return SendMessage32A( lphc->hWndLBox, LB_ADDSTRING32, 0, lParam);
1373 case CB_INSERTSTRING16:
1374 wParam = (INT32)(INT16)wParam;
1375 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1376 case CB_INSERTSTRING32:
1377 return SendMessage32A( lphc->hWndLBox, LB_INSERTSTRING32, wParam, lParam);
1379 case CB_DELETESTRING16:
1380 case CB_DELETESTRING32:
1381 return SendMessage32A( lphc->hWndLBox, LB_DELETESTRING32, wParam, 0);
1383 case CB_SELECTSTRING16:
1384 wParam = (INT32)(INT16)wParam;
1385 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1386 case CB_SELECTSTRING32:
1387 return COMBO_SelectString( lphc, (INT32)wParam, (LPSTR)lParam );
1389 case CB_FINDSTRING16:
1390 wParam = (INT32)(INT16)wParam;
1391 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1392 case CB_FINDSTRING32:
1393 return SendMessage32A( lphc->hWndLBox, LB_FINDSTRING32, wParam, lParam);
1395 case CB_FINDSTRINGEXACT16:
1396 wParam = (INT32)(INT16)wParam;
1397 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1398 case CB_FINDSTRINGEXACT32:
1399 return SendMessage32A( lphc->hWndLBox, LB_FINDSTRINGEXACT32,
1400 wParam, lParam );
1401 case CB_SETITEMHEIGHT16:
1402 wParam = (INT32)(INT16)wParam;
1403 case CB_SETITEMHEIGHT32:
1404 return COMBO_SetItemHeight( lphc, (INT32)wParam, (INT32)lParam);
1406 case CB_RESETCONTENT16:
1407 case CB_RESETCONTENT32:
1408 SendMessage32A( lphc->hWndLBox, LB_RESETCONTENT32, 0, 0 );
1409 CBPaintText( lphc, 0 );
1410 return TRUE;
1412 case CB_INITSTORAGE32:
1413 return SendMessage32A( lphc->hWndLBox, LB_INITSTORAGE32, wParam, lParam);
1415 case CB_GETHORIZONTALEXTENT32:
1416 return SendMessage32A( lphc->hWndLBox, LB_GETHORIZONTALEXTENT32, 0, 0);
1418 case CB_SETHORIZONTALEXTENT32:
1419 return SendMessage32A( lphc->hWndLBox, LB_SETHORIZONTALEXTENT32, wParam, 0);
1421 case CB_GETTOPINDEX32:
1422 return SendMessage32A( lphc->hWndLBox, LB_GETTOPINDEX32, 0, 0);
1424 case CB_GETLOCALE32:
1425 return SendMessage32A( lphc->hWndLBox, LB_GETLOCALE32, 0, 0);
1427 case CB_SETLOCALE32:
1428 return SendMessage32A( lphc->hWndLBox, LB_SETLOCALE32, wParam, 0);
1430 case CB_GETDROPPEDWIDTH32:
1431 if( lphc->droppedWidth )
1432 return lphc->droppedWidth;
1433 return lphc->RectCombo.right - lphc->RectCombo.left -
1434 (lphc->wState & CBF_EDIT) ? CBitOffset : 0;
1436 case CB_SETDROPPEDWIDTH32:
1437 if( (CB_GETTYPE(lphc) != CBS_SIMPLE) &&
1438 (INT32)wParam < 32768 ) lphc->droppedWidth = (INT32)wParam;
1439 return CB_ERR;
1441 case CB_GETDROPPEDCONTROLRECT16:
1442 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1443 if( lParam )
1445 RECT32 r;
1446 CBGetDroppedControlRect32( lphc, &r );
1447 CONV_RECT32TO16( &r, (LPRECT16)lParam );
1449 return CB_OKAY;
1451 case CB_GETDROPPEDCONTROLRECT32:
1452 if( lParam ) CBGetDroppedControlRect32(lphc, (LPRECT32)lParam );
1453 return CB_OKAY;
1455 case CB_GETDROPPEDSTATE16:
1456 case CB_GETDROPPEDSTATE32:
1457 return (lphc->wState & CBF_DROPPED) ? TRUE : FALSE;
1459 case CB_DIR16:
1460 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1461 /* fall through */
1462 case CB_DIR32:
1463 return COMBO_Directory( lphc, (UINT32)wParam,
1464 (LPSTR)lParam, (message == CB_DIR32));
1465 case CB_SHOWDROPDOWN16:
1466 case CB_SHOWDROPDOWN32:
1467 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
1468 if( wParam )
1470 if( !(lphc->wState & CBF_DROPPED) )
1471 CBDropDown( lphc );
1473 else
1474 if( lphc->wState & CBF_DROPPED )
1475 CBRollUp( lphc, FALSE, TRUE );
1476 return TRUE;
1478 case CB_GETCOUNT16:
1479 case CB_GETCOUNT32:
1480 return SendMessage32A( lphc->hWndLBox, LB_GETCOUNT32, 0, 0);
1482 case CB_GETCURSEL16:
1483 case CB_GETCURSEL32:
1484 return SendMessage32A( lphc->hWndLBox, LB_GETCURSEL32, 0, 0);
1486 case CB_SETCURSEL16:
1487 wParam = (INT32)(INT16)wParam;
1488 case CB_SETCURSEL32:
1489 return SendMessage32A( lphc->hWndLBox, LB_SETCURSEL32, wParam, 0);
1491 case CB_GETLBTEXT16:
1492 wParam = (INT32)(INT16)wParam;
1493 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
1494 case CB_GETLBTEXT32:
1495 return SendMessage32A( lphc->hWndLBox, LB_GETTEXT32, wParam, lParam);
1497 case CB_GETLBTEXTLEN16:
1498 wParam = (INT32)(INT16)wParam;
1499 case CB_GETLBTEXTLEN32:
1500 return SendMessage32A( lphc->hWndLBox, LB_GETTEXTLEN32, wParam, 0);
1502 case CB_GETITEMDATA16:
1503 wParam = (INT32)(INT16)wParam;
1504 case CB_GETITEMDATA32:
1505 return SendMessage32A( lphc->hWndLBox, LB_GETITEMDATA32, wParam, 0);
1507 case CB_SETITEMDATA16:
1508 wParam = (INT32)(INT16)wParam;
1509 case CB_SETITEMDATA32:
1510 return SendMessage32A( lphc->hWndLBox, LB_SETITEMDATA32, wParam, lParam);
1512 case CB_GETEDITSEL16:
1513 wParam = lParam = 0; /* just in case */
1514 case CB_GETEDITSEL32:
1515 if( lphc->wState & CBF_EDIT )
1517 INT32 a, b;
1519 return SendMessage32A( lphc->hWndEdit, EM_GETSEL32,
1520 (wParam) ? wParam : (WPARAM32)&a,
1521 (lParam) ? lParam : (LPARAM)&b );
1523 return CB_ERR;
1525 case CB_SETEDITSEL16:
1526 case CB_SETEDITSEL32:
1527 if( lphc->wState & CBF_EDIT )
1528 return SendMessage32A( lphc->hWndEdit, EM_SETSEL32,
1529 (INT32)(INT16)LOWORD(lParam), (INT32)(INT16)HIWORD(lParam) );
1530 return CB_ERR;
1532 case CB_SETEXTENDEDUI16:
1533 case CB_SETEXTENDEDUI32:
1534 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) return CB_ERR;
1536 if( wParam )
1537 lphc->wState |= CBF_EUI;
1538 else lphc->wState &= ~CBF_EUI;
1539 return CB_OKAY;
1541 case CB_GETEXTENDEDUI16:
1542 case CB_GETEXTENDEDUI32:
1543 return (lphc->wState & CBF_EUI) ? TRUE : FALSE;
1545 case (WM_USER + 0x1B):
1546 dprintf_combo(stddeb,"Combo [%04x]: undocumented msg!\n", (HWND16)hwnd );
1548 return DefWindowProc32A(hwnd, message, wParam, lParam);
1550 return CB_ERR;