blob: 951f548357a126502e6274f01b2f7d505ea6b112 [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
18 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
Alexandre Julliard2787be81995-05-22 18:23:01 +000019 */
20
Alexandre Julliarde2abbb11995-03-19 17:39:39 +000021#include <string.h>
David Luyeree517e81999-02-28 12:27:56 +000022#include <stdlib.h>
Jeremy Whited3e22d92000-02-10 19:03:02 +000023#include <stdio.h>
24#include "windef.h"
25#include "wingdi.h"
Alex Korobka311d3291999-01-01 18:40:02 +000026#include "wine/winuser16.h"
Nick Hollowayb9ce4fd1999-09-11 16:29:00 +000027#include "wine/winbase16.h"
Dmitry Timoshkov74620992001-01-09 21:51:04 +000028#include "wine/unicode.h"
Alex Korobka311d3291999-01-01 18:40:02 +000029#include "winuser.h"
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000030#include "winerror.h"
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000031#include "spy.h"
Alexandre Julliarda41b2cf2001-01-15 20:12:55 +000032#include "user.h"
Alexandre Julliard91222da2000-12-10 23:01:33 +000033#include "controls.h"
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000034#include "wine/debug.h"
Alexandre Julliard0e607781993-11-03 19:23:37 +000035
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000036WINE_DEFAULT_DEBUG_CHANNEL(listbox);
37WINE_DECLARE_DEBUG_CHANNEL(combo);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000038
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000039/* Unimplemented yet:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000040 * - LBS_USETABSTOPS
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000041 * - Locale handling
Andreas Mohr85ba8792001-01-06 00:34:14 +000042 *
43 * Probably needs improvement:
44 * - LBS_NOSEL
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000045 */
Alexandre Julliarde2abbb11995-03-19 17:39:39 +000046
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000047/* Items array granularity */
48#define LB_ARRAY_GRANULARITY 16
Alexandre Julliard0e607781993-11-03 19:23:37 +000049
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000050/* Scrolling timeout in ms */
51#define LB_SCROLL_TIMEOUT 50
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000052
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000053/* Listbox system timer id */
54#define LB_TIMER_ID 2
Alexandre Julliardac9c9b01996-07-28 18:50:11 +000055
Gerard Patel41b07fb2000-06-15 00:07:20 +000056/* flag listbox changed while setredraw false - internal style */
Alexandre Julliardde424282001-08-10 22:51:42 +000057#define LBS_DISPLAYCHANGED 0x80000000
Gerard Patel41b07fb2000-06-15 00:07:20 +000058
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000059/* Item structure */
60typedef struct
Alexandre Julliard2787be81995-05-22 18:23:01 +000061{
Dmitry Timoshkov74620992001-01-09 21:51:04 +000062 LPWSTR str; /* Item text */
Alexandre Julliarda3960291999-02-26 11:11:13 +000063 BOOL selected; /* Is item selected? */
64 UINT height; /* Item height (only for OWNERDRAWVARIABLE) */
Dmitry Timoshkov74620992001-01-09 21:51:04 +000065 DWORD data; /* User data */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000066} LB_ITEMDATA;
Alexandre Julliard2787be81995-05-22 18:23:01 +000067
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000068/* Listbox structure */
69typedef struct
Alexandre Julliard2787be81995-05-22 18:23:01 +000070{
Alexandre Julliarda3960291999-02-26 11:11:13 +000071 HWND owner; /* Owner window to send notifications to */
72 UINT style; /* Window style */
73 INT width; /* Window width */
74 INT height; /* Window height */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000075 LB_ITEMDATA *items; /* Array of items */
Alexandre Julliarda3960291999-02-26 11:11:13 +000076 INT nb_items; /* Number of items */
77 INT top_item; /* Top visible item */
78 INT selected_item; /* Selected item */
79 INT focus_item; /* Item that has the focus */
80 INT anchor_item; /* Anchor item for extended selection */
81 INT item_height; /* Default item height */
82 INT page_size; /* Items per listbox page */
83 INT column_width; /* Column width for multi-column listboxes */
84 INT horz_extent; /* Horizontal extent (0 if no hscroll) */
85 INT horz_pos; /* Horizontal position */
86 INT nb_tabs; /* Number of tabs in array */
87 INT *tabs; /* Array of tabs */
88 BOOL caret_on; /* Is caret on? */
Luc Tourangeau5ee117b1999-04-04 12:48:21 +000089 BOOL captured; /* Is mouse captured? */
Alexandre Julliardab2f43f2000-05-26 22:28:34 +000090 BOOL in_focus;
Alexandre Julliarda3960291999-02-26 11:11:13 +000091 HFONT font; /* Current font */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000092 LCID locale; /* Current locale for string comparisons */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000093 LPHEADCOMBO lphc; /* ComboLBox */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000094} LB_DESCR;
Alexandre Julliard2787be81995-05-22 18:23:01 +000095
Alexandre Julliardfa68b751995-04-03 16:55:37 +000096
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000097#define IS_OWNERDRAW(descr) \
98 ((descr)->style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE))
Alexandre Julliardb817f4f1996-03-14 18:08:34 +000099
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000100#define HAS_STRINGS(descr) \
101 (!IS_OWNERDRAW(descr) || ((descr)->style & LBS_HASSTRINGS))
Alexandre Julliard2787be81995-05-22 18:23:01 +0000102
Gerard Patelc9a6d501999-07-25 13:03:17 +0000103
104#define IS_MULTISELECT(descr) \
105 ((descr)->style & LBS_MULTIPLESEL || ((descr)->style & LBS_EXTENDEDSEL))
106
Alexandre Julliardde424282001-08-10 22:51:42 +0000107#define SEND_NOTIFICATION(hwnd,descr,code) \
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000108 (SendMessageW( (descr)->owner, WM_COMMAND, \
Alexandre Julliardde424282001-08-10 22:51:42 +0000109 MAKEWPARAM( GetWindowLongA((hwnd),GWL_ID), (code)), (hwnd) ))
Alexandre Julliardfa68b751995-04-03 16:55:37 +0000110
Gerard Patelc9a6d501999-07-25 13:03:17 +0000111#define ISWIN31 (LOWORD(GetVersion()) == 0x0a03)
112
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000113/* Current timer status */
114typedef enum
Alexandre Julliardfa68b751995-04-03 16:55:37 +0000115{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000116 LB_TIMER_NONE,
117 LB_TIMER_UP,
118 LB_TIMER_LEFT,
119 LB_TIMER_DOWN,
120 LB_TIMER_RIGHT
121} TIMER_DIRECTION;
Alexandre Julliardfa68b751995-04-03 16:55:37 +0000122
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000123static TIMER_DIRECTION LISTBOX_Timer = LB_TIMER_NONE;
124
Alexandre Julliard91222da2000-12-10 23:01:33 +0000125static LRESULT WINAPI ComboLBWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000126static LRESULT WINAPI ComboLBWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
Alexandre Julliard91222da2000-12-10 23:01:33 +0000127static LRESULT WINAPI ListBoxWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000128static LRESULT WINAPI ListBoxWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
Alexandre Julliard91222da2000-12-10 23:01:33 +0000129
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000130static LRESULT LISTBOX_GetItemRect( LB_DESCR *descr, INT index, RECT *rect );
Alexandre Julliard91222da2000-12-10 23:01:33 +0000131
132/*********************************************************************
133 * listbox class descriptor
134 */
135const struct builtin_class_descr LISTBOX_builtin_class =
136{
137 "ListBox", /* name */
138 CS_GLOBALCLASS | CS_DBLCLKS /*| CS_PARENTDC*/, /* style */
139 ListBoxWndProcA, /* procA */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000140 ListBoxWndProcW, /* procW */
Alexandre Julliard91222da2000-12-10 23:01:33 +0000141 sizeof(LB_DESCR *), /* extra */
142 IDC_ARROWA, /* cursor */
143 0 /* brush */
144};
145
146
147/*********************************************************************
148 * combolbox class descriptor
149 */
150const struct builtin_class_descr COMBOLBOX_builtin_class =
151{
152 "ComboLBox", /* name */
153 CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS, /* style */
154 ComboLBWndProcA, /* procA */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000155 ComboLBWndProcW, /* procW */
Alexandre Julliard91222da2000-12-10 23:01:33 +0000156 sizeof(LB_DESCR *), /* extra */
157 IDC_ARROWA, /* cursor */
158 0 /* brush */
159};
160
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000161
Alexandre Julliardde424282001-08-10 22:51:42 +0000162/* check whether app is a Win 3.1 app */
163inline static BOOL is_old_app( HWND hwnd )
164{
165 return (GetExpWinVer16( GetWindowLongA(hwnd,GWL_HINSTANCE) ) & 0xFF00 ) == 0x0300;
166}
167
168
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000169/***********************************************************************
170 * LISTBOX_Dump
171 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000172void LISTBOX_Dump( HWND hwnd )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000173{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000174 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000175 LB_ITEMDATA *item;
Alexandre Julliardde424282001-08-10 22:51:42 +0000176 LB_DESCR *descr = (LB_DESCR *)GetWindowLongA( hwnd, 0 );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000177
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000178 TRACE( "Listbox:\n" );
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000179 TRACE( "hwnd=%04x descr=%08x items=%d top=%d\n",
Alexandre Julliardde424282001-08-10 22:51:42 +0000180 hwnd, (UINT)descr, descr->nb_items,
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000181 descr->top_item );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000182 for (i = 0, item = descr->items; i < descr->nb_items; i++, item++)
183 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000184 TRACE( "%4d: %-40s %d %08lx %3d\n",
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000185 i, debugstr_w(item->str), item->selected, item->data, item->height );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000186 }
Alexandre Julliard2787be81995-05-22 18:23:01 +0000187}
188
189
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000190/***********************************************************************
191 * LISTBOX_GetCurrentPageSize
192 *
193 * Return the current page size
194 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000195static INT LISTBOX_GetCurrentPageSize( LB_DESCR *descr )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000196{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000197 INT i, height;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000198 if (!(descr->style & LBS_OWNERDRAWVARIABLE)) return descr->page_size;
199 for (i = descr->top_item, height = 0; i < descr->nb_items; i++)
200 {
201 if ((height += descr->items[i].height) > descr->height) break;
202 }
203 if (i == descr->top_item) return 1;
204 else return i - descr->top_item;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000205}
206
207
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000208/***********************************************************************
209 * LISTBOX_GetMaxTopIndex
210 *
211 * Return the maximum possible index for the top of the listbox.
212 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000213static INT LISTBOX_GetMaxTopIndex( LB_DESCR *descr )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000214{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000215 INT max, page;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000216
217 if (descr->style & LBS_OWNERDRAWVARIABLE)
218 {
219 page = descr->height;
220 for (max = descr->nb_items - 1; max >= 0; max--)
221 if ((page -= descr->items[max].height) < 0) break;
222 if (max < descr->nb_items - 1) max++;
223 }
224 else if (descr->style & LBS_MULTICOLUMN)
225 {
226 if ((page = descr->width / descr->column_width) < 1) page = 1;
227 max = (descr->nb_items + descr->page_size - 1) / descr->page_size;
228 max = (max - page) * descr->page_size;
229 }
230 else
231 {
232 max = descr->nb_items - descr->page_size;
233 }
234 if (max < 0) max = 0;
235 return max;
236}
237
238
239/***********************************************************************
240 * LISTBOX_UpdateScroll
241 *
242 * Update the scrollbars. Should be called whenever the content
243 * of the listbox changes.
244 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000245static void LISTBOX_UpdateScroll( HWND hwnd, LB_DESCR *descr )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000246{
247 SCROLLINFO info;
248
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000249 /* Check the listbox scroll bar flags individually before we call
250 SetScrollInfo otherwise when the listbox style is WS_HSCROLL and
251 no WS_VSCROLL, we end up with an uninitialized, visible horizontal
252 scroll bar when we do not need one.
253 if (!(descr->style & WS_VSCROLL)) return;
Alexandre Julliardde424282001-08-10 22:51:42 +0000254 */
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000255
Vincent BĂ©ron9a624912002-05-31 23:06:46 +0000256 /* It is important that we check descr->style, and not wnd->dwStyle,
257 for WS_VSCROLL, as the former is exactly the one passed in
258 argument to CreateWindow.
259 In Windows (and from now on in Wine :) a listbox created
260 with such a style (no WS_SCROLL) does not update
261 the scrollbar with listbox-related data, thus letting
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000262 the programmer use it for his/her own purposes. */
263
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000264 if (descr->style & LBS_NOREDRAW) return;
265 info.cbSize = sizeof(info);
266
267 if (descr->style & LBS_MULTICOLUMN)
268 {
269 info.nMin = 0;
270 info.nMax = (descr->nb_items - 1) / descr->page_size;
271 info.nPos = descr->top_item / descr->page_size;
272 info.nPage = descr->width / descr->column_width;
273 if (info.nPage < 1) info.nPage = 1;
274 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_HSCROLL)
Alexandre Julliardde424282001-08-10 22:51:42 +0000278 SetScrollInfo( hwnd, SB_HORZ, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000279 info.nMax = 0;
280 info.fMask = SIF_RANGE;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000281 if (descr->style & WS_VSCROLL)
Alexandre Julliardde424282001-08-10 22:51:42 +0000282 SetScrollInfo( hwnd, SB_VERT, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000283 }
284 else
285 {
286 info.nMin = 0;
287 info.nMax = descr->nb_items - 1;
288 info.nPos = descr->top_item;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000289 info.nPage = LISTBOX_GetCurrentPageSize( descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000290 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
291 if (descr->style & LBS_DISABLENOSCROLL)
292 info.fMask |= SIF_DISABLENOSCROLL;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000293 if (descr->style & WS_VSCROLL)
Alexandre Julliardde424282001-08-10 22:51:42 +0000294 SetScrollInfo( hwnd, SB_VERT, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000295
296 if (descr->horz_extent)
297 {
298 info.nMin = 0;
299 info.nMax = descr->horz_extent - 1;
300 info.nPos = descr->horz_pos;
301 info.nPage = descr->width;
302 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
303 if (descr->style & LBS_DISABLENOSCROLL)
304 info.fMask |= SIF_DISABLENOSCROLL;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000305 if (descr->style & WS_HSCROLL)
Alexandre Julliardde424282001-08-10 22:51:42 +0000306 SetScrollInfo( hwnd, SB_HORZ, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000307 }
308 }
309}
310
311
312/***********************************************************************
313 * LISTBOX_SetTopItem
314 *
315 * Set the top item of the listbox, scrolling up or down if necessary.
316 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000317static LRESULT LISTBOX_SetTopItem( HWND hwnd, LB_DESCR *descr, INT index,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000318 BOOL scroll )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000319{
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000320 INT max = LISTBOX_GetMaxTopIndex( descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000321 if (index > max) index = max;
322 if (index < 0) index = 0;
323 if (descr->style & LBS_MULTICOLUMN) index -= index % descr->page_size;
324 if (descr->top_item == index) return LB_OKAY;
325 if (descr->style & LBS_MULTICOLUMN)
326 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000327 INT diff = (descr->top_item - index) / descr->page_size * descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000328 if (scroll && (abs(diff) < descr->width))
Alexandre Julliardde424282001-08-10 22:51:42 +0000329 ScrollWindowEx( hwnd, diff, 0, NULL, NULL, 0, NULL,
NF Stevens762f18d1999-01-24 19:02:16 +0000330 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
331
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000332 else
333 scroll = FALSE;
334 }
335 else if (scroll)
336 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000337 INT diff;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000338 if (descr->style & LBS_OWNERDRAWVARIABLE)
339 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000340 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000341 diff = 0;
342 if (index > descr->top_item)
343 {
344 for (i = index - 1; i >= descr->top_item; i--)
345 diff -= descr->items[i].height;
346 }
347 else
348 {
349 for (i = index; i < descr->top_item; i++)
350 diff += descr->items[i].height;
351 }
352 }
Alexandre Julliardde424282001-08-10 22:51:42 +0000353 else
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000354 diff = (descr->top_item - index) * descr->item_height;
355
356 if (abs(diff) < descr->height)
Alexandre Julliardde424282001-08-10 22:51:42 +0000357 ScrollWindowEx( hwnd, 0, diff, NULL, NULL, 0, NULL,
NF Stevens762f18d1999-01-24 19:02:16 +0000358 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000359 else
360 scroll = FALSE;
361 }
Alexandre Julliardde424282001-08-10 22:51:42 +0000362 if (!scroll) InvalidateRect( hwnd, NULL, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000363 descr->top_item = index;
Alexandre Julliardde424282001-08-10 22:51:42 +0000364 LISTBOX_UpdateScroll( hwnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000365 return LB_OKAY;
366}
367
368
369/***********************************************************************
370 * LISTBOX_UpdatePage
371 *
372 * Update the page size. Should be called when the size of
373 * the client area or the item height changes.
374 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000375static void LISTBOX_UpdatePage( HWND hwnd, LB_DESCR *descr )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000376{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000377 INT page_size;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000378
Alexandre Julliardde424282001-08-10 22:51:42 +0000379 if ((descr->item_height == 0) || (page_size = descr->height / descr->item_height) < 1)
Paul Quinn75722071999-05-22 18:45:06 +0000380 page_size = 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000381 if (page_size == descr->page_size) return;
382 descr->page_size = page_size;
383 if (descr->style & LBS_MULTICOLUMN)
Alexandre Julliardde424282001-08-10 22:51:42 +0000384 InvalidateRect( hwnd, NULL, TRUE );
385 LISTBOX_SetTopItem( hwnd, descr, descr->top_item, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000386}
387
388
389/***********************************************************************
390 * LISTBOX_UpdateSize
391 *
392 * Update the size of the listbox. Should be called when the size of
393 * the client area changes.
394 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000395static void LISTBOX_UpdateSize( HWND hwnd, LB_DESCR *descr )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000396{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000397 RECT rect;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000398
Alexandre Julliardde424282001-08-10 22:51:42 +0000399 GetClientRect( hwnd, &rect );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000400 descr->width = rect.right - rect.left;
401 descr->height = rect.bottom - rect.top;
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +0000402 if (!(descr->style & LBS_NOINTEGRALHEIGHT) && !(descr->style & LBS_OWNERDRAWVARIABLE))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000403 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000404 INT remaining;
Alexandre Julliardde424282001-08-10 22:51:42 +0000405 RECT rect;
Mike McCormack5ae1c392000-09-09 19:39:24 +0000406
Alexandre Julliardde424282001-08-10 22:51:42 +0000407 GetWindowRect( hwnd, &rect );
Mike McCormack5ae1c392000-09-09 19:39:24 +0000408 if(descr->item_height != 0)
409 remaining = descr->height % descr->item_height;
410 else
411 remaining = 0;
Gerard Patelcef12532000-08-01 20:48:40 +0000412 if ((descr->height > descr->item_height) && remaining)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000413 {
Alexandre Julliardde424282001-08-10 22:51:42 +0000414 if (is_old_app(hwnd))
Gerard Patelcef12532000-08-01 20:48:40 +0000415 { /* give a margin for error to 16 bits programs - if we need
416 less than the height of the nonclient area, round to the
Alexandre Julliardde424282001-08-10 22:51:42 +0000417 *next* number of items */
418 int ncheight = rect.bottom - rect.top - descr->height;
Gerard Patelcef12532000-08-01 20:48:40 +0000419 if ((descr->item_height - remaining) <= ncheight)
420 remaining = remaining - descr->item_height;
421 }
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000422 TRACE("[%04x]: changing height %d -> %d\n",
Alexandre Julliardde424282001-08-10 22:51:42 +0000423 hwnd, descr->height, descr->height - remaining );
424 SetWindowPos( hwnd, 0, 0, 0, rect.right - rect.left,
425 rect.bottom - rect.top - remaining,
Alexandre Julliard01d63461997-01-20 19:43:45 +0000426 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000427 return;
428 }
429 }
Alexandre Julliardde424282001-08-10 22:51:42 +0000430 TRACE("[%04x]: new size = %d,%d\n", hwnd, descr->width, descr->height );
431 LISTBOX_UpdatePage( hwnd, descr );
432 LISTBOX_UpdateScroll( hwnd, descr );
Louis Philippe Gagnon956c8472000-12-13 21:26:45 +0000433
434 /* Invalidate the focused item so it will be repainted correctly */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000435 if (LISTBOX_GetItemRect( descr, descr->focus_item, &rect ) == 1)
Louis Philippe Gagnon956c8472000-12-13 21:26:45 +0000436 {
Alexandre Julliardde424282001-08-10 22:51:42 +0000437 InvalidateRect( hwnd, &rect, FALSE );
Louis Philippe Gagnon956c8472000-12-13 21:26:45 +0000438 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000439}
440
441
442/***********************************************************************
443 * LISTBOX_GetItemRect
444 *
445 * Get the rectangle enclosing an item, in listbox client coordinates.
446 * Return 1 if the rectangle is (partially) visible, 0 if hidden, -1 on error.
447 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000448static LRESULT LISTBOX_GetItemRect( LB_DESCR *descr, INT index, RECT *rect )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000449{
450 /* Index <= 0 is legal even on empty listboxes */
451 if (index && (index >= descr->nb_items)) return -1;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000452 SetRect( rect, 0, 0, descr->width, descr->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000453 if (descr->style & LBS_MULTICOLUMN)
454 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000455 INT col = (index / descr->page_size) -
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000456 (descr->top_item / descr->page_size);
457 rect->left += col * descr->column_width;
458 rect->right = rect->left + descr->column_width;
459 rect->top += (index % descr->page_size) * descr->item_height;
460 rect->bottom = rect->top + descr->item_height;
461 }
462 else if (descr->style & LBS_OWNERDRAWVARIABLE)
463 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000464 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000465 rect->right += descr->horz_pos;
Alexandre Julliard349a9531997-02-02 19:01:52 +0000466 if ((index >= 0) && (index < descr->nb_items))
467 {
468 if (index < descr->top_item)
469 {
470 for (i = descr->top_item-1; i >= index; i--)
471 rect->top -= descr->items[i].height;
472 }
473 else
474 {
475 for (i = descr->top_item; i < index; i++)
476 rect->top += descr->items[i].height;
477 }
478 rect->bottom = rect->top + descr->items[index].height;
479
480 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000481 }
482 else
483 {
484 rect->top += (index - descr->top_item) * descr->item_height;
485 rect->bottom = rect->top + descr->item_height;
486 rect->right += descr->horz_pos;
487 }
488
489 return ((rect->left < descr->width) && (rect->right > 0) &&
490 (rect->top < descr->height) && (rect->bottom > 0));
491}
492
493
494/***********************************************************************
495 * LISTBOX_GetItemFromPoint
496 *
497 * Return the item nearest from point (x,y) (in client coordinates).
498 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000499static INT LISTBOX_GetItemFromPoint( LB_DESCR *descr, INT x, INT y )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000500{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000501 INT index = descr->top_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000502
503 if (!descr->nb_items) return -1; /* No items */
504 if (descr->style & LBS_OWNERDRAWVARIABLE)
505 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000506 INT pos = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000507 if (y >= 0)
508 {
509 while (index < descr->nb_items)
510 {
511 if ((pos += descr->items[index].height) > y) break;
512 index++;
513 }
514 }
515 else
516 {
517 while (index > 0)
518 {
519 index--;
520 if ((pos -= descr->items[index].height) <= y) break;
521 }
522 }
523 }
524 else if (descr->style & LBS_MULTICOLUMN)
525 {
526 if (y >= descr->item_height * descr->page_size) return -1;
527 if (y >= 0) index += y / descr->item_height;
528 if (x >= 0) index += (x / descr->column_width) * descr->page_size;
529 else index -= (((x + 1) / descr->column_width) - 1) * descr->page_size;
530 }
531 else
532 {
533 index += (y / descr->item_height);
534 }
535 if (index < 0) return 0;
536 if (index >= descr->nb_items) return -1;
537 return index;
538}
539
540
541/***********************************************************************
542 * LISTBOX_PaintItem
543 *
544 * Paint an item.
545 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000546static void LISTBOX_PaintItem( HWND hwnd, LB_DESCR *descr, HDC hdc,
Gerard Patel8caa4072000-09-24 19:29:18 +0000547 const RECT *rect, INT index, UINT action, BOOL ignoreFocus )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000548{
549 LB_ITEMDATA *item = NULL;
550 if (index < descr->nb_items) item = &descr->items[index];
551
552 if (IS_OWNERDRAW(descr))
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000553 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000554 DRAWITEMSTRUCT dis;
Gerard Patel9788ba62000-07-16 15:39:37 +0000555 RECT r;
556 HRGN hrgn;
Alexandre Julliardde424282001-08-10 22:51:42 +0000557 UINT id = GetWindowLongA( hwnd, GWL_ID );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000558
Marcus Meissner9ad90171999-01-20 14:08:00 +0000559 if (!item)
560 {
Alexandre Julliardde424282001-08-10 22:51:42 +0000561 if (action == ODA_FOCUS)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000562 DrawFocusRect( hdc, rect );
Marcus Meissner9ad90171999-01-20 14:08:00 +0000563 else
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000564 FIXME("called with an out of bounds index %d(%d) in owner draw, Not good.\n",index,descr->nb_items);
Marcus Meissner9ad90171999-01-20 14:08:00 +0000565 return;
566 }
Gerard Patel9788ba62000-07-16 15:39:37 +0000567
568 /* some programs mess with the clipping region when
569 drawing the item, *and* restore the previous region
570 after they are done, so a region has better to exist
571 else everything ends clipped */
Alexandre Julliardde424282001-08-10 22:51:42 +0000572 GetClientRect(hwnd, &r);
Gerard Patel9788ba62000-07-16 15:39:37 +0000573 hrgn = CreateRectRgnIndirect(&r);
574 SelectClipRgn( hdc, hrgn);
575 DeleteObject( hrgn );
576
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000577 dis.CtlType = ODT_LISTBOX;
Alexandre Julliardde424282001-08-10 22:51:42 +0000578 dis.CtlID = id;
579 dis.hwndItem = hwnd;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000580 dis.itemAction = action;
581 dis.hDC = hdc;
582 dis.itemID = index;
583 dis.itemState = 0;
584 if (item && item->selected) dis.itemState |= ODS_SELECTED;
Gerard Patel8caa4072000-09-24 19:29:18 +0000585 if (!ignoreFocus && (descr->focus_item == index) &&
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000586 (descr->caret_on) &&
Alexandre Julliardab2f43f2000-05-26 22:28:34 +0000587 (descr->in_focus)) dis.itemState |= ODS_FOCUS;
Alexandre Julliardde424282001-08-10 22:51:42 +0000588 if (!IsWindowEnabled(hwnd)) dis.itemState |= ODS_DISABLED;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000589 dis.itemData = item ? item->data : 0;
590 dis.rcItem = *rect;
Alexandre Julliardde424282001-08-10 22:51:42 +0000591 TRACE("[%04x]: drawitem %d (%s) action=%02x state=%02x rect=%d,%d-%d,%d\n",
592 hwnd, index, item ? debugstr_w(item->str) : "", action,
593 dis.itemState, rect->left, rect->top, rect->right, rect->bottom );
594 SendMessageW(descr->owner, WM_DRAWITEM, id, (LPARAM)&dis);
Alexandre Julliard2787be81995-05-22 18:23:01 +0000595 }
596 else
Alexandre Julliardac9c9b01996-07-28 18:50:11 +0000597 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000598 COLORREF oldText = 0, oldBk = 0;
599
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000600 if (action == ODA_FOCUS)
601 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000602 DrawFocusRect( hdc, rect );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000603 return;
604 }
605 if (item && item->selected)
606 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000607 oldBk = SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
608 oldText = SetTextColor( hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000609 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000610
Alexandre Julliardde424282001-08-10 22:51:42 +0000611 TRACE("[%04x]: painting %d (%s) action=%02x rect=%d,%d-%d,%d\n",
612 hwnd, index, item ? debugstr_w(item->str) : "", action,
613 rect->left, rect->top, rect->right, rect->bottom );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000614 if (!item)
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000615 ExtTextOutW( hdc, rect->left + 1, rect->top,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000616 ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000617 else if (!(descr->style & LBS_USETABSTOPS))
618 ExtTextOutW( hdc, rect->left + 1, rect->top,
619 ETO_OPAQUE | ETO_CLIPPED, rect, item->str,
620 strlenW(item->str), NULL );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000621 else
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000622 {
623 /* Output empty string to paint background in the full width. */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000624 ExtTextOutW( hdc, rect->left + 1, rect->top,
625 ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
626 TabbedTextOutW( hdc, rect->left + 1 , rect->top,
627 item->str, strlenW(item->str),
628 descr->nb_tabs, descr->tabs, 0);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000629 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000630 if (item && item->selected)
631 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000632 SetBkColor( hdc, oldBk );
633 SetTextColor( hdc, oldText );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000634 }
Gerard Patel8caa4072000-09-24 19:29:18 +0000635 if (!ignoreFocus && (descr->focus_item == index) &&
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000636 (descr->caret_on) &&
Alexandre Julliardab2f43f2000-05-26 22:28:34 +0000637 (descr->in_focus)) DrawFocusRect( hdc, rect );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000638 }
Alexandre Julliard2787be81995-05-22 18:23:01 +0000639}
640
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000641
642/***********************************************************************
643 * LISTBOX_SetRedraw
644 *
645 * Change the redraw flag.
646 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000647static void LISTBOX_SetRedraw( HWND hwnd, LB_DESCR *descr, BOOL on )
Alexandre Julliardac9c9b01996-07-28 18:50:11 +0000648{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000649 if (on)
650 {
651 if (!(descr->style & LBS_NOREDRAW)) return;
652 descr->style &= ~LBS_NOREDRAW;
Gerard Patel41b07fb2000-06-15 00:07:20 +0000653 if (descr->style & LBS_DISPLAYCHANGED)
654 { /* page was changed while setredraw false, refresh automatically */
Alexandre Julliardde424282001-08-10 22:51:42 +0000655 InvalidateRect(hwnd, NULL, TRUE);
Gerard Patel41b07fb2000-06-15 00:07:20 +0000656 if ((descr->top_item + descr->page_size) > descr->nb_items)
Alexandre Julliardde424282001-08-10 22:51:42 +0000657 { /* reset top of page if less than number of items/page */
Gerard Patel41b07fb2000-06-15 00:07:20 +0000658 descr->top_item = descr->nb_items - descr->page_size;
659 if (descr->top_item < 0) descr->top_item = 0;
660 }
661 descr->style &= ~LBS_DISPLAYCHANGED;
662 }
Alexandre Julliardde424282001-08-10 22:51:42 +0000663 LISTBOX_UpdateScroll( hwnd, descr );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000664 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000665 else descr->style |= LBS_NOREDRAW;
666}
Alexandre Julliard2787be81995-05-22 18:23:01 +0000667
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000668
669/***********************************************************************
670 * LISTBOX_RepaintItem
671 *
672 * Repaint a single item synchronously.
673 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000674static void LISTBOX_RepaintItem( HWND hwnd, LB_DESCR *descr, INT index,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000675 UINT action )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000676{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000677 HDC hdc;
678 RECT rect;
679 HFONT oldFont = 0;
680 HBRUSH hbrush, oldBrush = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000681
Francois Boisvert428d2981999-05-08 09:33:53 +0000682 /* Do not repaint the item if the item is not visible */
Alexandre Julliardde424282001-08-10 22:51:42 +0000683 if (!IsWindowVisible(hwnd)) return;
Gerard Patel41b07fb2000-06-15 00:07:20 +0000684 if (descr->style & LBS_NOREDRAW)
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000685 {
Gerard Patel41b07fb2000-06-15 00:07:20 +0000686 descr->style |= LBS_DISPLAYCHANGED;
687 return;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000688 }
689 if (LISTBOX_GetItemRect( descr, index, &rect ) != 1) return;
Alexandre Julliardde424282001-08-10 22:51:42 +0000690 if (!(hdc = GetDCEx( hwnd, 0, DCX_CACHE ))) return;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000691 if (descr->font) oldFont = SelectObject( hdc, descr->font );
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000692 hbrush = SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
Alexandre Julliardde424282001-08-10 22:51:42 +0000693 hdc, (LPARAM)hwnd );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000694 if (hbrush) oldBrush = SelectObject( hdc, hbrush );
Alexandre Julliardde424282001-08-10 22:51:42 +0000695 if (!IsWindowEnabled(hwnd))
Alexandre Julliarda3960291999-02-26 11:11:13 +0000696 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
697 SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
Alexandre Julliardde424282001-08-10 22:51:42 +0000698 LISTBOX_PaintItem( hwnd, descr, hdc, &rect, index, action, FALSE );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000699 if (oldFont) SelectObject( hdc, oldFont );
700 if (oldBrush) SelectObject( hdc, oldBrush );
Alexandre Julliardde424282001-08-10 22:51:42 +0000701 ReleaseDC( hwnd, hdc );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000702}
703
704
705/***********************************************************************
706 * LISTBOX_InitStorage
707 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000708static LRESULT LISTBOX_InitStorage( HWND hwnd, LB_DESCR *descr, INT nb_items )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000709{
710 LB_ITEMDATA *item;
711
712 nb_items += LB_ARRAY_GRANULARITY - 1;
713 nb_items -= (nb_items % LB_ARRAY_GRANULARITY);
714 if (descr->items)
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000715 nb_items += HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(*item);
716 if (!(item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000717 nb_items * sizeof(LB_ITEMDATA) )))
718 {
Alexandre Julliardde424282001-08-10 22:51:42 +0000719 SEND_NOTIFICATION( hwnd, descr, LBN_ERRSPACE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000720 return LB_ERRSPACE;
721 }
722 descr->items = item;
723 return LB_OKAY;
724}
725
726
727/***********************************************************************
728 * LISTBOX_SetTabStops
729 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000730static BOOL LISTBOX_SetTabStops( HWND hwnd, LB_DESCR *descr, INT count,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000731 LPINT tabs, BOOL short_ints )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000732{
733 if (!(descr->style & LBS_USETABSTOPS)) return TRUE;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000734 if (descr->tabs) HeapFree( GetProcessHeap(), 0, descr->tabs );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000735 if (!(descr->nb_tabs = count))
736 {
737 descr->tabs = NULL;
738 return TRUE;
739 }
740 /* FIXME: count = 1 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000741 if (!(descr->tabs = (INT *)HeapAlloc( GetProcessHeap(), 0,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000742 descr->nb_tabs * sizeof(INT) )))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000743 return FALSE;
744 if (short_ints)
745 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000746 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000747 LPINT16 p = (LPINT16)tabs;
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000748
Alexandre Julliardde424282001-08-10 22:51:42 +0000749 TRACE("[%04x]: settabstops ", hwnd );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000750 for (i = 0; i < descr->nb_tabs; i++) {
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000751 descr->tabs[i] = *p++<<1; /* FIXME */
Alexandre Julliard15de6151999-08-04 12:22:42 +0000752 if (TRACE_ON(listbox)) DPRINTF("%hd ", descr->tabs[i]);
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000753 }
Alexandre Julliard15de6151999-08-04 12:22:42 +0000754 if (TRACE_ON(listbox)) DPRINTF("\n");
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000755 }
Alexandre Julliarda3960291999-02-26 11:11:13 +0000756 else memcpy( descr->tabs, tabs, descr->nb_tabs * sizeof(INT) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000757 /* FIXME: repaint the window? */
Alexandre Julliard2787be81995-05-22 18:23:01 +0000758 return TRUE;
759}
760
761
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000762/***********************************************************************
763 * LISTBOX_GetText
764 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000765static LRESULT LISTBOX_GetText( LB_DESCR *descr, INT index, LPARAM lParam, BOOL unicode )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000766{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000767 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
768 if (HAS_STRINGS(descr))
769 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000770 if (!lParam)
771 return strlenW(descr->items[index].str);
772
Dmitry Timoshkove8ffcaa2001-04-16 19:32:19 +0000773 TRACE("index %d (0x%04x) %s\n", index, index, debugstr_w(descr->items[index].str));
774
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000775 if(unicode)
776 {
777 LPWSTR buffer = (LPWSTR)lParam;
778 strcpyW( buffer, descr->items[index].str );
779 return strlenW(buffer);
780 }
781 else
782 {
783 LPSTR buffer = (LPSTR)lParam;
Gerard Pateldb8fb6f2001-01-10 23:54:46 +0000784 return WideCharToMultiByte(CP_ACP, 0, descr->items[index].str, -1, buffer, 0x7FFFFFFF, NULL, NULL) - 1;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000785 }
Marcus Meissner4f7dc461998-11-22 15:43:34 +0000786 } else {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000787 if (lParam)
788 *((LPDWORD)lParam)=*(LPDWORD)(&descr->items[index].data);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000789 return sizeof(DWORD);
790 }
Alexandre Julliard2787be81995-05-22 18:23:01 +0000791}
792
793
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000794/***********************************************************************
795 * LISTBOX_FindStringPos
796 *
797 * Find the nearest string located before a given string in sort order.
798 * If 'exact' is TRUE, return an error if we don't get an exact match.
799 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000800static INT LISTBOX_FindStringPos( HWND hwnd, LB_DESCR *descr, LPCWSTR str,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000801 BOOL exact )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000802{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000803 INT index, min, max, res = -1;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000804
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000805 if (!(descr->style & LBS_SORT)) return -1; /* Add it at the end */
806 min = 0;
807 max = descr->nb_items;
808 while (min != max)
809 {
810 index = (min + max) / 2;
811 if (HAS_STRINGS(descr))
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000812 res = lstrcmpiW( descr->items[index].str, str );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000813 else
814 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000815 COMPAREITEMSTRUCT cis;
Alexandre Julliardde424282001-08-10 22:51:42 +0000816 UINT id = GetWindowLongA( hwnd, GWL_ID );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000817
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000818 cis.CtlType = ODT_LISTBOX;
Alexandre Julliardde424282001-08-10 22:51:42 +0000819 cis.CtlID = id;
820 cis.hwndItem = hwnd;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000821 cis.itemID1 = index;
822 cis.itemData1 = descr->items[index].data;
823 cis.itemID2 = -1;
824 cis.itemData2 = (DWORD)str;
825 cis.dwLocaleId = descr->locale;
Alexandre Julliardde424282001-08-10 22:51:42 +0000826 res = SendMessageW( descr->owner, WM_COMPAREITEM, id, (LPARAM)&cis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000827 }
828 if (!res) return index;
829 if (res > 0) max = index;
830 else min = index + 1;
831 }
832 return exact ? -1 : max;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000833}
834
835
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000836/***********************************************************************
837 * LISTBOX_FindFileStrPos
838 *
839 * Find the nearest string located before a given string in directory
840 * sort order (i.e. first files, then directories, then drives).
841 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000842static INT LISTBOX_FindFileStrPos( HWND hwnd, LB_DESCR *descr, LPCWSTR str )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000843{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000844 INT min, max, res = -1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000845
846 if (!HAS_STRINGS(descr))
Alexandre Julliardde424282001-08-10 22:51:42 +0000847 return LISTBOX_FindStringPos( hwnd, descr, str, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000848 min = 0;
849 max = descr->nb_items;
850 while (min != max)
851 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000852 INT index = (min + max) / 2;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000853 LPCWSTR p = descr->items[index].str;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000854 if (*p == '[') /* drive or directory */
855 {
856 if (*str != '[') res = -1;
857 else if (p[1] == '-') /* drive */
858 {
859 if (str[1] == '-') res = str[2] - p[2];
860 else res = -1;
861 }
862 else /* directory */
863 {
864 if (str[1] == '-') res = 1;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000865 else res = lstrcmpiW( str, p );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000866 }
867 }
868 else /* filename */
869 {
870 if (*str == '[') res = 1;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000871 else res = lstrcmpiW( str, p );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000872 }
873 if (!res) return index;
874 if (res < 0) max = index;
875 else min = index + 1;
876 }
877 return max;
878}
879
880
881/***********************************************************************
882 * LISTBOX_FindString
883 *
884 * Find the item beginning with a given string.
885 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000886static INT LISTBOX_FindString( HWND hwnd, LB_DESCR *descr, INT start,
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000887 LPCWSTR str, BOOL exact )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000888{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000889 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000890 LB_ITEMDATA *item;
891
892 if (start >= descr->nb_items) start = -1;
893 item = descr->items + start + 1;
894 if (HAS_STRINGS(descr))
895 {
Rein Klazesd35c8341999-08-21 13:04:58 +0000896 if (!str || ! str[0] ) return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000897 if (exact)
898 {
899 for (i = start + 1; i < descr->nb_items; i++, item++)
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000900 if (!lstrcmpiW( str, item->str )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000901 for (i = 0, item = descr->items; i <= start; i++, item++)
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000902 if (!lstrcmpiW( str, item->str )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000903 }
904 else
905 {
906 /* Special case for drives and directories: ignore prefix */
907#define CHECK_DRIVE(item) \
908 if ((item)->str[0] == '[') \
909 { \
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000910 if (!strncmpiW( str, (item)->str+1, len )) return i; \
911 if (((item)->str[1] == '-') && !strncmpiW(str, (item)->str+2, len)) \
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000912 return i; \
913 }
914
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000915 INT len = strlenW(str);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000916 for (i = start + 1; i < descr->nb_items; i++, item++)
917 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000918 if (!strncmpiW( str, item->str, len )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000919 CHECK_DRIVE(item);
920 }
921 for (i = 0, item = descr->items; i <= start; i++, item++)
922 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000923 if (!strncmpiW( str, item->str, len )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000924 CHECK_DRIVE(item);
925 }
926#undef CHECK_DRIVE
927 }
928 }
929 else
930 {
931 if (exact && (descr->style & LBS_SORT))
932 /* If sorted, use a WM_COMPAREITEM binary search */
Alexandre Julliardde424282001-08-10 22:51:42 +0000933 return LISTBOX_FindStringPos( hwnd, descr, str, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000934
935 /* Otherwise use a linear search */
936 for (i = start + 1; i < descr->nb_items; i++, item++)
937 if (item->data == (DWORD)str) return i;
938 for (i = 0, item = descr->items; i <= start; i++, item++)
939 if (item->data == (DWORD)str) return i;
940 }
941 return LB_ERR;
942}
943
944
945/***********************************************************************
946 * LISTBOX_GetSelCount
947 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000948static LRESULT LISTBOX_GetSelCount( LB_DESCR *descr )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000949{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000950 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000951 LB_ITEMDATA *item = descr->items;
952
953 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
954 for (i = count = 0; i < descr->nb_items; i++, item++)
955 if (item->selected) count++;
956 return count;
957}
958
959
960/***********************************************************************
961 * LISTBOX_GetSelItems16
962 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000963static LRESULT LISTBOX_GetSelItems16( LB_DESCR *descr, INT16 max, LPINT16 array )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000964{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000965 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000966 LB_ITEMDATA *item = descr->items;
967
968 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
969 for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++)
970 if (item->selected) array[count++] = (INT16)i;
971 return count;
972}
973
974
975/***********************************************************************
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000976 * LISTBOX_GetSelItems
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000977 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000978static LRESULT LISTBOX_GetSelItems( LB_DESCR *descr, INT max, LPINT array )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000979{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000980 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000981 LB_ITEMDATA *item = descr->items;
982
983 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
984 for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++)
985 if (item->selected) array[count++] = i;
986 return count;
987}
988
989
990/***********************************************************************
991 * LISTBOX_Paint
992 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000993static LRESULT LISTBOX_Paint( HWND hwnd, LB_DESCR *descr, HDC hdc )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000994{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000995 INT i, col_pos = descr->page_size - 1;
996 RECT rect;
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +0000997 RECT focusRect = {-1, -1, -1, -1};
Alexandre Julliarda3960291999-02-26 11:11:13 +0000998 HFONT oldFont = 0;
999 HBRUSH hbrush, oldBrush = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001000
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001001 if (descr->style & LBS_NOREDRAW) return 0;
Serge Ivanov07917e42000-06-07 03:46:57 +00001002
1003 SetRect( &rect, 0, 0, descr->width, descr->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001004 if (descr->style & LBS_MULTICOLUMN)
1005 rect.right = rect.left + descr->column_width;
1006 else if (descr->horz_pos)
1007 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001008 SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001009 rect.right += descr->horz_pos;
1010 }
1011
Alexandre Julliarda3960291999-02-26 11:11:13 +00001012 if (descr->font) oldFont = SelectObject( hdc, descr->font );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001013 hbrush = SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
Alexandre Julliardde424282001-08-10 22:51:42 +00001014 hdc, (LPARAM)hwnd );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001015 if (hbrush) oldBrush = SelectObject( hdc, hbrush );
Alexandre Julliardde424282001-08-10 22:51:42 +00001016 if (!IsWindowEnabled(hwnd)) SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001017
1018 if (!descr->nb_items && (descr->focus_item != -1) && descr->caret_on &&
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00001019 (descr->in_focus))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001020 {
1021 /* Special case for empty listbox: paint focus rect */
1022 rect.bottom = rect.top + descr->item_height;
Alexandre Julliardde424282001-08-10 22:51:42 +00001023 LISTBOX_PaintItem( hwnd, descr, hdc, &rect, descr->focus_item,
Gerard Patel8caa4072000-09-24 19:29:18 +00001024 ODA_FOCUS, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001025 rect.top = rect.bottom;
1026 }
1027
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001028 /* Paint all the item, regarding the selection
1029 Focus state will be painted after */
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001030
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001031 for (i = descr->top_item; i < descr->nb_items; i++)
1032 {
1033 if (!(descr->style & LBS_OWNERDRAWVARIABLE))
1034 rect.bottom = rect.top + descr->item_height;
1035 else
1036 rect.bottom = rect.top + descr->items[i].height;
1037
Gerard Patel8caa4072000-09-24 19:29:18 +00001038 if (i == descr->focus_item)
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001039 {
1040 /* keep the focus rect, to paint the focus item after */
1041 focusRect.left = rect.left;
1042 focusRect.right = rect.right;
1043 focusRect.top = rect.top;
1044 focusRect.bottom = rect.bottom;
1045 }
Alexandre Julliardde424282001-08-10 22:51:42 +00001046 LISTBOX_PaintItem( hwnd, descr, hdc, &rect, i, ODA_DRAWENTIRE, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001047 rect.top = rect.bottom;
1048
1049 if ((descr->style & LBS_MULTICOLUMN) && !col_pos)
1050 {
1051 if (!IS_OWNERDRAW(descr))
1052 {
1053 /* Clear the bottom of the column */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001054 if (rect.top < descr->height)
1055 {
1056 rect.bottom = descr->height;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001057 ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001058 &rect, NULL, 0, NULL );
1059 }
1060 }
1061
1062 /* Go to the next column */
1063 rect.left += descr->column_width;
1064 rect.right += descr->column_width;
1065 rect.top = 0;
1066 col_pos = descr->page_size - 1;
1067 }
1068 else
1069 {
1070 col_pos--;
1071 if (rect.top >= descr->height) break;
1072 }
1073 }
1074
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001075 /* Paint the focus item now */
Serge Ivanov07917e42000-06-07 03:46:57 +00001076 if (focusRect.top != focusRect.bottom && descr->caret_on)
Alexandre Julliardde424282001-08-10 22:51:42 +00001077 LISTBOX_PaintItem( hwnd, descr, hdc, &focusRect, descr->focus_item, ODA_FOCUS, FALSE );
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001078
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001079 if (!IS_OWNERDRAW(descr))
1080 {
1081 /* Clear the remainder of the client area */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001082 if (rect.top < descr->height)
1083 {
1084 rect.bottom = descr->height;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001085 ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001086 &rect, NULL, 0, NULL );
1087 }
1088 if (rect.right < descr->width)
1089 {
1090 rect.left = rect.right;
1091 rect.right = descr->width;
1092 rect.top = 0;
1093 rect.bottom = descr->height;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001094 ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001095 &rect, NULL, 0, NULL );
1096 }
1097 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001098 if (oldFont) SelectObject( hdc, oldFont );
1099 if (oldBrush) SelectObject( hdc, oldBrush );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001100 return 0;
1101}
1102
1103
1104/***********************************************************************
1105 * LISTBOX_InvalidateItems
1106 *
1107 * Invalidate all items from a given item. If the specified item is not
1108 * visible, nothing happens.
1109 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001110static void LISTBOX_InvalidateItems( HWND hwnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001111{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001112 RECT rect;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001113
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001114 if (LISTBOX_GetItemRect( descr, index, &rect ) == 1)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001115 {
Gerard Patel41b07fb2000-06-15 00:07:20 +00001116 if (descr->style & LBS_NOREDRAW)
1117 {
1118 descr->style |= LBS_DISPLAYCHANGED;
1119 return;
1120 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001121 rect.bottom = descr->height;
Alexandre Julliardde424282001-08-10 22:51:42 +00001122 InvalidateRect( hwnd, &rect, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001123 if (descr->style & LBS_MULTICOLUMN)
1124 {
1125 /* Repaint the other columns */
1126 rect.left = rect.right;
1127 rect.right = descr->width;
1128 rect.top = 0;
Alexandre Julliardde424282001-08-10 22:51:42 +00001129 InvalidateRect( hwnd, &rect, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001130 }
1131 }
1132}
1133
1134
1135/***********************************************************************
1136 * LISTBOX_GetItemHeight
1137 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001138static LRESULT LISTBOX_GetItemHeight( LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001139{
1140 if (descr->style & LBS_OWNERDRAWVARIABLE)
1141 {
1142 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
1143 return descr->items[index].height;
1144 }
1145 else return descr->item_height;
1146}
1147
1148
1149/***********************************************************************
1150 * LISTBOX_SetItemHeight
1151 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001152static LRESULT LISTBOX_SetItemHeight( HWND hwnd, LB_DESCR *descr, INT index,
Alexandre Julliardc72a9aa2002-01-31 21:05:05 +00001153 INT height, BOOL repaint )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001154{
1155 if (!height) height = 1;
1156
1157 if (descr->style & LBS_OWNERDRAWVARIABLE)
1158 {
1159 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
Alexandre Julliardde424282001-08-10 22:51:42 +00001160 TRACE("[%04x]: item %d height = %d\n", hwnd, index, height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001161 descr->items[index].height = height;
Alexandre Julliardde424282001-08-10 22:51:42 +00001162 LISTBOX_UpdateScroll( hwnd, descr );
Alexandre Julliardc72a9aa2002-01-31 21:05:05 +00001163 if (repaint)
1164 LISTBOX_InvalidateItems( hwnd, descr, index );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001165 }
1166 else if (height != descr->item_height)
1167 {
Alexandre Julliardde424282001-08-10 22:51:42 +00001168 TRACE("[%04x]: new height = %d\n", hwnd, height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001169 descr->item_height = height;
Alexandre Julliardde424282001-08-10 22:51:42 +00001170 LISTBOX_UpdatePage( hwnd, descr );
1171 LISTBOX_UpdateScroll( hwnd, descr );
Alexandre Julliardc72a9aa2002-01-31 21:05:05 +00001172 if (repaint)
1173 InvalidateRect( hwnd, 0, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001174 }
1175 return LB_OKAY;
1176}
1177
1178
1179/***********************************************************************
1180 * LISTBOX_SetHorizontalPos
1181 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001182static void LISTBOX_SetHorizontalPos( HWND hwnd, LB_DESCR *descr, INT pos )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001183{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001184 INT diff;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001185
1186 if (pos > descr->horz_extent - descr->width)
1187 pos = descr->horz_extent - descr->width;
1188 if (pos < 0) pos = 0;
1189 if (!(diff = descr->horz_pos - pos)) return;
Alexandre Julliardde424282001-08-10 22:51:42 +00001190 TRACE("[%04x]: new horz pos = %d\n", hwnd, pos );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001191 descr->horz_pos = pos;
Alexandre Julliardde424282001-08-10 22:51:42 +00001192 LISTBOX_UpdateScroll( hwnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001193 if (abs(diff) < descr->width)
Alexandre Julliardde424282001-08-10 22:51:42 +00001194 ScrollWindowEx( hwnd, diff, 0, NULL, NULL, 0, NULL,
NF Stevens762f18d1999-01-24 19:02:16 +00001195 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001196 else
Alexandre Julliardde424282001-08-10 22:51:42 +00001197 InvalidateRect( hwnd, NULL, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001198}
1199
1200
1201/***********************************************************************
1202 * LISTBOX_SetHorizontalExtent
1203 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001204static LRESULT LISTBOX_SetHorizontalExtent( HWND hwnd, LB_DESCR *descr,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001205 INT extent )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001206{
1207 if (!descr->horz_extent || (descr->style & LBS_MULTICOLUMN))
1208 return LB_OKAY;
1209 if (extent <= 0) extent = 1;
1210 if (extent == descr->horz_extent) return LB_OKAY;
Alexandre Julliardde424282001-08-10 22:51:42 +00001211 TRACE("[%04x]: new horz extent = %d\n", hwnd, extent );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001212 descr->horz_extent = extent;
1213 if (descr->horz_pos > extent - descr->width)
Alexandre Julliardde424282001-08-10 22:51:42 +00001214 LISTBOX_SetHorizontalPos( hwnd, descr, extent - descr->width );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001215 else
Alexandre Julliardde424282001-08-10 22:51:42 +00001216 LISTBOX_UpdateScroll( hwnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001217 return LB_OKAY;
1218}
1219
1220
1221/***********************************************************************
1222 * LISTBOX_SetColumnWidth
1223 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001224static LRESULT LISTBOX_SetColumnWidth( HWND hwnd, LB_DESCR *descr, INT width)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001225{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001226 if (width == descr->column_width) return LB_OKAY;
Alexandre Julliardde424282001-08-10 22:51:42 +00001227 TRACE("[%04x]: new column width = %d\n", hwnd, width );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001228 descr->column_width = width;
Alexandre Julliardde424282001-08-10 22:51:42 +00001229 LISTBOX_UpdatePage( hwnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001230 return LB_OKAY;
1231}
1232
1233
1234/***********************************************************************
1235 * LISTBOX_SetFont
1236 *
1237 * Returns the item height.
1238 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001239static INT LISTBOX_SetFont( HWND hwnd, LB_DESCR *descr, HFONT font )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001240{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001241 HDC hdc;
1242 HFONT oldFont = 0;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001243 TEXTMETRICW tm;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001244
1245 descr->font = font;
1246
Alexandre Julliardde424282001-08-10 22:51:42 +00001247 if (!(hdc = GetDCEx( hwnd, 0, DCX_CACHE )))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001248 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001249 ERR("unable to get DC.\n" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001250 return 16;
1251 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001252 if (font) oldFont = SelectObject( hdc, font );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001253 GetTextMetricsW( hdc, &tm );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001254 if (oldFont) SelectObject( hdc, oldFont );
Alexandre Julliardde424282001-08-10 22:51:42 +00001255 ReleaseDC( hwnd, hdc );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001256 if (!IS_OWNERDRAW(descr))
Alexandre Julliardc72a9aa2002-01-31 21:05:05 +00001257 LISTBOX_SetItemHeight( hwnd, descr, 0, tm.tmHeight, FALSE );
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001258 return tm.tmHeight ;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001259}
1260
1261
1262/***********************************************************************
1263 * LISTBOX_MakeItemVisible
1264 *
1265 * Make sure that a given item is partially or fully visible.
1266 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001267static void LISTBOX_MakeItemVisible( HWND hwnd, LB_DESCR *descr, INT index,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001268 BOOL fully )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001269{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001270 INT top;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001271
1272 if (index <= descr->top_item) top = index;
1273 else if (descr->style & LBS_MULTICOLUMN)
1274 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001275 INT cols = descr->width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001276 if (!fully) cols += descr->column_width - 1;
1277 if (cols >= descr->column_width) cols /= descr->column_width;
1278 else cols = 1;
1279 if (index < descr->top_item + (descr->page_size * cols)) return;
1280 top = index - descr->page_size * (cols - 1);
1281 }
1282 else if (descr->style & LBS_OWNERDRAWVARIABLE)
1283 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001284 INT height = fully ? descr->items[index].height : 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001285 for (top = index; top > descr->top_item; top--)
1286 if ((height += descr->items[top-1].height) > descr->height) break;
1287 }
1288 else
1289 {
1290 if (index < descr->top_item + descr->page_size) return;
1291 if (!fully && (index == descr->top_item + descr->page_size) &&
1292 (descr->height > (descr->page_size * descr->item_height))) return;
1293 top = index - descr->page_size + 1;
1294 }
Alexandre Julliardde424282001-08-10 22:51:42 +00001295 LISTBOX_SetTopItem( hwnd, descr, top, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001296}
1297
Gerard Patel2ffbb312000-07-09 12:18:14 +00001298/***********************************************************************
1299 * LISTBOX_SetCaretIndex
1300 *
1301 * NOTES
1302 * index must be between 0 and descr->nb_items-1, or LB_ERR is returned.
1303 *
1304 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001305static LRESULT LISTBOX_SetCaretIndex( HWND hwnd, LB_DESCR *descr, INT index,
Gerard Patel2ffbb312000-07-09 12:18:14 +00001306 BOOL fully_visible )
1307{
Alexandre Julliardde424282001-08-10 22:51:42 +00001308 INT oldfocus = descr->focus_item;
Gerard Patel2ffbb312000-07-09 12:18:14 +00001309
Andreas Mohr85ba8792001-01-06 00:34:14 +00001310 if (descr->style & LBS_NOSEL) return LB_ERR;
Gerard Patel2ffbb312000-07-09 12:18:14 +00001311 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
1312 if (index == oldfocus) return LB_OKAY;
1313 descr->focus_item = index;
1314 if ((oldfocus != -1) && descr->caret_on && (descr->in_focus))
Alexandre Julliardde424282001-08-10 22:51:42 +00001315 LISTBOX_RepaintItem( hwnd, descr, oldfocus, ODA_FOCUS );
Gerard Patel2ffbb312000-07-09 12:18:14 +00001316
Alexandre Julliardde424282001-08-10 22:51:42 +00001317 LISTBOX_MakeItemVisible( hwnd, descr, index, fully_visible );
Gerard Patel2ffbb312000-07-09 12:18:14 +00001318 if (descr->caret_on && (descr->in_focus))
Alexandre Julliardde424282001-08-10 22:51:42 +00001319 LISTBOX_RepaintItem( hwnd, descr, index, ODA_FOCUS );
Gerard Patel2ffbb312000-07-09 12:18:14 +00001320
1321 return LB_OKAY;
1322}
1323
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001324
1325/***********************************************************************
1326 * LISTBOX_SelectItemRange
1327 *
1328 * Select a range of items. Should only be used on a MULTIPLESEL listbox.
1329 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001330static LRESULT LISTBOX_SelectItemRange( HWND hwnd, LB_DESCR *descr, INT first,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001331 INT last, BOOL on )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001332{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001333 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001334
1335 /* A few sanity checks */
1336
Andreas Mohr85ba8792001-01-06 00:34:14 +00001337 if (descr->style & LBS_NOSEL) return LB_ERR;
Alexandre Julliard03468f71998-02-15 19:40:49 +00001338 if ((last == -1) && (descr->nb_items == 0)) return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001339 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
1340 if (last == -1) last = descr->nb_items - 1;
1341 if ((first < 0) || (first >= descr->nb_items)) return LB_ERR;
1342 if ((last < 0) || (last >= descr->nb_items)) return LB_ERR;
1343 /* selected_item reflects last selected/unselected item on multiple sel */
1344 descr->selected_item = last;
1345
1346 if (on) /* Turn selection on */
1347 {
1348 for (i = first; i <= last; i++)
1349 {
1350 if (descr->items[i].selected) continue;
1351 descr->items[i].selected = TRUE;
Alexandre Julliardde424282001-08-10 22:51:42 +00001352 LISTBOX_RepaintItem( hwnd, descr, i, ODA_SELECT );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001353 }
Alexandre Julliardde424282001-08-10 22:51:42 +00001354 LISTBOX_SetCaretIndex( hwnd, descr, last, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001355 }
1356 else /* Turn selection off */
1357 {
1358 for (i = first; i <= last; i++)
1359 {
1360 if (!descr->items[i].selected) continue;
1361 descr->items[i].selected = FALSE;
Alexandre Julliardde424282001-08-10 22:51:42 +00001362 LISTBOX_RepaintItem( hwnd, descr, i, ODA_SELECT );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001363 }
1364 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001365 return LB_OKAY;
1366}
1367
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001368/***********************************************************************
1369 * LISTBOX_SetSelection
1370 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001371static LRESULT LISTBOX_SetSelection( HWND hwnd, LB_DESCR *descr, INT index,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001372 BOOL on, BOOL send_notify )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001373{
Dmitry Timoshkove0f493e1999-11-28 19:44:33 +00001374 TRACE( "index=%d notify=%s\n", index, send_notify ? "YES" : "NO" );
1375
Andreas Mohr85ba8792001-01-06 00:34:14 +00001376 if (descr->style & LBS_NOSEL) return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001377 if ((index < -1) || (index >= descr->nb_items)) return LB_ERR;
1378 if (descr->style & LBS_MULTIPLESEL)
1379 {
1380 if (index == -1) /* Select all items */
Alexandre Julliardde424282001-08-10 22:51:42 +00001381 return LISTBOX_SelectItemRange( hwnd, descr, 0, -1, on );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001382 else /* Only one item */
Alexandre Julliardde424282001-08-10 22:51:42 +00001383 return LISTBOX_SelectItemRange( hwnd, descr, index, index, on );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001384 }
1385 else
1386 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001387 INT oldsel = descr->selected_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001388 if (index == oldsel) return LB_OKAY;
1389 if (oldsel != -1) descr->items[oldsel].selected = FALSE;
1390 if (index != -1) descr->items[index].selected = TRUE;
1391 descr->selected_item = index;
Alexandre Julliardde424282001-08-10 22:51:42 +00001392 if (oldsel != -1) LISTBOX_RepaintItem( hwnd, descr, oldsel, ODA_SELECT );
1393 if (index != -1) LISTBOX_RepaintItem( hwnd, descr, index, ODA_SELECT );
1394 if (send_notify && descr->nb_items) SEND_NOTIFICATION( hwnd, descr,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001395 (index != -1) ? LBN_SELCHANGE : LBN_SELCANCEL );
Alex Korobka311d3291999-01-01 18:40:02 +00001396 else
1397 if( descr->lphc ) /* set selection change flag for parent combo */
1398 descr->lphc->wState |= CBF_SELCHANGE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001399 }
1400 return LB_OKAY;
1401}
1402
1403
1404/***********************************************************************
1405 * LISTBOX_MoveCaret
1406 *
1407 * Change the caret position and extend the selection to the new caret.
1408 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001409static void LISTBOX_MoveCaret( HWND hwnd, LB_DESCR *descr, INT index,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001410 BOOL fully_visible )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001411{
Alexandre Julliardde424282001-08-10 22:51:42 +00001412 INT oldfocus = descr->focus_item;
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001413
Alexandre Julliardde424282001-08-10 22:51:42 +00001414 if ((index < 0) || (index >= descr->nb_items))
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001415 return;
1416
1417 /* Important, repaint needs to be done in this order if
1418 you want to mimic Windows behavior:
Vincent BĂ©ron9a624912002-05-31 23:06:46 +00001419 1. Remove the focus and paint the item
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001420 2. Remove the selection and paint the item(s)
1421 3. Set the selection and repaint the item(s)
1422 4. Set the focus to 'index' and repaint the item */
1423
1424 /* 1. remove the focus and repaint the item */
1425 descr->focus_item = -1;
1426 if ((oldfocus != -1) && descr->caret_on && (descr->in_focus))
Alexandre Julliardde424282001-08-10 22:51:42 +00001427 LISTBOX_RepaintItem( hwnd, descr, oldfocus, ODA_FOCUS );
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001428
1429 /* 2. then turn off the previous selection */
1430 /* 3. repaint the new selected item */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001431 if (descr->style & LBS_EXTENDEDSEL)
1432 {
1433 if (descr->anchor_item != -1)
1434 {
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001435 INT first = min( index, descr->anchor_item );
1436 INT last = max( index, descr->anchor_item );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001437 if (first > 0)
Alexandre Julliardde424282001-08-10 22:51:42 +00001438 LISTBOX_SelectItemRange( hwnd, descr, 0, first - 1, FALSE );
1439 LISTBOX_SelectItemRange( hwnd, descr, last + 1, -1, FALSE );
1440 LISTBOX_SelectItemRange( hwnd, descr, first, last, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001441 }
1442 }
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00001443 else if (!(descr->style & LBS_MULTIPLESEL))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001444 {
1445 /* Set selection to new caret item */
Alexandre Julliardde424282001-08-10 22:51:42 +00001446 LISTBOX_SetSelection( hwnd, descr, index, TRUE, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001447 }
Alexandre Julliardde424282001-08-10 22:51:42 +00001448
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001449 /* 4. repaint the new item with the focus */
1450 descr->focus_item = index;
Alexandre Julliardde424282001-08-10 22:51:42 +00001451 LISTBOX_MakeItemVisible( hwnd, descr, index, fully_visible );
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001452 if (descr->caret_on && (descr->in_focus))
Alexandre Julliardde424282001-08-10 22:51:42 +00001453 LISTBOX_RepaintItem( hwnd, descr, index, ODA_FOCUS );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001454}
1455
1456
1457/***********************************************************************
1458 * LISTBOX_InsertItem
1459 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001460static LRESULT LISTBOX_InsertItem( HWND hwnd, LB_DESCR *descr, INT index,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001461 LPWSTR str, DWORD data )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001462{
1463 LB_ITEMDATA *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001464 INT max_items;
Gerard Patelc9a6d501999-07-25 13:03:17 +00001465 INT oldfocus = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001466
1467 if (index == -1) index = descr->nb_items;
1468 else if ((index < 0) || (index > descr->nb_items)) return LB_ERR;
1469 if (!descr->items) max_items = 0;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001470 else max_items = HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(*item);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001471 if (descr->nb_items == max_items)
1472 {
1473 /* We need to grow the array */
1474 max_items += LB_ARRAY_GRANULARITY;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001475 if (!(item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001476 max_items * sizeof(LB_ITEMDATA) )))
1477 {
Alexandre Julliardde424282001-08-10 22:51:42 +00001478 SEND_NOTIFICATION( hwnd, descr, LBN_ERRSPACE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001479 return LB_ERRSPACE;
1480 }
1481 descr->items = item;
1482 }
1483
1484 /* Insert the item structure */
1485
1486 item = &descr->items[index];
1487 if (index < descr->nb_items)
1488 RtlMoveMemory( item + 1, item,
1489 (descr->nb_items - index) * sizeof(LB_ITEMDATA) );
1490 item->str = str;
1491 item->data = data;
1492 item->height = 0;
1493 item->selected = FALSE;
1494 descr->nb_items++;
1495
1496 /* Get item height */
1497
1498 if (descr->style & LBS_OWNERDRAWVARIABLE)
1499 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001500 MEASUREITEMSTRUCT mis;
Alexandre Julliardde424282001-08-10 22:51:42 +00001501 UINT id = GetWindowLongA( hwnd, GWL_ID );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001502
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001503 mis.CtlType = ODT_LISTBOX;
Alexandre Julliardde424282001-08-10 22:51:42 +00001504 mis.CtlID = id;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001505 mis.itemID = index;
1506 mis.itemData = descr->items[index].data;
1507 mis.itemHeight = descr->item_height;
Alexandre Julliardde424282001-08-10 22:51:42 +00001508 SendMessageW( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001509 item->height = mis.itemHeight ? mis.itemHeight : 1;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001510 TRACE("[%04x]: measure item %d (%s) = %d\n",
Alexandre Julliardde424282001-08-10 22:51:42 +00001511 hwnd, index, str ? debugstr_w(str) : "", item->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001512 }
1513
1514 /* Repaint the items */
1515
Alexandre Julliardde424282001-08-10 22:51:42 +00001516 LISTBOX_UpdateScroll( hwnd, descr );
1517 LISTBOX_InvalidateItems( hwnd, descr, index );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001518
1519 /* Move selection and focused item */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001520 /* If listbox was empty, set focus to the first item */
Gerard Patelc9a6d501999-07-25 13:03:17 +00001521 if (descr->nb_items == 1)
Alexandre Julliardde424282001-08-10 22:51:42 +00001522 LISTBOX_SetCaretIndex( hwnd, descr, 0, FALSE );
Gerard Patelc9a6d501999-07-25 13:03:17 +00001523 /* single select don't change selection index in win31 */
1524 else if ((ISWIN31) && !(IS_MULTISELECT(descr)))
1525 {
1526 descr->selected_item++;
Alexandre Julliardde424282001-08-10 22:51:42 +00001527 LISTBOX_SetSelection( hwnd, descr, descr->selected_item-1, TRUE, FALSE );
Gerard Patelc9a6d501999-07-25 13:03:17 +00001528 }
1529 else
1530 {
1531 if (index <= descr->selected_item)
1532 {
1533 descr->selected_item++;
1534 descr->focus_item = oldfocus; /* focus not changed */
1535 }
1536 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001537 return LB_OKAY;
1538}
1539
1540
1541/***********************************************************************
1542 * LISTBOX_InsertString
1543 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001544static LRESULT LISTBOX_InsertString( HWND hwnd, LB_DESCR *descr, INT index,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001545 LPCWSTR str )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001546{
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001547 LPWSTR new_str = NULL;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001548 DWORD data = 0;
1549 LRESULT ret;
1550
1551 if (HAS_STRINGS(descr))
1552 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001553 static const WCHAR empty_stringW[] = { 0 };
1554 if (!str) str = empty_stringW;
1555 if (!(new_str = HeapAlloc( GetProcessHeap(), 0, (strlenW(str) + 1) * sizeof(WCHAR) )))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001556 {
Alexandre Julliardde424282001-08-10 22:51:42 +00001557 SEND_NOTIFICATION( hwnd, descr, LBN_ERRSPACE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001558 return LB_ERRSPACE;
1559 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001560 strcpyW(new_str, str);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001561 }
1562 else data = (DWORD)str;
1563
1564 if (index == -1) index = descr->nb_items;
Alexandre Julliardde424282001-08-10 22:51:42 +00001565 if ((ret = LISTBOX_InsertItem( hwnd, descr, index, new_str, data )) != 0)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001566 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001567 if (new_str) HeapFree( GetProcessHeap(), 0, new_str );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001568 return ret;
1569 }
1570
Francois Gougetee285b72001-05-11 20:03:40 +00001571 TRACE("[%04x]: added item %d %s\n",
Alexandre Julliardde424282001-08-10 22:51:42 +00001572 hwnd, index, HAS_STRINGS(descr) ? debugstr_w(new_str) : "" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001573 return index;
1574}
1575
1576
1577/***********************************************************************
1578 * LISTBOX_DeleteItem
1579 *
1580 * Delete the content of an item. 'index' must be a valid index.
1581 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001582static void LISTBOX_DeleteItem( HWND hwnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001583{
1584 /* Note: Win 3.1 only sends DELETEITEM on owner-draw items,
1585 * while Win95 sends it for all items with user data.
1586 * It's probably better to send it too often than not
1587 * often enough, so this is what we do here.
1588 */
1589 if (IS_OWNERDRAW(descr) || descr->items[index].data)
1590 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001591 DELETEITEMSTRUCT dis;
Alexandre Julliardde424282001-08-10 22:51:42 +00001592 UINT id = GetWindowLongA( hwnd, GWL_ID );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001593
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001594 dis.CtlType = ODT_LISTBOX;
Alexandre Julliardde424282001-08-10 22:51:42 +00001595 dis.CtlID = id;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001596 dis.itemID = index;
Alexandre Julliardde424282001-08-10 22:51:42 +00001597 dis.hwndItem = hwnd;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001598 dis.itemData = descr->items[index].data;
Alexandre Julliardde424282001-08-10 22:51:42 +00001599 SendMessageW( descr->owner, WM_DELETEITEM, id, (LPARAM)&dis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001600 }
1601 if (HAS_STRINGS(descr) && descr->items[index].str)
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001602 HeapFree( GetProcessHeap(), 0, descr->items[index].str );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001603}
1604
1605
1606/***********************************************************************
1607 * LISTBOX_RemoveItem
1608 *
1609 * Remove an item from the listbox and delete its content.
1610 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001611static LRESULT LISTBOX_RemoveItem( HWND hwnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001612{
1613 LB_ITEMDATA *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001614 INT max_items;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001615
Aric Stewartfe9a0f02001-01-04 19:27:03 +00001616 if ((index == -1) && (descr->nb_items > 0)) index = descr->nb_items - 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001617 else if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +00001618
1619 /* We need to invalidate the original rect instead of the updated one. */
Alexandre Julliardde424282001-08-10 22:51:42 +00001620 LISTBOX_InvalidateItems( hwnd, descr, index );
Yuxi Zhangf94c3c52000-02-26 19:13:12 +00001621
Alexandre Julliardde424282001-08-10 22:51:42 +00001622 LISTBOX_DeleteItem( hwnd, descr, index );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001623
1624 /* Remove the item */
1625
1626 item = &descr->items[index];
1627 if (index < descr->nb_items-1)
1628 RtlMoveMemory( item, item + 1,
1629 (descr->nb_items - index - 1) * sizeof(LB_ITEMDATA) );
1630 descr->nb_items--;
1631 if (descr->anchor_item == descr->nb_items) descr->anchor_item--;
1632
1633 /* Shrink the item array if possible */
1634
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001635 max_items = HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(LB_ITEMDATA);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001636 if (descr->nb_items < max_items - 2*LB_ARRAY_GRANULARITY)
1637 {
1638 max_items -= LB_ARRAY_GRANULARITY;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001639 item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001640 max_items * sizeof(LB_ITEMDATA) );
1641 if (item) descr->items = item;
1642 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001643 /* Repaint the items */
1644
Alexandre Julliardde424282001-08-10 22:51:42 +00001645 LISTBOX_UpdateScroll( hwnd, descr );
Gerard Patelc9a6d501999-07-25 13:03:17 +00001646 /* if we removed the scrollbar, reset the top of the list
1647 (correct for owner-drawn ???) */
1648 if (descr->nb_items == descr->page_size)
Alexandre Julliardde424282001-08-10 22:51:42 +00001649 LISTBOX_SetTopItem( hwnd, descr, 0, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001650
1651 /* Move selection and focused item */
Gerard Patelc9a6d501999-07-25 13:03:17 +00001652 if (!IS_MULTISELECT(descr))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001653 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00001654 if (index == descr->selected_item)
1655 descr->selected_item = -1;
1656 else if (index < descr->selected_item)
1657 {
1658 descr->selected_item--;
1659 if (ISWIN31) /* win 31 do not change the selected item number */
Alexandre Julliardde424282001-08-10 22:51:42 +00001660 LISTBOX_SetSelection( hwnd, descr, descr->selected_item + 1, TRUE, FALSE);
Gerard Patelc9a6d501999-07-25 13:03:17 +00001661 }
1662 }
Yuxi Zhangf94c3c52000-02-26 19:13:12 +00001663
Gerard Patelc9a6d501999-07-25 13:03:17 +00001664 if (descr->focus_item >= descr->nb_items)
1665 {
1666 descr->focus_item = descr->nb_items - 1;
1667 if (descr->focus_item < 0) descr->focus_item = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001668 }
1669 return LB_OKAY;
1670}
1671
1672
1673/***********************************************************************
1674 * LISTBOX_ResetContent
1675 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001676static void LISTBOX_ResetContent( HWND hwnd, LB_DESCR *descr )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001677{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001678 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001679
Alexandre Julliardde424282001-08-10 22:51:42 +00001680 for (i = 0; i < descr->nb_items; i++) LISTBOX_DeleteItem( hwnd, descr, i );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001681 if (descr->items) HeapFree( GetProcessHeap(), 0, descr->items );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001682 descr->nb_items = 0;
1683 descr->top_item = 0;
1684 descr->selected_item = -1;
1685 descr->focus_item = 0;
1686 descr->anchor_item = -1;
1687 descr->items = NULL;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001688}
1689
1690
1691/***********************************************************************
1692 * LISTBOX_SetCount
1693 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001694static LRESULT LISTBOX_SetCount( HWND hwnd, LB_DESCR *descr, INT count )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001695{
1696 LRESULT ret;
1697
1698 if (HAS_STRINGS(descr)) return LB_ERR;
1699 /* FIXME: this is far from optimal... */
1700 if (count > descr->nb_items)
1701 {
1702 while (count > descr->nb_items)
Alexandre Julliardde424282001-08-10 22:51:42 +00001703 if ((ret = LISTBOX_InsertString( hwnd, descr, -1, 0 )) < 0)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001704 return ret;
1705 }
1706 else if (count < descr->nb_items)
1707 {
1708 while (count < descr->nb_items)
Alexandre Julliardde424282001-08-10 22:51:42 +00001709 if ((ret = LISTBOX_RemoveItem( hwnd, descr, -1 )) < 0)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001710 return ret;
1711 }
1712 return LB_OKAY;
1713}
1714
1715
1716/***********************************************************************
1717 * LISTBOX_Directory
1718 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001719static LRESULT LISTBOX_Directory( HWND hwnd, LB_DESCR *descr, UINT attrib,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001720 LPCWSTR filespec, BOOL long_names )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001721{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001722 HANDLE handle;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001723 LRESULT ret = LB_OKAY;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001724 WIN32_FIND_DATAW entry;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001725 int pos;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001726
Ove Kaaven2c691b32000-11-25 03:06:03 +00001727 /* don't scan directory if we just want drives exclusively */
1728 if (attrib != (DDL_DRIVES | DDL_EXCLUSIVE)) {
1729 /* scan directory */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001730 if ((handle = FindFirstFileW(filespec, &entry)) == INVALID_HANDLE_VALUE)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001731 {
Ove Kaaven2c691b32000-11-25 03:06:03 +00001732 if (GetLastError() != ERROR_NO_MORE_FILES) return LB_ERR;
1733 }
1734 else
1735 {
1736 do
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001737 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001738 WCHAR buffer[270];
Ove Kaaven2c691b32000-11-25 03:06:03 +00001739 if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1740 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001741 static const WCHAR bracketW[] = { ']',0 };
1742 static const WCHAR dotW[] = { '.',0 };
Ove Kaaven2c691b32000-11-25 03:06:03 +00001743 if (!(attrib & DDL_DIRECTORY) ||
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001744 !strcmpW( entry.cAlternateFileName, dotW )) continue;
1745 buffer[0] = '[';
1746 if (long_names) strcpyW( buffer + 1, entry.cFileName );
1747 else strcpyW( buffer + 1, entry.cAlternateFileName );
1748 strcatW(buffer, bracketW);
Ove Kaaven2c691b32000-11-25 03:06:03 +00001749 }
1750 else /* not a directory */
1751 {
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001752#define ATTRIBS (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
1753 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE)
1754
Ove Kaaven2c691b32000-11-25 03:06:03 +00001755 if ((attrib & DDL_EXCLUSIVE) &&
1756 ((attrib & ATTRIBS) != (entry.dwFileAttributes & ATTRIBS)))
1757 continue;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001758#undef ATTRIBS
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001759 if (long_names) strcpyW( buffer, entry.cFileName );
1760 else strcpyW( buffer, entry.cAlternateFileName );
Ove Kaaven2c691b32000-11-25 03:06:03 +00001761 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001762 if (!long_names) CharLowerW( buffer );
Alexandre Julliardde424282001-08-10 22:51:42 +00001763 pos = LISTBOX_FindFileStrPos( hwnd, descr, buffer );
1764 if ((ret = LISTBOX_InsertString( hwnd, descr, pos, buffer )) < 0)
Ove Kaaven2c691b32000-11-25 03:06:03 +00001765 break;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001766 } while (FindNextFileW( handle, &entry ));
Ove Kaaven2c691b32000-11-25 03:06:03 +00001767 FindClose( handle );
1768 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001769 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001770
Ove Kaaven2c691b32000-11-25 03:06:03 +00001771 /* scan drives */
Alexandre Julliard889f7421997-04-15 17:19:52 +00001772 if ((ret >= 0) && (attrib & DDL_DRIVES))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001773 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001774 WCHAR buffer[] = {'[','-','a','-',']',0};
1775 WCHAR root[] = {'A',':','\\',0};
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001776 int drive;
Alexandre Julliardbf672592000-12-12 00:44:42 +00001777 for (drive = 0; drive < 26; drive++, buffer[2]++, root[0]++)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001778 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001779 if (GetDriveTypeW(root) <= DRIVE_NO_ROOT_DIR) continue;
Alexandre Julliardde424282001-08-10 22:51:42 +00001780 if ((ret = LISTBOX_InsertString( hwnd, descr, -1, buffer )) < 0)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001781 break;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001782 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001783 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001784 return ret;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001785}
1786
1787
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001788/***********************************************************************
1789 * LISTBOX_HandleVScroll
1790 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001791static LRESULT LISTBOX_HandleVScroll( HWND hwnd, LB_DESCR *descr, WPARAM wParam )
Alexandre Julliard2787be81995-05-22 18:23:01 +00001792{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001793 SCROLLINFO info;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001794
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001795 if (descr->style & LBS_MULTICOLUMN) return 0;
1796 switch(LOWORD(wParam))
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +00001797 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001798 case SB_LINEUP:
Alexandre Julliardde424282001-08-10 22:51:42 +00001799 LISTBOX_SetTopItem( hwnd, descr, descr->top_item - 1, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001800 break;
1801 case SB_LINEDOWN:
Alexandre Julliardde424282001-08-10 22:51:42 +00001802 LISTBOX_SetTopItem( hwnd, descr, descr->top_item + 1, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001803 break;
1804 case SB_PAGEUP:
Alexandre Julliardde424282001-08-10 22:51:42 +00001805 LISTBOX_SetTopItem( hwnd, descr, descr->top_item -
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001806 LISTBOX_GetCurrentPageSize( descr ), TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001807 break;
1808 case SB_PAGEDOWN:
Alexandre Julliardde424282001-08-10 22:51:42 +00001809 LISTBOX_SetTopItem( hwnd, descr, descr->top_item +
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001810 LISTBOX_GetCurrentPageSize( descr ), TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001811 break;
1812 case SB_THUMBPOSITION:
Alexandre Julliardde424282001-08-10 22:51:42 +00001813 LISTBOX_SetTopItem( hwnd, descr, HIWORD(wParam), TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001814 break;
1815 case SB_THUMBTRACK:
1816 info.cbSize = sizeof(info);
1817 info.fMask = SIF_TRACKPOS;
Alexandre Julliardde424282001-08-10 22:51:42 +00001818 GetScrollInfo( hwnd, SB_VERT, &info );
1819 LISTBOX_SetTopItem( hwnd, descr, info.nTrackPos, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001820 break;
1821 case SB_TOP:
Alexandre Julliardde424282001-08-10 22:51:42 +00001822 LISTBOX_SetTopItem( hwnd, descr, 0, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001823 break;
1824 case SB_BOTTOM:
Alexandre Julliardde424282001-08-10 22:51:42 +00001825 LISTBOX_SetTopItem( hwnd, descr, descr->nb_items, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001826 break;
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +00001827 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001828 return 0;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001829}
1830
Alexandre Julliardb817f4f1996-03-14 18:08:34 +00001831
Alexandre Julliard2787be81995-05-22 18:23:01 +00001832/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001833 * LISTBOX_HandleHScroll
Alexandre Julliard2787be81995-05-22 18:23:01 +00001834 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001835static LRESULT LISTBOX_HandleHScroll( HWND hwnd, LB_DESCR *descr, WPARAM wParam )
Alexandre Julliard2787be81995-05-22 18:23:01 +00001836{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001837 SCROLLINFO info;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001838 INT page;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001839
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001840 if (descr->style & LBS_MULTICOLUMN)
1841 {
1842 switch(LOWORD(wParam))
1843 {
1844 case SB_LINELEFT:
Alexandre Julliardde424282001-08-10 22:51:42 +00001845 LISTBOX_SetTopItem( hwnd, descr, descr->top_item-descr->page_size,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001846 TRUE );
1847 break;
1848 case SB_LINERIGHT:
Alexandre Julliardde424282001-08-10 22:51:42 +00001849 LISTBOX_SetTopItem( hwnd, descr, descr->top_item+descr->page_size,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001850 TRUE );
1851 break;
1852 case SB_PAGELEFT:
1853 page = descr->width / descr->column_width;
1854 if (page < 1) page = 1;
Alexandre Julliardde424282001-08-10 22:51:42 +00001855 LISTBOX_SetTopItem( hwnd, descr,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001856 descr->top_item - page * descr->page_size, TRUE );
1857 break;
1858 case SB_PAGERIGHT:
1859 page = descr->width / descr->column_width;
1860 if (page < 1) page = 1;
Alexandre Julliardde424282001-08-10 22:51:42 +00001861 LISTBOX_SetTopItem( hwnd, descr,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001862 descr->top_item + page * descr->page_size, TRUE );
1863 break;
1864 case SB_THUMBPOSITION:
Alexandre Julliardde424282001-08-10 22:51:42 +00001865 LISTBOX_SetTopItem( hwnd, descr, HIWORD(wParam)*descr->page_size,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001866 TRUE );
1867 break;
1868 case SB_THUMBTRACK:
1869 info.cbSize = sizeof(info);
1870 info.fMask = SIF_TRACKPOS;
Alexandre Julliardde424282001-08-10 22:51:42 +00001871 GetScrollInfo( hwnd, SB_VERT, &info );
1872 LISTBOX_SetTopItem( hwnd, descr, info.nTrackPos*descr->page_size,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001873 TRUE );
1874 break;
1875 case SB_LEFT:
Alexandre Julliardde424282001-08-10 22:51:42 +00001876 LISTBOX_SetTopItem( hwnd, descr, 0, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001877 break;
1878 case SB_RIGHT:
Alexandre Julliardde424282001-08-10 22:51:42 +00001879 LISTBOX_SetTopItem( hwnd, descr, descr->nb_items, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001880 break;
1881 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001882 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001883 else if (descr->horz_extent)
1884 {
1885 switch(LOWORD(wParam))
1886 {
1887 case SB_LINELEFT:
Alexandre Julliardde424282001-08-10 22:51:42 +00001888 LISTBOX_SetHorizontalPos( hwnd, descr, descr->horz_pos - 1 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001889 break;
1890 case SB_LINERIGHT:
Alexandre Julliardde424282001-08-10 22:51:42 +00001891 LISTBOX_SetHorizontalPos( hwnd, descr, descr->horz_pos + 1 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001892 break;
1893 case SB_PAGELEFT:
Alexandre Julliardde424282001-08-10 22:51:42 +00001894 LISTBOX_SetHorizontalPos( hwnd, descr,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001895 descr->horz_pos - descr->width );
1896 break;
1897 case SB_PAGERIGHT:
Alexandre Julliardde424282001-08-10 22:51:42 +00001898 LISTBOX_SetHorizontalPos( hwnd, descr,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001899 descr->horz_pos + descr->width );
1900 break;
1901 case SB_THUMBPOSITION:
Alexandre Julliardde424282001-08-10 22:51:42 +00001902 LISTBOX_SetHorizontalPos( hwnd, descr, HIWORD(wParam) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001903 break;
1904 case SB_THUMBTRACK:
1905 info.cbSize = sizeof(info);
1906 info.fMask = SIF_TRACKPOS;
Alexandre Julliardde424282001-08-10 22:51:42 +00001907 GetScrollInfo( hwnd, SB_HORZ, &info );
1908 LISTBOX_SetHorizontalPos( hwnd, descr, info.nTrackPos );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001909 break;
1910 case SB_LEFT:
Alexandre Julliardde424282001-08-10 22:51:42 +00001911 LISTBOX_SetHorizontalPos( hwnd, descr, 0 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001912 break;
1913 case SB_RIGHT:
Alexandre Julliardde424282001-08-10 22:51:42 +00001914 LISTBOX_SetHorizontalPos( hwnd, descr,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001915 descr->horz_extent - descr->width );
1916 break;
1917 }
1918 }
1919 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001920}
1921
Alexandre Julliardde424282001-08-10 22:51:42 +00001922static LRESULT LISTBOX_HandleMouseWheel(HWND hwnd, LB_DESCR *descr, WPARAM wParam )
Stephane Lussier4bdf4af2000-04-18 11:56:33 +00001923{
1924 short gcWheelDelta = 0;
1925 UINT pulScrollLines = 3;
1926
1927 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
1928
1929 gcWheelDelta -= (short) HIWORD(wParam);
1930
1931 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
1932 {
1933 int cLineScroll = (int) min((UINT) descr->page_size, pulScrollLines);
1934 cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
Alexandre Julliardde424282001-08-10 22:51:42 +00001935 LISTBOX_SetTopItem( hwnd, descr, descr->top_item + cLineScroll, TRUE );
Stephane Lussier4bdf4af2000-04-18 11:56:33 +00001936 }
1937 return 0;
1938}
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001939
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001940/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001941 * LISTBOX_HandleLButtonDown
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001942 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001943static LRESULT LISTBOX_HandleLButtonDown( HWND hwnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001944 WPARAM wParam, INT x, INT y )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001945{
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001946 INT index = LISTBOX_GetItemFromPoint( descr, x, y );
Alexandre Julliardde424282001-08-10 22:51:42 +00001947 TRACE("[%04x]: lbuttondown %d,%d item %d\n", hwnd, x, y, index );
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00001948 if (!descr->caret_on && (descr->in_focus)) return 0;
Jason Mawdsley50523d12000-06-11 20:34:07 +00001949
1950 if (!descr->in_focus)
1951 {
Alexandre Julliardde424282001-08-10 22:51:42 +00001952 if( !descr->lphc ) SetFocus( hwnd );
1953 else SetFocus( (descr->lphc->hWndEdit) ? descr->lphc->hWndEdit : descr->lphc->self );
Jason Mawdsley50523d12000-06-11 20:34:07 +00001954 }
1955
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001956 if (index == -1) return 0;
Andreas Mohr2b5d9c62000-08-29 03:52:16 +00001957
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001958 if (descr->style & LBS_EXTENDEDSEL)
1959 {
1960 /* we should perhaps make sure that all items are deselected
1961 FIXME: needed for !LBS_EXTENDEDSEL, too ?
1962 if (!(wParam & (MK_SHIFT|MK_CONTROL)))
Alexandre Julliardde424282001-08-10 22:51:42 +00001963 LISTBOX_SetSelection( hwnd, descr, -1, FALSE, FALSE);
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001964 */
1965
1966 if (!(wParam & MK_SHIFT)) descr->anchor_item = index;
1967 if (wParam & MK_CONTROL)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001968 {
Alexandre Julliardde424282001-08-10 22:51:42 +00001969 LISTBOX_SetCaretIndex( hwnd, descr, index, FALSE );
1970 LISTBOX_SetSelection( hwnd, descr, index,
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001971 !descr->items[index].selected,
1972 (descr->style & LBS_NOTIFY) != 0);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001973 }
Alexandre Julliardde424282001-08-10 22:51:42 +00001974 else LISTBOX_MoveCaret( hwnd, descr, index, FALSE );
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001975 }
1976 else
1977 {
Alexandre Julliardde424282001-08-10 22:51:42 +00001978 LISTBOX_MoveCaret( hwnd, descr, index, FALSE );
1979 LISTBOX_SetSelection( hwnd, descr, index,
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001980 (!(descr->style & LBS_MULTIPLESEL) ||
1981 !descr->items[index].selected),
1982 (descr->style & LBS_NOTIFY) != 0 );
Alexandre Julliard2787be81995-05-22 18:23:01 +00001983 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001984
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00001985 descr->captured = TRUE;
Alexandre Julliardde424282001-08-10 22:51:42 +00001986 SetCapture( hwnd );
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001987
1988 if (!descr->lphc)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001989 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001990 if (descr->style & LBS_NOTIFY )
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001991 SendMessageW( descr->owner, WM_LBTRACKPOINT, index,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001992 MAKELPARAM( x, y ) );
Alexandre Julliardde424282001-08-10 22:51:42 +00001993 if (GetWindowLongA( hwnd, GWL_EXSTYLE ) & WS_EX_DRAGDETECT)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001994 {
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00001995 POINT pt;
Alexandre Julliardde424282001-08-10 22:51:42 +00001996
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00001997 pt.x = x;
1998 pt.y = y;
1999
Alexandre Julliardde424282001-08-10 22:51:42 +00002000 if (DragDetect( hwnd, pt ))
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002001 SendMessageW( descr->owner, WM_BEGINDRAG, 0, 0 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002002 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00002003 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002004 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002005}
2006
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002007
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002008/*************************************************************************
Alexandre Julliardde424282001-08-10 22:51:42 +00002009 * LISTBOX_HandleLButtonDownCombo [Internal]
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002010 *
2011 * Process LButtonDown message for the ComboListBox
2012 *
Alexandre Julliardde424282001-08-10 22:51:42 +00002013nn * PARAMS
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002014 * pWnd [I] The windows internal structure
2015 * pDescr [I] The ListBox internal structure
2016 * wParam [I] Key Flag (WM_LBUTTONDOWN doc for more info)
2017 * x [I] X Mouse Coordinate
2018 * y [I] Y Mouse Coordinate
2019 *
2020 * RETURNS
2021 * 0 since we are processing the WM_LBUTTONDOWN Message
2022 *
2023 * NOTES
2024 * This function is only to be used when a ListBox is a ComboListBox
2025 */
2026
Alexandre Julliardde424282001-08-10 22:51:42 +00002027static LRESULT LISTBOX_HandleLButtonDownCombo( HWND hwnd, LB_DESCR *pDescr,
Alexandre Julliard7f90a8c2000-05-23 04:18:12 +00002028 UINT msg, WPARAM wParam, INT x, INT y)
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002029{
2030 RECT clientRect, screenRect;
2031 POINT mousePos;
2032
2033 mousePos.x = x;
2034 mousePos.y = y;
2035
Alexandre Julliardde424282001-08-10 22:51:42 +00002036 GetClientRect(hwnd, &clientRect);
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002037
2038 if(PtInRect(&clientRect, mousePos))
Alexandre Julliardde424282001-08-10 22:51:42 +00002039 {
Alexandre Julliard7f90a8c2000-05-23 04:18:12 +00002040 /* MousePos is in client, resume normal processing */
2041 if (msg == WM_LBUTTONDOWN)
Serge Ivanov07917e42000-06-07 03:46:57 +00002042 {
2043 pDescr->lphc->droppedIndex = pDescr->nb_items ? pDescr->selected_item : -1;
Alexandre Julliardde424282001-08-10 22:51:42 +00002044 return LISTBOX_HandleLButtonDown( hwnd, pDescr, wParam, x, y);
Serge Ivanov07917e42000-06-07 03:46:57 +00002045 }
Alexandre Julliard7f90a8c2000-05-23 04:18:12 +00002046 else if (pDescr->style & LBS_NOTIFY)
Alexandre Julliardde424282001-08-10 22:51:42 +00002047 SEND_NOTIFICATION( hwnd, pDescr, LBN_DBLCLK );
Alexandre Julliard7f90a8c2000-05-23 04:18:12 +00002048 return 0;
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002049 }
2050 else
2051 {
2052 POINT screenMousePos;
2053 HWND hWndOldCapture;
2054
2055 /* Check the Non-Client Area */
2056 screenMousePos = mousePos;
2057 hWndOldCapture = GetCapture();
2058 ReleaseCapture();
Alexandre Julliardde424282001-08-10 22:51:42 +00002059 GetWindowRect(hwnd, &screenRect);
2060 ClientToScreen(hwnd, &screenMousePos);
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002061
2062 if(!PtInRect(&screenRect, screenMousePos))
Alexandre Julliardde424282001-08-10 22:51:42 +00002063 {
2064 LISTBOX_SetCaretIndex( hwnd, pDescr, pDescr->lphc->droppedIndex, FALSE );
2065 LISTBOX_SetSelection( hwnd, pDescr, pDescr->lphc->droppedIndex, FALSE, FALSE );
Serge Ivanov07917e42000-06-07 03:46:57 +00002066 COMBO_FlipListbox( pDescr->lphc, FALSE, FALSE );
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002067 return 0;
2068 }
2069 else
2070 {
2071 /* Check to see the NC is a scrollbar */
2072 INT nHitTestType=0;
Alexandre Julliardde424282001-08-10 22:51:42 +00002073 LONG style = GetWindowLongA( hwnd, GWL_STYLE );
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002074 /* Check Vertical scroll bar */
Alexandre Julliardde424282001-08-10 22:51:42 +00002075 if (style & WS_VSCROLL)
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002076 {
2077 clientRect.right += GetSystemMetrics(SM_CXVSCROLL);
Alexandre Julliardde424282001-08-10 22:51:42 +00002078 if (PtInRect( &clientRect, mousePos ))
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002079 {
2080 nHitTestType = HTVSCROLL;
2081 }
2082 }
2083 /* Check horizontal scroll bar */
Alexandre Julliardde424282001-08-10 22:51:42 +00002084 if (style & WS_HSCROLL)
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002085 {
2086 clientRect.bottom += GetSystemMetrics(SM_CYHSCROLL);
2087 if (PtInRect( &clientRect, mousePos ))
2088 {
2089 nHitTestType = HTHSCROLL;
2090 }
2091 }
Vincent BĂ©ron9a624912002-05-31 23:06:46 +00002092 /* Windows sends this message when a scrollbar is clicked
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002093 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002094
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002095 if(nHitTestType != 0)
2096 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002097 SendMessageW(hwnd, WM_NCLBUTTONDOWN, nHitTestType,
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002098 MAKELONG(screenMousePos.x, screenMousePos.y));
2099 }
Vincent BĂ©ron9a624912002-05-31 23:06:46 +00002100 /* Resume the Capture after scrolling is complete
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002101 */
2102 if(hWndOldCapture != 0)
2103 {
2104 SetCapture(hWndOldCapture);
2105 }
2106 }
2107 }
2108 return 0;
2109}
2110
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002111/***********************************************************************
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002112 * LISTBOX_HandleLButtonUp
2113 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002114static LRESULT LISTBOX_HandleLButtonUp( HWND hwnd, LB_DESCR *descr )
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002115{
2116 if (LISTBOX_Timer != LB_TIMER_NONE)
Alexandre Julliardde424282001-08-10 22:51:42 +00002117 KillSystemTimer( hwnd, LB_TIMER_ID );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002118 LISTBOX_Timer = LB_TIMER_NONE;
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002119 if (descr->captured)
Alexandre Julliard33072e11997-06-29 18:08:02 +00002120 {
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002121 descr->captured = FALSE;
Alexandre Julliardde424282001-08-10 22:51:42 +00002122 if (GetCapture() == hwnd) ReleaseCapture();
Gerard Patelc9a6d501999-07-25 13:03:17 +00002123 if ((descr->style & LBS_NOTIFY) && descr->nb_items)
Alexandre Julliardde424282001-08-10 22:51:42 +00002124 SEND_NOTIFICATION( hwnd, descr, LBN_SELCHANGE );
Alexandre Julliard33072e11997-06-29 18:08:02 +00002125 }
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002126 return 0;
2127}
2128
2129
2130/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002131 * LISTBOX_HandleTimer
Alexandre Julliardade697e1995-11-26 13:59:11 +00002132 *
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002133 * Handle scrolling upon a timer event.
2134 * Return TRUE if scrolling should continue.
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002135 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002136static LRESULT LISTBOX_HandleTimer( HWND hwnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002137 INT index, TIMER_DIRECTION dir )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002138{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002139 switch(dir)
Alexandre Julliardade697e1995-11-26 13:59:11 +00002140 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002141 case LB_TIMER_UP:
2142 if (descr->top_item) index = descr->top_item - 1;
2143 else index = 0;
2144 break;
2145 case LB_TIMER_LEFT:
2146 if (descr->top_item) index -= descr->page_size;
2147 break;
2148 case LB_TIMER_DOWN:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002149 index = descr->top_item + LISTBOX_GetCurrentPageSize( descr );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002150 if (index == descr->focus_item) index++;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002151 if (index >= descr->nb_items) index = descr->nb_items - 1;
2152 break;
2153 case LB_TIMER_RIGHT:
2154 if (index + descr->page_size < descr->nb_items)
2155 index += descr->page_size;
2156 break;
2157 case LB_TIMER_NONE:
2158 break;
Alexandre Julliardade697e1995-11-26 13:59:11 +00002159 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002160 if (index == descr->focus_item) return FALSE;
Alexandre Julliardde424282001-08-10 22:51:42 +00002161 LISTBOX_MoveCaret( hwnd, descr, index, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002162 return TRUE;
2163}
Alexandre Julliardade697e1995-11-26 13:59:11 +00002164
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002165
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002166/***********************************************************************
2167 * LISTBOX_HandleSystemTimer
2168 *
2169 * WM_SYSTIMER handler.
2170 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002171static LRESULT LISTBOX_HandleSystemTimer( HWND hwnd, LB_DESCR *descr )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002172{
Alexandre Julliardde424282001-08-10 22:51:42 +00002173 if (!LISTBOX_HandleTimer( hwnd, descr, descr->focus_item, LISTBOX_Timer ))
Alexandre Julliardade697e1995-11-26 13:59:11 +00002174 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002175 KillSystemTimer( hwnd, LB_TIMER_ID );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002176 LISTBOX_Timer = LB_TIMER_NONE;
Alexandre Julliardade697e1995-11-26 13:59:11 +00002177 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00002178 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002179}
2180
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002181
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002182/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002183 * LISTBOX_HandleMouseMove
2184 *
2185 * WM_MOUSEMOVE handler.
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002186 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002187static void LISTBOX_HandleMouseMove( HWND hwnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002188 INT x, INT y )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002189{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002190 INT index;
Serge Ivanov07917e42000-06-07 03:46:57 +00002191 TIMER_DIRECTION dir = LB_TIMER_NONE;
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00002192
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002193 if (!descr->captured) return;
2194
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002195 if (descr->style & LBS_MULTICOLUMN)
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00002196 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002197 if (y < 0) y = 0;
2198 else if (y >= descr->item_height * descr->page_size)
2199 y = descr->item_height * descr->page_size - 1;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002200
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002201 if (x < 0)
2202 {
2203 dir = LB_TIMER_LEFT;
2204 x = 0;
2205 }
2206 else if (x >= descr->width)
2207 {
2208 dir = LB_TIMER_RIGHT;
2209 x = descr->width - 1;
2210 }
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00002211 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002212 else
2213 {
2214 if (y < 0) dir = LB_TIMER_UP; /* above */
2215 else if (y >= descr->height) dir = LB_TIMER_DOWN; /* below */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002216 }
2217
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002218 index = LISTBOX_GetItemFromPoint( descr, x, y );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002219 if (index == -1) index = descr->focus_item;
Alexandre Julliardde424282001-08-10 22:51:42 +00002220 if (!LISTBOX_HandleTimer( hwnd, descr, index, dir )) dir = LB_TIMER_NONE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002221
2222 /* Start/stop the system timer */
2223
2224 if (dir != LB_TIMER_NONE)
Alexandre Julliardde424282001-08-10 22:51:42 +00002225 SetSystemTimer( hwnd, LB_TIMER_ID, LB_SCROLL_TIMEOUT, NULL);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002226 else if (LISTBOX_Timer != LB_TIMER_NONE)
Alexandre Julliardde424282001-08-10 22:51:42 +00002227 KillSystemTimer( hwnd, LB_TIMER_ID );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002228 LISTBOX_Timer = dir;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002229}
2230
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002231
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002232/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002233 * LISTBOX_HandleKeyDown
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002234 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002235static LRESULT LISTBOX_HandleKeyDown( HWND hwnd, LB_DESCR *descr, WPARAM wParam )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002236{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002237 INT caret = -1;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002238 BOOL bForceSelection = TRUE; /* select item pointed to by focus_item */
2239 if ((IS_MULTISELECT(descr)) || (descr->selected_item == descr->focus_item))
2240 bForceSelection = FALSE; /* only for single select list */
2241
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002242 if (descr->style & LBS_WANTKEYBOARDINPUT)
2243 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002244 caret = SendMessageW( descr->owner, WM_VKEYTOITEM,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002245 MAKEWPARAM(LOWORD(wParam), descr->focus_item),
Alexandre Julliardde424282001-08-10 22:51:42 +00002246 hwnd );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002247 if (caret == -2) return 0;
2248 }
2249 if (caret == -1) switch(wParam)
2250 {
2251 case VK_LEFT:
2252 if (descr->style & LBS_MULTICOLUMN)
2253 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00002254 bForceSelection = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002255 if (descr->focus_item >= descr->page_size)
2256 caret = descr->focus_item - descr->page_size;
2257 break;
2258 }
2259 /* fall through */
2260 case VK_UP:
2261 caret = descr->focus_item - 1;
2262 if (caret < 0) caret = 0;
2263 break;
2264 case VK_RIGHT:
2265 if (descr->style & LBS_MULTICOLUMN)
2266 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00002267 bForceSelection = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002268 if (descr->focus_item + descr->page_size < descr->nb_items)
2269 caret = descr->focus_item + descr->page_size;
2270 break;
2271 }
2272 /* fall through */
2273 case VK_DOWN:
2274 caret = descr->focus_item + 1;
2275 if (caret >= descr->nb_items) caret = descr->nb_items - 1;
2276 break;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002277
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002278 case VK_PRIOR:
2279 if (descr->style & LBS_MULTICOLUMN)
2280 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002281 INT page = descr->width / descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002282 if (page < 1) page = 1;
2283 caret = descr->focus_item - (page * descr->page_size) + 1;
2284 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002285 else caret = descr->focus_item-LISTBOX_GetCurrentPageSize(descr) + 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002286 if (caret < 0) caret = 0;
2287 break;
2288 case VK_NEXT:
2289 if (descr->style & LBS_MULTICOLUMN)
2290 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002291 INT page = descr->width / descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002292 if (page < 1) page = 1;
2293 caret = descr->focus_item + (page * descr->page_size) - 1;
2294 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002295 else caret = descr->focus_item + LISTBOX_GetCurrentPageSize(descr) - 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002296 if (caret >= descr->nb_items) caret = descr->nb_items - 1;
2297 break;
2298 case VK_HOME:
2299 caret = 0;
2300 break;
2301 case VK_END:
2302 caret = descr->nb_items - 1;
2303 break;
2304 case VK_SPACE:
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002305 if (descr->style & LBS_EXTENDEDSEL) caret = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002306 else if (descr->style & LBS_MULTIPLESEL)
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002307 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002308 LISTBOX_SetSelection( hwnd, descr, descr->focus_item,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002309 !descr->items[descr->focus_item].selected,
2310 (descr->style & LBS_NOTIFY) != 0 );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002311 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002312 break;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002313 default:
2314 bForceSelection = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002315 }
Gerard Patelc9a6d501999-07-25 13:03:17 +00002316 if (bForceSelection) /* focused item is used instead of key */
2317 caret = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002318 if (caret >= 0)
2319 {
2320 if ((descr->style & LBS_EXTENDEDSEL) &&
Alexandre Julliarda3960291999-02-26 11:11:13 +00002321 !(GetKeyState( VK_SHIFT ) & 0x8000))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002322 descr->anchor_item = caret;
Alexandre Julliardde424282001-08-10 22:51:42 +00002323 LISTBOX_MoveCaret( hwnd, descr, caret, TRUE );
2324 LISTBOX_SetSelection( hwnd, descr, caret, TRUE, FALSE);
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002325 if (descr->style & LBS_NOTIFY)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002326 {
Dmitry Timoshkov6df245d2001-04-09 18:30:25 +00002327 if( descr->lphc )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002328 {
2329 /* make sure that combo parent doesn't hide us */
2330 descr->lphc->wState |= CBF_NOROLLUP;
2331 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002332 if (descr->nb_items) SEND_NOTIFICATION( hwnd, descr, LBN_SELCHANGE );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002333 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002334 }
2335 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002336}
2337
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002338
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002339/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002340 * LISTBOX_HandleChar
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002341 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002342static LRESULT LISTBOX_HandleChar( HWND hwnd, LB_DESCR *descr, WCHAR charW )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002343{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002344 INT caret = -1;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002345 WCHAR str[2];
2346
2347 str[0] = charW;
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002348 str[1] = '\0';
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002349
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002350 if (descr->style & LBS_WANTKEYBOARDINPUT)
2351 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002352 caret = SendMessageW( descr->owner, WM_CHARTOITEM,
2353 MAKEWPARAM(charW, descr->focus_item),
Alexandre Julliardde424282001-08-10 22:51:42 +00002354 hwnd );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002355 if (caret == -2) return 0;
2356 }
2357 if (caret == -1)
Alexandre Julliardde424282001-08-10 22:51:42 +00002358 caret = LISTBOX_FindString( hwnd, descr, descr->focus_item, str, FALSE);
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002359 if (caret != -1)
2360 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00002361 if ((!IS_MULTISELECT(descr)) && descr->selected_item == -1)
Alexandre Julliardde424282001-08-10 22:51:42 +00002362 LISTBOX_SetSelection( hwnd, descr, caret, TRUE, FALSE);
2363 LISTBOX_MoveCaret( hwnd, descr, caret, TRUE );
Gerard Patelc9a6d501999-07-25 13:03:17 +00002364 if ((descr->style & LBS_NOTIFY) && descr->nb_items)
Alexandre Julliardde424282001-08-10 22:51:42 +00002365 SEND_NOTIFICATION( hwnd, descr, LBN_SELCHANGE );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002366 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002367 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002368}
2369
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002370
2371/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002372 * LISTBOX_Create
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002373 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002374static BOOL LISTBOX_Create( HWND hwnd, LPHEADCOMBO lphc )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002375{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002376 LB_DESCR *descr;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002377 MEASUREITEMSTRUCT mis;
2378 RECT rect;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002379
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002380 if (!(descr = HeapAlloc( GetProcessHeap(), 0, sizeof(*descr) )))
2381 return FALSE;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002382
Alexandre Julliardde424282001-08-10 22:51:42 +00002383 GetClientRect( hwnd, &rect );
2384 descr->owner = GetParent( hwnd );
2385 descr->style = GetWindowLongA( hwnd, GWL_STYLE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002386 descr->width = rect.right - rect.left;
2387 descr->height = rect.bottom - rect.top;
2388 descr->items = NULL;
2389 descr->nb_items = 0;
2390 descr->top_item = 0;
2391 descr->selected_item = -1;
2392 descr->focus_item = 0;
2393 descr->anchor_item = -1;
2394 descr->item_height = 1;
2395 descr->page_size = 1;
2396 descr->column_width = 150;
Alexandre Julliardde424282001-08-10 22:51:42 +00002397 descr->horz_extent = (descr->style & WS_HSCROLL) ? 1 : 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002398 descr->horz_pos = 0;
2399 descr->nb_tabs = 0;
2400 descr->tabs = NULL;
Serge Ivanov07917e42000-06-07 03:46:57 +00002401 descr->caret_on = lphc ? FALSE : TRUE;
Andreas Mohr85ba8792001-01-06 00:34:14 +00002402 if (descr->style & LBS_NOSEL) descr->caret_on = FALSE;
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002403 descr->in_focus = FALSE;
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002404 descr->captured = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002405 descr->font = 0;
2406 descr->locale = 0; /* FIXME */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002407 descr->lphc = lphc;
2408
Alexandre Julliardde424282001-08-10 22:51:42 +00002409 if (is_old_app(hwnd) && ( descr->style & ( WS_VSCROLL | WS_HSCROLL ) ) )
Nick Hollowayb9ce4fd1999-09-11 16:29:00 +00002410 {
2411 /* Win95 document "List Box Differences" from MSDN:
2412 If a list box in a version 3.x application has either the
2413 WS_HSCROLL or WS_VSCROLL style, the list box receives both
2414 horizontal and vertical scroll bars.
2415 */
2416 descr->style |= WS_VSCROLL | WS_HSCROLL;
2417 }
2418
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002419 if( lphc )
2420 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +00002421 TRACE_(combo)("[%04x]: resetting owner %04x -> %04x\n",
Alexandre Julliardde424282001-08-10 22:51:42 +00002422 hwnd, descr->owner, lphc->self );
2423 descr->owner = lphc->self;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002424 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00002425
Alexandre Julliardde424282001-08-10 22:51:42 +00002426 SetWindowLongA( hwnd, 0, (LONG)descr );
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002427
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002428/* if (wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) descr->style &= ~LBS_NOTIFY;
2429 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002430 if (descr->style & LBS_EXTENDEDSEL) descr->style |= LBS_MULTIPLESEL;
2431 if (descr->style & LBS_MULTICOLUMN) descr->style &= ~LBS_OWNERDRAWVARIABLE;
2432 if (descr->style & LBS_OWNERDRAWVARIABLE) descr->style |= LBS_NOINTEGRALHEIGHT;
Alexandre Julliardde424282001-08-10 22:51:42 +00002433 descr->item_height = LISTBOX_SetFont( hwnd, descr, 0 );
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002434
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002435 if (descr->style & LBS_OWNERDRAWFIXED)
2436 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002437 if( descr->lphc && (descr->lphc->dwStyle & CBS_DROPDOWN))
2438 {
2439 /* WinWord gets VERY unhappy if we send WM_MEASUREITEM from here */
Francis Beaudetf585c611999-04-02 10:37:42 +00002440 descr->item_height = lphc->fixedOwnerDrawHeight;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002441 }
2442 else
2443 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002444 UINT id = GetWindowLongA( hwnd, GWL_ID );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002445 mis.CtlType = ODT_LISTBOX;
Alexandre Julliardde424282001-08-10 22:51:42 +00002446 mis.CtlID = id;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002447 mis.itemID = -1;
2448 mis.itemWidth = 0;
2449 mis.itemData = 0;
2450 mis.itemHeight = descr->item_height;
Alexandre Julliardde424282001-08-10 22:51:42 +00002451 SendMessageW( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002452 descr->item_height = mis.itemHeight ? mis.itemHeight : 1;
2453 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002454 }
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002455
Andreas Mohr85ba8792001-01-06 00:34:14 +00002456 TRACE("owner: %04x, style: %08x, width: %d, height: %d\n", descr->owner, descr->style, descr->width, descr->height);
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002457 return TRUE;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002458}
2459
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002460
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002461/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002462 * LISTBOX_Destroy
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002463 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002464static BOOL LISTBOX_Destroy( HWND hwnd, LB_DESCR *descr )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002465{
Alexandre Julliardde424282001-08-10 22:51:42 +00002466 LISTBOX_ResetContent( hwnd, descr );
2467 SetWindowLongA( hwnd, 0, 0 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002468 HeapFree( GetProcessHeap(), 0, descr );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00002469 return TRUE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002470}
2471
2472
2473/***********************************************************************
Alexandre Julliardde424282001-08-10 22:51:42 +00002474 * ListBoxWndProc_common
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002475 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002476static LRESULT WINAPI ListBoxWndProc_common( HWND hwnd, UINT msg,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002477 WPARAM wParam, LPARAM lParam, BOOL unicode )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002478{
2479 LRESULT ret;
2480 LB_DESCR *descr;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002481
Alexandre Julliardde424282001-08-10 22:51:42 +00002482 if (!(descr = (LB_DESCR *)GetWindowLongA( hwnd, 0 )))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002483 {
Bill Medlande79f0762001-07-17 00:55:23 +00002484 if (msg == WM_CREATE)
2485 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002486 if (!LISTBOX_Create( hwnd, NULL ))
Bill Medlande79f0762001-07-17 00:55:23 +00002487 return -1;
Alexandre Julliardde424282001-08-10 22:51:42 +00002488 TRACE("creating wnd=%04x descr=%lx\n", hwnd, GetWindowLongA( hwnd, 0 ) );
Bill Medlande79f0762001-07-17 00:55:23 +00002489 return 0;
2490 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002491 /* Ignore all other messages before we get a WM_CREATE */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002492 return unicode ? DefWindowProcW( hwnd, msg, wParam, lParam ) :
2493 DefWindowProcA( hwnd, msg, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002494 }
2495
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002496 TRACE("[%04x]: msg %s wp %08x lp %08lx\n",
Guy L. Albertellidb9b5492001-09-07 18:38:57 +00002497 hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002498 switch(msg)
2499 {
2500 case LB_RESETCONTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002501 case LB_RESETCONTENT:
Alexandre Julliardde424282001-08-10 22:51:42 +00002502 LISTBOX_ResetContent( hwnd, descr );
2503 LISTBOX_UpdateScroll( hwnd, descr );
2504 InvalidateRect( hwnd, NULL, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002505 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002506
2507 case LB_ADDSTRING16:
Alexandre Julliard982a2232000-12-13 20:20:09 +00002508 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002509 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002510 case LB_ADDSTRING:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002511 {
2512 INT ret;
2513 LPWSTR textW;
2514 if(unicode || !HAS_STRINGS(descr))
2515 textW = (LPWSTR)lParam;
2516 else
2517 {
2518 LPSTR textA = (LPSTR)lParam;
2519 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2520 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2521 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2522 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002523 wParam = LISTBOX_FindStringPos( hwnd, descr, textW, FALSE );
2524 ret = LISTBOX_InsertString( hwnd, descr, wParam, textW );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002525 if (!unicode && HAS_STRINGS(descr))
2526 HeapFree(GetProcessHeap(), 0, textW);
2527 return ret;
2528 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002529
2530 case LB_INSERTSTRING16:
Alexandre Julliard982a2232000-12-13 20:20:09 +00002531 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002532 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002533 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002534 case LB_INSERTSTRING:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002535 {
2536 INT ret;
2537 LPWSTR textW;
2538 if(unicode || !HAS_STRINGS(descr))
2539 textW = (LPWSTR)lParam;
2540 else
2541 {
2542 LPSTR textA = (LPSTR)lParam;
2543 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2544 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2545 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2546 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002547 ret = LISTBOX_InsertString( hwnd, descr, wParam, textW );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002548 if(!unicode && HAS_STRINGS(descr))
2549 HeapFree(GetProcessHeap(), 0, textW);
2550 return ret;
2551 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002552
2553 case LB_ADDFILE16:
Alexandre Julliard982a2232000-12-13 20:20:09 +00002554 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002555 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002556 case LB_ADDFILE:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002557 {
2558 INT ret;
2559 LPWSTR textW;
2560 if(unicode || !HAS_STRINGS(descr))
2561 textW = (LPWSTR)lParam;
2562 else
2563 {
2564 LPSTR textA = (LPSTR)lParam;
2565 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2566 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2567 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2568 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002569 wParam = LISTBOX_FindFileStrPos( hwnd, descr, textW );
2570 ret = LISTBOX_InsertString( hwnd, descr, wParam, textW );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002571 if(!unicode && HAS_STRINGS(descr))
2572 HeapFree(GetProcessHeap(), 0, textW);
2573 return ret;
2574 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002575
2576 case LB_DELETESTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002577 case LB_DELETESTRING:
Alexandre Julliardde424282001-08-10 22:51:42 +00002578 if (LISTBOX_RemoveItem( hwnd, descr, wParam) != LB_ERR)
Gerard Patelc9a6d501999-07-25 13:03:17 +00002579 return descr->nb_items;
2580 else
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002581 return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002582
2583 case LB_GETITEMDATA16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002584 case LB_GETITEMDATA:
2585 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002586 return LB_ERR;
2587 return descr->items[wParam].data;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002588
2589 case LB_SETITEMDATA16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002590 case LB_SETITEMDATA:
2591 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002592 return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002593 descr->items[wParam].data = (DWORD)lParam;
Marcus Meissner9aded511999-05-01 10:23:45 +00002594 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002595
2596 case LB_GETCOUNT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002597 case LB_GETCOUNT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002598 return descr->nb_items;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002599
2600 case LB_GETTEXT16:
Alexandre Julliard982a2232000-12-13 20:20:09 +00002601 lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002602 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002603 case LB_GETTEXT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002604 return LISTBOX_GetText( descr, wParam, lParam, unicode );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002605
2606 case LB_GETTEXTLEN16:
2607 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002608 case LB_GETTEXTLEN:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002609 if ((INT)wParam >= descr->nb_items || (INT)wParam < 0)
Marcus Meissner9aded511999-05-01 10:23:45 +00002610 return LB_ERR;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002611 return (HAS_STRINGS(descr) ? strlenW(descr->items[wParam].str)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002612 : sizeof(DWORD));
2613
2614 case LB_GETCURSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002615 case LB_GETCURSEL:
Francis Beaudet8730e451999-03-25 13:22:02 +00002616 if (descr->nb_items==0)
Marcus Meissner9aded511999-05-01 10:23:45 +00002617 return LB_ERR;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002618 if (!IS_MULTISELECT(descr))
2619 return descr->selected_item;
Marcus Meissner9aded511999-05-01 10:23:45 +00002620 /* else */
2621 if (descr->selected_item!=-1)
2622 return descr->selected_item;
2623 /* else */
2624 return descr->focus_item;
Lawson Whitney613092a1999-03-22 14:46:43 +00002625 /* otherwise, if the user tries to move the selection with the */
2626 /* arrow keys, we will give the application something to choke on */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002627 case LB_GETTOPINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002628 case LB_GETTOPINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002629 return descr->top_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002630
2631 case LB_GETITEMHEIGHT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002632 case LB_GETITEMHEIGHT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002633 return LISTBOX_GetItemHeight( descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002634
2635 case LB_SETITEMHEIGHT16:
2636 lParam = LOWORD(lParam);
2637 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002638 case LB_SETITEMHEIGHT:
Alexandre Julliardc72a9aa2002-01-31 21:05:05 +00002639 return LISTBOX_SetItemHeight( hwnd, descr, wParam, lParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002640
Alexandre Julliarda3960291999-02-26 11:11:13 +00002641 case LB_ITEMFROMPOINT:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002642 {
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002643 POINT pt;
2644 RECT rect;
2645
2646 pt.x = LOWORD(lParam);
2647 pt.y = HIWORD(lParam);
2648 rect.left = 0;
2649 rect.top = 0;
2650 rect.right = descr->width;
2651 rect.bottom = descr->height;
2652
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002653 return MAKELONG( LISTBOX_GetItemFromPoint(descr, pt.x, pt.y),
Gerard Patel777508a1999-05-08 12:35:17 +00002654 !PtInRect( &rect, pt ) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002655 }
2656
2657 case LB_SETCARETINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002658 case LB_SETCARETINDEX:
Gerard Patelc9a6d501999-07-25 13:03:17 +00002659 if ((!IS_MULTISELECT(descr)) && (descr->selected_item != -1)) return LB_ERR;
Alexandre Julliardde424282001-08-10 22:51:42 +00002660 if (LISTBOX_SetCaretIndex( hwnd, descr, wParam, !lParam ) == LB_ERR)
Gerard Patelc9a6d501999-07-25 13:03:17 +00002661 return LB_ERR;
2662 else if (ISWIN31)
2663 return wParam;
2664 else
2665 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002666
2667 case LB_GETCARETINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002668 case LB_GETCARETINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002669 return descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002670
2671 case LB_SETTOPINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002672 case LB_SETTOPINDEX:
Alexandre Julliardde424282001-08-10 22:51:42 +00002673 return LISTBOX_SetTopItem( hwnd, descr, wParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002674
2675 case LB_SETCOLUMNWIDTH16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002676 case LB_SETCOLUMNWIDTH:
Alexandre Julliardde424282001-08-10 22:51:42 +00002677 return LISTBOX_SetColumnWidth( hwnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002678
2679 case LB_GETITEMRECT16:
2680 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002681 RECT rect;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002682 ret = LISTBOX_GetItemRect( descr, (INT16)wParam, &rect );
Alexandre Julliard982a2232000-12-13 20:20:09 +00002683 CONV_RECT32TO16( &rect, MapSL(lParam) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002684 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002685 return ret;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002686
Alexandre Julliarda3960291999-02-26 11:11:13 +00002687 case LB_GETITEMRECT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002688 return LISTBOX_GetItemRect( descr, wParam, (RECT *)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002689
2690 case LB_FINDSTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002691 wParam = (INT)(INT16)wParam;
Alexandre Julliard982a2232000-12-13 20:20:09 +00002692 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002693 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002694 case LB_FINDSTRING:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002695 {
2696 INT ret;
2697 LPWSTR textW;
2698 if(unicode || !HAS_STRINGS(descr))
2699 textW = (LPWSTR)lParam;
2700 else
2701 {
2702 LPSTR textA = (LPSTR)lParam;
2703 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2704 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2705 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2706 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002707 ret = LISTBOX_FindString( hwnd, descr, wParam, textW, FALSE );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002708 if(!unicode && HAS_STRINGS(descr))
2709 HeapFree(GetProcessHeap(), 0, textW);
2710 return ret;
2711 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002712
2713 case LB_FINDSTRINGEXACT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002714 wParam = (INT)(INT16)wParam;
Alexandre Julliard982a2232000-12-13 20:20:09 +00002715 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002716 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002717 case LB_FINDSTRINGEXACT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002718 {
2719 INT ret;
2720 LPWSTR textW;
2721 if(unicode || !HAS_STRINGS(descr))
2722 textW = (LPWSTR)lParam;
2723 else
2724 {
2725 LPSTR textA = (LPSTR)lParam;
2726 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2727 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2728 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2729 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002730 ret = LISTBOX_FindString( hwnd, descr, wParam, textW, TRUE );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002731 if(!unicode && HAS_STRINGS(descr))
2732 HeapFree(GetProcessHeap(), 0, textW);
2733 return ret;
2734 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002735
2736 case LB_SELECTSTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002737 wParam = (INT)(INT16)wParam;
Alexandre Julliard982a2232000-12-13 20:20:09 +00002738 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002739 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002740 case LB_SELECTSTRING:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002741 {
2742 INT index;
2743 LPWSTR textW;
Dmitry Timoshkove8ffcaa2001-04-16 19:32:19 +00002744
2745 if(HAS_STRINGS(descr))
2746 TRACE("LB_SELECTSTRING: %s\n", unicode ? debugstr_w((LPWSTR)lParam) :
2747 debugstr_a((LPSTR)lParam));
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002748 if(unicode || !HAS_STRINGS(descr))
2749 textW = (LPWSTR)lParam;
2750 else
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002751 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002752 LPSTR textA = (LPSTR)lParam;
2753 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2754 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2755 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002756 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002757 index = LISTBOX_FindString( hwnd, descr, wParam, textW, FALSE );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002758 if(!unicode && HAS_STRINGS(descr))
2759 HeapFree(GetProcessHeap(), 0, textW);
2760 if (index != LB_ERR)
Dmitry Timoshkove8ffcaa2001-04-16 19:32:19 +00002761 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002762 LISTBOX_SetCaretIndex( hwnd, descr, index, TRUE );
2763 LISTBOX_SetSelection( hwnd, descr, index, TRUE, FALSE );
Dmitry Timoshkove8ffcaa2001-04-16 19:32:19 +00002764 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002765 return index;
2766 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002767
2768 case LB_GETSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002769 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002770 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002771 case LB_GETSEL:
2772 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002773 return LB_ERR;
2774 return descr->items[wParam].selected;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002775
2776 case LB_SETSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002777 lParam = (INT)(INT16)lParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002778 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002779 case LB_SETSEL:
Alexandre Julliardde424282001-08-10 22:51:42 +00002780 return LISTBOX_SetSelection( hwnd, descr, lParam, wParam, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002781
2782 case LB_SETCURSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002783 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002784 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002785 case LB_SETCURSEL:
Gerard Patelc9a6d501999-07-25 13:03:17 +00002786 if (IS_MULTISELECT(descr)) return LB_ERR;
Alexandre Julliardde424282001-08-10 22:51:42 +00002787 LISTBOX_SetCaretIndex( hwnd, descr, wParam, TRUE );
2788 return LISTBOX_SetSelection( hwnd, descr, wParam, TRUE, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002789
2790 case LB_GETSELCOUNT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002791 case LB_GETSELCOUNT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002792 return LISTBOX_GetSelCount( descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002793
2794 case LB_GETSELITEMS16:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002795 return LISTBOX_GetSelItems16( descr, wParam, (LPINT16)MapSL(lParam) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002796
Alexandre Julliarda3960291999-02-26 11:11:13 +00002797 case LB_GETSELITEMS:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002798 return LISTBOX_GetSelItems( descr, wParam, (LPINT)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002799
2800 case LB_SELITEMRANGE16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002801 case LB_SELITEMRANGE:
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002802 if (LOWORD(lParam) <= HIWORD(lParam))
Alexandre Julliardde424282001-08-10 22:51:42 +00002803 return LISTBOX_SelectItemRange( hwnd, descr, LOWORD(lParam),
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002804 HIWORD(lParam), wParam );
2805 else
Alexandre Julliardde424282001-08-10 22:51:42 +00002806 return LISTBOX_SelectItemRange( hwnd, descr, HIWORD(lParam),
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002807 LOWORD(lParam), wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002808
2809 case LB_SELITEMRANGEEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002810 case LB_SELITEMRANGEEX:
2811 if ((INT)lParam >= (INT)wParam)
Alexandre Julliardde424282001-08-10 22:51:42 +00002812 return LISTBOX_SelectItemRange( hwnd, descr, wParam, lParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002813 else
Alexandre Julliardde424282001-08-10 22:51:42 +00002814 return LISTBOX_SelectItemRange( hwnd, descr, lParam, wParam, FALSE);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002815
2816 case LB_GETHORIZONTALEXTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002817 case LB_GETHORIZONTALEXTENT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002818 return descr->horz_extent;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002819
2820 case LB_SETHORIZONTALEXTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002821 case LB_SETHORIZONTALEXTENT:
Alexandre Julliardde424282001-08-10 22:51:42 +00002822 return LISTBOX_SetHorizontalExtent( hwnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002823
2824 case LB_GETANCHORINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002825 case LB_GETANCHORINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002826 return descr->anchor_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002827
2828 case LB_SETANCHORINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002829 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002830 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002831 case LB_SETANCHORINDEX:
2832 if (((INT)wParam < -1) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002833 return LB_ERR;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002834 descr->anchor_item = (INT)wParam;
Marcus Meissner9aded511999-05-01 10:23:45 +00002835 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002836
2837 case LB_DIR16:
Ove Kaaven2c691b32000-11-25 03:06:03 +00002838 /* according to Win16 docs, DDL_DRIVES should make DDL_EXCLUSIVE
2839 * be set automatically (this is different in Win32) */
2840 if (wParam & DDL_DRIVES) wParam |= DDL_EXCLUSIVE;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002841 lParam = (LPARAM)MapSL(lParam);
2842 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002843 case LB_DIR:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002844 {
2845 INT ret;
2846 LPWSTR textW;
2847 if(unicode)
2848 textW = (LPWSTR)lParam;
2849 else
2850 {
2851 LPSTR textA = (LPSTR)lParam;
2852 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2853 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2854 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2855 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002856 ret = LISTBOX_Directory( hwnd, descr, wParam, textW, msg == LB_DIR );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002857 if(!unicode)
2858 HeapFree(GetProcessHeap(), 0, textW);
2859 return ret;
2860 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002861
Alexandre Julliarda3960291999-02-26 11:11:13 +00002862 case LB_GETLOCALE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002863 return descr->locale;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002864
Alexandre Julliarda3960291999-02-26 11:11:13 +00002865 case LB_SETLOCALE:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002866 descr->locale = (LCID)wParam; /* FIXME: should check for valid lcid */
Marcus Meissner9aded511999-05-01 10:23:45 +00002867 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002868
Alexandre Julliarda3960291999-02-26 11:11:13 +00002869 case LB_INITSTORAGE:
Alexandre Julliardde424282001-08-10 22:51:42 +00002870 return LISTBOX_InitStorage( hwnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002871
Alexandre Julliarda3960291999-02-26 11:11:13 +00002872 case LB_SETCOUNT:
Alexandre Julliardde424282001-08-10 22:51:42 +00002873 return LISTBOX_SetCount( hwnd, descr, (INT)wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002874
2875 case LB_SETTABSTOPS16:
Alexandre Julliardde424282001-08-10 22:51:42 +00002876 return LISTBOX_SetTabStops( hwnd, descr, (INT)(INT16)wParam, MapSL(lParam), TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002877
Alexandre Julliarda3960291999-02-26 11:11:13 +00002878 case LB_SETTABSTOPS:
Alexandre Julliardde424282001-08-10 22:51:42 +00002879 return LISTBOX_SetTabStops( hwnd, descr, wParam, (LPINT)lParam, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002880
2881 case LB_CARETON16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002882 case LB_CARETON:
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002883 if (descr->caret_on)
Marcus Meissner9aded511999-05-01 10:23:45 +00002884 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002885 descr->caret_on = TRUE;
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002886 if ((descr->focus_item != -1) && (descr->in_focus))
Alexandre Julliardde424282001-08-10 22:51:42 +00002887 LISTBOX_RepaintItem( hwnd, descr, descr->focus_item, ODA_FOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002888 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002889
2890 case LB_CARETOFF16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002891 case LB_CARETOFF:
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002892 if (!descr->caret_on)
Marcus Meissner9aded511999-05-01 10:23:45 +00002893 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002894 descr->caret_on = FALSE;
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002895 if ((descr->focus_item != -1) && (descr->in_focus))
Alexandre Julliardde424282001-08-10 22:51:42 +00002896 LISTBOX_RepaintItem( hwnd, descr, descr->focus_item, ODA_FOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002897 return LB_OKAY;
Alexandre Julliardde424282001-08-10 22:51:42 +00002898
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002899 case WM_DESTROY:
Alexandre Julliardde424282001-08-10 22:51:42 +00002900 return LISTBOX_Destroy( hwnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002901
2902 case WM_ENABLE:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002903 InvalidateRect( hwnd, NULL, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002904 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002905
2906 case WM_SETREDRAW:
Alexandre Julliardde424282001-08-10 22:51:42 +00002907 LISTBOX_SetRedraw( hwnd, descr, wParam != 0 );
Marcus Meissner9aded511999-05-01 10:23:45 +00002908 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002909
2910 case WM_GETDLGCODE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002911 return DLGC_WANTARROWS | DLGC_WANTCHARS;
2912
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002913 case WM_PAINT:
2914 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002915 PAINTSTRUCT ps;
Alexandre Julliardde424282001-08-10 22:51:42 +00002916 HDC hdc = ( wParam ) ? ((HDC)wParam) : BeginPaint( hwnd, &ps );
2917 ret = LISTBOX_Paint( hwnd, descr, hdc );
Alexandre Julliarda3960291999-02-26 11:11:13 +00002918 if( !wParam ) EndPaint( hwnd, &ps );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002919 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002920 return ret;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002921 case WM_SIZE:
Alexandre Julliardde424282001-08-10 22:51:42 +00002922 LISTBOX_UpdateSize( hwnd, descr );
Marcus Meissner9aded511999-05-01 10:23:45 +00002923 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002924 case WM_GETFONT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002925 return descr->font;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002926 case WM_SETFONT:
Alexandre Julliardde424282001-08-10 22:51:42 +00002927 LISTBOX_SetFont( hwnd, descr, (HFONT)wParam );
2928 if (lParam) InvalidateRect( hwnd, 0, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002929 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002930 case WM_SETFOCUS:
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002931 descr->in_focus = TRUE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002932 descr->caret_on = TRUE;
2933 if (descr->focus_item != -1)
Alexandre Julliardde424282001-08-10 22:51:42 +00002934 LISTBOX_RepaintItem( hwnd, descr, descr->focus_item, ODA_FOCUS );
2935 SEND_NOTIFICATION( hwnd, descr, LBN_SETFOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002936 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002937 case WM_KILLFOCUS:
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002938 descr->in_focus = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002939 if ((descr->focus_item != -1) && descr->caret_on)
Alexandre Julliardde424282001-08-10 22:51:42 +00002940 LISTBOX_RepaintItem( hwnd, descr, descr->focus_item, ODA_FOCUS );
2941 SEND_NOTIFICATION( hwnd, descr, LBN_KILLFOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002942 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002943 case WM_HSCROLL:
Alexandre Julliardde424282001-08-10 22:51:42 +00002944 return LISTBOX_HandleHScroll( hwnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002945 case WM_VSCROLL:
Alexandre Julliardde424282001-08-10 22:51:42 +00002946 return LISTBOX_HandleVScroll( hwnd, descr, wParam );
Stephane Lussier4bdf4af2000-04-18 11:56:33 +00002947 case WM_MOUSEWHEEL:
2948 if (wParam & (MK_SHIFT | MK_CONTROL))
Alexandre Julliardde424282001-08-10 22:51:42 +00002949 return DefWindowProcW( hwnd, msg, wParam, lParam );
2950 return LISTBOX_HandleMouseWheel( hwnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002951 case WM_LBUTTONDOWN:
Alexandre Julliardde424282001-08-10 22:51:42 +00002952 return LISTBOX_HandleLButtonDown( hwnd, descr, wParam,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002953 (INT16)LOWORD(lParam),
2954 (INT16)HIWORD(lParam) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002955 case WM_LBUTTONDBLCLK:
2956 if (descr->style & LBS_NOTIFY)
Alexandre Julliardde424282001-08-10 22:51:42 +00002957 SEND_NOTIFICATION( hwnd, descr, LBN_DBLCLK );
Marcus Meissner9aded511999-05-01 10:23:45 +00002958 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002959 case WM_MOUSEMOVE:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002960 if (GetCapture() == hwnd)
Alexandre Julliardde424282001-08-10 22:51:42 +00002961 LISTBOX_HandleMouseMove( hwnd, descr, (INT16)LOWORD(lParam),
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002962 (INT16)HIWORD(lParam) );
Marcus Meissner9aded511999-05-01 10:23:45 +00002963 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002964 case WM_LBUTTONUP:
Alexandre Julliardde424282001-08-10 22:51:42 +00002965 return LISTBOX_HandleLButtonUp( hwnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002966 case WM_KEYDOWN:
Alexandre Julliardde424282001-08-10 22:51:42 +00002967 return LISTBOX_HandleKeyDown( hwnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002968 case WM_CHAR:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002969 {
2970 WCHAR charW;
2971 if(unicode)
2972 charW = (WCHAR)wParam;
2973 else
2974 {
2975 CHAR charA = (CHAR)wParam;
2976 MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1);
2977 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002978 return LISTBOX_HandleChar( hwnd, descr, charW );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002979 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002980 case WM_SYSTIMER:
Alexandre Julliardde424282001-08-10 22:51:42 +00002981 return LISTBOX_HandleSystemTimer( hwnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002982 case WM_ERASEBKGND:
Gerard Patel41b07fb2000-06-15 00:07:20 +00002983 if ((IS_OWNERDRAW(descr)) && !(descr->style & LBS_DISPLAYCHANGED))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002984 {
Luc Tourangeau89147991999-04-18 09:23:56 +00002985 RECT rect;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002986 HBRUSH hbrush = SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
Alexandre Julliardde424282001-08-10 22:51:42 +00002987 wParam, (LPARAM)hwnd );
Dmitry Timoshkov52ece0e2001-02-26 22:31:55 +00002988 TRACE("hbrush = %04x\n", hbrush);
2989 if(!hbrush)
2990 hbrush = GetSysColorBrush(COLOR_WINDOW);
2991 if(hbrush)
2992 {
2993 GetClientRect(hwnd, &rect);
2994 FillRect((HDC)wParam, &rect, hbrush);
2995 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002996 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002997 return 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002998 case WM_DROPFILES:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002999 if( !descr->lphc )
3000 return unicode ? SendMessageW( descr->owner, msg, wParam, lParam ) :
3001 SendMessageA( descr->owner, msg, wParam, lParam );
3002 break;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003003
3004 case WM_DROPOBJECT:
3005 case WM_QUERYDROPOBJECT:
3006 case WM_DRAGSELECT:
3007 case WM_DRAGMOVE:
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003008 if( !descr->lphc )
3009 {
Alexandre Julliard982a2232000-12-13 20:20:09 +00003010 LPDRAGINFO16 dragInfo = MapSL( lParam );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003011 dragInfo->l = LISTBOX_GetItemFromPoint( descr, dragInfo->pt.x,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003012 dragInfo->pt.y );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003013 return SendMessage16( descr->owner, msg, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003014 }
3015 break;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003016
3017 default:
3018 if ((msg >= WM_USER) && (msg < 0xc000))
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003019 WARN("[%04x]: unknown msg %04x wp %08x lp %08lx\n",
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003020 hwnd, msg, wParam, lParam );
3021 return unicode ? DefWindowProcW( hwnd, msg, wParam, lParam ) :
3022 DefWindowProcA( hwnd, msg, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003023 }
Marcus Meissner9aded511999-05-01 10:23:45 +00003024 return 0;
3025}
3026
3027/***********************************************************************
Alexandre Julliard91222da2000-12-10 23:01:33 +00003028 * ListBoxWndProcA
Marcus Meissner9aded511999-05-01 10:23:45 +00003029 *
3030 * This is just a wrapper for the real wndproc, it only does window locking
3031 * and unlocking.
3032 */
Alexandre Julliard91222da2000-12-10 23:01:33 +00003033static LRESULT WINAPI ListBoxWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
Marcus Meissner9aded511999-05-01 10:23:45 +00003034{
Alexandre Julliardde424282001-08-10 22:51:42 +00003035 if (!IsWindow(hwnd)) return 0;
3036 return ListBoxWndProc_common( hwnd, msg, wParam, lParam, FALSE );
Alexandre Julliard58199531994-04-21 01:20:00 +00003037}
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003038
3039/***********************************************************************
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003040 * ListBoxWndProcW
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003041 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003042static LRESULT WINAPI ListBoxWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003043{
Alexandre Julliardde424282001-08-10 22:51:42 +00003044 if (!IsWindow(hwnd)) return 0;
3045 return ListBoxWndProc_common( hwnd, msg, wParam, lParam, TRUE );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003046}
3047
3048/***********************************************************************
Alexandre Julliardde424282001-08-10 22:51:42 +00003049 * ComboLBWndProc_common
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003050 *
Alexandre Julliardde424282001-08-10 22:51:42 +00003051 * The real combo listbox wndproc
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003052 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003053static LRESULT WINAPI ComboLBWndProc_common( HWND hwnd, UINT msg,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003054 WPARAM wParam, LPARAM lParam, BOOL unicode )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003055{
3056 LRESULT lRet = 0;
Alexandre Julliardde424282001-08-10 22:51:42 +00003057 LB_DESCR *descr = (LB_DESCR *)GetWindowLongA( hwnd, 0 );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003058
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003059 TRACE_(combo)("[%04x]: msg %s wp %08x lp %08lx\n",
Guy L. Albertellidb9b5492001-09-07 18:38:57 +00003060 hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam );
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003061
3062 if( descr || msg == WM_CREATE )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003063 {
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003064 LPHEADCOMBO lphc = (descr) ? descr->lphc : NULL;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003065
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003066 switch( msg )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003067 {
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003068 case WM_CREATE:
3069 {
3070 CREATESTRUCTA *lpcs = (CREATESTRUCTA *)lParam;
3071 TRACE_(combo)("\tpassed parent handle = %p\n",lpcs->lpCreateParams);
3072 lphc = (LPHEADCOMBO)(lpcs->lpCreateParams);
Alexandre Julliardde424282001-08-10 22:51:42 +00003073 return LISTBOX_Create( hwnd, lphc );
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003074 }
3075 case WM_MOUSEMOVE:
3076 if ( (TWEAK_WineLook > WIN31_LOOK) &&
3077 (CB_GETTYPE(lphc) != CBS_SIMPLE) )
3078 {
3079 POINT mousePos;
3080 BOOL captured;
3081 RECT clientRect;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003082
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003083 mousePos.x = (INT16)LOWORD(lParam);
3084 mousePos.y = (INT16)HIWORD(lParam);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003085
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003086 /*
3087 * If we are in a dropdown combobox, we simulate that
3088 * the mouse is captured to show the tracking of the item.
3089 */
3090 GetClientRect(hwnd, &clientRect);
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003091
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003092 if (PtInRect( &clientRect, mousePos ))
3093 {
3094 captured = descr->captured;
3095 descr->captured = TRUE;
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003096
Alexandre Julliardde424282001-08-10 22:51:42 +00003097 LISTBOX_HandleMouseMove( hwnd, descr,
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003098 mousePos.x, mousePos.y);
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003099
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003100 descr->captured = captured;
Pierre Mageau25c62cc1999-09-11 16:26:03 +00003101
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003102 }
3103 else
3104 {
Alexandre Julliardde424282001-08-10 22:51:42 +00003105 LISTBOX_HandleMouseMove( hwnd, descr,
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003106 mousePos.x, mousePos.y);
3107 }
Pierre Mageau25c62cc1999-09-11 16:26:03 +00003108
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003109 return 0;
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003110
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003111 }
3112 else
3113 {
3114 /*
3115 * If we are in Win3.1 look, go with the default behavior.
3116 */
3117 return unicode ? ListBoxWndProcW( hwnd, msg, wParam, lParam ) :
3118 ListBoxWndProcA( hwnd, msg, wParam, lParam );
3119 }
3120 case WM_LBUTTONUP:
3121 if (TWEAK_WineLook > WIN31_LOOK)
3122 {
3123 POINT mousePos;
3124 RECT clientRect;
Pierre Mageau25c62cc1999-09-11 16:26:03 +00003125
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003126 /*
3127 * If the mouse button "up" is not in the listbox,
3128 * we make sure there is no selection by re-selecting the
3129 * item that was selected when the listbox was made visible.
3130 */
3131 mousePos.x = (INT16)LOWORD(lParam);
3132 mousePos.y = (INT16)HIWORD(lParam);
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003133
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003134 GetClientRect(hwnd, &clientRect);
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003135
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003136 /*
3137 * When the user clicks outside the combobox and the focus
3138 * is lost, the owning combobox will send a fake buttonup with
3139 * 0xFFFFFFF as the mouse location, we must also revert the
3140 * selection to the original selection.
3141 */
3142 if ( (lParam == (LPARAM)-1) ||
3143 (!PtInRect( &clientRect, mousePos )) )
3144 {
Alexandre Julliardde424282001-08-10 22:51:42 +00003145 LISTBOX_MoveCaret( hwnd, descr, lphc->droppedIndex, FALSE );
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003146 }
3147 }
Alexandre Julliardde424282001-08-10 22:51:42 +00003148 return LISTBOX_HandleLButtonUp( hwnd, descr );
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003149 case WM_LBUTTONDBLCLK:
3150 case WM_LBUTTONDOWN:
Alexandre Julliardde424282001-08-10 22:51:42 +00003151 return LISTBOX_HandleLButtonDownCombo(hwnd, descr, msg, wParam,
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003152 (INT16)LOWORD(lParam),
3153 (INT16)HIWORD(lParam) );
3154 case WM_NCACTIVATE:
3155 return FALSE;
3156 case WM_KEYDOWN:
3157 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
3158 {
3159 /* for some reason(?) Windows makes it possible to
3160 * show/hide ComboLBox by sending it WM_KEYDOWNs */
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003161
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003162 if( (!(lphc->wState & CBF_EUI) && wParam == VK_F4) ||
3163 ( (lphc->wState & CBF_EUI) && !(lphc->wState & CBF_DROPPED)
3164 && (wParam == VK_DOWN || wParam == VK_UP)) )
3165 {
3166 COMBO_FlipListbox( lphc, FALSE, FALSE );
3167 return 0;
3168 }
3169 }
Alexandre Julliardde424282001-08-10 22:51:42 +00003170 return LISTBOX_HandleKeyDown( hwnd, descr, wParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003171
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003172 case LB_SETCURSEL16:
3173 case LB_SETCURSEL:
3174 lRet = unicode ? ListBoxWndProcW( hwnd, msg, wParam, lParam ) :
3175 ListBoxWndProcA( hwnd, msg, wParam, lParam );
Alexandre Julliardde424282001-08-10 22:51:42 +00003176 lRet =(lRet == LB_ERR) ? lRet : descr->selected_item;
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003177 return lRet;
3178 case WM_NCDESTROY:
3179 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
3180 lphc->hWndLBox = 0;
3181 /* fall through */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003182
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003183 default:
3184 return unicode ? ListBoxWndProcW( hwnd, msg, wParam, lParam ) :
3185 ListBoxWndProcA( hwnd, msg, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003186 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003187 }
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003188 lRet = unicode ? DefWindowProcW( hwnd, msg, wParam, lParam ) :
3189 DefWindowProcA( hwnd, msg, wParam, lParam );
3190
3191 TRACE_(combo)("\t default on msg [%04x]\n", (UINT16)msg );
3192
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003193 return lRet;
3194}
3195
Marcus Meissner9aded511999-05-01 10:23:45 +00003196/***********************************************************************
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003197 * ComboLBWndProcA
Marcus Meissner9aded511999-05-01 10:23:45 +00003198 *
Vincent BĂ©ron9a624912002-05-31 23:06:46 +00003199 * NOTE: in Windows, winproc address of the ComboLBox is the same
Marcus Meissner9aded511999-05-01 10:23:45 +00003200 * as that of the Listbox.
Marcus Meissner9aded511999-05-01 10:23:45 +00003201 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003202LRESULT WINAPI ComboLBWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
Marcus Meissner9aded511999-05-01 10:23:45 +00003203{
Alexandre Julliardde424282001-08-10 22:51:42 +00003204 if (!IsWindow(hwnd)) return 0;
3205 return ComboLBWndProc_common( hwnd, msg, wParam, lParam, FALSE );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003206}
3207
3208/***********************************************************************
3209 * ComboLBWndProcW
3210 */
3211LRESULT WINAPI ComboLBWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
3212{
Alexandre Julliardde424282001-08-10 22:51:42 +00003213 if (!IsWindow(hwnd)) return 0;
3214 return ComboLBWndProc_common( hwnd, msg, wParam, lParam, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00003215}