blob: 05ad7c922b126f587888af0dfa7d365572ab0d18 [file] [log] [blame]
Alexandre Julliard0e607781993-11-03 19:23:37 +00001/*
Alexandre Julliard2787be81995-05-22 18:23:01 +00002 * Combo controls
3 *
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00004 * Copyright 1997 Alex Korobka
Alexandre Julliard2787be81995-05-22 18:23:01 +00005 *
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00006 * FIXME: roll up in Netscape 3.01.
Alexandre Julliard2787be81995-05-22 18:23:01 +00007 */
Alexandre Julliard0e607781993-11-03 19:23:37 +00008
Alexandre Julliard1285c2f1996-05-06 16:06:24 +00009#include <string.h>
Alexandre Julliard8d24ae61994-04-05 21:42:43 +000010
Marcus Meissnerddca3151999-05-22 11:33:23 +000011#include "winbase.h"
Jeremy Whited3e22d92000-02-10 19:03:02 +000012#include "windef.h"
Marcus Meissnerddca3151999-05-22 11:33:23 +000013#include "wingdi.h"
Jeremy Whited3e22d92000-02-10 19:03:02 +000014#include "winuser.h"
Alex Korobka311d3291999-01-01 18:40:02 +000015#include "wine/winuser16.h"
Alexandre Julliardf1aa3031996-08-05 17:42:43 +000016#include "win.h"
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000017#include "spy.h"
Alexandre Julliard3a405ba1994-10-30 16:25:19 +000018#include "user.h"
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +000019#include "heap.h"
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000020#include "combo.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000021#include "drive.h"
Alexandre Julliard9fe7a251999-05-14 08:17:14 +000022#include "debugtools.h"
Francis Beaudetf585c611999-04-02 10:37:42 +000023#include "tweak.h"
Alexandre Julliard0e607781993-11-03 19:23:37 +000024
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000025DEFAULT_DEBUG_CHANNEL(combo)
26
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000027 /* bits in the dwKeyData */
28#define KEYDATA_ALT 0x2000
29#define KEYDATA_PREVSTATE 0x4000
Alexandre Julliard86a8d0f1994-01-18 23:04:40 +000030
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000031/*
32 * Additional combo box definitions
33 */
Alexandre Julliardb817f4f1996-03-14 18:08:34 +000034
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000035#define CB_GETPTR( wnd ) (*(LPHEADCOMBO*)((wnd)->wExtra))
36#define CB_NOTIFY( lphc, code ) \
Alexandre Julliarda3960291999-02-26 11:11:13 +000037 (SendMessageA( (lphc)->owner, WM_COMMAND, \
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000038 MAKEWPARAM((lphc)->self->wIDmenu, (code)), (lphc)->self->hwndSelf))
39#define CB_GETEDITTEXTLENGTH( lphc ) \
Alexandre Julliarda3960291999-02-26 11:11:13 +000040 (SendMessageA( (lphc)->hWndEdit, WM_GETTEXTLENGTH, 0, 0 ))
Alexandre Julliard1285c2f1996-05-06 16:06:24 +000041
Gerard Patel8c362541999-10-13 13:50:17 +000042#define ISWIN31 (LOWORD(GetVersion()) == 0x0a03)
43
Francis Beaudetf585c611999-04-02 10:37:42 +000044/*
45 * Drawing globals
46 */
Alexandre Julliarda3960291999-02-26 11:11:13 +000047static HBITMAP hComboBmp = 0;
Francis Beaudetf585c611999-04-02 10:37:42 +000048static UINT CBitHeight, CBitWidth;
49
50/*
51 * Look and feel dependant "constants"
52 */
Abey George318832e1999-07-10 11:34:01 +000053
54#define COMBO_YBORDERGAP 5
Francis Beaudetf585c611999-04-02 10:37:42 +000055#define COMBO_XBORDERSIZE() ( (TWEAK_WineLook == WIN31_LOOK) ? 0 : 2 )
56#define COMBO_YBORDERSIZE() ( (TWEAK_WineLook == WIN31_LOOK) ? 0 : 2 )
57#define COMBO_EDITBUTTONSPACE() ( (TWEAK_WineLook == WIN31_LOOK) ? 8 : 0 )
58#define EDIT_CONTROL_PADDING() ( (TWEAK_WineLook == WIN31_LOOK) ? 0 : 1 )
Alexandre Julliard2787be81995-05-22 18:23:01 +000059
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000060/***********************************************************************
61 * COMBO_Init
62 *
63 * Load combo button bitmap.
64 */
Alexandre Julliarda3960291999-02-26 11:11:13 +000065static BOOL COMBO_Init()
Alexandre Julliard2787be81995-05-22 18:23:01 +000066{
Alexandre Julliarda3960291999-02-26 11:11:13 +000067 HDC hDC;
Alexandre Julliard2787be81995-05-22 18:23:01 +000068
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000069 if( hComboBmp ) return TRUE;
Alexandre Julliarda3960291999-02-26 11:11:13 +000070 if( (hDC = CreateCompatibleDC(0)) )
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +000071 {
Alexandre Julliarda3960291999-02-26 11:11:13 +000072 BOOL bRet = FALSE;
73 if( (hComboBmp = LoadBitmapA(0, MAKEINTRESOURCEA(OBM_COMBO))) )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000074 {
Alexandre Julliarda3960291999-02-26 11:11:13 +000075 BITMAP bm;
76 HBITMAP hPrevB;
77 RECT r;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +000078
Alexandre Julliarda3960291999-02-26 11:11:13 +000079 GetObjectA( hComboBmp, sizeof(bm), &bm );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000080 CBitHeight = bm.bmHeight;
81 CBitWidth = bm.bmWidth;
82
Alexandre Julliard9fe7a251999-05-14 08:17:14 +000083 TRACE("combo bitmap [%i,%i]\n", CBitWidth, CBitHeight );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000084
85 hPrevB = SelectObject16( hDC, hComboBmp);
Alexandre Julliarda3960291999-02-26 11:11:13 +000086 SetRect( &r, 0, 0, CBitWidth, CBitHeight );
87 InvertRect( hDC, &r );
88 SelectObject( hDC, hPrevB );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000089 bRet = TRUE;
90 }
Alexandre Julliarda3960291999-02-26 11:11:13 +000091 DeleteDC( hDC );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000092 return bRet;
Alexandre Julliard2787be81995-05-22 18:23:01 +000093 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000094 return FALSE;
95}
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +000096
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000097/***********************************************************************
98 * COMBO_NCCreate
99 */
100static LRESULT COMBO_NCCreate(WND* wnd, LPARAM lParam)
101{
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000102 LPHEADCOMBO lphc;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000103
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000104 if ( wnd && COMBO_Init() &&
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000105 (lphc = HeapAlloc(GetProcessHeap(), 0, sizeof(HEADCOMBO))) )
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000106 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000107 LPCREATESTRUCTA lpcs = (CREATESTRUCTA*)lParam;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000108
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000109 memset( lphc, 0, sizeof(HEADCOMBO) );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000110 *(LPHEADCOMBO*)wnd->wExtra = lphc;
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +0000111
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000112 /* some braindead apps do try to use scrollbar/border flags */
113
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000114 lphc->dwStyle = (lpcs->style & ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL));
115 wnd->dwStyle &= ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000116
Francis Beaudetf585c611999-04-02 10:37:42 +0000117 /*
118 * We also have to remove the client edge style to make sure
119 * we don't end-up with a non client area.
120 */
121 wnd->dwExStyle &= ~(WS_EX_CLIENTEDGE);
122
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000123 if( !(lpcs->style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) )
124 lphc->dwStyle |= CBS_HASSTRINGS;
125 if( !(wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) )
126 lphc->wState |= CBF_NOTIFY;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000127
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000128 TRACE("[0x%08x], style = %08x\n",
Alexandre Julliarda3960291999-02-26 11:11:13 +0000129 (UINT)lphc, lphc->dwStyle );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000130
Alexandre Julliarda3960291999-02-26 11:11:13 +0000131 return (LRESULT)(UINT)wnd->hwndSelf;
Alexandre Julliard670cdc41997-08-24 16:00:30 +0000132 }
133 return (LRESULT)FALSE;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000134}
135
136/***********************************************************************
137 * COMBO_NCDestroy
138 */
139static LRESULT COMBO_NCDestroy( LPHEADCOMBO lphc )
140{
141
142 if( lphc )
143 {
144 WND* wnd = lphc->self;
145
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000146 TRACE("[%04x]: freeing storage\n", CB_HWND(lphc));
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000147
148 if( (CB_GETTYPE(lphc) != CBS_SIMPLE) && lphc->hWndLBox )
Alexandre Julliarda3960291999-02-26 11:11:13 +0000149 DestroyWindow( lphc->hWndLBox );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000150
151 HeapFree( GetProcessHeap(), 0, lphc );
152 wnd->wExtra[0] = 0;
153 }
Alexandre Julliard1285c2f1996-05-06 16:06:24 +0000154 return 0;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000155}
156
Alex Korobkaf172d641998-10-14 18:40:35 +0000157/***********************************************************************
Francis Beaudetf585c611999-04-02 10:37:42 +0000158 * CBGetTextAreaHeight
159 *
160 * This method will calculate the height of the text area of the
161 * combobox.
162 * The height of the text area is set in two ways.
163 * It can be set explicitely through a combobox message of through a
164 * WM_MEASUREITEM callback.
165 * If this is not the case, the height is set to 13 dialog units.
166 * This height was determined through experimentation.
167 */
168static INT CBGetTextAreaHeight(
169 HWND hwnd,
170 LPHEADCOMBO lphc)
171{
172 INT iTextItemHeight;
Alex Korobkaf172d641998-10-14 18:40:35 +0000173
Francis Beaudetf585c611999-04-02 10:37:42 +0000174 if( lphc->editHeight ) /* explicitly set height */
175 {
176 iTextItemHeight = lphc->editHeight;
177 }
178 else
179 {
180 TEXTMETRICA tm;
181 HDC hDC = GetDC(hwnd);
182 HFONT hPrevFont = 0;
183 INT baseUnitY;
184
185 if (lphc->hFont)
186 hPrevFont = SelectObject( hDC, lphc->hFont );
187
188 GetTextMetricsA(hDC, &tm);
189
190 baseUnitY = tm.tmHeight;
191
192 if( hPrevFont )
193 SelectObject( hDC, hPrevFont );
194
195 ReleaseDC(hwnd, hDC);
196
197 iTextItemHeight = ((13 * baseUnitY) / 8);
Alex Korobkaf172d641998-10-14 18:40:35 +0000198
Francis Beaudetf585c611999-04-02 10:37:42 +0000199 /*
200 * This "formula" calculates the height of the complete control.
201 * To calculate the height of the text area, we have to remove the
202 * borders.
203 */
204 iTextItemHeight -= 2*COMBO_YBORDERSIZE();
205 }
206
207 /*
208 * Check the ownerdraw case if we haven't asked the parent the size
209 * of the item yet.
210 */
211 if ( CB_OWNERDRAWN(lphc) &&
212 (lphc->wState & CBF_MEASUREITEM) )
213 {
214 MEASUREITEMSTRUCT measureItem;
215 RECT clientRect;
216 INT originalItemHeight = iTextItemHeight;
217
218 /*
219 * We use the client rect for the width of the item.
220 */
221 GetClientRect(hwnd, &clientRect);
222
223 lphc->wState &= ~CBF_MEASUREITEM;
224
225 /*
226 * Send a first one to measure the size of the text area
227 */
228 measureItem.CtlType = ODT_COMBOBOX;
229 measureItem.CtlID = lphc->self->wIDmenu;
230 measureItem.itemID = -1;
231 measureItem.itemWidth = clientRect.right;
232 measureItem.itemHeight = iTextItemHeight - 6; /* ownerdrawn cb is taller */
233 measureItem.itemData = 0;
234 SendMessageA(lphc->owner, WM_MEASUREITEM,
235 (WPARAM)measureItem.CtlID, (LPARAM)&measureItem);
236 iTextItemHeight = 6 + measureItem.itemHeight;
Alex Korobkaf172d641998-10-14 18:40:35 +0000237
Francis Beaudetf585c611999-04-02 10:37:42 +0000238 /*
239 * Send a second one in the case of a fixed ownerdraw list to calculate the
240 * size of the list items. (we basically do this on behalf of the listbox)
241 */
242 if (lphc->dwStyle & CBS_OWNERDRAWFIXED)
243 {
244 measureItem.CtlType = ODT_COMBOBOX;
245 measureItem.CtlID = lphc->self->wIDmenu;
246 measureItem.itemID = 0;
247 measureItem.itemWidth = clientRect.right;
248 measureItem.itemHeight = originalItemHeight;
249 measureItem.itemData = 0;
250 SendMessageA(lphc->owner, WM_MEASUREITEM,
251 (WPARAM)measureItem.CtlID, (LPARAM)&measureItem);
252 lphc->fixedOwnerDrawHeight = measureItem.itemHeight;
253 }
254
255 /*
256 * Keep the size for the next time
257 */
258 lphc->editHeight = iTextItemHeight;
259 }
260
261 return iTextItemHeight;
Alex Korobkaf172d641998-10-14 18:40:35 +0000262}
263
Jim Astonaebda221999-11-07 21:04:57 +0000264/***********************************************************************
265 * CBForceDummyResize
266 *
267 * The dummy resize is used for listboxes that have a popup to trigger
268 * a re-arranging of the contents of the combobox and the recalculation
269 * of the size of the "real" control window.
270 */
271static void CBForceDummyResize(
272 LPHEADCOMBO lphc)
273{
274 RECT windowRect;
275 int newComboHeight;
276
277 newComboHeight = CBGetTextAreaHeight(CB_HWND(lphc),lphc) + 2*COMBO_YBORDERSIZE();
278
279 GetWindowRect(CB_HWND(lphc), &windowRect);
280
281 /*
282 * We have to be careful, resizing a combobox also has the meaning that the
283 * dropped rect will be resized. In this case, we want to trigger a resize
284 * to recalculate layout but we don't want to change the dropped rectangle
285 * So, we pass the height of text area of control as the height.
286 * this will cancel-out in the processing of the WM_WINDOWPOSCHANGING
287 * message.
288 */
289 SetWindowPos( CB_HWND(lphc),
290 (HWND)NULL,
291 0, 0,
292 windowRect.right - windowRect.left,
293 newComboHeight,
294 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
295}
Alexandre Julliarda0d77311998-09-13 16:32:00 +0000296
Alexandre Julliard2787be81995-05-22 18:23:01 +0000297/***********************************************************************
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000298 * CBCalcPlacement
299 *
300 * Set up component coordinates given valid lphc->RectCombo.
Alexandre Julliard2787be81995-05-22 18:23:01 +0000301 */
Francis Beaudetf585c611999-04-02 10:37:42 +0000302static void CBCalcPlacement(
303 HWND hwnd,
304 LPHEADCOMBO lphc,
305 LPRECT lprEdit,
306 LPRECT lprButton,
307 LPRECT lprLB)
Alexandre Julliard2787be81995-05-22 18:23:01 +0000308{
Francis Beaudetf585c611999-04-02 10:37:42 +0000309 /*
310 * Again, start with the client rectangle.
311 */
312 GetClientRect(hwnd, lprEdit);
Alexandre Julliard2787be81995-05-22 18:23:01 +0000313
Francis Beaudetf585c611999-04-02 10:37:42 +0000314 /*
315 * Remove the borders
316 */
317 InflateRect(lprEdit, -COMBO_XBORDERSIZE(), -COMBO_YBORDERSIZE());
Alexandre Julliard2787be81995-05-22 18:23:01 +0000318
Francis Beaudetf585c611999-04-02 10:37:42 +0000319 /*
320 * Chop off the bottom part to fit with the height of the text area.
321 */
322 lprEdit->bottom = lprEdit->top + CBGetTextAreaHeight(hwnd, lphc);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000323
Francis Beaudetf585c611999-04-02 10:37:42 +0000324 /*
325 * The button starts the same vertical position as the text area.
326 */
327 CopyRect(lprButton, lprEdit);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000328
Francis Beaudetf585c611999-04-02 10:37:42 +0000329 /*
330 * If the combobox is "simple" there is no button.
331 */
332 if( CB_GETTYPE(lphc) == CBS_SIMPLE )
333 lprButton->left = lprButton->right = lprButton->bottom = 0;
334 else
335 {
336 /*
337 * Let's assume the combobox button is the same width as the
338 * scrollbar button.
339 * size the button horizontally and cut-off the text area.
340 */
341 lprButton->left = lprButton->right - GetSystemMetrics(SM_CXVSCROLL);
342 lprEdit->right = lprButton->left;
343 }
344
345 /*
346 * In the case of a dropdown, there is an additional spacing between the
347 * text area and the button.
348 */
349 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
350 {
351 lprEdit->right -= COMBO_EDITBUTTONSPACE();
352 }
Alex Korobkaf172d641998-10-14 18:40:35 +0000353
Francis Beaudetf585c611999-04-02 10:37:42 +0000354 /*
355 * If we have an edit control, we space it away from the borders slightly.
356 */
357 if (CB_GETTYPE(lphc) != CBS_DROPDOWNLIST)
358 {
359 InflateRect(lprEdit, -EDIT_CONTROL_PADDING(), -EDIT_CONTROL_PADDING());
360 }
361
362 /*
363 * Adjust the size of the listbox popup.
364 */
365 if( CB_GETTYPE(lphc) == CBS_SIMPLE )
366 {
367 /*
368 * Use the client rectangle to initialize the listbox rectangle
369 */
370 GetClientRect(hwnd, lprLB);
Alex Korobkaf172d641998-10-14 18:40:35 +0000371
Francis Beaudetf585c611999-04-02 10:37:42 +0000372 /*
373 * Then, chop-off the top part.
374 */
375 lprLB->top = lprEdit->bottom + COMBO_YBORDERSIZE();
376 }
377 else
378 {
379 /*
380 * Make sure the dropped width is as large as the combobox itself.
381 */
382 if (lphc->droppedWidth < (lprButton->right + COMBO_XBORDERSIZE()))
383 {
384 lprLB->right = lprLB->left + (lprButton->right + COMBO_XBORDERSIZE());
Alex Korobkaf172d641998-10-14 18:40:35 +0000385
Francis Beaudetf585c611999-04-02 10:37:42 +0000386 /*
387 * In the case of a dropdown, the popup listbox is offset to the right.
388 * so, we want to make sure it's flush with the right side of the
389 * combobox
390 */
391 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
392 lprLB->right -= COMBO_EDITBUTTONSPACE();
393 }
394 else
Alexandre Julliard54c27111998-03-29 19:44:57 +0000395 lprLB->right = lprLB->left + lphc->droppedWidth;
Francis Beaudetf585c611999-04-02 10:37:42 +0000396 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000397
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000398 TRACE("\ttext\t= (%i,%i-%i,%i)\n",
Francis Beaudetf585c611999-04-02 10:37:42 +0000399 lprEdit->left, lprEdit->top, lprEdit->right, lprEdit->bottom);
400
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000401 TRACE("\tbutton\t= (%i,%i-%i,%i)\n",
Francis Beaudetf585c611999-04-02 10:37:42 +0000402 lprButton->left, lprButton->top, lprButton->right, lprButton->bottom);
403
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000404 TRACE("\tlbox\t= (%i,%i-%i,%i)\n",
Francis Beaudetf585c611999-04-02 10:37:42 +0000405 lprLB->left, lprLB->top, lprLB->right, lprLB->bottom );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000406}
407
408/***********************************************************************
Francis Beaudetf585c611999-04-02 10:37:42 +0000409 * CBGetDroppedControlRect
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000410 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000411static void CBGetDroppedControlRect( LPHEADCOMBO lphc, LPRECT lpRect)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000412{
Francois Boisvert3b876e41999-05-14 18:37:28 +0000413 /* In windows, CB_GETDROPPEDCONTROLRECT returns the upper left corner
414 of the combo box and the lower right corner of the listbox */
415
416 GetWindowRect(lphc->self->hwndSelf, lpRect);
417
418 lpRect->right = lpRect->left + lphc->droppedRect.right - lphc->droppedRect.left;
419 lpRect->bottom = lpRect->top + lphc->droppedRect.bottom - lphc->droppedRect.top;
420
Francis Beaudetf585c611999-04-02 10:37:42 +0000421}
422
423/***********************************************************************
424 * COMBO_WindowPosChanging
425 */
426static LRESULT COMBO_WindowPosChanging(
427 HWND hwnd,
428 LPHEADCOMBO lphc,
429 WINDOWPOS* posChanging)
430{
431 /*
432 * We need to override the WM_WINDOWPOSCHANGING method to handle all
433 * the non-simple comboboxes. The problem is that those controls are
434 * always the same height. We have to make sure they are not resized
435 * to another value.
436 */
Francis Beaudetab6f8611999-04-22 09:08:09 +0000437 if ( ( CB_GETTYPE(lphc) != CBS_SIMPLE ) &&
438 ((posChanging->flags & SWP_NOSIZE) == 0) )
Francis Beaudetf585c611999-04-02 10:37:42 +0000439 {
Francis Beaudetab6f8611999-04-22 09:08:09 +0000440 int newComboHeight;
441
442 newComboHeight = CBGetTextAreaHeight(hwnd,lphc) +
Francis Beaudetf585c611999-04-02 10:37:42 +0000443 2*COMBO_YBORDERSIZE();
Francis Beaudetab6f8611999-04-22 09:08:09 +0000444
445 /*
446 * Resizing a combobox has another side effect, it resizes the dropped
447 * rectangle as well. However, it does it only if the new height for the
448 * combobox is different than the height it should have. In other words,
449 * if the application resizing the combobox only had the intention to resize
450 * the actual control, for example, to do the layout of a dialog that is
451 * resized, the height of the dropdown is not changed.
452 */
453 if (posChanging->cy != newComboHeight)
454 {
455 lphc->droppedRect.bottom = lphc->droppedRect.top + posChanging->cy - newComboHeight;
456
457 posChanging->cy = newComboHeight;
458 }
Francis Beaudetf585c611999-04-02 10:37:42 +0000459 }
460
461 return 0;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000462}
463
464/***********************************************************************
465 * COMBO_Create
466 */
467static LRESULT COMBO_Create( LPHEADCOMBO lphc, WND* wnd, LPARAM lParam)
468{
469 static char clbName[] = "ComboLBox";
470 static char editName[] = "Edit";
471
Alexandre Julliarda3960291999-02-26 11:11:13 +0000472 LPCREATESTRUCTA lpcs = (CREATESTRUCTA*)lParam;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000473
474 if( !CB_GETTYPE(lphc) ) lphc->dwStyle |= CBS_SIMPLE;
David Grant8a922132000-05-30 17:48:33 +0000475 if( CB_GETTYPE(lphc) != CBS_DROPDOWNLIST ) lphc->wState |= CBF_EDIT;
476
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000477 lphc->self = wnd;
478 lphc->owner = lpcs->hwndParent;
479
Francis Beaudetf585c611999-04-02 10:37:42 +0000480 /*
481 * The item height and dropped width are not set when the control
482 * is created.
483 */
484 lphc->droppedWidth = lphc->editHeight = 0;
485
486 /*
487 * The first time we go through, we want to measure the ownerdraw item
488 */
489 lphc->wState |= CBF_MEASUREITEM;
490
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000491 /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */
492
493 if( lphc->owner || !(lpcs->style & WS_VISIBLE) )
494 {
Francis Beaudetbc0b0201999-07-30 17:57:45 +0000495 UINT lbeStyle = 0;
496 UINT lbeExStyle = 0;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000497
Francis Beaudetf585c611999-04-02 10:37:42 +0000498 /*
499 * Initialize the dropped rect to the size of the client area of the
500 * control and then, force all the areas of the combobox to be
501 * recalculated.
502 */
503 GetClientRect( wnd->hwndSelf, &lphc->droppedRect );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000504
Francis Beaudetf585c611999-04-02 10:37:42 +0000505 CBCalcPlacement(wnd->hwndSelf,
506 lphc,
507 &lphc->textRect,
508 &lphc->buttonRect,
509 &lphc->droppedRect );
510
511 /*
512 * Adjust the position of the popup listbox if it's necessary
513 */
514 if ( CB_GETTYPE(lphc) != CBS_SIMPLE )
515 {
516 lphc->droppedRect.top = lphc->textRect.bottom + COMBO_YBORDERSIZE();
517
518 /*
519 * If it's a dropdown, the listbox is offset
520 */
521 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
522 lphc->droppedRect.left += COMBO_EDITBUTTONSPACE();
523
524 ClientToScreen(wnd->hwndSelf, (LPPOINT)&lphc->droppedRect);
525 ClientToScreen(wnd->hwndSelf, (LPPOINT)&lphc->droppedRect.right);
526 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000527
528 /* create listbox popup */
529
Serge Ivanov9926d332000-06-07 03:48:02 +0000530 lbeStyle = (LBS_NOTIFY | WS_BORDER | WS_CLIPSIBLINGS | WS_CHILD) |
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000531 (lpcs->style & (WS_VSCROLL | CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE));
532
533 if( lphc->dwStyle & CBS_SORT )
534 lbeStyle |= LBS_SORT;
535 if( lphc->dwStyle & CBS_HASSTRINGS )
536 lbeStyle |= LBS_HASSTRINGS;
537 if( lphc->dwStyle & CBS_NOINTEGRALHEIGHT )
538 lbeStyle |= LBS_NOINTEGRALHEIGHT;
539 if( lphc->dwStyle & CBS_DISABLENOSCROLL )
540 lbeStyle |= LBS_DISABLENOSCROLL;
541
542 if( CB_GETTYPE(lphc) == CBS_SIMPLE ) /* child listbox */
Francis Beaudetbc0b0201999-07-30 17:57:45 +0000543 {
Serge Ivanov9926d332000-06-07 03:48:02 +0000544 lbeStyle |= WS_VISIBLE;
Francis Beaudetbc0b0201999-07-30 17:57:45 +0000545
546 /*
547 * In win 95 look n feel, the listbox in the simple combobox has
548 * the WS_EXCLIENTEDGE style instead of the WS_BORDER style.
549 */
550 if (TWEAK_WineLook > WIN31_LOOK)
551 {
552 lbeStyle &= ~WS_BORDER;
553 lbeExStyle |= WS_EX_CLIENTEDGE;
554 }
555 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000556
Francis Beaudetbc0b0201999-07-30 17:57:45 +0000557 lphc->hWndLBox = CreateWindowExA(lbeExStyle,
Francis Beaudetf585c611999-04-02 10:37:42 +0000558 clbName,
559 NULL,
560 lbeStyle,
561 lphc->droppedRect.left,
562 lphc->droppedRect.top,
563 lphc->droppedRect.right - lphc->droppedRect.left,
564 lphc->droppedRect.bottom - lphc->droppedRect.top,
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +0000565 lphc->self->hwndSelf,
Serge Ivanov9926d332000-06-07 03:48:02 +0000566 (HMENU)ID_CB_LISTBOX,
Francis Beaudetf585c611999-04-02 10:37:42 +0000567 lphc->self->hInstance,
568 (LPVOID)lphc );
569
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000570 if( lphc->hWndLBox )
571 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000572 BOOL bEdit = TRUE;
Serge Ivanov9926d332000-06-07 03:48:02 +0000573 lbeStyle = WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | ES_LEFT | ES_COMBO;
Francis Beaudetf585c611999-04-02 10:37:42 +0000574
575 /*
576 * In Win95 look, the border fo the edit control is
577 * provided by the combobox
578 */
579 if (TWEAK_WineLook == WIN31_LOOK)
580 lbeStyle |= WS_BORDER;
581
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000582 if( lphc->wState & CBF_EDIT )
583 {
584 if( lphc->dwStyle & CBS_OEMCONVERT )
585 lbeStyle |= ES_OEMCONVERT;
586 if( lphc->dwStyle & CBS_AUTOHSCROLL )
587 lbeStyle |= ES_AUTOHSCROLL;
588 if( lphc->dwStyle & CBS_LOWERCASE )
589 lbeStyle |= ES_LOWERCASE;
590 else if( lphc->dwStyle & CBS_UPPERCASE )
591 lbeStyle |= ES_UPPERCASE;
Francis Beaudetf585c611999-04-02 10:37:42 +0000592
593 lphc->hWndEdit = CreateWindowExA(0,
594 editName,
595 NULL,
596 lbeStyle,
597 lphc->textRect.left, lphc->textRect.top,
598 lphc->textRect.right - lphc->textRect.left,
599 lphc->textRect.bottom - lphc->textRect.top,
600 lphc->self->hwndSelf,
601 (HMENU)ID_CB_EDIT,
602 lphc->self->hInstance,
603 NULL );
604
605 if( !lphc->hWndEdit )
606 bEdit = FALSE;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000607 }
608
609 if( bEdit )
610 {
Francis Beaudetf585c611999-04-02 10:37:42 +0000611 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
612 {
Serge Ivanov9926d332000-06-07 03:48:02 +0000613 /* Now do the trick with parent */
614 SetParent(lphc->hWndLBox, HWND_DESKTOP);
615 /*
616 * If the combo is a dropdown, we must resize the control to fit only
617 * the text area and button. To do this, we send a dummy resize and the
618 * WM_WINDOWPOSCHANGING message will take care of setting the height for
619 * us.
620 */
Francis Beaudetab6f8611999-04-22 09:08:09 +0000621 CBForceDummyResize(lphc);
Francis Beaudetf585c611999-04-02 10:37:42 +0000622 }
623
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000624 TRACE("init done\n");
Francis Beaudetf585c611999-04-02 10:37:42 +0000625 return wnd->hwndSelf;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000626 }
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000627 ERR("edit control failure.\n");
628 } else ERR("listbox failure.\n");
629 } else ERR("no owner for visible combo.\n");
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000630
631 /* CreateWindow() will send WM_NCDESTROY to cleanup */
632
633 return -1;
634}
635
636/***********************************************************************
637 * CBPaintButton
638 *
639 * Paint combo button (normal, pressed, and disabled states).
640 */
Francis Beaudetf585c611999-04-02 10:37:42 +0000641static void CBPaintButton(
642 LPHEADCOMBO lphc,
643 HDC hdc,
644 RECT rectButton)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000645{
Francis Beaudetf585c611999-04-02 10:37:42 +0000646 if( lphc->wState & CBF_NOREDRAW )
647 return;
Alexandre Julliarde658d821997-11-30 17:45:40 +0000648
Francis Beaudet28d2ccb1999-08-14 15:51:49 +0000649 if (TWEAK_WineLook == WIN31_LOOK)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000650 {
Francis Beaudet28d2ccb1999-08-14 15:51:49 +0000651 UINT x, y;
652 BOOL bBool;
653 HDC hMemDC;
654 HBRUSH hPrevBrush;
655 COLORREF oldTextColor, oldBkColor;
656
657
658 hPrevBrush = SelectObject(hdc, GetSysColorBrush(COLOR_BTNFACE));
659
660 /*
661 * Draw the button background
662 */
663 PatBlt( hdc,
664 rectButton.left,
665 rectButton.top,
666 rectButton.right-rectButton.left,
667 rectButton.bottom-rectButton.top,
668 PATCOPY );
669
670 if( (bBool = lphc->wState & CBF_BUTTONDOWN) )
671 {
672 DrawEdge( hdc, &rectButton, EDGE_SUNKEN, BF_RECT );
673 }
674 else
675 {
676 DrawEdge( hdc, &rectButton, EDGE_RAISED, BF_RECT );
677 }
678
679 /*
680 * Remove the edge of the button from the rectangle
681 * and calculate the position of the bitmap.
682 */
683 InflateRect( &rectButton, -2, -2);
684
685 x = (rectButton.left + rectButton.right - CBitWidth) >> 1;
686 y = (rectButton.top + rectButton.bottom - CBitHeight) >> 1;
687
688
689 hMemDC = CreateCompatibleDC( hdc );
690 SelectObject( hMemDC, hComboBmp );
691 oldTextColor = SetTextColor( hdc, GetSysColor(COLOR_BTNFACE) );
692 oldBkColor = SetBkColor( hdc, CB_DISABLED(lphc) ? RGB(128,128,128) :
693 RGB(0,0,0) );
694 BitBlt( hdc, x, y, CBitWidth, CBitHeight, hMemDC, 0, 0, SRCCOPY );
695 SetBkColor( hdc, oldBkColor );
696 SetTextColor( hdc, oldTextColor );
697 DeleteDC( hMemDC );
698 SelectObject( hdc, hPrevBrush );
Huw D M Davies2d617be1998-12-08 09:14:09 +0000699 }
Francis Beaudet28d2ccb1999-08-14 15:51:49 +0000700 else
701 {
702 UINT buttonState = DFCS_SCROLLCOMBOBOX;
Huw D M Davies2d617be1998-12-08 09:14:09 +0000703
Francis Beaudet28d2ccb1999-08-14 15:51:49 +0000704 if (lphc->wState & CBF_BUTTONDOWN)
705 {
706 buttonState |= DFCS_PUSHED;
707 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000708
Francis Beaudetf1328721999-09-19 14:09:52 +0000709 if (CB_DISABLED(lphc))
710 {
711 buttonState |= DFCS_INACTIVE;
712 }
713
714 DrawFrameControl(hdc,
Francis Beaudet28d2ccb1999-08-14 15:51:49 +0000715 &rectButton,
716 DFC_SCROLL,
717 buttonState);
718 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000719}
720
721/***********************************************************************
722 * CBPaintText
723 *
724 * Paint CBS_DROPDOWNLIST text field / update edit control contents.
725 */
Francis Beaudetf585c611999-04-02 10:37:42 +0000726static void CBPaintText(
727 LPHEADCOMBO lphc,
728 HDC hdc,
729 RECT rectEdit)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000730{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000731 INT id, size = 0;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000732 LPSTR pText = NULL;
733
Alexandre Julliard60ce85c1998-02-01 18:33:27 +0000734 if( lphc->wState & CBF_NOREDRAW ) return;
Alexandre Julliarde658d821997-11-30 17:45:40 +0000735
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000736 /* follow Windows combobox that sends a bunch of text
Alexandre Julliard84c70f51997-05-09 08:40:27 +0000737 * inquiries to its listbox while processing WM_PAINT. */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000738
Alexandre Julliarda3960291999-02-26 11:11:13 +0000739 if( (id = SendMessageA(lphc->hWndLBox, LB_GETCURSEL, 0, 0) ) != LB_ERR )
Alexandre Julliard84c70f51997-05-09 08:40:27 +0000740 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000741 size = SendMessageA( lphc->hWndLBox, LB_GETTEXTLEN, id, 0);
Alexandre Julliard84c70f51997-05-09 08:40:27 +0000742 if( (pText = HeapAlloc( GetProcessHeap(), 0, size + 1)) )
743 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000744 SendMessageA( lphc->hWndLBox, LB_GETTEXT, (WPARAM)id, (LPARAM)pText );
Alexandre Julliard84c70f51997-05-09 08:40:27 +0000745 pText[size] = '\0'; /* just in case */
746 } else return;
747 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000748
749 if( lphc->wState & CBF_EDIT )
750 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000751 if( CB_HASSTRINGS(lphc) ) SetWindowTextA( lphc->hWndEdit, pText ? pText : "" );
Alexandre Julliard84c70f51997-05-09 08:40:27 +0000752 if( lphc->wState & CBF_FOCUSED )
Alexandre Julliarda3960291999-02-26 11:11:13 +0000753 SendMessageA( lphc->hWndEdit, EM_SETSEL, 0, (LPARAM)(-1));
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000754 }
755 else /* paint text field ourselves */
756 {
Francis Beaudetf1328721999-09-19 14:09:52 +0000757 UINT itemState;
758 HFONT hPrevFont = (lphc->hFont) ? SelectObject(hdc, lphc->hFont) : 0;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000759
Francis Beaudetf1328721999-09-19 14:09:52 +0000760 /*
761 * Give ourselves some space.
762 */
763 InflateRect( &rectEdit, -1, -1 );
764
765 if ( (lphc->wState & CBF_FOCUSED) &&
766 !(lphc->wState & CBF_DROPPED) )
767 {
768 /* highlight */
769
770 FillRect( hdc, &rectEdit, GetSysColorBrush(COLOR_HIGHLIGHT) );
771 SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
772 SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
773 itemState = ODS_SELECTED | ODS_FOCUS;
774 }
775 else
776 itemState = 0;
777
778 if( CB_OWNERDRAWN(lphc) )
779 {
780 DRAWITEMSTRUCT dis;
781 HRGN clipRegion;
782
783 /*
784 * Save the current clip region.
785 * To retrieve the clip region, we need to create one "dummy"
786 * clip region.
787 */
788 clipRegion = CreateRectRgnIndirect(&rectEdit);
789
790 if (GetClipRgn(hdc, clipRegion)!=1)
791 {
792 DeleteObject(clipRegion);
793 clipRegion=(HRGN)NULL;
794 }
795
796 if ( lphc->self->dwStyle & WS_DISABLED )
797 itemState |= ODS_DISABLED;
798
799 dis.CtlType = ODT_COMBOBOX;
800 dis.CtlID = lphc->self->wIDmenu;
801 dis.hwndItem = lphc->self->hwndSelf;
802 dis.itemAction = ODA_DRAWENTIRE;
803 dis.itemID = id;
804 dis.itemState = itemState;
805 dis.hDC = hdc;
806 dis.rcItem = rectEdit;
807 dis.itemData = SendMessageA( lphc->hWndLBox, LB_GETITEMDATA,
808 (WPARAM)id, 0 );
809
810 /*
811 * Clip the DC and have the parent draw the item.
812 */
813 IntersectClipRect(hdc,
814 rectEdit.left, rectEdit.top,
815 rectEdit.right, rectEdit.bottom);
816
817 SendMessageA(lphc->owner, WM_DRAWITEM,
818 lphc->self->wIDmenu, (LPARAM)&dis );
819
820 /*
821 * Reset the clipping region.
822 */
823 SelectClipRgn(hdc, clipRegion);
824 }
825 else
826 {
827 ExtTextOutA( hdc,
828 rectEdit.left + 1,
829 rectEdit.top + 1,
830 ETO_OPAQUE | ETO_CLIPPED,
831 &rectEdit,
832 pText ? pText : "" , size, NULL );
833
834 if(lphc->wState & CBF_FOCUSED && !(lphc->wState & CBF_DROPPED))
835 DrawFocusRect( hdc, &rectEdit );
836 }
837
838 if( hPrevFont )
839 SelectObject(hdc, hPrevFont );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000840 }
David Luyer39413f81998-10-11 14:36:56 +0000841 if (pText)
842 HeapFree( GetProcessHeap(), 0, pText );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000843}
844
845/***********************************************************************
Francis Beaudetf585c611999-04-02 10:37:42 +0000846 * CBPaintBorder
847 */
848static void CBPaintBorder(
849 HWND hwnd,
850 LPHEADCOMBO lphc,
851 HDC hdc)
852{
853 RECT clientRect;
854
855 if (CB_GETTYPE(lphc) != CBS_SIMPLE)
856 {
857 GetClientRect(hwnd, &clientRect);
858 }
859 else
860 {
861 CopyRect(&clientRect, &lphc->textRect);
862
863 InflateRect(&clientRect, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
864 InflateRect(&clientRect, COMBO_XBORDERSIZE(), COMBO_YBORDERSIZE());
865 }
866
867 DrawEdge(hdc, &clientRect, EDGE_SUNKEN, BF_RECT);
868}
869
870/***********************************************************************
Francis Beaudetf1328721999-09-19 14:09:52 +0000871 * COMBO_PrepareColors
872 *
873 * This method will sent the appropriate WM_CTLCOLOR message to
874 * prepare and setup the colors for the combo's DC.
875 *
876 * It also returns the brush to use for the background.
877 */
878static HBRUSH COMBO_PrepareColors(
879 HWND hwnd,
880 LPHEADCOMBO lphc,
881 HDC hDC)
882{
883 HBRUSH hBkgBrush;
884
885 /*
886 * Get the background brush for this control.
887 */
888 if (CB_DISABLED(lphc))
889 {
890 hBkgBrush = SendMessageA( lphc->owner, WM_CTLCOLORSTATIC,
891 hDC, lphc->self->hwndSelf );
892
893 /*
894 * We have to change the text color since WM_CTLCOLORSTATIC will
895 * set it to the "enabled" color. This is the same behavior as the
896 * edit control
897 */
898 SetTextColor(hDC, GetSysColor(COLOR_GRAYTEXT));
899 }
900 else
901 {
902 if (lphc->wState & CBF_EDIT)
903 {
904 hBkgBrush = SendMessageA( lphc->owner, WM_CTLCOLOREDIT,
905 hDC, lphc->self->hwndSelf );
906 }
907 else
908 {
909 hBkgBrush = SendMessageA( lphc->owner, WM_CTLCOLORLISTBOX,
910 hDC, lphc->self->hwndSelf );
911 }
912 }
913
914 /*
915 * Catch errors.
916 */
917 if( !hBkgBrush )
918 hBkgBrush = GetSysColorBrush(COLOR_WINDOW);
919
920 return hBkgBrush;
921}
922
923/***********************************************************************
Francis Beaudetf585c611999-04-02 10:37:42 +0000924 * COMBO_EraseBackground
925 */
926static LRESULT COMBO_EraseBackground(
927 HWND hwnd,
928 LPHEADCOMBO lphc,
929 HDC hParamDC)
930{
931 HBRUSH hBkgBrush;
932 RECT clientRect;
933 HDC hDC;
934
935 hDC = (hParamDC) ? hParamDC
936 : GetDC(hwnd);
937
938 /*
939 * Calculate the area that we want to erase.
940 */
941 if (CB_GETTYPE(lphc) != CBS_SIMPLE)
942 {
943 GetClientRect(hwnd, &clientRect);
944 }
945 else
946 {
947 CopyRect(&clientRect, &lphc->textRect);
948
949 InflateRect(&clientRect, COMBO_XBORDERSIZE(), COMBO_YBORDERSIZE());
950 }
951
Francis Beaudetf1328721999-09-19 14:09:52 +0000952 /*
953 * Retrieve the background brush
954 */
955 hBkgBrush = COMBO_PrepareColors(hwnd, lphc, hDC);
Francis Beaudetf585c611999-04-02 10:37:42 +0000956
957 FillRect(hDC, &clientRect, hBkgBrush);
958
959 if (!hParamDC)
960 ReleaseDC(hwnd, hDC);
961
962 return TRUE;
963}
964
965/***********************************************************************
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000966 * COMBO_Paint
967 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000968static LRESULT COMBO_Paint(LPHEADCOMBO lphc, HDC hParamDC)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000969{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000970 PAINTSTRUCT ps;
971 HDC hDC;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000972
973 hDC = (hParamDC) ? hParamDC
Alexandre Julliarda3960291999-02-26 11:11:13 +0000974 : BeginPaint( lphc->self->hwndSelf, &ps);
Francis Beaudetf585c611999-04-02 10:37:42 +0000975
976
Alexandre Julliarde658d821997-11-30 17:45:40 +0000977 if( hDC && !(lphc->wState & CBF_NOREDRAW) )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000978 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000979 HBRUSH hPrevBrush, hBkgBrush;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000980
Francis Beaudetf1328721999-09-19 14:09:52 +0000981 /*
982 * Retrieve the background brush and select it in the
983 * DC.
984 */
985 hBkgBrush = COMBO_PrepareColors(lphc->self->hwndSelf, lphc, hDC);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000986
Alexandre Julliarda3960291999-02-26 11:11:13 +0000987 hPrevBrush = SelectObject( hDC, hBkgBrush );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000988
Francis Beaudetf585c611999-04-02 10:37:42 +0000989 /*
990 * In non 3.1 look, there is a sunken border on the combobox
991 */
992 if (TWEAK_WineLook != WIN31_LOOK)
993 {
994 CBPaintBorder(CB_HWND(lphc), lphc, hDC);
995 }
996
997 if( !IsRectEmpty(&lphc->buttonRect) )
998 {
999 CBPaintButton(lphc, hDC, lphc->buttonRect);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001000 }
1001
1002 if( !(lphc->wState & CBF_EDIT) )
1003 {
Francis Beaudetf585c611999-04-02 10:37:42 +00001004 /*
1005 * The text area has a border only in Win 3.1 look.
1006 */
1007 if (TWEAK_WineLook == WIN31_LOOK)
1008 {
1009 HPEN hPrevPen = SelectObject( hDC, GetSysColorPen(COLOR_WINDOWFRAME) );
Huw D M Davies2d617be1998-12-08 09:14:09 +00001010
Francis Beaudetf585c611999-04-02 10:37:42 +00001011 Rectangle( hDC,
1012 lphc->textRect.left, lphc->textRect.top,
1013 lphc->textRect.right - 1, lphc->textRect.bottom - 1);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001014
Alexandre Julliarda3960291999-02-26 11:11:13 +00001015 SelectObject( hDC, hPrevPen );
Francis Beaudetf585c611999-04-02 10:37:42 +00001016 }
1017
1018 CBPaintText( lphc, hDC, lphc->textRect);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001019 }
Francis Beaudetf585c611999-04-02 10:37:42 +00001020
1021 if( hPrevBrush )
1022 SelectObject( hDC, hPrevBrush );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001023 }
Francis Beaudetf585c611999-04-02 10:37:42 +00001024
1025 if( !hParamDC )
1026 EndPaint(lphc->self->hwndSelf, &ps);
1027
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001028 return 0;
1029}
1030
1031/***********************************************************************
1032 * CBUpdateLBox
1033 *
1034 * Select listbox entry according to the contents of the edit control.
1035 */
Serge Ivanov9926d332000-06-07 03:48:02 +00001036static INT CBUpdateLBox( LPHEADCOMBO lphc, BOOL bSelect )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001037{
Dmitry Timoshkov38d04b81999-12-06 00:57:20 +00001038 INT length, idx;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001039 LPSTR pText = NULL;
1040
Dmitry Timoshkov38d04b81999-12-06 00:57:20 +00001041 idx = LB_ERR;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001042 length = CB_GETEDITTEXTLENGTH( lphc );
1043
1044 if( length > 0 )
1045 pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1);
1046
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001047 TRACE("\t edit text length %i\n", length );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001048
1049 if( pText )
1050 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001051 if( length ) GetWindowTextA( lphc->hWndEdit, pText, length + 1);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001052 else pText[0] = '\0';
Alexandre Julliarda3960291999-02-26 11:11:13 +00001053 idx = SendMessageA( lphc->hWndLBox, LB_FINDSTRING,
1054 (WPARAM)(-1), (LPARAM)pText );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001055 HeapFree( GetProcessHeap(), 0, pText );
1056 }
1057
Serge Ivanov9926d332000-06-07 03:48:02 +00001058 SendMessageA( lphc->hWndLBox, LB_SETCURSEL, (WPARAM)(bSelect ? idx : -1), 0 );
1059
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001060 /* probably superfluous but Windows sends this too */
Serge Ivanov9926d332000-06-07 03:48:02 +00001061 SendMessageA( lphc->hWndLBox, LB_SETCARETINDEX, (WPARAM)(idx < 0 ? 0 : idx), 0 );
1062 SendMessageA( lphc->hWndLBox, LB_SETTOPINDEX, (WPARAM)(idx < 0 ? 0 : idx), 0 );
Dmitry Timoshkov38d04b81999-12-06 00:57:20 +00001063 return idx;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001064}
1065
1066/***********************************************************************
1067 * CBUpdateEdit
1068 *
1069 * Copy a listbox entry to the edit control.
1070 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001071static void CBUpdateEdit( LPHEADCOMBO lphc , INT index )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001072{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001073 INT length;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001074 LPSTR pText = NULL;
1075
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001076 TRACE("\t %i\n", index );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001077
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001078 if( index >= 0 ) /* got an entry */
1079 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001080 length = SendMessageA( lphc->hWndLBox, LB_GETTEXTLEN, (WPARAM)index, 0);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001081 if( length )
1082 {
1083 if( (pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1)) )
1084 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001085 SendMessageA( lphc->hWndLBox, LB_GETTEXT,
1086 (WPARAM)index, (LPARAM)pText );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001087 }
1088 }
1089 }
Dmitry Timoshkov38d04b81999-12-06 00:57:20 +00001090
Gerard Patelc9e60312000-06-18 17:20:37 +00001091 lphc->wState |= (CBF_NOEDITNOTIFY | CBF_NOLBSELECT);
Dmitry Timoshkov38d04b81999-12-06 00:57:20 +00001092 SendMessageA( lphc->hWndEdit, WM_SETTEXT, 0, pText ? (LPARAM)pText : (LPARAM)"" );
Gerard Patelc9e60312000-06-18 17:20:37 +00001093 lphc->wState &= ~(CBF_NOEDITNOTIFY | CBF_NOLBSELECT);
Dmitry Timoshkov38d04b81999-12-06 00:57:20 +00001094
David Grant8a922132000-05-30 17:48:33 +00001095 if( lphc->wState & CBF_FOCUSED )
1096 SendMessageA( lphc->hWndEdit, EM_SETSEL, 0, (LPARAM)(-1) );
1097
Dmitry Timoshkov38d04b81999-12-06 00:57:20 +00001098 if( pText )
1099 HeapFree( GetProcessHeap(), 0, pText );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001100}
1101
1102/***********************************************************************
1103 * CBDropDown
1104 *
1105 * Show listbox popup.
1106 */
1107static void CBDropDown( LPHEADCOMBO lphc )
1108{
Gerard Pateld2922342000-06-25 12:47:59 +00001109 RECT rect,r;
Abey George318832e1999-07-10 11:34:01 +00001110 int nItems = 0;
Serge Ivanov9926d332000-06-07 03:48:02 +00001111 int nDroppedHeight;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001112
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001113 TRACE("[%04x]: drop down\n", CB_HWND(lphc));
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001114
1115 CB_NOTIFY( lphc, CBN_DROPDOWN );
1116
1117 /* set selection */
1118
1119 lphc->wState |= CBF_DROPPED;
1120 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
1121 {
Serge Ivanov9926d332000-06-07 03:48:02 +00001122 lphc->droppedIndex = CBUpdateLBox( lphc, TRUE );
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00001123
1124 if( !(lphc->wState & CBF_CAPTURE) )
1125 CBUpdateEdit( lphc, lphc->droppedIndex );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001126 }
1127 else
1128 {
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00001129 lphc->droppedIndex = SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0 );
1130
Serge Ivanov9926d332000-06-07 03:48:02 +00001131 SendMessageA( lphc->hWndLBox, LB_SETTOPINDEX,
1132 (WPARAM)(lphc->droppedIndex == LB_ERR ? 0 : lphc->droppedIndex), 0 );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001133 SendMessageA( lphc->hWndLBox, LB_CARETON, 0, 0 );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001134 }
1135
1136 /* now set popup position */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001137 GetWindowRect( lphc->self->hwndSelf, &rect );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001138
Francis Beaudetf585c611999-04-02 10:37:42 +00001139 /*
1140 * If it's a dropdown, the listbox is offset
1141 */
1142 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
1143 rect.left += COMBO_EDITBUTTONSPACE();
1144
Abey George318832e1999-07-10 11:34:01 +00001145 /* if the dropped height is greater than the total height of the dropped
1146 items list, then force the drop down list height to be the total height
1147 of the items in the dropped list */
1148
Pierre Mageaua4335821999-09-05 12:12:30 +00001149 /* And Remove any extra space (Best Fit) */
Abey George318832e1999-07-10 11:34:01 +00001150 nDroppedHeight = lphc->droppedRect.bottom - lphc->droppedRect.top;
Gerard Pateld2922342000-06-25 12:47:59 +00001151 /* if listbox length has been set directly by its handle */
1152 GetWindowRect(lphc->hWndLBox, &r);
1153 if (nDroppedHeight < r.bottom - r.top)
1154 nDroppedHeight = r.bottom - r.top;
Abey George318832e1999-07-10 11:34:01 +00001155 nItems = (int)SendMessageA (lphc->hWndLBox, LB_GETCOUNT, 0, 0);
Serge Ivanov9926d332000-06-07 03:48:02 +00001156
1157 if (nItems > 0)
Abey George318832e1999-07-10 11:34:01 +00001158 {
Serge Ivanov9926d332000-06-07 03:48:02 +00001159 int nHeight;
Abey George318832e1999-07-10 11:34:01 +00001160
Serge Ivanov9926d332000-06-07 03:48:02 +00001161 nHeight = (int)SendMessageA (lphc->hWndLBox, LB_GETITEMHEIGHT, 0, 0);
1162 nHeight *= nItems;
1163
1164 if (nHeight < nDroppedHeight - COMBO_YBORDERSIZE())
1165 nDroppedHeight = nHeight + COMBO_YBORDERSIZE();
Pierre Mageaua4335821999-09-05 12:12:30 +00001166 }
Abey George318832e1999-07-10 11:34:01 +00001167
Serge Ivanov9926d332000-06-07 03:48:02 +00001168 /*If height of dropped rectangle gets beyond a screen size it should go up, otherwise down.*/
1169 if( (rect.bottom + nDroppedHeight) >= GetSystemMetrics( SM_CYSCREEN ) )
1170 rect.bottom = rect.top - nDroppedHeight;
Abey George318832e1999-07-10 11:34:01 +00001171
Francis Beaudetf585c611999-04-02 10:37:42 +00001172 SetWindowPos( lphc->hWndLBox, HWND_TOP, rect.left, rect.bottom,
Francis Beaudetab6f8611999-04-22 09:08:09 +00001173 lphc->droppedRect.right - lphc->droppedRect.left,
Serge Ivanov9926d332000-06-07 03:48:02 +00001174 nDroppedHeight,
1175 SWP_NOACTIVATE | SWP_SHOWWINDOW);
1176
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001177
Alexandre Julliarde658d821997-11-30 17:45:40 +00001178 if( !(lphc->wState & CBF_NOREDRAW) )
Francis Beaudetf585c611999-04-02 10:37:42 +00001179 RedrawWindow( lphc->self->hwndSelf, NULL, 0, RDW_INVALIDATE |
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001180 RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
Francis Beaudetf585c611999-04-02 10:37:42 +00001181
Alexandre Julliarddcc175d2000-05-30 15:28:06 +00001182 EnableWindow( lphc->hWndLBox, TRUE );
Serge Ivanov9926d332000-06-07 03:48:02 +00001183 if (GetCapture() != lphc->self->hwndSelf)
1184 SetCapture(lphc->hWndLBox);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001185}
1186
1187/***********************************************************************
1188 * CBRollUp
1189 *
1190 * Hide listbox popup.
1191 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001192static void CBRollUp( LPHEADCOMBO lphc, BOOL ok, BOOL bButton )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001193{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001194 HWND hWnd = lphc->self->hwndSelf;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001195
1196 CB_NOTIFY( lphc, (ok) ? CBN_SELENDOK : CBN_SELENDCANCEL );
1197
Alexandre Julliarda3960291999-02-26 11:11:13 +00001198 if( IsWindow( hWnd ) && CB_GETTYPE(lphc) != CBS_SIMPLE )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001199 {
1200
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001201 TRACE("[%04x]: roll up [%i]\n", CB_HWND(lphc), (INT)ok );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001202
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001203 if( lphc->wState & CBF_DROPPED )
1204 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001205 RECT rect;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001206
1207 lphc->wState &= ~CBF_DROPPED;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001208 ShowWindow( lphc->hWndLBox, SW_HIDE );
Pierre Mageau25c62cc1999-09-11 16:26:03 +00001209 if(GetCapture() == lphc->hWndLBox)
1210 {
1211 ReleaseCapture();
1212 }
1213
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001214 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
1215 {
Francis Beaudetf585c611999-04-02 10:37:42 +00001216 rect = lphc->buttonRect;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001217 }
1218 else
1219 {
1220 if( bButton )
Francis Beaudetf585c611999-04-02 10:37:42 +00001221 {
1222 UnionRect( &rect,
1223 &lphc->buttonRect,
1224 &lphc->textRect);
1225 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001226 else
Francis Beaudetf585c611999-04-02 10:37:42 +00001227 rect = lphc->textRect;
1228
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001229 bButton = TRUE;
1230 }
1231
Alexandre Julliarde658d821997-11-30 17:45:40 +00001232 if( bButton && !(lphc->wState & CBF_NOREDRAW) )
Alexandre Julliarda3960291999-02-26 11:11:13 +00001233 RedrawWindow( hWnd, &rect, 0, RDW_INVALIDATE |
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001234 RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
1235 CB_NOTIFY( lphc, CBN_CLOSEUP );
1236 }
1237 }
1238}
1239
1240/***********************************************************************
1241 * COMBO_FlipListbox
1242 *
1243 * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
1244 */
Serge Ivanov9926d332000-06-07 03:48:02 +00001245BOOL COMBO_FlipListbox( LPHEADCOMBO lphc, BOOL ok, BOOL bRedrawButton )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001246{
1247 if( lphc->wState & CBF_DROPPED )
1248 {
Serge Ivanov9926d332000-06-07 03:48:02 +00001249 CBRollUp( lphc, ok, bRedrawButton );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001250 return FALSE;
1251 }
1252
1253 CBDropDown( lphc );
1254 return TRUE;
1255}
1256
1257/***********************************************************************
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001258 * CBRepaintButton
Alexandre Julliardf1aa3031996-08-05 17:42:43 +00001259 */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001260static void CBRepaintButton( LPHEADCOMBO lphc )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001261 {
Francis Beaudetf585c611999-04-02 10:37:42 +00001262 InvalidateRect(CB_HWND(lphc), &lphc->buttonRect, TRUE);
1263 UpdateWindow(CB_HWND(lphc));
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001264}
1265
1266/***********************************************************************
1267 * COMBO_SetFocus
1268 */
1269static void COMBO_SetFocus( LPHEADCOMBO lphc )
1270{
1271 if( !(lphc->wState & CBF_FOCUSED) )
1272 {
1273 if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
Alexandre Julliarda3960291999-02-26 11:11:13 +00001274 SendMessageA( lphc->hWndLBox, LB_CARETON, 0, 0 );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001275
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001276 lphc->wState |= CBF_FOCUSED;
Dmitry Timoshkovcd207581999-12-12 20:47:45 +00001277
Francis Beaudetf585c611999-04-02 10:37:42 +00001278 if( !(lphc->wState & CBF_EDIT) )
Francis Beaudetf585c611999-04-02 10:37:42 +00001279 InvalidateRect(CB_HWND(lphc), &lphc->textRect, TRUE);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001280
1281 CB_NOTIFY( lphc, CBN_SETFOCUS );
1282 }
1283}
1284
1285/***********************************************************************
1286 * COMBO_KillFocus
1287 */
1288static void COMBO_KillFocus( LPHEADCOMBO lphc )
1289{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001290 HWND hWnd = lphc->self->hwndSelf;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001291
1292 if( lphc->wState & CBF_FOCUSED )
1293 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001294 CBRollUp( lphc, FALSE, TRUE );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001295 if( IsWindow( hWnd ) )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001296 {
1297 if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
Alexandre Julliarda3960291999-02-26 11:11:13 +00001298 SendMessageA( lphc->hWndLBox, LB_CARETOFF, 0, 0 );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001299
1300 lphc->wState &= ~CBF_FOCUSED;
1301
1302 /* redraw text */
Dmitry Timoshkovcd207581999-12-12 20:47:45 +00001303 if( !(lphc->wState & CBF_EDIT) )
Francis Beaudetf585c611999-04-02 10:37:42 +00001304 InvalidateRect(CB_HWND(lphc), &lphc->textRect, TRUE);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001305
1306 CB_NOTIFY( lphc, CBN_KILLFOCUS );
1307 }
1308 }
1309}
1310
1311/***********************************************************************
1312 * COMBO_Command
1313 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001314static LRESULT COMBO_Command( LPHEADCOMBO lphc, WPARAM wParam, HWND hWnd )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001315{
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00001316 if ( lphc->wState & CBF_EDIT && lphc->hWndEdit == hWnd )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001317 {
1318 /* ">> 8" makes gcc generate jump-table instead of cmp ladder */
1319
1320 switch( HIWORD(wParam) >> 8 )
1321 {
1322 case (EN_SETFOCUS >> 8):
1323
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001324 TRACE("[%04x]: edit [%04x] got focus\n",
Alexandre Julliard54c27111998-03-29 19:44:57 +00001325 CB_HWND(lphc), lphc->hWndEdit );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001326
Dmitry Timoshkovcd207581999-12-12 20:47:45 +00001327 COMBO_SetFocus( lphc );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001328 break;
1329
1330 case (EN_KILLFOCUS >> 8):
1331
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001332 TRACE("[%04x]: edit [%04x] lost focus\n",
Alexandre Julliard54c27111998-03-29 19:44:57 +00001333 CB_HWND(lphc), lphc->hWndEdit );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001334
1335 /* NOTE: it seems that Windows' edit control sends an
1336 * undocumented message WM_USER + 0x1B instead of this
1337 * notification (only when it happens to be a part of
1338 * the combo). ?? - AK.
1339 */
1340
1341 COMBO_KillFocus( lphc );
1342 break;
1343
1344
1345 case (EN_CHANGE >> 8):
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00001346 /*
1347 * In some circumstances (when the selection of the combobox
1348 * is changed for example) we don't wans the EN_CHANGE notification
1349 * to be forwarded to the parent of the combobox. This code
1350 * checks a flag that is set in these occasions and ignores the
1351 * notification.
1352 */
Huw D M Davies2e340302000-03-24 19:44:39 +00001353 if (!(lphc->wState & CBF_NOEDITNOTIFY))
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00001354 CB_NOTIFY( lphc, CBN_EDITCHANGE );
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00001355
David Grant8a922132000-05-30 17:48:33 +00001356 if (lphc->wState & CBF_NOLBSELECT)
1357 {
1358 lphc->wState &= ~CBF_NOLBSELECT;
1359 }
1360 else
1361 {
Serge Ivanov9926d332000-06-07 03:48:02 +00001362 CBUpdateLBox( lphc, lphc->wState & CBF_DROPPED );
David Grant8a922132000-05-30 17:48:33 +00001363 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001364 break;
1365
1366 case (EN_UPDATE >> 8):
Huw D M Davies2e340302000-03-24 19:44:39 +00001367 if (!(lphc->wState & CBF_NOEDITNOTIFY))
1368 CB_NOTIFY( lphc, CBN_EDITUPDATE );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001369 break;
1370
1371 case (EN_ERRSPACE >> 8):
1372 CB_NOTIFY( lphc, CBN_ERRSPACE );
1373 }
1374 }
1375 else if( lphc->hWndLBox == hWnd )
1376 {
1377 switch( HIWORD(wParam) )
1378 {
1379 case LBN_ERRSPACE:
1380 CB_NOTIFY( lphc, CBN_ERRSPACE );
1381 break;
1382
1383 case LBN_DBLCLK:
1384 CB_NOTIFY( lphc, CBN_DBLCLK );
1385 break;
1386
1387 case LBN_SELCHANGE:
1388 case LBN_SELCANCEL:
1389
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001390 TRACE("[%04x]: lbox selection change [%04x]\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001391 CB_HWND(lphc), lphc->wState );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001392
1393 /* do not roll up if selection is being tracked
1394 * by arrowkeys in the dropdown listbox */
1395
David Grant8a922132000-05-30 17:48:33 +00001396 if( (lphc->dwStyle & CBS_SIMPLE) ||
1397 ((lphc->wState & CBF_DROPPED) && !(lphc->wState & CBF_NOROLLUP)) )
1398 {
1399 CBRollUp( lphc, (HIWORD(wParam) == LBN_SELCHANGE), TRUE );
1400 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001401 else lphc->wState &= ~CBF_NOROLLUP;
1402
1403 CB_NOTIFY( lphc, CBN_SELCHANGE );
Serge Ivanov9926d332000-06-07 03:48:02 +00001404
1405 if( HIWORD(wParam) == LBN_SELCHANGE)
1406 {
1407 if( lphc->wState & CBF_EDIT )
1408 {
1409 INT index = SendMessageA(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
1410 lphc->wState |= CBF_NOLBSELECT;
1411 CBUpdateEdit( lphc, index );
1412 /* select text in edit, as Windows does */
1413 SendMessageA( lphc->hWndEdit, EM_SETSEL, 0, (LPARAM)(-1) );
1414 }
1415 else
1416 InvalidateRect(CB_HWND(lphc), &lphc->textRect, TRUE);
1417 }
1418
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001419 /* fall through */
1420
1421 case LBN_SETFOCUS:
1422 case LBN_KILLFOCUS:
1423 /* nothing to do here since ComboLBox always resets the focus to its
1424 * combo/edit counterpart */
Alexandre Julliard3db94ef1997-09-28 17:43:24 +00001425 break;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001426 }
1427 }
1428 return 0;
1429}
1430
1431/***********************************************************************
1432 * COMBO_ItemOp
1433 *
1434 * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
1435 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001436static LRESULT COMBO_ItemOp( LPHEADCOMBO lphc, UINT msg,
1437 WPARAM wParam, LPARAM lParam )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001438{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001439 HWND hWnd = lphc->self->hwndSelf;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001440
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001441 TRACE("[%04x]: ownerdraw op %04x\n", CB_HWND(lphc), msg );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001442
Alexandre Julliarda3960291999-02-26 11:11:13 +00001443#define lpIS ((LPDELETEITEMSTRUCT)lParam)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001444
1445 /* two first items are the same in all 4 structs */
1446 lpIS->CtlType = ODT_COMBOBOX;
1447 lpIS->CtlID = lphc->self->wIDmenu;
1448
1449 switch( msg ) /* patch window handle */
1450 {
1451 case WM_DELETEITEM:
1452 lpIS->hwndItem = hWnd;
1453#undef lpIS
1454 break;
1455 case WM_DRAWITEM:
Alexandre Julliarda3960291999-02-26 11:11:13 +00001456#define lpIS ((LPDRAWITEMSTRUCT)lParam)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001457 lpIS->hwndItem = hWnd;
1458#undef lpIS
1459 break;
1460 case WM_COMPAREITEM:
Alexandre Julliarda3960291999-02-26 11:11:13 +00001461#define lpIS ((LPCOMPAREITEMSTRUCT)lParam)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001462 lpIS->hwndItem = hWnd;
1463#undef lpIS
1464 break;
1465 }
1466
Alexandre Julliarda3960291999-02-26 11:11:13 +00001467 return SendMessageA( lphc->owner, msg, lphc->self->wIDmenu, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001468}
1469
1470/***********************************************************************
1471 * COMBO_GetText
1472 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001473static LRESULT COMBO_GetText( LPHEADCOMBO lphc, UINT N, LPSTR lpText)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001474{
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001475 if( lphc->wState & CBF_EDIT )
Alexandre Julliarda3960291999-02-26 11:11:13 +00001476 return SendMessageA( lphc->hWndEdit, WM_GETTEXT,
1477 (WPARAM)N, (LPARAM)lpText );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001478
1479 /* get it from the listbox */
1480
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001481 if( lphc->hWndLBox )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001482 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001483 INT idx = SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0 );
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001484 if( idx != LB_ERR )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001485 {
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001486 LPSTR lpBuffer;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001487 INT length = SendMessageA( lphc->hWndLBox, LB_GETTEXTLEN,
1488 (WPARAM)idx, 0 );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001489
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001490 /* 'length' is without the terminating character */
1491 if( length >= N )
1492 lpBuffer = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1 );
1493 else
1494 lpBuffer = lpText;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001495
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001496 if( lpBuffer )
1497 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001498 INT n = SendMessageA( lphc->hWndLBox, LB_GETTEXT,
1499 (WPARAM)idx, (LPARAM)lpBuffer );
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001500
1501 /* truncate if buffer is too short */
1502
1503 if( length >= N )
1504 {
Marcus Meissner21777c51998-11-22 15:41:00 +00001505 if (N && lpText) {
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001506 if( n != LB_ERR ) memcpy( lpText, lpBuffer, (N>n) ? n+1 : N-1 );
1507 lpText[N - 1] = '\0';
Marcus Meissner21777c51998-11-22 15:41:00 +00001508 }
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00001509 HeapFree( GetProcessHeap(), 0, lpBuffer );
1510 }
1511 return (LRESULT)n;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001512 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001513 }
1514 }
1515 return 0;
Alexandre Julliardf1aa3031996-08-05 17:42:43 +00001516}
1517
1518
1519/***********************************************************************
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001520 * CBResetPos
1521 *
1522 * This function sets window positions according to the updated
1523 * component placement struct.
Alexandre Julliardf1aa3031996-08-05 17:42:43 +00001524 */
Francis Beaudetf585c611999-04-02 10:37:42 +00001525static void CBResetPos(
1526 LPHEADCOMBO lphc,
1527 LPRECT rectEdit,
1528 LPRECT rectLB,
1529 BOOL bRedraw)
Alexandre Julliardf1aa3031996-08-05 17:42:43 +00001530{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001531 BOOL bDrop = (CB_GETTYPE(lphc) != CBS_SIMPLE);
Alexandre Julliardf1aa3031996-08-05 17:42:43 +00001532
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001533 /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
1534 * sizing messages */
1535
1536 if( lphc->wState & CBF_EDIT )
Francis Beaudetf585c611999-04-02 10:37:42 +00001537 SetWindowPos( lphc->hWndEdit, 0,
1538 rectEdit->left, rectEdit->top,
1539 rectEdit->right - rectEdit->left,
1540 rectEdit->bottom - rectEdit->top,
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001541 SWP_NOZORDER | SWP_NOACTIVATE | ((bDrop) ? SWP_NOREDRAW : 0) );
1542
Francis Beaudetf585c611999-04-02 10:37:42 +00001543 SetWindowPos( lphc->hWndLBox, 0,
1544 rectLB->left, rectLB->top,
1545 rectLB->right - rectLB->left,
1546 rectLB->bottom - rectLB->top,
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001547 SWP_NOACTIVATE | SWP_NOZORDER | ((bDrop) ? SWP_NOREDRAW : 0) );
1548
1549 if( bDrop )
1550 {
1551 if( lphc->wState & CBF_DROPPED )
1552 {
1553 lphc->wState &= ~CBF_DROPPED;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001554 ShowWindow( lphc->hWndLBox, SW_HIDE );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001555 }
1556
Alexandre Julliarde658d821997-11-30 17:45:40 +00001557 if( bRedraw && !(lphc->wState & CBF_NOREDRAW) )
Alexandre Julliarda3960291999-02-26 11:11:13 +00001558 RedrawWindow( lphc->self->hwndSelf, NULL, 0,
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001559 RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
1560 }
1561}
1562
1563
1564/***********************************************************************
1565 * COMBO_Size
1566 */
1567static void COMBO_Size( LPHEADCOMBO lphc )
Alex Korobkaf172d641998-10-14 18:40:35 +00001568 {
Francis Beaudetf585c611999-04-02 10:37:42 +00001569 CBCalcPlacement(lphc->self->hwndSelf,
1570 lphc,
1571 &lphc->textRect,
1572 &lphc->buttonRect,
1573 &lphc->droppedRect);
Pascal Lessarde69fcc01999-03-24 14:59:37 +00001574
Francis Beaudetf585c611999-04-02 10:37:42 +00001575 CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001576}
1577
1578
1579/***********************************************************************
1580 * COMBO_Font
1581 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001582static void COMBO_Font( LPHEADCOMBO lphc, HFONT hFont, BOOL bRedraw )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001583{
Francis Beaudetf585c611999-04-02 10:37:42 +00001584 /*
1585 * Set the font
1586 */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001587 lphc->hFont = hFont;
1588
Francis Beaudetf585c611999-04-02 10:37:42 +00001589 /*
1590 * Propagate to owned windows.
1591 */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001592 if( lphc->wState & CBF_EDIT )
Alexandre Julliarda3960291999-02-26 11:11:13 +00001593 SendMessageA( lphc->hWndEdit, WM_SETFONT, (WPARAM)hFont, bRedraw );
1594 SendMessageA( lphc->hWndLBox, WM_SETFONT, (WPARAM)hFont, bRedraw );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001595
Francis Beaudetf585c611999-04-02 10:37:42 +00001596 /*
1597 * Redo the layout of the control.
1598 */
1599 if ( CB_GETTYPE(lphc) == CBS_SIMPLE)
1600 {
1601 CBCalcPlacement(lphc->self->hwndSelf,
1602 lphc,
1603 &lphc->textRect,
1604 &lphc->buttonRect,
1605 &lphc->droppedRect);
1606
1607 CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
1608 }
1609 else
1610 {
Francis Beaudetab6f8611999-04-22 09:08:09 +00001611 CBForceDummyResize(lphc);
Francis Beaudetf585c611999-04-02 10:37:42 +00001612 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001613}
1614
1615
1616/***********************************************************************
1617 * COMBO_SetItemHeight
1618 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001619static LRESULT COMBO_SetItemHeight( LPHEADCOMBO lphc, INT index, INT height )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001620{
1621 LRESULT lRet = CB_ERR;
1622
1623 if( index == -1 ) /* set text field height */
1624 {
1625 if( height < 32768 )
1626 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001627 lphc->editHeight = height;
Francis Beaudetf585c611999-04-02 10:37:42 +00001628
1629 /*
1630 * Redo the layout of the control.
1631 */
1632 if ( CB_GETTYPE(lphc) == CBS_SIMPLE)
1633 {
1634 CBCalcPlacement(lphc->self->hwndSelf,
1635 lphc,
1636 &lphc->textRect,
1637 &lphc->buttonRect,
1638 &lphc->droppedRect);
1639
1640 CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
1641 }
1642 else
1643 {
Francis Beaudetab6f8611999-04-22 09:08:09 +00001644 CBForceDummyResize(lphc);
Francis Beaudetf585c611999-04-02 10:37:42 +00001645 }
1646
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001647 lRet = height;
1648 }
1649 }
1650 else if ( CB_OWNERDRAWN(lphc) ) /* set listbox item height */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001651 lRet = SendMessageA( lphc->hWndLBox, LB_SETITEMHEIGHT,
1652 (WPARAM)index, (LPARAM)height );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001653 return lRet;
Alexandre Julliardf1aa3031996-08-05 17:42:43 +00001654}
1655
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001656/***********************************************************************
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001657 * COMBO_SelectString
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001658 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001659static LRESULT COMBO_SelectString( LPHEADCOMBO lphc, INT start, LPCSTR pText )
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001660{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001661 INT index = SendMessageA( lphc->hWndLBox, LB_SELECTSTRING,
1662 (WPARAM)start, (LPARAM)pText );
Alex Korobkaf172d641998-10-14 18:40:35 +00001663 if( index >= 0 )
1664 {
Francis Beaudetf585c611999-04-02 10:37:42 +00001665 if( lphc->wState & CBF_EDIT )
1666 CBUpdateEdit( lphc, index );
1667 else
1668 {
1669 InvalidateRect(CB_HWND(lphc), &lphc->textRect, TRUE);
1670 }
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00001671 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001672 return (LRESULT)index;
Alexandre Julliard75d86e11996-11-17 18:59:11 +00001673}
Alexandre Julliardf1aa3031996-08-05 17:42:43 +00001674
1675/***********************************************************************
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001676 * COMBO_LButtonDown
1677 */
1678static void COMBO_LButtonDown( LPHEADCOMBO lphc, LPARAM lParam )
1679{
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00001680 POINT pt;
Francis Beaudetf585c611999-04-02 10:37:42 +00001681 BOOL bButton;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001682 HWND hWnd = lphc->self->hwndSelf;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001683
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00001684 pt.x = LOWORD(lParam);
1685 pt.y = HIWORD(lParam);
Francis Beaudetf585c611999-04-02 10:37:42 +00001686 bButton = PtInRect(&lphc->buttonRect, pt);
1687
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001688 if( (CB_GETTYPE(lphc) == CBS_DROPDOWNLIST) ||
1689 (bButton && (CB_GETTYPE(lphc) == CBS_DROPDOWN)) )
1690 {
1691 lphc->wState |= CBF_BUTTONDOWN;
1692 if( lphc->wState & CBF_DROPPED )
1693 {
1694 /* got a click to cancel selection */
1695
Pavel Roskin6d40d1b1999-03-12 17:00:13 +00001696 lphc->wState &= ~CBF_BUTTONDOWN;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001697 CBRollUp( lphc, TRUE, FALSE );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001698 if( !IsWindow( hWnd ) ) return;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001699
1700 if( lphc->wState & CBF_CAPTURE )
1701 {
1702 lphc->wState &= ~CBF_CAPTURE;
1703 ReleaseCapture();
1704 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001705 }
1706 else
1707 {
1708 /* drop down the listbox and start tracking */
1709
1710 lphc->wState |= CBF_CAPTURE;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001711 SetCapture( hWnd );
Serge Ivanov9926d332000-06-07 03:48:02 +00001712 CBDropDown( lphc );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001713 }
1714 if( bButton ) CBRepaintButton( lphc );
1715 }
1716}
1717
1718/***********************************************************************
1719 * COMBO_LButtonUp
1720 *
1721 * Release capture and stop tracking if needed.
1722 */
1723static void COMBO_LButtonUp( LPHEADCOMBO lphc, LPARAM lParam )
1724{
1725 if( lphc->wState & CBF_CAPTURE )
1726 {
1727 lphc->wState &= ~CBF_CAPTURE;
1728 if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
1729 {
Serge Ivanov9926d332000-06-07 03:48:02 +00001730 INT index = CBUpdateLBox( lphc, TRUE );
1731 lphc->wState |= CBF_NOLBSELECT;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001732 CBUpdateEdit( lphc, index );
Serge Ivanov9926d332000-06-07 03:48:02 +00001733 lphc->wState &= ~CBF_NOLBSELECT;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001734 }
1735 ReleaseCapture();
Pierre Mageau25c62cc1999-09-11 16:26:03 +00001736 SetCapture(lphc->hWndLBox);
1737
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001738 }
1739
1740 if( lphc->wState & CBF_BUTTONDOWN )
1741 {
1742 lphc->wState &= ~CBF_BUTTONDOWN;
1743 CBRepaintButton( lphc );
1744 }
1745}
1746
1747/***********************************************************************
1748 * COMBO_MouseMove
1749 *
1750 * Two things to do - track combo button and release capture when
1751 * pointer goes into the listbox.
1752 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001753static void COMBO_MouseMove( LPHEADCOMBO lphc, WPARAM wParam, LPARAM lParam )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001754{
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00001755 POINT pt;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001756 RECT lbRect;
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00001757
1758 pt.x = LOWORD(lParam);
1759 pt.y = HIWORD(lParam);
1760
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001761 if( lphc->wState & CBF_BUTTONDOWN )
1762 {
Francis Beaudetf585c611999-04-02 10:37:42 +00001763 BOOL bButton;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001764
Francis Beaudetf585c611999-04-02 10:37:42 +00001765 bButton = PtInRect(&lphc->buttonRect, pt);
1766
1767 if( !bButton )
1768 {
1769 lphc->wState &= ~CBF_BUTTONDOWN;
1770 CBRepaintButton( lphc );
1771 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001772 }
1773
Alexandre Julliarda3960291999-02-26 11:11:13 +00001774 GetClientRect( lphc->hWndLBox, &lbRect );
1775 MapWindowPoints( lphc->self->hwndSelf, lphc->hWndLBox, &pt, 1 );
1776 if( PtInRect(&lbRect, pt) )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001777 {
1778 lphc->wState &= ~CBF_CAPTURE;
1779 ReleaseCapture();
Serge Ivanov9926d332000-06-07 03:48:02 +00001780 if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) CBUpdateLBox( lphc, TRUE );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001781
1782 /* hand over pointer tracking */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001783 SendMessageA( lphc->hWndLBox, WM_LBUTTONDOWN, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001784 }
1785}
1786
1787
1788/***********************************************************************
Marcus Meissner9aded511999-05-01 10:23:45 +00001789 * ComboWndProc_locked
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001790 *
1791 * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/ctrl/src/combobox_15.htm
Alexandre Julliard0e607781993-11-03 19:23:37 +00001792 */
Marcus Meissner9aded511999-05-01 10:23:45 +00001793static inline LRESULT WINAPI ComboWndProc_locked( WND* pWnd, UINT message,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001794 WPARAM wParam, LPARAM lParam )
Alexandre Julliard2787be81995-05-22 18:23:01 +00001795{
Marcus Meissner9aded511999-05-01 10:23:45 +00001796 if( pWnd ) {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001797 LPHEADCOMBO lphc = CB_GETPTR(pWnd);
Marcus Meissner9aded511999-05-01 10:23:45 +00001798 HWND hwnd = pWnd->hwndSelf;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001799
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001800 TRACE("[%04x]: msg %s wp %08x lp %08lx\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001801 pWnd->hwndSelf, SPY_GetMsgName(message), wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001802
1803 if( lphc || message == WM_NCCREATE )
1804 switch(message)
1805 {
1806
1807 /* System messages */
1808
1809 case WM_NCCREATE:
Marcus Meissner9aded511999-05-01 10:23:45 +00001810 return COMBO_NCCreate(pWnd, lParam);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001811 case WM_NCDESTROY:
1812 COMBO_NCDestroy(lphc);
Marcus Meissner9aded511999-05-01 10:23:45 +00001813 break;/* -> DefWindowProc */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001814
1815 case WM_CREATE:
Marcus Meissner9aded511999-05-01 10:23:45 +00001816 return COMBO_Create(lphc, pWnd, lParam);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001817
Francis Beaudetf585c611999-04-02 10:37:42 +00001818 case WM_PRINTCLIENT:
1819 if (lParam & PRF_ERASEBKGND)
1820 COMBO_EraseBackground(hwnd, lphc, wParam);
1821
1822 /* Fallthrough */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001823 case WM_PAINT:
1824 /* wParam may contain a valid HDC! */
Marcus Meissner9aded511999-05-01 10:23:45 +00001825 return COMBO_Paint(lphc, wParam);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001826 case WM_ERASEBKGND:
Marcus Meissner9aded511999-05-01 10:23:45 +00001827 return COMBO_EraseBackground(hwnd, lphc, wParam);
Serge Ivanov9926d332000-06-07 03:48:02 +00001828 case WM_GETDLGCODE:
1829 {
1830 LRESULT result = DLGC_WANTARROWS | DLGC_WANTCHARS;
1831 if (lParam && (((LPMSG)lParam)->message == WM_KEYDOWN))
1832 {
1833 int vk = (int)((LPMSG)lParam)->wParam;
1834
1835 if ((vk == VK_RETURN || vk == VK_ESCAPE) && (lphc->wState & CBF_DROPPED))
1836 result |= DLGC_WANTMESSAGE;
1837 }
1838 return result;
1839 }
1840 case WM_WINDOWPOSCHANGING:
Marcus Meissner9aded511999-05-01 10:23:45 +00001841 return COMBO_WindowPosChanging(hwnd, lphc, (LPWINDOWPOS)lParam);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001842 case WM_SIZE:
1843 if( lphc->hWndLBox &&
1844 !(lphc->wState & CBF_NORESIZE) ) COMBO_Size( lphc );
Marcus Meissner9aded511999-05-01 10:23:45 +00001845 return TRUE;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001846 case WM_SETFONT:
Alexandre Julliarda3960291999-02-26 11:11:13 +00001847 COMBO_Font( lphc, (HFONT16)wParam, (BOOL)lParam );
Marcus Meissner9aded511999-05-01 10:23:45 +00001848 return TRUE;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001849 case WM_GETFONT:
Marcus Meissner9aded511999-05-01 10:23:45 +00001850 return (LRESULT)lphc->hFont;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001851 case WM_SETFOCUS:
1852 if( lphc->wState & CBF_EDIT )
Alexandre Julliarda3960291999-02-26 11:11:13 +00001853 SetFocus( lphc->hWndEdit );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001854 else
1855 COMBO_SetFocus( lphc );
Marcus Meissner9aded511999-05-01 10:23:45 +00001856 return TRUE;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001857 case WM_KILLFOCUS:
1858#define hwndFocus ((HWND16)wParam)
1859 if( !hwndFocus ||
1860 (hwndFocus != lphc->hWndEdit && hwndFocus != lphc->hWndLBox ))
1861 COMBO_KillFocus( lphc );
1862#undef hwndFocus
Marcus Meissner9aded511999-05-01 10:23:45 +00001863 return TRUE;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001864 case WM_COMMAND:
Marcus Meissner9aded511999-05-01 10:23:45 +00001865 return COMBO_Command( lphc, wParam, (HWND)lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001866 case WM_GETTEXT:
Marcus Meissner9aded511999-05-01 10:23:45 +00001867 return COMBO_GetText( lphc, (UINT)wParam, (LPSTR)lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001868 case WM_SETTEXT:
1869 case WM_GETTEXTLENGTH:
1870 case WM_CLEAR:
1871 case WM_CUT:
1872 case WM_PASTE:
1873 case WM_COPY:
Gerard Patel8c362541999-10-13 13:50:17 +00001874 if ((message == WM_GETTEXTLENGTH) && !ISWIN31 && !(lphc->wState & CBF_EDIT))
1875 {
1876 int j = SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0 );
1877 if (j == -1) return 0;
1878 return SendMessageA( lphc->hWndLBox, LB_GETTEXTLEN, j, 0);
1879 }
1880 else if( lphc->wState & CBF_EDIT )
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00001881 {
Huw D M Davies2e340302000-03-24 19:44:39 +00001882 LRESULT ret;
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00001883 lphc->wState |= CBF_NOEDITNOTIFY;
Huw D M Davies2e340302000-03-24 19:44:39 +00001884 ret = SendMessageA( lphc->hWndEdit, message, wParam, lParam );
1885 lphc->wState &= ~CBF_NOEDITNOTIFY;
1886 return ret;
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00001887 }
Gerard Patel8c362541999-10-13 13:50:17 +00001888 else return CB_ERR;
1889
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001890 case WM_DRAWITEM:
1891 case WM_DELETEITEM:
1892 case WM_COMPAREITEM:
1893 case WM_MEASUREITEM:
Marcus Meissner9aded511999-05-01 10:23:45 +00001894 return COMBO_ItemOp( lphc, message, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001895 case WM_ENABLE:
1896 if( lphc->wState & CBF_EDIT )
Alexandre Julliarda3960291999-02-26 11:11:13 +00001897 EnableWindow( lphc->hWndEdit, (BOOL)wParam );
1898 EnableWindow( lphc->hWndLBox, (BOOL)wParam );
Francis Beaudetf1328721999-09-19 14:09:52 +00001899
1900 /* Force the control to repaint when the enabled state changes. */
1901 InvalidateRect(CB_HWND(lphc), NULL, TRUE);
Marcus Meissner9aded511999-05-01 10:23:45 +00001902 return TRUE;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001903 case WM_SETREDRAW:
Alexandre Julliarde658d821997-11-30 17:45:40 +00001904 if( wParam )
1905 lphc->wState &= ~CBF_NOREDRAW;
1906 else
1907 lphc->wState |= CBF_NOREDRAW;
1908
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001909 if( lphc->wState & CBF_EDIT )
Alexandre Julliarda3960291999-02-26 11:11:13 +00001910 SendMessageA( lphc->hWndEdit, message, wParam, lParam );
1911 SendMessageA( lphc->hWndLBox, message, wParam, lParam );
Marcus Meissner9aded511999-05-01 10:23:45 +00001912 return 0;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001913 case WM_SYSKEYDOWN:
1914 if( KEYDATA_ALT & HIWORD(lParam) )
1915 if( wParam == VK_UP || wParam == VK_DOWN )
Serge Ivanov9926d332000-06-07 03:48:02 +00001916 COMBO_FlipListbox( lphc, FALSE, FALSE );
1917 return 0;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001918
1919 case WM_CHAR:
1920 case WM_KEYDOWN:
Serge Ivanov9926d332000-06-07 03:48:02 +00001921 if (((CHAR)wParam == VK_RETURN || (CHAR)wParam == VK_ESCAPE) &&
1922 (lphc->wState & CBF_DROPPED))
1923 {
1924 CBRollUp( lphc, (CHAR)wParam == VK_RETURN, FALSE );
1925 return TRUE;
1926 }
1927
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001928 if( lphc->wState & CBF_EDIT )
Marcus Meissner9aded511999-05-01 10:23:45 +00001929 return SendMessageA( lphc->hWndEdit, message, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001930 else
Marcus Meissner9aded511999-05-01 10:23:45 +00001931 return SendMessageA( lphc->hWndLBox, message, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001932 case WM_LBUTTONDOWN:
Alexandre Julliarda3960291999-02-26 11:11:13 +00001933 if( !(lphc->wState & CBF_FOCUSED) ) SetFocus( lphc->self->hwndSelf );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001934 if( lphc->wState & CBF_FOCUSED ) COMBO_LButtonDown( lphc, lParam );
Marcus Meissner9aded511999-05-01 10:23:45 +00001935 return TRUE;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001936 case WM_LBUTTONUP:
1937 COMBO_LButtonUp( lphc, lParam );
Marcus Meissner9aded511999-05-01 10:23:45 +00001938 return TRUE;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001939 case WM_MOUSEMOVE:
1940 if( lphc->wState & CBF_CAPTURE )
1941 COMBO_MouseMove( lphc, wParam, lParam );
Marcus Meissner9aded511999-05-01 10:23:45 +00001942 return TRUE;
Stephane Lussier4bdf4af2000-04-18 11:56:33 +00001943
1944 case WM_MOUSEWHEEL:
1945 if (wParam & (MK_SHIFT | MK_CONTROL))
1946 return DefWindowProcA( hwnd, message, wParam, lParam );
1947 if ((short) HIWORD(wParam) > 0) return SendMessageA(hwnd,WM_KEYDOWN,VK_UP,0);
1948 if ((short) HIWORD(wParam) < 0) return SendMessageA(hwnd,WM_KEYDOWN,VK_DOWN,0);
1949 return TRUE;
1950
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001951 /* Combo messages */
1952
1953 case CB_ADDSTRING16:
1954 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001955 case CB_ADDSTRING:
Marcus Meissner9aded511999-05-01 10:23:45 +00001956 return SendMessageA( lphc->hWndLBox, LB_ADDSTRING, 0, lParam);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001957 case CB_INSERTSTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00001958 wParam = (INT)(INT16)wParam;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001959 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001960 case CB_INSERTSTRING:
Marcus Meissner9aded511999-05-01 10:23:45 +00001961 return SendMessageA( lphc->hWndLBox, LB_INSERTSTRING, wParam, lParam);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001962 case CB_DELETESTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00001963 case CB_DELETESTRING:
Marcus Meissner9aded511999-05-01 10:23:45 +00001964 return SendMessageA( lphc->hWndLBox, LB_DELETESTRING, wParam, 0);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001965 case CB_SELECTSTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00001966 wParam = (INT)(INT16)wParam;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001967 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001968 case CB_SELECTSTRING:
Marcus Meissner9aded511999-05-01 10:23:45 +00001969 return COMBO_SelectString( lphc, (INT)wParam, (LPSTR)lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001970 case CB_FINDSTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00001971 wParam = (INT)(INT16)wParam;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001972 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001973 case CB_FINDSTRING:
Marcus Meissner9aded511999-05-01 10:23:45 +00001974 return SendMessageA( lphc->hWndLBox, LB_FINDSTRING, wParam, lParam);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001975 case CB_FINDSTRINGEXACT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00001976 wParam = (INT)(INT16)wParam;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001977 if( CB_HASSTRINGS(lphc) ) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001978 case CB_FINDSTRINGEXACT:
Marcus Meissner9aded511999-05-01 10:23:45 +00001979 return SendMessageA( lphc->hWndLBox, LB_FINDSTRINGEXACT,
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001980 wParam, lParam );
1981 case CB_SETITEMHEIGHT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00001982 wParam = (INT)(INT16)wParam; /* signed integer */
1983 case CB_SETITEMHEIGHT:
Marcus Meissner9aded511999-05-01 10:23:45 +00001984 return COMBO_SetItemHeight( lphc, (INT)wParam, (INT)lParam);
Alexandre Julliarda0d77311998-09-13 16:32:00 +00001985 case CB_GETITEMHEIGHT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00001986 wParam = (INT)(INT16)wParam;
1987 case CB_GETITEMHEIGHT:
1988 if( (INT)wParam >= 0 ) /* listbox item */
Marcus Meissner9aded511999-05-01 10:23:45 +00001989 return SendMessageA( lphc->hWndLBox, LB_GETITEMHEIGHT, wParam, 0);
1990 return CBGetTextAreaHeight(hwnd, lphc);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001991 case CB_RESETCONTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00001992 case CB_RESETCONTENT:
1993 SendMessageA( lphc->hWndLBox, LB_RESETCONTENT, 0, 0 );
Francis Beaudetf585c611999-04-02 10:37:42 +00001994 InvalidateRect(CB_HWND(lphc), NULL, TRUE);
Marcus Meissner9aded511999-05-01 10:23:45 +00001995 return TRUE;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001996 case CB_INITSTORAGE:
Marcus Meissner9aded511999-05-01 10:23:45 +00001997 return SendMessageA( lphc->hWndLBox, LB_INITSTORAGE, wParam, lParam);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001998 case CB_GETHORIZONTALEXTENT:
Marcus Meissner9aded511999-05-01 10:23:45 +00001999 return SendMessageA( lphc->hWndLBox, LB_GETHORIZONTALEXTENT, 0, 0);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002000 case CB_SETHORIZONTALEXTENT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002001 return SendMessageA( lphc->hWndLBox, LB_SETHORIZONTALEXTENT, wParam, 0);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002002 case CB_GETTOPINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002003 return SendMessageA( lphc->hWndLBox, LB_GETTOPINDEX, 0, 0);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002004 case CB_GETLOCALE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002005 return SendMessageA( lphc->hWndLBox, LB_GETLOCALE, 0, 0);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002006 case CB_SETLOCALE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002007 return SendMessageA( lphc->hWndLBox, LB_SETLOCALE, wParam, 0);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002008 case CB_GETDROPPEDWIDTH:
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002009 if( lphc->droppedWidth )
Marcus Meissner9aded511999-05-01 10:23:45 +00002010 return lphc->droppedWidth;
2011 return lphc->droppedRect.right - lphc->droppedRect.left;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002012 case CB_SETDROPPEDWIDTH:
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002013 if( (CB_GETTYPE(lphc) != CBS_SIMPLE) &&
Alexandre Julliarda3960291999-02-26 11:11:13 +00002014 (INT)wParam < 32768 ) lphc->droppedWidth = (INT)wParam;
Marcus Meissner9aded511999-05-01 10:23:45 +00002015 return CB_ERR;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002016 case CB_GETDROPPEDCONTROLRECT16:
2017 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
2018 if( lParam )
2019 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002020 RECT r;
2021 CBGetDroppedControlRect( lphc, &r );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002022 CONV_RECT32TO16( &r, (LPRECT16)lParam );
2023 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002024 return CB_OKAY;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002025 case CB_GETDROPPEDCONTROLRECT:
2026 if( lParam ) CBGetDroppedControlRect(lphc, (LPRECT)lParam );
Marcus Meissner9aded511999-05-01 10:23:45 +00002027 return CB_OKAY;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002028 case CB_GETDROPPEDSTATE16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002029 case CB_GETDROPPEDSTATE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002030 return (lphc->wState & CBF_DROPPED) ? TRUE : FALSE;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002031 case CB_DIR16:
2032 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
2033 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002034 case CB_DIR:
Marcus Meissner9aded511999-05-01 10:23:45 +00002035 return COMBO_Directory( lphc, (UINT)wParam,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002036 (LPSTR)lParam, (message == CB_DIR));
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002037 case CB_SHOWDROPDOWN16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002038 case CB_SHOWDROPDOWN:
Alex Korobkaf172d641998-10-14 18:40:35 +00002039 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
2040 {
2041 if( wParam )
2042 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002043 if( !(lphc->wState & CBF_DROPPED) )
2044 CBDropDown( lphc );
Alex Korobkaf172d641998-10-14 18:40:35 +00002045 }
2046 else
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002047 if( lphc->wState & CBF_DROPPED )
2048 CBRollUp( lphc, FALSE, TRUE );
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00002049 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002050 return TRUE;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002051 case CB_GETCOUNT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002052 case CB_GETCOUNT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002053 return SendMessageA( lphc->hWndLBox, LB_GETCOUNT, 0, 0);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002054 case CB_GETCURSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002055 case CB_GETCURSEL:
Marcus Meissner9aded511999-05-01 10:23:45 +00002056 return SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002057 case CB_SETCURSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002058 wParam = (INT)(INT16)wParam;
2059 case CB_SETCURSEL:
2060 lParam = SendMessageA( lphc->hWndLBox, LB_SETCURSEL, wParam, 0);
David Grant8a922132000-05-30 17:48:33 +00002061 if( lParam >= 0 )
2062 SendMessageA( lphc->hWndLBox, LB_SETTOPINDEX, wParam, 0);
2063 if( lphc->wState & CBF_SELCHANGE )
Alex Korobka311d3291999-01-01 18:40:02 +00002064 {
2065 /* no LBN_SELCHANGE in this case, update manually */
Dmitry Timoshkovf4a27b81999-11-28 19:45:58 +00002066 if( lphc->wState & CBF_EDIT )
2067 CBUpdateEdit( lphc, (INT)wParam );
2068 else
2069 InvalidateRect(CB_HWND(lphc), &lphc->textRect, TRUE);
Alex Korobka311d3291999-01-01 18:40:02 +00002070 lphc->wState &= ~CBF_SELCHANGE;
2071 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002072 return lParam;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002073 case CB_GETLBTEXT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002074 wParam = (INT)(INT16)wParam;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002075 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002076 case CB_GETLBTEXT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002077 return SendMessageA( lphc->hWndLBox, LB_GETTEXT, wParam, lParam);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002078 case CB_GETLBTEXTLEN16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002079 wParam = (INT)(INT16)wParam;
2080 case CB_GETLBTEXTLEN:
Marcus Meissner9aded511999-05-01 10:23:45 +00002081 return SendMessageA( lphc->hWndLBox, LB_GETTEXTLEN, wParam, 0);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002082 case CB_GETITEMDATA16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002083 wParam = (INT)(INT16)wParam;
2084 case CB_GETITEMDATA:
Marcus Meissner9aded511999-05-01 10:23:45 +00002085 return SendMessageA( lphc->hWndLBox, LB_GETITEMDATA, wParam, 0);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002086 case CB_SETITEMDATA16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002087 wParam = (INT)(INT16)wParam;
2088 case CB_SETITEMDATA:
Marcus Meissner9aded511999-05-01 10:23:45 +00002089 return SendMessageA( lphc->hWndLBox, LB_SETITEMDATA, wParam, lParam);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002090 case CB_GETEDITSEL16:
2091 wParam = lParam = 0; /* just in case */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002092 case CB_GETEDITSEL:
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002093 if( lphc->wState & CBF_EDIT )
2094 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002095 INT a, b;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002096
Marcus Meissner9aded511999-05-01 10:23:45 +00002097 return SendMessageA( lphc->hWndEdit, EM_GETSEL,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002098 (wParam) ? wParam : (WPARAM)&a,
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002099 (lParam) ? lParam : (LPARAM)&b );
2100 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002101 return CB_ERR;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002102 case CB_SETEDITSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002103 case CB_SETEDITSEL:
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002104 if( lphc->wState & CBF_EDIT )
Marcus Meissner9aded511999-05-01 10:23:45 +00002105 return SendMessageA( lphc->hWndEdit, EM_SETSEL,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002106 (INT)(INT16)LOWORD(lParam), (INT)(INT16)HIWORD(lParam) );
Marcus Meissner9aded511999-05-01 10:23:45 +00002107 return CB_ERR;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002108 case CB_SETEXTENDEDUI16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002109 case CB_SETEXTENDEDUI:
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002110 if( CB_GETTYPE(lphc) == CBS_SIMPLE )
Marcus Meissner9aded511999-05-01 10:23:45 +00002111 return CB_ERR;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002112 if( wParam )
2113 lphc->wState |= CBF_EUI;
2114 else lphc->wState &= ~CBF_EUI;
Marcus Meissner9aded511999-05-01 10:23:45 +00002115 return CB_OKAY;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002116 case CB_GETEXTENDEDUI16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002117 case CB_GETEXTENDEDUI:
Marcus Meissner9aded511999-05-01 10:23:45 +00002118 return (lphc->wState & CBF_EUI) ? TRUE : FALSE;
Dmitry Timoshkov92f376f1999-12-05 02:45:10 +00002119
2120 default:
2121 if (message >= WM_USER)
2122 WARN("unknown msg WM_USER+%04x wp=%04x lp=%08lx\n",
2123 message - WM_USER, wParam, lParam );
2124 break;
Alexandre Julliard0e607781993-11-03 19:23:37 +00002125 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002126 return DefWindowProcA(hwnd, message, wParam, lParam);
Alexandre Julliard2787be81995-05-22 18:23:01 +00002127 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002128 return CB_ERR;
2129}
2130
2131/***********************************************************************
2132 * ComboWndProc
2133 *
2134 * This is just a wrapper for the real ComboWndProc which locks/unlocks
2135 * window structs.
2136 */
2137LRESULT WINAPI ComboWndProc( HWND hwnd, UINT message,
2138 WPARAM wParam, LPARAM lParam )
2139{
2140 WND* pWnd = WIN_FindWndPtr(hwnd);
2141 LRESULT retvalue = ComboWndProc_locked(pWnd,message,wParam,lParam);
2142
2143
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002144 WIN_ReleaseWndPtr(pWnd);
2145 return retvalue;
Alexandre Julliard2787be81995-05-22 18:23:01 +00002146}
2147