blob: 08c1eb7b2e8528ed160c0fc20a25bff9abf1bfc6 [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 Julliard0799c1a2002-03-09 23:29:33 +00005 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 *
16 * You should have received a copy of the GNU Lesser General Public
17 * License along with this library; if not, write to the Free Software
Jonathan Ernst360a3f92006-05-18 14:49:52 +020018 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Dimitrie O. Paund0c950c2004-10-11 19:51:16 +000019 *
20 * NOTES
21 *
22 * This code was audited for completeness against the documented features
23 * of Comctl32.dll version 6.0 on Oct. 9, 2004, by Dimitrie O. Paun.
24 *
25 * Unless otherwise noted, we believe this code to be complete, as per
26 * the specification mentioned above.
27 * If you discover missing features, or bugs, please note them below.
28 *
29 * TODO:
30 * - GetListBoxInfo()
31 * - LB_GETLISTBOXINFO
Dimitrie O. Paund0c950c2004-10-11 19:51:16 +000032 * - LBS_NODATA
Alexandre Julliard2787be81995-05-22 18:23:01 +000033 */
34
Alexandre Julliarde2abbb11995-03-19 17:39:39 +000035#include <string.h>
David Luyeree517e81999-02-28 12:27:56 +000036#include <stdlib.h>
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000037#include <stdarg.h>
Jeremy Whited3e22d92000-02-10 19:03:02 +000038#include <stdio.h>
39#include "windef.h"
Alexandre Julliarde37c6e12003-09-05 23:08:26 +000040#include "winbase.h"
Jeremy Whited3e22d92000-02-10 19:03:02 +000041#include "wingdi.h"
Alex Korobka311d3291999-01-01 18:40:02 +000042#include "wine/winuser16.h"
Nick Hollowayb9ce4fd1999-09-11 16:29:00 +000043#include "wine/winbase16.h"
Dmitry Timoshkov74620992001-01-09 21:51:04 +000044#include "wine/unicode.h"
Alexandre Julliard6b4c02e2005-04-27 10:23:24 +000045#include "user_private.h"
Alexandre Julliard91222da2000-12-10 23:01:33 +000046#include "controls.h"
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000047#include "wine/debug.h"
Alexandre Julliard0e607781993-11-03 19:23:37 +000048
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000049WINE_DEFAULT_DEBUG_CHANNEL(listbox);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000050
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000051/* Items array granularity */
52#define LB_ARRAY_GRANULARITY 16
Alexandre Julliard0e607781993-11-03 19:23:37 +000053
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000054/* Scrolling timeout in ms */
55#define LB_SCROLL_TIMEOUT 50
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000056
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000057/* Listbox system timer id */
58#define LB_TIMER_ID 2
Alexandre Julliardac9c9b01996-07-28 18:50:11 +000059
Gerard Patel41b07fb2000-06-15 00:07:20 +000060/* flag listbox changed while setredraw false - internal style */
Alexandre Julliardde424282001-08-10 22:51:42 +000061#define LBS_DISPLAYCHANGED 0x80000000
Gerard Patel41b07fb2000-06-15 00:07:20 +000062
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000063/* Item structure */
64typedef struct
Alexandre Julliard2787be81995-05-22 18:23:01 +000065{
Alexandre Julliard2c1b3c62005-09-12 11:24:23 +000066 LPWSTR str; /* Item text */
67 BOOL selected; /* Is item selected? */
68 UINT height; /* Item height (only for OWNERDRAWVARIABLE) */
69 ULONG_PTR data; /* User data */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000070} LB_ITEMDATA;
Alexandre Julliard2787be81995-05-22 18:23:01 +000071
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000072/* Listbox structure */
73typedef struct
Alexandre Julliard2787be81995-05-22 18:23:01 +000074{
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +000075 HWND self; /* Our own window handle */
Alexandre Julliarda3960291999-02-26 11:11:13 +000076 HWND owner; /* Owner window to send notifications to */
77 UINT style; /* Window style */
78 INT width; /* Window width */
79 INT height; /* Window height */
Dimitrie O. Paund0c950c2004-10-11 19:51:16 +000080 LB_ITEMDATA *items; /* Array of items */
Alexandre Julliarda3960291999-02-26 11:11:13 +000081 INT nb_items; /* Number of items */
82 INT top_item; /* Top visible item */
83 INT selected_item; /* Selected item */
84 INT focus_item; /* Item that has the focus */
85 INT anchor_item; /* Anchor item for extended selection */
86 INT item_height; /* Default item height */
87 INT page_size; /* Items per listbox page */
88 INT column_width; /* Column width for multi-column listboxes */
89 INT horz_extent; /* Horizontal extent (0 if no hscroll) */
90 INT horz_pos; /* Horizontal position */
91 INT nb_tabs; /* Number of tabs in array */
92 INT *tabs; /* Array of tabs */
Robert Shearman630c6ea2005-07-11 14:22:36 +000093 INT avg_char_width; /* Average width of characters */
Alexandre Julliarda3960291999-02-26 11:11:13 +000094 BOOL caret_on; /* Is caret on? */
Luc Tourangeau5ee117b1999-04-04 12:48:21 +000095 BOOL captured; /* Is mouse captured? */
Alexandre Julliardab2f43f2000-05-26 22:28:34 +000096 BOOL in_focus;
Alexandre Julliarda3960291999-02-26 11:11:13 +000097 HFONT font; /* Current font */
Dimitrie O. Paund0c950c2004-10-11 19:51:16 +000098 LCID locale; /* Current locale for string comparisons */
99 LPHEADCOMBO lphc; /* ComboLBox */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000100} LB_DESCR;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000101
Alexandre Julliardfa68b751995-04-03 16:55:37 +0000102
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000103#define IS_OWNERDRAW(descr) \
104 ((descr)->style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE))
Alexandre Julliardb817f4f1996-03-14 18:08:34 +0000105
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000106#define HAS_STRINGS(descr) \
107 (!IS_OWNERDRAW(descr) || ((descr)->style & LBS_HASSTRINGS))
Alexandre Julliard2787be81995-05-22 18:23:01 +0000108
Gerard Patelc9a6d501999-07-25 13:03:17 +0000109
110#define IS_MULTISELECT(descr) \
Jon Griffiths7a9e8002004-10-05 22:31:00 +0000111 ((descr)->style & (LBS_MULTIPLESEL|LBS_EXTENDEDSEL) && \
112 !((descr)->style & LBS_NOSEL))
Gerard Patelc9a6d501999-07-25 13:03:17 +0000113
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000114#define SEND_NOTIFICATION(descr,code) \
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000115 (SendMessageW( (descr)->owner, WM_COMMAND, \
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000116 MAKEWPARAM( GetWindowLongPtrW((descr->self),GWLP_ID), (code)), (LPARAM)(descr->self) ))
Alexandre Julliardfa68b751995-04-03 16:55:37 +0000117
Gerard Patelc9a6d501999-07-25 13:03:17 +0000118#define ISWIN31 (LOWORD(GetVersion()) == 0x0a03)
119
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000120/* Current timer status */
121typedef enum
Alexandre Julliardfa68b751995-04-03 16:55:37 +0000122{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000123 LB_TIMER_NONE,
124 LB_TIMER_UP,
125 LB_TIMER_LEFT,
126 LB_TIMER_DOWN,
127 LB_TIMER_RIGHT
128} TIMER_DIRECTION;
Alexandre Julliardfa68b751995-04-03 16:55:37 +0000129
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000130static TIMER_DIRECTION LISTBOX_Timer = LB_TIMER_NONE;
131
Alexandre Julliard91222da2000-12-10 23:01:33 +0000132static LRESULT WINAPI ListBoxWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000133static LRESULT WINAPI ListBoxWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
Alexandre Julliard91222da2000-12-10 23:01:33 +0000134
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000135static LRESULT LISTBOX_GetItemRect( LB_DESCR *descr, INT index, RECT *rect );
Alexandre Julliard91222da2000-12-10 23:01:33 +0000136
137/*********************************************************************
138 * listbox class descriptor
139 */
140const struct builtin_class_descr LISTBOX_builtin_class =
141{
142 "ListBox", /* name */
Alexandre Julliardb0622102003-12-10 04:14:35 +0000143 CS_DBLCLKS /*| CS_PARENTDC*/, /* style */
Alexandre Julliard91222da2000-12-10 23:01:33 +0000144 ListBoxWndProcA, /* procA */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000145 ListBoxWndProcW, /* procW */
Alexandre Julliard91222da2000-12-10 23:01:33 +0000146 sizeof(LB_DESCR *), /* extra */
Alexandre Julliardcf526442003-09-10 03:56:47 +0000147 IDC_ARROW, /* cursor */
Alexandre Julliard91222da2000-12-10 23:01:33 +0000148 0 /* brush */
149};
150
151
152/*********************************************************************
153 * combolbox class descriptor
154 */
155const struct builtin_class_descr COMBOLBOX_builtin_class =
156{
157 "ComboLBox", /* name */
Alexandre Julliardb0622102003-12-10 04:14:35 +0000158 CS_DBLCLKS | CS_SAVEBITS, /* style */
Dimitrie O. Paun134560e2004-10-18 21:22:44 +0000159 ListBoxWndProcA, /* procA */
160 ListBoxWndProcW, /* procW */
Alexandre Julliard91222da2000-12-10 23:01:33 +0000161 sizeof(LB_DESCR *), /* extra */
Alexandre Julliardcf526442003-09-10 03:56:47 +0000162 IDC_ARROW, /* cursor */
Alexandre Julliard91222da2000-12-10 23:01:33 +0000163 0 /* brush */
164};
165
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000166
Alexandre Julliardde424282001-08-10 22:51:42 +0000167/* check whether app is a Win 3.1 app */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000168inline static BOOL is_old_app( LB_DESCR *descr )
Alexandre Julliardde424282001-08-10 22:51:42 +0000169{
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000170 return (GetExpWinVer16( GetWindowLongPtrW(descr->self, GWLP_HINSTANCE) ) & 0xFF00 ) == 0x0300;
Alexandre Julliardde424282001-08-10 22:51:42 +0000171}
172
173
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000174/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000175 * LISTBOX_GetCurrentPageSize
176 *
177 * Return the current page size
178 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000179static INT LISTBOX_GetCurrentPageSize( LB_DESCR *descr )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000180{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000181 INT i, height;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000182 if (!(descr->style & LBS_OWNERDRAWVARIABLE)) return descr->page_size;
183 for (i = descr->top_item, height = 0; i < descr->nb_items; i++)
184 {
185 if ((height += descr->items[i].height) > descr->height) break;
186 }
187 if (i == descr->top_item) return 1;
188 else return i - descr->top_item;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000189}
190
191
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000192/***********************************************************************
193 * LISTBOX_GetMaxTopIndex
194 *
195 * Return the maximum possible index for the top of the listbox.
196 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000197static INT LISTBOX_GetMaxTopIndex( LB_DESCR *descr )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000198{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000199 INT max, page;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000200
201 if (descr->style & LBS_OWNERDRAWVARIABLE)
202 {
203 page = descr->height;
204 for (max = descr->nb_items - 1; max >= 0; max--)
205 if ((page -= descr->items[max].height) < 0) break;
206 if (max < descr->nb_items - 1) max++;
207 }
208 else if (descr->style & LBS_MULTICOLUMN)
209 {
210 if ((page = descr->width / descr->column_width) < 1) page = 1;
211 max = (descr->nb_items + descr->page_size - 1) / descr->page_size;
212 max = (max - page) * descr->page_size;
213 }
214 else
215 {
216 max = descr->nb_items - descr->page_size;
217 }
218 if (max < 0) max = 0;
219 return max;
220}
221
222
223/***********************************************************************
224 * LISTBOX_UpdateScroll
225 *
226 * Update the scrollbars. Should be called whenever the content
227 * of the listbox changes.
228 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000229static void LISTBOX_UpdateScroll( LB_DESCR *descr )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000230{
231 SCROLLINFO info;
232
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000233 /* Check the listbox scroll bar flags individually before we call
234 SetScrollInfo otherwise when the listbox style is WS_HSCROLL and
235 no WS_VSCROLL, we end up with an uninitialized, visible horizontal
236 scroll bar when we do not need one.
237 if (!(descr->style & WS_VSCROLL)) return;
Alexandre Julliardde424282001-08-10 22:51:42 +0000238 */
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000239
Vincent Béron9a624912002-05-31 23:06:46 +0000240 /* It is important that we check descr->style, and not wnd->dwStyle,
241 for WS_VSCROLL, as the former is exactly the one passed in
242 argument to CreateWindow.
243 In Windows (and from now on in Wine :) a listbox created
244 with such a style (no WS_SCROLL) does not update
245 the scrollbar with listbox-related data, thus letting
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000246 the programmer use it for his/her own purposes. */
247
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000248 if (descr->style & LBS_NOREDRAW) return;
249 info.cbSize = sizeof(info);
250
251 if (descr->style & LBS_MULTICOLUMN)
252 {
253 info.nMin = 0;
254 info.nMax = (descr->nb_items - 1) / descr->page_size;
255 info.nPos = descr->top_item / descr->page_size;
256 info.nPage = descr->width / descr->column_width;
257 if (info.nPage < 1) info.nPage = 1;
258 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
259 if (descr->style & LBS_DISABLENOSCROLL)
260 info.fMask |= SIF_DISABLENOSCROLL;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000261 if (descr->style & WS_HSCROLL)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000262 SetScrollInfo( descr->self, SB_HORZ, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000263 info.nMax = 0;
264 info.fMask = SIF_RANGE;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000265 if (descr->style & WS_VSCROLL)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000266 SetScrollInfo( descr->self, SB_VERT, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000267 }
268 else
269 {
270 info.nMin = 0;
271 info.nMax = descr->nb_items - 1;
272 info.nPos = descr->top_item;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000273 info.nPage = LISTBOX_GetCurrentPageSize( descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000274 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
275 if (descr->style & LBS_DISABLENOSCROLL)
276 info.fMask |= SIF_DISABLENOSCROLL;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000277 if (descr->style & WS_VSCROLL)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000278 SetScrollInfo( descr->self, SB_VERT, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000279
280 if (descr->horz_extent)
281 {
282 info.nMin = 0;
283 info.nMax = descr->horz_extent - 1;
284 info.nPos = descr->horz_pos;
285 info.nPage = descr->width;
286 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
287 if (descr->style & LBS_DISABLENOSCROLL)
288 info.fMask |= SIF_DISABLENOSCROLL;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000289 if (descr->style & WS_HSCROLL)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000290 SetScrollInfo( descr->self, SB_HORZ, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000291 }
292 }
293}
294
295
296/***********************************************************************
297 * LISTBOX_SetTopItem
298 *
299 * Set the top item of the listbox, scrolling up or down if necessary.
300 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000301static LRESULT LISTBOX_SetTopItem( LB_DESCR *descr, INT index, BOOL scroll )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000302{
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000303 INT max = LISTBOX_GetMaxTopIndex( descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000304 if (index > max) index = max;
305 if (index < 0) index = 0;
306 if (descr->style & LBS_MULTICOLUMN) index -= index % descr->page_size;
307 if (descr->top_item == index) return LB_OKAY;
308 if (descr->style & LBS_MULTICOLUMN)
309 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000310 INT diff = (descr->top_item - index) / descr->page_size * descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000311 if (scroll && (abs(diff) < descr->width))
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000312 ScrollWindowEx( descr->self, diff, 0, NULL, NULL, 0, NULL,
NF Stevens762f18d1999-01-24 19:02:16 +0000313 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
314
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000315 else
316 scroll = FALSE;
317 }
318 else if (scroll)
319 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000320 INT diff;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000321 if (descr->style & LBS_OWNERDRAWVARIABLE)
322 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000323 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000324 diff = 0;
325 if (index > descr->top_item)
326 {
327 for (i = index - 1; i >= descr->top_item; i--)
328 diff -= descr->items[i].height;
329 }
330 else
331 {
332 for (i = index; i < descr->top_item; i++)
333 diff += descr->items[i].height;
334 }
335 }
Alexandre Julliardde424282001-08-10 22:51:42 +0000336 else
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000337 diff = (descr->top_item - index) * descr->item_height;
338
339 if (abs(diff) < descr->height)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000340 ScrollWindowEx( descr->self, 0, diff, NULL, NULL, 0, NULL,
341 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000342 else
343 scroll = FALSE;
344 }
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000345 if (!scroll) InvalidateRect( descr->self, NULL, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000346 descr->top_item = index;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000347 LISTBOX_UpdateScroll( descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000348 return LB_OKAY;
349}
350
351
352/***********************************************************************
353 * LISTBOX_UpdatePage
354 *
355 * Update the page size. Should be called when the size of
356 * the client area or the item height changes.
357 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000358static void LISTBOX_UpdatePage( LB_DESCR *descr )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000359{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000360 INT page_size;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000361
Alexandre Julliardde424282001-08-10 22:51:42 +0000362 if ((descr->item_height == 0) || (page_size = descr->height / descr->item_height) < 1)
Paul Quinn75722071999-05-22 18:45:06 +0000363 page_size = 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000364 if (page_size == descr->page_size) return;
365 descr->page_size = page_size;
366 if (descr->style & LBS_MULTICOLUMN)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000367 InvalidateRect( descr->self, NULL, TRUE );
368 LISTBOX_SetTopItem( descr, descr->top_item, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000369}
370
371
372/***********************************************************************
373 * LISTBOX_UpdateSize
374 *
375 * Update the size of the listbox. Should be called when the size of
376 * the client area changes.
377 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000378static void LISTBOX_UpdateSize( LB_DESCR *descr )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000379{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000380 RECT rect;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000381
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000382 GetClientRect( descr->self, &rect );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000383 descr->width = rect.right - rect.left;
384 descr->height = rect.bottom - rect.top;
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +0000385 if (!(descr->style & LBS_NOINTEGRALHEIGHT) && !(descr->style & LBS_OWNERDRAWVARIABLE))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000386 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000387 INT remaining;
Alexandre Julliardde424282001-08-10 22:51:42 +0000388 RECT rect;
Mike McCormack5ae1c392000-09-09 19:39:24 +0000389
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000390 GetWindowRect( descr->self, &rect );
Mike McCormack5ae1c392000-09-09 19:39:24 +0000391 if(descr->item_height != 0)
392 remaining = descr->height % descr->item_height;
393 else
394 remaining = 0;
Gerard Patelcef12532000-08-01 20:48:40 +0000395 if ((descr->height > descr->item_height) && remaining)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000396 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000397 if (is_old_app(descr))
Gerard Patelcef12532000-08-01 20:48:40 +0000398 { /* give a margin for error to 16 bits programs - if we need
399 less than the height of the nonclient area, round to the
Alexandre Julliardde424282001-08-10 22:51:42 +0000400 *next* number of items */
401 int ncheight = rect.bottom - rect.top - descr->height;
Gerard Patelcef12532000-08-01 20:48:40 +0000402 if ((descr->item_height - remaining) <= ncheight)
403 remaining = remaining - descr->item_height;
404 }
Alexandre Julliardaff7dda2002-11-22 21:22:14 +0000405 TRACE("[%p]: changing height %d -> %d\n",
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000406 descr->self, descr->height, descr->height - remaining );
407 SetWindowPos( descr->self, 0, 0, 0, rect.right - rect.left,
408 rect.bottom - rect.top - remaining,
409 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000410 return;
411 }
412 }
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000413 TRACE("[%p]: new size = %d,%d\n", descr->self, descr->width, descr->height );
414 LISTBOX_UpdatePage( descr );
415 LISTBOX_UpdateScroll( descr );
Louis Philippe Gagnon956c8472000-12-13 21:26:45 +0000416
417 /* Invalidate the focused item so it will be repainted correctly */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000418 if (LISTBOX_GetItemRect( descr, descr->focus_item, &rect ) == 1)
Louis Philippe Gagnon956c8472000-12-13 21:26:45 +0000419 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000420 InvalidateRect( descr->self, &rect, FALSE );
Louis Philippe Gagnon956c8472000-12-13 21:26:45 +0000421 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000422}
423
424
425/***********************************************************************
426 * LISTBOX_GetItemRect
427 *
428 * Get the rectangle enclosing an item, in listbox client coordinates.
429 * Return 1 if the rectangle is (partially) visible, 0 if hidden, -1 on error.
430 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000431static LRESULT LISTBOX_GetItemRect( LB_DESCR *descr, INT index, RECT *rect )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000432{
433 /* Index <= 0 is legal even on empty listboxes */
Robert Shearman30ff9402005-07-12 18:11:40 +0000434 if (index && (index >= descr->nb_items))
435 {
436 memset(rect, 0, sizeof(*rect));
437 SetLastError(ERROR_INVALID_INDEX);
438 return LB_ERR;
439 }
Alexandre Julliarda3960291999-02-26 11:11:13 +0000440 SetRect( rect, 0, 0, descr->width, descr->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000441 if (descr->style & LBS_MULTICOLUMN)
442 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000443 INT col = (index / descr->page_size) -
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000444 (descr->top_item / descr->page_size);
445 rect->left += col * descr->column_width;
446 rect->right = rect->left + descr->column_width;
447 rect->top += (index % descr->page_size) * descr->item_height;
448 rect->bottom = rect->top + descr->item_height;
449 }
450 else if (descr->style & LBS_OWNERDRAWVARIABLE)
451 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000452 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000453 rect->right += descr->horz_pos;
Alexandre Julliard349a9531997-02-02 19:01:52 +0000454 if ((index >= 0) && (index < descr->nb_items))
455 {
456 if (index < descr->top_item)
457 {
458 for (i = descr->top_item-1; i >= index; i--)
459 rect->top -= descr->items[i].height;
460 }
461 else
462 {
463 for (i = descr->top_item; i < index; i++)
464 rect->top += descr->items[i].height;
465 }
466 rect->bottom = rect->top + descr->items[index].height;
467
468 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000469 }
470 else
471 {
472 rect->top += (index - descr->top_item) * descr->item_height;
473 rect->bottom = rect->top + descr->item_height;
474 rect->right += descr->horz_pos;
475 }
476
477 return ((rect->left < descr->width) && (rect->right > 0) &&
478 (rect->top < descr->height) && (rect->bottom > 0));
479}
480
481
482/***********************************************************************
483 * LISTBOX_GetItemFromPoint
484 *
485 * Return the item nearest from point (x,y) (in client coordinates).
486 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000487static INT LISTBOX_GetItemFromPoint( LB_DESCR *descr, INT x, INT y )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000488{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000489 INT index = descr->top_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000490
491 if (!descr->nb_items) return -1; /* No items */
492 if (descr->style & LBS_OWNERDRAWVARIABLE)
493 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000494 INT pos = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000495 if (y >= 0)
496 {
497 while (index < descr->nb_items)
498 {
499 if ((pos += descr->items[index].height) > y) break;
500 index++;
501 }
502 }
503 else
504 {
505 while (index > 0)
506 {
507 index--;
508 if ((pos -= descr->items[index].height) <= y) break;
509 }
510 }
511 }
512 else if (descr->style & LBS_MULTICOLUMN)
513 {
514 if (y >= descr->item_height * descr->page_size) return -1;
515 if (y >= 0) index += y / descr->item_height;
516 if (x >= 0) index += (x / descr->column_width) * descr->page_size;
517 else index -= (((x + 1) / descr->column_width) - 1) * descr->page_size;
518 }
519 else
520 {
521 index += (y / descr->item_height);
522 }
523 if (index < 0) return 0;
524 if (index >= descr->nb_items) return -1;
525 return index;
526}
527
528
529/***********************************************************************
530 * LISTBOX_PaintItem
531 *
532 * Paint an item.
533 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000534static void LISTBOX_PaintItem( LB_DESCR *descr, HDC hdc, const RECT *rect,
535 INT index, UINT action, BOOL ignoreFocus )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000536{
537 LB_ITEMDATA *item = NULL;
538 if (index < descr->nb_items) item = &descr->items[index];
539
540 if (IS_OWNERDRAW(descr))
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000541 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000542 DRAWITEMSTRUCT dis;
Gerard Patel9788ba62000-07-16 15:39:37 +0000543 RECT r;
544 HRGN hrgn;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000545
Marcus Meissner9ad90171999-01-20 14:08:00 +0000546 if (!item)
547 {
Alexandre Julliardde424282001-08-10 22:51:42 +0000548 if (action == ODA_FOCUS)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000549 DrawFocusRect( hdc, rect );
Marcus Meissner9ad90171999-01-20 14:08:00 +0000550 else
Dimitrie O. Paund0c950c2004-10-11 19:51:16 +0000551 ERR("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 +0000552 return;
553 }
Gerard Patel9788ba62000-07-16 15:39:37 +0000554
555 /* some programs mess with the clipping region when
556 drawing the item, *and* restore the previous region
557 after they are done, so a region has better to exist
558 else everything ends clipped */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000559 GetClientRect(descr->self, &r);
Gerard Patel9788ba62000-07-16 15:39:37 +0000560 hrgn = CreateRectRgnIndirect(&r);
561 SelectClipRgn( hdc, hrgn);
562 DeleteObject( hrgn );
563
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000564 dis.CtlType = ODT_LISTBOX;
Dmitry Timoshkovc2fe2f02005-07-29 14:42:19 +0000565 dis.CtlID = GetWindowLongPtrW( descr->self, GWLP_ID );
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000566 dis.hwndItem = descr->self;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000567 dis.itemAction = action;
568 dis.hDC = hdc;
569 dis.itemID = index;
570 dis.itemState = 0;
571 if (item && item->selected) dis.itemState |= ODS_SELECTED;
Gerard Patel8caa4072000-09-24 19:29:18 +0000572 if (!ignoreFocus && (descr->focus_item == index) &&
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000573 (descr->caret_on) &&
Alexandre Julliardab2f43f2000-05-26 22:28:34 +0000574 (descr->in_focus)) dis.itemState |= ODS_FOCUS;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000575 if (!IsWindowEnabled(descr->self)) dis.itemState |= ODS_DISABLED;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000576 dis.itemData = item ? item->data : 0;
577 dis.rcItem = *rect;
Dan Kegel0fd521f2003-01-08 21:09:25 +0000578 TRACE("[%p]: drawitem %d (%s) action=%02x state=%02x rect=%ld,%ld-%ld,%ld\n",
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000579 descr->self, index, item ? debugstr_w(item->str) : "", action,
Alexandre Julliardde424282001-08-10 22:51:42 +0000580 dis.itemState, rect->left, rect->top, rect->right, rect->bottom );
Francois Gougetae7a6462005-08-08 11:02:54 +0000581 SendMessageW(descr->owner, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis);
Alexandre Julliard2787be81995-05-22 18:23:01 +0000582 }
583 else
Alexandre Julliardac9c9b01996-07-28 18:50:11 +0000584 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000585 COLORREF oldText = 0, oldBk = 0;
586
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000587 if (action == ODA_FOCUS)
588 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000589 DrawFocusRect( hdc, rect );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000590 return;
591 }
592 if (item && item->selected)
593 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000594 oldBk = SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
595 oldText = SetTextColor( hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000596 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000597
Dan Kegel0fd521f2003-01-08 21:09:25 +0000598 TRACE("[%p]: painting %d (%s) action=%02x rect=%ld,%ld-%ld,%ld\n",
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000599 descr->self, index, item ? debugstr_w(item->str) : "", action,
Alexandre Julliardde424282001-08-10 22:51:42 +0000600 rect->left, rect->top, rect->right, rect->bottom );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000601 if (!item)
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000602 ExtTextOutW( hdc, rect->left + 1, rect->top,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000603 ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000604 else if (!(descr->style & LBS_USETABSTOPS))
605 ExtTextOutW( hdc, rect->left + 1, rect->top,
606 ETO_OPAQUE | ETO_CLIPPED, rect, item->str,
607 strlenW(item->str), NULL );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000608 else
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000609 {
610 /* Output empty string to paint background in the full width. */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000611 ExtTextOutW( hdc, rect->left + 1, rect->top,
612 ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
613 TabbedTextOutW( hdc, rect->left + 1 , rect->top,
614 item->str, strlenW(item->str),
615 descr->nb_tabs, descr->tabs, 0);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000616 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000617 if (item && item->selected)
618 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000619 SetBkColor( hdc, oldBk );
620 SetTextColor( hdc, oldText );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000621 }
Gerard Patel8caa4072000-09-24 19:29:18 +0000622 if (!ignoreFocus && (descr->focus_item == index) &&
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000623 (descr->caret_on) &&
Alexandre Julliardab2f43f2000-05-26 22:28:34 +0000624 (descr->in_focus)) DrawFocusRect( hdc, rect );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000625 }
Alexandre Julliard2787be81995-05-22 18:23:01 +0000626}
627
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000628
629/***********************************************************************
630 * LISTBOX_SetRedraw
631 *
632 * Change the redraw flag.
633 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000634static void LISTBOX_SetRedraw( LB_DESCR *descr, BOOL on )
Alexandre Julliardac9c9b01996-07-28 18:50:11 +0000635{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000636 if (on)
637 {
638 if (!(descr->style & LBS_NOREDRAW)) return;
639 descr->style &= ~LBS_NOREDRAW;
Gerard Patel41b07fb2000-06-15 00:07:20 +0000640 if (descr->style & LBS_DISPLAYCHANGED)
641 { /* page was changed while setredraw false, refresh automatically */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000642 InvalidateRect(descr->self, NULL, TRUE);
Gerard Patel41b07fb2000-06-15 00:07:20 +0000643 if ((descr->top_item + descr->page_size) > descr->nb_items)
Alexandre Julliardde424282001-08-10 22:51:42 +0000644 { /* reset top of page if less than number of items/page */
Gerard Patel41b07fb2000-06-15 00:07:20 +0000645 descr->top_item = descr->nb_items - descr->page_size;
646 if (descr->top_item < 0) descr->top_item = 0;
647 }
648 descr->style &= ~LBS_DISPLAYCHANGED;
649 }
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000650 LISTBOX_UpdateScroll( descr );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000651 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000652 else descr->style |= LBS_NOREDRAW;
653}
Alexandre Julliard2787be81995-05-22 18:23:01 +0000654
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000655
656/***********************************************************************
657 * LISTBOX_RepaintItem
658 *
659 * Repaint a single item synchronously.
660 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000661static void LISTBOX_RepaintItem( LB_DESCR *descr, INT index, UINT action )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000662{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000663 HDC hdc;
664 RECT rect;
665 HFONT oldFont = 0;
666 HBRUSH hbrush, oldBrush = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000667
Francois Boisvert428d2981999-05-08 09:33:53 +0000668 /* Do not repaint the item if the item is not visible */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000669 if (!IsWindowVisible(descr->self)) return;
Gerard Patel41b07fb2000-06-15 00:07:20 +0000670 if (descr->style & LBS_NOREDRAW)
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000671 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000672 descr->style |= LBS_DISPLAYCHANGED;
673 return;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000674 }
675 if (LISTBOX_GetItemRect( descr, index, &rect ) != 1) return;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000676 if (!(hdc = GetDCEx( descr->self, 0, DCX_CACHE ))) return;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000677 if (descr->font) oldFont = SelectObject( hdc, descr->font );
Michael Stefaniuc95591a62002-10-28 20:11:40 +0000678 hbrush = (HBRUSH)SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000679 (WPARAM)hdc, (LPARAM)descr->self );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000680 if (hbrush) oldBrush = SelectObject( hdc, hbrush );
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000681 if (!IsWindowEnabled(descr->self))
Alexandre Julliarda3960291999-02-26 11:11:13 +0000682 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
683 SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000684 LISTBOX_PaintItem( descr, hdc, &rect, index, action, FALSE );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000685 if (oldFont) SelectObject( hdc, oldFont );
686 if (oldBrush) SelectObject( hdc, oldBrush );
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000687 ReleaseDC( descr->self, hdc );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000688}
689
690
691/***********************************************************************
692 * LISTBOX_InitStorage
693 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000694static LRESULT LISTBOX_InitStorage( LB_DESCR *descr, INT nb_items )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000695{
696 LB_ITEMDATA *item;
697
698 nb_items += LB_ARRAY_GRANULARITY - 1;
699 nb_items -= (nb_items % LB_ARRAY_GRANULARITY);
Oleg Prokhorovde12a972003-10-14 05:24:20 +0000700 if (descr->items) {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000701 nb_items += HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(*item);
Oleg Prokhorovde12a972003-10-14 05:24:20 +0000702 item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
703 nb_items * sizeof(LB_ITEMDATA));
704 }
705 else {
706 item = HeapAlloc( GetProcessHeap(), 0,
707 nb_items * sizeof(LB_ITEMDATA));
708 }
709
710 if (!item)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000711 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000712 SEND_NOTIFICATION( descr, LBN_ERRSPACE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000713 return LB_ERRSPACE;
714 }
715 descr->items = item;
716 return LB_OKAY;
717}
718
719
720/***********************************************************************
721 * LISTBOX_SetTabStops
722 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000723static BOOL LISTBOX_SetTabStops( LB_DESCR *descr, INT count, LPINT tabs, BOOL short_ints )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000724{
Robert Shearman630c6ea2005-07-11 14:22:36 +0000725 INT i;
726
Robert Shearman7dd1d212005-07-12 17:55:35 +0000727 if (!(descr->style & LBS_USETABSTOPS))
728 {
729 SetLastError(ERROR_LB_WITHOUT_TABSTOPS);
730 return FALSE;
731 }
732
Michael Stefaniuc5ad7d852004-12-23 17:06:43 +0000733 HeapFree( GetProcessHeap(), 0, descr->tabs );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000734 if (!(descr->nb_tabs = count))
735 {
736 descr->tabs = NULL;
737 return TRUE;
738 }
Jakob Eriksson9ed61de2005-03-24 21:01:35 +0000739 if (!(descr->tabs = HeapAlloc( GetProcessHeap(), 0,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000740 descr->nb_tabs * sizeof(INT) )))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000741 return FALSE;
742 if (short_ints)
743 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000744 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000745 LPINT16 p = (LPINT16)tabs;
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000746
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000747 TRACE("[%p]: settabstops ", descr->self );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000748 for (i = 0; i < descr->nb_tabs; i++) {
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000749 descr->tabs[i] = *p++<<1; /* FIXME */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000750 TRACE("%hd ", descr->tabs[i]);
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000751 }
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000752 TRACE("\n");
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000753 }
Alexandre Julliarda3960291999-02-26 11:11:13 +0000754 else memcpy( descr->tabs, tabs, descr->nb_tabs * sizeof(INT) );
Robert Shearman630c6ea2005-07-11 14:22:36 +0000755
756 /* convert into "dialog units"*/
757 for (i = 0; i < descr->nb_tabs; i++)
758 descr->tabs[i] = MulDiv(descr->tabs[i], descr->avg_char_width, 4);
759
Alexandre Julliard2787be81995-05-22 18:23:01 +0000760 return TRUE;
761}
762
763
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000764/***********************************************************************
765 * LISTBOX_GetText
766 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000767static LRESULT LISTBOX_GetText( LB_DESCR *descr, INT index, LPWSTR buffer, BOOL unicode )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000768{
Robert Shearman30ff9402005-07-12 18:11:40 +0000769 if ((index < 0) || (index >= descr->nb_items))
770 {
771 SetLastError(ERROR_INVALID_INDEX);
772 return LB_ERR;
773 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000774 if (HAS_STRINGS(descr))
775 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000776 if (!buffer)
Mike McCormackfea1a842004-08-26 18:11:06 +0000777 {
778 DWORD len = strlenW(descr->items[index].str);
779 if( unicode )
780 return len;
781 return WideCharToMultiByte( CP_ACP, 0, descr->items[index].str, len,
782 NULL, 0, NULL, NULL );
783 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000784
Dmitry Timoshkove8ffcaa2001-04-16 19:32:19 +0000785 TRACE("index %d (0x%04x) %s\n", index, index, debugstr_w(descr->items[index].str));
786
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000787 if(unicode)
788 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000789 strcpyW( buffer, descr->items[index].str );
790 return strlenW(buffer);
791 }
792 else
793 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000794 return WideCharToMultiByte(CP_ACP, 0, descr->items[index].str, -1, (LPSTR)buffer, 0x7FFFFFFF, NULL, NULL) - 1;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000795 }
Marcus Meissner4f7dc461998-11-22 15:43:34 +0000796 } else {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000797 if (buffer)
798 *((LPDWORD)buffer)=*(LPDWORD)(&descr->items[index].data);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000799 return sizeof(DWORD);
800 }
Alexandre Julliard2787be81995-05-22 18:23:01 +0000801}
802
Robert Shearman7dd1d212005-07-12 17:55:35 +0000803static inline INT LISTBOX_lstrcmpiW( LCID lcid, LPCWSTR str1, LPCWSTR str2 )
804{
805 INT ret = CompareStringW( lcid, NORM_IGNORECASE, str1, -1, str2, -1 );
806 if (ret == CSTR_LESS_THAN)
807 return -1;
808 if (ret == CSTR_EQUAL)
809 return 0;
810 if (ret == CSTR_GREATER_THAN)
811 return 1;
812 return -1;
813}
Alexandre Julliard2787be81995-05-22 18:23:01 +0000814
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000815/***********************************************************************
816 * LISTBOX_FindStringPos
817 *
818 * Find the nearest string located before a given string in sort order.
819 * If 'exact' is TRUE, return an error if we don't get an exact match.
820 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000821static INT LISTBOX_FindStringPos( LB_DESCR *descr, LPCWSTR str, BOOL exact )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000822{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000823 INT index, min, max, res = -1;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000824
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000825 if (!(descr->style & LBS_SORT)) return -1; /* Add it at the end */
826 min = 0;
827 max = descr->nb_items;
828 while (min != max)
829 {
830 index = (min + max) / 2;
831 if (HAS_STRINGS(descr))
Robert Shearman7dd1d212005-07-12 17:55:35 +0000832 res = LISTBOX_lstrcmpiW( descr->locale, str, descr->items[index].str);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000833 else
834 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000835 COMPAREITEMSTRUCT cis;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000836 UINT id = (UINT)GetWindowLongPtrW( descr->self, GWLP_ID );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000837
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000838 cis.CtlType = ODT_LISTBOX;
Alexandre Julliardde424282001-08-10 22:51:42 +0000839 cis.CtlID = id;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000840 cis.hwndItem = descr->self;
Rein Klazes26b2e892003-04-08 19:41:52 +0000841 /* note that some application (MetaStock) expects the second item
842 * to be in the listbox */
843 cis.itemID1 = -1;
Alexandre Julliard2c1b3c62005-09-12 11:24:23 +0000844 cis.itemData1 = (ULONG_PTR)str;
Rein Klazes26b2e892003-04-08 19:41:52 +0000845 cis.itemID2 = index;
846 cis.itemData2 = descr->items[index].data;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000847 cis.dwLocaleId = descr->locale;
Alexandre Julliardde424282001-08-10 22:51:42 +0000848 res = SendMessageW( descr->owner, WM_COMPAREITEM, id, (LPARAM)&cis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000849 }
850 if (!res) return index;
Rein Klazes26b2e892003-04-08 19:41:52 +0000851 if (res < 0) max = index;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000852 else min = index + 1;
853 }
854 return exact ? -1 : max;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000855}
856
857
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000858/***********************************************************************
859 * LISTBOX_FindFileStrPos
860 *
861 * Find the nearest string located before a given string in directory
862 * sort order (i.e. first files, then directories, then drives).
863 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000864static INT LISTBOX_FindFileStrPos( LB_DESCR *descr, LPCWSTR str )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000865{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000866 INT min, max, res = -1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000867
868 if (!HAS_STRINGS(descr))
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000869 return LISTBOX_FindStringPos( descr, str, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000870 min = 0;
871 max = descr->nb_items;
872 while (min != max)
873 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000874 INT index = (min + max) / 2;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000875 LPCWSTR p = descr->items[index].str;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000876 if (*p == '[') /* drive or directory */
877 {
878 if (*str != '[') res = -1;
879 else if (p[1] == '-') /* drive */
880 {
881 if (str[1] == '-') res = str[2] - p[2];
882 else res = -1;
883 }
884 else /* directory */
885 {
886 if (str[1] == '-') res = 1;
Robert Shearman7dd1d212005-07-12 17:55:35 +0000887 else res = LISTBOX_lstrcmpiW( descr->locale, str, p );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000888 }
889 }
890 else /* filename */
891 {
892 if (*str == '[') res = 1;
Robert Shearman7dd1d212005-07-12 17:55:35 +0000893 else res = LISTBOX_lstrcmpiW( descr->locale, str, p );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000894 }
895 if (!res) return index;
896 if (res < 0) max = index;
897 else min = index + 1;
898 }
899 return max;
900}
901
902
903/***********************************************************************
904 * LISTBOX_FindString
905 *
906 * Find the item beginning with a given string.
907 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000908static INT LISTBOX_FindString( LB_DESCR *descr, INT start, LPCWSTR str, BOOL exact )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000909{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000910 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000911 LB_ITEMDATA *item;
912
913 if (start >= descr->nb_items) start = -1;
914 item = descr->items + start + 1;
915 if (HAS_STRINGS(descr))
916 {
Rein Klazesd35c8341999-08-21 13:04:58 +0000917 if (!str || ! str[0] ) return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000918 if (exact)
919 {
920 for (i = start + 1; i < descr->nb_items; i++, item++)
Robert Shearman7dd1d212005-07-12 17:55:35 +0000921 if (!LISTBOX_lstrcmpiW( descr->locale, str, item->str )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000922 for (i = 0, item = descr->items; i <= start; i++, item++)
Robert Shearman7dd1d212005-07-12 17:55:35 +0000923 if (!LISTBOX_lstrcmpiW( descr->locale, str, item->str )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000924 }
925 else
926 {
927 /* Special case for drives and directories: ignore prefix */
928#define CHECK_DRIVE(item) \
929 if ((item)->str[0] == '[') \
930 { \
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000931 if (!strncmpiW( str, (item)->str+1, len )) return i; \
932 if (((item)->str[1] == '-') && !strncmpiW(str, (item)->str+2, len)) \
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000933 return i; \
934 }
935
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000936 INT len = strlenW(str);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000937 for (i = start + 1; i < descr->nb_items; i++, item++)
938 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000939 if (!strncmpiW( str, item->str, len )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000940 CHECK_DRIVE(item);
941 }
942 for (i = 0, item = descr->items; i <= start; i++, item++)
943 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000944 if (!strncmpiW( str, item->str, len )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000945 CHECK_DRIVE(item);
946 }
947#undef CHECK_DRIVE
948 }
949 }
950 else
951 {
952 if (exact && (descr->style & LBS_SORT))
953 /* If sorted, use a WM_COMPAREITEM binary search */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +0000954 return LISTBOX_FindStringPos( descr, str, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000955
956 /* Otherwise use a linear search */
957 for (i = start + 1; i < descr->nb_items; i++, item++)
Alexandre Julliard2c1b3c62005-09-12 11:24:23 +0000958 if (item->data == (ULONG_PTR)str) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000959 for (i = 0, item = descr->items; i <= start; i++, item++)
Alexandre Julliard2c1b3c62005-09-12 11:24:23 +0000960 if (item->data == (ULONG_PTR)str) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000961 }
962 return LB_ERR;
963}
964
965
966/***********************************************************************
967 * LISTBOX_GetSelCount
968 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000969static LRESULT LISTBOX_GetSelCount( LB_DESCR *descr )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000970{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000971 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000972 LB_ITEMDATA *item = descr->items;
973
Jon Griffiths7a9e8002004-10-05 22:31:00 +0000974 if (!(descr->style & LBS_MULTIPLESEL) ||
975 (descr->style & LBS_NOSEL))
976 return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000977 for (i = count = 0; i < descr->nb_items; i++, item++)
978 if (item->selected) count++;
979 return count;
980}
981
982
983/***********************************************************************
984 * LISTBOX_GetSelItems16
985 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000986static LRESULT LISTBOX_GetSelItems16( LB_DESCR *descr, INT16 max, LPINT16 array )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000987{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000988 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000989 LB_ITEMDATA *item = descr->items;
990
991 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
992 for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++)
993 if (item->selected) array[count++] = (INT16)i;
994 return count;
995}
996
997
998/***********************************************************************
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000999 * LISTBOX_GetSelItems
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001000 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001001static LRESULT LISTBOX_GetSelItems( LB_DESCR *descr, INT max, LPINT array )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001002{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001003 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001004 LB_ITEMDATA *item = descr->items;
1005
1006 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
1007 for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++)
1008 if (item->selected) array[count++] = i;
1009 return count;
1010}
1011
1012
1013/***********************************************************************
1014 * LISTBOX_Paint
1015 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001016static LRESULT LISTBOX_Paint( LB_DESCR *descr, HDC hdc )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001017{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001018 INT i, col_pos = descr->page_size - 1;
1019 RECT rect;
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001020 RECT focusRect = {-1, -1, -1, -1};
Alexandre Julliarda3960291999-02-26 11:11:13 +00001021 HFONT oldFont = 0;
1022 HBRUSH hbrush, oldBrush = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001023
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001024 if (descr->style & LBS_NOREDRAW) return 0;
Serge Ivanov07917e42000-06-07 03:46:57 +00001025
1026 SetRect( &rect, 0, 0, descr->width, descr->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001027 if (descr->style & LBS_MULTICOLUMN)
1028 rect.right = rect.left + descr->column_width;
1029 else if (descr->horz_pos)
1030 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001031 SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001032 rect.right += descr->horz_pos;
1033 }
1034
Alexandre Julliarda3960291999-02-26 11:11:13 +00001035 if (descr->font) oldFont = SelectObject( hdc, descr->font );
Michael Stefaniuc95591a62002-10-28 20:11:40 +00001036 hbrush = (HBRUSH)SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001037 (WPARAM)hdc, (LPARAM)descr->self );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001038 if (hbrush) oldBrush = SelectObject( hdc, hbrush );
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001039 if (!IsWindowEnabled(descr->self)) SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001040
1041 if (!descr->nb_items && (descr->focus_item != -1) && descr->caret_on &&
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00001042 (descr->in_focus))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001043 {
1044 /* Special case for empty listbox: paint focus rect */
1045 rect.bottom = rect.top + descr->item_height;
Jon Griffiths7a9e8002004-10-05 22:31:00 +00001046 ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
1047 &rect, NULL, 0, NULL );
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001048 LISTBOX_PaintItem( descr, hdc, &rect, descr->focus_item, ODA_FOCUS, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001049 rect.top = rect.bottom;
1050 }
1051
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001052 /* Paint all the item, regarding the selection
1053 Focus state will be painted after */
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001054
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001055 for (i = descr->top_item; i < descr->nb_items; i++)
1056 {
1057 if (!(descr->style & LBS_OWNERDRAWVARIABLE))
1058 rect.bottom = rect.top + descr->item_height;
1059 else
1060 rect.bottom = rect.top + descr->items[i].height;
1061
Gerard Patel8caa4072000-09-24 19:29:18 +00001062 if (i == descr->focus_item)
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001063 {
1064 /* keep the focus rect, to paint the focus item after */
1065 focusRect.left = rect.left;
1066 focusRect.right = rect.right;
1067 focusRect.top = rect.top;
1068 focusRect.bottom = rect.bottom;
1069 }
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001070 LISTBOX_PaintItem( descr, hdc, &rect, i, ODA_DRAWENTIRE, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001071 rect.top = rect.bottom;
1072
1073 if ((descr->style & LBS_MULTICOLUMN) && !col_pos)
1074 {
1075 if (!IS_OWNERDRAW(descr))
1076 {
1077 /* Clear the bottom of the column */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001078 if (rect.top < descr->height)
1079 {
1080 rect.bottom = descr->height;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001081 ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001082 &rect, NULL, 0, NULL );
1083 }
1084 }
1085
1086 /* Go to the next column */
1087 rect.left += descr->column_width;
1088 rect.right += descr->column_width;
1089 rect.top = 0;
1090 col_pos = descr->page_size - 1;
1091 }
1092 else
1093 {
1094 col_pos--;
1095 if (rect.top >= descr->height) break;
1096 }
1097 }
1098
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001099 /* Paint the focus item now */
Jon Griffiths7a9e8002004-10-05 22:31:00 +00001100 if (focusRect.top != focusRect.bottom &&
1101 descr->caret_on && descr->in_focus)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001102 LISTBOX_PaintItem( descr, hdc, &focusRect, descr->focus_item, ODA_FOCUS, FALSE );
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001103
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001104 if (!IS_OWNERDRAW(descr))
1105 {
1106 /* Clear the remainder of the client area */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001107 if (rect.top < descr->height)
1108 {
1109 rect.bottom = descr->height;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001110 ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001111 &rect, NULL, 0, NULL );
1112 }
1113 if (rect.right < descr->width)
1114 {
1115 rect.left = rect.right;
1116 rect.right = descr->width;
1117 rect.top = 0;
1118 rect.bottom = descr->height;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001119 ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001120 &rect, NULL, 0, NULL );
1121 }
1122 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001123 if (oldFont) SelectObject( hdc, oldFont );
1124 if (oldBrush) SelectObject( hdc, oldBrush );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001125 return 0;
1126}
1127
1128
1129/***********************************************************************
1130 * LISTBOX_InvalidateItems
1131 *
1132 * Invalidate all items from a given item. If the specified item is not
1133 * visible, nothing happens.
1134 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001135static void LISTBOX_InvalidateItems( LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001136{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001137 RECT rect;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001138
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001139 if (LISTBOX_GetItemRect( descr, index, &rect ) == 1)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001140 {
Gerard Patel41b07fb2000-06-15 00:07:20 +00001141 if (descr->style & LBS_NOREDRAW)
1142 {
1143 descr->style |= LBS_DISPLAYCHANGED;
1144 return;
1145 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001146 rect.bottom = descr->height;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001147 InvalidateRect( descr->self, &rect, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001148 if (descr->style & LBS_MULTICOLUMN)
1149 {
1150 /* Repaint the other columns */
1151 rect.left = rect.right;
1152 rect.right = descr->width;
1153 rect.top = 0;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001154 InvalidateRect( descr->self, &rect, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001155 }
1156 }
1157}
1158
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001159static void LISTBOX_InvalidateItemRect( LB_DESCR *descr, INT index )
Aric Stewarte8195352003-12-02 05:28:26 +00001160{
1161 RECT rect;
1162
1163 if (LISTBOX_GetItemRect( descr, index, &rect ) == 1)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001164 InvalidateRect( descr->self, &rect, TRUE );
Aric Stewarte8195352003-12-02 05:28:26 +00001165}
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001166
1167/***********************************************************************
1168 * LISTBOX_GetItemHeight
1169 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001170static LRESULT LISTBOX_GetItemHeight( LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001171{
1172 if (descr->style & LBS_OWNERDRAWVARIABLE)
1173 {
Robert Shearman30ff9402005-07-12 18:11:40 +00001174 if ((index < 0) || (index >= descr->nb_items))
1175 {
1176 SetLastError(ERROR_INVALID_INDEX);
1177 return LB_ERR;
1178 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001179 return descr->items[index].height;
1180 }
1181 else return descr->item_height;
1182}
1183
1184
1185/***********************************************************************
1186 * LISTBOX_SetItemHeight
1187 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001188static LRESULT LISTBOX_SetItemHeight( LB_DESCR *descr, INT index, INT height, BOOL repaint )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001189{
Mike McCormackabf3a572006-03-09 14:22:30 +09001190 if (height > MAXBYTE)
1191 return -1;
1192
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001193 if (!height) height = 1;
1194
1195 if (descr->style & LBS_OWNERDRAWVARIABLE)
1196 {
Robert Shearman30ff9402005-07-12 18:11:40 +00001197 if ((index < 0) || (index >= descr->nb_items))
1198 {
1199 SetLastError(ERROR_INVALID_INDEX);
1200 return LB_ERR;
1201 }
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001202 TRACE("[%p]: item %d height = %d\n", descr->self, index, height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001203 descr->items[index].height = height;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001204 LISTBOX_UpdateScroll( descr );
Alexandre Julliardc72a9aa2002-01-31 21:05:05 +00001205 if (repaint)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001206 LISTBOX_InvalidateItems( descr, index );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001207 }
1208 else if (height != descr->item_height)
1209 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001210 TRACE("[%p]: new height = %d\n", descr->self, height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001211 descr->item_height = height;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001212 LISTBOX_UpdatePage( descr );
1213 LISTBOX_UpdateScroll( descr );
Alexandre Julliardc72a9aa2002-01-31 21:05:05 +00001214 if (repaint)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001215 InvalidateRect( descr->self, 0, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001216 }
1217 return LB_OKAY;
1218}
1219
1220
1221/***********************************************************************
1222 * LISTBOX_SetHorizontalPos
1223 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001224static void LISTBOX_SetHorizontalPos( LB_DESCR *descr, INT pos )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001225{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001226 INT diff;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001227
1228 if (pos > descr->horz_extent - descr->width)
1229 pos = descr->horz_extent - descr->width;
1230 if (pos < 0) pos = 0;
1231 if (!(diff = descr->horz_pos - pos)) return;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001232 TRACE("[%p]: new horz pos = %d\n", descr->self, pos );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001233 descr->horz_pos = pos;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001234 LISTBOX_UpdateScroll( descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001235 if (abs(diff) < descr->width)
Huw Davies66c1acc2004-03-18 04:00:08 +00001236 {
1237 RECT rect;
1238 /* Invalidate the focused item so it will be repainted correctly */
1239 if (LISTBOX_GetItemRect( descr, descr->focus_item, &rect ) == 1)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001240 InvalidateRect( descr->self, &rect, TRUE );
1241 ScrollWindowEx( descr->self, diff, 0, NULL, NULL, 0, NULL,
NF Stevens762f18d1999-01-24 19:02:16 +00001242 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
Huw Davies66c1acc2004-03-18 04:00:08 +00001243 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001244 else
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001245 InvalidateRect( descr->self, NULL, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001246}
1247
1248
1249/***********************************************************************
1250 * LISTBOX_SetHorizontalExtent
1251 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001252static LRESULT LISTBOX_SetHorizontalExtent( LB_DESCR *descr, INT extent )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001253{
1254 if (!descr->horz_extent || (descr->style & LBS_MULTICOLUMN))
1255 return LB_OKAY;
1256 if (extent <= 0) extent = 1;
1257 if (extent == descr->horz_extent) return LB_OKAY;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001258 TRACE("[%p]: new horz extent = %d\n", descr->self, extent );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001259 descr->horz_extent = extent;
1260 if (descr->horz_pos > extent - descr->width)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001261 LISTBOX_SetHorizontalPos( descr, extent - descr->width );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001262 else
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001263 LISTBOX_UpdateScroll( descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001264 return LB_OKAY;
1265}
1266
1267
1268/***********************************************************************
1269 * LISTBOX_SetColumnWidth
1270 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001271static LRESULT LISTBOX_SetColumnWidth( LB_DESCR *descr, INT width)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001272{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001273 if (width == descr->column_width) return LB_OKAY;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001274 TRACE("[%p]: new column width = %d\n", descr->self, width );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001275 descr->column_width = width;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001276 LISTBOX_UpdatePage( descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001277 return LB_OKAY;
1278}
1279
1280
1281/***********************************************************************
1282 * LISTBOX_SetFont
1283 *
1284 * Returns the item height.
1285 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001286static INT LISTBOX_SetFont( LB_DESCR *descr, HFONT font )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001287{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001288 HDC hdc;
1289 HFONT oldFont = 0;
Robert Shearman630c6ea2005-07-11 14:22:36 +00001290 const char *alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
1291 SIZE sz;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001292
1293 descr->font = font;
1294
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001295 if (!(hdc = GetDCEx( descr->self, 0, DCX_CACHE )))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001296 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001297 ERR("unable to get DC.\n" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001298 return 16;
1299 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001300 if (font) oldFont = SelectObject( hdc, font );
Robert Shearman630c6ea2005-07-11 14:22:36 +00001301 GetTextExtentPointA( hdc, alphabet, 52, &sz);
Alexandre Julliarda3960291999-02-26 11:11:13 +00001302 if (oldFont) SelectObject( hdc, oldFont );
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001303 ReleaseDC( descr->self, hdc );
Robert Shearman630c6ea2005-07-11 14:22:36 +00001304
1305 descr->avg_char_width = (sz.cx / 26 + 1) / 2;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001306 if (!IS_OWNERDRAW(descr))
Robert Shearman630c6ea2005-07-11 14:22:36 +00001307 LISTBOX_SetItemHeight( descr, 0, sz.cy, FALSE );
1308 return sz.cy;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001309}
1310
1311
1312/***********************************************************************
1313 * LISTBOX_MakeItemVisible
1314 *
1315 * Make sure that a given item is partially or fully visible.
1316 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001317static void LISTBOX_MakeItemVisible( LB_DESCR *descr, INT index, BOOL fully )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001318{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001319 INT top;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001320
1321 if (index <= descr->top_item) top = index;
1322 else if (descr->style & LBS_MULTICOLUMN)
1323 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001324 INT cols = descr->width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001325 if (!fully) cols += descr->column_width - 1;
1326 if (cols >= descr->column_width) cols /= descr->column_width;
1327 else cols = 1;
1328 if (index < descr->top_item + (descr->page_size * cols)) return;
1329 top = index - descr->page_size * (cols - 1);
1330 }
1331 else if (descr->style & LBS_OWNERDRAWVARIABLE)
1332 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001333 INT height = fully ? descr->items[index].height : 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001334 for (top = index; top > descr->top_item; top--)
1335 if ((height += descr->items[top-1].height) > descr->height) break;
1336 }
1337 else
1338 {
1339 if (index < descr->top_item + descr->page_size) return;
1340 if (!fully && (index == descr->top_item + descr->page_size) &&
1341 (descr->height > (descr->page_size * descr->item_height))) return;
1342 top = index - descr->page_size + 1;
1343 }
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001344 LISTBOX_SetTopItem( descr, top, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001345}
1346
Gerard Patel2ffbb312000-07-09 12:18:14 +00001347/***********************************************************************
1348 * LISTBOX_SetCaretIndex
1349 *
1350 * NOTES
1351 * index must be between 0 and descr->nb_items-1, or LB_ERR is returned.
1352 *
1353 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001354static LRESULT LISTBOX_SetCaretIndex( LB_DESCR *descr, INT index, BOOL fully_visible )
Gerard Patel2ffbb312000-07-09 12:18:14 +00001355{
Alexandre Julliardde424282001-08-10 22:51:42 +00001356 INT oldfocus = descr->focus_item;
Gerard Patel2ffbb312000-07-09 12:18:14 +00001357
Andreas Mohr85ba8792001-01-06 00:34:14 +00001358 if (descr->style & LBS_NOSEL) return LB_ERR;
Gerard Patel2ffbb312000-07-09 12:18:14 +00001359 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
1360 if (index == oldfocus) return LB_OKAY;
1361 descr->focus_item = index;
1362 if ((oldfocus != -1) && descr->caret_on && (descr->in_focus))
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001363 LISTBOX_RepaintItem( descr, oldfocus, ODA_FOCUS );
Gerard Patel2ffbb312000-07-09 12:18:14 +00001364
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001365 LISTBOX_MakeItemVisible( descr, index, fully_visible );
Gerard Patel2ffbb312000-07-09 12:18:14 +00001366 if (descr->caret_on && (descr->in_focus))
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001367 LISTBOX_RepaintItem( descr, index, ODA_FOCUS );
Gerard Patel2ffbb312000-07-09 12:18:14 +00001368
1369 return LB_OKAY;
1370}
1371
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001372
1373/***********************************************************************
1374 * LISTBOX_SelectItemRange
1375 *
1376 * Select a range of items. Should only be used on a MULTIPLESEL listbox.
1377 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001378static LRESULT LISTBOX_SelectItemRange( LB_DESCR *descr, INT first,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001379 INT last, BOOL on )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001380{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001381 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001382
1383 /* A few sanity checks */
1384
Andreas Mohr85ba8792001-01-06 00:34:14 +00001385 if (descr->style & LBS_NOSEL) return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001386 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
Dmitry Timoshkovb43afee2005-12-01 11:12:34 +01001387
1388 if (!descr->nb_items) return LB_OKAY;
1389
qingdoa daoo7c34bfa2006-06-02 09:02:42 +08001390 if (last == -1 || last >= descr->nb_items) last = descr->nb_items - 1;
Dmitry Timoshkovb43afee2005-12-01 11:12:34 +01001391 if (first < 0) first = 0;
1392 if (last < first) return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001393
1394 if (on) /* Turn selection on */
1395 {
1396 for (i = first; i <= last; i++)
1397 {
1398 if (descr->items[i].selected) continue;
1399 descr->items[i].selected = TRUE;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001400 LISTBOX_InvalidateItemRect(descr, i);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001401 }
1402 }
1403 else /* Turn selection off */
1404 {
1405 for (i = first; i <= last; i++)
1406 {
1407 if (!descr->items[i].selected) continue;
1408 descr->items[i].selected = FALSE;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001409 LISTBOX_InvalidateItemRect(descr, i);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001410 }
1411 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001412 return LB_OKAY;
1413}
1414
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001415/***********************************************************************
1416 * LISTBOX_SetSelection
1417 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001418static LRESULT LISTBOX_SetSelection( LB_DESCR *descr, INT index,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001419 BOOL on, BOOL send_notify )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001420{
Dmitry Timoshkove0f493e1999-11-28 19:44:33 +00001421 TRACE( "index=%d notify=%s\n", index, send_notify ? "YES" : "NO" );
1422
Jon Griffiths7a9e8002004-10-05 22:31:00 +00001423 if (descr->style & LBS_NOSEL)
1424 {
1425 descr->selected_item = index;
1426 return LB_ERR;
1427 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001428 if ((index < -1) || (index >= descr->nb_items)) return LB_ERR;
1429 if (descr->style & LBS_MULTIPLESEL)
1430 {
1431 if (index == -1) /* Select all items */
Dmitry Timoshkovb43afee2005-12-01 11:12:34 +01001432 return LISTBOX_SelectItemRange( descr, 0, descr->nb_items, on );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001433 else /* Only one item */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001434 return LISTBOX_SelectItemRange( descr, index, index, on );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001435 }
1436 else
1437 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001438 INT oldsel = descr->selected_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001439 if (index == oldsel) return LB_OKAY;
1440 if (oldsel != -1) descr->items[oldsel].selected = FALSE;
1441 if (index != -1) descr->items[index].selected = TRUE;
1442 descr->selected_item = index;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001443 if (oldsel != -1) LISTBOX_RepaintItem( descr, oldsel, ODA_SELECT );
1444 if (index != -1) LISTBOX_RepaintItem( descr, index, ODA_SELECT );
1445 if (send_notify && descr->nb_items) SEND_NOTIFICATION( descr,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001446 (index != -1) ? LBN_SELCHANGE : LBN_SELCANCEL );
Alex Korobka311d3291999-01-01 18:40:02 +00001447 else
1448 if( descr->lphc ) /* set selection change flag for parent combo */
1449 descr->lphc->wState |= CBF_SELCHANGE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001450 }
1451 return LB_OKAY;
1452}
1453
1454
1455/***********************************************************************
1456 * LISTBOX_MoveCaret
1457 *
1458 * Change the caret position and extend the selection to the new caret.
1459 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001460static void LISTBOX_MoveCaret( LB_DESCR *descr, INT index, BOOL fully_visible )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001461{
Alexandre Julliardde424282001-08-10 22:51:42 +00001462 INT oldfocus = descr->focus_item;
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001463
Alexandre Julliardde424282001-08-10 22:51:42 +00001464 if ((index < 0) || (index >= descr->nb_items))
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001465 return;
1466
1467 /* Important, repaint needs to be done in this order if
1468 you want to mimic Windows behavior:
Vincent Béron9a624912002-05-31 23:06:46 +00001469 1. Remove the focus and paint the item
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001470 2. Remove the selection and paint the item(s)
1471 3. Set the selection and repaint the item(s)
1472 4. Set the focus to 'index' and repaint the item */
1473
1474 /* 1. remove the focus and repaint the item */
1475 descr->focus_item = -1;
1476 if ((oldfocus != -1) && descr->caret_on && (descr->in_focus))
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001477 LISTBOX_RepaintItem( descr, oldfocus, ODA_FOCUS );
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001478
1479 /* 2. then turn off the previous selection */
1480 /* 3. repaint the new selected item */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001481 if (descr->style & LBS_EXTENDEDSEL)
1482 {
1483 if (descr->anchor_item != -1)
1484 {
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001485 INT first = min( index, descr->anchor_item );
1486 INT last = max( index, descr->anchor_item );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001487 if (first > 0)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001488 LISTBOX_SelectItemRange( descr, 0, first - 1, FALSE );
1489 LISTBOX_SelectItemRange( descr, last + 1, -1, FALSE );
1490 LISTBOX_SelectItemRange( descr, first, last, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001491 }
1492 }
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00001493 else if (!(descr->style & LBS_MULTIPLESEL))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001494 {
1495 /* Set selection to new caret item */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001496 LISTBOX_SetSelection( descr, index, TRUE, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001497 }
Alexandre Julliardde424282001-08-10 22:51:42 +00001498
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001499 /* 4. repaint the new item with the focus */
1500 descr->focus_item = index;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001501 LISTBOX_MakeItemVisible( descr, index, fully_visible );
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001502 if (descr->caret_on && (descr->in_focus))
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001503 LISTBOX_RepaintItem( descr, index, ODA_FOCUS );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001504}
1505
1506
1507/***********************************************************************
1508 * LISTBOX_InsertItem
1509 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001510static LRESULT LISTBOX_InsertItem( LB_DESCR *descr, INT index,
Alexandre Julliard2c1b3c62005-09-12 11:24:23 +00001511 LPWSTR str, ULONG_PTR data )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001512{
1513 LB_ITEMDATA *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001514 INT max_items;
Gerard Patelc9a6d501999-07-25 13:03:17 +00001515 INT oldfocus = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001516
1517 if (index == -1) index = descr->nb_items;
1518 else if ((index < 0) || (index > descr->nb_items)) return LB_ERR;
1519 if (!descr->items) max_items = 0;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001520 else max_items = HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(*item);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001521 if (descr->nb_items == max_items)
1522 {
1523 /* We need to grow the array */
1524 max_items += LB_ARRAY_GRANULARITY;
Oleg Prokhorovde12a972003-10-14 05:24:20 +00001525 if (descr->items)
1526 item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
1527 max_items * sizeof(LB_ITEMDATA) );
1528 else
Jon Griffiths7a9e8002004-10-05 22:31:00 +00001529 item = HeapAlloc( GetProcessHeap(), 0,
Oleg Prokhorovde12a972003-10-14 05:24:20 +00001530 max_items * sizeof(LB_ITEMDATA) );
1531 if (!item)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001532 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001533 SEND_NOTIFICATION( descr, LBN_ERRSPACE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001534 return LB_ERRSPACE;
1535 }
1536 descr->items = item;
1537 }
1538
1539 /* Insert the item structure */
1540
1541 item = &descr->items[index];
1542 if (index < descr->nb_items)
1543 RtlMoveMemory( item + 1, item,
1544 (descr->nb_items - index) * sizeof(LB_ITEMDATA) );
1545 item->str = str;
1546 item->data = data;
1547 item->height = 0;
1548 item->selected = FALSE;
1549 descr->nb_items++;
1550
1551 /* Get item height */
1552
1553 if (descr->style & LBS_OWNERDRAWVARIABLE)
1554 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001555 MEASUREITEMSTRUCT mis;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001556 UINT id = (UINT)GetWindowLongPtrW( descr->self, GWLP_ID );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001557
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001558 mis.CtlType = ODT_LISTBOX;
Alexandre Julliardde424282001-08-10 22:51:42 +00001559 mis.CtlID = id;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001560 mis.itemID = index;
1561 mis.itemData = descr->items[index].data;
1562 mis.itemHeight = descr->item_height;
Alexandre Julliardde424282001-08-10 22:51:42 +00001563 SendMessageW( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001564 item->height = mis.itemHeight ? mis.itemHeight : 1;
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00001565 TRACE("[%p]: measure item %d (%s) = %d\n",
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001566 descr->self, index, str ? debugstr_w(str) : "", item->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001567 }
1568
1569 /* Repaint the items */
1570
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001571 LISTBOX_UpdateScroll( descr );
1572 LISTBOX_InvalidateItems( descr, index );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001573
1574 /* Move selection and focused item */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001575 /* If listbox was empty, set focus to the first item */
Gerard Patelc9a6d501999-07-25 13:03:17 +00001576 if (descr->nb_items == 1)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001577 LISTBOX_SetCaretIndex( descr, 0, FALSE );
Gerard Patelc9a6d501999-07-25 13:03:17 +00001578 /* single select don't change selection index in win31 */
1579 else if ((ISWIN31) && !(IS_MULTISELECT(descr)))
1580 {
1581 descr->selected_item++;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001582 LISTBOX_SetSelection( descr, descr->selected_item-1, TRUE, FALSE );
Gerard Patelc9a6d501999-07-25 13:03:17 +00001583 }
1584 else
1585 {
1586 if (index <= descr->selected_item)
1587 {
Jon Griffiths7a9e8002004-10-05 22:31:00 +00001588 descr->selected_item++;
1589 descr->focus_item = oldfocus; /* focus not changed */
Gerard Patelc9a6d501999-07-25 13:03:17 +00001590 }
1591 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001592 return LB_OKAY;
1593}
1594
1595
1596/***********************************************************************
1597 * LISTBOX_InsertString
1598 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001599static LRESULT LISTBOX_InsertString( LB_DESCR *descr, INT index, LPCWSTR str )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001600{
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001601 LPWSTR new_str = NULL;
Alexandre Julliard2c1b3c62005-09-12 11:24:23 +00001602 ULONG_PTR data = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001603 LRESULT ret;
1604
1605 if (HAS_STRINGS(descr))
1606 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001607 static const WCHAR empty_stringW[] = { 0 };
1608 if (!str) str = empty_stringW;
1609 if (!(new_str = HeapAlloc( GetProcessHeap(), 0, (strlenW(str) + 1) * sizeof(WCHAR) )))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001610 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001611 SEND_NOTIFICATION( descr, LBN_ERRSPACE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001612 return LB_ERRSPACE;
1613 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001614 strcpyW(new_str, str);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001615 }
Alexandre Julliard2c1b3c62005-09-12 11:24:23 +00001616 else data = (ULONG_PTR)str;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001617
1618 if (index == -1) index = descr->nb_items;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001619 if ((ret = LISTBOX_InsertItem( descr, index, new_str, data )) != 0)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001620 {
Michael Stefaniuc5ad7d852004-12-23 17:06:43 +00001621 HeapFree( GetProcessHeap(), 0, new_str );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001622 return ret;
1623 }
1624
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00001625 TRACE("[%p]: added item %d %s\n",
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001626 descr->self, index, HAS_STRINGS(descr) ? debugstr_w(new_str) : "" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001627 return index;
1628}
1629
1630
1631/***********************************************************************
1632 * LISTBOX_DeleteItem
1633 *
1634 * Delete the content of an item. 'index' must be a valid index.
1635 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001636static void LISTBOX_DeleteItem( LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001637{
1638 /* Note: Win 3.1 only sends DELETEITEM on owner-draw items,
1639 * while Win95 sends it for all items with user data.
1640 * It's probably better to send it too often than not
1641 * often enough, so this is what we do here.
1642 */
1643 if (IS_OWNERDRAW(descr) || descr->items[index].data)
1644 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001645 DELETEITEMSTRUCT dis;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001646 UINT id = (UINT)GetWindowLongPtrW( descr->self, GWLP_ID );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001647
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001648 dis.CtlType = ODT_LISTBOX;
Alexandre Julliardde424282001-08-10 22:51:42 +00001649 dis.CtlID = id;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001650 dis.itemID = index;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001651 dis.hwndItem = descr->self;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001652 dis.itemData = descr->items[index].data;
Alexandre Julliardde424282001-08-10 22:51:42 +00001653 SendMessageW( descr->owner, WM_DELETEITEM, id, (LPARAM)&dis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001654 }
Michael Stefaniucfee72b62006-06-12 00:11:36 +02001655 if (HAS_STRINGS(descr))
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001656 HeapFree( GetProcessHeap(), 0, descr->items[index].str );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001657}
1658
1659
1660/***********************************************************************
1661 * LISTBOX_RemoveItem
1662 *
1663 * Remove an item from the listbox and delete its content.
1664 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001665static LRESULT LISTBOX_RemoveItem( LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001666{
1667 LB_ITEMDATA *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001668 INT max_items;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001669
Jason Edmeades34db84e2005-08-27 09:24:14 +00001670 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +00001671
1672 /* We need to invalidate the original rect instead of the updated one. */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001673 LISTBOX_InvalidateItems( descr, index );
Yuxi Zhangf94c3c52000-02-26 19:13:12 +00001674
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001675 LISTBOX_DeleteItem( descr, index );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001676
1677 /* Remove the item */
1678
1679 item = &descr->items[index];
1680 if (index < descr->nb_items-1)
1681 RtlMoveMemory( item, item + 1,
1682 (descr->nb_items - index - 1) * sizeof(LB_ITEMDATA) );
1683 descr->nb_items--;
1684 if (descr->anchor_item == descr->nb_items) descr->anchor_item--;
1685
1686 /* Shrink the item array if possible */
1687
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001688 max_items = HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(LB_ITEMDATA);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001689 if (descr->nb_items < max_items - 2*LB_ARRAY_GRANULARITY)
1690 {
1691 max_items -= LB_ARRAY_GRANULARITY;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001692 item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001693 max_items * sizeof(LB_ITEMDATA) );
1694 if (item) descr->items = item;
1695 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001696 /* Repaint the items */
1697
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001698 LISTBOX_UpdateScroll( descr );
Gerard Patelc9a6d501999-07-25 13:03:17 +00001699 /* if we removed the scrollbar, reset the top of the list
1700 (correct for owner-drawn ???) */
1701 if (descr->nb_items == descr->page_size)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001702 LISTBOX_SetTopItem( descr, 0, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001703
1704 /* Move selection and focused item */
Gerard Patelc9a6d501999-07-25 13:03:17 +00001705 if (!IS_MULTISELECT(descr))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001706 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00001707 if (index == descr->selected_item)
1708 descr->selected_item = -1;
1709 else if (index < descr->selected_item)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001710 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00001711 descr->selected_item--;
1712 if (ISWIN31) /* win 31 do not change the selected item number */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001713 LISTBOX_SetSelection( descr, descr->selected_item + 1, TRUE, FALSE);
1714 }
Gerard Patelc9a6d501999-07-25 13:03:17 +00001715 }
Yuxi Zhangf94c3c52000-02-26 19:13:12 +00001716
Gerard Patelc9a6d501999-07-25 13:03:17 +00001717 if (descr->focus_item >= descr->nb_items)
1718 {
1719 descr->focus_item = descr->nb_items - 1;
1720 if (descr->focus_item < 0) descr->focus_item = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001721 }
1722 return LB_OKAY;
1723}
1724
1725
1726/***********************************************************************
1727 * LISTBOX_ResetContent
1728 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001729static void LISTBOX_ResetContent( LB_DESCR *descr )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001730{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001731 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001732
Maxime Bellengé64a42962005-02-21 18:31:02 +00001733 for(i = descr->nb_items - 1; i>=0; i--) LISTBOX_DeleteItem( descr, i);
Michael Stefaniuc5ad7d852004-12-23 17:06:43 +00001734 HeapFree( GetProcessHeap(), 0, descr->items );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001735 descr->nb_items = 0;
1736 descr->top_item = 0;
1737 descr->selected_item = -1;
1738 descr->focus_item = 0;
1739 descr->anchor_item = -1;
1740 descr->items = NULL;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001741}
1742
1743
1744/***********************************************************************
1745 * LISTBOX_SetCount
1746 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001747static LRESULT LISTBOX_SetCount( LB_DESCR *descr, INT count )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001748{
1749 LRESULT ret;
1750
Robert Shearman30ff9402005-07-12 18:11:40 +00001751 if (HAS_STRINGS(descr))
1752 {
1753 SetLastError(ERROR_SETCOUNT_ON_BAD_LB);
1754 return LB_ERR;
1755 }
1756
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001757 /* FIXME: this is far from optimal... */
1758 if (count > descr->nb_items)
1759 {
1760 while (count > descr->nb_items)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001761 if ((ret = LISTBOX_InsertString( descr, -1, 0 )) < 0)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001762 return ret;
1763 }
1764 else if (count < descr->nb_items)
1765 {
1766 while (count < descr->nb_items)
Jason Edmeades34db84e2005-08-27 09:24:14 +00001767 if ((ret = LISTBOX_RemoveItem( descr, (descr->nb_items - 1) )) < 0)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001768 return ret;
1769 }
1770 return LB_OKAY;
1771}
1772
1773
1774/***********************************************************************
1775 * LISTBOX_Directory
1776 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001777static LRESULT LISTBOX_Directory( LB_DESCR *descr, UINT attrib,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001778 LPCWSTR filespec, BOOL long_names )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001779{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001780 HANDLE handle;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001781 LRESULT ret = LB_OKAY;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001782 WIN32_FIND_DATAW entry;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001783 int pos;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001784
Ove Kaaven2c691b32000-11-25 03:06:03 +00001785 /* don't scan directory if we just want drives exclusively */
1786 if (attrib != (DDL_DRIVES | DDL_EXCLUSIVE)) {
1787 /* scan directory */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001788 if ((handle = FindFirstFileW(filespec, &entry)) == INVALID_HANDLE_VALUE)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001789 {
Mike Hearnbf9e3842003-06-04 20:21:45 +00001790 int le = GetLastError();
1791 if ((le != ERROR_NO_MORE_FILES) && (le != ERROR_FILE_NOT_FOUND)) return LB_ERR;
Ove Kaaven2c691b32000-11-25 03:06:03 +00001792 }
1793 else
1794 {
1795 do
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001796 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001797 WCHAR buffer[270];
Ove Kaaven2c691b32000-11-25 03:06:03 +00001798 if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1799 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001800 static const WCHAR bracketW[] = { ']',0 };
1801 static const WCHAR dotW[] = { '.',0 };
Ove Kaaven2c691b32000-11-25 03:06:03 +00001802 if (!(attrib & DDL_DIRECTORY) ||
Alexandre Julliard22508e52004-03-17 01:50:27 +00001803 !strcmpW( entry.cFileName, dotW )) continue;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001804 buffer[0] = '[';
Alexandre Julliard22508e52004-03-17 01:50:27 +00001805 if (!long_names && entry.cAlternateFileName[0])
1806 strcpyW( buffer + 1, entry.cAlternateFileName );
1807 else
1808 strcpyW( buffer + 1, entry.cFileName );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001809 strcatW(buffer, bracketW);
Ove Kaaven2c691b32000-11-25 03:06:03 +00001810 }
1811 else /* not a directory */
1812 {
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001813#define ATTRIBS (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
1814 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE)
1815
Ove Kaaven2c691b32000-11-25 03:06:03 +00001816 if ((attrib & DDL_EXCLUSIVE) &&
1817 ((attrib & ATTRIBS) != (entry.dwFileAttributes & ATTRIBS)))
1818 continue;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001819#undef ATTRIBS
Alexandre Julliard22508e52004-03-17 01:50:27 +00001820 if (!long_names && entry.cAlternateFileName[0])
Alexandre Julliard74650112004-03-20 19:27:10 +00001821 strcpyW( buffer, entry.cAlternateFileName );
Alexandre Julliard22508e52004-03-17 01:50:27 +00001822 else
Alexandre Julliard74650112004-03-20 19:27:10 +00001823 strcpyW( buffer, entry.cFileName );
Ove Kaaven2c691b32000-11-25 03:06:03 +00001824 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001825 if (!long_names) CharLowerW( buffer );
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001826 pos = LISTBOX_FindFileStrPos( descr, buffer );
1827 if ((ret = LISTBOX_InsertString( descr, pos, buffer )) < 0)
Ove Kaaven2c691b32000-11-25 03:06:03 +00001828 break;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001829 } while (FindNextFileW( handle, &entry ));
Ove Kaaven2c691b32000-11-25 03:06:03 +00001830 FindClose( handle );
1831 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001832 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001833
Ove Kaaven2c691b32000-11-25 03:06:03 +00001834 /* scan drives */
Alexandre Julliard889f7421997-04-15 17:19:52 +00001835 if ((ret >= 0) && (attrib & DDL_DRIVES))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001836 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001837 WCHAR buffer[] = {'[','-','a','-',']',0};
1838 WCHAR root[] = {'A',':','\\',0};
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001839 int drive;
Alexandre Julliardbf672592000-12-12 00:44:42 +00001840 for (drive = 0; drive < 26; drive++, buffer[2]++, root[0]++)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001841 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001842 if (GetDriveTypeW(root) <= DRIVE_NO_ROOT_DIR) continue;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001843 if ((ret = LISTBOX_InsertString( descr, -1, buffer )) < 0)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001844 break;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001845 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001846 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001847 return ret;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001848}
1849
1850
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001851/***********************************************************************
1852 * LISTBOX_HandleVScroll
1853 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001854static LRESULT LISTBOX_HandleVScroll( LB_DESCR *descr, WORD scrollReq, WORD pos )
Alexandre Julliard2787be81995-05-22 18:23:01 +00001855{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001856 SCROLLINFO info;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001857
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001858 if (descr->style & LBS_MULTICOLUMN) return 0;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001859 switch(scrollReq)
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +00001860 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001861 case SB_LINEUP:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001862 LISTBOX_SetTopItem( descr, descr->top_item - 1, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001863 break;
1864 case SB_LINEDOWN:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001865 LISTBOX_SetTopItem( descr, descr->top_item + 1, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001866 break;
1867 case SB_PAGEUP:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001868 LISTBOX_SetTopItem( descr, descr->top_item -
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001869 LISTBOX_GetCurrentPageSize( descr ), TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001870 break;
1871 case SB_PAGEDOWN:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001872 LISTBOX_SetTopItem( descr, descr->top_item +
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001873 LISTBOX_GetCurrentPageSize( descr ), TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001874 break;
1875 case SB_THUMBPOSITION:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001876 LISTBOX_SetTopItem( descr, pos, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001877 break;
1878 case SB_THUMBTRACK:
1879 info.cbSize = sizeof(info);
1880 info.fMask = SIF_TRACKPOS;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001881 GetScrollInfo( descr->self, SB_VERT, &info );
1882 LISTBOX_SetTopItem( descr, info.nTrackPos, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001883 break;
1884 case SB_TOP:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001885 LISTBOX_SetTopItem( descr, 0, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001886 break;
1887 case SB_BOTTOM:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001888 LISTBOX_SetTopItem( descr, descr->nb_items, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001889 break;
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +00001890 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001891 return 0;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001892}
1893
Alexandre Julliardb817f4f1996-03-14 18:08:34 +00001894
Alexandre Julliard2787be81995-05-22 18:23:01 +00001895/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001896 * LISTBOX_HandleHScroll
Alexandre Julliard2787be81995-05-22 18:23:01 +00001897 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001898static LRESULT LISTBOX_HandleHScroll( LB_DESCR *descr, WORD scrollReq, WORD pos )
Alexandre Julliard2787be81995-05-22 18:23:01 +00001899{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001900 SCROLLINFO info;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001901 INT page;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001902
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001903 if (descr->style & LBS_MULTICOLUMN)
1904 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001905 switch(scrollReq)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001906 {
1907 case SB_LINELEFT:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001908 LISTBOX_SetTopItem( descr, descr->top_item-descr->page_size,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001909 TRUE );
1910 break;
1911 case SB_LINERIGHT:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001912 LISTBOX_SetTopItem( descr, descr->top_item+descr->page_size,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001913 TRUE );
1914 break;
1915 case SB_PAGELEFT:
1916 page = descr->width / descr->column_width;
1917 if (page < 1) page = 1;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001918 LISTBOX_SetTopItem( descr,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001919 descr->top_item - page * descr->page_size, TRUE );
1920 break;
1921 case SB_PAGERIGHT:
1922 page = descr->width / descr->column_width;
1923 if (page < 1) page = 1;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001924 LISTBOX_SetTopItem( descr,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001925 descr->top_item + page * descr->page_size, TRUE );
1926 break;
1927 case SB_THUMBPOSITION:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001928 LISTBOX_SetTopItem( descr, pos*descr->page_size, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001929 break;
1930 case SB_THUMBTRACK:
1931 info.cbSize = sizeof(info);
1932 info.fMask = SIF_TRACKPOS;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001933 GetScrollInfo( descr->self, SB_VERT, &info );
1934 LISTBOX_SetTopItem( descr, info.nTrackPos*descr->page_size,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001935 TRUE );
1936 break;
1937 case SB_LEFT:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001938 LISTBOX_SetTopItem( descr, 0, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001939 break;
1940 case SB_RIGHT:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001941 LISTBOX_SetTopItem( descr, descr->nb_items, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001942 break;
1943 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001944 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001945 else if (descr->horz_extent)
1946 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001947 switch(scrollReq)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001948 {
1949 case SB_LINELEFT:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001950 LISTBOX_SetHorizontalPos( descr, descr->horz_pos - 1 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001951 break;
1952 case SB_LINERIGHT:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001953 LISTBOX_SetHorizontalPos( descr, descr->horz_pos + 1 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001954 break;
1955 case SB_PAGELEFT:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001956 LISTBOX_SetHorizontalPos( descr,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001957 descr->horz_pos - descr->width );
1958 break;
1959 case SB_PAGERIGHT:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001960 LISTBOX_SetHorizontalPos( descr,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001961 descr->horz_pos + descr->width );
1962 break;
1963 case SB_THUMBPOSITION:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001964 LISTBOX_SetHorizontalPos( descr, pos );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001965 break;
1966 case SB_THUMBTRACK:
1967 info.cbSize = sizeof(info);
1968 info.fMask = SIF_TRACKPOS;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001969 GetScrollInfo( descr->self, SB_HORZ, &info );
1970 LISTBOX_SetHorizontalPos( descr, info.nTrackPos );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001971 break;
1972 case SB_LEFT:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001973 LISTBOX_SetHorizontalPos( descr, 0 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001974 break;
1975 case SB_RIGHT:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001976 LISTBOX_SetHorizontalPos( descr,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001977 descr->horz_extent - descr->width );
1978 break;
1979 }
1980 }
1981 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001982}
1983
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001984static LRESULT LISTBOX_HandleMouseWheel(LB_DESCR *descr, SHORT delta )
Stephane Lussier4bdf4af2000-04-18 11:56:33 +00001985{
1986 short gcWheelDelta = 0;
1987 UINT pulScrollLines = 3;
1988
1989 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
1990
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001991 gcWheelDelta -= delta;
Stephane Lussier4bdf4af2000-04-18 11:56:33 +00001992
1993 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
1994 {
1995 int cLineScroll = (int) min((UINT) descr->page_size, pulScrollLines);
1996 cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00001997 LISTBOX_SetTopItem( descr, descr->top_item + cLineScroll, TRUE );
Stephane Lussier4bdf4af2000-04-18 11:56:33 +00001998 }
1999 return 0;
2000}
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002001
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002002/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002003 * LISTBOX_HandleLButtonDown
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002004 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002005static LRESULT LISTBOX_HandleLButtonDown( LB_DESCR *descr, DWORD keys, INT x, INT y )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002006{
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002007 INT index = LISTBOX_GetItemFromPoint( descr, x, y );
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002008 TRACE("[%p]: lbuttondown %d,%d item %d\n", descr->self, x, y, index );
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002009 if (!descr->caret_on && (descr->in_focus)) return 0;
Jason Mawdsley50523d12000-06-11 20:34:07 +00002010
2011 if (!descr->in_focus)
2012 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002013 if( !descr->lphc ) SetFocus( descr->self );
Alexandre Julliardde424282001-08-10 22:51:42 +00002014 else SetFocus( (descr->lphc->hWndEdit) ? descr->lphc->hWndEdit : descr->lphc->self );
Jason Mawdsley50523d12000-06-11 20:34:07 +00002015 }
2016
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00002017 if (index == -1) return 0;
Andreas Mohr2b5d9c62000-08-29 03:52:16 +00002018
Jon Griffiths7a9e8002004-10-05 22:31:00 +00002019 if (descr->style & (LBS_EXTENDEDSEL | LBS_MULTIPLESEL))
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00002020 {
2021 /* we should perhaps make sure that all items are deselected
2022 FIXME: needed for !LBS_EXTENDEDSEL, too ?
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002023 if (!(keys & (MK_SHIFT|MK_CONTROL)))
2024 LISTBOX_SetSelection( descr, -1, FALSE, FALSE);
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00002025 */
2026
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002027 if (!(keys & MK_SHIFT)) descr->anchor_item = index;
2028 if (keys & MK_CONTROL)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002029 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002030 LISTBOX_SetCaretIndex( descr, index, FALSE );
2031 LISTBOX_SetSelection( descr, index,
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00002032 !descr->items[index].selected,
2033 (descr->style & LBS_NOTIFY) != 0);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002034 }
Jon Griffiths7a9e8002004-10-05 22:31:00 +00002035 else
2036 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002037 LISTBOX_MoveCaret( descr, index, FALSE );
Jon Griffiths7a9e8002004-10-05 22:31:00 +00002038
Lauri Tulmind3cc4dc2005-01-10 16:22:33 +00002039 if (descr->style & LBS_EXTENDEDSEL)
Jon Griffiths7a9e8002004-10-05 22:31:00 +00002040 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002041 LISTBOX_SetSelection( descr, index,
Lauri Tulmind3cc4dc2005-01-10 16:22:33 +00002042 descr->items[index].selected,
2043 (descr->style & LBS_NOTIFY) != 0 );
2044 }
2045 else
2046 {
2047 LISTBOX_SetSelection( descr, index,
2048 !descr->items[index].selected,
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00002049 (descr->style & LBS_NOTIFY) != 0 );
Jon Griffiths7a9e8002004-10-05 22:31:00 +00002050 }
2051 }
2052 }
2053 else
2054 {
2055 descr->anchor_item = index;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002056 LISTBOX_MoveCaret( descr, index, FALSE );
2057 LISTBOX_SetSelection( descr, index,
Jon Griffiths7a9e8002004-10-05 22:31:00 +00002058 TRUE, (descr->style & LBS_NOTIFY) != 0 );
Alexandre Julliard2787be81995-05-22 18:23:01 +00002059 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002060
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002061 descr->captured = TRUE;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002062 SetCapture( descr->self );
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00002063
2064 if (!descr->lphc)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002065 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002066 if (descr->style & LBS_NOTIFY )
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002067 SendMessageW( descr->owner, WM_LBTRACKPOINT, index,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002068 MAKELPARAM( x, y ) );
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002069 if (GetWindowLongW( descr->self, GWL_EXSTYLE ) & WS_EX_DRAGDETECT)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002070 {
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002071 POINT pt;
Alexandre Julliardde424282001-08-10 22:51:42 +00002072
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002073 pt.x = x;
2074 pt.y = y;
2075
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002076 if (DragDetect( descr->self, pt ))
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002077 SendMessageW( descr->owner, WM_BEGINDRAG, 0, 0 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002078 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00002079 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002080 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002081}
2082
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002083
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002084/*************************************************************************
Alexandre Julliardde424282001-08-10 22:51:42 +00002085 * LISTBOX_HandleLButtonDownCombo [Internal]
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002086 *
2087 * Process LButtonDown message for the ComboListBox
2088 *
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002089 * PARAMS
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002090 * pWnd [I] The windows internal structure
2091 * pDescr [I] The ListBox internal structure
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002092 * keys [I] Key Flag (WM_LBUTTONDOWN doc for more info)
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002093 * x [I] X Mouse Coordinate
2094 * y [I] Y Mouse Coordinate
2095 *
2096 * RETURNS
2097 * 0 since we are processing the WM_LBUTTONDOWN Message
2098 *
2099 * NOTES
2100 * This function is only to be used when a ListBox is a ComboListBox
2101 */
2102
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002103static LRESULT LISTBOX_HandleLButtonDownCombo( LB_DESCR *descr, UINT msg, DWORD keys, INT x, INT y)
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002104{
2105 RECT clientRect, screenRect;
2106 POINT mousePos;
2107
2108 mousePos.x = x;
2109 mousePos.y = y;
2110
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002111 GetClientRect(descr->self, &clientRect);
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002112
2113 if(PtInRect(&clientRect, mousePos))
Alexandre Julliardde424282001-08-10 22:51:42 +00002114 {
Alexandre Julliard7f90a8c2000-05-23 04:18:12 +00002115 /* MousePos is in client, resume normal processing */
2116 if (msg == WM_LBUTTONDOWN)
Serge Ivanov07917e42000-06-07 03:46:57 +00002117 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002118 descr->lphc->droppedIndex = descr->nb_items ? descr->selected_item : -1;
2119 return LISTBOX_HandleLButtonDown( descr, keys, x, y);
Serge Ivanov07917e42000-06-07 03:46:57 +00002120 }
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002121 else if (descr->style & LBS_NOTIFY)
2122 SEND_NOTIFICATION( descr, LBN_DBLCLK );
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002123 }
2124 else
2125 {
2126 POINT screenMousePos;
2127 HWND hWndOldCapture;
2128
2129 /* Check the Non-Client Area */
2130 screenMousePos = mousePos;
2131 hWndOldCapture = GetCapture();
2132 ReleaseCapture();
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002133 GetWindowRect(descr->self, &screenRect);
2134 ClientToScreen(descr->self, &screenMousePos);
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002135
2136 if(!PtInRect(&screenRect, screenMousePos))
Alexandre Julliardde424282001-08-10 22:51:42 +00002137 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002138 LISTBOX_SetCaretIndex( descr, descr->lphc->droppedIndex, FALSE );
2139 LISTBOX_SetSelection( descr, descr->lphc->droppedIndex, FALSE, FALSE );
2140 COMBO_FlipListbox( descr->lphc, FALSE, FALSE );
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002141 }
2142 else
2143 {
2144 /* Check to see the NC is a scrollbar */
2145 INT nHitTestType=0;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002146 LONG style = GetWindowLongW( descr->self, GWL_STYLE );
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002147 /* Check Vertical scroll bar */
Alexandre Julliardde424282001-08-10 22:51:42 +00002148 if (style & WS_VSCROLL)
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002149 {
2150 clientRect.right += GetSystemMetrics(SM_CXVSCROLL);
Alexandre Julliardde424282001-08-10 22:51:42 +00002151 if (PtInRect( &clientRect, mousePos ))
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002152 nHitTestType = HTVSCROLL;
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002153 }
2154 /* Check horizontal scroll bar */
Alexandre Julliardde424282001-08-10 22:51:42 +00002155 if (style & WS_HSCROLL)
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002156 {
2157 clientRect.bottom += GetSystemMetrics(SM_CYHSCROLL);
2158 if (PtInRect( &clientRect, mousePos ))
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002159 nHitTestType = HTHSCROLL;
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002160 }
Vincent Béron9a624912002-05-31 23:06:46 +00002161 /* Windows sends this message when a scrollbar is clicked
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002162 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002163
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002164 if(nHitTestType != 0)
2165 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002166 SendMessageW(descr->self, WM_NCLBUTTONDOWN, nHitTestType,
2167 MAKELONG(screenMousePos.x, screenMousePos.y));
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002168 }
Vincent Béron9a624912002-05-31 23:06:46 +00002169 /* Resume the Capture after scrolling is complete
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002170 */
2171 if(hWndOldCapture != 0)
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002172 SetCapture(hWndOldCapture);
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002173 }
2174 }
2175 return 0;
2176}
2177
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002178/***********************************************************************
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002179 * LISTBOX_HandleLButtonUp
2180 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002181static LRESULT LISTBOX_HandleLButtonUp( LB_DESCR *descr )
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002182{
2183 if (LISTBOX_Timer != LB_TIMER_NONE)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002184 KillSystemTimer( descr->self, LB_TIMER_ID );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002185 LISTBOX_Timer = LB_TIMER_NONE;
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002186 if (descr->captured)
Alexandre Julliard33072e11997-06-29 18:08:02 +00002187 {
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002188 descr->captured = FALSE;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002189 if (GetCapture() == descr->self) ReleaseCapture();
Gerard Patelc9a6d501999-07-25 13:03:17 +00002190 if ((descr->style & LBS_NOTIFY) && descr->nb_items)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002191 SEND_NOTIFICATION( descr, LBN_SELCHANGE );
Alexandre Julliard33072e11997-06-29 18:08:02 +00002192 }
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002193 return 0;
2194}
2195
2196
2197/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002198 * LISTBOX_HandleTimer
Alexandre Julliardade697e1995-11-26 13:59:11 +00002199 *
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002200 * Handle scrolling upon a timer event.
2201 * Return TRUE if scrolling should continue.
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002202 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002203static LRESULT LISTBOX_HandleTimer( LB_DESCR *descr, INT index, TIMER_DIRECTION dir )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002204{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002205 switch(dir)
Alexandre Julliardade697e1995-11-26 13:59:11 +00002206 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002207 case LB_TIMER_UP:
2208 if (descr->top_item) index = descr->top_item - 1;
2209 else index = 0;
2210 break;
2211 case LB_TIMER_LEFT:
2212 if (descr->top_item) index -= descr->page_size;
2213 break;
2214 case LB_TIMER_DOWN:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002215 index = descr->top_item + LISTBOX_GetCurrentPageSize( descr );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002216 if (index == descr->focus_item) index++;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002217 if (index >= descr->nb_items) index = descr->nb_items - 1;
2218 break;
2219 case LB_TIMER_RIGHT:
2220 if (index + descr->page_size < descr->nb_items)
2221 index += descr->page_size;
2222 break;
2223 case LB_TIMER_NONE:
2224 break;
Alexandre Julliardade697e1995-11-26 13:59:11 +00002225 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002226 if (index == descr->focus_item) return FALSE;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002227 LISTBOX_MoveCaret( descr, index, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002228 return TRUE;
2229}
Alexandre Julliardade697e1995-11-26 13:59:11 +00002230
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002231
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002232/***********************************************************************
2233 * LISTBOX_HandleSystemTimer
2234 *
2235 * WM_SYSTIMER handler.
2236 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002237static LRESULT LISTBOX_HandleSystemTimer( LB_DESCR *descr )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002238{
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002239 if (!LISTBOX_HandleTimer( descr, descr->focus_item, LISTBOX_Timer ))
Alexandre Julliardade697e1995-11-26 13:59:11 +00002240 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002241 KillSystemTimer( descr->self, LB_TIMER_ID );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002242 LISTBOX_Timer = LB_TIMER_NONE;
Alexandre Julliardade697e1995-11-26 13:59:11 +00002243 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00002244 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002245}
2246
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002247
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002248/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002249 * LISTBOX_HandleMouseMove
2250 *
2251 * WM_MOUSEMOVE handler.
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002252 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002253static void LISTBOX_HandleMouseMove( LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002254 INT x, INT y )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002255{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002256 INT index;
Serge Ivanov07917e42000-06-07 03:46:57 +00002257 TIMER_DIRECTION dir = LB_TIMER_NONE;
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00002258
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002259 if (!descr->captured) return;
2260
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002261 if (descr->style & LBS_MULTICOLUMN)
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00002262 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002263 if (y < 0) y = 0;
2264 else if (y >= descr->item_height * descr->page_size)
2265 y = descr->item_height * descr->page_size - 1;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002266
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002267 if (x < 0)
2268 {
2269 dir = LB_TIMER_LEFT;
2270 x = 0;
2271 }
2272 else if (x >= descr->width)
2273 {
2274 dir = LB_TIMER_RIGHT;
2275 x = descr->width - 1;
2276 }
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00002277 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002278 else
2279 {
2280 if (y < 0) dir = LB_TIMER_UP; /* above */
2281 else if (y >= descr->height) dir = LB_TIMER_DOWN; /* below */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002282 }
2283
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002284 index = LISTBOX_GetItemFromPoint( descr, x, y );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002285 if (index == -1) index = descr->focus_item;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002286 if (!LISTBOX_HandleTimer( descr, index, dir )) dir = LB_TIMER_NONE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002287
2288 /* Start/stop the system timer */
2289
2290 if (dir != LB_TIMER_NONE)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002291 SetSystemTimer( descr->self, LB_TIMER_ID, LB_SCROLL_TIMEOUT, NULL);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002292 else if (LISTBOX_Timer != LB_TIMER_NONE)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002293 KillSystemTimer( descr->self, LB_TIMER_ID );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002294 LISTBOX_Timer = dir;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002295}
2296
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002297
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002298/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002299 * LISTBOX_HandleKeyDown
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002300 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002301static LRESULT LISTBOX_HandleKeyDown( LB_DESCR *descr, DWORD key )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002302{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002303 INT caret = -1;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002304 BOOL bForceSelection = TRUE; /* select item pointed to by focus_item */
2305 if ((IS_MULTISELECT(descr)) || (descr->selected_item == descr->focus_item))
Jon Griffiths7a9e8002004-10-05 22:31:00 +00002306 bForceSelection = FALSE; /* only for single select list */
Gerard Patelc9a6d501999-07-25 13:03:17 +00002307
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002308 if (descr->style & LBS_WANTKEYBOARDINPUT)
2309 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002310 caret = SendMessageW( descr->owner, WM_VKEYTOITEM,
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002311 MAKEWPARAM(LOWORD(key), descr->focus_item),
2312 (LPARAM)descr->self );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002313 if (caret == -2) return 0;
2314 }
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002315 if (caret == -1) switch(key)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002316 {
2317 case VK_LEFT:
2318 if (descr->style & LBS_MULTICOLUMN)
2319 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00002320 bForceSelection = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002321 if (descr->focus_item >= descr->page_size)
2322 caret = descr->focus_item - descr->page_size;
2323 break;
2324 }
2325 /* fall through */
2326 case VK_UP:
2327 caret = descr->focus_item - 1;
2328 if (caret < 0) caret = 0;
2329 break;
2330 case VK_RIGHT:
2331 if (descr->style & LBS_MULTICOLUMN)
2332 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00002333 bForceSelection = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002334 if (descr->focus_item + descr->page_size < descr->nb_items)
2335 caret = descr->focus_item + descr->page_size;
2336 break;
2337 }
2338 /* fall through */
2339 case VK_DOWN:
2340 caret = descr->focus_item + 1;
2341 if (caret >= descr->nb_items) caret = descr->nb_items - 1;
2342 break;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002343
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002344 case VK_PRIOR:
2345 if (descr->style & LBS_MULTICOLUMN)
2346 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002347 INT page = descr->width / descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002348 if (page < 1) page = 1;
2349 caret = descr->focus_item - (page * descr->page_size) + 1;
2350 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002351 else caret = descr->focus_item-LISTBOX_GetCurrentPageSize(descr) + 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002352 if (caret < 0) caret = 0;
2353 break;
2354 case VK_NEXT:
2355 if (descr->style & LBS_MULTICOLUMN)
2356 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002357 INT page = descr->width / descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002358 if (page < 1) page = 1;
2359 caret = descr->focus_item + (page * descr->page_size) - 1;
2360 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002361 else caret = descr->focus_item + LISTBOX_GetCurrentPageSize(descr) - 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002362 if (caret >= descr->nb_items) caret = descr->nb_items - 1;
2363 break;
2364 case VK_HOME:
2365 caret = 0;
2366 break;
2367 case VK_END:
2368 caret = descr->nb_items - 1;
2369 break;
2370 case VK_SPACE:
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002371 if (descr->style & LBS_EXTENDEDSEL) caret = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002372 else if (descr->style & LBS_MULTIPLESEL)
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002373 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002374 LISTBOX_SetSelection( descr, descr->focus_item,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002375 !descr->items[descr->focus_item].selected,
2376 (descr->style & LBS_NOTIFY) != 0 );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002377 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002378 break;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002379 default:
2380 bForceSelection = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002381 }
Gerard Patelc9a6d501999-07-25 13:03:17 +00002382 if (bForceSelection) /* focused item is used instead of key */
2383 caret = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002384 if (caret >= 0)
2385 {
Jon Griffiths7a9e8002004-10-05 22:31:00 +00002386 if (((descr->style & LBS_EXTENDEDSEL) &&
2387 !(GetKeyState( VK_SHIFT ) & 0x8000)) ||
2388 !IS_MULTISELECT(descr))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002389 descr->anchor_item = caret;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002390 LISTBOX_MoveCaret( descr, caret, TRUE );
Jon Griffiths7a9e8002004-10-05 22:31:00 +00002391
2392 if (descr->style & LBS_MULTIPLESEL)
2393 descr->selected_item = caret;
2394 else
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002395 LISTBOX_SetSelection( descr, caret, TRUE, FALSE);
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002396 if (descr->style & LBS_NOTIFY)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002397 {
Jon Griffiths7a9e8002004-10-05 22:31:00 +00002398 if( descr->lphc )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002399 {
Jon Griffiths7a9e8002004-10-05 22:31:00 +00002400 /* make sure that combo parent doesn't hide us */
2401 descr->lphc->wState |= CBF_NOROLLUP;
2402 }
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002403 if (descr->nb_items) SEND_NOTIFICATION( descr, LBN_SELCHANGE );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002404 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002405 }
2406 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002407}
2408
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002409
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002410/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002411 * LISTBOX_HandleChar
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002412 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002413static LRESULT LISTBOX_HandleChar( LB_DESCR *descr, WCHAR charW )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002414{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002415 INT caret = -1;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002416 WCHAR str[2];
2417
2418 str[0] = charW;
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002419 str[1] = '\0';
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002420
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002421 if (descr->style & LBS_WANTKEYBOARDINPUT)
2422 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002423 caret = SendMessageW( descr->owner, WM_CHARTOITEM,
2424 MAKEWPARAM(charW, descr->focus_item),
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002425 (LPARAM)descr->self );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002426 if (caret == -2) return 0;
2427 }
2428 if (caret == -1)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002429 caret = LISTBOX_FindString( descr, descr->focus_item, str, FALSE);
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002430 if (caret != -1)
2431 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00002432 if ((!IS_MULTISELECT(descr)) && descr->selected_item == -1)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002433 LISTBOX_SetSelection( descr, caret, TRUE, FALSE);
2434 LISTBOX_MoveCaret( descr, caret, TRUE );
Gerard Patelc9a6d501999-07-25 13:03:17 +00002435 if ((descr->style & LBS_NOTIFY) && descr->nb_items)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002436 SEND_NOTIFICATION( descr, LBN_SELCHANGE );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002437 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002438 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002439}
2440
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002441
2442/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002443 * LISTBOX_Create
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002444 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002445static BOOL LISTBOX_Create( HWND hwnd, LPHEADCOMBO lphc )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002446{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002447 LB_DESCR *descr;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002448 MEASUREITEMSTRUCT mis;
2449 RECT rect;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002450
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002451 if (!(descr = HeapAlloc( GetProcessHeap(), 0, sizeof(*descr) )))
2452 return FALSE;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002453
Alexandre Julliardde424282001-08-10 22:51:42 +00002454 GetClientRect( hwnd, &rect );
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002455 descr->self = hwnd;
2456 descr->owner = GetParent( descr->self );
2457 descr->style = GetWindowLongW( descr->self, GWL_STYLE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002458 descr->width = rect.right - rect.left;
2459 descr->height = rect.bottom - rect.top;
2460 descr->items = NULL;
2461 descr->nb_items = 0;
2462 descr->top_item = 0;
2463 descr->selected_item = -1;
2464 descr->focus_item = 0;
2465 descr->anchor_item = -1;
2466 descr->item_height = 1;
2467 descr->page_size = 1;
2468 descr->column_width = 150;
Alexandre Julliardde424282001-08-10 22:51:42 +00002469 descr->horz_extent = (descr->style & WS_HSCROLL) ? 1 : 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002470 descr->horz_pos = 0;
2471 descr->nb_tabs = 0;
2472 descr->tabs = NULL;
Serge Ivanov07917e42000-06-07 03:46:57 +00002473 descr->caret_on = lphc ? FALSE : TRUE;
Andreas Mohr85ba8792001-01-06 00:34:14 +00002474 if (descr->style & LBS_NOSEL) descr->caret_on = FALSE;
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002475 descr->in_focus = FALSE;
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002476 descr->captured = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002477 descr->font = 0;
Robert Shearman7dd1d212005-07-12 17:55:35 +00002478 descr->locale = GetUserDefaultLCID();
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002479 descr->lphc = lphc;
2480
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002481 if (is_old_app(descr) && ( descr->style & ( WS_VSCROLL | WS_HSCROLL ) ) )
Nick Hollowayb9ce4fd1999-09-11 16:29:00 +00002482 {
2483 /* Win95 document "List Box Differences" from MSDN:
2484 If a list box in a version 3.x application has either the
2485 WS_HSCROLL or WS_VSCROLL style, the list box receives both
2486 horizontal and vertical scroll bars.
2487 */
2488 descr->style |= WS_VSCROLL | WS_HSCROLL;
2489 }
2490
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002491 if( lphc )
2492 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002493 TRACE("[%p]: resetting owner %p -> %p\n", descr->self, descr->owner, lphc->self );
Alexandre Julliardde424282001-08-10 22:51:42 +00002494 descr->owner = lphc->self;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002495 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00002496
Alexandre Julliard5c377852005-09-12 12:20:38 +00002497 SetWindowLongPtrW( descr->self, 0, (LONG_PTR)descr );
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002498
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002499/* if (wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) descr->style &= ~LBS_NOTIFY;
2500 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002501 if (descr->style & LBS_EXTENDEDSEL) descr->style |= LBS_MULTIPLESEL;
2502 if (descr->style & LBS_MULTICOLUMN) descr->style &= ~LBS_OWNERDRAWVARIABLE;
2503 if (descr->style & LBS_OWNERDRAWVARIABLE) descr->style |= LBS_NOINTEGRALHEIGHT;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002504 descr->item_height = LISTBOX_SetFont( descr, 0 );
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002505
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002506 if (descr->style & LBS_OWNERDRAWFIXED)
2507 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002508 if( descr->lphc && (descr->lphc->dwStyle & CBS_DROPDOWN))
2509 {
2510 /* WinWord gets VERY unhappy if we send WM_MEASUREITEM from here */
Francis Beaudetf585c611999-04-02 10:37:42 +00002511 descr->item_height = lphc->fixedOwnerDrawHeight;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002512 }
2513 else
2514 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002515 UINT id = (UINT)GetWindowLongPtrW( descr->self, GWLP_ID );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002516 mis.CtlType = ODT_LISTBOX;
Alexandre Julliardde424282001-08-10 22:51:42 +00002517 mis.CtlID = id;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002518 mis.itemID = -1;
2519 mis.itemWidth = 0;
2520 mis.itemData = 0;
2521 mis.itemHeight = descr->item_height;
Alexandre Julliardde424282001-08-10 22:51:42 +00002522 SendMessageW( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002523 descr->item_height = mis.itemHeight ? mis.itemHeight : 1;
2524 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002525 }
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002526
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00002527 TRACE("owner: %p, style: %08x, width: %d, height: %d\n", descr->owner, descr->style, descr->width, descr->height);
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002528 return TRUE;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002529}
2530
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002531
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002532/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002533 * LISTBOX_Destroy
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002534 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002535static BOOL LISTBOX_Destroy( LB_DESCR *descr )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002536{
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002537 LISTBOX_ResetContent( descr );
Alexandre Julliard5c377852005-09-12 12:20:38 +00002538 SetWindowLongPtrW( descr->self, 0, 0 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002539 HeapFree( GetProcessHeap(), 0, descr );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00002540 return TRUE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002541}
2542
2543
2544/***********************************************************************
Alexandre Julliardde424282001-08-10 22:51:42 +00002545 * ListBoxWndProc_common
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002546 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002547static LRESULT WINAPI ListBoxWndProc_common( HWND hwnd, UINT msg,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002548 WPARAM wParam, LPARAM lParam, BOOL unicode )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002549{
Alexandre Julliard5c377852005-09-12 12:20:38 +00002550 LB_DESCR *descr = (LB_DESCR *)GetWindowLongPtrW( hwnd, 0 );
Dimitrie O. Paun134560e2004-10-18 21:22:44 +00002551 LPHEADCOMBO lphc = 0;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002552 LRESULT ret;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002553
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002554 if (!descr)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002555 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002556 if (!IsWindow(hwnd)) return 0;
2557
Bill Medlande79f0762001-07-17 00:55:23 +00002558 if (msg == WM_CREATE)
2559 {
Dimitrie O. Paun134560e2004-10-18 21:22:44 +00002560 CREATESTRUCTW *lpcs = (CREATESTRUCTW *)lParam;
2561 if (lpcs->style & LBS_COMBOBOX) lphc = (LPHEADCOMBO)lpcs->lpCreateParams;
2562 if (!LISTBOX_Create( hwnd, lphc )) return -1;
Alexandre Julliard5c377852005-09-12 12:20:38 +00002563 TRACE("creating wnd=%p descr=%lx\n", hwnd, GetWindowLongPtrW( hwnd, 0 ) );
Bill Medlande79f0762001-07-17 00:55:23 +00002564 return 0;
2565 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002566 /* Ignore all other messages before we get a WM_CREATE */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002567 return unicode ? DefWindowProcW( hwnd, msg, wParam, lParam ) :
2568 DefWindowProcA( hwnd, msg, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002569 }
Dimitrie O. Paun134560e2004-10-18 21:22:44 +00002570 if (descr->style & LBS_COMBOBOX) lphc = descr->lphc;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002571
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00002572 TRACE("[%p]: msg %s wp %08x lp %08lx\n",
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002573 descr->self, SPY_GetMsgName(msg, descr->self), wParam, lParam );
Dimitrie O. Paun134560e2004-10-18 21:22:44 +00002574
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002575 switch(msg)
2576 {
2577 case LB_RESETCONTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002578 case LB_RESETCONTENT:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002579 LISTBOX_ResetContent( descr );
2580 LISTBOX_UpdateScroll( descr );
2581 InvalidateRect( descr->self, NULL, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002582 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002583
2584 case LB_ADDSTRING16:
Alexandre Julliard982a2232000-12-13 20:20:09 +00002585 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002586 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002587 case LB_ADDSTRING:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002588 {
2589 INT ret;
2590 LPWSTR textW;
2591 if(unicode || !HAS_STRINGS(descr))
2592 textW = (LPWSTR)lParam;
2593 else
2594 {
2595 LPSTR textA = (LPSTR)lParam;
2596 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2597 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2598 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2599 }
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002600 wParam = LISTBOX_FindStringPos( descr, textW, FALSE );
2601 ret = LISTBOX_InsertString( descr, wParam, textW );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002602 if (!unicode && HAS_STRINGS(descr))
2603 HeapFree(GetProcessHeap(), 0, textW);
2604 return ret;
2605 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002606
2607 case LB_INSERTSTRING16:
Alexandre Julliard982a2232000-12-13 20:20:09 +00002608 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002609 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002610 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002611 case LB_INSERTSTRING:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002612 {
2613 INT ret;
2614 LPWSTR textW;
2615 if(unicode || !HAS_STRINGS(descr))
2616 textW = (LPWSTR)lParam;
2617 else
2618 {
2619 LPSTR textA = (LPSTR)lParam;
2620 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2621 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2622 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2623 }
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002624 ret = LISTBOX_InsertString( descr, wParam, textW );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002625 if(!unicode && HAS_STRINGS(descr))
2626 HeapFree(GetProcessHeap(), 0, textW);
2627 return ret;
2628 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002629
2630 case LB_ADDFILE16:
Alexandre Julliard982a2232000-12-13 20:20:09 +00002631 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002632 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002633 case LB_ADDFILE:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002634 {
2635 INT ret;
2636 LPWSTR textW;
2637 if(unicode || !HAS_STRINGS(descr))
2638 textW = (LPWSTR)lParam;
2639 else
2640 {
2641 LPSTR textA = (LPSTR)lParam;
2642 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2643 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2644 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2645 }
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002646 wParam = LISTBOX_FindFileStrPos( descr, textW );
2647 ret = LISTBOX_InsertString( descr, wParam, textW );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002648 if(!unicode && HAS_STRINGS(descr))
2649 HeapFree(GetProcessHeap(), 0, textW);
2650 return ret;
2651 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002652
2653 case LB_DELETESTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002654 case LB_DELETESTRING:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002655 if (LISTBOX_RemoveItem( descr, wParam) != LB_ERR)
Robert Shearman30ff9402005-07-12 18:11:40 +00002656 return descr->nb_items;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002657 else
Robert Shearman30ff9402005-07-12 18:11:40 +00002658 {
2659 SetLastError(ERROR_INVALID_INDEX);
2660 return LB_ERR;
2661 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002662
2663 case LB_GETITEMDATA16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002664 case LB_GETITEMDATA:
2665 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Robert Shearman30ff9402005-07-12 18:11:40 +00002666 {
2667 SetLastError(ERROR_INVALID_INDEX);
Marcus Meissner9aded511999-05-01 10:23:45 +00002668 return LB_ERR;
Robert Shearman30ff9402005-07-12 18:11:40 +00002669 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002670 return descr->items[wParam].data;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002671
2672 case LB_SETITEMDATA16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002673 case LB_SETITEMDATA:
2674 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Robert Shearman30ff9402005-07-12 18:11:40 +00002675 {
2676 SetLastError(ERROR_INVALID_INDEX);
Marcus Meissner9aded511999-05-01 10:23:45 +00002677 return LB_ERR;
Robert Shearman30ff9402005-07-12 18:11:40 +00002678 }
Alexandre Julliard556a1292005-09-12 15:36:39 +00002679 descr->items[wParam].data = lParam;
Marcus Meissner9aded511999-05-01 10:23:45 +00002680 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002681
2682 case LB_GETCOUNT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002683 case LB_GETCOUNT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002684 return descr->nb_items;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002685
2686 case LB_GETTEXT16:
Alexandre Julliard982a2232000-12-13 20:20:09 +00002687 lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002688 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002689 case LB_GETTEXT:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002690 return LISTBOX_GetText( descr, wParam, (LPWSTR)lParam, unicode );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002691
2692 case LB_GETTEXTLEN16:
2693 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002694 case LB_GETTEXTLEN:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002695 if ((INT)wParam >= descr->nb_items || (INT)wParam < 0)
Robert Shearman30ff9402005-07-12 18:11:40 +00002696 {
2697 SetLastError(ERROR_INVALID_INDEX);
Marcus Meissner9aded511999-05-01 10:23:45 +00002698 return LB_ERR;
Robert Shearman30ff9402005-07-12 18:11:40 +00002699 }
Alexandre Julliard741325b2002-06-13 19:20:43 +00002700 if (!HAS_STRINGS(descr)) return sizeof(DWORD);
2701 if (unicode) return strlenW( descr->items[wParam].str );
2702 return WideCharToMultiByte( CP_ACP, 0, descr->items[wParam].str,
2703 strlenW(descr->items[wParam].str), NULL, 0, NULL, NULL );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002704
2705 case LB_GETCURSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002706 case LB_GETCURSEL:
Jon Griffiths7a9e8002004-10-05 22:31:00 +00002707 if (descr->nb_items == 0)
2708 return LB_ERR;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002709 if (!IS_MULTISELECT(descr))
Jon Griffiths7a9e8002004-10-05 22:31:00 +00002710 return descr->selected_item;
2711 if (descr->selected_item != -1)
2712 return descr->selected_item;
2713 return descr->focus_item;
Lawson Whitney613092a1999-03-22 14:46:43 +00002714 /* otherwise, if the user tries to move the selection with the */
2715 /* arrow keys, we will give the application something to choke on */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002716 case LB_GETTOPINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002717 case LB_GETTOPINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002718 return descr->top_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002719
2720 case LB_GETITEMHEIGHT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002721 case LB_GETITEMHEIGHT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002722 return LISTBOX_GetItemHeight( descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002723
2724 case LB_SETITEMHEIGHT16:
2725 lParam = LOWORD(lParam);
2726 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002727 case LB_SETITEMHEIGHT:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002728 return LISTBOX_SetItemHeight( descr, wParam, lParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002729
Alexandre Julliarda3960291999-02-26 11:11:13 +00002730 case LB_ITEMFROMPOINT:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002731 {
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002732 POINT pt;
2733 RECT rect;
2734
2735 pt.x = LOWORD(lParam);
2736 pt.y = HIWORD(lParam);
2737 rect.left = 0;
2738 rect.top = 0;
2739 rect.right = descr->width;
2740 rect.bottom = descr->height;
2741
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002742 return MAKELONG( LISTBOX_GetItemFromPoint(descr, pt.x, pt.y),
Gerard Patel777508a1999-05-08 12:35:17 +00002743 !PtInRect( &rect, pt ) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002744 }
2745
2746 case LB_SETCARETINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002747 case LB_SETCARETINDEX:
Gerard Patelc9a6d501999-07-25 13:03:17 +00002748 if ((!IS_MULTISELECT(descr)) && (descr->selected_item != -1)) return LB_ERR;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002749 if (LISTBOX_SetCaretIndex( descr, wParam, !lParam ) == LB_ERR)
Gerard Patelc9a6d501999-07-25 13:03:17 +00002750 return LB_ERR;
2751 else if (ISWIN31)
2752 return wParam;
2753 else
2754 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002755
2756 case LB_GETCARETINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002757 case LB_GETCARETINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002758 return descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002759
2760 case LB_SETTOPINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002761 case LB_SETTOPINDEX:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002762 return LISTBOX_SetTopItem( descr, wParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002763
2764 case LB_SETCOLUMNWIDTH16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002765 case LB_SETCOLUMNWIDTH:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002766 return LISTBOX_SetColumnWidth( descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002767
2768 case LB_GETITEMRECT16:
2769 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002770 RECT rect;
Alexandre Julliard3c39a992004-08-31 00:02:02 +00002771 RECT16 *r16 = MapSL(lParam);
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002772 ret = LISTBOX_GetItemRect( descr, (INT16)wParam, &rect );
Alexandre Julliard3c39a992004-08-31 00:02:02 +00002773 r16->left = rect.left;
2774 r16->top = rect.top;
2775 r16->right = rect.right;
2776 r16->bottom = rect.bottom;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002777 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002778 return ret;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002779
Alexandre Julliarda3960291999-02-26 11:11:13 +00002780 case LB_GETITEMRECT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002781 return LISTBOX_GetItemRect( descr, wParam, (RECT *)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002782
2783 case LB_FINDSTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002784 wParam = (INT)(INT16)wParam;
Alexandre Julliard982a2232000-12-13 20:20:09 +00002785 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002786 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002787 case LB_FINDSTRING:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002788 {
2789 INT ret;
2790 LPWSTR textW;
2791 if(unicode || !HAS_STRINGS(descr))
2792 textW = (LPWSTR)lParam;
2793 else
2794 {
2795 LPSTR textA = (LPSTR)lParam;
2796 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2797 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2798 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2799 }
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002800 ret = LISTBOX_FindString( descr, wParam, textW, FALSE );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002801 if(!unicode && HAS_STRINGS(descr))
2802 HeapFree(GetProcessHeap(), 0, textW);
2803 return ret;
2804 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002805
2806 case LB_FINDSTRINGEXACT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002807 wParam = (INT)(INT16)wParam;
Alexandre Julliard982a2232000-12-13 20:20:09 +00002808 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002809 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002810 case LB_FINDSTRINGEXACT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002811 {
2812 INT ret;
2813 LPWSTR textW;
2814 if(unicode || !HAS_STRINGS(descr))
2815 textW = (LPWSTR)lParam;
2816 else
2817 {
2818 LPSTR textA = (LPSTR)lParam;
2819 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2820 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2821 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2822 }
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002823 ret = LISTBOX_FindString( descr, wParam, textW, TRUE );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002824 if(!unicode && HAS_STRINGS(descr))
2825 HeapFree(GetProcessHeap(), 0, textW);
2826 return ret;
2827 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002828
2829 case LB_SELECTSTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002830 wParam = (INT)(INT16)wParam;
Alexandre Julliard982a2232000-12-13 20:20:09 +00002831 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002832 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002833 case LB_SELECTSTRING:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002834 {
2835 INT index;
2836 LPWSTR textW;
Dmitry Timoshkove8ffcaa2001-04-16 19:32:19 +00002837
2838 if(HAS_STRINGS(descr))
2839 TRACE("LB_SELECTSTRING: %s\n", unicode ? debugstr_w((LPWSTR)lParam) :
2840 debugstr_a((LPSTR)lParam));
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002841 if(unicode || !HAS_STRINGS(descr))
2842 textW = (LPWSTR)lParam;
2843 else
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002844 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002845 LPSTR textA = (LPSTR)lParam;
2846 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2847 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2848 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002849 }
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002850 index = LISTBOX_FindString( descr, wParam, textW, FALSE );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002851 if(!unicode && HAS_STRINGS(descr))
2852 HeapFree(GetProcessHeap(), 0, textW);
2853 if (index != LB_ERR)
Dmitry Timoshkove8ffcaa2001-04-16 19:32:19 +00002854 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002855 LISTBOX_MoveCaret( descr, index, TRUE );
2856 LISTBOX_SetSelection( descr, index, TRUE, FALSE );
Dmitry Timoshkove8ffcaa2001-04-16 19:32:19 +00002857 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002858 return index;
2859 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002860
2861 case LB_GETSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002862 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002863 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002864 case LB_GETSEL:
2865 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002866 return LB_ERR;
2867 return descr->items[wParam].selected;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002868
2869 case LB_SETSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002870 lParam = (INT)(INT16)lParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002871 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002872 case LB_SETSEL:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002873 return LISTBOX_SetSelection( descr, lParam, wParam, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002874
2875 case LB_SETCURSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002876 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002877 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002878 case LB_SETCURSEL:
Gerard Patelc9a6d501999-07-25 13:03:17 +00002879 if (IS_MULTISELECT(descr)) return LB_ERR;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002880 LISTBOX_SetCaretIndex( descr, wParam, TRUE );
2881 ret = LISTBOX_SetSelection( descr, wParam, TRUE, FALSE );
Dimitrie O. Paun134560e2004-10-18 21:22:44 +00002882 if (lphc && ret != LB_ERR) ret = descr->selected_item;
2883 return ret;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002884
2885 case LB_GETSELCOUNT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002886 case LB_GETSELCOUNT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002887 return LISTBOX_GetSelCount( descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002888
2889 case LB_GETSELITEMS16:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002890 return LISTBOX_GetSelItems16( descr, wParam, (LPINT16)MapSL(lParam) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002891
Alexandre Julliarda3960291999-02-26 11:11:13 +00002892 case LB_GETSELITEMS:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002893 return LISTBOX_GetSelItems( descr, wParam, (LPINT)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002894
2895 case LB_SELITEMRANGE16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002896 case LB_SELITEMRANGE:
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002897 if (LOWORD(lParam) <= HIWORD(lParam))
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002898 return LISTBOX_SelectItemRange( descr, LOWORD(lParam),
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002899 HIWORD(lParam), wParam );
2900 else
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002901 return LISTBOX_SelectItemRange( descr, HIWORD(lParam),
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002902 LOWORD(lParam), wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002903
2904 case LB_SELITEMRANGEEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002905 case LB_SELITEMRANGEEX:
2906 if ((INT)lParam >= (INT)wParam)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002907 return LISTBOX_SelectItemRange( descr, wParam, lParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002908 else
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002909 return LISTBOX_SelectItemRange( descr, lParam, wParam, FALSE);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002910
2911 case LB_GETHORIZONTALEXTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002912 case LB_GETHORIZONTALEXTENT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002913 return descr->horz_extent;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002914
2915 case LB_SETHORIZONTALEXTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002916 case LB_SETHORIZONTALEXTENT:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002917 return LISTBOX_SetHorizontalExtent( descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002918
2919 case LB_GETANCHORINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002920 case LB_GETANCHORINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002921 return descr->anchor_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002922
2923 case LB_SETANCHORINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002924 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002925 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002926 case LB_SETANCHORINDEX:
2927 if (((INT)wParam < -1) || ((INT)wParam >= descr->nb_items))
Robert Shearman30ff9402005-07-12 18:11:40 +00002928 {
2929 SetLastError(ERROR_INVALID_INDEX);
Marcus Meissner9aded511999-05-01 10:23:45 +00002930 return LB_ERR;
Robert Shearman30ff9402005-07-12 18:11:40 +00002931 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00002932 descr->anchor_item = (INT)wParam;
Marcus Meissner9aded511999-05-01 10:23:45 +00002933 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002934
2935 case LB_DIR16:
Ove Kaaven2c691b32000-11-25 03:06:03 +00002936 /* according to Win16 docs, DDL_DRIVES should make DDL_EXCLUSIVE
2937 * be set automatically (this is different in Win32) */
2938 if (wParam & DDL_DRIVES) wParam |= DDL_EXCLUSIVE;
Jon Griffiths7a9e8002004-10-05 22:31:00 +00002939 lParam = (LPARAM)MapSL(lParam);
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002940 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002941 case LB_DIR:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002942 {
2943 INT ret;
2944 LPWSTR textW;
2945 if(unicode)
2946 textW = (LPWSTR)lParam;
2947 else
2948 {
2949 LPSTR textA = (LPSTR)lParam;
2950 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2951 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2952 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2953 }
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002954 ret = LISTBOX_Directory( descr, wParam, textW, msg == LB_DIR );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002955 if(!unicode)
2956 HeapFree(GetProcessHeap(), 0, textW);
2957 return ret;
2958 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002959
Alexandre Julliarda3960291999-02-26 11:11:13 +00002960 case LB_GETLOCALE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002961 return descr->locale;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002962
Alexandre Julliarda3960291999-02-26 11:11:13 +00002963 case LB_SETLOCALE:
Robert Shearman7dd1d212005-07-12 17:55:35 +00002964 {
2965 LCID ret;
2966 if (!IsValidLocale((LCID)wParam, LCID_INSTALLED))
2967 return LB_ERR;
2968 ret = descr->locale;
2969 descr->locale = (LCID)wParam;
2970 return ret;
2971 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002972
Alexandre Julliarda3960291999-02-26 11:11:13 +00002973 case LB_INITSTORAGE:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002974 return LISTBOX_InitStorage( descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002975
Alexandre Julliarda3960291999-02-26 11:11:13 +00002976 case LB_SETCOUNT:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002977 return LISTBOX_SetCount( descr, (INT)wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002978
2979 case LB_SETTABSTOPS16:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002980 return LISTBOX_SetTabStops( descr, (INT)(INT16)wParam, MapSL(lParam), TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002981
Alexandre Julliarda3960291999-02-26 11:11:13 +00002982 case LB_SETTABSTOPS:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002983 return LISTBOX_SetTabStops( descr, wParam, (LPINT)lParam, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002984
2985 case LB_CARETON16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002986 case LB_CARETON:
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002987 if (descr->caret_on)
Marcus Meissner9aded511999-05-01 10:23:45 +00002988 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002989 descr->caret_on = TRUE;
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002990 if ((descr->focus_item != -1) && (descr->in_focus))
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00002991 LISTBOX_RepaintItem( descr, descr->focus_item, ODA_FOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002992 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002993
2994 case LB_CARETOFF16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002995 case LB_CARETOFF:
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002996 if (!descr->caret_on)
Marcus Meissner9aded511999-05-01 10:23:45 +00002997 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002998 descr->caret_on = FALSE;
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002999 if ((descr->focus_item != -1) && (descr->in_focus))
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003000 LISTBOX_RepaintItem( descr, descr->focus_item, ODA_FOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00003001 return LB_OKAY;
Alexandre Julliardde424282001-08-10 22:51:42 +00003002
Dmitry Timoshkov26b40c22005-10-27 18:28:23 +00003003 case LB_GETLISTBOXINFO:
3004 FIXME("LB_GETLISTBOXINFO: stub!\n");
3005 return 0;
3006
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003007 case WM_DESTROY:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003008 return LISTBOX_Destroy( descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003009
3010 case WM_ENABLE:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003011 InvalidateRect( descr->self, NULL, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00003012 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003013
3014 case WM_SETREDRAW:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003015 LISTBOX_SetRedraw( descr, wParam != 0 );
Marcus Meissner9aded511999-05-01 10:23:45 +00003016 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003017
3018 case WM_GETDLGCODE:
Marcus Meissner9aded511999-05-01 10:23:45 +00003019 return DLGC_WANTARROWS | DLGC_WANTCHARS;
3020
Michael Kaufmanne9310da2005-11-08 12:52:35 +00003021 case WM_PRINTCLIENT:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003022 case WM_PAINT:
3023 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00003024 PAINTSTRUCT ps;
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003025 HDC hdc = ( wParam ) ? ((HDC)wParam) : BeginPaint( descr->self, &ps );
3026 ret = LISTBOX_Paint( descr, hdc );
3027 if( !wParam ) EndPaint( descr->self, &ps );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003028 }
Marcus Meissner9aded511999-05-01 10:23:45 +00003029 return ret;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003030 case WM_SIZE:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003031 LISTBOX_UpdateSize( descr );
Marcus Meissner9aded511999-05-01 10:23:45 +00003032 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003033 case WM_GETFONT:
Michael Stefaniuc95591a62002-10-28 20:11:40 +00003034 return (LRESULT)descr->font;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003035 case WM_SETFONT:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003036 LISTBOX_SetFont( descr, (HFONT)wParam );
3037 if (lParam) InvalidateRect( descr->self, 0, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00003038 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003039 case WM_SETFOCUS:
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00003040 descr->in_focus = TRUE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003041 descr->caret_on = TRUE;
3042 if (descr->focus_item != -1)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003043 LISTBOX_RepaintItem( descr, descr->focus_item, ODA_FOCUS );
3044 SEND_NOTIFICATION( descr, LBN_SETFOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00003045 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003046 case WM_KILLFOCUS:
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00003047 descr->in_focus = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003048 if ((descr->focus_item != -1) && descr->caret_on)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003049 LISTBOX_RepaintItem( descr, descr->focus_item, ODA_FOCUS );
3050 SEND_NOTIFICATION( descr, LBN_KILLFOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00003051 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003052 case WM_HSCROLL:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003053 return LISTBOX_HandleHScroll( descr, LOWORD(wParam), HIWORD(wParam) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003054 case WM_VSCROLL:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003055 return LISTBOX_HandleVScroll( descr, LOWORD(wParam), HIWORD(wParam) );
Stephane Lussier4bdf4af2000-04-18 11:56:33 +00003056 case WM_MOUSEWHEEL:
3057 if (wParam & (MK_SHIFT | MK_CONTROL))
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003058 return DefWindowProcW( descr->self, msg, wParam, lParam );
3059 return LISTBOX_HandleMouseWheel( descr, (SHORT)HIWORD(wParam) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003060 case WM_LBUTTONDOWN:
Dimitrie O. Paun134560e2004-10-18 21:22:44 +00003061 if (lphc)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003062 return LISTBOX_HandleLButtonDownCombo(descr, msg, wParam,
Dimitrie O. Paun134560e2004-10-18 21:22:44 +00003063 (INT16)LOWORD(lParam),
3064 (INT16)HIWORD(lParam) );
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003065 return LISTBOX_HandleLButtonDown( descr, wParam,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003066 (INT16)LOWORD(lParam),
3067 (INT16)HIWORD(lParam) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003068 case WM_LBUTTONDBLCLK:
Dimitrie O. Paun134560e2004-10-18 21:22:44 +00003069 if (lphc)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003070 return LISTBOX_HandleLButtonDownCombo(descr, msg, wParam,
Dimitrie O. Paun134560e2004-10-18 21:22:44 +00003071 (INT16)LOWORD(lParam),
3072 (INT16)HIWORD(lParam) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003073 if (descr->style & LBS_NOTIFY)
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003074 SEND_NOTIFICATION( descr, LBN_DBLCLK );
Marcus Meissner9aded511999-05-01 10:23:45 +00003075 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003076 case WM_MOUSEMOVE:
Dimitrie O. Paun134560e2004-10-18 21:22:44 +00003077 if ( lphc && ((lphc->dwStyle & CBS_DROPDOWNLIST) != CBS_SIMPLE) )
3078 {
3079 BOOL captured = descr->captured;
3080 POINT mousePos;
3081 RECT clientRect;
3082
3083 mousePos.x = (INT16)LOWORD(lParam);
3084 mousePos.y = (INT16)HIWORD(lParam);
3085
3086 /*
3087 * If we are in a dropdown combobox, we simulate that
3088 * the mouse is captured to show the tracking of the item.
3089 */
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003090 if (GetClientRect(descr->self, &clientRect) && PtInRect( &clientRect, mousePos ))
Dimitrie O. Paun134560e2004-10-18 21:22:44 +00003091 descr->captured = TRUE;
3092
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003093 LISTBOX_HandleMouseMove( descr, mousePos.x, mousePos.y);
Dimitrie O. Paun134560e2004-10-18 21:22:44 +00003094
3095 descr->captured = captured;
3096 }
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003097 else if (GetCapture() == descr->self)
Dimitrie O. Paun134560e2004-10-18 21:22:44 +00003098 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003099 LISTBOX_HandleMouseMove( descr, (INT16)LOWORD(lParam),
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003100 (INT16)HIWORD(lParam) );
Dimitrie O. Paun134560e2004-10-18 21:22:44 +00003101 }
Marcus Meissner9aded511999-05-01 10:23:45 +00003102 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003103 case WM_LBUTTONUP:
Dimitrie O. Paun134560e2004-10-18 21:22:44 +00003104 if (lphc)
3105 {
3106 POINT mousePos;
3107 RECT clientRect;
3108
3109 /*
3110 * If the mouse button "up" is not in the listbox,
3111 * we make sure there is no selection by re-selecting the
3112 * item that was selected when the listbox was made visible.
3113 */
3114 mousePos.x = (INT16)LOWORD(lParam);
3115 mousePos.y = (INT16)HIWORD(lParam);
3116
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003117 GetClientRect(descr->self, &clientRect);
Dimitrie O. Paun134560e2004-10-18 21:22:44 +00003118
3119 /*
3120 * When the user clicks outside the combobox and the focus
3121 * is lost, the owning combobox will send a fake buttonup with
3122 * 0xFFFFFFF as the mouse location, we must also revert the
3123 * selection to the original selection.
3124 */
3125 if ( (lParam == (LPARAM)-1) || (!PtInRect( &clientRect, mousePos )) )
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003126 LISTBOX_MoveCaret( descr, lphc->droppedIndex, FALSE );
Dimitrie O. Paun134560e2004-10-18 21:22:44 +00003127 }
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003128 return LISTBOX_HandleLButtonUp( descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003129 case WM_KEYDOWN:
Dimitrie O. Paun134560e2004-10-18 21:22:44 +00003130 if( lphc && (lphc->dwStyle & CBS_DROPDOWNLIST) != CBS_SIMPLE )
3131 {
3132 /* for some reason Windows makes it possible to
3133 * show/hide ComboLBox by sending it WM_KEYDOWNs */
3134
3135 if( (!(lphc->wState & CBF_EUI) && wParam == VK_F4) ||
3136 ( (lphc->wState & CBF_EUI) && !(lphc->wState & CBF_DROPPED)
3137 && (wParam == VK_DOWN || wParam == VK_UP)) )
3138 {
3139 COMBO_FlipListbox( lphc, FALSE, FALSE );
3140 return 0;
3141 }
3142 }
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003143 return LISTBOX_HandleKeyDown( descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003144 case WM_CHAR:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003145 {
3146 WCHAR charW;
3147 if(unicode)
3148 charW = (WCHAR)wParam;
3149 else
3150 {
3151 CHAR charA = (CHAR)wParam;
3152 MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1);
3153 }
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003154 return LISTBOX_HandleChar( descr, charW );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003155 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003156 case WM_SYSTIMER:
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003157 return LISTBOX_HandleSystemTimer( descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003158 case WM_ERASEBKGND:
Gerard Patel41b07fb2000-06-15 00:07:20 +00003159 if ((IS_OWNERDRAW(descr)) && !(descr->style & LBS_DISPLAYCHANGED))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003160 {
Luc Tourangeau89147991999-04-18 09:23:56 +00003161 RECT rect;
Michael Stefaniuc95591a62002-10-28 20:11:40 +00003162 HBRUSH hbrush = (HBRUSH)SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003163 wParam, (LPARAM)descr->self );
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003164 TRACE("hbrush = %p\n", hbrush);
Dmitry Timoshkov52ece0e2001-02-26 22:31:55 +00003165 if(!hbrush)
3166 hbrush = GetSysColorBrush(COLOR_WINDOW);
3167 if(hbrush)
3168 {
Dimitrie O. Paune89adaa2004-10-26 22:03:00 +00003169 GetClientRect(descr->self, &rect);
Dmitry Timoshkov52ece0e2001-02-26 22:31:55 +00003170 FillRect((HDC)wParam, &rect, hbrush);
3171 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003172 }
Marcus Meissner9aded511999-05-01 10:23:45 +00003173 return 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003174 case WM_DROPFILES:
Dimitrie O. Paun134560e2004-10-18 21:22:44 +00003175 if( lphc ) return 0;
3176 return unicode ? SendMessageW( descr->owner, msg, wParam, lParam ) :
3177 SendMessageA( descr->owner, msg, wParam, lParam );
3178
3179 case WM_NCDESTROY:
3180 if( lphc && (lphc->dwStyle & CBS_DROPDOWNLIST) != CBS_SIMPLE )
3181 lphc->hWndLBox = 0;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003182 break;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003183
Dimitrie O. Paun134560e2004-10-18 21:22:44 +00003184 case WM_NCACTIVATE:
3185 if (lphc) return 0;
3186 break;
3187
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003188 default:
3189 if ((msg >= WM_USER) && (msg < 0xc000))
Alexandre Julliardaff7dda2002-11-22 21:22:14 +00003190 WARN("[%p]: unknown msg %04x wp %08x lp %08lx\n",
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003191 hwnd, msg, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003192 }
Dimitrie O. Paun134560e2004-10-18 21:22:44 +00003193
3194 return unicode ? DefWindowProcW( hwnd, msg, wParam, lParam ) :
3195 DefWindowProcA( hwnd, msg, wParam, lParam );
Marcus Meissner9aded511999-05-01 10:23:45 +00003196}
3197
3198/***********************************************************************
Alexandre Julliard91222da2000-12-10 23:01:33 +00003199 * ListBoxWndProcA
Marcus Meissner9aded511999-05-01 10:23:45 +00003200 */
Alexandre Julliard91222da2000-12-10 23:01:33 +00003201static LRESULT WINAPI ListBoxWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
Marcus Meissner9aded511999-05-01 10:23:45 +00003202{
Alexandre Julliardde424282001-08-10 22:51:42 +00003203 return ListBoxWndProc_common( hwnd, msg, wParam, lParam, FALSE );
Alexandre Julliard58199531994-04-21 01:20:00 +00003204}
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003205
3206/***********************************************************************
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003207 * ListBoxWndProcW
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003208 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003209static LRESULT WINAPI ListBoxWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003210{
Alexandre Julliardde424282001-08-10 22:51:42 +00003211 return ListBoxWndProc_common( hwnd, msg, wParam, lParam, TRUE );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003212}