blob: 9d034371346dbea19d829b6b052b0791e6092088 [file] [log] [blame]
Alexandre Julliard0e607781993-11-03 19:23:37 +00001/*
Alexandre Julliard2787be81995-05-22 18:23:01 +00002 * Listbox controls
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003 *
4 * Copyright 1996 Alexandre Julliard
Alexandre Julliard2787be81995-05-22 18:23:01 +00005 */
6
Alexandre Julliarde2abbb11995-03-19 17:39:39 +00007#include <string.h>
David Luyeree517e81999-02-28 12:27:56 +00008#include <stdlib.h>
Alex Korobka311d3291999-01-01 18:40:02 +00009#include "wine/winuser16.h"
10#include "winuser.h"
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000011#include "winerror.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000012#include "drive.h"
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +000013#include "heap.h"
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000014#include "spy.h"
15#include "win.h"
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000016#include "combo.h"
Alexandre Julliard06c275a1999-05-02 14:32:27 +000017#include "debugtools.h"
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +000018#include "tweak.h"
Alexandre Julliard0e607781993-11-03 19:23:37 +000019
Alexandre Julliard9fe7a251999-05-14 08:17:14 +000020DEFAULT_DEBUG_CHANNEL(listbox)
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000021DECLARE_DEBUG_CHANNEL(combo)
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000022
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000023/* Unimplemented yet:
24 * - LBS_NOSEL
25 * - LBS_USETABSTOPS
26 * - Unicode
27 * - Locale handling
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000028 */
Alexandre Julliarde2abbb11995-03-19 17:39:39 +000029
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000030/* Items array granularity */
31#define LB_ARRAY_GRANULARITY 16
Alexandre Julliard0e607781993-11-03 19:23:37 +000032
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000033/* Scrolling timeout in ms */
34#define LB_SCROLL_TIMEOUT 50
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000035
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000036/* Listbox system timer id */
37#define LB_TIMER_ID 2
Alexandre Julliardac9c9b01996-07-28 18:50:11 +000038
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000039/* Item structure */
40typedef struct
Alexandre Julliard2787be81995-05-22 18:23:01 +000041{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000042 LPSTR str; /* Item text */
Alexandre Julliarda3960291999-02-26 11:11:13 +000043 BOOL selected; /* Is item selected? */
44 UINT height; /* Item height (only for OWNERDRAWVARIABLE) */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000045 DWORD data; /* User data */
46} LB_ITEMDATA;
Alexandre Julliard2787be81995-05-22 18:23:01 +000047
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000048/* Listbox structure */
49typedef struct
Alexandre Julliard2787be81995-05-22 18:23:01 +000050{
Alexandre Julliarda3960291999-02-26 11:11:13 +000051 HANDLE heap; /* Heap for this listbox */
52 HWND owner; /* Owner window to send notifications to */
53 UINT style; /* Window style */
54 INT width; /* Window width */
55 INT height; /* Window height */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000056 LB_ITEMDATA *items; /* Array of items */
Alexandre Julliarda3960291999-02-26 11:11:13 +000057 INT nb_items; /* Number of items */
58 INT top_item; /* Top visible item */
59 INT selected_item; /* Selected item */
60 INT focus_item; /* Item that has the focus */
61 INT anchor_item; /* Anchor item for extended selection */
62 INT item_height; /* Default item height */
63 INT page_size; /* Items per listbox page */
64 INT column_width; /* Column width for multi-column listboxes */
65 INT horz_extent; /* Horizontal extent (0 if no hscroll) */
66 INT horz_pos; /* Horizontal position */
67 INT nb_tabs; /* Number of tabs in array */
68 INT *tabs; /* Array of tabs */
69 BOOL caret_on; /* Is caret on? */
Luc Tourangeau5ee117b1999-04-04 12:48:21 +000070 BOOL captured; /* Is mouse captured? */
Alexandre Julliarda3960291999-02-26 11:11:13 +000071 HFONT font; /* Current font */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000072 LCID locale; /* Current locale for string comparisons */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000073 LPHEADCOMBO lphc; /* ComboLBox */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000074} LB_DESCR;
Alexandre Julliard2787be81995-05-22 18:23:01 +000075
Alexandre Julliardfa68b751995-04-03 16:55:37 +000076
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000077#define IS_OWNERDRAW(descr) \
78 ((descr)->style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE))
Alexandre Julliardb817f4f1996-03-14 18:08:34 +000079
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000080#define HAS_STRINGS(descr) \
81 (!IS_OWNERDRAW(descr) || ((descr)->style & LBS_HASSTRINGS))
Alexandre Julliard2787be81995-05-22 18:23:01 +000082
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000083#define SEND_NOTIFICATION(wnd,descr,code) \
Alexandre Julliarda3960291999-02-26 11:11:13 +000084 (SendMessageA( (descr)->owner, WM_COMMAND, \
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000085 MAKEWPARAM((((descr)->lphc)?ID_CB_LISTBOX:(wnd)->wIDmenu), (code) ), (wnd)->hwndSelf ))
Alexandre Julliardfa68b751995-04-03 16:55:37 +000086
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000087/* Current timer status */
88typedef enum
Alexandre Julliardfa68b751995-04-03 16:55:37 +000089{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000090 LB_TIMER_NONE,
91 LB_TIMER_UP,
92 LB_TIMER_LEFT,
93 LB_TIMER_DOWN,
94 LB_TIMER_RIGHT
95} TIMER_DIRECTION;
Alexandre Julliardfa68b751995-04-03 16:55:37 +000096
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000097static TIMER_DIRECTION LISTBOX_Timer = LB_TIMER_NONE;
98
99
100/***********************************************************************
101 * LISTBOX_Dump
102 */
103void LISTBOX_Dump( WND *wnd )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000104{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000105 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000106 LB_ITEMDATA *item;
107 LB_DESCR *descr = *(LB_DESCR **)wnd->wExtra;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000108
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000109 TRACE( "Listbox:\n" );
110 TRACE( "hwnd=%04x descr=%08x heap=%08x items=%d top=%d\n",
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000111 wnd->hwndSelf, (UINT)descr, descr->heap, descr->nb_items,
112 descr->top_item );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000113 for (i = 0, item = descr->items; i < descr->nb_items; i++, item++)
114 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000115 TRACE( "%4d: %-40s %d %08lx %3d\n",
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000116 i, item->str, item->selected, item->data, item->height );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000117 }
Alexandre Julliard2787be81995-05-22 18:23:01 +0000118}
119
120
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000121/***********************************************************************
122 * LISTBOX_GetCurrentPageSize
123 *
124 * Return the current page size
125 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000126static INT LISTBOX_GetCurrentPageSize( WND *wnd, LB_DESCR *descr )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000127{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000128 INT i, height;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000129 if (!(descr->style & LBS_OWNERDRAWVARIABLE)) return descr->page_size;
130 for (i = descr->top_item, height = 0; i < descr->nb_items; i++)
131 {
132 if ((height += descr->items[i].height) > descr->height) break;
133 }
134 if (i == descr->top_item) return 1;
135 else return i - descr->top_item;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000136}
137
138
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000139/***********************************************************************
140 * LISTBOX_GetMaxTopIndex
141 *
142 * Return the maximum possible index for the top of the listbox.
143 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000144static INT LISTBOX_GetMaxTopIndex( WND *wnd, LB_DESCR *descr )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000145{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000146 INT max, page;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000147
148 if (descr->style & LBS_OWNERDRAWVARIABLE)
149 {
150 page = descr->height;
151 for (max = descr->nb_items - 1; max >= 0; max--)
152 if ((page -= descr->items[max].height) < 0) break;
153 if (max < descr->nb_items - 1) max++;
154 }
155 else if (descr->style & LBS_MULTICOLUMN)
156 {
157 if ((page = descr->width / descr->column_width) < 1) page = 1;
158 max = (descr->nb_items + descr->page_size - 1) / descr->page_size;
159 max = (max - page) * descr->page_size;
160 }
161 else
162 {
163 max = descr->nb_items - descr->page_size;
164 }
165 if (max < 0) max = 0;
166 return max;
167}
168
169
170/***********************************************************************
171 * LISTBOX_UpdateScroll
172 *
173 * Update the scrollbars. Should be called whenever the content
174 * of the listbox changes.
175 */
176static void LISTBOX_UpdateScroll( WND *wnd, LB_DESCR *descr )
177{
178 SCROLLINFO info;
179
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000180 if (!(descr->style & WS_VSCROLL)) return;
181 /* It is important that we check descr->style, and not wnd->dwStyle,
182 for WS_VSCROLL, as the former is exactly the one passed in
183 argument to CreateWindow.
184 In Windows (and from now on in Wine :) a listbox created
185 with such a style (no WS_SCROLL) does not update
186 the scrollbar with listbox-related data, thus letting
187 the programmer use it for his/her own purposes. */
188
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000189 if (descr->style & LBS_NOREDRAW) return;
190 info.cbSize = sizeof(info);
191
192 if (descr->style & LBS_MULTICOLUMN)
193 {
194 info.nMin = 0;
195 info.nMax = (descr->nb_items - 1) / descr->page_size;
196 info.nPos = descr->top_item / descr->page_size;
197 info.nPage = descr->width / descr->column_width;
198 if (info.nPage < 1) info.nPage = 1;
199 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
200 if (descr->style & LBS_DISABLENOSCROLL)
201 info.fMask |= SIF_DISABLENOSCROLL;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000202 SetScrollInfo( wnd->hwndSelf, SB_HORZ, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000203 info.nMax = 0;
204 info.fMask = SIF_RANGE;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000205 SetScrollInfo( wnd->hwndSelf, SB_VERT, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000206 }
207 else
208 {
209 info.nMin = 0;
210 info.nMax = descr->nb_items - 1;
211 info.nPos = descr->top_item;
212 info.nPage = LISTBOX_GetCurrentPageSize( wnd, descr );
213 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
214 if (descr->style & LBS_DISABLENOSCROLL)
215 info.fMask |= SIF_DISABLENOSCROLL;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000216 SetScrollInfo( wnd->hwndSelf, SB_VERT, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000217
218 if (descr->horz_extent)
219 {
220 info.nMin = 0;
221 info.nMax = descr->horz_extent - 1;
222 info.nPos = descr->horz_pos;
223 info.nPage = descr->width;
224 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
225 if (descr->style & LBS_DISABLENOSCROLL)
226 info.fMask |= SIF_DISABLENOSCROLL;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000227 SetScrollInfo( wnd->hwndSelf, SB_HORZ, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000228 }
229 }
230}
231
232
233/***********************************************************************
234 * LISTBOX_SetTopItem
235 *
236 * Set the top item of the listbox, scrolling up or down if necessary.
237 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000238static LRESULT LISTBOX_SetTopItem( WND *wnd, LB_DESCR *descr, INT index,
239 BOOL scroll )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000240{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000241 INT max = LISTBOX_GetMaxTopIndex( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000242 if (index > max) index = max;
243 if (index < 0) index = 0;
244 if (descr->style & LBS_MULTICOLUMN) index -= index % descr->page_size;
245 if (descr->top_item == index) return LB_OKAY;
246 if (descr->style & LBS_MULTICOLUMN)
247 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000248 INT diff = (descr->top_item - index) / descr->page_size * descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000249 if (scroll && (abs(diff) < descr->width))
Alexandre Julliarda3960291999-02-26 11:11:13 +0000250 ScrollWindowEx( wnd->hwndSelf, diff, 0, NULL, NULL, 0, NULL,
NF Stevens762f18d1999-01-24 19:02:16 +0000251 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
252
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000253 else
254 scroll = FALSE;
255 }
256 else if (scroll)
257 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000258 INT diff;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000259 if (descr->style & LBS_OWNERDRAWVARIABLE)
260 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000261 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000262 diff = 0;
263 if (index > descr->top_item)
264 {
265 for (i = index - 1; i >= descr->top_item; i--)
266 diff -= descr->items[i].height;
267 }
268 else
269 {
270 for (i = index; i < descr->top_item; i++)
271 diff += descr->items[i].height;
272 }
273 }
274 else
275 diff = (descr->top_item - index) * descr->item_height;
276
277 if (abs(diff) < descr->height)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000278 ScrollWindowEx( wnd->hwndSelf, 0, diff, NULL, NULL, 0, NULL,
NF Stevens762f18d1999-01-24 19:02:16 +0000279 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000280 else
281 scroll = FALSE;
282 }
Alexandre Julliarda3960291999-02-26 11:11:13 +0000283 if (!scroll) InvalidateRect( wnd->hwndSelf, NULL, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000284 descr->top_item = index;
285 LISTBOX_UpdateScroll( wnd, descr );
286 return LB_OKAY;
287}
288
289
290/***********************************************************************
291 * LISTBOX_UpdatePage
292 *
293 * Update the page size. Should be called when the size of
294 * the client area or the item height changes.
295 */
296static void LISTBOX_UpdatePage( WND *wnd, LB_DESCR *descr )
297{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000298 INT page_size;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000299
Paul Quinn75722071999-05-22 18:45:06 +0000300 if ((descr->item_height == 0) || (page_size = descr->height / descr->item_height) < 1)
301 page_size = 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000302 if (page_size == descr->page_size) return;
303 descr->page_size = page_size;
304 if (descr->style & LBS_MULTICOLUMN)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000305 InvalidateRect( wnd->hwndSelf, NULL, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000306 LISTBOX_SetTopItem( wnd, descr, descr->top_item, FALSE );
307}
308
309
310/***********************************************************************
311 * LISTBOX_UpdateSize
312 *
313 * Update the size of the listbox. Should be called when the size of
314 * the client area changes.
315 */
316static void LISTBOX_UpdateSize( WND *wnd, LB_DESCR *descr )
317{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000318 RECT rect;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000319
Alexandre Julliarda3960291999-02-26 11:11:13 +0000320 GetClientRect( wnd->hwndSelf, &rect );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000321 descr->width = rect.right - rect.left;
322 descr->height = rect.bottom - rect.top;
Alexandre Julliarda0d77311998-09-13 16:32:00 +0000323 if (!(descr->style & LBS_NOINTEGRALHEIGHT) && !IS_OWNERDRAW(descr))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000324 {
325 if ((descr->height > descr->item_height) &&
326 (descr->height % descr->item_height))
327 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000328 TRACE("[%04x]: changing height %d -> %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000329 wnd->hwndSelf, descr->height,
330 descr->height - descr->height%descr->item_height );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000331 SetWindowPos( wnd->hwndSelf, 0, 0, 0,
Alexandre Julliard01d63461997-01-20 19:43:45 +0000332 wnd->rectWindow.right - wnd->rectWindow.left,
333 wnd->rectWindow.bottom - wnd->rectWindow.top -
334 (descr->height % descr->item_height),
335 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000336 return;
337 }
338 }
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000339 TRACE("[%04x]: new size = %d,%d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000340 wnd->hwndSelf, descr->width, descr->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000341 LISTBOX_UpdatePage( wnd, descr );
342 LISTBOX_UpdateScroll( wnd, descr );
343}
344
345
346/***********************************************************************
347 * LISTBOX_GetItemRect
348 *
349 * Get the rectangle enclosing an item, in listbox client coordinates.
350 * Return 1 if the rectangle is (partially) visible, 0 if hidden, -1 on error.
351 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000352static LRESULT LISTBOX_GetItemRect( WND *wnd, LB_DESCR *descr, INT index,
353 RECT *rect )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000354{
355 /* Index <= 0 is legal even on empty listboxes */
356 if (index && (index >= descr->nb_items)) return -1;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000357 SetRect( rect, 0, 0, descr->width, descr->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000358 if (descr->style & LBS_MULTICOLUMN)
359 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000360 INT col = (index / descr->page_size) -
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000361 (descr->top_item / descr->page_size);
362 rect->left += col * descr->column_width;
363 rect->right = rect->left + descr->column_width;
364 rect->top += (index % descr->page_size) * descr->item_height;
365 rect->bottom = rect->top + descr->item_height;
366 }
367 else if (descr->style & LBS_OWNERDRAWVARIABLE)
368 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000369 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000370 rect->right += descr->horz_pos;
Alexandre Julliard349a9531997-02-02 19:01:52 +0000371 if ((index >= 0) && (index < descr->nb_items))
372 {
373 if (index < descr->top_item)
374 {
375 for (i = descr->top_item-1; i >= index; i--)
376 rect->top -= descr->items[i].height;
377 }
378 else
379 {
380 for (i = descr->top_item; i < index; i++)
381 rect->top += descr->items[i].height;
382 }
383 rect->bottom = rect->top + descr->items[index].height;
384
385 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000386 }
387 else
388 {
389 rect->top += (index - descr->top_item) * descr->item_height;
390 rect->bottom = rect->top + descr->item_height;
391 rect->right += descr->horz_pos;
392 }
393
394 return ((rect->left < descr->width) && (rect->right > 0) &&
395 (rect->top < descr->height) && (rect->bottom > 0));
396}
397
398
399/***********************************************************************
400 * LISTBOX_GetItemFromPoint
401 *
402 * Return the item nearest from point (x,y) (in client coordinates).
403 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000404static INT LISTBOX_GetItemFromPoint( WND *wnd, LB_DESCR *descr,
405 INT x, INT y )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000406{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000407 INT index = descr->top_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000408
409 if (!descr->nb_items) return -1; /* No items */
410 if (descr->style & LBS_OWNERDRAWVARIABLE)
411 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000412 INT pos = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000413 if (y >= 0)
414 {
415 while (index < descr->nb_items)
416 {
417 if ((pos += descr->items[index].height) > y) break;
418 index++;
419 }
420 }
421 else
422 {
423 while (index > 0)
424 {
425 index--;
426 if ((pos -= descr->items[index].height) <= y) break;
427 }
428 }
429 }
430 else if (descr->style & LBS_MULTICOLUMN)
431 {
432 if (y >= descr->item_height * descr->page_size) return -1;
433 if (y >= 0) index += y / descr->item_height;
434 if (x >= 0) index += (x / descr->column_width) * descr->page_size;
435 else index -= (((x + 1) / descr->column_width) - 1) * descr->page_size;
436 }
437 else
438 {
439 index += (y / descr->item_height);
440 }
441 if (index < 0) return 0;
442 if (index >= descr->nb_items) return -1;
443 return index;
444}
445
446
447/***********************************************************************
448 * LISTBOX_PaintItem
449 *
450 * Paint an item.
451 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000452static void LISTBOX_PaintItem( WND *wnd, LB_DESCR *descr, HDC hdc,
453 const RECT *rect, INT index, UINT action )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000454{
455 LB_ITEMDATA *item = NULL;
456 if (index < descr->nb_items) item = &descr->items[index];
457
458 if (IS_OWNERDRAW(descr))
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000459 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000460 DRAWITEMSTRUCT dis;
461 UINT id = (descr->lphc) ? ID_CB_LISTBOX : wnd->wIDmenu;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000462
Marcus Meissner9ad90171999-01-20 14:08:00 +0000463 if (!item)
464 {
465 if (action == ODA_FOCUS)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000466 DrawFocusRect( hdc, rect );
Marcus Meissner9ad90171999-01-20 14:08:00 +0000467 else
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000468 FIXME("called with an out of bounds index %d(%d) in owner draw, Not good.\n",index,descr->nb_items);
Marcus Meissner9ad90171999-01-20 14:08:00 +0000469 return;
470 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000471 dis.CtlType = ODT_LISTBOX;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000472 dis.CtlID = id;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000473 dis.hwndItem = wnd->hwndSelf;
474 dis.itemAction = action;
475 dis.hDC = hdc;
476 dis.itemID = index;
477 dis.itemState = 0;
478 if (item && item->selected) dis.itemState |= ODS_SELECTED;
479 if ((descr->focus_item == index) &&
480 (descr->caret_on) &&
Alexandre Julliarda3960291999-02-26 11:11:13 +0000481 (GetFocus() == wnd->hwndSelf)) dis.itemState |= ODS_FOCUS;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000482 if (wnd->dwStyle & WS_DISABLED) dis.itemState |= ODS_DISABLED;
483 dis.itemData = item ? item->data : 0;
484 dis.rcItem = *rect;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000485 TRACE("[%04x]: drawitem %d (%s) action=%02x "
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000486 "state=%02x rect=%d,%d-%d,%d\n",
487 wnd->hwndSelf, index, item ? item->str : "", action,
488 dis.itemState, rect->left, rect->top,
489 rect->right, rect->bottom );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000490 SendMessageA(descr->owner, WM_DRAWITEM, id, (LPARAM)&dis);
Alexandre Julliard2787be81995-05-22 18:23:01 +0000491 }
492 else
Alexandre Julliardac9c9b01996-07-28 18:50:11 +0000493 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000494 COLORREF oldText = 0, oldBk = 0;
495
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000496 if (action == ODA_FOCUS)
497 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000498 DrawFocusRect( hdc, rect );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000499 return;
500 }
501 if (item && item->selected)
502 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000503 oldBk = SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
504 oldText = SetTextColor( hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000505 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000506
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000507 TRACE("[%04x]: painting %d (%s) action=%02x "
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000508 "rect=%d,%d-%d,%d\n",
509 wnd->hwndSelf, index, item ? item->str : "", action,
510 rect->left, rect->top, rect->right, rect->bottom );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000511 if (!item)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000512 ExtTextOutA( hdc, rect->left + 1, rect->top + 1,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000513 ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000514 else if (!(descr->style & LBS_USETABSTOPS))
Alexandre Julliarda3960291999-02-26 11:11:13 +0000515 ExtTextOutA( hdc, rect->left + 1, rect->top + 1,
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000516 ETO_OPAQUE | ETO_CLIPPED, rect, item->str,
517 strlen(item->str), NULL );
518 else
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000519 {
520 /* Output empty string to paint background in the full width. */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000521 ExtTextOutA( hdc, rect->left + 1, rect->top + 1,
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000522 ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000523 TabbedTextOutA( hdc, rect->left + 1 , rect->top + 1,
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000524 item->str, strlen(item->str),
525 descr->nb_tabs, descr->tabs, 0);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000526 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000527 if (item && item->selected)
528 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000529 SetBkColor( hdc, oldBk );
530 SetTextColor( hdc, oldText );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000531 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000532 if ((descr->focus_item == index) &&
533 (descr->caret_on) &&
Alexandre Julliarda3960291999-02-26 11:11:13 +0000534 (GetFocus() == wnd->hwndSelf)) DrawFocusRect( hdc, rect );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000535 }
Alexandre Julliard2787be81995-05-22 18:23:01 +0000536}
537
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000538
539/***********************************************************************
540 * LISTBOX_SetRedraw
541 *
542 * Change the redraw flag.
543 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000544static void LISTBOX_SetRedraw( WND *wnd, LB_DESCR *descr, BOOL on )
Alexandre Julliardac9c9b01996-07-28 18:50:11 +0000545{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000546 if (on)
547 {
548 if (!(descr->style & LBS_NOREDRAW)) return;
549 descr->style &= ~LBS_NOREDRAW;
550 LISTBOX_UpdateScroll( wnd, descr );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000551 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000552 else descr->style |= LBS_NOREDRAW;
553}
Alexandre Julliard2787be81995-05-22 18:23:01 +0000554
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000555
556/***********************************************************************
557 * LISTBOX_RepaintItem
558 *
559 * Repaint a single item synchronously.
560 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000561static void LISTBOX_RepaintItem( WND *wnd, LB_DESCR *descr, INT index,
562 UINT action )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000563{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000564 HDC hdc;
565 RECT rect;
566 HFONT oldFont = 0;
567 HBRUSH hbrush, oldBrush = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000568
Francois Boisvert428d2981999-05-08 09:33:53 +0000569 /* Do not repaint the item if the item is not visible */
570 if ((descr->style & LBS_NOREDRAW) || !IsWindowVisible(wnd->hwndSelf)) return;
571
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000572 if (LISTBOX_GetItemRect( wnd, descr, index, &rect ) != 1) return;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000573 if (!(hdc = GetDCEx( wnd->hwndSelf, 0, DCX_CACHE ))) return;
574 if (descr->font) oldFont = SelectObject( hdc, descr->font );
575 hbrush = SendMessageA( descr->owner, WM_CTLCOLORLISTBOX,
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000576 hdc, (LPARAM)wnd->hwndSelf );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000577 if (hbrush) oldBrush = SelectObject( hdc, hbrush );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000578 if (wnd->dwStyle & WS_DISABLED)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000579 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
580 SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000581 LISTBOX_PaintItem( wnd, descr, hdc, &rect, index, action );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000582 if (oldFont) SelectObject( hdc, oldFont );
583 if (oldBrush) SelectObject( hdc, oldBrush );
584 ReleaseDC( wnd->hwndSelf, hdc );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000585}
586
587
588/***********************************************************************
589 * LISTBOX_InitStorage
590 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000591static LRESULT LISTBOX_InitStorage( WND *wnd, LB_DESCR *descr, INT nb_items,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000592 DWORD bytes )
593{
594 LB_ITEMDATA *item;
595
596 nb_items += LB_ARRAY_GRANULARITY - 1;
597 nb_items -= (nb_items % LB_ARRAY_GRANULARITY);
598 if (descr->items)
599 nb_items += HeapSize( descr->heap, 0, descr->items ) / sizeof(*item);
600 if (!(item = HeapReAlloc( descr->heap, 0, descr->items,
601 nb_items * sizeof(LB_ITEMDATA) )))
602 {
603 SEND_NOTIFICATION( wnd, descr, LBN_ERRSPACE );
604 return LB_ERRSPACE;
605 }
606 descr->items = item;
607 return LB_OKAY;
608}
609
610
611/***********************************************************************
612 * LISTBOX_SetTabStops
613 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000614static BOOL LISTBOX_SetTabStops( WND *wnd, LB_DESCR *descr, INT count,
615 LPINT tabs, BOOL short_ints )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000616{
617 if (!(descr->style & LBS_USETABSTOPS)) return TRUE;
618 if (descr->tabs) HeapFree( descr->heap, 0, descr->tabs );
619 if (!(descr->nb_tabs = count))
620 {
621 descr->tabs = NULL;
622 return TRUE;
623 }
624 /* FIXME: count = 1 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000625 if (!(descr->tabs = (INT *)HeapAlloc( descr->heap, 0,
626 descr->nb_tabs * sizeof(INT) )))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000627 return FALSE;
628 if (short_ints)
629 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000630 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000631 LPINT16 p = (LPINT16)tabs;
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000632 dbg_decl_str(listbox, 256);
633
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000634 for (i = 0; i < descr->nb_tabs; i++) {
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000635 descr->tabs[i] = *p++<<1; /* FIXME */
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000636 if(TRACE_ON(listbox))
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000637 dsprintf(listbox, "%hd ", descr->tabs[i]);
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000638 }
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000639 TRACE("[%04x]: settabstops %s\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000640 wnd->hwndSelf, dbg_str(listbox));
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000641 }
Alexandre Julliarda3960291999-02-26 11:11:13 +0000642 else memcpy( descr->tabs, tabs, descr->nb_tabs * sizeof(INT) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000643 /* FIXME: repaint the window? */
Alexandre Julliard2787be81995-05-22 18:23:01 +0000644 return TRUE;
645}
646
647
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000648/***********************************************************************
649 * LISTBOX_GetText
650 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000651static LRESULT LISTBOX_GetText( WND *wnd, LB_DESCR *descr, INT index,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000652 LPSTR buffer )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000653{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000654 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
655 if (HAS_STRINGS(descr))
656 {
Marcus Meissner4f7dc461998-11-22 15:43:34 +0000657 if (!buffer)
658 return strlen(descr->items[index].str);
Alexandre Julliarda3960291999-02-26 11:11:13 +0000659 lstrcpyA( buffer, descr->items[index].str );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000660 return strlen(buffer);
Marcus Meissner4f7dc461998-11-22 15:43:34 +0000661 } else {
662 if (buffer)
663 *((LPDWORD)buffer)=*(LPDWORD)(&descr->items[index].data);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000664 return sizeof(DWORD);
665 }
Alexandre Julliard2787be81995-05-22 18:23:01 +0000666}
667
668
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000669/***********************************************************************
670 * LISTBOX_FindStringPos
671 *
672 * Find the nearest string located before a given string in sort order.
673 * If 'exact' is TRUE, return an error if we don't get an exact match.
674 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000675static INT LISTBOX_FindStringPos( WND *wnd, LB_DESCR *descr, LPCSTR str,
676 BOOL exact )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000677{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000678 INT index, min, max, res = -1;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000679
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000680 if (!(descr->style & LBS_SORT)) return -1; /* Add it at the end */
681 min = 0;
682 max = descr->nb_items;
683 while (min != max)
684 {
685 index = (min + max) / 2;
686 if (HAS_STRINGS(descr))
Alexandre Julliarda3960291999-02-26 11:11:13 +0000687 res = lstrcmpiA( descr->items[index].str, str );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000688 else
689 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000690 COMPAREITEMSTRUCT cis;
691 UINT id = (descr->lphc) ? ID_CB_LISTBOX : wnd->wIDmenu;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000692
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000693 cis.CtlType = ODT_LISTBOX;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000694 cis.CtlID = id;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000695 cis.hwndItem = wnd->hwndSelf;
696 cis.itemID1 = index;
697 cis.itemData1 = descr->items[index].data;
698 cis.itemID2 = -1;
699 cis.itemData2 = (DWORD)str;
700 cis.dwLocaleId = descr->locale;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000701 res = SendMessageA( descr->owner, WM_COMPAREITEM,
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000702 id, (LPARAM)&cis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000703 }
704 if (!res) return index;
705 if (res > 0) max = index;
706 else min = index + 1;
707 }
708 return exact ? -1 : max;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000709}
710
711
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000712/***********************************************************************
713 * LISTBOX_FindFileStrPos
714 *
715 * Find the nearest string located before a given string in directory
716 * sort order (i.e. first files, then directories, then drives).
717 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000718static INT LISTBOX_FindFileStrPos( WND *wnd, LB_DESCR *descr, LPCSTR str )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000719{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000720 INT min, max, res = -1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000721
722 if (!HAS_STRINGS(descr))
723 return LISTBOX_FindStringPos( wnd, descr, str, FALSE );
724 min = 0;
725 max = descr->nb_items;
726 while (min != max)
727 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000728 INT index = (min + max) / 2;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000729 const char *p = descr->items[index].str;
730 if (*p == '[') /* drive or directory */
731 {
732 if (*str != '[') res = -1;
733 else if (p[1] == '-') /* drive */
734 {
735 if (str[1] == '-') res = str[2] - p[2];
736 else res = -1;
737 }
738 else /* directory */
739 {
740 if (str[1] == '-') res = 1;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000741 else res = lstrcmpiA( str, p );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000742 }
743 }
744 else /* filename */
745 {
746 if (*str == '[') res = 1;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000747 else res = lstrcmpiA( str, p );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000748 }
749 if (!res) return index;
750 if (res < 0) max = index;
751 else min = index + 1;
752 }
753 return max;
754}
755
756
757/***********************************************************************
758 * LISTBOX_FindString
759 *
760 * Find the item beginning with a given string.
761 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000762static INT LISTBOX_FindString( WND *wnd, LB_DESCR *descr, INT start,
763 LPCSTR str, BOOL exact )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000764{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000765 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000766 LB_ITEMDATA *item;
767
768 if (start >= descr->nb_items) start = -1;
769 item = descr->items + start + 1;
770 if (HAS_STRINGS(descr))
771 {
Alexandre Julliard7ff1c411997-05-25 13:58:18 +0000772 if (!str) return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000773 if (exact)
774 {
775 for (i = start + 1; i < descr->nb_items; i++, item++)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000776 if (!lstrcmpiA( str, item->str )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000777 for (i = 0, item = descr->items; i <= start; i++, item++)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000778 if (!lstrcmpiA( str, item->str )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000779 }
780 else
781 {
782 /* Special case for drives and directories: ignore prefix */
783#define CHECK_DRIVE(item) \
784 if ((item)->str[0] == '[') \
785 { \
Alexandre Julliarda3960291999-02-26 11:11:13 +0000786 if (!lstrncmpiA( str, (item)->str+1, len )) return i; \
787 if (((item)->str[1] == '-') && !lstrncmpiA(str,(item)->str+2,len)) \
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000788 return i; \
789 }
790
Alexandre Julliarda3960291999-02-26 11:11:13 +0000791 INT len = strlen(str);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000792 for (i = start + 1; i < descr->nb_items; i++, item++)
793 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000794 if (!lstrncmpiA( str, item->str, len )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000795 CHECK_DRIVE(item);
796 }
797 for (i = 0, item = descr->items; i <= start; i++, item++)
798 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000799 if (!lstrncmpiA( str, item->str, len )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000800 CHECK_DRIVE(item);
801 }
802#undef CHECK_DRIVE
803 }
804 }
805 else
806 {
807 if (exact && (descr->style & LBS_SORT))
808 /* If sorted, use a WM_COMPAREITEM binary search */
809 return LISTBOX_FindStringPos( wnd, descr, str, TRUE );
810
811 /* Otherwise use a linear search */
812 for (i = start + 1; i < descr->nb_items; i++, item++)
813 if (item->data == (DWORD)str) return i;
814 for (i = 0, item = descr->items; i <= start; i++, item++)
815 if (item->data == (DWORD)str) return i;
816 }
817 return LB_ERR;
818}
819
820
821/***********************************************************************
822 * LISTBOX_GetSelCount
823 */
824static LRESULT LISTBOX_GetSelCount( WND *wnd, LB_DESCR *descr )
825{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000826 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000827 LB_ITEMDATA *item = descr->items;
828
829 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
830 for (i = count = 0; i < descr->nb_items; i++, item++)
831 if (item->selected) count++;
832 return count;
833}
834
835
836/***********************************************************************
837 * LISTBOX_GetSelItems16
838 */
839static LRESULT LISTBOX_GetSelItems16( WND *wnd, LB_DESCR *descr, INT16 max,
840 LPINT16 array )
841{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000842 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000843 LB_ITEMDATA *item = descr->items;
844
845 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
846 for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++)
847 if (item->selected) array[count++] = (INT16)i;
848 return count;
849}
850
851
852/***********************************************************************
853 * LISTBOX_GetSelItems32
854 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000855static LRESULT LISTBOX_GetSelItems( WND *wnd, LB_DESCR *descr, INT max,
856 LPINT array )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000857{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000858 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000859 LB_ITEMDATA *item = descr->items;
860
861 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
862 for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++)
863 if (item->selected) array[count++] = i;
864 return count;
865}
866
867
868/***********************************************************************
869 * LISTBOX_Paint
870 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000871static LRESULT LISTBOX_Paint( WND *wnd, LB_DESCR *descr, HDC hdc )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000872{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000873 INT i, col_pos = descr->page_size - 1;
874 RECT rect;
875 HFONT oldFont = 0;
876 HBRUSH hbrush, oldBrush = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000877
Alexandre Julliarda3960291999-02-26 11:11:13 +0000878 SetRect( &rect, 0, 0, descr->width, descr->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000879 if (descr->style & LBS_NOREDRAW) return 0;
880 if (descr->style & LBS_MULTICOLUMN)
881 rect.right = rect.left + descr->column_width;
882 else if (descr->horz_pos)
883 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000884 SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000885 rect.right += descr->horz_pos;
886 }
887
Alexandre Julliarda3960291999-02-26 11:11:13 +0000888 if (descr->font) oldFont = SelectObject( hdc, descr->font );
889 hbrush = SendMessageA( descr->owner, WM_CTLCOLORLISTBOX,
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000890 hdc, (LPARAM)wnd->hwndSelf );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000891 if (hbrush) oldBrush = SelectObject( hdc, hbrush );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000892 if (wnd->dwStyle & WS_DISABLED)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000893 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000894
895 if (!descr->nb_items && (descr->focus_item != -1) && descr->caret_on &&
Alexandre Julliarda3960291999-02-26 11:11:13 +0000896 (GetFocus() == wnd->hwndSelf))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000897 {
898 /* Special case for empty listbox: paint focus rect */
899 rect.bottom = rect.top + descr->item_height;
900 LISTBOX_PaintItem( wnd, descr, hdc, &rect, descr->focus_item,
Gerard Patelc979b7b1998-12-24 16:25:50 +0000901 ODA_FOCUS );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000902 rect.top = rect.bottom;
903 }
904
905 for (i = descr->top_item; i < descr->nb_items; i++)
906 {
907 if (!(descr->style & LBS_OWNERDRAWVARIABLE))
908 rect.bottom = rect.top + descr->item_height;
909 else
910 rect.bottom = rect.top + descr->items[i].height;
911
912 LISTBOX_PaintItem( wnd, descr, hdc, &rect, i, ODA_DRAWENTIRE );
913 rect.top = rect.bottom;
914
915 if ((descr->style & LBS_MULTICOLUMN) && !col_pos)
916 {
917 if (!IS_OWNERDRAW(descr))
918 {
919 /* Clear the bottom of the column */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000920 SetBkColor( hdc, GetSysColor( COLOR_WINDOW ) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000921 if (rect.top < descr->height)
922 {
923 rect.bottom = descr->height;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000924 ExtTextOutA( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000925 &rect, NULL, 0, NULL );
926 }
927 }
928
929 /* Go to the next column */
930 rect.left += descr->column_width;
931 rect.right += descr->column_width;
932 rect.top = 0;
933 col_pos = descr->page_size - 1;
934 }
935 else
936 {
937 col_pos--;
938 if (rect.top >= descr->height) break;
939 }
940 }
941
942 if (!IS_OWNERDRAW(descr))
943 {
944 /* Clear the remainder of the client area */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000945 SetBkColor( hdc, GetSysColor( COLOR_WINDOW ) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000946 if (rect.top < descr->height)
947 {
948 rect.bottom = descr->height;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000949 ExtTextOutA( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000950 &rect, NULL, 0, NULL );
951 }
952 if (rect.right < descr->width)
953 {
954 rect.left = rect.right;
955 rect.right = descr->width;
956 rect.top = 0;
957 rect.bottom = descr->height;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000958 ExtTextOutA( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000959 &rect, NULL, 0, NULL );
960 }
961 }
Alexandre Julliarda3960291999-02-26 11:11:13 +0000962 if (oldFont) SelectObject( hdc, oldFont );
963 if (oldBrush) SelectObject( hdc, oldBrush );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000964 return 0;
965}
966
967
968/***********************************************************************
969 * LISTBOX_InvalidateItems
970 *
971 * Invalidate all items from a given item. If the specified item is not
972 * visible, nothing happens.
973 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000974static void LISTBOX_InvalidateItems( WND *wnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000975{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000976 RECT rect;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000977
978 if (LISTBOX_GetItemRect( wnd, descr, index, &rect ) == 1)
979 {
980 rect.bottom = descr->height;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000981 InvalidateRect( wnd->hwndSelf, &rect, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000982 if (descr->style & LBS_MULTICOLUMN)
983 {
984 /* Repaint the other columns */
985 rect.left = rect.right;
986 rect.right = descr->width;
987 rect.top = 0;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000988 InvalidateRect( wnd->hwndSelf, &rect, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000989 }
990 }
991}
992
993
994/***********************************************************************
995 * LISTBOX_GetItemHeight
996 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000997static LRESULT LISTBOX_GetItemHeight( WND *wnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000998{
999 if (descr->style & LBS_OWNERDRAWVARIABLE)
1000 {
1001 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
1002 return descr->items[index].height;
1003 }
1004 else return descr->item_height;
1005}
1006
1007
1008/***********************************************************************
1009 * LISTBOX_SetItemHeight
1010 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001011static LRESULT LISTBOX_SetItemHeight( WND *wnd, LB_DESCR *descr, INT index,
1012 UINT height )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001013{
1014 if (!height) height = 1;
1015
1016 if (descr->style & LBS_OWNERDRAWVARIABLE)
1017 {
1018 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001019 TRACE("[%04x]: item %d height = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001020 wnd->hwndSelf, index, height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001021 descr->items[index].height = height;
1022 LISTBOX_UpdateScroll( wnd, descr );
1023 LISTBOX_InvalidateItems( wnd, descr, index );
1024 }
1025 else if (height != descr->item_height)
1026 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001027 TRACE("[%04x]: new height = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001028 wnd->hwndSelf, height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001029 descr->item_height = height;
1030 LISTBOX_UpdatePage( wnd, descr );
1031 LISTBOX_UpdateScroll( wnd, descr );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001032 InvalidateRect( wnd->hwndSelf, 0, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001033 }
1034 return LB_OKAY;
1035}
1036
1037
1038/***********************************************************************
1039 * LISTBOX_SetHorizontalPos
1040 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001041static void LISTBOX_SetHorizontalPos( WND *wnd, LB_DESCR *descr, INT pos )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001042{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001043 INT diff;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001044
1045 if (pos > descr->horz_extent - descr->width)
1046 pos = descr->horz_extent - descr->width;
1047 if (pos < 0) pos = 0;
1048 if (!(diff = descr->horz_pos - pos)) return;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001049 TRACE("[%04x]: new horz pos = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001050 wnd->hwndSelf, pos );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001051 descr->horz_pos = pos;
1052 LISTBOX_UpdateScroll( wnd, descr );
1053 if (abs(diff) < descr->width)
Alexandre Julliarda3960291999-02-26 11:11:13 +00001054 ScrollWindowEx( wnd->hwndSelf, diff, 0, NULL, NULL, 0, NULL,
NF Stevens762f18d1999-01-24 19:02:16 +00001055 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001056 else
Alexandre Julliarda3960291999-02-26 11:11:13 +00001057 InvalidateRect( wnd->hwndSelf, NULL, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001058}
1059
1060
1061/***********************************************************************
1062 * LISTBOX_SetHorizontalExtent
1063 */
1064static LRESULT LISTBOX_SetHorizontalExtent( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001065 UINT extent )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001066{
1067 if (!descr->horz_extent || (descr->style & LBS_MULTICOLUMN))
1068 return LB_OKAY;
1069 if (extent <= 0) extent = 1;
1070 if (extent == descr->horz_extent) return LB_OKAY;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001071 TRACE("[%04x]: new horz extent = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001072 wnd->hwndSelf, extent );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001073 descr->horz_extent = extent;
1074 if (descr->horz_pos > extent - descr->width)
1075 LISTBOX_SetHorizontalPos( wnd, descr, extent - descr->width );
1076 else
1077 LISTBOX_UpdateScroll( wnd, descr );
1078 return LB_OKAY;
1079}
1080
1081
1082/***********************************************************************
1083 * LISTBOX_SetColumnWidth
1084 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001085static LRESULT LISTBOX_SetColumnWidth( WND *wnd, LB_DESCR *descr, UINT width)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001086{
1087 width += 2; /* For left and right margin */
1088 if (width == descr->column_width) return LB_OKAY;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001089 TRACE("[%04x]: new column width = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001090 wnd->hwndSelf, width );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001091 descr->column_width = width;
1092 LISTBOX_UpdatePage( wnd, descr );
1093 return LB_OKAY;
1094}
1095
1096
1097/***********************************************************************
1098 * LISTBOX_SetFont
1099 *
1100 * Returns the item height.
1101 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001102static INT LISTBOX_SetFont( WND *wnd, LB_DESCR *descr, HFONT font )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001103{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001104 HDC hdc;
1105 HFONT oldFont = 0;
1106 TEXTMETRICA tm;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001107
1108 descr->font = font;
1109
Alexandre Julliarda3960291999-02-26 11:11:13 +00001110 if (!(hdc = GetDCEx( wnd->hwndSelf, 0, DCX_CACHE )))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001111 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001112 ERR("unable to get DC.\n" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001113 return 16;
1114 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001115 if (font) oldFont = SelectObject( hdc, font );
1116 GetTextMetricsA( hdc, &tm );
1117 if (oldFont) SelectObject( hdc, oldFont );
1118 ReleaseDC( wnd->hwndSelf, hdc );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001119 if (!IS_OWNERDRAW(descr))
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001120 LISTBOX_SetItemHeight( wnd, descr, 0, tm.tmHeight );
1121 return tm.tmHeight ;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001122}
1123
1124
1125/***********************************************************************
1126 * LISTBOX_MakeItemVisible
1127 *
1128 * Make sure that a given item is partially or fully visible.
1129 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001130static void LISTBOX_MakeItemVisible( WND *wnd, LB_DESCR *descr, INT index,
1131 BOOL fully )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001132{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001133 INT top;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001134
1135 if (index <= descr->top_item) top = index;
1136 else if (descr->style & LBS_MULTICOLUMN)
1137 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001138 INT cols = descr->width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001139 if (!fully) cols += descr->column_width - 1;
1140 if (cols >= descr->column_width) cols /= descr->column_width;
1141 else cols = 1;
1142 if (index < descr->top_item + (descr->page_size * cols)) return;
1143 top = index - descr->page_size * (cols - 1);
1144 }
1145 else if (descr->style & LBS_OWNERDRAWVARIABLE)
1146 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001147 INT height = fully ? descr->items[index].height : 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001148 for (top = index; top > descr->top_item; top--)
1149 if ((height += descr->items[top-1].height) > descr->height) break;
1150 }
1151 else
1152 {
1153 if (index < descr->top_item + descr->page_size) return;
1154 if (!fully && (index == descr->top_item + descr->page_size) &&
1155 (descr->height > (descr->page_size * descr->item_height))) return;
1156 top = index - descr->page_size + 1;
1157 }
1158 LISTBOX_SetTopItem( wnd, descr, top, TRUE );
1159}
1160
1161
1162/***********************************************************************
1163 * LISTBOX_SelectItemRange
1164 *
1165 * Select a range of items. Should only be used on a MULTIPLESEL listbox.
1166 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001167static LRESULT LISTBOX_SelectItemRange( WND *wnd, LB_DESCR *descr, INT first,
1168 INT last, BOOL on )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001169{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001170 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001171
1172 /* A few sanity checks */
1173
Alexandre Julliard03468f71998-02-15 19:40:49 +00001174 if ((last == -1) && (descr->nb_items == 0)) return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001175 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
1176 if (last == -1) last = descr->nb_items - 1;
1177 if ((first < 0) || (first >= descr->nb_items)) return LB_ERR;
1178 if ((last < 0) || (last >= descr->nb_items)) return LB_ERR;
1179 /* selected_item reflects last selected/unselected item on multiple sel */
1180 descr->selected_item = last;
1181
1182 if (on) /* Turn selection on */
1183 {
1184 for (i = first; i <= last; i++)
1185 {
1186 if (descr->items[i].selected) continue;
1187 descr->items[i].selected = TRUE;
1188 LISTBOX_RepaintItem( wnd, descr, i, ODA_SELECT );
1189 }
1190 }
1191 else /* Turn selection off */
1192 {
1193 for (i = first; i <= last; i++)
1194 {
1195 if (!descr->items[i].selected) continue;
1196 descr->items[i].selected = FALSE;
1197 LISTBOX_RepaintItem( wnd, descr, i, ODA_SELECT );
1198 }
1199 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001200 return LB_OKAY;
1201}
1202
1203
1204/***********************************************************************
1205 * LISTBOX_SetCaretIndex
Alexandre Julliard638f1691999-01-17 16:32:32 +00001206 *
1207 * NOTES
1208 * index must be between 0 and descr->nb_items-1, or LB_ERR is returned.
1209 *
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001210 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001211static LRESULT LISTBOX_SetCaretIndex( WND *wnd, LB_DESCR *descr, INT index,
1212 BOOL fully_visible )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001213{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001214 INT oldfocus = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001215
Alexandre Julliard638f1691999-01-17 16:32:32 +00001216 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001217 if (index == oldfocus) return LB_OKAY;
1218 descr->focus_item = index;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001219 if ((oldfocus != -1) && descr->caret_on && (GetFocus() == wnd->hwndSelf))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001220 LISTBOX_RepaintItem( wnd, descr, oldfocus, ODA_FOCUS );
Alexandre Julliard638f1691999-01-17 16:32:32 +00001221
1222 LISTBOX_MakeItemVisible( wnd, descr, index, fully_visible );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001223 if (descr->caret_on && (GetFocus() == wnd->hwndSelf))
Alexandre Julliard638f1691999-01-17 16:32:32 +00001224 LISTBOX_RepaintItem( wnd, descr, index, ODA_FOCUS );
1225
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001226 return LB_OKAY;
1227}
1228
1229
1230/***********************************************************************
1231 * LISTBOX_SetSelection
1232 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001233static LRESULT LISTBOX_SetSelection( WND *wnd, LB_DESCR *descr, INT index,
1234 BOOL on, BOOL send_notify )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001235{
1236 if ((index < -1) || (index >= descr->nb_items)) return LB_ERR;
1237 if (descr->style & LBS_MULTIPLESEL)
1238 {
1239 if (index == -1) /* Select all items */
1240 return LISTBOX_SelectItemRange( wnd, descr, 0, -1, on );
1241 else /* Only one item */
1242 return LISTBOX_SelectItemRange( wnd, descr, index, index, on );
1243 }
1244 else
1245 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001246 INT oldsel = descr->selected_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001247 if (index == oldsel) return LB_OKAY;
1248 if (oldsel != -1) descr->items[oldsel].selected = FALSE;
1249 if (index != -1) descr->items[index].selected = TRUE;
1250 descr->selected_item = index;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001251 if (oldsel != -1) LISTBOX_RepaintItem( wnd, descr, oldsel, ODA_SELECT);
1252 if (index != -1) LISTBOX_RepaintItem( wnd, descr, index, ODA_SELECT );
1253 if (send_notify) SEND_NOTIFICATION( wnd, descr,
1254 (index != -1) ? LBN_SELCHANGE : LBN_SELCANCEL );
Alex Korobka311d3291999-01-01 18:40:02 +00001255 else
1256 if( descr->lphc ) /* set selection change flag for parent combo */
1257 descr->lphc->wState |= CBF_SELCHANGE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001258 }
1259 return LB_OKAY;
1260}
1261
1262
1263/***********************************************************************
1264 * LISTBOX_MoveCaret
1265 *
1266 * Change the caret position and extend the selection to the new caret.
1267 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001268static void LISTBOX_MoveCaret( WND *wnd, LB_DESCR *descr, INT index,
1269 BOOL fully_visible )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001270{
1271 LISTBOX_SetCaretIndex( wnd, descr, index, fully_visible );
1272 if (descr->style & LBS_EXTENDEDSEL)
1273 {
1274 if (descr->anchor_item != -1)
1275 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001276 INT first = MIN( descr->focus_item, descr->anchor_item );
1277 INT last = MAX( descr->focus_item, descr->anchor_item );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001278 if (first > 0)
1279 LISTBOX_SelectItemRange( wnd, descr, 0, first - 1, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001280 LISTBOX_SelectItemRange( wnd, descr, last + 1, -1, FALSE );
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001281 LISTBOX_SelectItemRange( wnd, descr, first, last, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001282 }
1283 }
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00001284 else if (!(descr->style & LBS_MULTIPLESEL))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001285 {
1286 /* Set selection to new caret item */
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00001287 LISTBOX_SetSelection( wnd, descr, index, TRUE, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001288 }
1289}
1290
1291
1292/***********************************************************************
1293 * LISTBOX_InsertItem
1294 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001295static LRESULT LISTBOX_InsertItem( WND *wnd, LB_DESCR *descr, INT index,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001296 LPSTR str, DWORD data )
1297{
1298 LB_ITEMDATA *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001299 INT max_items;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001300
1301 if (index == -1) index = descr->nb_items;
1302 else if ((index < 0) || (index > descr->nb_items)) return LB_ERR;
1303 if (!descr->items) max_items = 0;
1304 else max_items = HeapSize( descr->heap, 0, descr->items ) / sizeof(*item);
1305 if (descr->nb_items == max_items)
1306 {
1307 /* We need to grow the array */
1308 max_items += LB_ARRAY_GRANULARITY;
1309 if (!(item = HeapReAlloc( descr->heap, 0, descr->items,
1310 max_items * sizeof(LB_ITEMDATA) )))
1311 {
1312 SEND_NOTIFICATION( wnd, descr, LBN_ERRSPACE );
1313 return LB_ERRSPACE;
1314 }
1315 descr->items = item;
1316 }
1317
1318 /* Insert the item structure */
1319
1320 item = &descr->items[index];
1321 if (index < descr->nb_items)
1322 RtlMoveMemory( item + 1, item,
1323 (descr->nb_items - index) * sizeof(LB_ITEMDATA) );
1324 item->str = str;
1325 item->data = data;
1326 item->height = 0;
1327 item->selected = FALSE;
1328 descr->nb_items++;
1329
1330 /* Get item height */
1331
1332 if (descr->style & LBS_OWNERDRAWVARIABLE)
1333 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001334 MEASUREITEMSTRUCT mis;
1335 UINT id = (descr->lphc) ? ID_CB_LISTBOX : wnd->wIDmenu;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001336
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001337 mis.CtlType = ODT_LISTBOX;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001338 mis.CtlID = id;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001339 mis.itemID = index;
1340 mis.itemData = descr->items[index].data;
1341 mis.itemHeight = descr->item_height;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001342 SendMessageA( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001343 item->height = mis.itemHeight ? mis.itemHeight : 1;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001344 TRACE("[%04x]: measure item %d (%s) = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001345 wnd->hwndSelf, index, str ? str : "", item->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001346 }
1347
1348 /* Repaint the items */
1349
1350 LISTBOX_UpdateScroll( wnd, descr );
1351 LISTBOX_InvalidateItems( wnd, descr, index );
1352
1353 /* Move selection and focused item */
1354
1355 if (index <= descr->selected_item) descr->selected_item++;
1356 if (index <= descr->focus_item)
1357 {
1358 descr->focus_item++;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001359 LISTBOX_MoveCaret( wnd, descr, descr->focus_item, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001360 }
1361
1362 /* If listbox was empty, set focus to the first item */
1363
1364 if (descr->nb_items == 1) LISTBOX_SetCaretIndex( wnd, descr, 0, FALSE );
1365 return LB_OKAY;
1366}
1367
1368
1369/***********************************************************************
1370 * LISTBOX_InsertString
1371 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001372static LRESULT LISTBOX_InsertString( WND *wnd, LB_DESCR *descr, INT index,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001373 LPCSTR str )
1374{
1375 LPSTR new_str = NULL;
1376 DWORD data = 0;
1377 LRESULT ret;
1378
1379 if (HAS_STRINGS(descr))
1380 {
1381 if (!(new_str = HEAP_strdupA( descr->heap, 0, str )))
1382 {
1383 SEND_NOTIFICATION( wnd, descr, LBN_ERRSPACE );
1384 return LB_ERRSPACE;
1385 }
1386 }
1387 else data = (DWORD)str;
1388
1389 if (index == -1) index = descr->nb_items;
1390 if ((ret = LISTBOX_InsertItem( wnd, descr, index, new_str, data )) != 0)
1391 {
1392 if (new_str) HeapFree( descr->heap, 0, new_str );
1393 return ret;
1394 }
1395
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001396 TRACE("[%04x]: added item %d '%s'\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001397 wnd->hwndSelf, index, HAS_STRINGS(descr) ? new_str : "" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001398 return index;
1399}
1400
1401
1402/***********************************************************************
1403 * LISTBOX_DeleteItem
1404 *
1405 * Delete the content of an item. 'index' must be a valid index.
1406 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001407static void LISTBOX_DeleteItem( WND *wnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001408{
1409 /* Note: Win 3.1 only sends DELETEITEM on owner-draw items,
1410 * while Win95 sends it for all items with user data.
1411 * It's probably better to send it too often than not
1412 * often enough, so this is what we do here.
1413 */
1414 if (IS_OWNERDRAW(descr) || descr->items[index].data)
1415 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001416 DELETEITEMSTRUCT dis;
1417 UINT id = (descr->lphc) ? ID_CB_LISTBOX : wnd->wIDmenu;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001418
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001419 dis.CtlType = ODT_LISTBOX;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001420 dis.CtlID = id;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001421 dis.itemID = index;
1422 dis.hwndItem = wnd->hwndSelf;
1423 dis.itemData = descr->items[index].data;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001424 SendMessageA( descr->owner, WM_DELETEITEM, id, (LPARAM)&dis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001425 }
1426 if (HAS_STRINGS(descr) && descr->items[index].str)
1427 HeapFree( descr->heap, 0, descr->items[index].str );
1428}
1429
1430
1431/***********************************************************************
1432 * LISTBOX_RemoveItem
1433 *
1434 * Remove an item from the listbox and delete its content.
1435 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001436static LRESULT LISTBOX_RemoveItem( WND *wnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001437{
1438 LB_ITEMDATA *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001439 INT max_items;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001440
1441 if (index == -1) index = descr->nb_items - 1;
1442 else if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
1443 LISTBOX_DeleteItem( wnd, descr, index );
1444
1445 /* Remove the item */
1446
1447 item = &descr->items[index];
1448 if (index < descr->nb_items-1)
1449 RtlMoveMemory( item, item + 1,
1450 (descr->nb_items - index - 1) * sizeof(LB_ITEMDATA) );
1451 descr->nb_items--;
1452 if (descr->anchor_item == descr->nb_items) descr->anchor_item--;
1453
1454 /* Shrink the item array if possible */
1455
1456 max_items = HeapSize( descr->heap, 0, descr->items ) / sizeof(LB_ITEMDATA);
1457 if (descr->nb_items < max_items - 2*LB_ARRAY_GRANULARITY)
1458 {
1459 max_items -= LB_ARRAY_GRANULARITY;
1460 item = HeapReAlloc( descr->heap, 0, descr->items,
1461 max_items * sizeof(LB_ITEMDATA) );
1462 if (item) descr->items = item;
1463 }
1464
1465 /* Repaint the items */
1466
1467 LISTBOX_UpdateScroll( wnd, descr );
1468 LISTBOX_InvalidateItems( wnd, descr, index );
1469
1470 /* Move selection and focused item */
1471
1472 if (index <= descr->selected_item) descr->selected_item--;
1473 if (index <= descr->focus_item)
1474 {
1475 descr->focus_item--;
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00001476 LISTBOX_MoveCaret( wnd, descr, descr->focus_item, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001477 }
1478 return LB_OKAY;
1479}
1480
1481
1482/***********************************************************************
1483 * LISTBOX_ResetContent
1484 */
1485static void LISTBOX_ResetContent( WND *wnd, LB_DESCR *descr )
1486{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001487 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001488
1489 for (i = 0; i < descr->nb_items; i++) LISTBOX_DeleteItem( wnd, descr, i );
1490 if (descr->items) HeapFree( descr->heap, 0, descr->items );
1491 descr->nb_items = 0;
1492 descr->top_item = 0;
1493 descr->selected_item = -1;
1494 descr->focus_item = 0;
1495 descr->anchor_item = -1;
1496 descr->items = NULL;
1497 LISTBOX_UpdateScroll( wnd, descr );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001498 InvalidateRect( wnd->hwndSelf, NULL, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001499}
1500
1501
1502/***********************************************************************
1503 * LISTBOX_SetCount
1504 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001505static LRESULT LISTBOX_SetCount( WND *wnd, LB_DESCR *descr, INT count )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001506{
1507 LRESULT ret;
1508
1509 if (HAS_STRINGS(descr)) return LB_ERR;
1510 /* FIXME: this is far from optimal... */
1511 if (count > descr->nb_items)
1512 {
1513 while (count > descr->nb_items)
1514 if ((ret = LISTBOX_InsertString( wnd, descr, -1, 0 )) < 0)
1515 return ret;
1516 }
1517 else if (count < descr->nb_items)
1518 {
1519 while (count < descr->nb_items)
1520 if ((ret = LISTBOX_RemoveItem( wnd, descr, -1 )) < 0)
1521 return ret;
1522 }
1523 return LB_OKAY;
1524}
1525
1526
1527/***********************************************************************
1528 * LISTBOX_Directory
1529 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001530static LRESULT LISTBOX_Directory( WND *wnd, LB_DESCR *descr, UINT attrib,
1531 LPCSTR filespec, BOOL long_names )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001532{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001533 HANDLE handle;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001534 LRESULT ret = LB_OKAY;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001535 WIN32_FIND_DATAA entry;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001536 int pos;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001537
Alexandre Julliarda3960291999-02-26 11:11:13 +00001538 if ((handle = FindFirstFileA(filespec,&entry)) == INVALID_HANDLE_VALUE)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001539 {
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001540 if (GetLastError() != ERROR_NO_MORE_FILES) return LB_ERR;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001541 }
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001542 else
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001543 {
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001544 do
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001545 {
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001546 char buffer[270];
1547 if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1548 {
1549 if (!(attrib & DDL_DIRECTORY) ||
1550 !strcmp( entry.cAlternateFileName, "." )) continue;
1551 if (long_names) sprintf( buffer, "[%s]", entry.cFileName );
1552 else sprintf( buffer, "[%s]", entry.cAlternateFileName );
1553 }
1554 else /* not a directory */
1555 {
1556#define ATTRIBS (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
1557 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE)
1558
1559 if ((attrib & DDL_EXCLUSIVE) &&
1560 ((attrib & ATTRIBS) != (entry.dwFileAttributes & ATTRIBS)))
1561 continue;
1562#undef ATTRIBS
1563 if (long_names) strcpy( buffer, entry.cFileName );
1564 else strcpy( buffer, entry.cAlternateFileName );
1565 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001566 if (!long_names) CharLowerA( buffer );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001567 pos = LISTBOX_FindFileStrPos( wnd, descr, buffer );
1568 if ((ret = LISTBOX_InsertString( wnd, descr, pos, buffer )) < 0)
1569 break;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001570 } while (FindNextFileA( handle, &entry ));
1571 FindClose( handle );
Alexandre Julliard2787be81995-05-22 18:23:01 +00001572 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001573
Alexandre Julliard889f7421997-04-15 17:19:52 +00001574 if ((ret >= 0) && (attrib & DDL_DRIVES))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001575 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001576 char buffer[] = "[-a-]";
1577 int drive;
1578 for (drive = 0; drive < MAX_DOS_DRIVES; drive++, buffer[2]++)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001579 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001580 if (!DRIVE_IsValid(drive)) continue;
1581 if ((ret = LISTBOX_InsertString( wnd, descr, -1, buffer )) < 0)
1582 break;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001583 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001584 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001585 return ret;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001586}
1587
1588
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001589/***********************************************************************
1590 * LISTBOX_HandleVScroll
1591 */
1592static LRESULT LISTBOX_HandleVScroll( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001593 WPARAM wParam, LPARAM lParam )
Alexandre Julliard2787be81995-05-22 18:23:01 +00001594{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001595 SCROLLINFO info;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001596
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001597 if (descr->style & LBS_MULTICOLUMN) return 0;
1598 switch(LOWORD(wParam))
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +00001599 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001600 case SB_LINEUP:
1601 LISTBOX_SetTopItem( wnd, descr, descr->top_item - 1, TRUE );
1602 break;
1603 case SB_LINEDOWN:
1604 LISTBOX_SetTopItem( wnd, descr, descr->top_item + 1, TRUE );
1605 break;
1606 case SB_PAGEUP:
1607 LISTBOX_SetTopItem( wnd, descr, descr->top_item -
1608 LISTBOX_GetCurrentPageSize( wnd, descr ), TRUE );
1609 break;
1610 case SB_PAGEDOWN:
1611 LISTBOX_SetTopItem( wnd, descr, descr->top_item +
1612 LISTBOX_GetCurrentPageSize( wnd, descr ), TRUE );
1613 break;
1614 case SB_THUMBPOSITION:
1615 LISTBOX_SetTopItem( wnd, descr, HIWORD(wParam), TRUE );
1616 break;
1617 case SB_THUMBTRACK:
1618 info.cbSize = sizeof(info);
1619 info.fMask = SIF_TRACKPOS;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001620 GetScrollInfo( wnd->hwndSelf, SB_VERT, &info );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001621 LISTBOX_SetTopItem( wnd, descr, info.nTrackPos, TRUE );
1622 break;
1623 case SB_TOP:
1624 LISTBOX_SetTopItem( wnd, descr, 0, TRUE );
1625 break;
1626 case SB_BOTTOM:
1627 LISTBOX_SetTopItem( wnd, descr, descr->nb_items, TRUE );
1628 break;
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +00001629 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001630 return 0;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001631}
1632
Alexandre Julliardb817f4f1996-03-14 18:08:34 +00001633
Alexandre Julliard2787be81995-05-22 18:23:01 +00001634/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001635 * LISTBOX_HandleHScroll
Alexandre Julliard2787be81995-05-22 18:23:01 +00001636 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001637static LRESULT LISTBOX_HandleHScroll( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001638 WPARAM wParam, LPARAM lParam )
Alexandre Julliard2787be81995-05-22 18:23:01 +00001639{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001640 SCROLLINFO info;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001641 INT page;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001642
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001643 if (descr->style & LBS_MULTICOLUMN)
1644 {
1645 switch(LOWORD(wParam))
1646 {
1647 case SB_LINELEFT:
1648 LISTBOX_SetTopItem( wnd, descr, descr->top_item-descr->page_size,
1649 TRUE );
1650 break;
1651 case SB_LINERIGHT:
1652 LISTBOX_SetTopItem( wnd, descr, descr->top_item+descr->page_size,
1653 TRUE );
1654 break;
1655 case SB_PAGELEFT:
1656 page = descr->width / descr->column_width;
1657 if (page < 1) page = 1;
1658 LISTBOX_SetTopItem( wnd, descr,
1659 descr->top_item - page * descr->page_size, TRUE );
1660 break;
1661 case SB_PAGERIGHT:
1662 page = descr->width / descr->column_width;
1663 if (page < 1) page = 1;
1664 LISTBOX_SetTopItem( wnd, descr,
1665 descr->top_item + page * descr->page_size, TRUE );
1666 break;
1667 case SB_THUMBPOSITION:
1668 LISTBOX_SetTopItem( wnd, descr, HIWORD(wParam)*descr->page_size,
1669 TRUE );
1670 break;
1671 case SB_THUMBTRACK:
1672 info.cbSize = sizeof(info);
1673 info.fMask = SIF_TRACKPOS;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001674 GetScrollInfo( wnd->hwndSelf, SB_VERT, &info );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001675 LISTBOX_SetTopItem( wnd, descr, info.nTrackPos*descr->page_size,
1676 TRUE );
1677 break;
1678 case SB_LEFT:
1679 LISTBOX_SetTopItem( wnd, descr, 0, TRUE );
1680 break;
1681 case SB_RIGHT:
1682 LISTBOX_SetTopItem( wnd, descr, descr->nb_items, TRUE );
1683 break;
1684 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001685 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001686 else if (descr->horz_extent)
1687 {
1688 switch(LOWORD(wParam))
1689 {
1690 case SB_LINELEFT:
1691 LISTBOX_SetHorizontalPos( wnd, descr, descr->horz_pos - 1 );
1692 break;
1693 case SB_LINERIGHT:
1694 LISTBOX_SetHorizontalPos( wnd, descr, descr->horz_pos + 1 );
1695 break;
1696 case SB_PAGELEFT:
1697 LISTBOX_SetHorizontalPos( wnd, descr,
1698 descr->horz_pos - descr->width );
1699 break;
1700 case SB_PAGERIGHT:
1701 LISTBOX_SetHorizontalPos( wnd, descr,
1702 descr->horz_pos + descr->width );
1703 break;
1704 case SB_THUMBPOSITION:
1705 LISTBOX_SetHorizontalPos( wnd, descr, HIWORD(wParam) );
1706 break;
1707 case SB_THUMBTRACK:
1708 info.cbSize = sizeof(info);
1709 info.fMask = SIF_TRACKPOS;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001710 GetScrollInfo( wnd->hwndSelf, SB_HORZ, &info );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001711 LISTBOX_SetHorizontalPos( wnd, descr, info.nTrackPos );
1712 break;
1713 case SB_LEFT:
1714 LISTBOX_SetHorizontalPos( wnd, descr, 0 );
1715 break;
1716 case SB_RIGHT:
1717 LISTBOX_SetHorizontalPos( wnd, descr,
1718 descr->horz_extent - descr->width );
1719 break;
1720 }
1721 }
1722 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001723}
1724
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001725
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001726/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001727 * LISTBOX_HandleLButtonDown
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001728 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001729static LRESULT LISTBOX_HandleLButtonDown( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001730 WPARAM wParam, INT x, INT y )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001731{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001732 INT index = LISTBOX_GetItemFromPoint( wnd, descr, x, y );
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001733 TRACE("[%04x]: lbuttondown %d,%d item %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001734 wnd->hwndSelf, x, y, index );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001735 if (!descr->caret_on && (GetFocus() == wnd->hwndSelf)) return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001736 if (index != -1)
1737 {
1738 if (descr->style & LBS_EXTENDEDSEL)
1739 {
1740 if (!(wParam & MK_SHIFT)) descr->anchor_item = index;
1741 if (wParam & MK_CONTROL)
1742 {
1743 LISTBOX_SetCaretIndex( wnd, descr, index, FALSE );
1744 LISTBOX_SetSelection( wnd, descr, index,
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00001745 !descr->items[index].selected, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001746 }
1747 else LISTBOX_MoveCaret( wnd, descr, index, FALSE );
1748 }
1749 else
1750 {
1751 LISTBOX_MoveCaret( wnd, descr, index, FALSE );
1752 LISTBOX_SetSelection( wnd, descr, index,
1753 (!(descr->style & LBS_MULTIPLESEL) ||
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00001754 !descr->items[index].selected), FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001755 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001756 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001757
Alexandre Julliarda3960291999-02-26 11:11:13 +00001758 if( !descr->lphc ) SetFocus( wnd->hwndSelf );
1759 else SetFocus( (descr->lphc->hWndEdit) ? descr->lphc->hWndEdit
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001760 : descr->lphc->self->hwndSelf ) ;
1761
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00001762 descr->captured = TRUE;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001763 SetCapture( wnd->hwndSelf );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001764 if (index != -1 && !descr->lphc)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001765 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001766 if (descr->style & LBS_NOTIFY )
Alexandre Julliarda3960291999-02-26 11:11:13 +00001767 SendMessageA( descr->owner, WM_LBTRACKPOINT, index,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001768 MAKELPARAM( x, y ) );
1769 if (wnd->dwExStyle & WS_EX_DRAGDETECT)
1770 {
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00001771 POINT pt;
1772
1773 pt.x = x;
1774 pt.y = y;
1775
Alexandre Julliarda3960291999-02-26 11:11:13 +00001776 if (DragDetect( wnd->hwndSelf, pt ))
1777 SendMessageA( descr->owner, WM_BEGINDRAG, 0, 0 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001778 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001779 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001780 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001781}
1782
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001783
1784/***********************************************************************
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00001785 * LISTBOX_HandleLButtonUp
1786 */
1787static LRESULT LISTBOX_HandleLButtonUp( WND *wnd, LB_DESCR *descr )
1788{
1789 if (LISTBOX_Timer != LB_TIMER_NONE)
Alexandre Julliarda3960291999-02-26 11:11:13 +00001790 KillSystemTimer( wnd->hwndSelf, LB_TIMER_ID );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00001791 LISTBOX_Timer = LB_TIMER_NONE;
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00001792 if (descr->captured)
Alexandre Julliard33072e11997-06-29 18:08:02 +00001793 {
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00001794 descr->captured = FALSE;
1795 if (GetCapture() == wnd->hwndSelf) ReleaseCapture();
Alexandre Julliard33072e11997-06-29 18:08:02 +00001796 if (descr->style & LBS_NOTIFY)
1797 SEND_NOTIFICATION( wnd, descr, LBN_SELCHANGE );
1798 }
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00001799 return 0;
1800}
1801
1802
1803/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001804 * LISTBOX_HandleTimer
Alexandre Julliardade697e1995-11-26 13:59:11 +00001805 *
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001806 * Handle scrolling upon a timer event.
1807 * Return TRUE if scrolling should continue.
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001808 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001809static LRESULT LISTBOX_HandleTimer( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001810 INT index, TIMER_DIRECTION dir )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001811{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001812 switch(dir)
Alexandre Julliardade697e1995-11-26 13:59:11 +00001813 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001814 case LB_TIMER_UP:
1815 if (descr->top_item) index = descr->top_item - 1;
1816 else index = 0;
1817 break;
1818 case LB_TIMER_LEFT:
1819 if (descr->top_item) index -= descr->page_size;
1820 break;
1821 case LB_TIMER_DOWN:
1822 index = descr->top_item + LISTBOX_GetCurrentPageSize( wnd, descr );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001823 if (index == descr->focus_item) index++;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001824 if (index >= descr->nb_items) index = descr->nb_items - 1;
1825 break;
1826 case LB_TIMER_RIGHT:
1827 if (index + descr->page_size < descr->nb_items)
1828 index += descr->page_size;
1829 break;
1830 case LB_TIMER_NONE:
1831 break;
Alexandre Julliardade697e1995-11-26 13:59:11 +00001832 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001833 if (index == descr->focus_item) return FALSE;
1834 LISTBOX_MoveCaret( wnd, descr, index, FALSE );
1835 return TRUE;
1836}
Alexandre Julliardade697e1995-11-26 13:59:11 +00001837
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001838
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001839/***********************************************************************
1840 * LISTBOX_HandleSystemTimer
1841 *
1842 * WM_SYSTIMER handler.
1843 */
1844static LRESULT LISTBOX_HandleSystemTimer( WND *wnd, LB_DESCR *descr )
1845{
1846 if (!LISTBOX_HandleTimer( wnd, descr, descr->focus_item, LISTBOX_Timer ))
Alexandre Julliardade697e1995-11-26 13:59:11 +00001847 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001848 KillSystemTimer( wnd->hwndSelf, LB_TIMER_ID );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001849 LISTBOX_Timer = LB_TIMER_NONE;
Alexandre Julliardade697e1995-11-26 13:59:11 +00001850 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001851 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001852}
1853
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001854
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001855/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001856 * LISTBOX_HandleMouseMove
1857 *
1858 * WM_MOUSEMOVE handler.
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001859 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001860static void LISTBOX_HandleMouseMove( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001861 INT x, INT y )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001862{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001863 INT index;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001864 TIMER_DIRECTION dir;
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00001865
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00001866 if (!descr->captured) return;
1867
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001868 if (descr->style & LBS_MULTICOLUMN)
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00001869 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001870 if (y < 0) y = 0;
1871 else if (y >= descr->item_height * descr->page_size)
1872 y = descr->item_height * descr->page_size - 1;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001873
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001874 if (x < 0)
1875 {
1876 dir = LB_TIMER_LEFT;
1877 x = 0;
1878 }
1879 else if (x >= descr->width)
1880 {
1881 dir = LB_TIMER_RIGHT;
1882 x = descr->width - 1;
1883 }
1884 else dir = LB_TIMER_NONE; /* inside */
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00001885 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001886 else
1887 {
1888 if (y < 0) dir = LB_TIMER_UP; /* above */
1889 else if (y >= descr->height) dir = LB_TIMER_DOWN; /* below */
1890 else dir = LB_TIMER_NONE; /* inside */
1891 }
1892
1893 index = LISTBOX_GetItemFromPoint( wnd, descr, x, y );
1894 if (index == -1) index = descr->focus_item;
1895 if (!LISTBOX_HandleTimer( wnd, descr, index, dir )) dir = LB_TIMER_NONE;
1896
1897 /* Start/stop the system timer */
1898
1899 if (dir != LB_TIMER_NONE)
Alexandre Julliarda3960291999-02-26 11:11:13 +00001900 SetSystemTimer( wnd->hwndSelf, LB_TIMER_ID, LB_SCROLL_TIMEOUT, NULL);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001901 else if (LISTBOX_Timer != LB_TIMER_NONE)
Alexandre Julliarda3960291999-02-26 11:11:13 +00001902 KillSystemTimer( wnd->hwndSelf, LB_TIMER_ID );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001903 LISTBOX_Timer = dir;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001904}
1905
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001906
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001907/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001908 * LISTBOX_HandleKeyDown
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001909 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001910static LRESULT LISTBOX_HandleKeyDown( WND *wnd, LB_DESCR *descr, WPARAM wParam )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001911{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001912 INT caret = -1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001913 if (descr->style & LBS_WANTKEYBOARDINPUT)
1914 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001915 caret = SendMessageA( descr->owner, WM_VKEYTOITEM,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001916 MAKEWPARAM(LOWORD(wParam), descr->focus_item),
1917 wnd->hwndSelf );
1918 if (caret == -2) return 0;
1919 }
1920 if (caret == -1) switch(wParam)
1921 {
1922 case VK_LEFT:
1923 if (descr->style & LBS_MULTICOLUMN)
1924 {
1925 if (descr->focus_item >= descr->page_size)
1926 caret = descr->focus_item - descr->page_size;
1927 break;
1928 }
1929 /* fall through */
1930 case VK_UP:
1931 caret = descr->focus_item - 1;
1932 if (caret < 0) caret = 0;
1933 break;
1934 case VK_RIGHT:
1935 if (descr->style & LBS_MULTICOLUMN)
1936 {
1937 if (descr->focus_item + descr->page_size < descr->nb_items)
1938 caret = descr->focus_item + descr->page_size;
1939 break;
1940 }
1941 /* fall through */
1942 case VK_DOWN:
1943 caret = descr->focus_item + 1;
1944 if (caret >= descr->nb_items) caret = descr->nb_items - 1;
1945 break;
1946 case VK_PRIOR:
1947 if (descr->style & LBS_MULTICOLUMN)
1948 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001949 INT page = descr->width / descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001950 if (page < 1) page = 1;
1951 caret = descr->focus_item - (page * descr->page_size) + 1;
1952 }
1953 else caret = descr->focus_item-LISTBOX_GetCurrentPageSize(wnd,descr)+1;
1954 if (caret < 0) caret = 0;
1955 break;
1956 case VK_NEXT:
1957 if (descr->style & LBS_MULTICOLUMN)
1958 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001959 INT page = descr->width / descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001960 if (page < 1) page = 1;
1961 caret = descr->focus_item + (page * descr->page_size) - 1;
1962 }
1963 else caret = descr->focus_item+LISTBOX_GetCurrentPageSize(wnd,descr)-1;
1964 if (caret >= descr->nb_items) caret = descr->nb_items - 1;
1965 break;
1966 case VK_HOME:
1967 caret = 0;
1968 break;
1969 case VK_END:
1970 caret = descr->nb_items - 1;
1971 break;
1972 case VK_SPACE:
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00001973 if (descr->style & LBS_EXTENDEDSEL) caret = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001974 else if (descr->style & LBS_MULTIPLESEL)
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00001975 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001976 LISTBOX_SetSelection( wnd, descr, descr->focus_item,
1977 !descr->items[descr->focus_item].selected,
1978 (descr->style & LBS_NOTIFY) != 0 );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00001979 }
Alexandre Julliard7ff1c411997-05-25 13:58:18 +00001980 else if (descr->selected_item == -1)
1981 {
1982 LISTBOX_SetSelection( wnd, descr, descr->focus_item, TRUE,
1983 (descr->style & LBS_NOTIFY) != 0 );
1984 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001985 break;
1986 }
1987 if (caret >= 0)
1988 {
1989 if ((descr->style & LBS_EXTENDEDSEL) &&
Alexandre Julliarda3960291999-02-26 11:11:13 +00001990 !(GetKeyState( VK_SHIFT ) & 0x8000))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001991 descr->anchor_item = caret;
1992 LISTBOX_MoveCaret( wnd, descr, caret, TRUE );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00001993 if (descr->style & LBS_NOTIFY)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001994 {
1995 if( descr->lphc && CB_GETTYPE(descr->lphc) != CBS_SIMPLE )
1996 {
1997 /* make sure that combo parent doesn't hide us */
1998 descr->lphc->wState |= CBF_NOROLLUP;
1999 }
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002000 SEND_NOTIFICATION( wnd, descr, LBN_SELCHANGE );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002001 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002002 }
2003 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002004}
2005
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002006
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002007/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002008 * LISTBOX_HandleChar
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002009 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002010static LRESULT LISTBOX_HandleChar( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002011 WPARAM wParam )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002012{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002013 INT caret = -1;
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002014 char str[2];
2015
2016 str[0] = wParam & 0xff;
2017 str[1] = '\0';
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002018
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002019 if (descr->style & LBS_WANTKEYBOARDINPUT)
2020 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002021 caret = SendMessageA( descr->owner, WM_CHARTOITEM,
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002022 MAKEWPARAM(LOWORD(wParam), descr->focus_item),
2023 wnd->hwndSelf );
2024 if (caret == -2) return 0;
2025 }
2026 if (caret == -1)
2027 caret = LISTBOX_FindString( wnd, descr, descr->focus_item, str, FALSE);
2028 if (caret != -1)
2029 {
2030 LISTBOX_MoveCaret( wnd, descr, caret, TRUE );
2031 if (descr->style & LBS_NOTIFY)
2032 SEND_NOTIFICATION( wnd, descr, LBN_SELCHANGE );
2033 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002034 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002035}
2036
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002037
2038/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002039 * LISTBOX_Create
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002040 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002041static BOOL LISTBOX_Create( WND *wnd, LPHEADCOMBO lphc )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002042{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002043 LB_DESCR *descr;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002044 MEASUREITEMSTRUCT mis;
2045 RECT rect;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002046
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002047 if (!(descr = HeapAlloc( GetProcessHeap(), 0, sizeof(*descr) )))
2048 return FALSE;
2049 if (!(descr->heap = HeapCreate( 0, 0x10000, 0 )))
2050 {
2051 HeapFree( GetProcessHeap(), 0, descr );
2052 return FALSE;
2053 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00002054 GetClientRect( wnd->hwndSelf, &rect );
2055 descr->owner = GetParent( wnd->hwndSelf );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002056 descr->style = wnd->dwStyle;
2057 descr->width = rect.right - rect.left;
2058 descr->height = rect.bottom - rect.top;
2059 descr->items = NULL;
2060 descr->nb_items = 0;
2061 descr->top_item = 0;
2062 descr->selected_item = -1;
2063 descr->focus_item = 0;
2064 descr->anchor_item = -1;
2065 descr->item_height = 1;
2066 descr->page_size = 1;
2067 descr->column_width = 150;
2068 descr->horz_extent = (wnd->dwStyle & WS_HSCROLL) ? 1 : 0;
2069 descr->horz_pos = 0;
2070 descr->nb_tabs = 0;
2071 descr->tabs = NULL;
2072 descr->caret_on = TRUE;
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002073 descr->captured = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002074 descr->font = 0;
2075 descr->locale = 0; /* FIXME */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002076 descr->lphc = lphc;
2077
2078 if( lphc )
2079 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +00002080 TRACE_(combo)("[%04x]: resetting owner %04x -> %04x\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002081 wnd->hwndSelf, descr->owner, lphc->self->hwndSelf );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002082 descr->owner = lphc->self->hwndSelf;
2083 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00002084
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002085 *(LB_DESCR **)wnd->wExtra = descr;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002086
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002087/* if (wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) descr->style &= ~LBS_NOTIFY;
2088 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002089 if (descr->style & LBS_EXTENDEDSEL) descr->style |= LBS_MULTIPLESEL;
2090 if (descr->style & LBS_MULTICOLUMN) descr->style &= ~LBS_OWNERDRAWVARIABLE;
2091 if (descr->style & LBS_OWNERDRAWVARIABLE) descr->style |= LBS_NOINTEGRALHEIGHT;
2092 descr->item_height = LISTBOX_SetFont( wnd, descr, 0 );
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002093
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002094 if (descr->style & LBS_OWNERDRAWFIXED)
2095 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002096 if( descr->lphc && (descr->lphc->dwStyle & CBS_DROPDOWN))
2097 {
2098 /* WinWord gets VERY unhappy if we send WM_MEASUREITEM from here */
Francis Beaudetf585c611999-04-02 10:37:42 +00002099 descr->item_height = lphc->fixedOwnerDrawHeight;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002100 }
2101 else
2102 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002103 UINT id = (descr->lphc ) ? ID_CB_LISTBOX : wnd->wIDmenu;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002104
2105 mis.CtlType = ODT_LISTBOX;
2106 mis.CtlID = id;
2107 mis.itemID = -1;
2108 mis.itemWidth = 0;
2109 mis.itemData = 0;
2110 mis.itemHeight = descr->item_height;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002111 SendMessageA( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002112 descr->item_height = mis.itemHeight ? mis.itemHeight : 1;
2113 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002114 }
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002115
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002116 return TRUE;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002117}
2118
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002119
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002120/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002121 * LISTBOX_Destroy
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002122 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002123static BOOL LISTBOX_Destroy( WND *wnd, LB_DESCR *descr )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002124{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002125 LISTBOX_ResetContent( wnd, descr );
2126 HeapDestroy( descr->heap );
2127 HeapFree( GetProcessHeap(), 0, descr );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002128 wnd->wExtra[0] = 0;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00002129 return TRUE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002130}
2131
2132
2133/***********************************************************************
2134 * ListBoxWndProc
2135 */
Marcus Meissner9aded511999-05-01 10:23:45 +00002136static inline LRESULT WINAPI ListBoxWndProc_locked( WND* wnd, UINT msg,
2137 WPARAM wParam, LPARAM lParam )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002138{
2139 LRESULT ret;
2140 LB_DESCR *descr;
Marcus Meissner9aded511999-05-01 10:23:45 +00002141 HWND hwnd = wnd->hwndSelf;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002142
2143 if (!wnd) return 0;
2144 if (!(descr = *(LB_DESCR **)wnd->wExtra))
2145 {
2146 if (msg == WM_CREATE)
2147 {
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002148 if (!LISTBOX_Create( wnd, NULL ))
Marcus Meissner9aded511999-05-01 10:23:45 +00002149 return -1;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002150 TRACE("creating wnd=%04x descr=%p\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002151 hwnd, *(LB_DESCR **)wnd->wExtra );
Marcus Meissner9aded511999-05-01 10:23:45 +00002152 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002153 }
2154 /* Ignore all other messages before we get a WM_CREATE */
Marcus Meissner9aded511999-05-01 10:23:45 +00002155 return DefWindowProcA( hwnd, msg, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002156 }
2157
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002158 TRACE("[%04x]: msg %s wp %08x lp %08lx\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002159 wnd->hwndSelf, SPY_GetMsgName(msg), wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002160 switch(msg)
2161 {
2162 case LB_RESETCONTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002163 case LB_RESETCONTENT:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002164 LISTBOX_ResetContent( wnd, descr );
Marcus Meissner9aded511999-05-01 10:23:45 +00002165 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002166
2167 case LB_ADDSTRING16:
2168 if (HAS_STRINGS(descr)) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
2169 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002170 case LB_ADDSTRING:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002171 wParam = LISTBOX_FindStringPos( wnd, descr, (LPCSTR)lParam, FALSE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002172 return LISTBOX_InsertString( wnd, descr, wParam, (LPCSTR)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002173
2174 case LB_INSERTSTRING16:
2175 if (HAS_STRINGS(descr)) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002176 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002177 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002178 case LB_INSERTSTRING:
Marcus Meissner9aded511999-05-01 10:23:45 +00002179 return LISTBOX_InsertString( wnd, descr, wParam, (LPCSTR)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002180
2181 case LB_ADDFILE16:
2182 if (HAS_STRINGS(descr)) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
2183 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002184 case LB_ADDFILE:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002185 wParam = LISTBOX_FindFileStrPos( wnd, descr, (LPCSTR)lParam );
Marcus Meissner9aded511999-05-01 10:23:45 +00002186 return LISTBOX_InsertString( wnd, descr, wParam, (LPCSTR)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002187
2188 case LB_DELETESTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002189 case LB_DELETESTRING:
Marcus Meissner9aded511999-05-01 10:23:45 +00002190 return LISTBOX_RemoveItem( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002191
2192 case LB_GETITEMDATA16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002193 case LB_GETITEMDATA:
2194 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002195 return LB_ERR;
2196 return descr->items[wParam].data;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002197
2198 case LB_SETITEMDATA16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002199 case LB_SETITEMDATA:
2200 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002201 return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002202 descr->items[wParam].data = (DWORD)lParam;
Marcus Meissner9aded511999-05-01 10:23:45 +00002203 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002204
2205 case LB_GETCOUNT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002206 case LB_GETCOUNT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002207 return descr->nb_items;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002208
2209 case LB_GETTEXT16:
2210 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
2211 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002212 case LB_GETTEXT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002213 return LISTBOX_GetText( wnd, descr, wParam, (LPSTR)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002214
2215 case LB_GETTEXTLEN16:
2216 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002217 case LB_GETTEXTLEN:
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002218 if (wParam >= descr->nb_items)
Marcus Meissner9aded511999-05-01 10:23:45 +00002219 return LB_ERR;
2220 return (HAS_STRINGS(descr) ? strlen(descr->items[wParam].str)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002221 : sizeof(DWORD));
2222
2223 case LB_GETCURSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002224 case LB_GETCURSEL:
Francis Beaudet8730e451999-03-25 13:22:02 +00002225 if (descr->nb_items==0)
Marcus Meissner9aded511999-05-01 10:23:45 +00002226 return LB_ERR;
2227 /* else */
2228 if (descr->selected_item!=-1)
2229 return descr->selected_item;
2230 /* else */
2231 return descr->focus_item;
Lawson Whitney613092a1999-03-22 14:46:43 +00002232 /* otherwise, if the user tries to move the selection with the */
2233 /* arrow keys, we will give the application something to choke on */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002234 case LB_GETTOPINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002235 case LB_GETTOPINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002236 return descr->top_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002237
2238 case LB_GETITEMHEIGHT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002239 case LB_GETITEMHEIGHT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002240 return LISTBOX_GetItemHeight( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002241
2242 case LB_SETITEMHEIGHT16:
2243 lParam = LOWORD(lParam);
2244 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002245 case LB_SETITEMHEIGHT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002246 return LISTBOX_SetItemHeight( wnd, descr, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002247
Alexandre Julliarda3960291999-02-26 11:11:13 +00002248 case LB_ITEMFROMPOINT:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002249 {
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002250 POINT pt;
2251 RECT rect;
2252
2253 pt.x = LOWORD(lParam);
2254 pt.y = HIWORD(lParam);
2255 rect.left = 0;
2256 rect.top = 0;
2257 rect.right = descr->width;
2258 rect.bottom = descr->height;
2259
Marcus Meissner9aded511999-05-01 10:23:45 +00002260 return MAKELONG( LISTBOX_GetItemFromPoint(wnd, descr, pt.x, pt.y),
Gerard Patel777508a1999-05-08 12:35:17 +00002261 !PtInRect( &rect, pt ) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002262 }
2263
2264 case LB_SETCARETINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002265 case LB_SETCARETINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002266 return LISTBOX_SetCaretIndex( wnd, descr, wParam, !lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002267
2268 case LB_GETCARETINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002269 case LB_GETCARETINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002270 return descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002271
2272 case LB_SETTOPINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002273 case LB_SETTOPINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002274 return LISTBOX_SetTopItem( wnd, descr, wParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002275
2276 case LB_SETCOLUMNWIDTH16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002277 case LB_SETCOLUMNWIDTH:
Marcus Meissner9aded511999-05-01 10:23:45 +00002278 return LISTBOX_SetColumnWidth( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002279
2280 case LB_GETITEMRECT16:
2281 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002282 RECT rect;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002283 ret = LISTBOX_GetItemRect( wnd, descr, (INT16)wParam, &rect );
2284 CONV_RECT32TO16( &rect, (RECT16 *)PTR_SEG_TO_LIN(lParam) );
2285 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002286 return ret;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002287
Alexandre Julliarda3960291999-02-26 11:11:13 +00002288 case LB_GETITEMRECT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002289 return LISTBOX_GetItemRect( wnd, descr, wParam, (RECT *)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002290
2291 case LB_FINDSTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002292 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002293 if (HAS_STRINGS(descr)) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
2294 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002295 case LB_FINDSTRING:
Marcus Meissner9aded511999-05-01 10:23:45 +00002296 return LISTBOX_FindString( wnd, descr, wParam, (LPCSTR)lParam, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002297
2298 case LB_FINDSTRINGEXACT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002299 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002300 if (HAS_STRINGS(descr)) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
2301 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002302 case LB_FINDSTRINGEXACT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002303 return LISTBOX_FindString( wnd, descr, wParam, (LPCSTR)lParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002304
2305 case LB_SELECTSTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002306 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002307 if (HAS_STRINGS(descr)) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
2308 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002309 case LB_SELECTSTRING:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002310 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002311 INT index = LISTBOX_FindString( wnd, descr, wParam,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002312 (LPCSTR)lParam, FALSE );
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002313 if (index == LB_ERR)
Marcus Meissner9aded511999-05-01 10:23:45 +00002314 return LB_ERR;
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002315 LISTBOX_SetSelection( wnd, descr, index, TRUE, FALSE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002316 return index;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002317 }
2318
2319 case LB_GETSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002320 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002321 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002322 case LB_GETSEL:
2323 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002324 return LB_ERR;
2325 return descr->items[wParam].selected;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002326
2327 case LB_SETSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002328 lParam = (INT)(INT16)lParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002329 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002330 case LB_SETSEL:
Marcus Meissner9aded511999-05-01 10:23:45 +00002331 return LISTBOX_SetSelection( wnd, descr, lParam, wParam, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002332
2333 case LB_SETCURSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002334 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002335 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002336 case LB_SETCURSEL:
Alexandre Julliard638f1691999-01-17 16:32:32 +00002337 LISTBOX_SetCaretIndex( wnd, descr, wParam, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002338 return LISTBOX_SetSelection( wnd, descr, wParam, TRUE, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002339
2340 case LB_GETSELCOUNT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002341 case LB_GETSELCOUNT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002342 return LISTBOX_GetSelCount( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002343
2344 case LB_GETSELITEMS16:
Marcus Meissner9aded511999-05-01 10:23:45 +00002345 return LISTBOX_GetSelItems16( wnd, descr, wParam,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002346 (LPINT16)PTR_SEG_TO_LIN(lParam) );
2347
Alexandre Julliarda3960291999-02-26 11:11:13 +00002348 case LB_GETSELITEMS:
Marcus Meissner9aded511999-05-01 10:23:45 +00002349 return LISTBOX_GetSelItems( wnd, descr, wParam, (LPINT)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002350
2351 case LB_SELITEMRANGE16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002352 case LB_SELITEMRANGE:
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002353 if (LOWORD(lParam) <= HIWORD(lParam))
Marcus Meissner9aded511999-05-01 10:23:45 +00002354 return LISTBOX_SelectItemRange( wnd, descr, LOWORD(lParam),
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002355 HIWORD(lParam), wParam );
2356 else
Marcus Meissner9aded511999-05-01 10:23:45 +00002357 return LISTBOX_SelectItemRange( wnd, descr, HIWORD(lParam),
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002358 LOWORD(lParam), wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002359
2360 case LB_SELITEMRANGEEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002361 case LB_SELITEMRANGEEX:
2362 if ((INT)lParam >= (INT)wParam)
Marcus Meissner9aded511999-05-01 10:23:45 +00002363 return LISTBOX_SelectItemRange( wnd, descr, wParam, lParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002364 else
Marcus Meissner9aded511999-05-01 10:23:45 +00002365 return LISTBOX_SelectItemRange( wnd, descr, lParam, wParam, FALSE);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002366
2367 case LB_GETHORIZONTALEXTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002368 case LB_GETHORIZONTALEXTENT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002369 return descr->horz_extent;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002370
2371 case LB_SETHORIZONTALEXTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002372 case LB_SETHORIZONTALEXTENT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002373 return LISTBOX_SetHorizontalExtent( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002374
2375 case LB_GETANCHORINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002376 case LB_GETANCHORINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002377 return descr->anchor_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002378
2379 case LB_SETANCHORINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002380 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002381 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002382 case LB_SETANCHORINDEX:
2383 if (((INT)wParam < -1) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002384 return LB_ERR;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002385 descr->anchor_item = (INT)wParam;
Marcus Meissner9aded511999-05-01 10:23:45 +00002386 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002387
2388 case LB_DIR16:
Marcus Meissner9aded511999-05-01 10:23:45 +00002389 return LISTBOX_Directory( wnd, descr, wParam,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002390 (LPCSTR)PTR_SEG_TO_LIN(lParam), FALSE );
2391
Alexandre Julliarda3960291999-02-26 11:11:13 +00002392 case LB_DIR:
Marcus Meissner9aded511999-05-01 10:23:45 +00002393 return LISTBOX_Directory( wnd, descr, wParam, (LPCSTR)lParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002394
Alexandre Julliarda3960291999-02-26 11:11:13 +00002395 case LB_GETLOCALE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002396 return descr->locale;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002397
Alexandre Julliarda3960291999-02-26 11:11:13 +00002398 case LB_SETLOCALE:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002399 descr->locale = (LCID)wParam; /* FIXME: should check for valid lcid */
Marcus Meissner9aded511999-05-01 10:23:45 +00002400 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002401
Alexandre Julliarda3960291999-02-26 11:11:13 +00002402 case LB_INITSTORAGE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002403 return LISTBOX_InitStorage( wnd, descr, wParam, (DWORD)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002404
Alexandre Julliarda3960291999-02-26 11:11:13 +00002405 case LB_SETCOUNT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002406 return LISTBOX_SetCount( wnd, descr, (INT)wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002407
2408 case LB_SETTABSTOPS16:
Marcus Meissner9aded511999-05-01 10:23:45 +00002409 return LISTBOX_SetTabStops( wnd, descr, (INT)(INT16)wParam,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002410 (LPINT)PTR_SEG_TO_LIN(lParam), TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002411
Alexandre Julliarda3960291999-02-26 11:11:13 +00002412 case LB_SETTABSTOPS:
Marcus Meissner9aded511999-05-01 10:23:45 +00002413 return LISTBOX_SetTabStops( wnd, descr, wParam, (LPINT)lParam, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002414
2415 case LB_CARETON16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002416 case LB_CARETON:
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002417 if (descr->caret_on)
Marcus Meissner9aded511999-05-01 10:23:45 +00002418 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002419 descr->caret_on = TRUE;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002420 if ((descr->focus_item != -1) && (GetFocus() == wnd->hwndSelf))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002421 LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002422 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002423
2424 case LB_CARETOFF16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002425 case LB_CARETOFF:
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002426 if (!descr->caret_on)
Marcus Meissner9aded511999-05-01 10:23:45 +00002427 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002428 descr->caret_on = FALSE;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002429 if ((descr->focus_item != -1) && (GetFocus() == wnd->hwndSelf))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002430 LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002431 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002432
2433 case WM_DESTROY:
Marcus Meissner9aded511999-05-01 10:23:45 +00002434 return LISTBOX_Destroy( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002435
2436 case WM_ENABLE:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002437 InvalidateRect( hwnd, NULL, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002438 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002439
2440 case WM_SETREDRAW:
2441 LISTBOX_SetRedraw( wnd, descr, wParam != 0 );
Marcus Meissner9aded511999-05-01 10:23:45 +00002442 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002443
2444 case WM_GETDLGCODE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002445 return DLGC_WANTARROWS | DLGC_WANTCHARS;
2446
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002447 case WM_PAINT:
2448 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002449 PAINTSTRUCT ps;
2450 HDC hdc = ( wParam ) ? ((HDC)wParam)
2451 : BeginPaint( hwnd, &ps );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002452 ret = LISTBOX_Paint( wnd, descr, hdc );
Alexandre Julliarda3960291999-02-26 11:11:13 +00002453 if( !wParam ) EndPaint( hwnd, &ps );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002454 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002455 return ret;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002456 case WM_SIZE:
2457 LISTBOX_UpdateSize( wnd, descr );
Marcus Meissner9aded511999-05-01 10:23:45 +00002458 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002459 case WM_GETFONT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002460 return descr->font;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002461 case WM_SETFONT:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002462 LISTBOX_SetFont( wnd, descr, (HFONT)wParam );
2463 if (lParam) InvalidateRect( wnd->hwndSelf, 0, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002464 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002465 case WM_SETFOCUS:
2466 descr->caret_on = TRUE;
2467 if (descr->focus_item != -1)
2468 LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
2469 SEND_NOTIFICATION( wnd, descr, LBN_SETFOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002470 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002471 case WM_KILLFOCUS:
2472 if ((descr->focus_item != -1) && descr->caret_on)
2473 LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
2474 SEND_NOTIFICATION( wnd, descr, LBN_KILLFOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002475 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002476 case WM_HSCROLL:
Marcus Meissner9aded511999-05-01 10:23:45 +00002477 return LISTBOX_HandleHScroll( wnd, descr, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002478 case WM_VSCROLL:
Marcus Meissner9aded511999-05-01 10:23:45 +00002479 return LISTBOX_HandleVScroll( wnd, descr, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002480 case WM_LBUTTONDOWN:
Marcus Meissner9aded511999-05-01 10:23:45 +00002481 return LISTBOX_HandleLButtonDown( wnd, descr, wParam,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002482 (INT16)LOWORD(lParam),
2483 (INT16)HIWORD(lParam) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002484 case WM_LBUTTONDBLCLK:
2485 if (descr->style & LBS_NOTIFY)
2486 SEND_NOTIFICATION( wnd, descr, LBN_DBLCLK );
Marcus Meissner9aded511999-05-01 10:23:45 +00002487 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002488 case WM_MOUSEMOVE:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002489 if (GetCapture() == hwnd)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002490 LISTBOX_HandleMouseMove( wnd, descr, (INT16)LOWORD(lParam),
2491 (INT16)HIWORD(lParam) );
Marcus Meissner9aded511999-05-01 10:23:45 +00002492 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002493 case WM_LBUTTONUP:
Marcus Meissner9aded511999-05-01 10:23:45 +00002494 return LISTBOX_HandleLButtonUp( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002495 case WM_KEYDOWN:
Marcus Meissner9aded511999-05-01 10:23:45 +00002496 return LISTBOX_HandleKeyDown( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002497 case WM_CHAR:
Marcus Meissner9aded511999-05-01 10:23:45 +00002498 return LISTBOX_HandleChar( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002499 case WM_SYSTIMER:
Marcus Meissner9aded511999-05-01 10:23:45 +00002500 return LISTBOX_HandleSystemTimer( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002501 case WM_ERASEBKGND:
2502 if (IS_OWNERDRAW(descr))
2503 {
Luc Tourangeau89147991999-04-18 09:23:56 +00002504 RECT rect;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002505 HBRUSH hbrush = SendMessageA( descr->owner, WM_CTLCOLORLISTBOX,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002506 wParam, (LPARAM)wnd->hwndSelf );
Luc Tourangeau89147991999-04-18 09:23:56 +00002507 GetClientRect(hwnd, &rect);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002508 if (hbrush) FillRect( (HDC)wParam, &rect, hbrush );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002509 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002510 return 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002511 case WM_DROPFILES:
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002512 if( !descr->lphc )
Marcus Meissner9aded511999-05-01 10:23:45 +00002513 return SendMessageA( descr->owner, msg, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002514 break;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002515
2516 case WM_DROPOBJECT:
2517 case WM_QUERYDROPOBJECT:
2518 case WM_DRAGSELECT:
2519 case WM_DRAGMOVE:
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002520 if( !descr->lphc )
2521 {
2522 LPDRAGINFO dragInfo = (LPDRAGINFO)PTR_SEG_TO_LIN( (SEGPTR)lParam );
2523 dragInfo->l = LISTBOX_GetItemFromPoint( wnd, descr, dragInfo->pt.x,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002524 dragInfo->pt.y );
Marcus Meissner9aded511999-05-01 10:23:45 +00002525 return SendMessageA( descr->owner, msg, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002526 }
2527 break;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002528
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00002529 case WM_NCCREATE:
Alexandre Julliardd30dfd21998-09-27 18:28:36 +00002530 if (TWEAK_WineLook > WIN31_LOOK)
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +00002531 wnd->dwExStyle |= WS_EX_CLIENTEDGE;
Marcus Meissner9aded511999-05-01 10:23:45 +00002532 return DefWindowProcA( hwnd, msg, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002533 default:
2534 if ((msg >= WM_USER) && (msg < 0xc000))
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002535 WARN("[%04x]: unknown msg %04x wp %08x lp %08lx\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002536 hwnd, msg, wParam, lParam );
Marcus Meissner9aded511999-05-01 10:23:45 +00002537 return DefWindowProcA( hwnd, msg, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002538 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002539 return 0;
2540}
2541
2542/***********************************************************************
2543 * ListBoxWndProc
2544 *
2545 * This is just a wrapper for the real wndproc, it only does window locking
2546 * and unlocking.
2547 */
2548LRESULT WINAPI ListBoxWndProc( HWND hwnd, UINT msg,
2549 WPARAM wParam, LPARAM lParam )
2550{
2551 WND* wndPtr = WIN_FindWndPtr( hwnd );
2552 LRESULT res = ListBoxWndProc_locked(wndPtr,msg,wParam,lParam);
2553
2554 WIN_ReleaseWndPtr(wndPtr);
2555 return res;
Alexandre Julliard58199531994-04-21 01:20:00 +00002556}
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002557
2558/***********************************************************************
2559 * COMBO_Directory
2560 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002561LRESULT COMBO_Directory( LPHEADCOMBO lphc, UINT attrib, LPSTR dir, BOOL bLong)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002562{
2563 WND *wnd = WIN_FindWndPtr( lphc->hWndLBox );
2564
2565 if( wnd )
2566 {
2567 LB_DESCR *descr = *(LB_DESCR **)wnd->wExtra;
2568 if( descr )
2569 {
2570 LRESULT lRet = LISTBOX_Directory( wnd, descr, attrib, dir, bLong );
2571
Alexandre Julliarda3960291999-02-26 11:11:13 +00002572 RedrawWindow( lphc->self->hwndSelf, NULL, 0,
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002573 RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002574 WIN_ReleaseWndPtr(wnd);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002575 return lRet;
2576 }
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002577 WIN_ReleaseWndPtr(wnd);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002578 }
2579 return CB_ERR;
2580}
2581
2582/***********************************************************************
Marcus Meissner9aded511999-05-01 10:23:45 +00002583 * ComboLBWndProc_locked
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002584 *
Marcus Meissner9aded511999-05-01 10:23:45 +00002585 * The real combo listbox wndproc, but called with locked WND struct.
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002586 */
Marcus Meissner9aded511999-05-01 10:23:45 +00002587static inline LRESULT WINAPI ComboLBWndProc_locked( WND* wnd, UINT msg,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002588 WPARAM wParam, LPARAM lParam )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002589{
2590 LRESULT lRet = 0;
Marcus Meissner9aded511999-05-01 10:23:45 +00002591 HWND hwnd = wnd->hwndSelf;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002592
2593 if (wnd)
2594 {
2595 LB_DESCR *descr = *(LB_DESCR **)wnd->wExtra;
2596
Alexandre Julliard06c275a1999-05-02 14:32:27 +00002597 TRACE_(combo)("[%04x]: msg %s wp %08x lp %08lx\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002598 wnd->hwndSelf, SPY_GetMsgName(msg), wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002599
2600 if( descr || msg == WM_CREATE )
2601 {
2602 LPHEADCOMBO lphc = (descr) ? descr->lphc : NULL;
2603
2604 switch( msg )
2605 {
2606 case WM_CREATE:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002607#define lpcs ((LPCREATESTRUCTA)lParam)
Alexandre Julliard06c275a1999-05-02 14:32:27 +00002608 TRACE_(combo)("\tpassed parent handle = 0x%08x\n",
Alexandre Julliarda3960291999-02-26 11:11:13 +00002609 (UINT)lpcs->lpCreateParams);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002610
2611 lphc = (LPHEADCOMBO)(lpcs->lpCreateParams);
2612#undef lpcs
Marcus Meissner9aded511999-05-01 10:23:45 +00002613 return LISTBOX_Create( wnd, lphc );
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00002614 case WM_MOUSEMOVE:
2615 if ( (TWEAK_WineLook > WIN31_LOOK) &&
2616 (CB_GETTYPE(lphc) != CBS_SIMPLE) )
2617 {
2618 POINT mousePos;
2619 BOOL captured;
2620 RECT clientRect;
2621
2622 mousePos.x = (INT16)LOWORD(lParam);
2623 mousePos.y = (INT16)HIWORD(lParam);
2624
2625 /*
2626 * If we are in a dropdown combobox, we simulate that
2627 * the mouse is captured to show the tracking of the item.
2628 */
2629 captured = descr->captured;
2630 descr->captured = TRUE;
2631
2632 LISTBOX_HandleMouseMove( wnd,
2633 descr,
2634 mousePos.x, mousePos.y);
2635
2636 descr->captured = captured;
2637
2638 /*
2639 * However, when tracking, it is important that we do not
2640 * perform a selection if the cursor is outside the list.
2641 */
2642 GetClientRect(hwnd, &clientRect);
2643
2644 if (!PtInRect( &clientRect, mousePos ))
2645 {
2646 LISTBOX_MoveCaret( wnd, descr, -1, FALSE );
2647 }
2648
2649 return 0;
2650 }
2651 else
2652 {
2653 /*
2654 * If we are in Win3.1 look, go with the default behavior.
2655 */
2656 return ListBoxWndProc( hwnd, msg, wParam, lParam );
2657 }
2658 case WM_LBUTTONUP:
2659 if (TWEAK_WineLook > WIN31_LOOK)
2660 {
2661 POINT mousePos;
2662 RECT clientRect;
2663
2664 /*
2665 * If the mouse button "up" is not in the listbox,
2666 * we make sure there is no selection by re-selecting the
2667 * item that was selected when the listbox was made visible.
2668 */
2669 mousePos.x = (INT16)LOWORD(lParam);
2670 mousePos.y = (INT16)HIWORD(lParam);
2671
2672 GetClientRect(hwnd, &clientRect);
2673
2674 /*
2675 * When the user clicks outside the combobox and the focus
2676 * is lost, the owning combobox will send a fake buttonup with
2677 * 0xFFFFFFF as the mouse location, we must also revert the
2678 * selection to the original selection.
2679 */
2680 if ( (lParam == 0xFFFFFFFF) ||
2681 (!PtInRect( &clientRect, mousePos )) )
2682 {
2683 LISTBOX_MoveCaret( wnd,
2684 descr,
2685 lphc->droppedIndex,
2686 FALSE );
2687 }
2688 }
2689 return LISTBOX_HandleLButtonUp( wnd, descr );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002690 case WM_LBUTTONDOWN:
Marcus Meissner9aded511999-05-01 10:23:45 +00002691 return LISTBOX_HandleLButtonDown( wnd, descr, wParam,
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002692 (INT16)LOWORD(lParam), (INT16)HIWORD(lParam));
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002693 /* avoid activation at all costs */
2694
2695 case WM_MOUSEACTIVATE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002696 return MA_NOACTIVATE;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002697 case WM_NCACTIVATE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002698 return FALSE;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002699 case WM_KEYDOWN:
2700 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
2701 {
2702 /* for some reason(?) Windows makes it possible to
2703 * show/hide ComboLBox by sending it WM_KEYDOWNs */
2704
2705 if( (!(lphc->wState & CBF_EUI) && wParam == VK_F4) ||
2706 ( (lphc->wState & CBF_EUI) && !(lphc->wState & CBF_DROPPED)
2707 && (wParam == VK_DOWN || wParam == VK_UP)) )
2708 {
2709 COMBO_FlipListbox( lphc, FALSE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002710 return 0;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002711 }
2712 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002713 return LISTBOX_HandleKeyDown( wnd, descr, wParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002714
Alex Korobka311d3291999-01-01 18:40:02 +00002715 case LB_SETCURSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002716 case LB_SETCURSEL:
Alex Korobka311d3291999-01-01 18:40:02 +00002717 lRet = ListBoxWndProc( hwnd, msg, wParam, lParam );
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002718 lRet =(lRet == LB_ERR) ? lRet : descr->selected_item;
Marcus Meissner9aded511999-05-01 10:23:45 +00002719 return lRet;
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00002720 case WM_NCDESTROY:
2721 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
2722 lphc->hWndLBox = 0;
2723 /* fall through */
2724
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002725 default:
Marcus Meissner9aded511999-05-01 10:23:45 +00002726 return ListBoxWndProc( hwnd, msg, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002727 }
2728 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00002729 lRet = DefWindowProcA( hwnd, msg, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002730
Alexandre Julliard06c275a1999-05-02 14:32:27 +00002731 TRACE_(combo)("\t default on msg [%04x]\n", (UINT16)msg );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002732 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002733 return lRet;
2734}
2735
Marcus Meissner9aded511999-05-01 10:23:45 +00002736/***********************************************************************
2737 * ComboLBWndProc
2738 *
2739 * NOTE: in Windows, winproc address of the ComboLBox is the same
2740 * as that of the Listbox.
2741 *
2742 * This is just a wrapper for the real wndproc, it only does window locking
2743 * and unlocking.
2744 */
2745LRESULT WINAPI ComboLBWndProc( HWND hwnd, UINT msg,
2746 WPARAM wParam, LPARAM lParam )
2747{
2748 WND *wnd = WIN_FindWndPtr( hwnd );
2749 LRESULT res = ComboLBWndProc_locked(wnd,msg,wParam,lParam);
2750
2751 WIN_ReleaseWndPtr(wnd);
2752 return res;
2753}