blob: 252cff7e587e30f04fea68843f8507d6ce9b5d1f [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>
Jeremy Whited3e22d92000-02-10 19:03:02 +00009#include <stdio.h>
10#include "windef.h"
11#include "wingdi.h"
Alex Korobka311d3291999-01-01 18:40:02 +000012#include "wine/winuser16.h"
Nick Hollowayb9ce4fd1999-09-11 16:29:00 +000013#include "wine/winbase16.h"
Dmitry Timoshkov74620992001-01-09 21:51:04 +000014#include "wine/unicode.h"
Alex Korobka311d3291999-01-01 18:40:02 +000015#include "winuser.h"
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000016#include "winerror.h"
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000017#include "spy.h"
18#include "win.h"
Alexandre Julliarda41b2cf2001-01-15 20:12:55 +000019#include "user.h"
Alexandre Julliard91222da2000-12-10 23:01:33 +000020#include "controls.h"
Alexandre Julliard06c275a1999-05-02 14:32:27 +000021#include "debugtools.h"
Alexandre Julliard0e607781993-11-03 19:23:37 +000022
Jeremy Whited3e22d92000-02-10 19:03:02 +000023DEFAULT_DEBUG_CHANNEL(listbox);
24DECLARE_DEBUG_CHANNEL(combo);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000025
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000026/* Unimplemented yet:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000027 * - LBS_USETABSTOPS
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000028 * - Locale handling
Andreas Mohr85ba8792001-01-06 00:34:14 +000029 *
30 * Probably needs improvement:
31 * - LBS_NOSEL
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000032 */
Alexandre Julliarde2abbb11995-03-19 17:39:39 +000033
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000034/* Items array granularity */
35#define LB_ARRAY_GRANULARITY 16
Alexandre Julliard0e607781993-11-03 19:23:37 +000036
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000037/* Scrolling timeout in ms */
38#define LB_SCROLL_TIMEOUT 50
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000039
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000040/* Listbox system timer id */
41#define LB_TIMER_ID 2
Alexandre Julliardac9c9b01996-07-28 18:50:11 +000042
Gerard Patel41b07fb2000-06-15 00:07:20 +000043/* flag listbox changed while setredraw false - internal style */
44#define LBS_DISPLAYCHANGED 0x80000000
45
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000046/* Item structure */
47typedef struct
Alexandre Julliard2787be81995-05-22 18:23:01 +000048{
Dmitry Timoshkov74620992001-01-09 21:51:04 +000049 LPWSTR str; /* Item text */
Alexandre Julliarda3960291999-02-26 11:11:13 +000050 BOOL selected; /* Is item selected? */
51 UINT height; /* Item height (only for OWNERDRAWVARIABLE) */
Dmitry Timoshkov74620992001-01-09 21:51:04 +000052 DWORD data; /* User data */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000053} LB_ITEMDATA;
Alexandre Julliard2787be81995-05-22 18:23:01 +000054
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000055/* Listbox structure */
56typedef struct
Alexandre Julliard2787be81995-05-22 18:23:01 +000057{
Alexandre Julliarda3960291999-02-26 11:11:13 +000058 HWND owner; /* Owner window to send notifications to */
59 UINT style; /* Window style */
60 INT width; /* Window width */
61 INT height; /* Window height */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000062 LB_ITEMDATA *items; /* Array of items */
Alexandre Julliarda3960291999-02-26 11:11:13 +000063 INT nb_items; /* Number of items */
64 INT top_item; /* Top visible item */
65 INT selected_item; /* Selected item */
66 INT focus_item; /* Item that has the focus */
67 INT anchor_item; /* Anchor item for extended selection */
68 INT item_height; /* Default item height */
69 INT page_size; /* Items per listbox page */
70 INT column_width; /* Column width for multi-column listboxes */
71 INT horz_extent; /* Horizontal extent (0 if no hscroll) */
72 INT horz_pos; /* Horizontal position */
73 INT nb_tabs; /* Number of tabs in array */
74 INT *tabs; /* Array of tabs */
75 BOOL caret_on; /* Is caret on? */
Luc Tourangeau5ee117b1999-04-04 12:48:21 +000076 BOOL captured; /* Is mouse captured? */
Alexandre Julliardab2f43f2000-05-26 22:28:34 +000077 BOOL in_focus;
Alexandre Julliarda3960291999-02-26 11:11:13 +000078 HFONT font; /* Current font */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000079 LCID locale; /* Current locale for string comparisons */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000080 LPHEADCOMBO lphc; /* ComboLBox */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000081} LB_DESCR;
Alexandre Julliard2787be81995-05-22 18:23:01 +000082
Alexandre Julliardfa68b751995-04-03 16:55:37 +000083
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000084#define IS_OWNERDRAW(descr) \
85 ((descr)->style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE))
Alexandre Julliardb817f4f1996-03-14 18:08:34 +000086
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000087#define HAS_STRINGS(descr) \
88 (!IS_OWNERDRAW(descr) || ((descr)->style & LBS_HASSTRINGS))
Alexandre Julliard2787be81995-05-22 18:23:01 +000089
Gerard Patelc9a6d501999-07-25 13:03:17 +000090
91#define IS_MULTISELECT(descr) \
92 ((descr)->style & LBS_MULTIPLESEL || ((descr)->style & LBS_EXTENDEDSEL))
93
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000094#define SEND_NOTIFICATION(wnd,descr,code) \
Dmitry Timoshkov74620992001-01-09 21:51:04 +000095 (SendMessageW( (descr)->owner, WM_COMMAND, \
Serge Ivanov07917e42000-06-07 03:46:57 +000096 MAKEWPARAM((wnd)->wIDmenu, (code)), (wnd)->hwndSelf ))
Alexandre Julliardfa68b751995-04-03 16:55:37 +000097
Gerard Patelc9a6d501999-07-25 13:03:17 +000098#define ISWIN31 (LOWORD(GetVersion()) == 0x0a03)
99
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000100/* Current timer status */
101typedef enum
Alexandre Julliardfa68b751995-04-03 16:55:37 +0000102{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000103 LB_TIMER_NONE,
104 LB_TIMER_UP,
105 LB_TIMER_LEFT,
106 LB_TIMER_DOWN,
107 LB_TIMER_RIGHT
108} TIMER_DIRECTION;
Alexandre Julliardfa68b751995-04-03 16:55:37 +0000109
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000110static TIMER_DIRECTION LISTBOX_Timer = LB_TIMER_NONE;
111
Alexandre Julliard91222da2000-12-10 23:01:33 +0000112static LRESULT WINAPI ComboLBWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000113static LRESULT WINAPI ComboLBWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
Alexandre Julliard91222da2000-12-10 23:01:33 +0000114static LRESULT WINAPI ListBoxWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000115static LRESULT WINAPI ListBoxWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
Alexandre Julliard91222da2000-12-10 23:01:33 +0000116
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000117static LRESULT LISTBOX_GetItemRect( LB_DESCR *descr, INT index, RECT *rect );
Alexandre Julliard91222da2000-12-10 23:01:33 +0000118
119/*********************************************************************
120 * listbox class descriptor
121 */
122const struct builtin_class_descr LISTBOX_builtin_class =
123{
124 "ListBox", /* name */
125 CS_GLOBALCLASS | CS_DBLCLKS /*| CS_PARENTDC*/, /* style */
126 ListBoxWndProcA, /* procA */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000127 ListBoxWndProcW, /* procW */
Alexandre Julliard91222da2000-12-10 23:01:33 +0000128 sizeof(LB_DESCR *), /* extra */
129 IDC_ARROWA, /* cursor */
130 0 /* brush */
131};
132
133
134/*********************************************************************
135 * combolbox class descriptor
136 */
137const struct builtin_class_descr COMBOLBOX_builtin_class =
138{
139 "ComboLBox", /* name */
140 CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS, /* style */
141 ComboLBWndProcA, /* procA */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000142 ComboLBWndProcW, /* procW */
Alexandre Julliard91222da2000-12-10 23:01:33 +0000143 sizeof(LB_DESCR *), /* extra */
144 IDC_ARROWA, /* cursor */
145 0 /* brush */
146};
147
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000148
149/***********************************************************************
150 * LISTBOX_Dump
151 */
152void LISTBOX_Dump( WND *wnd )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000153{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000154 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000155 LB_ITEMDATA *item;
156 LB_DESCR *descr = *(LB_DESCR **)wnd->wExtra;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000157
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000158 TRACE( "Listbox:\n" );
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000159 TRACE( "hwnd=%04x descr=%08x items=%d top=%d\n",
160 wnd->hwndSelf, (UINT)descr, descr->nb_items,
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000161 descr->top_item );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000162 for (i = 0, item = descr->items; i < descr->nb_items; i++, item++)
163 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000164 TRACE( "%4d: %-40s %d %08lx %3d\n",
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000165 i, debugstr_w(item->str), item->selected, item->data, item->height );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000166 }
Alexandre Julliard2787be81995-05-22 18:23:01 +0000167}
168
169
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000170/***********************************************************************
171 * LISTBOX_GetCurrentPageSize
172 *
173 * Return the current page size
174 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000175static INT LISTBOX_GetCurrentPageSize( LB_DESCR *descr )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000176{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000177 INT i, height;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000178 if (!(descr->style & LBS_OWNERDRAWVARIABLE)) return descr->page_size;
179 for (i = descr->top_item, height = 0; i < descr->nb_items; i++)
180 {
181 if ((height += descr->items[i].height) > descr->height) break;
182 }
183 if (i == descr->top_item) return 1;
184 else return i - descr->top_item;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000185}
186
187
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000188/***********************************************************************
189 * LISTBOX_GetMaxTopIndex
190 *
191 * Return the maximum possible index for the top of the listbox.
192 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000193static INT LISTBOX_GetMaxTopIndex( LB_DESCR *descr )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000194{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000195 INT max, page;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000196
197 if (descr->style & LBS_OWNERDRAWVARIABLE)
198 {
199 page = descr->height;
200 for (max = descr->nb_items - 1; max >= 0; max--)
201 if ((page -= descr->items[max].height) < 0) break;
202 if (max < descr->nb_items - 1) max++;
203 }
204 else if (descr->style & LBS_MULTICOLUMN)
205 {
206 if ((page = descr->width / descr->column_width) < 1) page = 1;
207 max = (descr->nb_items + descr->page_size - 1) / descr->page_size;
208 max = (max - page) * descr->page_size;
209 }
210 else
211 {
212 max = descr->nb_items - descr->page_size;
213 }
214 if (max < 0) max = 0;
215 return max;
216}
217
218
219/***********************************************************************
220 * LISTBOX_UpdateScroll
221 *
222 * Update the scrollbars. Should be called whenever the content
223 * of the listbox changes.
224 */
225static void LISTBOX_UpdateScroll( WND *wnd, LB_DESCR *descr )
226{
227 SCROLLINFO info;
228
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000229 /* Check the listbox scroll bar flags individually before we call
230 SetScrollInfo otherwise when the listbox style is WS_HSCROLL and
231 no WS_VSCROLL, we end up with an uninitialized, visible horizontal
232 scroll bar when we do not need one.
233 if (!(descr->style & WS_VSCROLL)) return;
234 */
235
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000236 /* It is important that we check descr->style, and not wnd->dwStyle,
237 for WS_VSCROLL, as the former is exactly the one passed in
238 argument to CreateWindow.
239 In Windows (and from now on in Wine :) a listbox created
240 with such a style (no WS_SCROLL) does not update
241 the scrollbar with listbox-related data, thus letting
242 the programmer use it for his/her own purposes. */
243
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000244 if (descr->style & LBS_NOREDRAW) return;
245 info.cbSize = sizeof(info);
246
247 if (descr->style & LBS_MULTICOLUMN)
248 {
249 info.nMin = 0;
250 info.nMax = (descr->nb_items - 1) / descr->page_size;
251 info.nPos = descr->top_item / descr->page_size;
252 info.nPage = descr->width / descr->column_width;
253 if (info.nPage < 1) info.nPage = 1;
254 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
255 if (descr->style & LBS_DISABLENOSCROLL)
256 info.fMask |= SIF_DISABLENOSCROLL;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000257 if (descr->style & WS_HSCROLL)
258 SetScrollInfo( wnd->hwndSelf, SB_HORZ, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000259 info.nMax = 0;
260 info.fMask = SIF_RANGE;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000261 if (descr->style & WS_VSCROLL)
262 SetScrollInfo( wnd->hwndSelf, SB_VERT, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000263 }
264 else
265 {
266 info.nMin = 0;
267 info.nMax = descr->nb_items - 1;
268 info.nPos = descr->top_item;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000269 info.nPage = LISTBOX_GetCurrentPageSize( descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000270 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
271 if (descr->style & LBS_DISABLENOSCROLL)
272 info.fMask |= SIF_DISABLENOSCROLL;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000273 if (descr->style & WS_VSCROLL)
274 SetScrollInfo( wnd->hwndSelf, SB_VERT, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000275
276 if (descr->horz_extent)
277 {
278 info.nMin = 0;
279 info.nMax = descr->horz_extent - 1;
280 info.nPos = descr->horz_pos;
281 info.nPage = descr->width;
282 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
283 if (descr->style & LBS_DISABLENOSCROLL)
284 info.fMask |= SIF_DISABLENOSCROLL;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000285 if (descr->style & WS_HSCROLL)
286 SetScrollInfo( wnd->hwndSelf, SB_HORZ, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000287 }
288 }
289}
290
291
292/***********************************************************************
293 * LISTBOX_SetTopItem
294 *
295 * Set the top item of the listbox, scrolling up or down if necessary.
296 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000297static LRESULT LISTBOX_SetTopItem( WND *wnd, LB_DESCR *descr, INT index,
298 BOOL scroll )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000299{
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000300 INT max = LISTBOX_GetMaxTopIndex( descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000301 if (index > max) index = max;
302 if (index < 0) index = 0;
303 if (descr->style & LBS_MULTICOLUMN) index -= index % descr->page_size;
304 if (descr->top_item == index) return LB_OKAY;
305 if (descr->style & LBS_MULTICOLUMN)
306 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000307 INT diff = (descr->top_item - index) / descr->page_size * descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000308 if (scroll && (abs(diff) < descr->width))
Alexandre Julliarda3960291999-02-26 11:11:13 +0000309 ScrollWindowEx( wnd->hwndSelf, diff, 0, NULL, NULL, 0, NULL,
NF Stevens762f18d1999-01-24 19:02:16 +0000310 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
311
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000312 else
313 scroll = FALSE;
314 }
315 else if (scroll)
316 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000317 INT diff;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000318 if (descr->style & LBS_OWNERDRAWVARIABLE)
319 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000320 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000321 diff = 0;
322 if (index > descr->top_item)
323 {
324 for (i = index - 1; i >= descr->top_item; i--)
325 diff -= descr->items[i].height;
326 }
327 else
328 {
329 for (i = index; i < descr->top_item; i++)
330 diff += descr->items[i].height;
331 }
332 }
333 else
334 diff = (descr->top_item - index) * descr->item_height;
335
336 if (abs(diff) < descr->height)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000337 ScrollWindowEx( wnd->hwndSelf, 0, diff, NULL, NULL, 0, NULL,
NF Stevens762f18d1999-01-24 19:02:16 +0000338 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000339 else
340 scroll = FALSE;
341 }
Alexandre Julliarda3960291999-02-26 11:11:13 +0000342 if (!scroll) InvalidateRect( wnd->hwndSelf, NULL, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000343 descr->top_item = index;
344 LISTBOX_UpdateScroll( wnd, descr );
345 return LB_OKAY;
346}
347
348
349/***********************************************************************
350 * LISTBOX_UpdatePage
351 *
352 * Update the page size. Should be called when the size of
353 * the client area or the item height changes.
354 */
355static void LISTBOX_UpdatePage( WND *wnd, LB_DESCR *descr )
356{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000357 INT page_size;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000358
Paul Quinn75722071999-05-22 18:45:06 +0000359 if ((descr->item_height == 0) || (page_size = descr->height / descr->item_height) < 1)
360 page_size = 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000361 if (page_size == descr->page_size) return;
362 descr->page_size = page_size;
363 if (descr->style & LBS_MULTICOLUMN)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000364 InvalidateRect( wnd->hwndSelf, NULL, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000365 LISTBOX_SetTopItem( wnd, descr, descr->top_item, FALSE );
366}
367
368
369/***********************************************************************
370 * LISTBOX_UpdateSize
371 *
372 * Update the size of the listbox. Should be called when the size of
373 * the client area changes.
374 */
375static void LISTBOX_UpdateSize( WND *wnd, LB_DESCR *descr )
376{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000377 RECT rect;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000378
Alexandre Julliarda3960291999-02-26 11:11:13 +0000379 GetClientRect( wnd->hwndSelf, &rect );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000380 descr->width = rect.right - rect.left;
381 descr->height = rect.bottom - rect.top;
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +0000382 if (!(descr->style & LBS_NOINTEGRALHEIGHT) && !(descr->style & LBS_OWNERDRAWVARIABLE))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000383 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000384 INT remaining;
Mike McCormack5ae1c392000-09-09 19:39:24 +0000385
386 if(descr->item_height != 0)
387 remaining = descr->height % descr->item_height;
388 else
389 remaining = 0;
Gerard Patelcef12532000-08-01 20:48:40 +0000390 if ((descr->height > descr->item_height) && remaining)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000391 {
Gerard Patelcef12532000-08-01 20:48:40 +0000392 if (!(wnd->flags & WIN_ISWIN32))
393 { /* give a margin for error to 16 bits programs - if we need
394 less than the height of the nonclient area, round to the
395 *next* number of items */
396 int ncheight = wnd->rectWindow.bottom - wnd->rectWindow.top - descr->height;
397 if ((descr->item_height - remaining) <= ncheight)
398 remaining = remaining - descr->item_height;
399 }
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000400 TRACE("[%04x]: changing height %d -> %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000401 wnd->hwndSelf, descr->height,
Gerard Patelcef12532000-08-01 20:48:40 +0000402 descr->height - remaining );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000403 SetWindowPos( wnd->hwndSelf, 0, 0, 0,
Alexandre Julliard01d63461997-01-20 19:43:45 +0000404 wnd->rectWindow.right - wnd->rectWindow.left,
Gerard Patelcef12532000-08-01 20:48:40 +0000405 wnd->rectWindow.bottom - wnd->rectWindow.top - remaining,
Alexandre Julliard01d63461997-01-20 19:43:45 +0000406 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000407 return;
408 }
409 }
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000410 TRACE("[%04x]: new size = %d,%d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000411 wnd->hwndSelf, descr->width, descr->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000412 LISTBOX_UpdatePage( wnd, descr );
413 LISTBOX_UpdateScroll( wnd, descr );
Louis Philippe Gagnon956c8472000-12-13 21:26:45 +0000414
415 /* Invalidate the focused item so it will be repainted correctly */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000416 if (LISTBOX_GetItemRect( descr, descr->focus_item, &rect ) == 1)
Louis Philippe Gagnon956c8472000-12-13 21:26:45 +0000417 {
418 InvalidateRect( wnd->hwndSelf, &rect, FALSE );
419 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000420}
421
422
423/***********************************************************************
424 * LISTBOX_GetItemRect
425 *
426 * Get the rectangle enclosing an item, in listbox client coordinates.
427 * Return 1 if the rectangle is (partially) visible, 0 if hidden, -1 on error.
428 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000429static LRESULT LISTBOX_GetItemRect( LB_DESCR *descr, INT index, RECT *rect )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000430{
431 /* Index <= 0 is legal even on empty listboxes */
432 if (index && (index >= descr->nb_items)) return -1;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000433 SetRect( rect, 0, 0, descr->width, descr->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000434 if (descr->style & LBS_MULTICOLUMN)
435 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000436 INT col = (index / descr->page_size) -
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000437 (descr->top_item / descr->page_size);
438 rect->left += col * descr->column_width;
439 rect->right = rect->left + descr->column_width;
440 rect->top += (index % descr->page_size) * descr->item_height;
441 rect->bottom = rect->top + descr->item_height;
442 }
443 else if (descr->style & LBS_OWNERDRAWVARIABLE)
444 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000445 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000446 rect->right += descr->horz_pos;
Alexandre Julliard349a9531997-02-02 19:01:52 +0000447 if ((index >= 0) && (index < descr->nb_items))
448 {
449 if (index < descr->top_item)
450 {
451 for (i = descr->top_item-1; i >= index; i--)
452 rect->top -= descr->items[i].height;
453 }
454 else
455 {
456 for (i = descr->top_item; i < index; i++)
457 rect->top += descr->items[i].height;
458 }
459 rect->bottom = rect->top + descr->items[index].height;
460
461 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000462 }
463 else
464 {
465 rect->top += (index - descr->top_item) * descr->item_height;
466 rect->bottom = rect->top + descr->item_height;
467 rect->right += descr->horz_pos;
468 }
469
470 return ((rect->left < descr->width) && (rect->right > 0) &&
471 (rect->top < descr->height) && (rect->bottom > 0));
472}
473
474
475/***********************************************************************
476 * LISTBOX_GetItemFromPoint
477 *
478 * Return the item nearest from point (x,y) (in client coordinates).
479 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000480static INT LISTBOX_GetItemFromPoint( LB_DESCR *descr, INT x, INT y )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000481{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000482 INT index = descr->top_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000483
484 if (!descr->nb_items) return -1; /* No items */
485 if (descr->style & LBS_OWNERDRAWVARIABLE)
486 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000487 INT pos = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000488 if (y >= 0)
489 {
490 while (index < descr->nb_items)
491 {
492 if ((pos += descr->items[index].height) > y) break;
493 index++;
494 }
495 }
496 else
497 {
498 while (index > 0)
499 {
500 index--;
501 if ((pos -= descr->items[index].height) <= y) break;
502 }
503 }
504 }
505 else if (descr->style & LBS_MULTICOLUMN)
506 {
507 if (y >= descr->item_height * descr->page_size) return -1;
508 if (y >= 0) index += y / descr->item_height;
509 if (x >= 0) index += (x / descr->column_width) * descr->page_size;
510 else index -= (((x + 1) / descr->column_width) - 1) * descr->page_size;
511 }
512 else
513 {
514 index += (y / descr->item_height);
515 }
516 if (index < 0) return 0;
517 if (index >= descr->nb_items) return -1;
518 return index;
519}
520
521
522/***********************************************************************
523 * LISTBOX_PaintItem
524 *
525 * Paint an item.
526 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000527static void LISTBOX_PaintItem( WND *wnd, LB_DESCR *descr, HDC hdc,
Gerard Patel8caa4072000-09-24 19:29:18 +0000528 const RECT *rect, INT index, UINT action, BOOL ignoreFocus )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000529{
530 LB_ITEMDATA *item = NULL;
531 if (index < descr->nb_items) item = &descr->items[index];
532
533 if (IS_OWNERDRAW(descr))
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000534 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000535 DRAWITEMSTRUCT dis;
Gerard Patel9788ba62000-07-16 15:39:37 +0000536 RECT r;
537 HRGN hrgn;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000538
Marcus Meissner9ad90171999-01-20 14:08:00 +0000539 if (!item)
540 {
541 if (action == ODA_FOCUS)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000542 DrawFocusRect( hdc, rect );
Marcus Meissner9ad90171999-01-20 14:08:00 +0000543 else
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000544 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 +0000545 return;
546 }
Gerard Patel9788ba62000-07-16 15:39:37 +0000547
548 /* some programs mess with the clipping region when
549 drawing the item, *and* restore the previous region
550 after they are done, so a region has better to exist
551 else everything ends clipped */
552 GetClientRect(wnd->hwndSelf, &r);
553 hrgn = CreateRectRgnIndirect(&r);
554 SelectClipRgn( hdc, hrgn);
555 DeleteObject( hrgn );
556
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000557 dis.CtlType = ODT_LISTBOX;
Serge Ivanov07917e42000-06-07 03:46:57 +0000558 dis.CtlID = wnd->wIDmenu;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000559 dis.hwndItem = wnd->hwndSelf;
560 dis.itemAction = action;
561 dis.hDC = hdc;
562 dis.itemID = index;
563 dis.itemState = 0;
564 if (item && item->selected) dis.itemState |= ODS_SELECTED;
Gerard Patel8caa4072000-09-24 19:29:18 +0000565 if (!ignoreFocus && (descr->focus_item == index) &&
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000566 (descr->caret_on) &&
Alexandre Julliardab2f43f2000-05-26 22:28:34 +0000567 (descr->in_focus)) dis.itemState |= ODS_FOCUS;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000568 if (wnd->dwStyle & WS_DISABLED) dis.itemState |= ODS_DISABLED;
569 dis.itemData = item ? item->data : 0;
570 dis.rcItem = *rect;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000571 TRACE("[%04x]: drawitem %d (%s) action=%02x "
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000572 "state=%02x rect=%d,%d-%d,%d\n",
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000573 wnd->hwndSelf, index, item ? debugstr_w(item->str) : "", action,
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000574 dis.itemState, rect->left, rect->top,
575 rect->right, rect->bottom );
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000576 SendMessageW(descr->owner, WM_DRAWITEM, wnd->wIDmenu, (LPARAM)&dis);
Alexandre Julliard2787be81995-05-22 18:23:01 +0000577 }
578 else
Alexandre Julliardac9c9b01996-07-28 18:50:11 +0000579 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000580 COLORREF oldText = 0, oldBk = 0;
581
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000582 if (action == ODA_FOCUS)
583 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000584 DrawFocusRect( hdc, rect );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000585 return;
586 }
587 if (item && item->selected)
588 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000589 oldBk = SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
590 oldText = SetTextColor( hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000591 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000592
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000593 TRACE("[%04x]: painting %d (%s) action=%02x "
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000594 "rect=%d,%d-%d,%d\n",
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000595 wnd->hwndSelf, index, item ? debugstr_w(item->str) : "", action,
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000596 rect->left, rect->top, rect->right, rect->bottom );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000597 if (!item)
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000598 ExtTextOutW( hdc, rect->left + 1, rect->top,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000599 ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000600 else if (!(descr->style & LBS_USETABSTOPS))
601 ExtTextOutW( hdc, rect->left + 1, rect->top,
602 ETO_OPAQUE | ETO_CLIPPED, rect, item->str,
603 strlenW(item->str), NULL );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000604 else
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000605 {
606 /* Output empty string to paint background in the full width. */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000607 ExtTextOutW( hdc, rect->left + 1, rect->top,
608 ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
609 TabbedTextOutW( hdc, rect->left + 1 , rect->top,
610 item->str, strlenW(item->str),
611 descr->nb_tabs, descr->tabs, 0);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000612 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000613 if (item && item->selected)
614 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000615 SetBkColor( hdc, oldBk );
616 SetTextColor( hdc, oldText );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000617 }
Gerard Patel8caa4072000-09-24 19:29:18 +0000618 if (!ignoreFocus && (descr->focus_item == index) &&
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000619 (descr->caret_on) &&
Alexandre Julliardab2f43f2000-05-26 22:28:34 +0000620 (descr->in_focus)) DrawFocusRect( hdc, rect );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000621 }
Alexandre Julliard2787be81995-05-22 18:23:01 +0000622}
623
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000624
625/***********************************************************************
626 * LISTBOX_SetRedraw
627 *
628 * Change the redraw flag.
629 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000630static void LISTBOX_SetRedraw( WND *wnd, LB_DESCR *descr, BOOL on )
Alexandre Julliardac9c9b01996-07-28 18:50:11 +0000631{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000632 if (on)
633 {
634 if (!(descr->style & LBS_NOREDRAW)) return;
635 descr->style &= ~LBS_NOREDRAW;
Gerard Patel41b07fb2000-06-15 00:07:20 +0000636 if (descr->style & LBS_DISPLAYCHANGED)
637 { /* page was changed while setredraw false, refresh automatically */
638 InvalidateRect(wnd->hwndSelf, NULL, TRUE);
639 if ((descr->top_item + descr->page_size) > descr->nb_items)
640 { /* reset top of page if less than number of items/page */
641 descr->top_item = descr->nb_items - descr->page_size;
642 if (descr->top_item < 0) descr->top_item = 0;
643 }
644 descr->style &= ~LBS_DISPLAYCHANGED;
645 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000646 LISTBOX_UpdateScroll( wnd, descr );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000647 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000648 else descr->style |= LBS_NOREDRAW;
649}
Alexandre Julliard2787be81995-05-22 18:23:01 +0000650
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000651
652/***********************************************************************
653 * LISTBOX_RepaintItem
654 *
655 * Repaint a single item synchronously.
656 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000657static void LISTBOX_RepaintItem( WND *wnd, LB_DESCR *descr, INT index,
658 UINT action )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000659{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000660 HDC hdc;
661 RECT rect;
662 HFONT oldFont = 0;
663 HBRUSH hbrush, oldBrush = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000664
Francois Boisvert428d2981999-05-08 09:33:53 +0000665 /* Do not repaint the item if the item is not visible */
Gerard Patel41b07fb2000-06-15 00:07:20 +0000666 if (!IsWindowVisible(wnd->hwndSelf)) return;
667 if (descr->style & LBS_NOREDRAW)
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000668 {
Gerard Patel41b07fb2000-06-15 00:07:20 +0000669 descr->style |= LBS_DISPLAYCHANGED;
670 return;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000671 }
672 if (LISTBOX_GetItemRect( descr, index, &rect ) != 1) return;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000673 if (!(hdc = GetDCEx( wnd->hwndSelf, 0, DCX_CACHE ))) return;
674 if (descr->font) oldFont = SelectObject( hdc, descr->font );
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000675 hbrush = SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000676 hdc, (LPARAM)wnd->hwndSelf );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000677 if (hbrush) oldBrush = SelectObject( hdc, hbrush );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000678 if (wnd->dwStyle & WS_DISABLED)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000679 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
680 SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
Gerard Patel8caa4072000-09-24 19:29:18 +0000681 LISTBOX_PaintItem( wnd, descr, hdc, &rect, index, action, FALSE );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000682 if (oldFont) SelectObject( hdc, oldFont );
683 if (oldBrush) SelectObject( hdc, oldBrush );
684 ReleaseDC( wnd->hwndSelf, hdc );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000685}
686
687
688/***********************************************************************
689 * LISTBOX_InitStorage
690 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000691static LRESULT LISTBOX_InitStorage( WND *wnd, LB_DESCR *descr, INT nb_items )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000692{
693 LB_ITEMDATA *item;
694
695 nb_items += LB_ARRAY_GRANULARITY - 1;
696 nb_items -= (nb_items % LB_ARRAY_GRANULARITY);
697 if (descr->items)
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000698 nb_items += HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(*item);
699 if (!(item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000700 nb_items * sizeof(LB_ITEMDATA) )))
701 {
702 SEND_NOTIFICATION( wnd, descr, LBN_ERRSPACE );
703 return LB_ERRSPACE;
704 }
705 descr->items = item;
706 return LB_OKAY;
707}
708
709
710/***********************************************************************
711 * LISTBOX_SetTabStops
712 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000713static BOOL LISTBOX_SetTabStops( WND *wnd, LB_DESCR *descr, INT count,
714 LPINT tabs, BOOL short_ints )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000715{
716 if (!(descr->style & LBS_USETABSTOPS)) return TRUE;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000717 if (descr->tabs) HeapFree( GetProcessHeap(), 0, descr->tabs );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000718 if (!(descr->nb_tabs = count))
719 {
720 descr->tabs = NULL;
721 return TRUE;
722 }
723 /* FIXME: count = 1 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000724 if (!(descr->tabs = (INT *)HeapAlloc( GetProcessHeap(), 0,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000725 descr->nb_tabs * sizeof(INT) )))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000726 return FALSE;
727 if (short_ints)
728 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000729 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000730 LPINT16 p = (LPINT16)tabs;
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000731
Alexandre Julliard15de6151999-08-04 12:22:42 +0000732 TRACE("[%04x]: settabstops ", wnd->hwndSelf );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000733 for (i = 0; i < descr->nb_tabs; i++) {
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000734 descr->tabs[i] = *p++<<1; /* FIXME */
Alexandre Julliard15de6151999-08-04 12:22:42 +0000735 if (TRACE_ON(listbox)) DPRINTF("%hd ", descr->tabs[i]);
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000736 }
Alexandre Julliard15de6151999-08-04 12:22:42 +0000737 if (TRACE_ON(listbox)) DPRINTF("\n");
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000738 }
Alexandre Julliarda3960291999-02-26 11:11:13 +0000739 else memcpy( descr->tabs, tabs, descr->nb_tabs * sizeof(INT) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000740 /* FIXME: repaint the window? */
Alexandre Julliard2787be81995-05-22 18:23:01 +0000741 return TRUE;
742}
743
744
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000745/***********************************************************************
746 * LISTBOX_GetText
747 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000748static LRESULT LISTBOX_GetText( LB_DESCR *descr, INT index, LPARAM lParam, BOOL unicode )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000749{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000750 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
751 if (HAS_STRINGS(descr))
752 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000753 if (!lParam)
754 return strlenW(descr->items[index].str);
755
756 if(unicode)
757 {
758 LPWSTR buffer = (LPWSTR)lParam;
759 strcpyW( buffer, descr->items[index].str );
760 return strlenW(buffer);
761 }
762 else
763 {
764 LPSTR buffer = (LPSTR)lParam;
Gerard Pateldb8fb6f2001-01-10 23:54:46 +0000765 return WideCharToMultiByte(CP_ACP, 0, descr->items[index].str, -1, buffer, 0x7FFFFFFF, NULL, NULL) - 1;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000766 }
Marcus Meissner4f7dc461998-11-22 15:43:34 +0000767 } else {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000768 if (lParam)
769 *((LPDWORD)lParam)=*(LPDWORD)(&descr->items[index].data);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000770 return sizeof(DWORD);
771 }
Alexandre Julliard2787be81995-05-22 18:23:01 +0000772}
773
774
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000775/***********************************************************************
776 * LISTBOX_FindStringPos
777 *
778 * Find the nearest string located before a given string in sort order.
779 * If 'exact' is TRUE, return an error if we don't get an exact match.
780 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000781static INT LISTBOX_FindStringPos( WND *wnd, LB_DESCR *descr, LPCWSTR str,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000782 BOOL exact )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000783{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000784 INT index, min, max, res = -1;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000785
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000786 if (!(descr->style & LBS_SORT)) return -1; /* Add it at the end */
787 min = 0;
788 max = descr->nb_items;
789 while (min != max)
790 {
791 index = (min + max) / 2;
792 if (HAS_STRINGS(descr))
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000793 res = lstrcmpiW( descr->items[index].str, str );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000794 else
795 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000796 COMPAREITEMSTRUCT cis;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000797
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000798 cis.CtlType = ODT_LISTBOX;
Serge Ivanov07917e42000-06-07 03:46:57 +0000799 cis.CtlID = wnd->wIDmenu;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000800 cis.hwndItem = wnd->hwndSelf;
801 cis.itemID1 = index;
802 cis.itemData1 = descr->items[index].data;
803 cis.itemID2 = -1;
804 cis.itemData2 = (DWORD)str;
805 cis.dwLocaleId = descr->locale;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000806 res = SendMessageW( descr->owner, WM_COMPAREITEM,
Serge Ivanov07917e42000-06-07 03:46:57 +0000807 wnd->wIDmenu, (LPARAM)&cis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000808 }
809 if (!res) return index;
810 if (res > 0) max = index;
811 else min = index + 1;
812 }
813 return exact ? -1 : max;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000814}
815
816
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000817/***********************************************************************
818 * LISTBOX_FindFileStrPos
819 *
820 * Find the nearest string located before a given string in directory
821 * sort order (i.e. first files, then directories, then drives).
822 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000823static INT LISTBOX_FindFileStrPos( WND *wnd, LB_DESCR *descr, LPCWSTR str )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000824{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000825 INT min, max, res = -1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000826
827 if (!HAS_STRINGS(descr))
828 return LISTBOX_FindStringPos( wnd, descr, str, FALSE );
829 min = 0;
830 max = descr->nb_items;
831 while (min != max)
832 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000833 INT index = (min + max) / 2;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000834 LPCWSTR p = descr->items[index].str;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000835 if (*p == '[') /* drive or directory */
836 {
837 if (*str != '[') res = -1;
838 else if (p[1] == '-') /* drive */
839 {
840 if (str[1] == '-') res = str[2] - p[2];
841 else res = -1;
842 }
843 else /* directory */
844 {
845 if (str[1] == '-') res = 1;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000846 else res = lstrcmpiW( str, p );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000847 }
848 }
849 else /* filename */
850 {
851 if (*str == '[') res = 1;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000852 else res = lstrcmpiW( str, p );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000853 }
854 if (!res) return index;
855 if (res < 0) max = index;
856 else min = index + 1;
857 }
858 return max;
859}
860
861
862/***********************************************************************
863 * LISTBOX_FindString
864 *
865 * Find the item beginning with a given string.
866 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000867static INT LISTBOX_FindString( WND *wnd, LB_DESCR *descr, INT start,
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000868 LPCWSTR str, BOOL exact )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000869{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000870 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000871 LB_ITEMDATA *item;
872
873 if (start >= descr->nb_items) start = -1;
874 item = descr->items + start + 1;
875 if (HAS_STRINGS(descr))
876 {
Rein Klazesd35c8341999-08-21 13:04:58 +0000877 if (!str || ! str[0] ) return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000878 if (exact)
879 {
880 for (i = start + 1; i < descr->nb_items; i++, item++)
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000881 if (!lstrcmpiW( str, item->str )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000882 for (i = 0, item = descr->items; i <= start; i++, item++)
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000883 if (!lstrcmpiW( str, item->str )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000884 }
885 else
886 {
887 /* Special case for drives and directories: ignore prefix */
888#define CHECK_DRIVE(item) \
889 if ((item)->str[0] == '[') \
890 { \
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000891 if (!strncmpiW( str, (item)->str+1, len )) return i; \
892 if (((item)->str[1] == '-') && !strncmpiW(str, (item)->str+2, len)) \
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000893 return i; \
894 }
895
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000896 INT len = strlenW(str);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000897 for (i = start + 1; i < descr->nb_items; i++, item++)
898 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000899 if (!strncmpiW( str, item->str, len )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000900 CHECK_DRIVE(item);
901 }
902 for (i = 0, item = descr->items; i <= start; i++, item++)
903 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000904 if (!strncmpiW( str, item->str, len )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000905 CHECK_DRIVE(item);
906 }
907#undef CHECK_DRIVE
908 }
909 }
910 else
911 {
912 if (exact && (descr->style & LBS_SORT))
913 /* If sorted, use a WM_COMPAREITEM binary search */
914 return LISTBOX_FindStringPos( wnd, descr, str, TRUE );
915
916 /* Otherwise use a linear search */
917 for (i = start + 1; i < descr->nb_items; i++, item++)
918 if (item->data == (DWORD)str) return i;
919 for (i = 0, item = descr->items; i <= start; i++, item++)
920 if (item->data == (DWORD)str) return i;
921 }
922 return LB_ERR;
923}
924
925
926/***********************************************************************
927 * LISTBOX_GetSelCount
928 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000929static LRESULT LISTBOX_GetSelCount( LB_DESCR *descr )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000930{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000931 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000932 LB_ITEMDATA *item = descr->items;
933
934 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
935 for (i = count = 0; i < descr->nb_items; i++, item++)
936 if (item->selected) count++;
937 return count;
938}
939
940
941/***********************************************************************
942 * LISTBOX_GetSelItems16
943 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000944static LRESULT LISTBOX_GetSelItems16( LB_DESCR *descr, INT16 max, LPINT16 array )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000945{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000946 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000947 LB_ITEMDATA *item = descr->items;
948
949 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
950 for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++)
951 if (item->selected) array[count++] = (INT16)i;
952 return count;
953}
954
955
956/***********************************************************************
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000957 * LISTBOX_GetSelItems
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000958 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000959static LRESULT LISTBOX_GetSelItems( LB_DESCR *descr, INT max, LPINT array )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000960{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000961 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000962 LB_ITEMDATA *item = descr->items;
963
964 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
965 for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++)
966 if (item->selected) array[count++] = i;
967 return count;
968}
969
970
971/***********************************************************************
972 * LISTBOX_Paint
973 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000974static LRESULT LISTBOX_Paint( WND *wnd, LB_DESCR *descr, HDC hdc )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000975{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000976 INT i, col_pos = descr->page_size - 1;
977 RECT rect;
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +0000978 RECT focusRect = {-1, -1, -1, -1};
Alexandre Julliarda3960291999-02-26 11:11:13 +0000979 HFONT oldFont = 0;
980 HBRUSH hbrush, oldBrush = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000981
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000982 if (descr->style & LBS_NOREDRAW) return 0;
Serge Ivanov07917e42000-06-07 03:46:57 +0000983
984 SetRect( &rect, 0, 0, descr->width, descr->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000985 if (descr->style & LBS_MULTICOLUMN)
986 rect.right = rect.left + descr->column_width;
987 else if (descr->horz_pos)
988 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000989 SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000990 rect.right += descr->horz_pos;
991 }
992
Alexandre Julliarda3960291999-02-26 11:11:13 +0000993 if (descr->font) oldFont = SelectObject( hdc, descr->font );
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000994 hbrush = SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000995 hdc, (LPARAM)wnd->hwndSelf );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000996 if (hbrush) oldBrush = SelectObject( hdc, hbrush );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000997 if (wnd->dwStyle & WS_DISABLED)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000998 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000999
1000 if (!descr->nb_items && (descr->focus_item != -1) && descr->caret_on &&
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00001001 (descr->in_focus))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001002 {
1003 /* Special case for empty listbox: paint focus rect */
1004 rect.bottom = rect.top + descr->item_height;
1005 LISTBOX_PaintItem( wnd, descr, hdc, &rect, descr->focus_item,
Gerard Patel8caa4072000-09-24 19:29:18 +00001006 ODA_FOCUS, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001007 rect.top = rect.bottom;
1008 }
1009
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001010 /* Paint all the item, regarding the selection
1011 Focus state will be painted after */
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001012
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001013 for (i = descr->top_item; i < descr->nb_items; i++)
1014 {
1015 if (!(descr->style & LBS_OWNERDRAWVARIABLE))
1016 rect.bottom = rect.top + descr->item_height;
1017 else
1018 rect.bottom = rect.top + descr->items[i].height;
1019
Gerard Patel8caa4072000-09-24 19:29:18 +00001020 if (i == descr->focus_item)
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001021 {
1022 /* keep the focus rect, to paint the focus item after */
1023 focusRect.left = rect.left;
1024 focusRect.right = rect.right;
1025 focusRect.top = rect.top;
1026 focusRect.bottom = rect.bottom;
1027 }
Gerard Patel8caa4072000-09-24 19:29:18 +00001028 LISTBOX_PaintItem( wnd, descr, hdc, &rect, i, ODA_DRAWENTIRE, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001029 rect.top = rect.bottom;
1030
1031 if ((descr->style & LBS_MULTICOLUMN) && !col_pos)
1032 {
1033 if (!IS_OWNERDRAW(descr))
1034 {
1035 /* Clear the bottom of the column */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001036 if (rect.top < descr->height)
1037 {
1038 rect.bottom = descr->height;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001039 ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001040 &rect, NULL, 0, NULL );
1041 }
1042 }
1043
1044 /* Go to the next column */
1045 rect.left += descr->column_width;
1046 rect.right += descr->column_width;
1047 rect.top = 0;
1048 col_pos = descr->page_size - 1;
1049 }
1050 else
1051 {
1052 col_pos--;
1053 if (rect.top >= descr->height) break;
1054 }
1055 }
1056
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001057 /* Paint the focus item now */
Serge Ivanov07917e42000-06-07 03:46:57 +00001058 if (focusRect.top != focusRect.bottom && descr->caret_on)
Gerard Patel8caa4072000-09-24 19:29:18 +00001059 LISTBOX_PaintItem( wnd, descr, hdc, &focusRect, descr->focus_item, ODA_FOCUS, FALSE );
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001060
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001061 if (!IS_OWNERDRAW(descr))
1062 {
1063 /* Clear the remainder of the client area */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001064 if (rect.top < descr->height)
1065 {
1066 rect.bottom = descr->height;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001067 ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001068 &rect, NULL, 0, NULL );
1069 }
1070 if (rect.right < descr->width)
1071 {
1072 rect.left = rect.right;
1073 rect.right = descr->width;
1074 rect.top = 0;
1075 rect.bottom = descr->height;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001076 ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001077 &rect, NULL, 0, NULL );
1078 }
1079 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001080 if (oldFont) SelectObject( hdc, oldFont );
1081 if (oldBrush) SelectObject( hdc, oldBrush );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001082 return 0;
1083}
1084
1085
1086/***********************************************************************
1087 * LISTBOX_InvalidateItems
1088 *
1089 * Invalidate all items from a given item. If the specified item is not
1090 * visible, nothing happens.
1091 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001092static void LISTBOX_InvalidateItems( WND *wnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001093{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001094 RECT rect;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001095
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001096 if (LISTBOX_GetItemRect( descr, index, &rect ) == 1)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001097 {
Gerard Patel41b07fb2000-06-15 00:07:20 +00001098 if (descr->style & LBS_NOREDRAW)
1099 {
1100 descr->style |= LBS_DISPLAYCHANGED;
1101 return;
1102 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001103 rect.bottom = descr->height;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001104 InvalidateRect( wnd->hwndSelf, &rect, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001105 if (descr->style & LBS_MULTICOLUMN)
1106 {
1107 /* Repaint the other columns */
1108 rect.left = rect.right;
1109 rect.right = descr->width;
1110 rect.top = 0;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001111 InvalidateRect( wnd->hwndSelf, &rect, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001112 }
1113 }
1114}
1115
1116
1117/***********************************************************************
1118 * LISTBOX_GetItemHeight
1119 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001120static LRESULT LISTBOX_GetItemHeight( LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001121{
1122 if (descr->style & LBS_OWNERDRAWVARIABLE)
1123 {
1124 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
1125 return descr->items[index].height;
1126 }
1127 else return descr->item_height;
1128}
1129
1130
1131/***********************************************************************
1132 * LISTBOX_SetItemHeight
1133 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001134static LRESULT LISTBOX_SetItemHeight( WND *wnd, LB_DESCR *descr, INT index,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001135 INT height )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001136{
1137 if (!height) height = 1;
1138
1139 if (descr->style & LBS_OWNERDRAWVARIABLE)
1140 {
1141 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001142 TRACE("[%04x]: item %d height = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001143 wnd->hwndSelf, index, height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001144 descr->items[index].height = height;
1145 LISTBOX_UpdateScroll( wnd, descr );
1146 LISTBOX_InvalidateItems( wnd, descr, index );
1147 }
1148 else if (height != descr->item_height)
1149 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001150 TRACE("[%04x]: new height = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001151 wnd->hwndSelf, height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001152 descr->item_height = height;
1153 LISTBOX_UpdatePage( wnd, descr );
1154 LISTBOX_UpdateScroll( wnd, descr );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001155 InvalidateRect( wnd->hwndSelf, 0, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001156 }
1157 return LB_OKAY;
1158}
1159
1160
1161/***********************************************************************
1162 * LISTBOX_SetHorizontalPos
1163 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001164static void LISTBOX_SetHorizontalPos( WND *wnd, LB_DESCR *descr, INT pos )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001165{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001166 INT diff;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001167
1168 if (pos > descr->horz_extent - descr->width)
1169 pos = descr->horz_extent - descr->width;
1170 if (pos < 0) pos = 0;
1171 if (!(diff = descr->horz_pos - pos)) return;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001172 TRACE("[%04x]: new horz pos = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001173 wnd->hwndSelf, pos );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001174 descr->horz_pos = pos;
1175 LISTBOX_UpdateScroll( wnd, descr );
1176 if (abs(diff) < descr->width)
Alexandre Julliarda3960291999-02-26 11:11:13 +00001177 ScrollWindowEx( wnd->hwndSelf, diff, 0, NULL, NULL, 0, NULL,
NF Stevens762f18d1999-01-24 19:02:16 +00001178 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001179 else
Alexandre Julliarda3960291999-02-26 11:11:13 +00001180 InvalidateRect( wnd->hwndSelf, NULL, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001181}
1182
1183
1184/***********************************************************************
1185 * LISTBOX_SetHorizontalExtent
1186 */
1187static LRESULT LISTBOX_SetHorizontalExtent( WND *wnd, LB_DESCR *descr,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001188 INT extent )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001189{
1190 if (!descr->horz_extent || (descr->style & LBS_MULTICOLUMN))
1191 return LB_OKAY;
1192 if (extent <= 0) extent = 1;
1193 if (extent == descr->horz_extent) return LB_OKAY;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001194 TRACE("[%04x]: new horz extent = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001195 wnd->hwndSelf, extent );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001196 descr->horz_extent = extent;
1197 if (descr->horz_pos > extent - descr->width)
1198 LISTBOX_SetHorizontalPos( wnd, descr, extent - descr->width );
1199 else
1200 LISTBOX_UpdateScroll( wnd, descr );
1201 return LB_OKAY;
1202}
1203
1204
1205/***********************************************************************
1206 * LISTBOX_SetColumnWidth
1207 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001208static LRESULT LISTBOX_SetColumnWidth( WND *wnd, LB_DESCR *descr, INT width)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001209{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001210 if (width == descr->column_width) return LB_OKAY;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001211 TRACE("[%04x]: new column width = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001212 wnd->hwndSelf, width );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001213 descr->column_width = width;
1214 LISTBOX_UpdatePage( wnd, descr );
1215 return LB_OKAY;
1216}
1217
1218
1219/***********************************************************************
1220 * LISTBOX_SetFont
1221 *
1222 * Returns the item height.
1223 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001224static INT LISTBOX_SetFont( WND *wnd, LB_DESCR *descr, HFONT font )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001225{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001226 HDC hdc;
1227 HFONT oldFont = 0;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001228 TEXTMETRICW tm;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001229
1230 descr->font = font;
1231
Alexandre Julliarda3960291999-02-26 11:11:13 +00001232 if (!(hdc = GetDCEx( wnd->hwndSelf, 0, DCX_CACHE )))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001233 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001234 ERR("unable to get DC.\n" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001235 return 16;
1236 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001237 if (font) oldFont = SelectObject( hdc, font );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001238 GetTextMetricsW( hdc, &tm );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001239 if (oldFont) SelectObject( hdc, oldFont );
1240 ReleaseDC( wnd->hwndSelf, hdc );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001241 if (!IS_OWNERDRAW(descr))
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001242 LISTBOX_SetItemHeight( wnd, descr, 0, tm.tmHeight );
1243 return tm.tmHeight ;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001244}
1245
1246
1247/***********************************************************************
1248 * LISTBOX_MakeItemVisible
1249 *
1250 * Make sure that a given item is partially or fully visible.
1251 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001252static void LISTBOX_MakeItemVisible( WND *wnd, LB_DESCR *descr, INT index,
1253 BOOL fully )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001254{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001255 INT top;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001256
1257 if (index <= descr->top_item) top = index;
1258 else if (descr->style & LBS_MULTICOLUMN)
1259 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001260 INT cols = descr->width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001261 if (!fully) cols += descr->column_width - 1;
1262 if (cols >= descr->column_width) cols /= descr->column_width;
1263 else cols = 1;
1264 if (index < descr->top_item + (descr->page_size * cols)) return;
1265 top = index - descr->page_size * (cols - 1);
1266 }
1267 else if (descr->style & LBS_OWNERDRAWVARIABLE)
1268 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001269 INT height = fully ? descr->items[index].height : 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001270 for (top = index; top > descr->top_item; top--)
1271 if ((height += descr->items[top-1].height) > descr->height) break;
1272 }
1273 else
1274 {
1275 if (index < descr->top_item + descr->page_size) return;
1276 if (!fully && (index == descr->top_item + descr->page_size) &&
1277 (descr->height > (descr->page_size * descr->item_height))) return;
1278 top = index - descr->page_size + 1;
1279 }
1280 LISTBOX_SetTopItem( wnd, descr, top, TRUE );
1281}
1282
Gerard Patel2ffbb312000-07-09 12:18:14 +00001283/***********************************************************************
1284 * LISTBOX_SetCaretIndex
1285 *
1286 * NOTES
1287 * index must be between 0 and descr->nb_items-1, or LB_ERR is returned.
1288 *
1289 */
1290static LRESULT LISTBOX_SetCaretIndex( WND *wnd, LB_DESCR *descr, INT index,
1291 BOOL fully_visible )
1292{
1293 INT oldfocus = descr->focus_item;
1294
Andreas Mohr85ba8792001-01-06 00:34:14 +00001295 if (descr->style & LBS_NOSEL) return LB_ERR;
Gerard Patel2ffbb312000-07-09 12:18:14 +00001296 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
1297 if (index == oldfocus) return LB_OKAY;
1298 descr->focus_item = index;
1299 if ((oldfocus != -1) && descr->caret_on && (descr->in_focus))
1300 LISTBOX_RepaintItem( wnd, descr, oldfocus, ODA_FOCUS );
1301
1302 LISTBOX_MakeItemVisible( wnd, descr, index, fully_visible );
1303 if (descr->caret_on && (descr->in_focus))
1304 LISTBOX_RepaintItem( wnd, descr, index, ODA_FOCUS );
1305
1306 return LB_OKAY;
1307}
1308
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001309
1310/***********************************************************************
1311 * LISTBOX_SelectItemRange
1312 *
1313 * Select a range of items. Should only be used on a MULTIPLESEL listbox.
1314 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001315static LRESULT LISTBOX_SelectItemRange( WND *wnd, LB_DESCR *descr, INT first,
1316 INT last, BOOL on )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001317{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001318 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001319
1320 /* A few sanity checks */
1321
Andreas Mohr85ba8792001-01-06 00:34:14 +00001322 if (descr->style & LBS_NOSEL) return LB_ERR;
Alexandre Julliard03468f71998-02-15 19:40:49 +00001323 if ((last == -1) && (descr->nb_items == 0)) return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001324 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
1325 if (last == -1) last = descr->nb_items - 1;
1326 if ((first < 0) || (first >= descr->nb_items)) return LB_ERR;
1327 if ((last < 0) || (last >= descr->nb_items)) return LB_ERR;
1328 /* selected_item reflects last selected/unselected item on multiple sel */
1329 descr->selected_item = last;
1330
1331 if (on) /* Turn selection on */
1332 {
1333 for (i = first; i <= last; i++)
1334 {
1335 if (descr->items[i].selected) continue;
1336 descr->items[i].selected = TRUE;
1337 LISTBOX_RepaintItem( wnd, descr, i, ODA_SELECT );
1338 }
Gerard Patel2ffbb312000-07-09 12:18:14 +00001339 LISTBOX_SetCaretIndex( wnd, descr, last, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001340 }
1341 else /* Turn selection off */
1342 {
1343 for (i = first; i <= last; i++)
1344 {
1345 if (!descr->items[i].selected) continue;
1346 descr->items[i].selected = FALSE;
1347 LISTBOX_RepaintItem( wnd, descr, i, ODA_SELECT );
1348 }
1349 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001350 return LB_OKAY;
1351}
1352
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001353/***********************************************************************
1354 * LISTBOX_SetSelection
1355 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001356static LRESULT LISTBOX_SetSelection( WND *wnd, LB_DESCR *descr, INT index,
1357 BOOL on, BOOL send_notify )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001358{
Dmitry Timoshkove0f493e1999-11-28 19:44:33 +00001359 TRACE( "index=%d notify=%s\n", index, send_notify ? "YES" : "NO" );
1360
Andreas Mohr85ba8792001-01-06 00:34:14 +00001361 if (descr->style & LBS_NOSEL) return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001362 if ((index < -1) || (index >= descr->nb_items)) return LB_ERR;
1363 if (descr->style & LBS_MULTIPLESEL)
1364 {
1365 if (index == -1) /* Select all items */
1366 return LISTBOX_SelectItemRange( wnd, descr, 0, -1, on );
1367 else /* Only one item */
1368 return LISTBOX_SelectItemRange( wnd, descr, index, index, on );
1369 }
1370 else
1371 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001372 INT oldsel = descr->selected_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001373 if (index == oldsel) return LB_OKAY;
1374 if (oldsel != -1) descr->items[oldsel].selected = FALSE;
1375 if (index != -1) descr->items[index].selected = TRUE;
1376 descr->selected_item = index;
Huw D M Davies65a0fa62000-03-25 21:41:17 +00001377 if (oldsel != -1) LISTBOX_RepaintItem( wnd, descr, oldsel, ODA_SELECT );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001378 if (index != -1) LISTBOX_RepaintItem( wnd, descr, index, ODA_SELECT );
Gerard Patelc9a6d501999-07-25 13:03:17 +00001379 if (send_notify && descr->nb_items) SEND_NOTIFICATION( wnd, descr,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001380 (index != -1) ? LBN_SELCHANGE : LBN_SELCANCEL );
Alex Korobka311d3291999-01-01 18:40:02 +00001381 else
1382 if( descr->lphc ) /* set selection change flag for parent combo */
1383 descr->lphc->wState |= CBF_SELCHANGE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001384 }
1385 return LB_OKAY;
1386}
1387
1388
1389/***********************************************************************
1390 * LISTBOX_MoveCaret
1391 *
1392 * Change the caret position and extend the selection to the new caret.
1393 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001394static void LISTBOX_MoveCaret( WND *wnd, LB_DESCR *descr, INT index,
1395 BOOL fully_visible )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001396{
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001397 INT oldfocus = descr->focus_item;
1398
1399 if ((index < 0) || (index >= descr->nb_items))
1400 return;
1401
1402 /* Important, repaint needs to be done in this order if
1403 you want to mimic Windows behavior:
1404 1. Remove the focus and paint the item
1405 2. Remove the selection and paint the item(s)
1406 3. Set the selection and repaint the item(s)
1407 4. Set the focus to 'index' and repaint the item */
1408
1409 /* 1. remove the focus and repaint the item */
1410 descr->focus_item = -1;
1411 if ((oldfocus != -1) && descr->caret_on && (descr->in_focus))
1412 LISTBOX_RepaintItem( wnd, descr, oldfocus, ODA_FOCUS );
1413
1414 /* 2. then turn off the previous selection */
1415 /* 3. repaint the new selected item */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001416 if (descr->style & LBS_EXTENDEDSEL)
1417 {
1418 if (descr->anchor_item != -1)
1419 {
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001420 INT first = min( index, descr->anchor_item );
1421 INT last = max( index, descr->anchor_item );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001422 if (first > 0)
1423 LISTBOX_SelectItemRange( wnd, descr, 0, first - 1, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001424 LISTBOX_SelectItemRange( wnd, descr, last + 1, -1, FALSE );
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001425 LISTBOX_SelectItemRange( wnd, descr, first, last, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001426 }
1427 }
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00001428 else if (!(descr->style & LBS_MULTIPLESEL))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001429 {
1430 /* Set selection to new caret item */
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00001431 LISTBOX_SetSelection( wnd, descr, index, TRUE, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001432 }
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001433
1434 /* 4. repaint the new item with the focus */
1435 descr->focus_item = index;
1436 LISTBOX_MakeItemVisible( wnd, descr, index, fully_visible );
1437 if (descr->caret_on && (descr->in_focus))
1438 LISTBOX_RepaintItem( wnd, descr, index, ODA_FOCUS );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001439}
1440
1441
1442/***********************************************************************
1443 * LISTBOX_InsertItem
1444 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001445static LRESULT LISTBOX_InsertItem( WND *wnd, LB_DESCR *descr, INT index,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001446 LPWSTR str, DWORD data )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001447{
1448 LB_ITEMDATA *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001449 INT max_items;
Gerard Patelc9a6d501999-07-25 13:03:17 +00001450 INT oldfocus = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001451
1452 if (index == -1) index = descr->nb_items;
1453 else if ((index < 0) || (index > descr->nb_items)) return LB_ERR;
1454 if (!descr->items) max_items = 0;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001455 else max_items = HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(*item);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001456 if (descr->nb_items == max_items)
1457 {
1458 /* We need to grow the array */
1459 max_items += LB_ARRAY_GRANULARITY;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001460 if (!(item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001461 max_items * sizeof(LB_ITEMDATA) )))
1462 {
1463 SEND_NOTIFICATION( wnd, descr, LBN_ERRSPACE );
1464 return LB_ERRSPACE;
1465 }
1466 descr->items = item;
1467 }
1468
1469 /* Insert the item structure */
1470
1471 item = &descr->items[index];
1472 if (index < descr->nb_items)
1473 RtlMoveMemory( item + 1, item,
1474 (descr->nb_items - index) * sizeof(LB_ITEMDATA) );
1475 item->str = str;
1476 item->data = data;
1477 item->height = 0;
1478 item->selected = FALSE;
1479 descr->nb_items++;
1480
1481 /* Get item height */
1482
1483 if (descr->style & LBS_OWNERDRAWVARIABLE)
1484 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001485 MEASUREITEMSTRUCT mis;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001486
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001487 mis.CtlType = ODT_LISTBOX;
Serge Ivanov07917e42000-06-07 03:46:57 +00001488 mis.CtlID = wnd->wIDmenu;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001489 mis.itemID = index;
1490 mis.itemData = descr->items[index].data;
1491 mis.itemHeight = descr->item_height;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001492 SendMessageW( descr->owner, WM_MEASUREITEM, wnd->wIDmenu, (LPARAM)&mis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001493 item->height = mis.itemHeight ? mis.itemHeight : 1;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001494 TRACE("[%04x]: measure item %d (%s) = %d\n",
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001495 wnd->hwndSelf, index, str ? debugstr_w(str) : "", item->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001496 }
1497
1498 /* Repaint the items */
1499
1500 LISTBOX_UpdateScroll( wnd, descr );
1501 LISTBOX_InvalidateItems( wnd, descr, index );
1502
1503 /* Move selection and focused item */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001504 /* If listbox was empty, set focus to the first item */
Gerard Patelc9a6d501999-07-25 13:03:17 +00001505 if (descr->nb_items == 1)
1506 LISTBOX_SetCaretIndex( wnd, descr, 0, FALSE );
1507 /* single select don't change selection index in win31 */
1508 else if ((ISWIN31) && !(IS_MULTISELECT(descr)))
1509 {
1510 descr->selected_item++;
1511 LISTBOX_SetSelection( wnd, descr, descr->selected_item-1, TRUE, FALSE );
1512 }
1513 else
1514 {
1515 if (index <= descr->selected_item)
1516 {
1517 descr->selected_item++;
1518 descr->focus_item = oldfocus; /* focus not changed */
1519 }
1520 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001521 return LB_OKAY;
1522}
1523
1524
1525/***********************************************************************
1526 * LISTBOX_InsertString
1527 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001528static LRESULT LISTBOX_InsertString( WND *wnd, LB_DESCR *descr, INT index,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001529 LPCWSTR str )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001530{
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001531 LPWSTR new_str = NULL;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001532 DWORD data = 0;
1533 LRESULT ret;
1534
1535 if (HAS_STRINGS(descr))
1536 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001537 static const WCHAR empty_stringW[] = { 0 };
1538 if (!str) str = empty_stringW;
1539 if (!(new_str = HeapAlloc( GetProcessHeap(), 0, (strlenW(str) + 1) * sizeof(WCHAR) )))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001540 {
1541 SEND_NOTIFICATION( wnd, descr, LBN_ERRSPACE );
1542 return LB_ERRSPACE;
1543 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001544 strcpyW(new_str, str);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001545 }
1546 else data = (DWORD)str;
1547
1548 if (index == -1) index = descr->nb_items;
1549 if ((ret = LISTBOX_InsertItem( wnd, descr, index, new_str, data )) != 0)
1550 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001551 if (new_str) HeapFree( GetProcessHeap(), 0, new_str );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001552 return ret;
1553 }
1554
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001555 TRACE("[%04x]: added item %d '%s'\n",
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001556 wnd->hwndSelf, index, HAS_STRINGS(descr) ? debugstr_w(new_str) : "" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001557 return index;
1558}
1559
1560
1561/***********************************************************************
1562 * LISTBOX_DeleteItem
1563 *
1564 * Delete the content of an item. 'index' must be a valid index.
1565 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001566static void LISTBOX_DeleteItem( WND *wnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001567{
1568 /* Note: Win 3.1 only sends DELETEITEM on owner-draw items,
1569 * while Win95 sends it for all items with user data.
1570 * It's probably better to send it too often than not
1571 * often enough, so this is what we do here.
1572 */
1573 if (IS_OWNERDRAW(descr) || descr->items[index].data)
1574 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001575 DELETEITEMSTRUCT dis;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001576
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001577 dis.CtlType = ODT_LISTBOX;
Serge Ivanov07917e42000-06-07 03:46:57 +00001578 dis.CtlID = wnd->wIDmenu;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001579 dis.itemID = index;
1580 dis.hwndItem = wnd->hwndSelf;
1581 dis.itemData = descr->items[index].data;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001582 SendMessageW( descr->owner, WM_DELETEITEM, wnd->wIDmenu, (LPARAM)&dis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001583 }
1584 if (HAS_STRINGS(descr) && descr->items[index].str)
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001585 HeapFree( GetProcessHeap(), 0, descr->items[index].str );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001586}
1587
1588
1589/***********************************************************************
1590 * LISTBOX_RemoveItem
1591 *
1592 * Remove an item from the listbox and delete its content.
1593 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001594static LRESULT LISTBOX_RemoveItem( WND *wnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001595{
1596 LB_ITEMDATA *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001597 INT max_items;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001598
Aric Stewartfe9a0f02001-01-04 19:27:03 +00001599 if ((index == -1) && (descr->nb_items > 0)) index = descr->nb_items - 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001600 else if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +00001601
1602 /* We need to invalidate the original rect instead of the updated one. */
1603 LISTBOX_InvalidateItems( wnd, descr, index );
1604
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001605 LISTBOX_DeleteItem( wnd, descr, index );
1606
1607 /* Remove the item */
1608
1609 item = &descr->items[index];
1610 if (index < descr->nb_items-1)
1611 RtlMoveMemory( item, item + 1,
1612 (descr->nb_items - index - 1) * sizeof(LB_ITEMDATA) );
1613 descr->nb_items--;
1614 if (descr->anchor_item == descr->nb_items) descr->anchor_item--;
1615
1616 /* Shrink the item array if possible */
1617
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001618 max_items = HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(LB_ITEMDATA);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001619 if (descr->nb_items < max_items - 2*LB_ARRAY_GRANULARITY)
1620 {
1621 max_items -= LB_ARRAY_GRANULARITY;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001622 item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001623 max_items * sizeof(LB_ITEMDATA) );
1624 if (item) descr->items = item;
1625 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001626 /* Repaint the items */
1627
1628 LISTBOX_UpdateScroll( wnd, descr );
Gerard Patelc9a6d501999-07-25 13:03:17 +00001629 /* if we removed the scrollbar, reset the top of the list
1630 (correct for owner-drawn ???) */
1631 if (descr->nb_items == descr->page_size)
1632 LISTBOX_SetTopItem( wnd, descr, 0, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001633
1634 /* Move selection and focused item */
Gerard Patelc9a6d501999-07-25 13:03:17 +00001635 if (!IS_MULTISELECT(descr))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001636 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00001637 if (index == descr->selected_item)
1638 descr->selected_item = -1;
1639 else if (index < descr->selected_item)
1640 {
1641 descr->selected_item--;
1642 if (ISWIN31) /* win 31 do not change the selected item number */
1643 LISTBOX_SetSelection( wnd, descr, descr->selected_item + 1, TRUE, FALSE);
1644 }
1645 }
Yuxi Zhangf94c3c52000-02-26 19:13:12 +00001646
Gerard Patelc9a6d501999-07-25 13:03:17 +00001647 if (descr->focus_item >= descr->nb_items)
1648 {
1649 descr->focus_item = descr->nb_items - 1;
1650 if (descr->focus_item < 0) descr->focus_item = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001651 }
1652 return LB_OKAY;
1653}
1654
1655
1656/***********************************************************************
1657 * LISTBOX_ResetContent
1658 */
1659static void LISTBOX_ResetContent( WND *wnd, LB_DESCR *descr )
1660{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001661 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001662
1663 for (i = 0; i < descr->nb_items; i++) LISTBOX_DeleteItem( wnd, descr, i );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001664 if (descr->items) HeapFree( GetProcessHeap(), 0, descr->items );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001665 descr->nb_items = 0;
1666 descr->top_item = 0;
1667 descr->selected_item = -1;
1668 descr->focus_item = 0;
1669 descr->anchor_item = -1;
1670 descr->items = NULL;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001671}
1672
1673
1674/***********************************************************************
1675 * LISTBOX_SetCount
1676 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001677static LRESULT LISTBOX_SetCount( WND *wnd, LB_DESCR *descr, INT count )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001678{
1679 LRESULT ret;
1680
1681 if (HAS_STRINGS(descr)) return LB_ERR;
1682 /* FIXME: this is far from optimal... */
1683 if (count > descr->nb_items)
1684 {
1685 while (count > descr->nb_items)
1686 if ((ret = LISTBOX_InsertString( wnd, descr, -1, 0 )) < 0)
1687 return ret;
1688 }
1689 else if (count < descr->nb_items)
1690 {
1691 while (count < descr->nb_items)
1692 if ((ret = LISTBOX_RemoveItem( wnd, descr, -1 )) < 0)
1693 return ret;
1694 }
1695 return LB_OKAY;
1696}
1697
1698
1699/***********************************************************************
1700 * LISTBOX_Directory
1701 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001702static LRESULT LISTBOX_Directory( WND *wnd, LB_DESCR *descr, UINT attrib,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001703 LPCWSTR filespec, BOOL long_names )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001704{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001705 HANDLE handle;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001706 LRESULT ret = LB_OKAY;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001707 WIN32_FIND_DATAW entry;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001708 int pos;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001709
Ove Kaaven2c691b32000-11-25 03:06:03 +00001710 /* don't scan directory if we just want drives exclusively */
1711 if (attrib != (DDL_DRIVES | DDL_EXCLUSIVE)) {
1712 /* scan directory */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001713 if ((handle = FindFirstFileW(filespec, &entry)) == INVALID_HANDLE_VALUE)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001714 {
Ove Kaaven2c691b32000-11-25 03:06:03 +00001715 if (GetLastError() != ERROR_NO_MORE_FILES) return LB_ERR;
1716 }
1717 else
1718 {
1719 do
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001720 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001721 WCHAR buffer[270];
Ove Kaaven2c691b32000-11-25 03:06:03 +00001722 if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1723 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001724 static const WCHAR bracketW[] = { ']',0 };
1725 static const WCHAR dotW[] = { '.',0 };
Ove Kaaven2c691b32000-11-25 03:06:03 +00001726 if (!(attrib & DDL_DIRECTORY) ||
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001727 !strcmpW( entry.cAlternateFileName, dotW )) continue;
1728 buffer[0] = '[';
1729 if (long_names) strcpyW( buffer + 1, entry.cFileName );
1730 else strcpyW( buffer + 1, entry.cAlternateFileName );
1731 strcatW(buffer, bracketW);
Ove Kaaven2c691b32000-11-25 03:06:03 +00001732 }
1733 else /* not a directory */
1734 {
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001735#define ATTRIBS (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
1736 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE)
1737
Ove Kaaven2c691b32000-11-25 03:06:03 +00001738 if ((attrib & DDL_EXCLUSIVE) &&
1739 ((attrib & ATTRIBS) != (entry.dwFileAttributes & ATTRIBS)))
1740 continue;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001741#undef ATTRIBS
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001742 if (long_names) strcpyW( buffer, entry.cFileName );
1743 else strcpyW( buffer, entry.cAlternateFileName );
Ove Kaaven2c691b32000-11-25 03:06:03 +00001744 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001745 if (!long_names) CharLowerW( buffer );
Ove Kaaven2c691b32000-11-25 03:06:03 +00001746 pos = LISTBOX_FindFileStrPos( wnd, descr, buffer );
1747 if ((ret = LISTBOX_InsertString( wnd, descr, pos, buffer )) < 0)
1748 break;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001749 } while (FindNextFileW( handle, &entry ));
Ove Kaaven2c691b32000-11-25 03:06:03 +00001750 FindClose( handle );
1751 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001752 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001753
Ove Kaaven2c691b32000-11-25 03:06:03 +00001754 /* scan drives */
Alexandre Julliard889f7421997-04-15 17:19:52 +00001755 if ((ret >= 0) && (attrib & DDL_DRIVES))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001756 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001757 WCHAR buffer[] = {'[','-','a','-',']',0};
1758 WCHAR root[] = {'A',':','\\',0};
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001759 int drive;
Alexandre Julliardbf672592000-12-12 00:44:42 +00001760 for (drive = 0; drive < 26; drive++, buffer[2]++, root[0]++)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001761 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001762 if (GetDriveTypeW(root) <= DRIVE_NO_ROOT_DIR) continue;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001763 if ((ret = LISTBOX_InsertString( wnd, descr, -1, buffer )) < 0)
1764 break;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001765 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001766 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001767 return ret;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001768}
1769
1770
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001771/***********************************************************************
1772 * LISTBOX_HandleVScroll
1773 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001774static LRESULT LISTBOX_HandleVScroll( WND *wnd, LB_DESCR *descr, WPARAM wParam )
Alexandre Julliard2787be81995-05-22 18:23:01 +00001775{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001776 SCROLLINFO info;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001777
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001778 if (descr->style & LBS_MULTICOLUMN) return 0;
1779 switch(LOWORD(wParam))
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +00001780 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001781 case SB_LINEUP:
1782 LISTBOX_SetTopItem( wnd, descr, descr->top_item - 1, TRUE );
1783 break;
1784 case SB_LINEDOWN:
1785 LISTBOX_SetTopItem( wnd, descr, descr->top_item + 1, TRUE );
1786 break;
1787 case SB_PAGEUP:
1788 LISTBOX_SetTopItem( wnd, descr, descr->top_item -
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001789 LISTBOX_GetCurrentPageSize( descr ), TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001790 break;
1791 case SB_PAGEDOWN:
1792 LISTBOX_SetTopItem( wnd, descr, descr->top_item +
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001793 LISTBOX_GetCurrentPageSize( descr ), TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001794 break;
1795 case SB_THUMBPOSITION:
1796 LISTBOX_SetTopItem( wnd, descr, HIWORD(wParam), TRUE );
1797 break;
1798 case SB_THUMBTRACK:
1799 info.cbSize = sizeof(info);
1800 info.fMask = SIF_TRACKPOS;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001801 GetScrollInfo( wnd->hwndSelf, SB_VERT, &info );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001802 LISTBOX_SetTopItem( wnd, descr, info.nTrackPos, TRUE );
1803 break;
1804 case SB_TOP:
1805 LISTBOX_SetTopItem( wnd, descr, 0, TRUE );
1806 break;
1807 case SB_BOTTOM:
1808 LISTBOX_SetTopItem( wnd, descr, descr->nb_items, TRUE );
1809 break;
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +00001810 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001811 return 0;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001812}
1813
Alexandre Julliardb817f4f1996-03-14 18:08:34 +00001814
Alexandre Julliard2787be81995-05-22 18:23:01 +00001815/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001816 * LISTBOX_HandleHScroll
Alexandre Julliard2787be81995-05-22 18:23:01 +00001817 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001818static LRESULT LISTBOX_HandleHScroll( WND *wnd, LB_DESCR *descr, WPARAM wParam )
Alexandre Julliard2787be81995-05-22 18:23:01 +00001819{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001820 SCROLLINFO info;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001821 INT page;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001822
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001823 if (descr->style & LBS_MULTICOLUMN)
1824 {
1825 switch(LOWORD(wParam))
1826 {
1827 case SB_LINELEFT:
1828 LISTBOX_SetTopItem( wnd, descr, descr->top_item-descr->page_size,
1829 TRUE );
1830 break;
1831 case SB_LINERIGHT:
1832 LISTBOX_SetTopItem( wnd, descr, descr->top_item+descr->page_size,
1833 TRUE );
1834 break;
1835 case SB_PAGELEFT:
1836 page = descr->width / descr->column_width;
1837 if (page < 1) page = 1;
1838 LISTBOX_SetTopItem( wnd, descr,
1839 descr->top_item - page * descr->page_size, TRUE );
1840 break;
1841 case SB_PAGERIGHT:
1842 page = descr->width / descr->column_width;
1843 if (page < 1) page = 1;
1844 LISTBOX_SetTopItem( wnd, descr,
1845 descr->top_item + page * descr->page_size, TRUE );
1846 break;
1847 case SB_THUMBPOSITION:
1848 LISTBOX_SetTopItem( wnd, descr, HIWORD(wParam)*descr->page_size,
1849 TRUE );
1850 break;
1851 case SB_THUMBTRACK:
1852 info.cbSize = sizeof(info);
1853 info.fMask = SIF_TRACKPOS;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001854 GetScrollInfo( wnd->hwndSelf, SB_VERT, &info );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001855 LISTBOX_SetTopItem( wnd, descr, info.nTrackPos*descr->page_size,
1856 TRUE );
1857 break;
1858 case SB_LEFT:
1859 LISTBOX_SetTopItem( wnd, descr, 0, TRUE );
1860 break;
1861 case SB_RIGHT:
1862 LISTBOX_SetTopItem( wnd, descr, descr->nb_items, TRUE );
1863 break;
1864 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001865 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001866 else if (descr->horz_extent)
1867 {
1868 switch(LOWORD(wParam))
1869 {
1870 case SB_LINELEFT:
1871 LISTBOX_SetHorizontalPos( wnd, descr, descr->horz_pos - 1 );
1872 break;
1873 case SB_LINERIGHT:
1874 LISTBOX_SetHorizontalPos( wnd, descr, descr->horz_pos + 1 );
1875 break;
1876 case SB_PAGELEFT:
1877 LISTBOX_SetHorizontalPos( wnd, descr,
1878 descr->horz_pos - descr->width );
1879 break;
1880 case SB_PAGERIGHT:
1881 LISTBOX_SetHorizontalPos( wnd, descr,
1882 descr->horz_pos + descr->width );
1883 break;
1884 case SB_THUMBPOSITION:
1885 LISTBOX_SetHorizontalPos( wnd, descr, HIWORD(wParam) );
1886 break;
1887 case SB_THUMBTRACK:
1888 info.cbSize = sizeof(info);
1889 info.fMask = SIF_TRACKPOS;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001890 GetScrollInfo( wnd->hwndSelf, SB_HORZ, &info );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001891 LISTBOX_SetHorizontalPos( wnd, descr, info.nTrackPos );
1892 break;
1893 case SB_LEFT:
1894 LISTBOX_SetHorizontalPos( wnd, descr, 0 );
1895 break;
1896 case SB_RIGHT:
1897 LISTBOX_SetHorizontalPos( wnd, descr,
1898 descr->horz_extent - descr->width );
1899 break;
1900 }
1901 }
1902 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001903}
1904
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001905static LRESULT LISTBOX_HandleMouseWheel(WND *wnd, LB_DESCR *descr, WPARAM wParam )
Stephane Lussier4bdf4af2000-04-18 11:56:33 +00001906{
1907 short gcWheelDelta = 0;
1908 UINT pulScrollLines = 3;
1909
1910 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
1911
1912 gcWheelDelta -= (short) HIWORD(wParam);
1913
1914 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
1915 {
1916 int cLineScroll = (int) min((UINT) descr->page_size, pulScrollLines);
1917 cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
1918 LISTBOX_SetTopItem( wnd, descr, descr->top_item + cLineScroll, TRUE );
1919 }
1920 return 0;
1921}
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001922
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001923/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001924 * LISTBOX_HandleLButtonDown
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001925 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001926static LRESULT LISTBOX_HandleLButtonDown( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001927 WPARAM wParam, INT x, INT y )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001928{
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001929 INT index = LISTBOX_GetItemFromPoint( descr, x, y );
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001930 TRACE("[%04x]: lbuttondown %d,%d item %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001931 wnd->hwndSelf, x, y, index );
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00001932 if (!descr->caret_on && (descr->in_focus)) return 0;
Jason Mawdsley50523d12000-06-11 20:34:07 +00001933
1934 if (!descr->in_focus)
1935 {
1936 if( !descr->lphc ) SetFocus( wnd->hwndSelf );
1937 else SetFocus( (descr->lphc->hWndEdit) ? descr->lphc->hWndEdit
1938 : descr->lphc->self->hwndSelf );
1939 }
1940
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001941 if (index == -1) return 0;
Andreas Mohr2b5d9c62000-08-29 03:52:16 +00001942
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001943 if (descr->style & LBS_EXTENDEDSEL)
1944 {
1945 /* we should perhaps make sure that all items are deselected
1946 FIXME: needed for !LBS_EXTENDEDSEL, too ?
1947 if (!(wParam & (MK_SHIFT|MK_CONTROL)))
1948 LISTBOX_SetSelection( wnd, descr, -1, FALSE, FALSE);
1949 */
1950
1951 if (!(wParam & MK_SHIFT)) descr->anchor_item = index;
1952 if (wParam & MK_CONTROL)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001953 {
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001954 LISTBOX_SetCaretIndex( wnd, descr, index, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001955 LISTBOX_SetSelection( wnd, descr, index,
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001956 !descr->items[index].selected,
1957 (descr->style & LBS_NOTIFY) != 0);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001958 }
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001959 else LISTBOX_MoveCaret( wnd, descr, index, FALSE );
1960 }
1961 else
1962 {
1963 LISTBOX_MoveCaret( wnd, descr, index, FALSE );
1964 LISTBOX_SetSelection( wnd, descr, index,
1965 (!(descr->style & LBS_MULTIPLESEL) ||
1966 !descr->items[index].selected),
1967 (descr->style & LBS_NOTIFY) != 0 );
Alexandre Julliard2787be81995-05-22 18:23:01 +00001968 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001969
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00001970 descr->captured = TRUE;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001971 SetCapture( wnd->hwndSelf );
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001972
1973 if (!descr->lphc)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001974 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001975 if (descr->style & LBS_NOTIFY )
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001976 SendMessageW( descr->owner, WM_LBTRACKPOINT, index,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001977 MAKELPARAM( x, y ) );
1978 if (wnd->dwExStyle & WS_EX_DRAGDETECT)
1979 {
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00001980 POINT pt;
1981
1982 pt.x = x;
1983 pt.y = y;
1984
Alexandre Julliarda3960291999-02-26 11:11:13 +00001985 if (DragDetect( wnd->hwndSelf, pt ))
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001986 SendMessageW( descr->owner, WM_BEGINDRAG, 0, 0 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001987 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001988 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001989 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001990}
1991
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001992
Pierre Mageau25c62cc1999-09-11 16:26:03 +00001993/*************************************************************************
1994 * LISTBOX_HandleLButtonDownCombo [Internal]
1995 *
1996 * Process LButtonDown message for the ComboListBox
1997 *
1998 * PARAMS
1999 * pWnd [I] The windows internal structure
2000 * pDescr [I] The ListBox internal structure
2001 * wParam [I] Key Flag (WM_LBUTTONDOWN doc for more info)
2002 * x [I] X Mouse Coordinate
2003 * y [I] Y Mouse Coordinate
2004 *
2005 * RETURNS
2006 * 0 since we are processing the WM_LBUTTONDOWN Message
2007 *
2008 * NOTES
2009 * This function is only to be used when a ListBox is a ComboListBox
2010 */
2011
2012static LRESULT LISTBOX_HandleLButtonDownCombo( WND *pWnd, LB_DESCR *pDescr,
Alexandre Julliard7f90a8c2000-05-23 04:18:12 +00002013 UINT msg, WPARAM wParam, INT x, INT y)
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002014{
2015 RECT clientRect, screenRect;
2016 POINT mousePos;
2017
2018 mousePos.x = x;
2019 mousePos.y = y;
2020
2021 GetClientRect(pWnd->hwndSelf, &clientRect);
2022
2023 if(PtInRect(&clientRect, mousePos))
2024 {
Alexandre Julliard7f90a8c2000-05-23 04:18:12 +00002025 /* MousePos is in client, resume normal processing */
2026 if (msg == WM_LBUTTONDOWN)
Serge Ivanov07917e42000-06-07 03:46:57 +00002027 {
2028 pDescr->lphc->droppedIndex = pDescr->nb_items ? pDescr->selected_item : -1;
Alexandre Julliard7f90a8c2000-05-23 04:18:12 +00002029 return LISTBOX_HandleLButtonDown( pWnd, pDescr, wParam, x, y);
Serge Ivanov07917e42000-06-07 03:46:57 +00002030 }
Alexandre Julliard7f90a8c2000-05-23 04:18:12 +00002031 else if (pDescr->style & LBS_NOTIFY)
2032 SEND_NOTIFICATION( pWnd, pDescr, LBN_DBLCLK );
2033 return 0;
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002034 }
2035 else
2036 {
2037 POINT screenMousePos;
2038 HWND hWndOldCapture;
2039
2040 /* Check the Non-Client Area */
2041 screenMousePos = mousePos;
2042 hWndOldCapture = GetCapture();
2043 ReleaseCapture();
2044 GetWindowRect(pWnd->hwndSelf, &screenRect);
2045 ClientToScreen(pWnd->hwndSelf, &screenMousePos);
2046
2047 if(!PtInRect(&screenRect, screenMousePos))
2048 {
Serge Ivanov07917e42000-06-07 03:46:57 +00002049 LISTBOX_SetSelection( pWnd, pDescr, pDescr->lphc->droppedIndex, FALSE, FALSE );
2050 COMBO_FlipListbox( pDescr->lphc, FALSE, FALSE );
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002051 return 0;
2052 }
2053 else
2054 {
2055 /* Check to see the NC is a scrollbar */
2056 INT nHitTestType=0;
2057 /* Check Vertical scroll bar */
2058 if (pWnd->dwStyle & WS_VSCROLL)
2059 {
2060 clientRect.right += GetSystemMetrics(SM_CXVSCROLL);
2061 if (PtInRect( &clientRect, mousePos ))
2062 {
2063 nHitTestType = HTVSCROLL;
2064 }
2065 }
2066 /* Check horizontal scroll bar */
2067 if (pWnd->dwStyle & WS_HSCROLL)
2068 {
2069 clientRect.bottom += GetSystemMetrics(SM_CYHSCROLL);
2070 if (PtInRect( &clientRect, mousePos ))
2071 {
2072 nHitTestType = HTHSCROLL;
2073 }
2074 }
2075 /* Windows sends this message when a scrollbar is clicked
2076 */
2077
2078 if(nHitTestType != 0)
2079 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002080 SendMessageW(pWnd->hwndSelf, WM_NCLBUTTONDOWN, nHitTestType,
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002081 MAKELONG(screenMousePos.x, screenMousePos.y));
2082 }
2083 /* Resume the Capture after scrolling is complete
2084 */
2085 if(hWndOldCapture != 0)
2086 {
2087 SetCapture(hWndOldCapture);
2088 }
2089 }
2090 }
2091 return 0;
2092}
2093
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002094/***********************************************************************
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002095 * LISTBOX_HandleLButtonUp
2096 */
2097static LRESULT LISTBOX_HandleLButtonUp( WND *wnd, LB_DESCR *descr )
2098{
2099 if (LISTBOX_Timer != LB_TIMER_NONE)
Alexandre Julliarda3960291999-02-26 11:11:13 +00002100 KillSystemTimer( wnd->hwndSelf, LB_TIMER_ID );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002101 LISTBOX_Timer = LB_TIMER_NONE;
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002102 if (descr->captured)
Alexandre Julliard33072e11997-06-29 18:08:02 +00002103 {
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002104 descr->captured = FALSE;
2105 if (GetCapture() == wnd->hwndSelf) ReleaseCapture();
Gerard Patelc9a6d501999-07-25 13:03:17 +00002106 if ((descr->style & LBS_NOTIFY) && descr->nb_items)
Alexandre Julliard33072e11997-06-29 18:08:02 +00002107 SEND_NOTIFICATION( wnd, descr, LBN_SELCHANGE );
2108 }
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002109 return 0;
2110}
2111
2112
2113/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002114 * LISTBOX_HandleTimer
Alexandre Julliardade697e1995-11-26 13:59:11 +00002115 *
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002116 * Handle scrolling upon a timer event.
2117 * Return TRUE if scrolling should continue.
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002118 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002119static LRESULT LISTBOX_HandleTimer( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002120 INT index, TIMER_DIRECTION dir )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002121{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002122 switch(dir)
Alexandre Julliardade697e1995-11-26 13:59:11 +00002123 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002124 case LB_TIMER_UP:
2125 if (descr->top_item) index = descr->top_item - 1;
2126 else index = 0;
2127 break;
2128 case LB_TIMER_LEFT:
2129 if (descr->top_item) index -= descr->page_size;
2130 break;
2131 case LB_TIMER_DOWN:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002132 index = descr->top_item + LISTBOX_GetCurrentPageSize( descr );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002133 if (index == descr->focus_item) index++;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002134 if (index >= descr->nb_items) index = descr->nb_items - 1;
2135 break;
2136 case LB_TIMER_RIGHT:
2137 if (index + descr->page_size < descr->nb_items)
2138 index += descr->page_size;
2139 break;
2140 case LB_TIMER_NONE:
2141 break;
Alexandre Julliardade697e1995-11-26 13:59:11 +00002142 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002143 if (index == descr->focus_item) return FALSE;
2144 LISTBOX_MoveCaret( wnd, descr, index, FALSE );
2145 return TRUE;
2146}
Alexandre Julliardade697e1995-11-26 13:59:11 +00002147
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002148
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002149/***********************************************************************
2150 * LISTBOX_HandleSystemTimer
2151 *
2152 * WM_SYSTIMER handler.
2153 */
2154static LRESULT LISTBOX_HandleSystemTimer( WND *wnd, LB_DESCR *descr )
2155{
2156 if (!LISTBOX_HandleTimer( wnd, descr, descr->focus_item, LISTBOX_Timer ))
Alexandre Julliardade697e1995-11-26 13:59:11 +00002157 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002158 KillSystemTimer( wnd->hwndSelf, LB_TIMER_ID );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002159 LISTBOX_Timer = LB_TIMER_NONE;
Alexandre Julliardade697e1995-11-26 13:59:11 +00002160 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00002161 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002162}
2163
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002164
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002165/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002166 * LISTBOX_HandleMouseMove
2167 *
2168 * WM_MOUSEMOVE handler.
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002169 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002170static void LISTBOX_HandleMouseMove( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002171 INT x, INT y )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002172{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002173 INT index;
Serge Ivanov07917e42000-06-07 03:46:57 +00002174 TIMER_DIRECTION dir = LB_TIMER_NONE;
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00002175
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002176 if (!descr->captured) return;
2177
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002178 if (descr->style & LBS_MULTICOLUMN)
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00002179 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002180 if (y < 0) y = 0;
2181 else if (y >= descr->item_height * descr->page_size)
2182 y = descr->item_height * descr->page_size - 1;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002183
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002184 if (x < 0)
2185 {
2186 dir = LB_TIMER_LEFT;
2187 x = 0;
2188 }
2189 else if (x >= descr->width)
2190 {
2191 dir = LB_TIMER_RIGHT;
2192 x = descr->width - 1;
2193 }
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00002194 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002195 else
2196 {
2197 if (y < 0) dir = LB_TIMER_UP; /* above */
2198 else if (y >= descr->height) dir = LB_TIMER_DOWN; /* below */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002199 }
2200
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002201 index = LISTBOX_GetItemFromPoint( descr, x, y );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002202 if (index == -1) index = descr->focus_item;
2203 if (!LISTBOX_HandleTimer( wnd, descr, index, dir )) dir = LB_TIMER_NONE;
2204
2205 /* Start/stop the system timer */
2206
2207 if (dir != LB_TIMER_NONE)
Alexandre Julliarda3960291999-02-26 11:11:13 +00002208 SetSystemTimer( wnd->hwndSelf, LB_TIMER_ID, LB_SCROLL_TIMEOUT, NULL);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002209 else if (LISTBOX_Timer != LB_TIMER_NONE)
Alexandre Julliarda3960291999-02-26 11:11:13 +00002210 KillSystemTimer( wnd->hwndSelf, LB_TIMER_ID );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002211 LISTBOX_Timer = dir;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002212}
2213
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002214
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002215/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002216 * LISTBOX_HandleKeyDown
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002217 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002218static LRESULT LISTBOX_HandleKeyDown( WND *wnd, LB_DESCR *descr, WPARAM wParam )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002219{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002220 INT caret = -1;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002221 BOOL bForceSelection = TRUE; /* select item pointed to by focus_item */
2222 if ((IS_MULTISELECT(descr)) || (descr->selected_item == descr->focus_item))
2223 bForceSelection = FALSE; /* only for single select list */
2224
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002225 if (descr->style & LBS_WANTKEYBOARDINPUT)
2226 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002227 caret = SendMessageW( descr->owner, WM_VKEYTOITEM,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002228 MAKEWPARAM(LOWORD(wParam), descr->focus_item),
2229 wnd->hwndSelf );
2230 if (caret == -2) return 0;
2231 }
2232 if (caret == -1) switch(wParam)
2233 {
2234 case VK_LEFT:
2235 if (descr->style & LBS_MULTICOLUMN)
2236 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00002237 bForceSelection = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002238 if (descr->focus_item >= descr->page_size)
2239 caret = descr->focus_item - descr->page_size;
2240 break;
2241 }
2242 /* fall through */
2243 case VK_UP:
2244 caret = descr->focus_item - 1;
2245 if (caret < 0) caret = 0;
2246 break;
2247 case VK_RIGHT:
2248 if (descr->style & LBS_MULTICOLUMN)
2249 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00002250 bForceSelection = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002251 if (descr->focus_item + descr->page_size < descr->nb_items)
2252 caret = descr->focus_item + descr->page_size;
2253 break;
2254 }
2255 /* fall through */
2256 case VK_DOWN:
2257 caret = descr->focus_item + 1;
2258 if (caret >= descr->nb_items) caret = descr->nb_items - 1;
2259 break;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002260
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002261 case VK_PRIOR:
2262 if (descr->style & LBS_MULTICOLUMN)
2263 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002264 INT page = descr->width / descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002265 if (page < 1) page = 1;
2266 caret = descr->focus_item - (page * descr->page_size) + 1;
2267 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002268 else caret = descr->focus_item-LISTBOX_GetCurrentPageSize(descr) + 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002269 if (caret < 0) caret = 0;
2270 break;
2271 case VK_NEXT:
2272 if (descr->style & LBS_MULTICOLUMN)
2273 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002274 INT page = descr->width / descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002275 if (page < 1) page = 1;
2276 caret = descr->focus_item + (page * descr->page_size) - 1;
2277 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002278 else caret = descr->focus_item + LISTBOX_GetCurrentPageSize(descr) - 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002279 if (caret >= descr->nb_items) caret = descr->nb_items - 1;
2280 break;
2281 case VK_HOME:
2282 caret = 0;
2283 break;
2284 case VK_END:
2285 caret = descr->nb_items - 1;
2286 break;
2287 case VK_SPACE:
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002288 if (descr->style & LBS_EXTENDEDSEL) caret = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002289 else if (descr->style & LBS_MULTIPLESEL)
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002290 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002291 LISTBOX_SetSelection( wnd, descr, descr->focus_item,
2292 !descr->items[descr->focus_item].selected,
2293 (descr->style & LBS_NOTIFY) != 0 );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002294 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002295 break;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002296 default:
2297 bForceSelection = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002298 }
Gerard Patelc9a6d501999-07-25 13:03:17 +00002299 if (bForceSelection) /* focused item is used instead of key */
2300 caret = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002301 if (caret >= 0)
2302 {
2303 if ((descr->style & LBS_EXTENDEDSEL) &&
Alexandre Julliarda3960291999-02-26 11:11:13 +00002304 !(GetKeyState( VK_SHIFT ) & 0x8000))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002305 descr->anchor_item = caret;
2306 LISTBOX_MoveCaret( wnd, descr, caret, TRUE );
Gerard Patelc9a6d501999-07-25 13:03:17 +00002307 LISTBOX_SetSelection( wnd, descr, caret, TRUE, FALSE);
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002308 if (descr->style & LBS_NOTIFY)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002309 {
Dmitry Timoshkov6df245d2001-04-09 18:30:25 +00002310 if( descr->lphc )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002311 {
2312 /* make sure that combo parent doesn't hide us */
2313 descr->lphc->wState |= CBF_NOROLLUP;
2314 }
Gerard Patelc9a6d501999-07-25 13:03:17 +00002315 if (descr->nb_items) SEND_NOTIFICATION( wnd, descr, LBN_SELCHANGE );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002316 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002317 }
2318 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002319}
2320
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002321
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002322/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002323 * LISTBOX_HandleChar
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002324 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002325static LRESULT LISTBOX_HandleChar( WND *wnd, LB_DESCR *descr, WCHAR charW )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002326{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002327 INT caret = -1;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002328 WCHAR str[2];
2329
2330 str[0] = charW;
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002331 str[1] = '\0';
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002332
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002333 if (descr->style & LBS_WANTKEYBOARDINPUT)
2334 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002335 caret = SendMessageW( descr->owner, WM_CHARTOITEM,
2336 MAKEWPARAM(charW, descr->focus_item),
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002337 wnd->hwndSelf );
2338 if (caret == -2) return 0;
2339 }
2340 if (caret == -1)
2341 caret = LISTBOX_FindString( wnd, descr, descr->focus_item, str, FALSE);
2342 if (caret != -1)
2343 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00002344 if ((!IS_MULTISELECT(descr)) && descr->selected_item == -1)
2345 LISTBOX_SetSelection( wnd, descr, caret, TRUE, FALSE);
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002346 LISTBOX_MoveCaret( wnd, descr, caret, TRUE );
Gerard Patelc9a6d501999-07-25 13:03:17 +00002347 if ((descr->style & LBS_NOTIFY) && descr->nb_items)
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002348 SEND_NOTIFICATION( wnd, descr, LBN_SELCHANGE );
2349 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002350 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002351}
2352
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002353
2354/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002355 * LISTBOX_Create
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002356 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002357static BOOL LISTBOX_Create( WND *wnd, LPHEADCOMBO lphc )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002358{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002359 LB_DESCR *descr;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002360 MEASUREITEMSTRUCT mis;
2361 RECT rect;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002362
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002363 if (!(descr = HeapAlloc( GetProcessHeap(), 0, sizeof(*descr) )))
2364 return FALSE;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002365
Alexandre Julliarda3960291999-02-26 11:11:13 +00002366 GetClientRect( wnd->hwndSelf, &rect );
2367 descr->owner = GetParent( wnd->hwndSelf );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002368 descr->style = wnd->dwStyle;
2369 descr->width = rect.right - rect.left;
2370 descr->height = rect.bottom - rect.top;
2371 descr->items = NULL;
2372 descr->nb_items = 0;
2373 descr->top_item = 0;
2374 descr->selected_item = -1;
2375 descr->focus_item = 0;
2376 descr->anchor_item = -1;
2377 descr->item_height = 1;
2378 descr->page_size = 1;
2379 descr->column_width = 150;
2380 descr->horz_extent = (wnd->dwStyle & WS_HSCROLL) ? 1 : 0;
2381 descr->horz_pos = 0;
2382 descr->nb_tabs = 0;
2383 descr->tabs = NULL;
Serge Ivanov07917e42000-06-07 03:46:57 +00002384 descr->caret_on = lphc ? FALSE : TRUE;
Andreas Mohr85ba8792001-01-06 00:34:14 +00002385 if (descr->style & LBS_NOSEL) descr->caret_on = FALSE;
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002386 descr->in_focus = FALSE;
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002387 descr->captured = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002388 descr->font = 0;
2389 descr->locale = 0; /* FIXME */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002390 descr->lphc = lphc;
2391
Nick Hollowayb9ce4fd1999-09-11 16:29:00 +00002392 if( ( GetExpWinVer16( wnd->hInstance ) & 0xFF00 ) == 0x0300
2393 && ( descr->style & ( WS_VSCROLL | WS_HSCROLL ) ) )
2394 {
2395 /* Win95 document "List Box Differences" from MSDN:
2396 If a list box in a version 3.x application has either the
2397 WS_HSCROLL or WS_VSCROLL style, the list box receives both
2398 horizontal and vertical scroll bars.
2399 */
2400 descr->style |= WS_VSCROLL | WS_HSCROLL;
2401 }
2402
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002403 if( lphc )
2404 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +00002405 TRACE_(combo)("[%04x]: resetting owner %04x -> %04x\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002406 wnd->hwndSelf, descr->owner, lphc->self->hwndSelf );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002407 descr->owner = lphc->self->hwndSelf;
2408 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00002409
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002410 *(LB_DESCR **)wnd->wExtra = descr;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002411
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002412/* if (wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) descr->style &= ~LBS_NOTIFY;
2413 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002414 if (descr->style & LBS_EXTENDEDSEL) descr->style |= LBS_MULTIPLESEL;
2415 if (descr->style & LBS_MULTICOLUMN) descr->style &= ~LBS_OWNERDRAWVARIABLE;
2416 if (descr->style & LBS_OWNERDRAWVARIABLE) descr->style |= LBS_NOINTEGRALHEIGHT;
2417 descr->item_height = LISTBOX_SetFont( wnd, descr, 0 );
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002418
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002419 if (descr->style & LBS_OWNERDRAWFIXED)
2420 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002421 if( descr->lphc && (descr->lphc->dwStyle & CBS_DROPDOWN))
2422 {
2423 /* WinWord gets VERY unhappy if we send WM_MEASUREITEM from here */
Francis Beaudetf585c611999-04-02 10:37:42 +00002424 descr->item_height = lphc->fixedOwnerDrawHeight;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002425 }
2426 else
2427 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002428 mis.CtlType = ODT_LISTBOX;
Serge Ivanov07917e42000-06-07 03:46:57 +00002429 mis.CtlID = wnd->wIDmenu;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002430 mis.itemID = -1;
2431 mis.itemWidth = 0;
2432 mis.itemData = 0;
2433 mis.itemHeight = descr->item_height;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002434 SendMessageW( descr->owner, WM_MEASUREITEM, wnd->wIDmenu, (LPARAM)&mis );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002435 descr->item_height = mis.itemHeight ? mis.itemHeight : 1;
2436 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002437 }
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002438
Andreas Mohr85ba8792001-01-06 00:34:14 +00002439 TRACE("owner: %04x, style: %08x, width: %d, height: %d\n", descr->owner, descr->style, descr->width, descr->height);
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002440 return TRUE;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002441}
2442
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002443
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002444/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002445 * LISTBOX_Destroy
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002446 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002447static BOOL LISTBOX_Destroy( WND *wnd, LB_DESCR *descr )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002448{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002449 LISTBOX_ResetContent( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002450 HeapFree( GetProcessHeap(), 0, descr );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002451 wnd->wExtra[0] = 0;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00002452 return TRUE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002453}
2454
2455
2456/***********************************************************************
2457 * ListBoxWndProc
2458 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002459static LRESULT WINAPI ListBoxWndProc_locked( WND* wnd, UINT msg,
2460 WPARAM wParam, LPARAM lParam, BOOL unicode )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002461{
2462 LRESULT ret;
2463 LB_DESCR *descr;
Marcus Meissner9aded511999-05-01 10:23:45 +00002464 HWND hwnd = wnd->hwndSelf;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002465
2466 if (!wnd) return 0;
2467 if (!(descr = *(LB_DESCR **)wnd->wExtra))
2468 {
Francis Beaudetf6a225b1999-07-30 17:58:24 +00002469 switch (msg)
2470 {
2471 case WM_CREATE:
2472 {
2473 if (!LISTBOX_Create( wnd, NULL ))
2474 return -1;
2475 TRACE("creating wnd=%04x descr=%p\n",
2476 hwnd, *(LB_DESCR **)wnd->wExtra );
2477 return 0;
2478 }
2479 case WM_NCCREATE:
2480 {
2481 /*
2482 * When a listbox is not in a combobox and the look
2483 * is win95, the WS_BORDER style is replaced with
2484 * the WS_EX_CLIENTEDGE style.
2485 */
2486 if ( (TWEAK_WineLook > WIN31_LOOK) &&
2487 (wnd->dwStyle & WS_BORDER) )
2488 {
2489 wnd->dwExStyle |= WS_EX_CLIENTEDGE;
2490 wnd->dwStyle &= ~ WS_BORDER;
2491 }
2492 }
2493 }
2494
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002495 /* Ignore all other messages before we get a WM_CREATE */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002496 return unicode ? DefWindowProcW( hwnd, msg, wParam, lParam ) :
2497 DefWindowProcA( hwnd, msg, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002498 }
2499
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002500 TRACE("[%04x]: msg %s wp %08x lp %08lx\n",
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002501 wnd->hwndSelf, SPY_GetMsgName(msg), wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002502 switch(msg)
2503 {
2504 case LB_RESETCONTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002505 case LB_RESETCONTENT:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002506 LISTBOX_ResetContent( wnd, descr );
Louis Philippe Gagnon537bcad2000-11-30 20:37:29 +00002507 LISTBOX_UpdateScroll( wnd, descr );
2508 InvalidateRect( wnd->hwndSelf, NULL, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002509 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002510
2511 case LB_ADDSTRING16:
Alexandre Julliard982a2232000-12-13 20:20:09 +00002512 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002513 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002514 case LB_ADDSTRING:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002515 {
2516 INT ret;
2517 LPWSTR textW;
2518 if(unicode || !HAS_STRINGS(descr))
2519 textW = (LPWSTR)lParam;
2520 else
2521 {
2522 LPSTR textA = (LPSTR)lParam;
2523 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2524 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2525 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2526 }
2527 wParam = LISTBOX_FindStringPos( wnd, descr, textW, FALSE );
2528 ret = LISTBOX_InsertString( wnd, descr, wParam, textW );
2529 if (!unicode && HAS_STRINGS(descr))
2530 HeapFree(GetProcessHeap(), 0, textW);
2531 return ret;
2532 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002533
2534 case LB_INSERTSTRING16:
Alexandre Julliard982a2232000-12-13 20:20:09 +00002535 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002536 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002537 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002538 case LB_INSERTSTRING:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002539 {
2540 INT ret;
2541 LPWSTR textW;
2542 if(unicode || !HAS_STRINGS(descr))
2543 textW = (LPWSTR)lParam;
2544 else
2545 {
2546 LPSTR textA = (LPSTR)lParam;
2547 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2548 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2549 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2550 }
2551 ret = LISTBOX_InsertString( wnd, descr, wParam, textW );
2552 if(!unicode && HAS_STRINGS(descr))
2553 HeapFree(GetProcessHeap(), 0, textW);
2554 return ret;
2555 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002556
2557 case LB_ADDFILE16:
Alexandre Julliard982a2232000-12-13 20:20:09 +00002558 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002559 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002560 case LB_ADDFILE:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002561 {
2562 INT ret;
2563 LPWSTR textW;
2564 if(unicode || !HAS_STRINGS(descr))
2565 textW = (LPWSTR)lParam;
2566 else
2567 {
2568 LPSTR textA = (LPSTR)lParam;
2569 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2570 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2571 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2572 }
2573 wParam = LISTBOX_FindFileStrPos( wnd, descr, textW );
2574 ret = LISTBOX_InsertString( wnd, descr, wParam, textW );
2575 if(!unicode && HAS_STRINGS(descr))
2576 HeapFree(GetProcessHeap(), 0, textW);
2577 return ret;
2578 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002579
2580 case LB_DELETESTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002581 case LB_DELETESTRING:
Gerard Patelc9a6d501999-07-25 13:03:17 +00002582 if (LISTBOX_RemoveItem( wnd, descr, wParam) != LB_ERR)
2583 return descr->nb_items;
2584 else
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002585 return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002586
2587 case LB_GETITEMDATA16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002588 case LB_GETITEMDATA:
2589 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002590 return LB_ERR;
2591 return descr->items[wParam].data;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002592
2593 case LB_SETITEMDATA16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002594 case LB_SETITEMDATA:
2595 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002596 return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002597 descr->items[wParam].data = (DWORD)lParam;
Marcus Meissner9aded511999-05-01 10:23:45 +00002598 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002599
2600 case LB_GETCOUNT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002601 case LB_GETCOUNT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002602 return descr->nb_items;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002603
2604 case LB_GETTEXT16:
Alexandre Julliard982a2232000-12-13 20:20:09 +00002605 lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002606 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002607 case LB_GETTEXT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002608 return LISTBOX_GetText( descr, wParam, lParam, unicode );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002609
2610 case LB_GETTEXTLEN16:
2611 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002612 case LB_GETTEXTLEN:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002613 if ((INT)wParam >= descr->nb_items || (INT)wParam < 0)
Marcus Meissner9aded511999-05-01 10:23:45 +00002614 return LB_ERR;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002615 return (HAS_STRINGS(descr) ? strlenW(descr->items[wParam].str)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002616 : sizeof(DWORD));
2617
2618 case LB_GETCURSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002619 case LB_GETCURSEL:
Francis Beaudet8730e451999-03-25 13:22:02 +00002620 if (descr->nb_items==0)
Marcus Meissner9aded511999-05-01 10:23:45 +00002621 return LB_ERR;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002622 if (!IS_MULTISELECT(descr))
2623 return descr->selected_item;
Marcus Meissner9aded511999-05-01 10:23:45 +00002624 /* else */
2625 if (descr->selected_item!=-1)
2626 return descr->selected_item;
2627 /* else */
2628 return descr->focus_item;
Lawson Whitney613092a1999-03-22 14:46:43 +00002629 /* otherwise, if the user tries to move the selection with the */
2630 /* arrow keys, we will give the application something to choke on */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002631 case LB_GETTOPINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002632 case LB_GETTOPINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002633 return descr->top_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002634
2635 case LB_GETITEMHEIGHT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002636 case LB_GETITEMHEIGHT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002637 return LISTBOX_GetItemHeight( descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002638
2639 case LB_SETITEMHEIGHT16:
2640 lParam = LOWORD(lParam);
2641 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002642 case LB_SETITEMHEIGHT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002643 return LISTBOX_SetItemHeight( wnd, descr, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002644
Alexandre Julliarda3960291999-02-26 11:11:13 +00002645 case LB_ITEMFROMPOINT:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002646 {
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002647 POINT pt;
2648 RECT rect;
2649
2650 pt.x = LOWORD(lParam);
2651 pt.y = HIWORD(lParam);
2652 rect.left = 0;
2653 rect.top = 0;
2654 rect.right = descr->width;
2655 rect.bottom = descr->height;
2656
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002657 return MAKELONG( LISTBOX_GetItemFromPoint(descr, pt.x, pt.y),
Gerard Patel777508a1999-05-08 12:35:17 +00002658 !PtInRect( &rect, pt ) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002659 }
2660
2661 case LB_SETCARETINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002662 case LB_SETCARETINDEX:
Gerard Patelc9a6d501999-07-25 13:03:17 +00002663 if ((!IS_MULTISELECT(descr)) && (descr->selected_item != -1)) return LB_ERR;
2664 if (LISTBOX_SetCaretIndex( wnd, descr, wParam, !lParam ) == LB_ERR)
2665 return LB_ERR;
2666 else if (ISWIN31)
2667 return wParam;
2668 else
2669 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002670
2671 case LB_GETCARETINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002672 case LB_GETCARETINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002673 return descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002674
2675 case LB_SETTOPINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002676 case LB_SETTOPINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002677 return LISTBOX_SetTopItem( wnd, descr, wParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002678
2679 case LB_SETCOLUMNWIDTH16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002680 case LB_SETCOLUMNWIDTH:
Marcus Meissner9aded511999-05-01 10:23:45 +00002681 return LISTBOX_SetColumnWidth( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002682
2683 case LB_GETITEMRECT16:
2684 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002685 RECT rect;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002686 ret = LISTBOX_GetItemRect( descr, (INT16)wParam, &rect );
Alexandre Julliard982a2232000-12-13 20:20:09 +00002687 CONV_RECT32TO16( &rect, MapSL(lParam) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002688 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002689 return ret;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002690
Alexandre Julliarda3960291999-02-26 11:11:13 +00002691 case LB_GETITEMRECT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002692 return LISTBOX_GetItemRect( descr, wParam, (RECT *)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002693
2694 case LB_FINDSTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002695 wParam = (INT)(INT16)wParam;
Alexandre Julliard982a2232000-12-13 20:20:09 +00002696 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002697 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002698 case LB_FINDSTRING:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002699 {
2700 INT ret;
2701 LPWSTR textW;
2702 if(unicode || !HAS_STRINGS(descr))
2703 textW = (LPWSTR)lParam;
2704 else
2705 {
2706 LPSTR textA = (LPSTR)lParam;
2707 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2708 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2709 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2710 }
2711 ret = LISTBOX_FindString( wnd, descr, wParam, textW, FALSE );
2712 if(!unicode && HAS_STRINGS(descr))
2713 HeapFree(GetProcessHeap(), 0, textW);
2714 return ret;
2715 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002716
2717 case LB_FINDSTRINGEXACT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002718 wParam = (INT)(INT16)wParam;
Alexandre Julliard982a2232000-12-13 20:20:09 +00002719 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002720 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002721 case LB_FINDSTRINGEXACT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002722 {
2723 INT ret;
2724 LPWSTR textW;
2725 if(unicode || !HAS_STRINGS(descr))
2726 textW = (LPWSTR)lParam;
2727 else
2728 {
2729 LPSTR textA = (LPSTR)lParam;
2730 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2731 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2732 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2733 }
2734 ret = LISTBOX_FindString( wnd, descr, wParam, textW, TRUE );
2735 if(!unicode && HAS_STRINGS(descr))
2736 HeapFree(GetProcessHeap(), 0, textW);
2737 return ret;
2738 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002739
2740 case LB_SELECTSTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002741 wParam = (INT)(INT16)wParam;
Alexandre Julliard982a2232000-12-13 20:20:09 +00002742 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002743 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002744 case LB_SELECTSTRING:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002745 {
2746 INT index;
2747 LPWSTR textW;
2748 if(unicode || !HAS_STRINGS(descr))
2749 textW = (LPWSTR)lParam;
2750 else
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002751 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002752 LPSTR textA = (LPSTR)lParam;
2753 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2754 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2755 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002756 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002757 index = LISTBOX_FindString( wnd, descr, wParam, textW, FALSE );
2758 if(!unicode && HAS_STRINGS(descr))
2759 HeapFree(GetProcessHeap(), 0, textW);
2760 if (index != LB_ERR)
2761 LISTBOX_SetSelection( wnd, descr, index, TRUE, FALSE );
2762 return index;
2763 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002764
2765 case LB_GETSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002766 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002767 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002768 case LB_GETSEL:
2769 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002770 return LB_ERR;
2771 return descr->items[wParam].selected;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002772
2773 case LB_SETSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002774 lParam = (INT)(INT16)lParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002775 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002776 case LB_SETSEL:
Marcus Meissner9aded511999-05-01 10:23:45 +00002777 return LISTBOX_SetSelection( wnd, descr, lParam, wParam, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002778
2779 case LB_SETCURSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002780 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002781 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002782 case LB_SETCURSEL:
Gerard Patelc9a6d501999-07-25 13:03:17 +00002783 if (IS_MULTISELECT(descr)) return LB_ERR;
Alexandre Julliard638f1691999-01-17 16:32:32 +00002784 LISTBOX_SetCaretIndex( wnd, descr, wParam, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002785 return LISTBOX_SetSelection( wnd, descr, wParam, TRUE, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002786
2787 case LB_GETSELCOUNT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002788 case LB_GETSELCOUNT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002789 return LISTBOX_GetSelCount( descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002790
2791 case LB_GETSELITEMS16:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002792 return LISTBOX_GetSelItems16( descr, wParam, (LPINT16)MapSL(lParam) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002793
Alexandre Julliarda3960291999-02-26 11:11:13 +00002794 case LB_GETSELITEMS:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002795 return LISTBOX_GetSelItems( descr, wParam, (LPINT)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002796
2797 case LB_SELITEMRANGE16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002798 case LB_SELITEMRANGE:
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002799 if (LOWORD(lParam) <= HIWORD(lParam))
Marcus Meissner9aded511999-05-01 10:23:45 +00002800 return LISTBOX_SelectItemRange( wnd, descr, LOWORD(lParam),
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002801 HIWORD(lParam), wParam );
2802 else
Marcus Meissner9aded511999-05-01 10:23:45 +00002803 return LISTBOX_SelectItemRange( wnd, descr, HIWORD(lParam),
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002804 LOWORD(lParam), wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002805
2806 case LB_SELITEMRANGEEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002807 case LB_SELITEMRANGEEX:
2808 if ((INT)lParam >= (INT)wParam)
Marcus Meissner9aded511999-05-01 10:23:45 +00002809 return LISTBOX_SelectItemRange( wnd, descr, wParam, lParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002810 else
Marcus Meissner9aded511999-05-01 10:23:45 +00002811 return LISTBOX_SelectItemRange( wnd, descr, lParam, wParam, FALSE);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002812
2813 case LB_GETHORIZONTALEXTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002814 case LB_GETHORIZONTALEXTENT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002815 return descr->horz_extent;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002816
2817 case LB_SETHORIZONTALEXTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002818 case LB_SETHORIZONTALEXTENT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002819 return LISTBOX_SetHorizontalExtent( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002820
2821 case LB_GETANCHORINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002822 case LB_GETANCHORINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002823 return descr->anchor_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002824
2825 case LB_SETANCHORINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002826 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002827 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002828 case LB_SETANCHORINDEX:
2829 if (((INT)wParam < -1) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002830 return LB_ERR;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002831 descr->anchor_item = (INT)wParam;
Marcus Meissner9aded511999-05-01 10:23:45 +00002832 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002833
2834 case LB_DIR16:
Ove Kaaven2c691b32000-11-25 03:06:03 +00002835 /* according to Win16 docs, DDL_DRIVES should make DDL_EXCLUSIVE
2836 * be set automatically (this is different in Win32) */
2837 if (wParam & DDL_DRIVES) wParam |= DDL_EXCLUSIVE;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002838 lParam = (LPARAM)MapSL(lParam);
2839 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002840 case LB_DIR:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002841 {
2842 INT ret;
2843 LPWSTR textW;
2844 if(unicode)
2845 textW = (LPWSTR)lParam;
2846 else
2847 {
2848 LPSTR textA = (LPSTR)lParam;
2849 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2850 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2851 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2852 }
2853 ret = LISTBOX_Directory( wnd, descr, wParam, textW, msg == LB_DIR );
2854 if(!unicode)
2855 HeapFree(GetProcessHeap(), 0, textW);
2856 return ret;
2857 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002858
Alexandre Julliarda3960291999-02-26 11:11:13 +00002859 case LB_GETLOCALE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002860 return descr->locale;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002861
Alexandre Julliarda3960291999-02-26 11:11:13 +00002862 case LB_SETLOCALE:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002863 descr->locale = (LCID)wParam; /* FIXME: should check for valid lcid */
Marcus Meissner9aded511999-05-01 10:23:45 +00002864 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002865
Alexandre Julliarda3960291999-02-26 11:11:13 +00002866 case LB_INITSTORAGE:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002867 return LISTBOX_InitStorage( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002868
Alexandre Julliarda3960291999-02-26 11:11:13 +00002869 case LB_SETCOUNT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002870 return LISTBOX_SetCount( wnd, descr, (INT)wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002871
2872 case LB_SETTABSTOPS16:
Alexandre Julliard982a2232000-12-13 20:20:09 +00002873 return LISTBOX_SetTabStops( wnd, descr, (INT)(INT16)wParam, MapSL(lParam), TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002874
Alexandre Julliarda3960291999-02-26 11:11:13 +00002875 case LB_SETTABSTOPS:
Marcus Meissner9aded511999-05-01 10:23:45 +00002876 return LISTBOX_SetTabStops( wnd, descr, wParam, (LPINT)lParam, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002877
2878 case LB_CARETON16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002879 case LB_CARETON:
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002880 if (descr->caret_on)
Marcus Meissner9aded511999-05-01 10:23:45 +00002881 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002882 descr->caret_on = TRUE;
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002883 if ((descr->focus_item != -1) && (descr->in_focus))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002884 LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002885 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002886
2887 case LB_CARETOFF16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002888 case LB_CARETOFF:
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002889 if (!descr->caret_on)
Marcus Meissner9aded511999-05-01 10:23:45 +00002890 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002891 descr->caret_on = FALSE;
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002892 if ((descr->focus_item != -1) && (descr->in_focus))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002893 LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002894 return LB_OKAY;
Susan Farleyd34205e2000-05-15 02:34:20 +00002895
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002896 case WM_DESTROY:
Marcus Meissner9aded511999-05-01 10:23:45 +00002897 return LISTBOX_Destroy( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002898
2899 case WM_ENABLE:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002900 InvalidateRect( hwnd, NULL, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002901 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002902
2903 case WM_SETREDRAW:
2904 LISTBOX_SetRedraw( wnd, descr, wParam != 0 );
Marcus Meissner9aded511999-05-01 10:23:45 +00002905 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002906
2907 case WM_GETDLGCODE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002908 return DLGC_WANTARROWS | DLGC_WANTCHARS;
2909
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002910 case WM_PAINT:
2911 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002912 PAINTSTRUCT ps;
2913 HDC hdc = ( wParam ) ? ((HDC)wParam)
2914 : BeginPaint( hwnd, &ps );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002915 ret = LISTBOX_Paint( wnd, descr, hdc );
Alexandre Julliarda3960291999-02-26 11:11:13 +00002916 if( !wParam ) EndPaint( hwnd, &ps );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002917 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002918 return ret;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002919 case WM_SIZE:
2920 LISTBOX_UpdateSize( wnd, descr );
Marcus Meissner9aded511999-05-01 10:23:45 +00002921 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002922 case WM_GETFONT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002923 return descr->font;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002924 case WM_SETFONT:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002925 LISTBOX_SetFont( wnd, descr, (HFONT)wParam );
2926 if (lParam) InvalidateRect( wnd->hwndSelf, 0, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002927 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002928 case WM_SETFOCUS:
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002929 descr->in_focus = TRUE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002930 descr->caret_on = TRUE;
2931 if (descr->focus_item != -1)
2932 LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
2933 SEND_NOTIFICATION( wnd, descr, LBN_SETFOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002934 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002935 case WM_KILLFOCUS:
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002936 descr->in_focus = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002937 if ((descr->focus_item != -1) && descr->caret_on)
2938 LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
2939 SEND_NOTIFICATION( wnd, descr, LBN_KILLFOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002940 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002941 case WM_HSCROLL:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002942 return LISTBOX_HandleHScroll( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002943 case WM_VSCROLL:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002944 return LISTBOX_HandleVScroll( wnd, descr, wParam );
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002945 case WM_MOUSEACTIVATE:
2946 return MA_NOACTIVATE;
Stephane Lussier4bdf4af2000-04-18 11:56:33 +00002947 case WM_MOUSEWHEEL:
2948 if (wParam & (MK_SHIFT | MK_CONTROL))
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002949 return unicode ? DefWindowProcW( hwnd, msg, wParam, lParam ) :
2950 DefWindowProcA( hwnd, msg, wParam, lParam );
2951 return LISTBOX_HandleMouseWheel( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002952 case WM_LBUTTONDOWN:
Marcus Meissner9aded511999-05-01 10:23:45 +00002953 return LISTBOX_HandleLButtonDown( wnd, descr, wParam,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002954 (INT16)LOWORD(lParam),
2955 (INT16)HIWORD(lParam) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002956 case WM_LBUTTONDBLCLK:
2957 if (descr->style & LBS_NOTIFY)
2958 SEND_NOTIFICATION( wnd, descr, LBN_DBLCLK );
Marcus Meissner9aded511999-05-01 10:23:45 +00002959 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002960 case WM_MOUSEMOVE:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002961 if (GetCapture() == hwnd)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002962 LISTBOX_HandleMouseMove( wnd, descr, (INT16)LOWORD(lParam),
2963 (INT16)HIWORD(lParam) );
Marcus Meissner9aded511999-05-01 10:23:45 +00002964 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002965 case WM_LBUTTONUP:
Marcus Meissner9aded511999-05-01 10:23:45 +00002966 return LISTBOX_HandleLButtonUp( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002967 case WM_KEYDOWN:
Marcus Meissner9aded511999-05-01 10:23:45 +00002968 return LISTBOX_HandleKeyDown( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002969 case WM_CHAR:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002970 {
2971 WCHAR charW;
2972 if(unicode)
2973 charW = (WCHAR)wParam;
2974 else
2975 {
2976 CHAR charA = (CHAR)wParam;
2977 MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1);
2978 }
2979 return LISTBOX_HandleChar( wnd, descr, charW );
2980 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002981 case WM_SYSTIMER:
Marcus Meissner9aded511999-05-01 10:23:45 +00002982 return LISTBOX_HandleSystemTimer( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002983 case WM_ERASEBKGND:
Gerard Patel41b07fb2000-06-15 00:07:20 +00002984 if ((IS_OWNERDRAW(descr)) && !(descr->style & LBS_DISPLAYCHANGED))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002985 {
Luc Tourangeau89147991999-04-18 09:23:56 +00002986 RECT rect;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002987 HBRUSH hbrush = SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002988 wParam, (LPARAM)wnd->hwndSelf );
Dmitry Timoshkov52ece0e2001-02-26 22:31:55 +00002989 TRACE("hbrush = %04x\n", hbrush);
2990 if(!hbrush)
2991 hbrush = GetSysColorBrush(COLOR_WINDOW);
2992 if(hbrush)
2993 {
2994 GetClientRect(hwnd, &rect);
2995 FillRect((HDC)wParam, &rect, hbrush);
2996 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002997 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002998 return 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002999 case WM_DROPFILES:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003000 if( !descr->lphc )
3001 return unicode ? SendMessageW( descr->owner, msg, wParam, lParam ) :
3002 SendMessageA( descr->owner, msg, wParam, lParam );
3003 break;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003004
3005 case WM_DROPOBJECT:
3006 case WM_QUERYDROPOBJECT:
3007 case WM_DRAGSELECT:
3008 case WM_DRAGMOVE:
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003009 if( !descr->lphc )
3010 {
Alexandre Julliard982a2232000-12-13 20:20:09 +00003011 LPDRAGINFO16 dragInfo = MapSL( lParam );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003012 dragInfo->l = LISTBOX_GetItemFromPoint( descr, dragInfo->pt.x,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003013 dragInfo->pt.y );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003014 return SendMessage16( descr->owner, msg, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003015 }
3016 break;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003017
3018 default:
3019 if ((msg >= WM_USER) && (msg < 0xc000))
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003020 WARN("[%04x]: unknown msg %04x wp %08x lp %08lx\n",
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003021 hwnd, msg, wParam, lParam );
3022 return unicode ? DefWindowProcW( hwnd, msg, wParam, lParam ) :
3023 DefWindowProcA( hwnd, msg, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003024 }
Marcus Meissner9aded511999-05-01 10:23:45 +00003025 return 0;
3026}
3027
3028/***********************************************************************
Alexandre Julliard91222da2000-12-10 23:01:33 +00003029 * ListBoxWndProcA
Marcus Meissner9aded511999-05-01 10:23:45 +00003030 *
3031 * This is just a wrapper for the real wndproc, it only does window locking
3032 * and unlocking.
3033 */
Alexandre Julliard91222da2000-12-10 23:01:33 +00003034static LRESULT WINAPI ListBoxWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
Marcus Meissner9aded511999-05-01 10:23:45 +00003035{
3036 WND* wndPtr = WIN_FindWndPtr( hwnd );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003037 LRESULT res = ListBoxWndProc_locked(wndPtr, msg, wParam, lParam, FALSE);
Marcus Meissner9aded511999-05-01 10:23:45 +00003038
3039 WIN_ReleaseWndPtr(wndPtr);
3040 return res;
Alexandre Julliard58199531994-04-21 01:20:00 +00003041}
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003042
3043/***********************************************************************
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003044 * ListBoxWndProcW
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003045 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003046static LRESULT WINAPI ListBoxWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003047{
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003048 WND* wndPtr = WIN_FindWndPtr( hwnd );
3049 LRESULT res = ListBoxWndProc_locked(wndPtr, msg, wParam, lParam, TRUE);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003050
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003051 WIN_ReleaseWndPtr(wndPtr);
3052 return res;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003053}
3054
3055/***********************************************************************
Marcus Meissner9aded511999-05-01 10:23:45 +00003056 * ComboLBWndProc_locked
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003057 *
Marcus Meissner9aded511999-05-01 10:23:45 +00003058 * The real combo listbox wndproc, but called with locked WND struct.
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003059 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003060static LRESULT WINAPI ComboLBWndProc_locked( WND* wnd, UINT msg,
3061 WPARAM wParam, LPARAM lParam, BOOL unicode )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003062{
3063 LRESULT lRet = 0;
Marcus Meissner9aded511999-05-01 10:23:45 +00003064 HWND hwnd = wnd->hwndSelf;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003065
3066 if (wnd)
3067 {
3068 LB_DESCR *descr = *(LB_DESCR **)wnd->wExtra;
3069
Alexandre Julliard06c275a1999-05-02 14:32:27 +00003070 TRACE_(combo)("[%04x]: msg %s wp %08x lp %08lx\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00003071 wnd->hwndSelf, SPY_GetMsgName(msg), wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003072
3073 if( descr || msg == WM_CREATE )
3074 {
3075 LPHEADCOMBO lphc = (descr) ? descr->lphc : NULL;
3076
3077 switch( msg )
3078 {
3079 case WM_CREATE:
Alexandre Julliarda3960291999-02-26 11:11:13 +00003080#define lpcs ((LPCREATESTRUCTA)lParam)
Alexandre Julliard06c275a1999-05-02 14:32:27 +00003081 TRACE_(combo)("\tpassed parent handle = 0x%08x\n",
Alexandre Julliarda3960291999-02-26 11:11:13 +00003082 (UINT)lpcs->lpCreateParams);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003083
3084 lphc = (LPHEADCOMBO)(lpcs->lpCreateParams);
3085#undef lpcs
Marcus Meissner9aded511999-05-01 10:23:45 +00003086 return LISTBOX_Create( wnd, lphc );
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003087 case WM_MOUSEMOVE:
3088 if ( (TWEAK_WineLook > WIN31_LOOK) &&
3089 (CB_GETTYPE(lphc) != CBS_SIMPLE) )
3090 {
3091 POINT mousePos;
3092 BOOL captured;
3093 RECT clientRect;
3094
3095 mousePos.x = (INT16)LOWORD(lParam);
3096 mousePos.y = (INT16)HIWORD(lParam);
3097
3098 /*
3099 * If we are in a dropdown combobox, we simulate that
3100 * the mouse is captured to show the tracking of the item.
3101 */
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003102 GetClientRect(hwnd, &clientRect);
3103
Pierre Mageau25c62cc1999-09-11 16:26:03 +00003104 if (PtInRect( &clientRect, mousePos ))
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003105 {
Pierre Mageau25c62cc1999-09-11 16:26:03 +00003106 captured = descr->captured;
3107 descr->captured = TRUE;
3108
3109 LISTBOX_HandleMouseMove( wnd, descr,
3110 mousePos.x, mousePos.y);
3111
3112 descr->captured = captured;
3113
3114 }
3115 else
3116 {
3117 LISTBOX_HandleMouseMove( wnd, descr,
3118 mousePos.x, mousePos.y);
3119 }
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003120
3121 return 0;
Pierre Mageau25c62cc1999-09-11 16:26:03 +00003122
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003123 }
3124 else
3125 {
3126 /*
3127 * If we are in Win3.1 look, go with the default behavior.
3128 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003129 return unicode ? ListBoxWndProcW( hwnd, msg, wParam, lParam ) :
3130 ListBoxWndProcA( hwnd, msg, wParam, lParam );
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003131 }
3132 case WM_LBUTTONUP:
3133 if (TWEAK_WineLook > WIN31_LOOK)
3134 {
3135 POINT mousePos;
3136 RECT clientRect;
3137
3138 /*
3139 * If the mouse button "up" is not in the listbox,
3140 * we make sure there is no selection by re-selecting the
3141 * item that was selected when the listbox was made visible.
3142 */
3143 mousePos.x = (INT16)LOWORD(lParam);
3144 mousePos.y = (INT16)HIWORD(lParam);
3145
3146 GetClientRect(hwnd, &clientRect);
3147
3148 /*
3149 * When the user clicks outside the combobox and the focus
3150 * is lost, the owning combobox will send a fake buttonup with
3151 * 0xFFFFFFF as the mouse location, we must also revert the
3152 * selection to the original selection.
3153 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003154 if ( (lParam == (LPARAM)-1) ||
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003155 (!PtInRect( &clientRect, mousePos )) )
3156 {
3157 LISTBOX_MoveCaret( wnd,
3158 descr,
3159 lphc->droppedIndex,
3160 FALSE );
3161 }
3162 }
3163 return LISTBOX_HandleLButtonUp( wnd, descr );
Chris Morganc0872e32000-05-07 18:24:36 +00003164 case WM_LBUTTONDBLCLK:
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003165 case WM_LBUTTONDOWN:
Alexandre Julliard7f90a8c2000-05-23 04:18:12 +00003166 return LISTBOX_HandleLButtonDownCombo(wnd, descr, msg, wParam,
Pierre Mageau25c62cc1999-09-11 16:26:03 +00003167 (INT16)LOWORD(lParam),
3168 (INT16)HIWORD(lParam) );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003169 case WM_MOUSEACTIVATE:
Marcus Meissner9aded511999-05-01 10:23:45 +00003170 return MA_NOACTIVATE;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003171 case WM_NCACTIVATE:
Marcus Meissner9aded511999-05-01 10:23:45 +00003172 return FALSE;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003173 case WM_KEYDOWN:
3174 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
3175 {
3176 /* for some reason(?) Windows makes it possible to
3177 * show/hide ComboLBox by sending it WM_KEYDOWNs */
3178
3179 if( (!(lphc->wState & CBF_EUI) && wParam == VK_F4) ||
3180 ( (lphc->wState & CBF_EUI) && !(lphc->wState & CBF_DROPPED)
3181 && (wParam == VK_DOWN || wParam == VK_UP)) )
3182 {
Serge Ivanov07917e42000-06-07 03:46:57 +00003183 COMBO_FlipListbox( lphc, FALSE, FALSE );
Marcus Meissner9aded511999-05-01 10:23:45 +00003184 return 0;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003185 }
3186 }
Marcus Meissner9aded511999-05-01 10:23:45 +00003187 return LISTBOX_HandleKeyDown( wnd, descr, wParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003188
Alex Korobka311d3291999-01-01 18:40:02 +00003189 case LB_SETCURSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00003190 case LB_SETCURSEL:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003191 lRet = unicode ? ListBoxWndProcW( hwnd, msg, wParam, lParam ) :
3192 ListBoxWndProcA( hwnd, msg, wParam, lParam );
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00003193 lRet =(lRet == LB_ERR) ? lRet : descr->selected_item;
Marcus Meissner9aded511999-05-01 10:23:45 +00003194 return lRet;
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00003195 case WM_NCDESTROY:
3196 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
3197 lphc->hWndLBox = 0;
3198 /* fall through */
3199
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003200 default:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003201 return unicode ? ListBoxWndProcW( hwnd, msg, wParam, lParam ) :
3202 ListBoxWndProcA( hwnd, msg, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003203 }
3204 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003205 lRet = unicode ? DefWindowProcW( hwnd, msg, wParam, lParam ) :
3206 DefWindowProcA( hwnd, msg, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003207
Alexandre Julliard06c275a1999-05-02 14:32:27 +00003208 TRACE_(combo)("\t default on msg [%04x]\n", (UINT16)msg );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003209 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003210 return lRet;
3211}
3212
Marcus Meissner9aded511999-05-01 10:23:45 +00003213/***********************************************************************
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003214 * ComboLBWndProcA
Marcus Meissner9aded511999-05-01 10:23:45 +00003215 *
3216 * NOTE: in Windows, winproc address of the ComboLBox is the same
3217 * as that of the Listbox.
3218 *
3219 * This is just a wrapper for the real wndproc, it only does window locking
3220 * and unlocking.
3221 */
Alexandre Julliard91222da2000-12-10 23:01:33 +00003222LRESULT WINAPI ComboLBWndProcA( HWND hwnd, UINT msg,
Marcus Meissner9aded511999-05-01 10:23:45 +00003223 WPARAM wParam, LPARAM lParam )
3224{
3225 WND *wnd = WIN_FindWndPtr( hwnd );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003226 LRESULT res = ComboLBWndProc_locked(wnd, msg, wParam, lParam, FALSE);
3227
3228 WIN_ReleaseWndPtr(wnd);
3229 return res;
3230}
3231
3232/***********************************************************************
3233 * ComboLBWndProcW
3234 */
3235LRESULT WINAPI ComboLBWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
3236{
3237 WND *wnd = WIN_FindWndPtr( hwnd );
3238 LRESULT res = ComboLBWndProc_locked(wnd, msg, wParam, lParam, TRUE);
Marcus Meissner9aded511999-05-01 10:23:45 +00003239
3240 WIN_ReleaseWndPtr(wnd);
3241 return res;
3242}