blob: 99e4103927b3484761175f05f24562f1d9a24ba6 [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
Dmitry Timoshkove8ffcaa2001-04-16 19:32:19 +0000756 TRACE("index %d (0x%04x) %s\n", index, index, debugstr_w(descr->items[index].str));
757
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000758 if(unicode)
759 {
760 LPWSTR buffer = (LPWSTR)lParam;
761 strcpyW( buffer, descr->items[index].str );
762 return strlenW(buffer);
763 }
764 else
765 {
766 LPSTR buffer = (LPSTR)lParam;
Gerard Pateldb8fb6f2001-01-10 23:54:46 +0000767 return WideCharToMultiByte(CP_ACP, 0, descr->items[index].str, -1, buffer, 0x7FFFFFFF, NULL, NULL) - 1;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000768 }
Marcus Meissner4f7dc461998-11-22 15:43:34 +0000769 } else {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000770 if (lParam)
771 *((LPDWORD)lParam)=*(LPDWORD)(&descr->items[index].data);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000772 return sizeof(DWORD);
773 }
Alexandre Julliard2787be81995-05-22 18:23:01 +0000774}
775
776
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000777/***********************************************************************
778 * LISTBOX_FindStringPos
779 *
780 * Find the nearest string located before a given string in sort order.
781 * If 'exact' is TRUE, return an error if we don't get an exact match.
782 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000783static INT LISTBOX_FindStringPos( WND *wnd, LB_DESCR *descr, LPCWSTR str,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000784 BOOL exact )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000785{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000786 INT index, min, max, res = -1;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000787
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000788 if (!(descr->style & LBS_SORT)) return -1; /* Add it at the end */
789 min = 0;
790 max = descr->nb_items;
791 while (min != max)
792 {
793 index = (min + max) / 2;
794 if (HAS_STRINGS(descr))
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000795 res = lstrcmpiW( descr->items[index].str, str );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000796 else
797 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000798 COMPAREITEMSTRUCT cis;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000799
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000800 cis.CtlType = ODT_LISTBOX;
Serge Ivanov07917e42000-06-07 03:46:57 +0000801 cis.CtlID = wnd->wIDmenu;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000802 cis.hwndItem = wnd->hwndSelf;
803 cis.itemID1 = index;
804 cis.itemData1 = descr->items[index].data;
805 cis.itemID2 = -1;
806 cis.itemData2 = (DWORD)str;
807 cis.dwLocaleId = descr->locale;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000808 res = SendMessageW( descr->owner, WM_COMPAREITEM,
Serge Ivanov07917e42000-06-07 03:46:57 +0000809 wnd->wIDmenu, (LPARAM)&cis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000810 }
811 if (!res) return index;
812 if (res > 0) max = index;
813 else min = index + 1;
814 }
815 return exact ? -1 : max;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000816}
817
818
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000819/***********************************************************************
820 * LISTBOX_FindFileStrPos
821 *
822 * Find the nearest string located before a given string in directory
823 * sort order (i.e. first files, then directories, then drives).
824 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000825static INT LISTBOX_FindFileStrPos( WND *wnd, LB_DESCR *descr, LPCWSTR str )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000826{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000827 INT min, max, res = -1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000828
829 if (!HAS_STRINGS(descr))
830 return LISTBOX_FindStringPos( wnd, descr, str, FALSE );
831 min = 0;
832 max = descr->nb_items;
833 while (min != max)
834 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000835 INT index = (min + max) / 2;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000836 LPCWSTR p = descr->items[index].str;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000837 if (*p == '[') /* drive or directory */
838 {
839 if (*str != '[') res = -1;
840 else if (p[1] == '-') /* drive */
841 {
842 if (str[1] == '-') res = str[2] - p[2];
843 else res = -1;
844 }
845 else /* directory */
846 {
847 if (str[1] == '-') res = 1;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000848 else res = lstrcmpiW( str, p );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000849 }
850 }
851 else /* filename */
852 {
853 if (*str == '[') res = 1;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000854 else res = lstrcmpiW( str, p );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000855 }
856 if (!res) return index;
857 if (res < 0) max = index;
858 else min = index + 1;
859 }
860 return max;
861}
862
863
864/***********************************************************************
865 * LISTBOX_FindString
866 *
867 * Find the item beginning with a given string.
868 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000869static INT LISTBOX_FindString( WND *wnd, LB_DESCR *descr, INT start,
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000870 LPCWSTR str, BOOL exact )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000871{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000872 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000873 LB_ITEMDATA *item;
874
875 if (start >= descr->nb_items) start = -1;
876 item = descr->items + start + 1;
877 if (HAS_STRINGS(descr))
878 {
Rein Klazesd35c8341999-08-21 13:04:58 +0000879 if (!str || ! str[0] ) return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000880 if (exact)
881 {
882 for (i = start + 1; i < descr->nb_items; 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 for (i = 0, item = descr->items; i <= start; i++, item++)
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000885 if (!lstrcmpiW( str, item->str )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000886 }
887 else
888 {
889 /* Special case for drives and directories: ignore prefix */
890#define CHECK_DRIVE(item) \
891 if ((item)->str[0] == '[') \
892 { \
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000893 if (!strncmpiW( str, (item)->str+1, len )) return i; \
894 if (((item)->str[1] == '-') && !strncmpiW(str, (item)->str+2, len)) \
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000895 return i; \
896 }
897
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000898 INT len = strlenW(str);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000899 for (i = start + 1; i < descr->nb_items; i++, item++)
900 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000901 if (!strncmpiW( str, item->str, len )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000902 CHECK_DRIVE(item);
903 }
904 for (i = 0, item = descr->items; i <= start; i++, item++)
905 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000906 if (!strncmpiW( str, item->str, len )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000907 CHECK_DRIVE(item);
908 }
909#undef CHECK_DRIVE
910 }
911 }
912 else
913 {
914 if (exact && (descr->style & LBS_SORT))
915 /* If sorted, use a WM_COMPAREITEM binary search */
916 return LISTBOX_FindStringPos( wnd, descr, str, TRUE );
917
918 /* Otherwise use a linear search */
919 for (i = start + 1; i < descr->nb_items; i++, item++)
920 if (item->data == (DWORD)str) return i;
921 for (i = 0, item = descr->items; i <= start; i++, item++)
922 if (item->data == (DWORD)str) return i;
923 }
924 return LB_ERR;
925}
926
927
928/***********************************************************************
929 * LISTBOX_GetSelCount
930 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000931static LRESULT LISTBOX_GetSelCount( LB_DESCR *descr )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000932{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000933 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000934 LB_ITEMDATA *item = descr->items;
935
936 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
937 for (i = count = 0; i < descr->nb_items; i++, item++)
938 if (item->selected) count++;
939 return count;
940}
941
942
943/***********************************************************************
944 * LISTBOX_GetSelItems16
945 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000946static LRESULT LISTBOX_GetSelItems16( LB_DESCR *descr, INT16 max, LPINT16 array )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000947{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000948 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000949 LB_ITEMDATA *item = descr->items;
950
951 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
952 for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++)
953 if (item->selected) array[count++] = (INT16)i;
954 return count;
955}
956
957
958/***********************************************************************
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000959 * LISTBOX_GetSelItems
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000960 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000961static LRESULT LISTBOX_GetSelItems( LB_DESCR *descr, INT max, LPINT array )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000962{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000963 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000964 LB_ITEMDATA *item = descr->items;
965
966 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
967 for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++)
968 if (item->selected) array[count++] = i;
969 return count;
970}
971
972
973/***********************************************************************
974 * LISTBOX_Paint
975 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000976static LRESULT LISTBOX_Paint( WND *wnd, LB_DESCR *descr, HDC hdc )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000977{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000978 INT i, col_pos = descr->page_size - 1;
979 RECT rect;
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +0000980 RECT focusRect = {-1, -1, -1, -1};
Alexandre Julliarda3960291999-02-26 11:11:13 +0000981 HFONT oldFont = 0;
982 HBRUSH hbrush, oldBrush = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000983
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000984 if (descr->style & LBS_NOREDRAW) return 0;
Serge Ivanov07917e42000-06-07 03:46:57 +0000985
986 SetRect( &rect, 0, 0, descr->width, descr->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000987 if (descr->style & LBS_MULTICOLUMN)
988 rect.right = rect.left + descr->column_width;
989 else if (descr->horz_pos)
990 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000991 SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000992 rect.right += descr->horz_pos;
993 }
994
Alexandre Julliarda3960291999-02-26 11:11:13 +0000995 if (descr->font) oldFont = SelectObject( hdc, descr->font );
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000996 hbrush = SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000997 hdc, (LPARAM)wnd->hwndSelf );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000998 if (hbrush) oldBrush = SelectObject( hdc, hbrush );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000999 if (wnd->dwStyle & WS_DISABLED)
Alexandre Julliarda3960291999-02-26 11:11:13 +00001000 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001001
1002 if (!descr->nb_items && (descr->focus_item != -1) && descr->caret_on &&
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00001003 (descr->in_focus))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001004 {
1005 /* Special case for empty listbox: paint focus rect */
1006 rect.bottom = rect.top + descr->item_height;
1007 LISTBOX_PaintItem( wnd, descr, hdc, &rect, descr->focus_item,
Gerard Patel8caa4072000-09-24 19:29:18 +00001008 ODA_FOCUS, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001009 rect.top = rect.bottom;
1010 }
1011
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001012 /* Paint all the item, regarding the selection
1013 Focus state will be painted after */
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001014
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001015 for (i = descr->top_item; i < descr->nb_items; i++)
1016 {
1017 if (!(descr->style & LBS_OWNERDRAWVARIABLE))
1018 rect.bottom = rect.top + descr->item_height;
1019 else
1020 rect.bottom = rect.top + descr->items[i].height;
1021
Gerard Patel8caa4072000-09-24 19:29:18 +00001022 if (i == descr->focus_item)
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001023 {
1024 /* keep the focus rect, to paint the focus item after */
1025 focusRect.left = rect.left;
1026 focusRect.right = rect.right;
1027 focusRect.top = rect.top;
1028 focusRect.bottom = rect.bottom;
1029 }
Gerard Patel8caa4072000-09-24 19:29:18 +00001030 LISTBOX_PaintItem( wnd, descr, hdc, &rect, i, ODA_DRAWENTIRE, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001031 rect.top = rect.bottom;
1032
1033 if ((descr->style & LBS_MULTICOLUMN) && !col_pos)
1034 {
1035 if (!IS_OWNERDRAW(descr))
1036 {
1037 /* Clear the bottom of the column */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001038 if (rect.top < descr->height)
1039 {
1040 rect.bottom = descr->height;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001041 ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001042 &rect, NULL, 0, NULL );
1043 }
1044 }
1045
1046 /* Go to the next column */
1047 rect.left += descr->column_width;
1048 rect.right += descr->column_width;
1049 rect.top = 0;
1050 col_pos = descr->page_size - 1;
1051 }
1052 else
1053 {
1054 col_pos--;
1055 if (rect.top >= descr->height) break;
1056 }
1057 }
1058
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001059 /* Paint the focus item now */
Serge Ivanov07917e42000-06-07 03:46:57 +00001060 if (focusRect.top != focusRect.bottom && descr->caret_on)
Gerard Patel8caa4072000-09-24 19:29:18 +00001061 LISTBOX_PaintItem( wnd, descr, hdc, &focusRect, descr->focus_item, ODA_FOCUS, FALSE );
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001062
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001063 if (!IS_OWNERDRAW(descr))
1064 {
1065 /* Clear the remainder of the client area */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001066 if (rect.top < descr->height)
1067 {
1068 rect.bottom = descr->height;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001069 ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001070 &rect, NULL, 0, NULL );
1071 }
1072 if (rect.right < descr->width)
1073 {
1074 rect.left = rect.right;
1075 rect.right = descr->width;
1076 rect.top = 0;
1077 rect.bottom = descr->height;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001078 ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001079 &rect, NULL, 0, NULL );
1080 }
1081 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001082 if (oldFont) SelectObject( hdc, oldFont );
1083 if (oldBrush) SelectObject( hdc, oldBrush );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001084 return 0;
1085}
1086
1087
1088/***********************************************************************
1089 * LISTBOX_InvalidateItems
1090 *
1091 * Invalidate all items from a given item. If the specified item is not
1092 * visible, nothing happens.
1093 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001094static void LISTBOX_InvalidateItems( WND *wnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001095{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001096 RECT rect;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001097
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001098 if (LISTBOX_GetItemRect( descr, index, &rect ) == 1)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001099 {
Gerard Patel41b07fb2000-06-15 00:07:20 +00001100 if (descr->style & LBS_NOREDRAW)
1101 {
1102 descr->style |= LBS_DISPLAYCHANGED;
1103 return;
1104 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001105 rect.bottom = descr->height;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001106 InvalidateRect( wnd->hwndSelf, &rect, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001107 if (descr->style & LBS_MULTICOLUMN)
1108 {
1109 /* Repaint the other columns */
1110 rect.left = rect.right;
1111 rect.right = descr->width;
1112 rect.top = 0;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001113 InvalidateRect( wnd->hwndSelf, &rect, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001114 }
1115 }
1116}
1117
1118
1119/***********************************************************************
1120 * LISTBOX_GetItemHeight
1121 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001122static LRESULT LISTBOX_GetItemHeight( LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001123{
1124 if (descr->style & LBS_OWNERDRAWVARIABLE)
1125 {
1126 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
1127 return descr->items[index].height;
1128 }
1129 else return descr->item_height;
1130}
1131
1132
1133/***********************************************************************
1134 * LISTBOX_SetItemHeight
1135 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001136static LRESULT LISTBOX_SetItemHeight( WND *wnd, LB_DESCR *descr, INT index,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001137 INT height )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001138{
1139 if (!height) height = 1;
1140
1141 if (descr->style & LBS_OWNERDRAWVARIABLE)
1142 {
1143 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001144 TRACE("[%04x]: item %d height = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001145 wnd->hwndSelf, index, height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001146 descr->items[index].height = height;
1147 LISTBOX_UpdateScroll( wnd, descr );
1148 LISTBOX_InvalidateItems( wnd, descr, index );
1149 }
1150 else if (height != descr->item_height)
1151 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001152 TRACE("[%04x]: new height = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001153 wnd->hwndSelf, height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001154 descr->item_height = height;
1155 LISTBOX_UpdatePage( wnd, descr );
1156 LISTBOX_UpdateScroll( wnd, descr );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001157 InvalidateRect( wnd->hwndSelf, 0, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001158 }
1159 return LB_OKAY;
1160}
1161
1162
1163/***********************************************************************
1164 * LISTBOX_SetHorizontalPos
1165 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001166static void LISTBOX_SetHorizontalPos( WND *wnd, LB_DESCR *descr, INT pos )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001167{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001168 INT diff;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001169
1170 if (pos > descr->horz_extent - descr->width)
1171 pos = descr->horz_extent - descr->width;
1172 if (pos < 0) pos = 0;
1173 if (!(diff = descr->horz_pos - pos)) return;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001174 TRACE("[%04x]: new horz pos = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001175 wnd->hwndSelf, pos );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001176 descr->horz_pos = pos;
1177 LISTBOX_UpdateScroll( wnd, descr );
1178 if (abs(diff) < descr->width)
Alexandre Julliarda3960291999-02-26 11:11:13 +00001179 ScrollWindowEx( wnd->hwndSelf, diff, 0, NULL, NULL, 0, NULL,
NF Stevens762f18d1999-01-24 19:02:16 +00001180 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001181 else
Alexandre Julliarda3960291999-02-26 11:11:13 +00001182 InvalidateRect( wnd->hwndSelf, NULL, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001183}
1184
1185
1186/***********************************************************************
1187 * LISTBOX_SetHorizontalExtent
1188 */
1189static LRESULT LISTBOX_SetHorizontalExtent( WND *wnd, LB_DESCR *descr,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001190 INT extent )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001191{
1192 if (!descr->horz_extent || (descr->style & LBS_MULTICOLUMN))
1193 return LB_OKAY;
1194 if (extent <= 0) extent = 1;
1195 if (extent == descr->horz_extent) return LB_OKAY;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001196 TRACE("[%04x]: new horz extent = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001197 wnd->hwndSelf, extent );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001198 descr->horz_extent = extent;
1199 if (descr->horz_pos > extent - descr->width)
1200 LISTBOX_SetHorizontalPos( wnd, descr, extent - descr->width );
1201 else
1202 LISTBOX_UpdateScroll( wnd, descr );
1203 return LB_OKAY;
1204}
1205
1206
1207/***********************************************************************
1208 * LISTBOX_SetColumnWidth
1209 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001210static LRESULT LISTBOX_SetColumnWidth( WND *wnd, LB_DESCR *descr, INT width)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001211{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001212 if (width == descr->column_width) return LB_OKAY;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001213 TRACE("[%04x]: new column width = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001214 wnd->hwndSelf, width );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001215 descr->column_width = width;
1216 LISTBOX_UpdatePage( wnd, descr );
1217 return LB_OKAY;
1218}
1219
1220
1221/***********************************************************************
1222 * LISTBOX_SetFont
1223 *
1224 * Returns the item height.
1225 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001226static INT LISTBOX_SetFont( WND *wnd, LB_DESCR *descr, HFONT font )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001227{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001228 HDC hdc;
1229 HFONT oldFont = 0;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001230 TEXTMETRICW tm;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001231
1232 descr->font = font;
1233
Alexandre Julliarda3960291999-02-26 11:11:13 +00001234 if (!(hdc = GetDCEx( wnd->hwndSelf, 0, DCX_CACHE )))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001235 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001236 ERR("unable to get DC.\n" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001237 return 16;
1238 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001239 if (font) oldFont = SelectObject( hdc, font );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001240 GetTextMetricsW( hdc, &tm );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001241 if (oldFont) SelectObject( hdc, oldFont );
1242 ReleaseDC( wnd->hwndSelf, hdc );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001243 if (!IS_OWNERDRAW(descr))
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001244 LISTBOX_SetItemHeight( wnd, descr, 0, tm.tmHeight );
1245 return tm.tmHeight ;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001246}
1247
1248
1249/***********************************************************************
1250 * LISTBOX_MakeItemVisible
1251 *
1252 * Make sure that a given item is partially or fully visible.
1253 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001254static void LISTBOX_MakeItemVisible( WND *wnd, LB_DESCR *descr, INT index,
1255 BOOL fully )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001256{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001257 INT top;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001258
1259 if (index <= descr->top_item) top = index;
1260 else if (descr->style & LBS_MULTICOLUMN)
1261 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001262 INT cols = descr->width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001263 if (!fully) cols += descr->column_width - 1;
1264 if (cols >= descr->column_width) cols /= descr->column_width;
1265 else cols = 1;
1266 if (index < descr->top_item + (descr->page_size * cols)) return;
1267 top = index - descr->page_size * (cols - 1);
1268 }
1269 else if (descr->style & LBS_OWNERDRAWVARIABLE)
1270 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001271 INT height = fully ? descr->items[index].height : 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001272 for (top = index; top > descr->top_item; top--)
1273 if ((height += descr->items[top-1].height) > descr->height) break;
1274 }
1275 else
1276 {
1277 if (index < descr->top_item + descr->page_size) return;
1278 if (!fully && (index == descr->top_item + descr->page_size) &&
1279 (descr->height > (descr->page_size * descr->item_height))) return;
1280 top = index - descr->page_size + 1;
1281 }
1282 LISTBOX_SetTopItem( wnd, descr, top, TRUE );
1283}
1284
Gerard Patel2ffbb312000-07-09 12:18:14 +00001285/***********************************************************************
1286 * LISTBOX_SetCaretIndex
1287 *
1288 * NOTES
1289 * index must be between 0 and descr->nb_items-1, or LB_ERR is returned.
1290 *
1291 */
1292static LRESULT LISTBOX_SetCaretIndex( WND *wnd, LB_DESCR *descr, INT index,
1293 BOOL fully_visible )
1294{
1295 INT oldfocus = descr->focus_item;
1296
Andreas Mohr85ba8792001-01-06 00:34:14 +00001297 if (descr->style & LBS_NOSEL) return LB_ERR;
Gerard Patel2ffbb312000-07-09 12:18:14 +00001298 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
1299 if (index == oldfocus) return LB_OKAY;
1300 descr->focus_item = index;
1301 if ((oldfocus != -1) && descr->caret_on && (descr->in_focus))
1302 LISTBOX_RepaintItem( wnd, descr, oldfocus, ODA_FOCUS );
1303
1304 LISTBOX_MakeItemVisible( wnd, descr, index, fully_visible );
1305 if (descr->caret_on && (descr->in_focus))
1306 LISTBOX_RepaintItem( wnd, descr, index, ODA_FOCUS );
1307
1308 return LB_OKAY;
1309}
1310
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001311
1312/***********************************************************************
1313 * LISTBOX_SelectItemRange
1314 *
1315 * Select a range of items. Should only be used on a MULTIPLESEL listbox.
1316 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001317static LRESULT LISTBOX_SelectItemRange( WND *wnd, LB_DESCR *descr, INT first,
1318 INT last, BOOL on )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001319{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001320 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001321
1322 /* A few sanity checks */
1323
Andreas Mohr85ba8792001-01-06 00:34:14 +00001324 if (descr->style & LBS_NOSEL) return LB_ERR;
Alexandre Julliard03468f71998-02-15 19:40:49 +00001325 if ((last == -1) && (descr->nb_items == 0)) return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001326 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
1327 if (last == -1) last = descr->nb_items - 1;
1328 if ((first < 0) || (first >= descr->nb_items)) return LB_ERR;
1329 if ((last < 0) || (last >= descr->nb_items)) return LB_ERR;
1330 /* selected_item reflects last selected/unselected item on multiple sel */
1331 descr->selected_item = last;
1332
1333 if (on) /* Turn selection on */
1334 {
1335 for (i = first; i <= last; i++)
1336 {
1337 if (descr->items[i].selected) continue;
1338 descr->items[i].selected = TRUE;
1339 LISTBOX_RepaintItem( wnd, descr, i, ODA_SELECT );
1340 }
Gerard Patel2ffbb312000-07-09 12:18:14 +00001341 LISTBOX_SetCaretIndex( wnd, descr, last, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001342 }
1343 else /* Turn selection off */
1344 {
1345 for (i = first; i <= last; i++)
1346 {
1347 if (!descr->items[i].selected) continue;
1348 descr->items[i].selected = FALSE;
1349 LISTBOX_RepaintItem( wnd, descr, i, ODA_SELECT );
1350 }
1351 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001352 return LB_OKAY;
1353}
1354
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001355/***********************************************************************
1356 * LISTBOX_SetSelection
1357 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001358static LRESULT LISTBOX_SetSelection( WND *wnd, LB_DESCR *descr, INT index,
1359 BOOL on, BOOL send_notify )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001360{
Dmitry Timoshkove0f493e1999-11-28 19:44:33 +00001361 TRACE( "index=%d notify=%s\n", index, send_notify ? "YES" : "NO" );
1362
Andreas Mohr85ba8792001-01-06 00:34:14 +00001363 if (descr->style & LBS_NOSEL) return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001364 if ((index < -1) || (index >= descr->nb_items)) return LB_ERR;
1365 if (descr->style & LBS_MULTIPLESEL)
1366 {
1367 if (index == -1) /* Select all items */
1368 return LISTBOX_SelectItemRange( wnd, descr, 0, -1, on );
1369 else /* Only one item */
1370 return LISTBOX_SelectItemRange( wnd, descr, index, index, on );
1371 }
1372 else
1373 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001374 INT oldsel = descr->selected_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001375 if (index == oldsel) return LB_OKAY;
1376 if (oldsel != -1) descr->items[oldsel].selected = FALSE;
1377 if (index != -1) descr->items[index].selected = TRUE;
1378 descr->selected_item = index;
Huw D M Davies65a0fa62000-03-25 21:41:17 +00001379 if (oldsel != -1) LISTBOX_RepaintItem( wnd, descr, oldsel, ODA_SELECT );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001380 if (index != -1) LISTBOX_RepaintItem( wnd, descr, index, ODA_SELECT );
Gerard Patelc9a6d501999-07-25 13:03:17 +00001381 if (send_notify && descr->nb_items) SEND_NOTIFICATION( wnd, descr,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001382 (index != -1) ? LBN_SELCHANGE : LBN_SELCANCEL );
Alex Korobka311d3291999-01-01 18:40:02 +00001383 else
1384 if( descr->lphc ) /* set selection change flag for parent combo */
1385 descr->lphc->wState |= CBF_SELCHANGE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001386 }
1387 return LB_OKAY;
1388}
1389
1390
1391/***********************************************************************
1392 * LISTBOX_MoveCaret
1393 *
1394 * Change the caret position and extend the selection to the new caret.
1395 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001396static void LISTBOX_MoveCaret( WND *wnd, LB_DESCR *descr, INT index,
1397 BOOL fully_visible )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001398{
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001399 INT oldfocus = descr->focus_item;
1400
1401 if ((index < 0) || (index >= descr->nb_items))
1402 return;
1403
1404 /* Important, repaint needs to be done in this order if
1405 you want to mimic Windows behavior:
1406 1. Remove the focus and paint the item
1407 2. Remove the selection and paint the item(s)
1408 3. Set the selection and repaint the item(s)
1409 4. Set the focus to 'index' and repaint the item */
1410
1411 /* 1. remove the focus and repaint the item */
1412 descr->focus_item = -1;
1413 if ((oldfocus != -1) && descr->caret_on && (descr->in_focus))
1414 LISTBOX_RepaintItem( wnd, descr, oldfocus, ODA_FOCUS );
1415
1416 /* 2. then turn off the previous selection */
1417 /* 3. repaint the new selected item */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001418 if (descr->style & LBS_EXTENDEDSEL)
1419 {
1420 if (descr->anchor_item != -1)
1421 {
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001422 INT first = min( index, descr->anchor_item );
1423 INT last = max( index, descr->anchor_item );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001424 if (first > 0)
1425 LISTBOX_SelectItemRange( wnd, descr, 0, first - 1, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001426 LISTBOX_SelectItemRange( wnd, descr, last + 1, -1, FALSE );
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001427 LISTBOX_SelectItemRange( wnd, descr, first, last, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001428 }
1429 }
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00001430 else if (!(descr->style & LBS_MULTIPLESEL))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001431 {
1432 /* Set selection to new caret item */
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00001433 LISTBOX_SetSelection( wnd, descr, index, TRUE, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001434 }
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001435
1436 /* 4. repaint the new item with the focus */
1437 descr->focus_item = index;
1438 LISTBOX_MakeItemVisible( wnd, descr, index, fully_visible );
1439 if (descr->caret_on && (descr->in_focus))
1440 LISTBOX_RepaintItem( wnd, descr, index, ODA_FOCUS );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001441}
1442
1443
1444/***********************************************************************
1445 * LISTBOX_InsertItem
1446 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001447static LRESULT LISTBOX_InsertItem( WND *wnd, LB_DESCR *descr, INT index,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001448 LPWSTR str, DWORD data )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001449{
1450 LB_ITEMDATA *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001451 INT max_items;
Gerard Patelc9a6d501999-07-25 13:03:17 +00001452 INT oldfocus = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001453
1454 if (index == -1) index = descr->nb_items;
1455 else if ((index < 0) || (index > descr->nb_items)) return LB_ERR;
1456 if (!descr->items) max_items = 0;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001457 else max_items = HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(*item);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001458 if (descr->nb_items == max_items)
1459 {
1460 /* We need to grow the array */
1461 max_items += LB_ARRAY_GRANULARITY;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001462 if (!(item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001463 max_items * sizeof(LB_ITEMDATA) )))
1464 {
1465 SEND_NOTIFICATION( wnd, descr, LBN_ERRSPACE );
1466 return LB_ERRSPACE;
1467 }
1468 descr->items = item;
1469 }
1470
1471 /* Insert the item structure */
1472
1473 item = &descr->items[index];
1474 if (index < descr->nb_items)
1475 RtlMoveMemory( item + 1, item,
1476 (descr->nb_items - index) * sizeof(LB_ITEMDATA) );
1477 item->str = str;
1478 item->data = data;
1479 item->height = 0;
1480 item->selected = FALSE;
1481 descr->nb_items++;
1482
1483 /* Get item height */
1484
1485 if (descr->style & LBS_OWNERDRAWVARIABLE)
1486 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001487 MEASUREITEMSTRUCT mis;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001488
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001489 mis.CtlType = ODT_LISTBOX;
Serge Ivanov07917e42000-06-07 03:46:57 +00001490 mis.CtlID = wnd->wIDmenu;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001491 mis.itemID = index;
1492 mis.itemData = descr->items[index].data;
1493 mis.itemHeight = descr->item_height;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001494 SendMessageW( descr->owner, WM_MEASUREITEM, wnd->wIDmenu, (LPARAM)&mis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001495 item->height = mis.itemHeight ? mis.itemHeight : 1;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001496 TRACE("[%04x]: measure item %d (%s) = %d\n",
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001497 wnd->hwndSelf, index, str ? debugstr_w(str) : "", item->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001498 }
1499
1500 /* Repaint the items */
1501
1502 LISTBOX_UpdateScroll( wnd, descr );
1503 LISTBOX_InvalidateItems( wnd, descr, index );
1504
1505 /* Move selection and focused item */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001506 /* If listbox was empty, set focus to the first item */
Gerard Patelc9a6d501999-07-25 13:03:17 +00001507 if (descr->nb_items == 1)
1508 LISTBOX_SetCaretIndex( wnd, descr, 0, FALSE );
1509 /* single select don't change selection index in win31 */
1510 else if ((ISWIN31) && !(IS_MULTISELECT(descr)))
1511 {
1512 descr->selected_item++;
1513 LISTBOX_SetSelection( wnd, descr, descr->selected_item-1, TRUE, FALSE );
1514 }
1515 else
1516 {
1517 if (index <= descr->selected_item)
1518 {
1519 descr->selected_item++;
1520 descr->focus_item = oldfocus; /* focus not changed */
1521 }
1522 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001523 return LB_OKAY;
1524}
1525
1526
1527/***********************************************************************
1528 * LISTBOX_InsertString
1529 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001530static LRESULT LISTBOX_InsertString( WND *wnd, LB_DESCR *descr, INT index,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001531 LPCWSTR str )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001532{
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001533 LPWSTR new_str = NULL;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001534 DWORD data = 0;
1535 LRESULT ret;
1536
1537 if (HAS_STRINGS(descr))
1538 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001539 static const WCHAR empty_stringW[] = { 0 };
1540 if (!str) str = empty_stringW;
1541 if (!(new_str = HeapAlloc( GetProcessHeap(), 0, (strlenW(str) + 1) * sizeof(WCHAR) )))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001542 {
1543 SEND_NOTIFICATION( wnd, descr, LBN_ERRSPACE );
1544 return LB_ERRSPACE;
1545 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001546 strcpyW(new_str, str);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001547 }
1548 else data = (DWORD)str;
1549
1550 if (index == -1) index = descr->nb_items;
1551 if ((ret = LISTBOX_InsertItem( wnd, descr, index, new_str, data )) != 0)
1552 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001553 if (new_str) HeapFree( GetProcessHeap(), 0, new_str );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001554 return ret;
1555 }
1556
Francois Gougetee285b72001-05-11 20:03:40 +00001557 TRACE("[%04x]: added item %d %s\n",
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001558 wnd->hwndSelf, index, HAS_STRINGS(descr) ? debugstr_w(new_str) : "" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001559 return index;
1560}
1561
1562
1563/***********************************************************************
1564 * LISTBOX_DeleteItem
1565 *
1566 * Delete the content of an item. 'index' must be a valid index.
1567 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001568static void LISTBOX_DeleteItem( WND *wnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001569{
1570 /* Note: Win 3.1 only sends DELETEITEM on owner-draw items,
1571 * while Win95 sends it for all items with user data.
1572 * It's probably better to send it too often than not
1573 * often enough, so this is what we do here.
1574 */
1575 if (IS_OWNERDRAW(descr) || descr->items[index].data)
1576 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001577 DELETEITEMSTRUCT dis;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001578
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001579 dis.CtlType = ODT_LISTBOX;
Serge Ivanov07917e42000-06-07 03:46:57 +00001580 dis.CtlID = wnd->wIDmenu;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001581 dis.itemID = index;
1582 dis.hwndItem = wnd->hwndSelf;
1583 dis.itemData = descr->items[index].data;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001584 SendMessageW( descr->owner, WM_DELETEITEM, wnd->wIDmenu, (LPARAM)&dis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001585 }
1586 if (HAS_STRINGS(descr) && descr->items[index].str)
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001587 HeapFree( GetProcessHeap(), 0, descr->items[index].str );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001588}
1589
1590
1591/***********************************************************************
1592 * LISTBOX_RemoveItem
1593 *
1594 * Remove an item from the listbox and delete its content.
1595 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001596static LRESULT LISTBOX_RemoveItem( WND *wnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001597{
1598 LB_ITEMDATA *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001599 INT max_items;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001600
Aric Stewartfe9a0f02001-01-04 19:27:03 +00001601 if ((index == -1) && (descr->nb_items > 0)) index = descr->nb_items - 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001602 else if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +00001603
1604 /* We need to invalidate the original rect instead of the updated one. */
1605 LISTBOX_InvalidateItems( wnd, descr, index );
1606
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001607 LISTBOX_DeleteItem( wnd, descr, index );
1608
1609 /* Remove the item */
1610
1611 item = &descr->items[index];
1612 if (index < descr->nb_items-1)
1613 RtlMoveMemory( item, item + 1,
1614 (descr->nb_items - index - 1) * sizeof(LB_ITEMDATA) );
1615 descr->nb_items--;
1616 if (descr->anchor_item == descr->nb_items) descr->anchor_item--;
1617
1618 /* Shrink the item array if possible */
1619
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001620 max_items = HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(LB_ITEMDATA);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001621 if (descr->nb_items < max_items - 2*LB_ARRAY_GRANULARITY)
1622 {
1623 max_items -= LB_ARRAY_GRANULARITY;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001624 item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001625 max_items * sizeof(LB_ITEMDATA) );
1626 if (item) descr->items = item;
1627 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001628 /* Repaint the items */
1629
1630 LISTBOX_UpdateScroll( wnd, descr );
Gerard Patelc9a6d501999-07-25 13:03:17 +00001631 /* if we removed the scrollbar, reset the top of the list
1632 (correct for owner-drawn ???) */
1633 if (descr->nb_items == descr->page_size)
1634 LISTBOX_SetTopItem( wnd, descr, 0, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001635
1636 /* Move selection and focused item */
Gerard Patelc9a6d501999-07-25 13:03:17 +00001637 if (!IS_MULTISELECT(descr))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001638 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00001639 if (index == descr->selected_item)
1640 descr->selected_item = -1;
1641 else if (index < descr->selected_item)
1642 {
1643 descr->selected_item--;
1644 if (ISWIN31) /* win 31 do not change the selected item number */
1645 LISTBOX_SetSelection( wnd, descr, descr->selected_item + 1, TRUE, FALSE);
1646 }
1647 }
Yuxi Zhangf94c3c52000-02-26 19:13:12 +00001648
Gerard Patelc9a6d501999-07-25 13:03:17 +00001649 if (descr->focus_item >= descr->nb_items)
1650 {
1651 descr->focus_item = descr->nb_items - 1;
1652 if (descr->focus_item < 0) descr->focus_item = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001653 }
1654 return LB_OKAY;
1655}
1656
1657
1658/***********************************************************************
1659 * LISTBOX_ResetContent
1660 */
1661static void LISTBOX_ResetContent( WND *wnd, LB_DESCR *descr )
1662{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001663 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001664
1665 for (i = 0; i < descr->nb_items; i++) LISTBOX_DeleteItem( wnd, descr, i );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001666 if (descr->items) HeapFree( GetProcessHeap(), 0, descr->items );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001667 descr->nb_items = 0;
1668 descr->top_item = 0;
1669 descr->selected_item = -1;
1670 descr->focus_item = 0;
1671 descr->anchor_item = -1;
1672 descr->items = NULL;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001673}
1674
1675
1676/***********************************************************************
1677 * LISTBOX_SetCount
1678 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001679static LRESULT LISTBOX_SetCount( WND *wnd, LB_DESCR *descr, INT count )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001680{
1681 LRESULT ret;
1682
1683 if (HAS_STRINGS(descr)) return LB_ERR;
1684 /* FIXME: this is far from optimal... */
1685 if (count > descr->nb_items)
1686 {
1687 while (count > descr->nb_items)
1688 if ((ret = LISTBOX_InsertString( wnd, descr, -1, 0 )) < 0)
1689 return ret;
1690 }
1691 else if (count < descr->nb_items)
1692 {
1693 while (count < descr->nb_items)
1694 if ((ret = LISTBOX_RemoveItem( wnd, descr, -1 )) < 0)
1695 return ret;
1696 }
1697 return LB_OKAY;
1698}
1699
1700
1701/***********************************************************************
1702 * LISTBOX_Directory
1703 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001704static LRESULT LISTBOX_Directory( WND *wnd, LB_DESCR *descr, UINT attrib,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001705 LPCWSTR filespec, BOOL long_names )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001706{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001707 HANDLE handle;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001708 LRESULT ret = LB_OKAY;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001709 WIN32_FIND_DATAW entry;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001710 int pos;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001711
Ove Kaaven2c691b32000-11-25 03:06:03 +00001712 /* don't scan directory if we just want drives exclusively */
1713 if (attrib != (DDL_DRIVES | DDL_EXCLUSIVE)) {
1714 /* scan directory */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001715 if ((handle = FindFirstFileW(filespec, &entry)) == INVALID_HANDLE_VALUE)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001716 {
Ove Kaaven2c691b32000-11-25 03:06:03 +00001717 if (GetLastError() != ERROR_NO_MORE_FILES) return LB_ERR;
1718 }
1719 else
1720 {
1721 do
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001722 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001723 WCHAR buffer[270];
Ove Kaaven2c691b32000-11-25 03:06:03 +00001724 if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1725 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001726 static const WCHAR bracketW[] = { ']',0 };
1727 static const WCHAR dotW[] = { '.',0 };
Ove Kaaven2c691b32000-11-25 03:06:03 +00001728 if (!(attrib & DDL_DIRECTORY) ||
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001729 !strcmpW( entry.cAlternateFileName, dotW )) continue;
1730 buffer[0] = '[';
1731 if (long_names) strcpyW( buffer + 1, entry.cFileName );
1732 else strcpyW( buffer + 1, entry.cAlternateFileName );
1733 strcatW(buffer, bracketW);
Ove Kaaven2c691b32000-11-25 03:06:03 +00001734 }
1735 else /* not a directory */
1736 {
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001737#define ATTRIBS (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
1738 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE)
1739
Ove Kaaven2c691b32000-11-25 03:06:03 +00001740 if ((attrib & DDL_EXCLUSIVE) &&
1741 ((attrib & ATTRIBS) != (entry.dwFileAttributes & ATTRIBS)))
1742 continue;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001743#undef ATTRIBS
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001744 if (long_names) strcpyW( buffer, entry.cFileName );
1745 else strcpyW( buffer, entry.cAlternateFileName );
Ove Kaaven2c691b32000-11-25 03:06:03 +00001746 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001747 if (!long_names) CharLowerW( buffer );
Ove Kaaven2c691b32000-11-25 03:06:03 +00001748 pos = LISTBOX_FindFileStrPos( wnd, descr, buffer );
1749 if ((ret = LISTBOX_InsertString( wnd, descr, pos, buffer )) < 0)
1750 break;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001751 } while (FindNextFileW( handle, &entry ));
Ove Kaaven2c691b32000-11-25 03:06:03 +00001752 FindClose( handle );
1753 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001754 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001755
Ove Kaaven2c691b32000-11-25 03:06:03 +00001756 /* scan drives */
Alexandre Julliard889f7421997-04-15 17:19:52 +00001757 if ((ret >= 0) && (attrib & DDL_DRIVES))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001758 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001759 WCHAR buffer[] = {'[','-','a','-',']',0};
1760 WCHAR root[] = {'A',':','\\',0};
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001761 int drive;
Alexandre Julliardbf672592000-12-12 00:44:42 +00001762 for (drive = 0; drive < 26; drive++, buffer[2]++, root[0]++)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001763 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001764 if (GetDriveTypeW(root) <= DRIVE_NO_ROOT_DIR) continue;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001765 if ((ret = LISTBOX_InsertString( wnd, descr, -1, buffer )) < 0)
1766 break;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001767 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001768 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001769 return ret;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001770}
1771
1772
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001773/***********************************************************************
1774 * LISTBOX_HandleVScroll
1775 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001776static LRESULT LISTBOX_HandleVScroll( WND *wnd, LB_DESCR *descr, WPARAM wParam )
Alexandre Julliard2787be81995-05-22 18:23:01 +00001777{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001778 SCROLLINFO info;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001779
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001780 if (descr->style & LBS_MULTICOLUMN) return 0;
1781 switch(LOWORD(wParam))
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +00001782 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001783 case SB_LINEUP:
1784 LISTBOX_SetTopItem( wnd, descr, descr->top_item - 1, TRUE );
1785 break;
1786 case SB_LINEDOWN:
1787 LISTBOX_SetTopItem( wnd, descr, descr->top_item + 1, TRUE );
1788 break;
1789 case SB_PAGEUP:
1790 LISTBOX_SetTopItem( wnd, descr, descr->top_item -
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001791 LISTBOX_GetCurrentPageSize( descr ), TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001792 break;
1793 case SB_PAGEDOWN:
1794 LISTBOX_SetTopItem( wnd, descr, descr->top_item +
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001795 LISTBOX_GetCurrentPageSize( descr ), TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001796 break;
1797 case SB_THUMBPOSITION:
1798 LISTBOX_SetTopItem( wnd, descr, HIWORD(wParam), TRUE );
1799 break;
1800 case SB_THUMBTRACK:
1801 info.cbSize = sizeof(info);
1802 info.fMask = SIF_TRACKPOS;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001803 GetScrollInfo( wnd->hwndSelf, SB_VERT, &info );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001804 LISTBOX_SetTopItem( wnd, descr, info.nTrackPos, TRUE );
1805 break;
1806 case SB_TOP:
1807 LISTBOX_SetTopItem( wnd, descr, 0, TRUE );
1808 break;
1809 case SB_BOTTOM:
1810 LISTBOX_SetTopItem( wnd, descr, descr->nb_items, TRUE );
1811 break;
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +00001812 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001813 return 0;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001814}
1815
Alexandre Julliardb817f4f1996-03-14 18:08:34 +00001816
Alexandre Julliard2787be81995-05-22 18:23:01 +00001817/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001818 * LISTBOX_HandleHScroll
Alexandre Julliard2787be81995-05-22 18:23:01 +00001819 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001820static LRESULT LISTBOX_HandleHScroll( WND *wnd, LB_DESCR *descr, WPARAM wParam )
Alexandre Julliard2787be81995-05-22 18:23:01 +00001821{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001822 SCROLLINFO info;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001823 INT page;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001824
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001825 if (descr->style & LBS_MULTICOLUMN)
1826 {
1827 switch(LOWORD(wParam))
1828 {
1829 case SB_LINELEFT:
1830 LISTBOX_SetTopItem( wnd, descr, descr->top_item-descr->page_size,
1831 TRUE );
1832 break;
1833 case SB_LINERIGHT:
1834 LISTBOX_SetTopItem( wnd, descr, descr->top_item+descr->page_size,
1835 TRUE );
1836 break;
1837 case SB_PAGELEFT:
1838 page = descr->width / descr->column_width;
1839 if (page < 1) page = 1;
1840 LISTBOX_SetTopItem( wnd, descr,
1841 descr->top_item - page * descr->page_size, TRUE );
1842 break;
1843 case SB_PAGERIGHT:
1844 page = descr->width / descr->column_width;
1845 if (page < 1) page = 1;
1846 LISTBOX_SetTopItem( wnd, descr,
1847 descr->top_item + page * descr->page_size, TRUE );
1848 break;
1849 case SB_THUMBPOSITION:
1850 LISTBOX_SetTopItem( wnd, descr, HIWORD(wParam)*descr->page_size,
1851 TRUE );
1852 break;
1853 case SB_THUMBTRACK:
1854 info.cbSize = sizeof(info);
1855 info.fMask = SIF_TRACKPOS;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001856 GetScrollInfo( wnd->hwndSelf, SB_VERT, &info );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001857 LISTBOX_SetTopItem( wnd, descr, info.nTrackPos*descr->page_size,
1858 TRUE );
1859 break;
1860 case SB_LEFT:
1861 LISTBOX_SetTopItem( wnd, descr, 0, TRUE );
1862 break;
1863 case SB_RIGHT:
1864 LISTBOX_SetTopItem( wnd, descr, descr->nb_items, TRUE );
1865 break;
1866 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001867 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001868 else if (descr->horz_extent)
1869 {
1870 switch(LOWORD(wParam))
1871 {
1872 case SB_LINELEFT:
1873 LISTBOX_SetHorizontalPos( wnd, descr, descr->horz_pos - 1 );
1874 break;
1875 case SB_LINERIGHT:
1876 LISTBOX_SetHorizontalPos( wnd, descr, descr->horz_pos + 1 );
1877 break;
1878 case SB_PAGELEFT:
1879 LISTBOX_SetHorizontalPos( wnd, descr,
1880 descr->horz_pos - descr->width );
1881 break;
1882 case SB_PAGERIGHT:
1883 LISTBOX_SetHorizontalPos( wnd, descr,
1884 descr->horz_pos + descr->width );
1885 break;
1886 case SB_THUMBPOSITION:
1887 LISTBOX_SetHorizontalPos( wnd, descr, HIWORD(wParam) );
1888 break;
1889 case SB_THUMBTRACK:
1890 info.cbSize = sizeof(info);
1891 info.fMask = SIF_TRACKPOS;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001892 GetScrollInfo( wnd->hwndSelf, SB_HORZ, &info );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001893 LISTBOX_SetHorizontalPos( wnd, descr, info.nTrackPos );
1894 break;
1895 case SB_LEFT:
1896 LISTBOX_SetHorizontalPos( wnd, descr, 0 );
1897 break;
1898 case SB_RIGHT:
1899 LISTBOX_SetHorizontalPos( wnd, descr,
1900 descr->horz_extent - descr->width );
1901 break;
1902 }
1903 }
1904 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001905}
1906
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001907static LRESULT LISTBOX_HandleMouseWheel(WND *wnd, LB_DESCR *descr, WPARAM wParam )
Stephane Lussier4bdf4af2000-04-18 11:56:33 +00001908{
1909 short gcWheelDelta = 0;
1910 UINT pulScrollLines = 3;
1911
1912 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
1913
1914 gcWheelDelta -= (short) HIWORD(wParam);
1915
1916 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
1917 {
1918 int cLineScroll = (int) min((UINT) descr->page_size, pulScrollLines);
1919 cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
1920 LISTBOX_SetTopItem( wnd, descr, descr->top_item + cLineScroll, TRUE );
1921 }
1922 return 0;
1923}
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001924
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001925/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001926 * LISTBOX_HandleLButtonDown
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001927 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001928static LRESULT LISTBOX_HandleLButtonDown( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001929 WPARAM wParam, INT x, INT y )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001930{
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001931 INT index = LISTBOX_GetItemFromPoint( descr, x, y );
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001932 TRACE("[%04x]: lbuttondown %d,%d item %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001933 wnd->hwndSelf, x, y, index );
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00001934 if (!descr->caret_on && (descr->in_focus)) return 0;
Jason Mawdsley50523d12000-06-11 20:34:07 +00001935
1936 if (!descr->in_focus)
1937 {
1938 if( !descr->lphc ) SetFocus( wnd->hwndSelf );
1939 else SetFocus( (descr->lphc->hWndEdit) ? descr->lphc->hWndEdit
1940 : descr->lphc->self->hwndSelf );
1941 }
1942
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001943 if (index == -1) return 0;
Andreas Mohr2b5d9c62000-08-29 03:52:16 +00001944
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001945 if (descr->style & LBS_EXTENDEDSEL)
1946 {
1947 /* we should perhaps make sure that all items are deselected
1948 FIXME: needed for !LBS_EXTENDEDSEL, too ?
1949 if (!(wParam & (MK_SHIFT|MK_CONTROL)))
1950 LISTBOX_SetSelection( wnd, descr, -1, FALSE, FALSE);
1951 */
1952
1953 if (!(wParam & MK_SHIFT)) descr->anchor_item = index;
1954 if (wParam & MK_CONTROL)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001955 {
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001956 LISTBOX_SetCaretIndex( wnd, descr, index, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001957 LISTBOX_SetSelection( wnd, descr, index,
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001958 !descr->items[index].selected,
1959 (descr->style & LBS_NOTIFY) != 0);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001960 }
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001961 else LISTBOX_MoveCaret( wnd, descr, index, FALSE );
1962 }
1963 else
1964 {
1965 LISTBOX_MoveCaret( wnd, descr, index, FALSE );
1966 LISTBOX_SetSelection( wnd, descr, index,
1967 (!(descr->style & LBS_MULTIPLESEL) ||
1968 !descr->items[index].selected),
1969 (descr->style & LBS_NOTIFY) != 0 );
Alexandre Julliard2787be81995-05-22 18:23:01 +00001970 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001971
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00001972 descr->captured = TRUE;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001973 SetCapture( wnd->hwndSelf );
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001974
1975 if (!descr->lphc)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001976 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001977 if (descr->style & LBS_NOTIFY )
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001978 SendMessageW( descr->owner, WM_LBTRACKPOINT, index,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001979 MAKELPARAM( x, y ) );
1980 if (wnd->dwExStyle & WS_EX_DRAGDETECT)
1981 {
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00001982 POINT pt;
1983
1984 pt.x = x;
1985 pt.y = y;
1986
Alexandre Julliarda3960291999-02-26 11:11:13 +00001987 if (DragDetect( wnd->hwndSelf, pt ))
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001988 SendMessageW( descr->owner, WM_BEGINDRAG, 0, 0 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001989 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001990 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001991 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001992}
1993
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001994
Pierre Mageau25c62cc1999-09-11 16:26:03 +00001995/*************************************************************************
1996 * LISTBOX_HandleLButtonDownCombo [Internal]
1997 *
1998 * Process LButtonDown message for the ComboListBox
1999 *
2000 * PARAMS
2001 * pWnd [I] The windows internal structure
2002 * pDescr [I] The ListBox internal structure
2003 * wParam [I] Key Flag (WM_LBUTTONDOWN doc for more info)
2004 * x [I] X Mouse Coordinate
2005 * y [I] Y Mouse Coordinate
2006 *
2007 * RETURNS
2008 * 0 since we are processing the WM_LBUTTONDOWN Message
2009 *
2010 * NOTES
2011 * This function is only to be used when a ListBox is a ComboListBox
2012 */
2013
2014static LRESULT LISTBOX_HandleLButtonDownCombo( WND *pWnd, LB_DESCR *pDescr,
Alexandre Julliard7f90a8c2000-05-23 04:18:12 +00002015 UINT msg, WPARAM wParam, INT x, INT y)
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002016{
2017 RECT clientRect, screenRect;
2018 POINT mousePos;
2019
2020 mousePos.x = x;
2021 mousePos.y = y;
2022
2023 GetClientRect(pWnd->hwndSelf, &clientRect);
2024
2025 if(PtInRect(&clientRect, mousePos))
2026 {
Alexandre Julliard7f90a8c2000-05-23 04:18:12 +00002027 /* MousePos is in client, resume normal processing */
2028 if (msg == WM_LBUTTONDOWN)
Serge Ivanov07917e42000-06-07 03:46:57 +00002029 {
2030 pDescr->lphc->droppedIndex = pDescr->nb_items ? pDescr->selected_item : -1;
Alexandre Julliard7f90a8c2000-05-23 04:18:12 +00002031 return LISTBOX_HandleLButtonDown( pWnd, pDescr, wParam, x, y);
Serge Ivanov07917e42000-06-07 03:46:57 +00002032 }
Alexandre Julliard7f90a8c2000-05-23 04:18:12 +00002033 else if (pDescr->style & LBS_NOTIFY)
2034 SEND_NOTIFICATION( pWnd, pDescr, LBN_DBLCLK );
2035 return 0;
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002036 }
2037 else
2038 {
2039 POINT screenMousePos;
2040 HWND hWndOldCapture;
2041
2042 /* Check the Non-Client Area */
2043 screenMousePos = mousePos;
2044 hWndOldCapture = GetCapture();
2045 ReleaseCapture();
2046 GetWindowRect(pWnd->hwndSelf, &screenRect);
2047 ClientToScreen(pWnd->hwndSelf, &screenMousePos);
2048
2049 if(!PtInRect(&screenRect, screenMousePos))
2050 {
Dmitry Timoshkove8ffcaa2001-04-16 19:32:19 +00002051 LISTBOX_SetCaretIndex( pWnd, pDescr, pDescr->lphc->droppedIndex, FALSE );
Serge Ivanov07917e42000-06-07 03:46:57 +00002052 LISTBOX_SetSelection( pWnd, pDescr, pDescr->lphc->droppedIndex, FALSE, FALSE );
2053 COMBO_FlipListbox( pDescr->lphc, FALSE, FALSE );
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002054 return 0;
2055 }
2056 else
2057 {
2058 /* Check to see the NC is a scrollbar */
2059 INT nHitTestType=0;
2060 /* Check Vertical scroll bar */
2061 if (pWnd->dwStyle & WS_VSCROLL)
2062 {
2063 clientRect.right += GetSystemMetrics(SM_CXVSCROLL);
2064 if (PtInRect( &clientRect, mousePos ))
2065 {
2066 nHitTestType = HTVSCROLL;
2067 }
2068 }
2069 /* Check horizontal scroll bar */
2070 if (pWnd->dwStyle & WS_HSCROLL)
2071 {
2072 clientRect.bottom += GetSystemMetrics(SM_CYHSCROLL);
2073 if (PtInRect( &clientRect, mousePos ))
2074 {
2075 nHitTestType = HTHSCROLL;
2076 }
2077 }
2078 /* Windows sends this message when a scrollbar is clicked
2079 */
2080
2081 if(nHitTestType != 0)
2082 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002083 SendMessageW(pWnd->hwndSelf, WM_NCLBUTTONDOWN, nHitTestType,
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002084 MAKELONG(screenMousePos.x, screenMousePos.y));
2085 }
2086 /* Resume the Capture after scrolling is complete
2087 */
2088 if(hWndOldCapture != 0)
2089 {
2090 SetCapture(hWndOldCapture);
2091 }
2092 }
2093 }
2094 return 0;
2095}
2096
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002097/***********************************************************************
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002098 * LISTBOX_HandleLButtonUp
2099 */
2100static LRESULT LISTBOX_HandleLButtonUp( WND *wnd, LB_DESCR *descr )
2101{
2102 if (LISTBOX_Timer != LB_TIMER_NONE)
Alexandre Julliarda3960291999-02-26 11:11:13 +00002103 KillSystemTimer( wnd->hwndSelf, LB_TIMER_ID );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002104 LISTBOX_Timer = LB_TIMER_NONE;
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002105 if (descr->captured)
Alexandre Julliard33072e11997-06-29 18:08:02 +00002106 {
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002107 descr->captured = FALSE;
2108 if (GetCapture() == wnd->hwndSelf) ReleaseCapture();
Gerard Patelc9a6d501999-07-25 13:03:17 +00002109 if ((descr->style & LBS_NOTIFY) && descr->nb_items)
Alexandre Julliard33072e11997-06-29 18:08:02 +00002110 SEND_NOTIFICATION( wnd, descr, LBN_SELCHANGE );
2111 }
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002112 return 0;
2113}
2114
2115
2116/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002117 * LISTBOX_HandleTimer
Alexandre Julliardade697e1995-11-26 13:59:11 +00002118 *
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002119 * Handle scrolling upon a timer event.
2120 * Return TRUE if scrolling should continue.
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002121 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002122static LRESULT LISTBOX_HandleTimer( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002123 INT index, TIMER_DIRECTION dir )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002124{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002125 switch(dir)
Alexandre Julliardade697e1995-11-26 13:59:11 +00002126 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002127 case LB_TIMER_UP:
2128 if (descr->top_item) index = descr->top_item - 1;
2129 else index = 0;
2130 break;
2131 case LB_TIMER_LEFT:
2132 if (descr->top_item) index -= descr->page_size;
2133 break;
2134 case LB_TIMER_DOWN:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002135 index = descr->top_item + LISTBOX_GetCurrentPageSize( descr );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002136 if (index == descr->focus_item) index++;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002137 if (index >= descr->nb_items) index = descr->nb_items - 1;
2138 break;
2139 case LB_TIMER_RIGHT:
2140 if (index + descr->page_size < descr->nb_items)
2141 index += descr->page_size;
2142 break;
2143 case LB_TIMER_NONE:
2144 break;
Alexandre Julliardade697e1995-11-26 13:59:11 +00002145 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002146 if (index == descr->focus_item) return FALSE;
2147 LISTBOX_MoveCaret( wnd, descr, index, FALSE );
2148 return TRUE;
2149}
Alexandre Julliardade697e1995-11-26 13:59:11 +00002150
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002151
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002152/***********************************************************************
2153 * LISTBOX_HandleSystemTimer
2154 *
2155 * WM_SYSTIMER handler.
2156 */
2157static LRESULT LISTBOX_HandleSystemTimer( WND *wnd, LB_DESCR *descr )
2158{
2159 if (!LISTBOX_HandleTimer( wnd, descr, descr->focus_item, LISTBOX_Timer ))
Alexandre Julliardade697e1995-11-26 13:59:11 +00002160 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002161 KillSystemTimer( wnd->hwndSelf, LB_TIMER_ID );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002162 LISTBOX_Timer = LB_TIMER_NONE;
Alexandre Julliardade697e1995-11-26 13:59:11 +00002163 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00002164 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002165}
2166
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002167
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002168/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002169 * LISTBOX_HandleMouseMove
2170 *
2171 * WM_MOUSEMOVE handler.
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002172 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002173static void LISTBOX_HandleMouseMove( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002174 INT x, INT y )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002175{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002176 INT index;
Serge Ivanov07917e42000-06-07 03:46:57 +00002177 TIMER_DIRECTION dir = LB_TIMER_NONE;
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00002178
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002179 if (!descr->captured) return;
2180
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002181 if (descr->style & LBS_MULTICOLUMN)
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00002182 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002183 if (y < 0) y = 0;
2184 else if (y >= descr->item_height * descr->page_size)
2185 y = descr->item_height * descr->page_size - 1;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002186
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002187 if (x < 0)
2188 {
2189 dir = LB_TIMER_LEFT;
2190 x = 0;
2191 }
2192 else if (x >= descr->width)
2193 {
2194 dir = LB_TIMER_RIGHT;
2195 x = descr->width - 1;
2196 }
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00002197 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002198 else
2199 {
2200 if (y < 0) dir = LB_TIMER_UP; /* above */
2201 else if (y >= descr->height) dir = LB_TIMER_DOWN; /* below */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002202 }
2203
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002204 index = LISTBOX_GetItemFromPoint( descr, x, y );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002205 if (index == -1) index = descr->focus_item;
2206 if (!LISTBOX_HandleTimer( wnd, descr, index, dir )) dir = LB_TIMER_NONE;
2207
2208 /* Start/stop the system timer */
2209
2210 if (dir != LB_TIMER_NONE)
Alexandre Julliarda3960291999-02-26 11:11:13 +00002211 SetSystemTimer( wnd->hwndSelf, LB_TIMER_ID, LB_SCROLL_TIMEOUT, NULL);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002212 else if (LISTBOX_Timer != LB_TIMER_NONE)
Alexandre Julliarda3960291999-02-26 11:11:13 +00002213 KillSystemTimer( wnd->hwndSelf, LB_TIMER_ID );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002214 LISTBOX_Timer = dir;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002215}
2216
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002217
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002218/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002219 * LISTBOX_HandleKeyDown
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002220 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002221static LRESULT LISTBOX_HandleKeyDown( WND *wnd, LB_DESCR *descr, WPARAM wParam )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002222{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002223 INT caret = -1;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002224 BOOL bForceSelection = TRUE; /* select item pointed to by focus_item */
2225 if ((IS_MULTISELECT(descr)) || (descr->selected_item == descr->focus_item))
2226 bForceSelection = FALSE; /* only for single select list */
2227
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002228 if (descr->style & LBS_WANTKEYBOARDINPUT)
2229 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002230 caret = SendMessageW( descr->owner, WM_VKEYTOITEM,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002231 MAKEWPARAM(LOWORD(wParam), descr->focus_item),
2232 wnd->hwndSelf );
2233 if (caret == -2) return 0;
2234 }
2235 if (caret == -1) switch(wParam)
2236 {
2237 case VK_LEFT:
2238 if (descr->style & LBS_MULTICOLUMN)
2239 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00002240 bForceSelection = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002241 if (descr->focus_item >= descr->page_size)
2242 caret = descr->focus_item - descr->page_size;
2243 break;
2244 }
2245 /* fall through */
2246 case VK_UP:
2247 caret = descr->focus_item - 1;
2248 if (caret < 0) caret = 0;
2249 break;
2250 case VK_RIGHT:
2251 if (descr->style & LBS_MULTICOLUMN)
2252 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00002253 bForceSelection = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002254 if (descr->focus_item + descr->page_size < descr->nb_items)
2255 caret = descr->focus_item + descr->page_size;
2256 break;
2257 }
2258 /* fall through */
2259 case VK_DOWN:
2260 caret = descr->focus_item + 1;
2261 if (caret >= descr->nb_items) caret = descr->nb_items - 1;
2262 break;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002263
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002264 case VK_PRIOR:
2265 if (descr->style & LBS_MULTICOLUMN)
2266 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002267 INT page = descr->width / descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002268 if (page < 1) page = 1;
2269 caret = descr->focus_item - (page * descr->page_size) + 1;
2270 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002271 else caret = descr->focus_item-LISTBOX_GetCurrentPageSize(descr) + 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002272 if (caret < 0) caret = 0;
2273 break;
2274 case VK_NEXT:
2275 if (descr->style & LBS_MULTICOLUMN)
2276 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002277 INT page = descr->width / descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002278 if (page < 1) page = 1;
2279 caret = descr->focus_item + (page * descr->page_size) - 1;
2280 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002281 else caret = descr->focus_item + LISTBOX_GetCurrentPageSize(descr) - 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002282 if (caret >= descr->nb_items) caret = descr->nb_items - 1;
2283 break;
2284 case VK_HOME:
2285 caret = 0;
2286 break;
2287 case VK_END:
2288 caret = descr->nb_items - 1;
2289 break;
2290 case VK_SPACE:
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002291 if (descr->style & LBS_EXTENDEDSEL) caret = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002292 else if (descr->style & LBS_MULTIPLESEL)
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002293 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002294 LISTBOX_SetSelection( wnd, descr, descr->focus_item,
2295 !descr->items[descr->focus_item].selected,
2296 (descr->style & LBS_NOTIFY) != 0 );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002297 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002298 break;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002299 default:
2300 bForceSelection = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002301 }
Gerard Patelc9a6d501999-07-25 13:03:17 +00002302 if (bForceSelection) /* focused item is used instead of key */
2303 caret = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002304 if (caret >= 0)
2305 {
2306 if ((descr->style & LBS_EXTENDEDSEL) &&
Alexandre Julliarda3960291999-02-26 11:11:13 +00002307 !(GetKeyState( VK_SHIFT ) & 0x8000))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002308 descr->anchor_item = caret;
2309 LISTBOX_MoveCaret( wnd, descr, caret, TRUE );
Gerard Patelc9a6d501999-07-25 13:03:17 +00002310 LISTBOX_SetSelection( wnd, descr, caret, TRUE, FALSE);
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002311 if (descr->style & LBS_NOTIFY)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002312 {
Dmitry Timoshkov6df245d2001-04-09 18:30:25 +00002313 if( descr->lphc )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002314 {
2315 /* make sure that combo parent doesn't hide us */
2316 descr->lphc->wState |= CBF_NOROLLUP;
2317 }
Gerard Patelc9a6d501999-07-25 13:03:17 +00002318 if (descr->nb_items) SEND_NOTIFICATION( wnd, descr, LBN_SELCHANGE );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002319 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002320 }
2321 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002322}
2323
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002324
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002325/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002326 * LISTBOX_HandleChar
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002327 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002328static LRESULT LISTBOX_HandleChar( WND *wnd, LB_DESCR *descr, WCHAR charW )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002329{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002330 INT caret = -1;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002331 WCHAR str[2];
2332
2333 str[0] = charW;
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002334 str[1] = '\0';
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002335
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002336 if (descr->style & LBS_WANTKEYBOARDINPUT)
2337 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002338 caret = SendMessageW( descr->owner, WM_CHARTOITEM,
2339 MAKEWPARAM(charW, descr->focus_item),
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002340 wnd->hwndSelf );
2341 if (caret == -2) return 0;
2342 }
2343 if (caret == -1)
2344 caret = LISTBOX_FindString( wnd, descr, descr->focus_item, str, FALSE);
2345 if (caret != -1)
2346 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00002347 if ((!IS_MULTISELECT(descr)) && descr->selected_item == -1)
2348 LISTBOX_SetSelection( wnd, descr, caret, TRUE, FALSE);
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002349 LISTBOX_MoveCaret( wnd, descr, caret, TRUE );
Gerard Patelc9a6d501999-07-25 13:03:17 +00002350 if ((descr->style & LBS_NOTIFY) && descr->nb_items)
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002351 SEND_NOTIFICATION( wnd, descr, LBN_SELCHANGE );
2352 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002353 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002354}
2355
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002356
2357/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002358 * LISTBOX_Create
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002359 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002360static BOOL LISTBOX_Create( WND *wnd, LPHEADCOMBO lphc )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002361{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002362 LB_DESCR *descr;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002363 MEASUREITEMSTRUCT mis;
2364 RECT rect;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002365
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002366 if (!(descr = HeapAlloc( GetProcessHeap(), 0, sizeof(*descr) )))
2367 return FALSE;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002368
Alexandre Julliarda3960291999-02-26 11:11:13 +00002369 GetClientRect( wnd->hwndSelf, &rect );
2370 descr->owner = GetParent( wnd->hwndSelf );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002371 descr->style = wnd->dwStyle;
2372 descr->width = rect.right - rect.left;
2373 descr->height = rect.bottom - rect.top;
2374 descr->items = NULL;
2375 descr->nb_items = 0;
2376 descr->top_item = 0;
2377 descr->selected_item = -1;
2378 descr->focus_item = 0;
2379 descr->anchor_item = -1;
2380 descr->item_height = 1;
2381 descr->page_size = 1;
2382 descr->column_width = 150;
2383 descr->horz_extent = (wnd->dwStyle & WS_HSCROLL) ? 1 : 0;
2384 descr->horz_pos = 0;
2385 descr->nb_tabs = 0;
2386 descr->tabs = NULL;
Serge Ivanov07917e42000-06-07 03:46:57 +00002387 descr->caret_on = lphc ? FALSE : TRUE;
Andreas Mohr85ba8792001-01-06 00:34:14 +00002388 if (descr->style & LBS_NOSEL) descr->caret_on = FALSE;
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002389 descr->in_focus = FALSE;
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002390 descr->captured = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002391 descr->font = 0;
2392 descr->locale = 0; /* FIXME */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002393 descr->lphc = lphc;
2394
Nick Hollowayb9ce4fd1999-09-11 16:29:00 +00002395 if( ( GetExpWinVer16( wnd->hInstance ) & 0xFF00 ) == 0x0300
2396 && ( descr->style & ( WS_VSCROLL | WS_HSCROLL ) ) )
2397 {
2398 /* Win95 document "List Box Differences" from MSDN:
2399 If a list box in a version 3.x application has either the
2400 WS_HSCROLL or WS_VSCROLL style, the list box receives both
2401 horizontal and vertical scroll bars.
2402 */
2403 descr->style |= WS_VSCROLL | WS_HSCROLL;
2404 }
2405
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002406 if( lphc )
2407 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +00002408 TRACE_(combo)("[%04x]: resetting owner %04x -> %04x\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002409 wnd->hwndSelf, descr->owner, lphc->self->hwndSelf );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002410 descr->owner = lphc->self->hwndSelf;
2411 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00002412
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002413 *(LB_DESCR **)wnd->wExtra = descr;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002414
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002415/* if (wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) descr->style &= ~LBS_NOTIFY;
2416 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002417 if (descr->style & LBS_EXTENDEDSEL) descr->style |= LBS_MULTIPLESEL;
2418 if (descr->style & LBS_MULTICOLUMN) descr->style &= ~LBS_OWNERDRAWVARIABLE;
2419 if (descr->style & LBS_OWNERDRAWVARIABLE) descr->style |= LBS_NOINTEGRALHEIGHT;
2420 descr->item_height = LISTBOX_SetFont( wnd, descr, 0 );
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002421
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002422 if (descr->style & LBS_OWNERDRAWFIXED)
2423 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002424 if( descr->lphc && (descr->lphc->dwStyle & CBS_DROPDOWN))
2425 {
2426 /* WinWord gets VERY unhappy if we send WM_MEASUREITEM from here */
Francis Beaudetf585c611999-04-02 10:37:42 +00002427 descr->item_height = lphc->fixedOwnerDrawHeight;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002428 }
2429 else
2430 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002431 mis.CtlType = ODT_LISTBOX;
Serge Ivanov07917e42000-06-07 03:46:57 +00002432 mis.CtlID = wnd->wIDmenu;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002433 mis.itemID = -1;
2434 mis.itemWidth = 0;
2435 mis.itemData = 0;
2436 mis.itemHeight = descr->item_height;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002437 SendMessageW( descr->owner, WM_MEASUREITEM, wnd->wIDmenu, (LPARAM)&mis );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002438 descr->item_height = mis.itemHeight ? mis.itemHeight : 1;
2439 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002440 }
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002441
Andreas Mohr85ba8792001-01-06 00:34:14 +00002442 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 +00002443 return TRUE;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002444}
2445
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002446
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002447/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002448 * LISTBOX_Destroy
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002449 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002450static BOOL LISTBOX_Destroy( WND *wnd, LB_DESCR *descr )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002451{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002452 LISTBOX_ResetContent( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002453 HeapFree( GetProcessHeap(), 0, descr );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002454 wnd->wExtra[0] = 0;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00002455 return TRUE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002456}
2457
2458
2459/***********************************************************************
2460 * ListBoxWndProc
2461 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002462static LRESULT WINAPI ListBoxWndProc_locked( WND* wnd, UINT msg,
2463 WPARAM wParam, LPARAM lParam, BOOL unicode )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002464{
2465 LRESULT ret;
2466 LB_DESCR *descr;
Marcus Meissner9aded511999-05-01 10:23:45 +00002467 HWND hwnd = wnd->hwndSelf;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002468
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002469 if (!(descr = *(LB_DESCR **)wnd->wExtra))
2470 {
Bill Medlande79f0762001-07-17 00:55:23 +00002471 if (msg == WM_CREATE)
2472 {
2473 if (!LISTBOX_Create( wnd, NULL ))
2474 return -1;
2475 TRACE("creating wnd=%04x descr=%p\n", hwnd, *(LB_DESCR **)wnd->wExtra );
2476 return 0;
2477 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002478 /* Ignore all other messages before we get a WM_CREATE */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002479 return unicode ? DefWindowProcW( hwnd, msg, wParam, lParam ) :
2480 DefWindowProcA( hwnd, msg, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002481 }
2482
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002483 TRACE("[%04x]: msg %s wp %08x lp %08lx\n",
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002484 wnd->hwndSelf, SPY_GetMsgName(msg), wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002485 switch(msg)
2486 {
2487 case LB_RESETCONTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002488 case LB_RESETCONTENT:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002489 LISTBOX_ResetContent( wnd, descr );
Louis Philippe Gagnon537bcad2000-11-30 20:37:29 +00002490 LISTBOX_UpdateScroll( wnd, descr );
2491 InvalidateRect( wnd->hwndSelf, NULL, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002492 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002493
2494 case LB_ADDSTRING16:
Alexandre Julliard982a2232000-12-13 20:20:09 +00002495 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002496 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002497 case LB_ADDSTRING:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002498 {
2499 INT ret;
2500 LPWSTR textW;
2501 if(unicode || !HAS_STRINGS(descr))
2502 textW = (LPWSTR)lParam;
2503 else
2504 {
2505 LPSTR textA = (LPSTR)lParam;
2506 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2507 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2508 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2509 }
2510 wParam = LISTBOX_FindStringPos( wnd, descr, textW, FALSE );
2511 ret = LISTBOX_InsertString( wnd, descr, wParam, textW );
2512 if (!unicode && HAS_STRINGS(descr))
2513 HeapFree(GetProcessHeap(), 0, textW);
2514 return ret;
2515 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002516
2517 case LB_INSERTSTRING16:
Alexandre Julliard982a2232000-12-13 20:20:09 +00002518 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002519 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002520 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002521 case LB_INSERTSTRING:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002522 {
2523 INT ret;
2524 LPWSTR textW;
2525 if(unicode || !HAS_STRINGS(descr))
2526 textW = (LPWSTR)lParam;
2527 else
2528 {
2529 LPSTR textA = (LPSTR)lParam;
2530 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2531 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2532 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2533 }
2534 ret = LISTBOX_InsertString( wnd, descr, wParam, textW );
2535 if(!unicode && HAS_STRINGS(descr))
2536 HeapFree(GetProcessHeap(), 0, textW);
2537 return ret;
2538 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002539
2540 case LB_ADDFILE16:
Alexandre Julliard982a2232000-12-13 20:20:09 +00002541 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002542 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002543 case LB_ADDFILE:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002544 {
2545 INT ret;
2546 LPWSTR textW;
2547 if(unicode || !HAS_STRINGS(descr))
2548 textW = (LPWSTR)lParam;
2549 else
2550 {
2551 LPSTR textA = (LPSTR)lParam;
2552 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2553 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2554 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2555 }
2556 wParam = LISTBOX_FindFileStrPos( wnd, descr, textW );
2557 ret = LISTBOX_InsertString( wnd, descr, wParam, textW );
2558 if(!unicode && HAS_STRINGS(descr))
2559 HeapFree(GetProcessHeap(), 0, textW);
2560 return ret;
2561 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002562
2563 case LB_DELETESTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002564 case LB_DELETESTRING:
Gerard Patelc9a6d501999-07-25 13:03:17 +00002565 if (LISTBOX_RemoveItem( wnd, descr, wParam) != LB_ERR)
2566 return descr->nb_items;
2567 else
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002568 return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002569
2570 case LB_GETITEMDATA16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002571 case LB_GETITEMDATA:
2572 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002573 return LB_ERR;
2574 return descr->items[wParam].data;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002575
2576 case LB_SETITEMDATA16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002577 case LB_SETITEMDATA:
2578 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002579 return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002580 descr->items[wParam].data = (DWORD)lParam;
Marcus Meissner9aded511999-05-01 10:23:45 +00002581 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002582
2583 case LB_GETCOUNT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002584 case LB_GETCOUNT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002585 return descr->nb_items;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002586
2587 case LB_GETTEXT16:
Alexandre Julliard982a2232000-12-13 20:20:09 +00002588 lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002589 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002590 case LB_GETTEXT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002591 return LISTBOX_GetText( descr, wParam, lParam, unicode );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002592
2593 case LB_GETTEXTLEN16:
2594 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002595 case LB_GETTEXTLEN:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002596 if ((INT)wParam >= descr->nb_items || (INT)wParam < 0)
Marcus Meissner9aded511999-05-01 10:23:45 +00002597 return LB_ERR;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002598 return (HAS_STRINGS(descr) ? strlenW(descr->items[wParam].str)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002599 : sizeof(DWORD));
2600
2601 case LB_GETCURSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002602 case LB_GETCURSEL:
Francis Beaudet8730e451999-03-25 13:22:02 +00002603 if (descr->nb_items==0)
Marcus Meissner9aded511999-05-01 10:23:45 +00002604 return LB_ERR;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002605 if (!IS_MULTISELECT(descr))
2606 return descr->selected_item;
Marcus Meissner9aded511999-05-01 10:23:45 +00002607 /* else */
2608 if (descr->selected_item!=-1)
2609 return descr->selected_item;
2610 /* else */
2611 return descr->focus_item;
Lawson Whitney613092a1999-03-22 14:46:43 +00002612 /* otherwise, if the user tries to move the selection with the */
2613 /* arrow keys, we will give the application something to choke on */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002614 case LB_GETTOPINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002615 case LB_GETTOPINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002616 return descr->top_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002617
2618 case LB_GETITEMHEIGHT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002619 case LB_GETITEMHEIGHT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002620 return LISTBOX_GetItemHeight( descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002621
2622 case LB_SETITEMHEIGHT16:
2623 lParam = LOWORD(lParam);
2624 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002625 case LB_SETITEMHEIGHT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002626 return LISTBOX_SetItemHeight( wnd, descr, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002627
Alexandre Julliarda3960291999-02-26 11:11:13 +00002628 case LB_ITEMFROMPOINT:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002629 {
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002630 POINT pt;
2631 RECT rect;
2632
2633 pt.x = LOWORD(lParam);
2634 pt.y = HIWORD(lParam);
2635 rect.left = 0;
2636 rect.top = 0;
2637 rect.right = descr->width;
2638 rect.bottom = descr->height;
2639
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002640 return MAKELONG( LISTBOX_GetItemFromPoint(descr, pt.x, pt.y),
Gerard Patel777508a1999-05-08 12:35:17 +00002641 !PtInRect( &rect, pt ) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002642 }
2643
2644 case LB_SETCARETINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002645 case LB_SETCARETINDEX:
Gerard Patelc9a6d501999-07-25 13:03:17 +00002646 if ((!IS_MULTISELECT(descr)) && (descr->selected_item != -1)) return LB_ERR;
2647 if (LISTBOX_SetCaretIndex( wnd, descr, wParam, !lParam ) == LB_ERR)
2648 return LB_ERR;
2649 else if (ISWIN31)
2650 return wParam;
2651 else
2652 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002653
2654 case LB_GETCARETINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002655 case LB_GETCARETINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002656 return descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002657
2658 case LB_SETTOPINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002659 case LB_SETTOPINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002660 return LISTBOX_SetTopItem( wnd, descr, wParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002661
2662 case LB_SETCOLUMNWIDTH16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002663 case LB_SETCOLUMNWIDTH:
Marcus Meissner9aded511999-05-01 10:23:45 +00002664 return LISTBOX_SetColumnWidth( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002665
2666 case LB_GETITEMRECT16:
2667 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002668 RECT rect;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002669 ret = LISTBOX_GetItemRect( descr, (INT16)wParam, &rect );
Alexandre Julliard982a2232000-12-13 20:20:09 +00002670 CONV_RECT32TO16( &rect, MapSL(lParam) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002671 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002672 return ret;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002673
Alexandre Julliarda3960291999-02-26 11:11:13 +00002674 case LB_GETITEMRECT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002675 return LISTBOX_GetItemRect( descr, wParam, (RECT *)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002676
2677 case LB_FINDSTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002678 wParam = (INT)(INT16)wParam;
Alexandre Julliard982a2232000-12-13 20:20:09 +00002679 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002680 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002681 case LB_FINDSTRING:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002682 {
2683 INT ret;
2684 LPWSTR textW;
2685 if(unicode || !HAS_STRINGS(descr))
2686 textW = (LPWSTR)lParam;
2687 else
2688 {
2689 LPSTR textA = (LPSTR)lParam;
2690 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2691 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2692 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2693 }
2694 ret = LISTBOX_FindString( wnd, descr, wParam, textW, FALSE );
2695 if(!unicode && HAS_STRINGS(descr))
2696 HeapFree(GetProcessHeap(), 0, textW);
2697 return ret;
2698 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002699
2700 case LB_FINDSTRINGEXACT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002701 wParam = (INT)(INT16)wParam;
Alexandre Julliard982a2232000-12-13 20:20:09 +00002702 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002703 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002704 case LB_FINDSTRINGEXACT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002705 {
2706 INT ret;
2707 LPWSTR textW;
2708 if(unicode || !HAS_STRINGS(descr))
2709 textW = (LPWSTR)lParam;
2710 else
2711 {
2712 LPSTR textA = (LPSTR)lParam;
2713 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2714 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2715 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2716 }
2717 ret = LISTBOX_FindString( wnd, descr, wParam, textW, TRUE );
2718 if(!unicode && HAS_STRINGS(descr))
2719 HeapFree(GetProcessHeap(), 0, textW);
2720 return ret;
2721 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002722
2723 case LB_SELECTSTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002724 wParam = (INT)(INT16)wParam;
Alexandre Julliard982a2232000-12-13 20:20:09 +00002725 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002726 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002727 case LB_SELECTSTRING:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002728 {
2729 INT index;
2730 LPWSTR textW;
Dmitry Timoshkove8ffcaa2001-04-16 19:32:19 +00002731
2732 if(HAS_STRINGS(descr))
2733 TRACE("LB_SELECTSTRING: %s\n", unicode ? debugstr_w((LPWSTR)lParam) :
2734 debugstr_a((LPSTR)lParam));
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002735 if(unicode || !HAS_STRINGS(descr))
2736 textW = (LPWSTR)lParam;
2737 else
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002738 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002739 LPSTR textA = (LPSTR)lParam;
2740 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2741 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2742 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002743 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002744 index = LISTBOX_FindString( wnd, descr, wParam, textW, FALSE );
2745 if(!unicode && HAS_STRINGS(descr))
2746 HeapFree(GetProcessHeap(), 0, textW);
2747 if (index != LB_ERR)
Dmitry Timoshkove8ffcaa2001-04-16 19:32:19 +00002748 {
2749 LISTBOX_SetCaretIndex( wnd, descr, index, TRUE );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002750 LISTBOX_SetSelection( wnd, descr, index, TRUE, FALSE );
Dmitry Timoshkove8ffcaa2001-04-16 19:32:19 +00002751 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002752 return index;
2753 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002754
2755 case LB_GETSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002756 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002757 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002758 case LB_GETSEL:
2759 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002760 return LB_ERR;
2761 return descr->items[wParam].selected;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002762
2763 case LB_SETSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002764 lParam = (INT)(INT16)lParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002765 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002766 case LB_SETSEL:
Marcus Meissner9aded511999-05-01 10:23:45 +00002767 return LISTBOX_SetSelection( wnd, descr, lParam, wParam, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002768
2769 case LB_SETCURSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002770 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002771 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002772 case LB_SETCURSEL:
Gerard Patelc9a6d501999-07-25 13:03:17 +00002773 if (IS_MULTISELECT(descr)) return LB_ERR;
Alexandre Julliard638f1691999-01-17 16:32:32 +00002774 LISTBOX_SetCaretIndex( wnd, descr, wParam, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002775 return LISTBOX_SetSelection( wnd, descr, wParam, TRUE, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002776
2777 case LB_GETSELCOUNT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002778 case LB_GETSELCOUNT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002779 return LISTBOX_GetSelCount( descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002780
2781 case LB_GETSELITEMS16:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002782 return LISTBOX_GetSelItems16( descr, wParam, (LPINT16)MapSL(lParam) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002783
Alexandre Julliarda3960291999-02-26 11:11:13 +00002784 case LB_GETSELITEMS:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002785 return LISTBOX_GetSelItems( descr, wParam, (LPINT)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002786
2787 case LB_SELITEMRANGE16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002788 case LB_SELITEMRANGE:
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002789 if (LOWORD(lParam) <= HIWORD(lParam))
Marcus Meissner9aded511999-05-01 10:23:45 +00002790 return LISTBOX_SelectItemRange( wnd, descr, LOWORD(lParam),
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002791 HIWORD(lParam), wParam );
2792 else
Marcus Meissner9aded511999-05-01 10:23:45 +00002793 return LISTBOX_SelectItemRange( wnd, descr, HIWORD(lParam),
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002794 LOWORD(lParam), wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002795
2796 case LB_SELITEMRANGEEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002797 case LB_SELITEMRANGEEX:
2798 if ((INT)lParam >= (INT)wParam)
Marcus Meissner9aded511999-05-01 10:23:45 +00002799 return LISTBOX_SelectItemRange( wnd, descr, wParam, lParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002800 else
Marcus Meissner9aded511999-05-01 10:23:45 +00002801 return LISTBOX_SelectItemRange( wnd, descr, lParam, wParam, FALSE);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002802
2803 case LB_GETHORIZONTALEXTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002804 case LB_GETHORIZONTALEXTENT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002805 return descr->horz_extent;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002806
2807 case LB_SETHORIZONTALEXTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002808 case LB_SETHORIZONTALEXTENT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002809 return LISTBOX_SetHorizontalExtent( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002810
2811 case LB_GETANCHORINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002812 case LB_GETANCHORINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002813 return descr->anchor_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002814
2815 case LB_SETANCHORINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002816 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002817 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002818 case LB_SETANCHORINDEX:
2819 if (((INT)wParam < -1) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002820 return LB_ERR;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002821 descr->anchor_item = (INT)wParam;
Marcus Meissner9aded511999-05-01 10:23:45 +00002822 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002823
2824 case LB_DIR16:
Ove Kaaven2c691b32000-11-25 03:06:03 +00002825 /* according to Win16 docs, DDL_DRIVES should make DDL_EXCLUSIVE
2826 * be set automatically (this is different in Win32) */
2827 if (wParam & DDL_DRIVES) wParam |= DDL_EXCLUSIVE;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002828 lParam = (LPARAM)MapSL(lParam);
2829 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002830 case LB_DIR:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002831 {
2832 INT ret;
2833 LPWSTR textW;
2834 if(unicode)
2835 textW = (LPWSTR)lParam;
2836 else
2837 {
2838 LPSTR textA = (LPSTR)lParam;
2839 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2840 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2841 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2842 }
2843 ret = LISTBOX_Directory( wnd, descr, wParam, textW, msg == LB_DIR );
2844 if(!unicode)
2845 HeapFree(GetProcessHeap(), 0, textW);
2846 return ret;
2847 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002848
Alexandre Julliarda3960291999-02-26 11:11:13 +00002849 case LB_GETLOCALE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002850 return descr->locale;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002851
Alexandre Julliarda3960291999-02-26 11:11:13 +00002852 case LB_SETLOCALE:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002853 descr->locale = (LCID)wParam; /* FIXME: should check for valid lcid */
Marcus Meissner9aded511999-05-01 10:23:45 +00002854 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002855
Alexandre Julliarda3960291999-02-26 11:11:13 +00002856 case LB_INITSTORAGE:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002857 return LISTBOX_InitStorage( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002858
Alexandre Julliarda3960291999-02-26 11:11:13 +00002859 case LB_SETCOUNT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002860 return LISTBOX_SetCount( wnd, descr, (INT)wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002861
2862 case LB_SETTABSTOPS16:
Alexandre Julliard982a2232000-12-13 20:20:09 +00002863 return LISTBOX_SetTabStops( wnd, descr, (INT)(INT16)wParam, MapSL(lParam), TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002864
Alexandre Julliarda3960291999-02-26 11:11:13 +00002865 case LB_SETTABSTOPS:
Marcus Meissner9aded511999-05-01 10:23:45 +00002866 return LISTBOX_SetTabStops( wnd, descr, wParam, (LPINT)lParam, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002867
2868 case LB_CARETON16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002869 case LB_CARETON:
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002870 if (descr->caret_on)
Marcus Meissner9aded511999-05-01 10:23:45 +00002871 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002872 descr->caret_on = TRUE;
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002873 if ((descr->focus_item != -1) && (descr->in_focus))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002874 LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002875 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002876
2877 case LB_CARETOFF16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002878 case LB_CARETOFF:
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002879 if (!descr->caret_on)
Marcus Meissner9aded511999-05-01 10:23:45 +00002880 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002881 descr->caret_on = FALSE;
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002882 if ((descr->focus_item != -1) && (descr->in_focus))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002883 LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002884 return LB_OKAY;
Susan Farleyd34205e2000-05-15 02:34:20 +00002885
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002886 case WM_DESTROY:
Marcus Meissner9aded511999-05-01 10:23:45 +00002887 return LISTBOX_Destroy( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002888
2889 case WM_ENABLE:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002890 InvalidateRect( hwnd, NULL, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002891 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002892
2893 case WM_SETREDRAW:
2894 LISTBOX_SetRedraw( wnd, descr, wParam != 0 );
Marcus Meissner9aded511999-05-01 10:23:45 +00002895 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002896
2897 case WM_GETDLGCODE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002898 return DLGC_WANTARROWS | DLGC_WANTCHARS;
2899
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002900 case WM_PAINT:
2901 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002902 PAINTSTRUCT ps;
2903 HDC hdc = ( wParam ) ? ((HDC)wParam)
2904 : BeginPaint( hwnd, &ps );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002905 ret = LISTBOX_Paint( wnd, descr, hdc );
Alexandre Julliarda3960291999-02-26 11:11:13 +00002906 if( !wParam ) EndPaint( hwnd, &ps );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002907 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002908 return ret;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002909 case WM_SIZE:
2910 LISTBOX_UpdateSize( wnd, descr );
Marcus Meissner9aded511999-05-01 10:23:45 +00002911 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002912 case WM_GETFONT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002913 return descr->font;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002914 case WM_SETFONT:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002915 LISTBOX_SetFont( wnd, descr, (HFONT)wParam );
2916 if (lParam) InvalidateRect( wnd->hwndSelf, 0, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002917 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002918 case WM_SETFOCUS:
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002919 descr->in_focus = TRUE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002920 descr->caret_on = TRUE;
2921 if (descr->focus_item != -1)
2922 LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
2923 SEND_NOTIFICATION( wnd, descr, LBN_SETFOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002924 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002925 case WM_KILLFOCUS:
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002926 descr->in_focus = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002927 if ((descr->focus_item != -1) && descr->caret_on)
2928 LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
2929 SEND_NOTIFICATION( wnd, descr, LBN_KILLFOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002930 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002931 case WM_HSCROLL:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002932 return LISTBOX_HandleHScroll( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002933 case WM_VSCROLL:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002934 return LISTBOX_HandleVScroll( wnd, descr, wParam );
Stephane Lussier4bdf4af2000-04-18 11:56:33 +00002935 case WM_MOUSEWHEEL:
2936 if (wParam & (MK_SHIFT | MK_CONTROL))
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002937 return unicode ? DefWindowProcW( hwnd, msg, wParam, lParam ) :
2938 DefWindowProcA( hwnd, msg, wParam, lParam );
2939 return LISTBOX_HandleMouseWheel( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002940 case WM_LBUTTONDOWN:
Marcus Meissner9aded511999-05-01 10:23:45 +00002941 return LISTBOX_HandleLButtonDown( wnd, descr, wParam,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002942 (INT16)LOWORD(lParam),
2943 (INT16)HIWORD(lParam) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002944 case WM_LBUTTONDBLCLK:
2945 if (descr->style & LBS_NOTIFY)
2946 SEND_NOTIFICATION( wnd, descr, LBN_DBLCLK );
Marcus Meissner9aded511999-05-01 10:23:45 +00002947 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002948 case WM_MOUSEMOVE:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002949 if (GetCapture() == hwnd)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002950 LISTBOX_HandleMouseMove( wnd, descr, (INT16)LOWORD(lParam),
2951 (INT16)HIWORD(lParam) );
Marcus Meissner9aded511999-05-01 10:23:45 +00002952 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002953 case WM_LBUTTONUP:
Marcus Meissner9aded511999-05-01 10:23:45 +00002954 return LISTBOX_HandleLButtonUp( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002955 case WM_KEYDOWN:
Marcus Meissner9aded511999-05-01 10:23:45 +00002956 return LISTBOX_HandleKeyDown( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002957 case WM_CHAR:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002958 {
2959 WCHAR charW;
2960 if(unicode)
2961 charW = (WCHAR)wParam;
2962 else
2963 {
2964 CHAR charA = (CHAR)wParam;
2965 MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1);
2966 }
2967 return LISTBOX_HandleChar( wnd, descr, charW );
2968 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002969 case WM_SYSTIMER:
Marcus Meissner9aded511999-05-01 10:23:45 +00002970 return LISTBOX_HandleSystemTimer( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002971 case WM_ERASEBKGND:
Gerard Patel41b07fb2000-06-15 00:07:20 +00002972 if ((IS_OWNERDRAW(descr)) && !(descr->style & LBS_DISPLAYCHANGED))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002973 {
Luc Tourangeau89147991999-04-18 09:23:56 +00002974 RECT rect;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002975 HBRUSH hbrush = SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002976 wParam, (LPARAM)wnd->hwndSelf );
Dmitry Timoshkov52ece0e2001-02-26 22:31:55 +00002977 TRACE("hbrush = %04x\n", hbrush);
2978 if(!hbrush)
2979 hbrush = GetSysColorBrush(COLOR_WINDOW);
2980 if(hbrush)
2981 {
2982 GetClientRect(hwnd, &rect);
2983 FillRect((HDC)wParam, &rect, hbrush);
2984 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002985 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002986 return 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002987 case WM_DROPFILES:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002988 if( !descr->lphc )
2989 return unicode ? SendMessageW( descr->owner, msg, wParam, lParam ) :
2990 SendMessageA( descr->owner, msg, wParam, lParam );
2991 break;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002992
2993 case WM_DROPOBJECT:
2994 case WM_QUERYDROPOBJECT:
2995 case WM_DRAGSELECT:
2996 case WM_DRAGMOVE:
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002997 if( !descr->lphc )
2998 {
Alexandre Julliard982a2232000-12-13 20:20:09 +00002999 LPDRAGINFO16 dragInfo = MapSL( lParam );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003000 dragInfo->l = LISTBOX_GetItemFromPoint( descr, dragInfo->pt.x,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003001 dragInfo->pt.y );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003002 return SendMessage16( descr->owner, msg, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003003 }
3004 break;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003005
3006 default:
3007 if ((msg >= WM_USER) && (msg < 0xc000))
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003008 WARN("[%04x]: unknown msg %04x wp %08x lp %08lx\n",
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003009 hwnd, msg, wParam, lParam );
3010 return unicode ? DefWindowProcW( hwnd, msg, wParam, lParam ) :
3011 DefWindowProcA( hwnd, msg, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003012 }
Marcus Meissner9aded511999-05-01 10:23:45 +00003013 return 0;
3014}
3015
3016/***********************************************************************
Alexandre Julliard91222da2000-12-10 23:01:33 +00003017 * ListBoxWndProcA
Marcus Meissner9aded511999-05-01 10:23:45 +00003018 *
3019 * This is just a wrapper for the real wndproc, it only does window locking
3020 * and unlocking.
3021 */
Alexandre Julliard91222da2000-12-10 23:01:33 +00003022static LRESULT WINAPI ListBoxWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
Marcus Meissner9aded511999-05-01 10:23:45 +00003023{
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003024 LRESULT res = 0;
3025 WND* wndPtr = WIN_FindWndPtr( hwnd );
Marcus Meissner9aded511999-05-01 10:23:45 +00003026
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003027 if (wndPtr)
3028 {
3029 res = ListBoxWndProc_locked(wndPtr, msg, wParam, lParam, FALSE);
3030 WIN_ReleaseWndPtr(wndPtr);
3031 }
Marcus Meissner9aded511999-05-01 10:23:45 +00003032 return res;
Alexandre Julliard58199531994-04-21 01:20:00 +00003033}
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003034
3035/***********************************************************************
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003036 * ListBoxWndProcW
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003037 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003038static LRESULT WINAPI ListBoxWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003039{
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003040 LRESULT res = 0;
3041 WND* wndPtr = WIN_FindWndPtr( hwnd );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003042
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003043 if (wndPtr)
3044 {
3045 res = ListBoxWndProc_locked(wndPtr, msg, wParam, lParam, TRUE);
3046 WIN_ReleaseWndPtr(wndPtr);
3047 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003048 return res;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003049}
3050
3051/***********************************************************************
Marcus Meissner9aded511999-05-01 10:23:45 +00003052 * ComboLBWndProc_locked
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003053 *
Marcus Meissner9aded511999-05-01 10:23:45 +00003054 * The real combo listbox wndproc, but called with locked WND struct.
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003055 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003056static LRESULT WINAPI ComboLBWndProc_locked( WND* wnd, UINT msg,
3057 WPARAM wParam, LPARAM lParam, BOOL unicode )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003058{
3059 LRESULT lRet = 0;
Dmitry Timoshkove8ffcaa2001-04-16 19:32:19 +00003060 HWND hwnd;
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003061 LB_DESCR *descr = *(LB_DESCR **)wnd->wExtra;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003062
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003063 TRACE_(combo)("[%04x]: msg %s wp %08x lp %08lx\n",
3064 wnd->hwndSelf, SPY_GetMsgName(msg), wParam, lParam );
3065
3066 hwnd = wnd->hwndSelf;
3067
3068 if( descr || msg == WM_CREATE )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003069 {
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003070 LPHEADCOMBO lphc = (descr) ? descr->lphc : NULL;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003071
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003072 switch( msg )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003073 {
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003074 case WM_CREATE:
3075 {
3076 CREATESTRUCTA *lpcs = (CREATESTRUCTA *)lParam;
3077 TRACE_(combo)("\tpassed parent handle = %p\n",lpcs->lpCreateParams);
3078 lphc = (LPHEADCOMBO)(lpcs->lpCreateParams);
3079 return LISTBOX_Create( wnd, lphc );
3080 }
3081 case WM_MOUSEMOVE:
3082 if ( (TWEAK_WineLook > WIN31_LOOK) &&
3083 (CB_GETTYPE(lphc) != CBS_SIMPLE) )
3084 {
3085 POINT mousePos;
3086 BOOL captured;
3087 RECT clientRect;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003088
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003089 mousePos.x = (INT16)LOWORD(lParam);
3090 mousePos.y = (INT16)HIWORD(lParam);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003091
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003092 /*
3093 * If we are in a dropdown combobox, we simulate that
3094 * the mouse is captured to show the tracking of the item.
3095 */
3096 GetClientRect(hwnd, &clientRect);
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003097
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003098 if (PtInRect( &clientRect, mousePos ))
3099 {
3100 captured = descr->captured;
3101 descr->captured = TRUE;
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003102
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003103 LISTBOX_HandleMouseMove( wnd, descr,
3104 mousePos.x, mousePos.y);
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003105
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003106 descr->captured = captured;
Pierre Mageau25c62cc1999-09-11 16:26:03 +00003107
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003108 }
3109 else
3110 {
3111 LISTBOX_HandleMouseMove( wnd, descr,
3112 mousePos.x, mousePos.y);
3113 }
Pierre Mageau25c62cc1999-09-11 16:26:03 +00003114
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003115 return 0;
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003116
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003117 }
3118 else
3119 {
3120 /*
3121 * If we are in Win3.1 look, go with the default behavior.
3122 */
3123 return unicode ? ListBoxWndProcW( hwnd, msg, wParam, lParam ) :
3124 ListBoxWndProcA( hwnd, msg, wParam, lParam );
3125 }
3126 case WM_LBUTTONUP:
3127 if (TWEAK_WineLook > WIN31_LOOK)
3128 {
3129 POINT mousePos;
3130 RECT clientRect;
Pierre Mageau25c62cc1999-09-11 16:26:03 +00003131
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003132 /*
3133 * If the mouse button "up" is not in the listbox,
3134 * we make sure there is no selection by re-selecting the
3135 * item that was selected when the listbox was made visible.
3136 */
3137 mousePos.x = (INT16)LOWORD(lParam);
3138 mousePos.y = (INT16)HIWORD(lParam);
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003139
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003140 GetClientRect(hwnd, &clientRect);
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003141
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003142 /*
3143 * When the user clicks outside the combobox and the focus
3144 * is lost, the owning combobox will send a fake buttonup with
3145 * 0xFFFFFFF as the mouse location, we must also revert the
3146 * selection to the original selection.
3147 */
3148 if ( (lParam == (LPARAM)-1) ||
3149 (!PtInRect( &clientRect, mousePos )) )
3150 {
3151 LISTBOX_MoveCaret( wnd, descr, lphc->droppedIndex, FALSE );
3152 }
3153 }
3154 return LISTBOX_HandleLButtonUp( wnd, descr );
3155 case WM_LBUTTONDBLCLK:
3156 case WM_LBUTTONDOWN:
3157 return LISTBOX_HandleLButtonDownCombo(wnd, descr, msg, wParam,
3158 (INT16)LOWORD(lParam),
3159 (INT16)HIWORD(lParam) );
3160 case WM_NCACTIVATE:
3161 return FALSE;
3162 case WM_KEYDOWN:
3163 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
3164 {
3165 /* for some reason(?) Windows makes it possible to
3166 * show/hide ComboLBox by sending it WM_KEYDOWNs */
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003167
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003168 if( (!(lphc->wState & CBF_EUI) && wParam == VK_F4) ||
3169 ( (lphc->wState & CBF_EUI) && !(lphc->wState & CBF_DROPPED)
3170 && (wParam == VK_DOWN || wParam == VK_UP)) )
3171 {
3172 COMBO_FlipListbox( lphc, FALSE, FALSE );
3173 return 0;
3174 }
3175 }
3176 return LISTBOX_HandleKeyDown( wnd, descr, wParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003177
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003178 case LB_SETCURSEL16:
3179 case LB_SETCURSEL:
3180 lRet = unicode ? ListBoxWndProcW( hwnd, msg, wParam, lParam ) :
3181 ListBoxWndProcA( hwnd, msg, wParam, lParam );
3182 lRet =(lRet == LB_ERR) ? lRet : descr->selected_item;
3183 return lRet;
3184 case WM_NCDESTROY:
3185 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
3186 lphc->hWndLBox = 0;
3187 /* fall through */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003188
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003189 default:
3190 return unicode ? ListBoxWndProcW( hwnd, msg, wParam, lParam ) :
3191 ListBoxWndProcA( hwnd, msg, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003192 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003193 }
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003194 lRet = unicode ? DefWindowProcW( hwnd, msg, wParam, lParam ) :
3195 DefWindowProcA( hwnd, msg, wParam, lParam );
3196
3197 TRACE_(combo)("\t default on msg [%04x]\n", (UINT16)msg );
3198
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003199 return lRet;
3200}
3201
Marcus Meissner9aded511999-05-01 10:23:45 +00003202/***********************************************************************
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003203 * ComboLBWndProcA
Marcus Meissner9aded511999-05-01 10:23:45 +00003204 *
3205 * NOTE: in Windows, winproc address of the ComboLBox is the same
3206 * as that of the Listbox.
3207 *
3208 * This is just a wrapper for the real wndproc, it only does window locking
3209 * and unlocking.
3210 */
Alexandre Julliard91222da2000-12-10 23:01:33 +00003211LRESULT WINAPI ComboLBWndProcA( HWND hwnd, UINT msg,
Marcus Meissner9aded511999-05-01 10:23:45 +00003212 WPARAM wParam, LPARAM lParam )
3213{
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003214 LRESULT res = 0;
Marcus Meissner9aded511999-05-01 10:23:45 +00003215 WND *wnd = WIN_FindWndPtr( hwnd );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003216
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003217 if (wnd)
3218 {
3219 res = ComboLBWndProc_locked(wnd, msg, wParam, lParam, FALSE);
3220 WIN_ReleaseWndPtr(wnd);
3221 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003222 return res;
3223}
3224
3225/***********************************************************************
3226 * ComboLBWndProcW
3227 */
3228LRESULT WINAPI ComboLBWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
3229{
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003230 LRESULT res = 0;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003231 WND *wnd = WIN_FindWndPtr( hwnd );
Marcus Meissner9aded511999-05-01 10:23:45 +00003232
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003233 if (wnd)
3234 {
3235 res = ComboLBWndProc_locked(wnd, msg, wParam, lParam, TRUE);
3236 WIN_ReleaseWndPtr(wnd);
3237 }
Marcus Meissner9aded511999-05-01 10:23:45 +00003238 return res;
3239}