blob: 360650816b5b559abd016078d46bb66e4420be5d [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"
Michael Stefaniuc2247af32002-09-04 19:37:01 +000035#include "win.h"
Alexandre Julliard0e607781993-11-03 19:23:37 +000036
Alexandre Julliard0799c1a2002-03-09 23:29:33 +000037WINE_DEFAULT_DEBUG_CHANNEL(listbox);
38WINE_DECLARE_DEBUG_CHANNEL(combo);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000039
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000040/* Unimplemented yet:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000041 * - LBS_USETABSTOPS
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000042 * - Locale handling
Andreas Mohr85ba8792001-01-06 00:34:14 +000043 *
44 * Probably needs improvement:
45 * - LBS_NOSEL
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000046 */
Alexandre Julliarde2abbb11995-03-19 17:39:39 +000047
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000048/* Items array granularity */
49#define LB_ARRAY_GRANULARITY 16
Alexandre Julliard0e607781993-11-03 19:23:37 +000050
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000051/* Scrolling timeout in ms */
52#define LB_SCROLL_TIMEOUT 50
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000053
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000054/* Listbox system timer id */
55#define LB_TIMER_ID 2
Alexandre Julliardac9c9b01996-07-28 18:50:11 +000056
Gerard Patel41b07fb2000-06-15 00:07:20 +000057/* flag listbox changed while setredraw false - internal style */
Alexandre Julliardde424282001-08-10 22:51:42 +000058#define LBS_DISPLAYCHANGED 0x80000000
Gerard Patel41b07fb2000-06-15 00:07:20 +000059
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000060/* Item structure */
61typedef struct
Alexandre Julliard2787be81995-05-22 18:23:01 +000062{
Dmitry Timoshkov74620992001-01-09 21:51:04 +000063 LPWSTR str; /* Item text */
Alexandre Julliarda3960291999-02-26 11:11:13 +000064 BOOL selected; /* Is item selected? */
65 UINT height; /* Item height (only for OWNERDRAWVARIABLE) */
Dmitry Timoshkov74620992001-01-09 21:51:04 +000066 DWORD data; /* User data */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000067} LB_ITEMDATA;
Alexandre Julliard2787be81995-05-22 18:23:01 +000068
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000069/* Listbox structure */
70typedef struct
Alexandre Julliard2787be81995-05-22 18:23:01 +000071{
Alexandre Julliarda3960291999-02-26 11:11:13 +000072 HWND owner; /* Owner window to send notifications to */
73 UINT style; /* Window style */
74 INT width; /* Window width */
75 INT height; /* Window height */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000076 LB_ITEMDATA *items; /* Array of items */
Alexandre Julliarda3960291999-02-26 11:11:13 +000077 INT nb_items; /* Number of items */
78 INT top_item; /* Top visible item */
79 INT selected_item; /* Selected item */
80 INT focus_item; /* Item that has the focus */
81 INT anchor_item; /* Anchor item for extended selection */
82 INT item_height; /* Default item height */
83 INT page_size; /* Items per listbox page */
84 INT column_width; /* Column width for multi-column listboxes */
85 INT horz_extent; /* Horizontal extent (0 if no hscroll) */
86 INT horz_pos; /* Horizontal position */
87 INT nb_tabs; /* Number of tabs in array */
88 INT *tabs; /* Array of tabs */
89 BOOL caret_on; /* Is caret on? */
Luc Tourangeau5ee117b1999-04-04 12:48:21 +000090 BOOL captured; /* Is mouse captured? */
Alexandre Julliardab2f43f2000-05-26 22:28:34 +000091 BOOL in_focus;
Alexandre Julliarda3960291999-02-26 11:11:13 +000092 HFONT font; /* Current font */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000093 LCID locale; /* Current locale for string comparisons */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000094 LPHEADCOMBO lphc; /* ComboLBox */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000095} LB_DESCR;
Alexandre Julliard2787be81995-05-22 18:23:01 +000096
Alexandre Julliardfa68b751995-04-03 16:55:37 +000097
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000098#define IS_OWNERDRAW(descr) \
99 ((descr)->style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE))
Alexandre Julliardb817f4f1996-03-14 18:08:34 +0000100
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000101#define HAS_STRINGS(descr) \
102 (!IS_OWNERDRAW(descr) || ((descr)->style & LBS_HASSTRINGS))
Alexandre Julliard2787be81995-05-22 18:23:01 +0000103
Gerard Patelc9a6d501999-07-25 13:03:17 +0000104
105#define IS_MULTISELECT(descr) \
106 ((descr)->style & LBS_MULTIPLESEL || ((descr)->style & LBS_EXTENDEDSEL))
107
Alexandre Julliardde424282001-08-10 22:51:42 +0000108#define SEND_NOTIFICATION(hwnd,descr,code) \
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000109 (SendMessageW( (descr)->owner, WM_COMMAND, \
Michael Stefaniuc2247af32002-09-04 19:37:01 +0000110 MAKEWPARAM( GetWindowLongA((hwnd),GWL_ID), (code)), (LPARAM)(hwnd) ))
Alexandre Julliardfa68b751995-04-03 16:55:37 +0000111
Gerard Patelc9a6d501999-07-25 13:03:17 +0000112#define ISWIN31 (LOWORD(GetVersion()) == 0x0a03)
113
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000114/* Current timer status */
115typedef enum
Alexandre Julliardfa68b751995-04-03 16:55:37 +0000116{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000117 LB_TIMER_NONE,
118 LB_TIMER_UP,
119 LB_TIMER_LEFT,
120 LB_TIMER_DOWN,
121 LB_TIMER_RIGHT
122} TIMER_DIRECTION;
Alexandre Julliardfa68b751995-04-03 16:55:37 +0000123
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000124static TIMER_DIRECTION LISTBOX_Timer = LB_TIMER_NONE;
125
Alexandre Julliard91222da2000-12-10 23:01:33 +0000126static LRESULT WINAPI ComboLBWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000127static LRESULT WINAPI ComboLBWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
Alexandre Julliard91222da2000-12-10 23:01:33 +0000128static LRESULT WINAPI ListBoxWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000129static LRESULT WINAPI ListBoxWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam );
Alexandre Julliard91222da2000-12-10 23:01:33 +0000130
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000131static LRESULT LISTBOX_GetItemRect( LB_DESCR *descr, INT index, RECT *rect );
Alexandre Julliard91222da2000-12-10 23:01:33 +0000132
133/*********************************************************************
134 * listbox class descriptor
135 */
136const struct builtin_class_descr LISTBOX_builtin_class =
137{
138 "ListBox", /* name */
139 CS_GLOBALCLASS | CS_DBLCLKS /*| CS_PARENTDC*/, /* style */
140 ListBoxWndProcA, /* procA */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000141 ListBoxWndProcW, /* procW */
Alexandre Julliard91222da2000-12-10 23:01:33 +0000142 sizeof(LB_DESCR *), /* extra */
143 IDC_ARROWA, /* cursor */
144 0 /* brush */
145};
146
147
148/*********************************************************************
149 * combolbox class descriptor
150 */
151const struct builtin_class_descr COMBOLBOX_builtin_class =
152{
153 "ComboLBox", /* name */
154 CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS, /* style */
155 ComboLBWndProcA, /* procA */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000156 ComboLBWndProcW, /* procW */
Alexandre Julliard91222da2000-12-10 23:01:33 +0000157 sizeof(LB_DESCR *), /* extra */
158 IDC_ARROWA, /* cursor */
159 0 /* brush */
160};
161
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000162
Alexandre Julliardde424282001-08-10 22:51:42 +0000163/* check whether app is a Win 3.1 app */
164inline static BOOL is_old_app( HWND hwnd )
165{
166 return (GetExpWinVer16( GetWindowLongA(hwnd,GWL_HINSTANCE) ) & 0xFF00 ) == 0x0300;
167}
168
169
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000170/***********************************************************************
171 * LISTBOX_Dump
172 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000173void LISTBOX_Dump( HWND hwnd )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000174{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000175 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000176 LB_ITEMDATA *item;
Alexandre Julliardde424282001-08-10 22:51:42 +0000177 LB_DESCR *descr = (LB_DESCR *)GetWindowLongA( hwnd, 0 );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000178
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000179 TRACE( "Listbox:\n" );
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000180 TRACE( "hwnd=%04x descr=%08x items=%d top=%d\n",
Alexandre Julliardde424282001-08-10 22:51:42 +0000181 hwnd, (UINT)descr, descr->nb_items,
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000182 descr->top_item );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000183 for (i = 0, item = descr->items; i < descr->nb_items; i++, item++)
184 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000185 TRACE( "%4d: %-40s %d %08lx %3d\n",
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000186 i, debugstr_w(item->str), item->selected, item->data, item->height );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000187 }
Alexandre Julliard2787be81995-05-22 18:23:01 +0000188}
189
190
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000191/***********************************************************************
192 * LISTBOX_GetCurrentPageSize
193 *
194 * Return the current page size
195 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000196static INT LISTBOX_GetCurrentPageSize( LB_DESCR *descr )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000197{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000198 INT i, height;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000199 if (!(descr->style & LBS_OWNERDRAWVARIABLE)) return descr->page_size;
200 for (i = descr->top_item, height = 0; i < descr->nb_items; i++)
201 {
202 if ((height += descr->items[i].height) > descr->height) break;
203 }
204 if (i == descr->top_item) return 1;
205 else return i - descr->top_item;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000206}
207
208
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000209/***********************************************************************
210 * LISTBOX_GetMaxTopIndex
211 *
212 * Return the maximum possible index for the top of the listbox.
213 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000214static INT LISTBOX_GetMaxTopIndex( LB_DESCR *descr )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000215{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000216 INT max, page;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000217
218 if (descr->style & LBS_OWNERDRAWVARIABLE)
219 {
220 page = descr->height;
221 for (max = descr->nb_items - 1; max >= 0; max--)
222 if ((page -= descr->items[max].height) < 0) break;
223 if (max < descr->nb_items - 1) max++;
224 }
225 else if (descr->style & LBS_MULTICOLUMN)
226 {
227 if ((page = descr->width / descr->column_width) < 1) page = 1;
228 max = (descr->nb_items + descr->page_size - 1) / descr->page_size;
229 max = (max - page) * descr->page_size;
230 }
231 else
232 {
233 max = descr->nb_items - descr->page_size;
234 }
235 if (max < 0) max = 0;
236 return max;
237}
238
239
240/***********************************************************************
241 * LISTBOX_UpdateScroll
242 *
243 * Update the scrollbars. Should be called whenever the content
244 * of the listbox changes.
245 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000246static void LISTBOX_UpdateScroll( HWND hwnd, LB_DESCR *descr )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000247{
248 SCROLLINFO info;
249
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000250 /* Check the listbox scroll bar flags individually before we call
251 SetScrollInfo otherwise when the listbox style is WS_HSCROLL and
252 no WS_VSCROLL, we end up with an uninitialized, visible horizontal
253 scroll bar when we do not need one.
254 if (!(descr->style & WS_VSCROLL)) return;
Alexandre Julliardde424282001-08-10 22:51:42 +0000255 */
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000256
Vincent BĂ©ron9a624912002-05-31 23:06:46 +0000257 /* It is important that we check descr->style, and not wnd->dwStyle,
258 for WS_VSCROLL, as the former is exactly the one passed in
259 argument to CreateWindow.
260 In Windows (and from now on in Wine :) a listbox created
261 with such a style (no WS_SCROLL) does not update
262 the scrollbar with listbox-related data, thus letting
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000263 the programmer use it for his/her own purposes. */
264
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000265 if (descr->style & LBS_NOREDRAW) return;
266 info.cbSize = sizeof(info);
267
268 if (descr->style & LBS_MULTICOLUMN)
269 {
270 info.nMin = 0;
271 info.nMax = (descr->nb_items - 1) / descr->page_size;
272 info.nPos = descr->top_item / descr->page_size;
273 info.nPage = descr->width / descr->column_width;
274 if (info.nPage < 1) info.nPage = 1;
275 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
276 if (descr->style & LBS_DISABLENOSCROLL)
277 info.fMask |= SIF_DISABLENOSCROLL;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000278 if (descr->style & WS_HSCROLL)
Alexandre Julliardde424282001-08-10 22:51:42 +0000279 SetScrollInfo( hwnd, SB_HORZ, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000280 info.nMax = 0;
281 info.fMask = SIF_RANGE;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000282 if (descr->style & WS_VSCROLL)
Alexandre Julliardde424282001-08-10 22:51:42 +0000283 SetScrollInfo( hwnd, SB_VERT, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000284 }
285 else
286 {
287 info.nMin = 0;
288 info.nMax = descr->nb_items - 1;
289 info.nPos = descr->top_item;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000290 info.nPage = LISTBOX_GetCurrentPageSize( descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000291 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
292 if (descr->style & LBS_DISABLENOSCROLL)
293 info.fMask |= SIF_DISABLENOSCROLL;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000294 if (descr->style & WS_VSCROLL)
Alexandre Julliardde424282001-08-10 22:51:42 +0000295 SetScrollInfo( hwnd, SB_VERT, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000296
297 if (descr->horz_extent)
298 {
299 info.nMin = 0;
300 info.nMax = descr->horz_extent - 1;
301 info.nPos = descr->horz_pos;
302 info.nPage = descr->width;
303 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
304 if (descr->style & LBS_DISABLENOSCROLL)
305 info.fMask |= SIF_DISABLENOSCROLL;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000306 if (descr->style & WS_HSCROLL)
Alexandre Julliardde424282001-08-10 22:51:42 +0000307 SetScrollInfo( hwnd, SB_HORZ, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000308 }
309 }
310}
311
312
313/***********************************************************************
314 * LISTBOX_SetTopItem
315 *
316 * Set the top item of the listbox, scrolling up or down if necessary.
317 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000318static LRESULT LISTBOX_SetTopItem( HWND hwnd, LB_DESCR *descr, INT index,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000319 BOOL scroll )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000320{
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000321 INT max = LISTBOX_GetMaxTopIndex( descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000322 if (index > max) index = max;
323 if (index < 0) index = 0;
324 if (descr->style & LBS_MULTICOLUMN) index -= index % descr->page_size;
325 if (descr->top_item == index) return LB_OKAY;
326 if (descr->style & LBS_MULTICOLUMN)
327 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000328 INT diff = (descr->top_item - index) / descr->page_size * descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000329 if (scroll && (abs(diff) < descr->width))
Alexandre Julliardde424282001-08-10 22:51:42 +0000330 ScrollWindowEx( hwnd, diff, 0, NULL, NULL, 0, NULL,
NF Stevens762f18d1999-01-24 19:02:16 +0000331 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
332
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000333 else
334 scroll = FALSE;
335 }
336 else if (scroll)
337 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000338 INT diff;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000339 if (descr->style & LBS_OWNERDRAWVARIABLE)
340 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000341 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000342 diff = 0;
343 if (index > descr->top_item)
344 {
345 for (i = index - 1; i >= descr->top_item; i--)
346 diff -= descr->items[i].height;
347 }
348 else
349 {
350 for (i = index; i < descr->top_item; i++)
351 diff += descr->items[i].height;
352 }
353 }
Alexandre Julliardde424282001-08-10 22:51:42 +0000354 else
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000355 diff = (descr->top_item - index) * descr->item_height;
356
357 if (abs(diff) < descr->height)
Alexandre Julliardde424282001-08-10 22:51:42 +0000358 ScrollWindowEx( hwnd, 0, diff, NULL, NULL, 0, NULL,
NF Stevens762f18d1999-01-24 19:02:16 +0000359 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000360 else
361 scroll = FALSE;
362 }
Alexandre Julliardde424282001-08-10 22:51:42 +0000363 if (!scroll) InvalidateRect( hwnd, NULL, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000364 descr->top_item = index;
Alexandre Julliardde424282001-08-10 22:51:42 +0000365 LISTBOX_UpdateScroll( hwnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000366 return LB_OKAY;
367}
368
369
370/***********************************************************************
371 * LISTBOX_UpdatePage
372 *
373 * Update the page size. Should be called when the size of
374 * the client area or the item height changes.
375 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000376static void LISTBOX_UpdatePage( HWND hwnd, LB_DESCR *descr )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000377{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000378 INT page_size;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000379
Alexandre Julliardde424282001-08-10 22:51:42 +0000380 if ((descr->item_height == 0) || (page_size = descr->height / descr->item_height) < 1)
Paul Quinn75722071999-05-22 18:45:06 +0000381 page_size = 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000382 if (page_size == descr->page_size) return;
383 descr->page_size = page_size;
384 if (descr->style & LBS_MULTICOLUMN)
Alexandre Julliardde424282001-08-10 22:51:42 +0000385 InvalidateRect( hwnd, NULL, TRUE );
386 LISTBOX_SetTopItem( hwnd, descr, descr->top_item, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000387}
388
389
390/***********************************************************************
391 * LISTBOX_UpdateSize
392 *
393 * Update the size of the listbox. Should be called when the size of
394 * the client area changes.
395 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000396static void LISTBOX_UpdateSize( HWND hwnd, LB_DESCR *descr )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000397{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000398 RECT rect;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000399
Alexandre Julliardde424282001-08-10 22:51:42 +0000400 GetClientRect( hwnd, &rect );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000401 descr->width = rect.right - rect.left;
402 descr->height = rect.bottom - rect.top;
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +0000403 if (!(descr->style & LBS_NOINTEGRALHEIGHT) && !(descr->style & LBS_OWNERDRAWVARIABLE))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000404 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000405 INT remaining;
Alexandre Julliardde424282001-08-10 22:51:42 +0000406 RECT rect;
Mike McCormack5ae1c392000-09-09 19:39:24 +0000407
Alexandre Julliardde424282001-08-10 22:51:42 +0000408 GetWindowRect( hwnd, &rect );
Mike McCormack5ae1c392000-09-09 19:39:24 +0000409 if(descr->item_height != 0)
410 remaining = descr->height % descr->item_height;
411 else
412 remaining = 0;
Gerard Patelcef12532000-08-01 20:48:40 +0000413 if ((descr->height > descr->item_height) && remaining)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000414 {
Alexandre Julliardde424282001-08-10 22:51:42 +0000415 if (is_old_app(hwnd))
Gerard Patelcef12532000-08-01 20:48:40 +0000416 { /* give a margin for error to 16 bits programs - if we need
417 less than the height of the nonclient area, round to the
Alexandre Julliardde424282001-08-10 22:51:42 +0000418 *next* number of items */
419 int ncheight = rect.bottom - rect.top - descr->height;
Gerard Patelcef12532000-08-01 20:48:40 +0000420 if ((descr->item_height - remaining) <= ncheight)
421 remaining = remaining - descr->item_height;
422 }
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000423 TRACE("[%04x]: changing height %d -> %d\n",
Alexandre Julliardde424282001-08-10 22:51:42 +0000424 hwnd, descr->height, descr->height - remaining );
425 SetWindowPos( hwnd, 0, 0, 0, rect.right - rect.left,
426 rect.bottom - rect.top - remaining,
Alexandre Julliard01d63461997-01-20 19:43:45 +0000427 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000428 return;
429 }
430 }
Alexandre Julliardde424282001-08-10 22:51:42 +0000431 TRACE("[%04x]: new size = %d,%d\n", hwnd, descr->width, descr->height );
432 LISTBOX_UpdatePage( hwnd, descr );
433 LISTBOX_UpdateScroll( hwnd, descr );
Louis Philippe Gagnon956c8472000-12-13 21:26:45 +0000434
435 /* Invalidate the focused item so it will be repainted correctly */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000436 if (LISTBOX_GetItemRect( descr, descr->focus_item, &rect ) == 1)
Louis Philippe Gagnon956c8472000-12-13 21:26:45 +0000437 {
Alexandre Julliardde424282001-08-10 22:51:42 +0000438 InvalidateRect( hwnd, &rect, FALSE );
Louis Philippe Gagnon956c8472000-12-13 21:26:45 +0000439 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000440}
441
442
443/***********************************************************************
444 * LISTBOX_GetItemRect
445 *
446 * Get the rectangle enclosing an item, in listbox client coordinates.
447 * Return 1 if the rectangle is (partially) visible, 0 if hidden, -1 on error.
448 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000449static LRESULT LISTBOX_GetItemRect( LB_DESCR *descr, INT index, RECT *rect )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000450{
451 /* Index <= 0 is legal even on empty listboxes */
452 if (index && (index >= descr->nb_items)) return -1;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000453 SetRect( rect, 0, 0, descr->width, descr->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000454 if (descr->style & LBS_MULTICOLUMN)
455 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000456 INT col = (index / descr->page_size) -
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000457 (descr->top_item / descr->page_size);
458 rect->left += col * descr->column_width;
459 rect->right = rect->left + descr->column_width;
460 rect->top += (index % descr->page_size) * descr->item_height;
461 rect->bottom = rect->top + descr->item_height;
462 }
463 else if (descr->style & LBS_OWNERDRAWVARIABLE)
464 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000465 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000466 rect->right += descr->horz_pos;
Alexandre Julliard349a9531997-02-02 19:01:52 +0000467 if ((index >= 0) && (index < descr->nb_items))
468 {
469 if (index < descr->top_item)
470 {
471 for (i = descr->top_item-1; i >= index; i--)
472 rect->top -= descr->items[i].height;
473 }
474 else
475 {
476 for (i = descr->top_item; i < index; i++)
477 rect->top += descr->items[i].height;
478 }
479 rect->bottom = rect->top + descr->items[index].height;
480
481 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000482 }
483 else
484 {
485 rect->top += (index - descr->top_item) * descr->item_height;
486 rect->bottom = rect->top + descr->item_height;
487 rect->right += descr->horz_pos;
488 }
489
490 return ((rect->left < descr->width) && (rect->right > 0) &&
491 (rect->top < descr->height) && (rect->bottom > 0));
492}
493
494
495/***********************************************************************
496 * LISTBOX_GetItemFromPoint
497 *
498 * Return the item nearest from point (x,y) (in client coordinates).
499 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000500static INT LISTBOX_GetItemFromPoint( LB_DESCR *descr, INT x, INT y )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000501{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000502 INT index = descr->top_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000503
504 if (!descr->nb_items) return -1; /* No items */
505 if (descr->style & LBS_OWNERDRAWVARIABLE)
506 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000507 INT pos = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000508 if (y >= 0)
509 {
510 while (index < descr->nb_items)
511 {
512 if ((pos += descr->items[index].height) > y) break;
513 index++;
514 }
515 }
516 else
517 {
518 while (index > 0)
519 {
520 index--;
521 if ((pos -= descr->items[index].height) <= y) break;
522 }
523 }
524 }
525 else if (descr->style & LBS_MULTICOLUMN)
526 {
527 if (y >= descr->item_height * descr->page_size) return -1;
528 if (y >= 0) index += y / descr->item_height;
529 if (x >= 0) index += (x / descr->column_width) * descr->page_size;
530 else index -= (((x + 1) / descr->column_width) - 1) * descr->page_size;
531 }
532 else
533 {
534 index += (y / descr->item_height);
535 }
536 if (index < 0) return 0;
537 if (index >= descr->nb_items) return -1;
538 return index;
539}
540
541
542/***********************************************************************
543 * LISTBOX_PaintItem
544 *
545 * Paint an item.
546 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000547static void LISTBOX_PaintItem( HWND hwnd, LB_DESCR *descr, HDC hdc,
Gerard Patel8caa4072000-09-24 19:29:18 +0000548 const RECT *rect, INT index, UINT action, BOOL ignoreFocus )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000549{
550 LB_ITEMDATA *item = NULL;
551 if (index < descr->nb_items) item = &descr->items[index];
552
553 if (IS_OWNERDRAW(descr))
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000554 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000555 DRAWITEMSTRUCT dis;
Gerard Patel9788ba62000-07-16 15:39:37 +0000556 RECT r;
557 HRGN hrgn;
Alexandre Julliardde424282001-08-10 22:51:42 +0000558 UINT id = GetWindowLongA( hwnd, GWL_ID );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000559
Marcus Meissner9ad90171999-01-20 14:08:00 +0000560 if (!item)
561 {
Alexandre Julliardde424282001-08-10 22:51:42 +0000562 if (action == ODA_FOCUS)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000563 DrawFocusRect( hdc, rect );
Marcus Meissner9ad90171999-01-20 14:08:00 +0000564 else
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000565 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 +0000566 return;
567 }
Gerard Patel9788ba62000-07-16 15:39:37 +0000568
569 /* some programs mess with the clipping region when
570 drawing the item, *and* restore the previous region
571 after they are done, so a region has better to exist
572 else everything ends clipped */
Alexandre Julliardde424282001-08-10 22:51:42 +0000573 GetClientRect(hwnd, &r);
Gerard Patel9788ba62000-07-16 15:39:37 +0000574 hrgn = CreateRectRgnIndirect(&r);
575 SelectClipRgn( hdc, hrgn);
576 DeleteObject( hrgn );
577
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000578 dis.CtlType = ODT_LISTBOX;
Alexandre Julliardde424282001-08-10 22:51:42 +0000579 dis.CtlID = id;
580 dis.hwndItem = hwnd;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000581 dis.itemAction = action;
582 dis.hDC = hdc;
583 dis.itemID = index;
584 dis.itemState = 0;
585 if (item && item->selected) dis.itemState |= ODS_SELECTED;
Gerard Patel8caa4072000-09-24 19:29:18 +0000586 if (!ignoreFocus && (descr->focus_item == index) &&
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000587 (descr->caret_on) &&
Alexandre Julliardab2f43f2000-05-26 22:28:34 +0000588 (descr->in_focus)) dis.itemState |= ODS_FOCUS;
Alexandre Julliardde424282001-08-10 22:51:42 +0000589 if (!IsWindowEnabled(hwnd)) dis.itemState |= ODS_DISABLED;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000590 dis.itemData = item ? item->data : 0;
591 dis.rcItem = *rect;
Alexandre Julliardde424282001-08-10 22:51:42 +0000592 TRACE("[%04x]: drawitem %d (%s) action=%02x state=%02x rect=%d,%d-%d,%d\n",
593 hwnd, index, item ? debugstr_w(item->str) : "", action,
594 dis.itemState, rect->left, rect->top, rect->right, rect->bottom );
595 SendMessageW(descr->owner, WM_DRAWITEM, id, (LPARAM)&dis);
Alexandre Julliard2787be81995-05-22 18:23:01 +0000596 }
597 else
Alexandre Julliardac9c9b01996-07-28 18:50:11 +0000598 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000599 COLORREF oldText = 0, oldBk = 0;
600
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000601 if (action == ODA_FOCUS)
602 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000603 DrawFocusRect( hdc, rect );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000604 return;
605 }
606 if (item && item->selected)
607 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000608 oldBk = SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
609 oldText = SetTextColor( hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000610 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000611
Alexandre Julliardde424282001-08-10 22:51:42 +0000612 TRACE("[%04x]: painting %d (%s) action=%02x rect=%d,%d-%d,%d\n",
613 hwnd, index, item ? debugstr_w(item->str) : "", action,
614 rect->left, rect->top, rect->right, rect->bottom );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000615 if (!item)
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000616 ExtTextOutW( hdc, rect->left + 1, rect->top,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000617 ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000618 else if (!(descr->style & LBS_USETABSTOPS))
619 ExtTextOutW( hdc, rect->left + 1, rect->top,
620 ETO_OPAQUE | ETO_CLIPPED, rect, item->str,
621 strlenW(item->str), NULL );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000622 else
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000623 {
624 /* Output empty string to paint background in the full width. */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000625 ExtTextOutW( hdc, rect->left + 1, rect->top,
626 ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
627 TabbedTextOutW( hdc, rect->left + 1 , rect->top,
628 item->str, strlenW(item->str),
629 descr->nb_tabs, descr->tabs, 0);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000630 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000631 if (item && item->selected)
632 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000633 SetBkColor( hdc, oldBk );
634 SetTextColor( hdc, oldText );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000635 }
Gerard Patel8caa4072000-09-24 19:29:18 +0000636 if (!ignoreFocus && (descr->focus_item == index) &&
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000637 (descr->caret_on) &&
Alexandre Julliardab2f43f2000-05-26 22:28:34 +0000638 (descr->in_focus)) DrawFocusRect( hdc, rect );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000639 }
Alexandre Julliard2787be81995-05-22 18:23:01 +0000640}
641
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000642
643/***********************************************************************
644 * LISTBOX_SetRedraw
645 *
646 * Change the redraw flag.
647 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000648static void LISTBOX_SetRedraw( HWND hwnd, LB_DESCR *descr, BOOL on )
Alexandre Julliardac9c9b01996-07-28 18:50:11 +0000649{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000650 if (on)
651 {
652 if (!(descr->style & LBS_NOREDRAW)) return;
653 descr->style &= ~LBS_NOREDRAW;
Gerard Patel41b07fb2000-06-15 00:07:20 +0000654 if (descr->style & LBS_DISPLAYCHANGED)
655 { /* page was changed while setredraw false, refresh automatically */
Alexandre Julliardde424282001-08-10 22:51:42 +0000656 InvalidateRect(hwnd, NULL, TRUE);
Gerard Patel41b07fb2000-06-15 00:07:20 +0000657 if ((descr->top_item + descr->page_size) > descr->nb_items)
Alexandre Julliardde424282001-08-10 22:51:42 +0000658 { /* reset top of page if less than number of items/page */
Gerard Patel41b07fb2000-06-15 00:07:20 +0000659 descr->top_item = descr->nb_items - descr->page_size;
660 if (descr->top_item < 0) descr->top_item = 0;
661 }
662 descr->style &= ~LBS_DISPLAYCHANGED;
663 }
Alexandre Julliardde424282001-08-10 22:51:42 +0000664 LISTBOX_UpdateScroll( hwnd, descr );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000665 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000666 else descr->style |= LBS_NOREDRAW;
667}
Alexandre Julliard2787be81995-05-22 18:23:01 +0000668
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000669
670/***********************************************************************
671 * LISTBOX_RepaintItem
672 *
673 * Repaint a single item synchronously.
674 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000675static void LISTBOX_RepaintItem( HWND hwnd, LB_DESCR *descr, INT index,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000676 UINT action )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000677{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000678 HDC hdc;
679 RECT rect;
680 HFONT oldFont = 0;
681 HBRUSH hbrush, oldBrush = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000682
Francois Boisvert428d2981999-05-08 09:33:53 +0000683 /* Do not repaint the item if the item is not visible */
Alexandre Julliardde424282001-08-10 22:51:42 +0000684 if (!IsWindowVisible(hwnd)) return;
Gerard Patel41b07fb2000-06-15 00:07:20 +0000685 if (descr->style & LBS_NOREDRAW)
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000686 {
Gerard Patel41b07fb2000-06-15 00:07:20 +0000687 descr->style |= LBS_DISPLAYCHANGED;
688 return;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000689 }
690 if (LISTBOX_GetItemRect( descr, index, &rect ) != 1) return;
Alexandre Julliardde424282001-08-10 22:51:42 +0000691 if (!(hdc = GetDCEx( hwnd, 0, DCX_CACHE ))) return;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000692 if (descr->font) oldFont = SelectObject( hdc, descr->font );
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000693 hbrush = SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
Alexandre Julliardde424282001-08-10 22:51:42 +0000694 hdc, (LPARAM)hwnd );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000695 if (hbrush) oldBrush = SelectObject( hdc, hbrush );
Alexandre Julliardde424282001-08-10 22:51:42 +0000696 if (!IsWindowEnabled(hwnd))
Alexandre Julliarda3960291999-02-26 11:11:13 +0000697 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
698 SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
Alexandre Julliardde424282001-08-10 22:51:42 +0000699 LISTBOX_PaintItem( hwnd, descr, hdc, &rect, index, action, FALSE );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000700 if (oldFont) SelectObject( hdc, oldFont );
701 if (oldBrush) SelectObject( hdc, oldBrush );
Alexandre Julliardde424282001-08-10 22:51:42 +0000702 ReleaseDC( hwnd, hdc );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000703}
704
705
706/***********************************************************************
707 * LISTBOX_InitStorage
708 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000709static LRESULT LISTBOX_InitStorage( HWND hwnd, LB_DESCR *descr, INT nb_items )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000710{
711 LB_ITEMDATA *item;
712
713 nb_items += LB_ARRAY_GRANULARITY - 1;
714 nb_items -= (nb_items % LB_ARRAY_GRANULARITY);
715 if (descr->items)
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000716 nb_items += HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(*item);
717 if (!(item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000718 nb_items * sizeof(LB_ITEMDATA) )))
719 {
Alexandre Julliardde424282001-08-10 22:51:42 +0000720 SEND_NOTIFICATION( hwnd, descr, LBN_ERRSPACE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000721 return LB_ERRSPACE;
722 }
723 descr->items = item;
724 return LB_OKAY;
725}
726
727
728/***********************************************************************
729 * LISTBOX_SetTabStops
730 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000731static BOOL LISTBOX_SetTabStops( HWND hwnd, LB_DESCR *descr, INT count,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000732 LPINT tabs, BOOL short_ints )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000733{
734 if (!(descr->style & LBS_USETABSTOPS)) return TRUE;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000735 if (descr->tabs) HeapFree( GetProcessHeap(), 0, descr->tabs );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000736 if (!(descr->nb_tabs = count))
737 {
738 descr->tabs = NULL;
739 return TRUE;
740 }
741 /* FIXME: count = 1 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000742 if (!(descr->tabs = (INT *)HeapAlloc( GetProcessHeap(), 0,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000743 descr->nb_tabs * sizeof(INT) )))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000744 return FALSE;
745 if (short_ints)
746 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000747 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000748 LPINT16 p = (LPINT16)tabs;
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000749
Alexandre Julliardde424282001-08-10 22:51:42 +0000750 TRACE("[%04x]: settabstops ", hwnd );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000751 for (i = 0; i < descr->nb_tabs; i++) {
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000752 descr->tabs[i] = *p++<<1; /* FIXME */
Alexandre Julliard15de6151999-08-04 12:22:42 +0000753 if (TRACE_ON(listbox)) DPRINTF("%hd ", descr->tabs[i]);
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000754 }
Alexandre Julliard15de6151999-08-04 12:22:42 +0000755 if (TRACE_ON(listbox)) DPRINTF("\n");
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000756 }
Alexandre Julliarda3960291999-02-26 11:11:13 +0000757 else memcpy( descr->tabs, tabs, descr->nb_tabs * sizeof(INT) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000758 /* FIXME: repaint the window? */
Alexandre Julliard2787be81995-05-22 18:23:01 +0000759 return TRUE;
760}
761
762
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000763/***********************************************************************
764 * LISTBOX_GetText
765 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000766static LRESULT LISTBOX_GetText( LB_DESCR *descr, INT index, LPARAM lParam, BOOL unicode )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000767{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000768 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
769 if (HAS_STRINGS(descr))
770 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000771 if (!lParam)
772 return strlenW(descr->items[index].str);
773
Dmitry Timoshkove8ffcaa2001-04-16 19:32:19 +0000774 TRACE("index %d (0x%04x) %s\n", index, index, debugstr_w(descr->items[index].str));
775
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000776 if(unicode)
777 {
778 LPWSTR buffer = (LPWSTR)lParam;
779 strcpyW( buffer, descr->items[index].str );
780 return strlenW(buffer);
781 }
782 else
783 {
784 LPSTR buffer = (LPSTR)lParam;
Gerard Pateldb8fb6f2001-01-10 23:54:46 +0000785 return WideCharToMultiByte(CP_ACP, 0, descr->items[index].str, -1, buffer, 0x7FFFFFFF, NULL, NULL) - 1;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000786 }
Marcus Meissner4f7dc461998-11-22 15:43:34 +0000787 } else {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000788 if (lParam)
789 *((LPDWORD)lParam)=*(LPDWORD)(&descr->items[index].data);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000790 return sizeof(DWORD);
791 }
Alexandre Julliard2787be81995-05-22 18:23:01 +0000792}
793
794
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000795/***********************************************************************
796 * LISTBOX_FindStringPos
797 *
798 * Find the nearest string located before a given string in sort order.
799 * If 'exact' is TRUE, return an error if we don't get an exact match.
800 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000801static INT LISTBOX_FindStringPos( HWND hwnd, LB_DESCR *descr, LPCWSTR str,
Alexandre Julliarda3960291999-02-26 11:11:13 +0000802 BOOL exact )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000803{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000804 INT index, min, max, res = -1;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000805
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000806 if (!(descr->style & LBS_SORT)) return -1; /* Add it at the end */
807 min = 0;
808 max = descr->nb_items;
809 while (min != max)
810 {
811 index = (min + max) / 2;
812 if (HAS_STRINGS(descr))
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000813 res = lstrcmpiW( descr->items[index].str, str );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000814 else
815 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000816 COMPAREITEMSTRUCT cis;
Alexandre Julliardde424282001-08-10 22:51:42 +0000817 UINT id = GetWindowLongA( hwnd, GWL_ID );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000818
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000819 cis.CtlType = ODT_LISTBOX;
Alexandre Julliardde424282001-08-10 22:51:42 +0000820 cis.CtlID = id;
821 cis.hwndItem = hwnd;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000822 cis.itemID1 = index;
823 cis.itemData1 = descr->items[index].data;
824 cis.itemID2 = -1;
825 cis.itemData2 = (DWORD)str;
826 cis.dwLocaleId = descr->locale;
Alexandre Julliardde424282001-08-10 22:51:42 +0000827 res = SendMessageW( descr->owner, WM_COMPAREITEM, id, (LPARAM)&cis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000828 }
829 if (!res) return index;
830 if (res > 0) max = index;
831 else min = index + 1;
832 }
833 return exact ? -1 : max;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000834}
835
836
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000837/***********************************************************************
838 * LISTBOX_FindFileStrPos
839 *
840 * Find the nearest string located before a given string in directory
841 * sort order (i.e. first files, then directories, then drives).
842 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000843static INT LISTBOX_FindFileStrPos( HWND hwnd, LB_DESCR *descr, LPCWSTR str )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000844{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000845 INT min, max, res = -1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000846
847 if (!HAS_STRINGS(descr))
Alexandre Julliardde424282001-08-10 22:51:42 +0000848 return LISTBOX_FindStringPos( hwnd, descr, str, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000849 min = 0;
850 max = descr->nb_items;
851 while (min != max)
852 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000853 INT index = (min + max) / 2;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000854 LPCWSTR p = descr->items[index].str;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000855 if (*p == '[') /* drive or directory */
856 {
857 if (*str != '[') res = -1;
858 else if (p[1] == '-') /* drive */
859 {
860 if (str[1] == '-') res = str[2] - p[2];
861 else res = -1;
862 }
863 else /* directory */
864 {
865 if (str[1] == '-') res = 1;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000866 else res = lstrcmpiW( str, p );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000867 }
868 }
869 else /* filename */
870 {
871 if (*str == '[') res = 1;
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000872 else res = lstrcmpiW( str, p );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000873 }
874 if (!res) return index;
875 if (res < 0) max = index;
876 else min = index + 1;
877 }
878 return max;
879}
880
881
882/***********************************************************************
883 * LISTBOX_FindString
884 *
885 * Find the item beginning with a given string.
886 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000887static INT LISTBOX_FindString( HWND hwnd, LB_DESCR *descr, INT start,
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000888 LPCWSTR str, BOOL exact )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000889{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000890 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000891 LB_ITEMDATA *item;
892
893 if (start >= descr->nb_items) start = -1;
894 item = descr->items + start + 1;
895 if (HAS_STRINGS(descr))
896 {
Rein Klazesd35c8341999-08-21 13:04:58 +0000897 if (!str || ! str[0] ) return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000898 if (exact)
899 {
900 for (i = start + 1; i < descr->nb_items; i++, item++)
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000901 if (!lstrcmpiW( str, item->str )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000902 for (i = 0, item = descr->items; i <= start; i++, item++)
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000903 if (!lstrcmpiW( str, item->str )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000904 }
905 else
906 {
907 /* Special case for drives and directories: ignore prefix */
908#define CHECK_DRIVE(item) \
909 if ((item)->str[0] == '[') \
910 { \
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000911 if (!strncmpiW( str, (item)->str+1, len )) return i; \
912 if (((item)->str[1] == '-') && !strncmpiW(str, (item)->str+2, len)) \
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000913 return i; \
914 }
915
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000916 INT len = strlenW(str);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000917 for (i = start + 1; i < descr->nb_items; i++, item++)
918 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000919 if (!strncmpiW( str, item->str, len )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000920 CHECK_DRIVE(item);
921 }
922 for (i = 0, item = descr->items; i <= start; i++, item++)
923 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000924 if (!strncmpiW( str, item->str, len )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000925 CHECK_DRIVE(item);
926 }
927#undef CHECK_DRIVE
928 }
929 }
930 else
931 {
932 if (exact && (descr->style & LBS_SORT))
933 /* If sorted, use a WM_COMPAREITEM binary search */
Alexandre Julliardde424282001-08-10 22:51:42 +0000934 return LISTBOX_FindStringPos( hwnd, descr, str, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000935
936 /* Otherwise use a linear search */
937 for (i = start + 1; i < descr->nb_items; i++, item++)
938 if (item->data == (DWORD)str) return i;
939 for (i = 0, item = descr->items; i <= start; i++, item++)
940 if (item->data == (DWORD)str) return i;
941 }
942 return LB_ERR;
943}
944
945
946/***********************************************************************
947 * LISTBOX_GetSelCount
948 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000949static LRESULT LISTBOX_GetSelCount( LB_DESCR *descr )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000950{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000951 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000952 LB_ITEMDATA *item = descr->items;
953
954 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
955 for (i = count = 0; i < descr->nb_items; i++, item++)
956 if (item->selected) count++;
957 return count;
958}
959
960
961/***********************************************************************
962 * LISTBOX_GetSelItems16
963 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000964static LRESULT LISTBOX_GetSelItems16( LB_DESCR *descr, INT16 max, LPINT16 array )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000965{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000966 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000967 LB_ITEMDATA *item = descr->items;
968
969 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
970 for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++)
971 if (item->selected) array[count++] = (INT16)i;
972 return count;
973}
974
975
976/***********************************************************************
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000977 * LISTBOX_GetSelItems
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000978 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +0000979static LRESULT LISTBOX_GetSelItems( LB_DESCR *descr, INT max, LPINT array )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000980{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000981 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000982 LB_ITEMDATA *item = descr->items;
983
984 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
985 for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++)
986 if (item->selected) array[count++] = i;
987 return count;
988}
989
990
991/***********************************************************************
992 * LISTBOX_Paint
993 */
Alexandre Julliardde424282001-08-10 22:51:42 +0000994static LRESULT LISTBOX_Paint( HWND hwnd, LB_DESCR *descr, HDC hdc )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000995{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000996 INT i, col_pos = descr->page_size - 1;
997 RECT rect;
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +0000998 RECT focusRect = {-1, -1, -1, -1};
Alexandre Julliarda3960291999-02-26 11:11:13 +0000999 HFONT oldFont = 0;
1000 HBRUSH hbrush, oldBrush = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001001
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001002 if (descr->style & LBS_NOREDRAW) return 0;
Serge Ivanov07917e42000-06-07 03:46:57 +00001003
1004 SetRect( &rect, 0, 0, descr->width, descr->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001005 if (descr->style & LBS_MULTICOLUMN)
1006 rect.right = rect.left + descr->column_width;
1007 else if (descr->horz_pos)
1008 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001009 SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001010 rect.right += descr->horz_pos;
1011 }
1012
Alexandre Julliarda3960291999-02-26 11:11:13 +00001013 if (descr->font) oldFont = SelectObject( hdc, descr->font );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001014 hbrush = SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
Alexandre Julliardde424282001-08-10 22:51:42 +00001015 hdc, (LPARAM)hwnd );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001016 if (hbrush) oldBrush = SelectObject( hdc, hbrush );
Alexandre Julliardde424282001-08-10 22:51:42 +00001017 if (!IsWindowEnabled(hwnd)) SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001018
1019 if (!descr->nb_items && (descr->focus_item != -1) && descr->caret_on &&
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00001020 (descr->in_focus))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001021 {
1022 /* Special case for empty listbox: paint focus rect */
1023 rect.bottom = rect.top + descr->item_height;
Alexandre Julliardde424282001-08-10 22:51:42 +00001024 LISTBOX_PaintItem( hwnd, descr, hdc, &rect, descr->focus_item,
Gerard Patel8caa4072000-09-24 19:29:18 +00001025 ODA_FOCUS, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001026 rect.top = rect.bottom;
1027 }
1028
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001029 /* Paint all the item, regarding the selection
1030 Focus state will be painted after */
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001031
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001032 for (i = descr->top_item; i < descr->nb_items; i++)
1033 {
1034 if (!(descr->style & LBS_OWNERDRAWVARIABLE))
1035 rect.bottom = rect.top + descr->item_height;
1036 else
1037 rect.bottom = rect.top + descr->items[i].height;
1038
Gerard Patel8caa4072000-09-24 19:29:18 +00001039 if (i == descr->focus_item)
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001040 {
1041 /* keep the focus rect, to paint the focus item after */
1042 focusRect.left = rect.left;
1043 focusRect.right = rect.right;
1044 focusRect.top = rect.top;
1045 focusRect.bottom = rect.bottom;
1046 }
Alexandre Julliardde424282001-08-10 22:51:42 +00001047 LISTBOX_PaintItem( hwnd, descr, hdc, &rect, i, ODA_DRAWENTIRE, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001048 rect.top = rect.bottom;
1049
1050 if ((descr->style & LBS_MULTICOLUMN) && !col_pos)
1051 {
1052 if (!IS_OWNERDRAW(descr))
1053 {
1054 /* Clear the bottom of the column */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001055 if (rect.top < descr->height)
1056 {
1057 rect.bottom = descr->height;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001058 ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001059 &rect, NULL, 0, NULL );
1060 }
1061 }
1062
1063 /* Go to the next column */
1064 rect.left += descr->column_width;
1065 rect.right += descr->column_width;
1066 rect.top = 0;
1067 col_pos = descr->page_size - 1;
1068 }
1069 else
1070 {
1071 col_pos--;
1072 if (rect.top >= descr->height) break;
1073 }
1074 }
1075
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001076 /* Paint the focus item now */
Serge Ivanov07917e42000-06-07 03:46:57 +00001077 if (focusRect.top != focusRect.bottom && descr->caret_on)
Alexandre Julliardde424282001-08-10 22:51:42 +00001078 LISTBOX_PaintItem( hwnd, descr, hdc, &focusRect, descr->focus_item, ODA_FOCUS, FALSE );
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001079
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001080 if (!IS_OWNERDRAW(descr))
1081 {
1082 /* Clear the remainder of the client area */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001083 if (rect.top < descr->height)
1084 {
1085 rect.bottom = descr->height;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001086 ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001087 &rect, NULL, 0, NULL );
1088 }
1089 if (rect.right < descr->width)
1090 {
1091 rect.left = rect.right;
1092 rect.right = descr->width;
1093 rect.top = 0;
1094 rect.bottom = descr->height;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001095 ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001096 &rect, NULL, 0, NULL );
1097 }
1098 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001099 if (oldFont) SelectObject( hdc, oldFont );
1100 if (oldBrush) SelectObject( hdc, oldBrush );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001101 return 0;
1102}
1103
1104
1105/***********************************************************************
1106 * LISTBOX_InvalidateItems
1107 *
1108 * Invalidate all items from a given item. If the specified item is not
1109 * visible, nothing happens.
1110 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001111static void LISTBOX_InvalidateItems( HWND hwnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001112{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001113 RECT rect;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001114
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001115 if (LISTBOX_GetItemRect( descr, index, &rect ) == 1)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001116 {
Gerard Patel41b07fb2000-06-15 00:07:20 +00001117 if (descr->style & LBS_NOREDRAW)
1118 {
1119 descr->style |= LBS_DISPLAYCHANGED;
1120 return;
1121 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001122 rect.bottom = descr->height;
Alexandre Julliardde424282001-08-10 22:51:42 +00001123 InvalidateRect( hwnd, &rect, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001124 if (descr->style & LBS_MULTICOLUMN)
1125 {
1126 /* Repaint the other columns */
1127 rect.left = rect.right;
1128 rect.right = descr->width;
1129 rect.top = 0;
Alexandre Julliardde424282001-08-10 22:51:42 +00001130 InvalidateRect( hwnd, &rect, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001131 }
1132 }
1133}
1134
1135
1136/***********************************************************************
1137 * LISTBOX_GetItemHeight
1138 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001139static LRESULT LISTBOX_GetItemHeight( LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001140{
1141 if (descr->style & LBS_OWNERDRAWVARIABLE)
1142 {
1143 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
1144 return descr->items[index].height;
1145 }
1146 else return descr->item_height;
1147}
1148
1149
1150/***********************************************************************
1151 * LISTBOX_SetItemHeight
1152 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001153static LRESULT LISTBOX_SetItemHeight( HWND hwnd, LB_DESCR *descr, INT index,
Alexandre Julliardc72a9aa2002-01-31 21:05:05 +00001154 INT height, BOOL repaint )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001155{
1156 if (!height) height = 1;
1157
1158 if (descr->style & LBS_OWNERDRAWVARIABLE)
1159 {
1160 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
Alexandre Julliardde424282001-08-10 22:51:42 +00001161 TRACE("[%04x]: item %d height = %d\n", hwnd, index, height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001162 descr->items[index].height = height;
Alexandre Julliardde424282001-08-10 22:51:42 +00001163 LISTBOX_UpdateScroll( hwnd, descr );
Alexandre Julliardc72a9aa2002-01-31 21:05:05 +00001164 if (repaint)
1165 LISTBOX_InvalidateItems( hwnd, descr, index );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001166 }
1167 else if (height != descr->item_height)
1168 {
Alexandre Julliardde424282001-08-10 22:51:42 +00001169 TRACE("[%04x]: new height = %d\n", hwnd, height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001170 descr->item_height = height;
Alexandre Julliardde424282001-08-10 22:51:42 +00001171 LISTBOX_UpdatePage( hwnd, descr );
1172 LISTBOX_UpdateScroll( hwnd, descr );
Alexandre Julliardc72a9aa2002-01-31 21:05:05 +00001173 if (repaint)
1174 InvalidateRect( hwnd, 0, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001175 }
1176 return LB_OKAY;
1177}
1178
1179
1180/***********************************************************************
1181 * LISTBOX_SetHorizontalPos
1182 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001183static void LISTBOX_SetHorizontalPos( HWND hwnd, LB_DESCR *descr, INT pos )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001184{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001185 INT diff;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001186
1187 if (pos > descr->horz_extent - descr->width)
1188 pos = descr->horz_extent - descr->width;
1189 if (pos < 0) pos = 0;
1190 if (!(diff = descr->horz_pos - pos)) return;
Alexandre Julliardde424282001-08-10 22:51:42 +00001191 TRACE("[%04x]: new horz pos = %d\n", hwnd, pos );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001192 descr->horz_pos = pos;
Alexandre Julliardde424282001-08-10 22:51:42 +00001193 LISTBOX_UpdateScroll( hwnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001194 if (abs(diff) < descr->width)
Alexandre Julliardde424282001-08-10 22:51:42 +00001195 ScrollWindowEx( hwnd, diff, 0, NULL, NULL, 0, NULL,
NF Stevens762f18d1999-01-24 19:02:16 +00001196 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001197 else
Alexandre Julliardde424282001-08-10 22:51:42 +00001198 InvalidateRect( hwnd, NULL, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001199}
1200
1201
1202/***********************************************************************
1203 * LISTBOX_SetHorizontalExtent
1204 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001205static LRESULT LISTBOX_SetHorizontalExtent( HWND hwnd, LB_DESCR *descr,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001206 INT extent )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001207{
1208 if (!descr->horz_extent || (descr->style & LBS_MULTICOLUMN))
1209 return LB_OKAY;
1210 if (extent <= 0) extent = 1;
1211 if (extent == descr->horz_extent) return LB_OKAY;
Alexandre Julliardde424282001-08-10 22:51:42 +00001212 TRACE("[%04x]: new horz extent = %d\n", hwnd, extent );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001213 descr->horz_extent = extent;
1214 if (descr->horz_pos > extent - descr->width)
Alexandre Julliardde424282001-08-10 22:51:42 +00001215 LISTBOX_SetHorizontalPos( hwnd, descr, extent - descr->width );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001216 else
Alexandre Julliardde424282001-08-10 22:51:42 +00001217 LISTBOX_UpdateScroll( hwnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001218 return LB_OKAY;
1219}
1220
1221
1222/***********************************************************************
1223 * LISTBOX_SetColumnWidth
1224 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001225static LRESULT LISTBOX_SetColumnWidth( HWND hwnd, LB_DESCR *descr, INT width)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001226{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001227 if (width == descr->column_width) return LB_OKAY;
Alexandre Julliardde424282001-08-10 22:51:42 +00001228 TRACE("[%04x]: new column width = %d\n", hwnd, width );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001229 descr->column_width = width;
Alexandre Julliardde424282001-08-10 22:51:42 +00001230 LISTBOX_UpdatePage( hwnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001231 return LB_OKAY;
1232}
1233
1234
1235/***********************************************************************
1236 * LISTBOX_SetFont
1237 *
1238 * Returns the item height.
1239 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001240static INT LISTBOX_SetFont( HWND hwnd, LB_DESCR *descr, HFONT font )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001241{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001242 HDC hdc;
1243 HFONT oldFont = 0;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001244 TEXTMETRICW tm;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001245
1246 descr->font = font;
1247
Alexandre Julliardde424282001-08-10 22:51:42 +00001248 if (!(hdc = GetDCEx( hwnd, 0, DCX_CACHE )))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001249 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001250 ERR("unable to get DC.\n" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001251 return 16;
1252 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001253 if (font) oldFont = SelectObject( hdc, font );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001254 GetTextMetricsW( hdc, &tm );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001255 if (oldFont) SelectObject( hdc, oldFont );
Alexandre Julliardde424282001-08-10 22:51:42 +00001256 ReleaseDC( hwnd, hdc );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001257 if (!IS_OWNERDRAW(descr))
Alexandre Julliardc72a9aa2002-01-31 21:05:05 +00001258 LISTBOX_SetItemHeight( hwnd, descr, 0, tm.tmHeight, FALSE );
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001259 return tm.tmHeight ;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001260}
1261
1262
1263/***********************************************************************
1264 * LISTBOX_MakeItemVisible
1265 *
1266 * Make sure that a given item is partially or fully visible.
1267 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001268static void LISTBOX_MakeItemVisible( HWND hwnd, LB_DESCR *descr, INT index,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001269 BOOL fully )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001270{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001271 INT top;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001272
1273 if (index <= descr->top_item) top = index;
1274 else if (descr->style & LBS_MULTICOLUMN)
1275 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001276 INT cols = descr->width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001277 if (!fully) cols += descr->column_width - 1;
1278 if (cols >= descr->column_width) cols /= descr->column_width;
1279 else cols = 1;
1280 if (index < descr->top_item + (descr->page_size * cols)) return;
1281 top = index - descr->page_size * (cols - 1);
1282 }
1283 else if (descr->style & LBS_OWNERDRAWVARIABLE)
1284 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001285 INT height = fully ? descr->items[index].height : 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001286 for (top = index; top > descr->top_item; top--)
1287 if ((height += descr->items[top-1].height) > descr->height) break;
1288 }
1289 else
1290 {
1291 if (index < descr->top_item + descr->page_size) return;
1292 if (!fully && (index == descr->top_item + descr->page_size) &&
1293 (descr->height > (descr->page_size * descr->item_height))) return;
1294 top = index - descr->page_size + 1;
1295 }
Alexandre Julliardde424282001-08-10 22:51:42 +00001296 LISTBOX_SetTopItem( hwnd, descr, top, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001297}
1298
Gerard Patel2ffbb312000-07-09 12:18:14 +00001299/***********************************************************************
1300 * LISTBOX_SetCaretIndex
1301 *
1302 * NOTES
1303 * index must be between 0 and descr->nb_items-1, or LB_ERR is returned.
1304 *
1305 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001306static LRESULT LISTBOX_SetCaretIndex( HWND hwnd, LB_DESCR *descr, INT index,
Gerard Patel2ffbb312000-07-09 12:18:14 +00001307 BOOL fully_visible )
1308{
Alexandre Julliardde424282001-08-10 22:51:42 +00001309 INT oldfocus = descr->focus_item;
Gerard Patel2ffbb312000-07-09 12:18:14 +00001310
Andreas Mohr85ba8792001-01-06 00:34:14 +00001311 if (descr->style & LBS_NOSEL) return LB_ERR;
Gerard Patel2ffbb312000-07-09 12:18:14 +00001312 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
1313 if (index == oldfocus) return LB_OKAY;
1314 descr->focus_item = index;
1315 if ((oldfocus != -1) && descr->caret_on && (descr->in_focus))
Alexandre Julliardde424282001-08-10 22:51:42 +00001316 LISTBOX_RepaintItem( hwnd, descr, oldfocus, ODA_FOCUS );
Gerard Patel2ffbb312000-07-09 12:18:14 +00001317
Alexandre Julliardde424282001-08-10 22:51:42 +00001318 LISTBOX_MakeItemVisible( hwnd, descr, index, fully_visible );
Gerard Patel2ffbb312000-07-09 12:18:14 +00001319 if (descr->caret_on && (descr->in_focus))
Alexandre Julliardde424282001-08-10 22:51:42 +00001320 LISTBOX_RepaintItem( hwnd, descr, index, ODA_FOCUS );
Gerard Patel2ffbb312000-07-09 12:18:14 +00001321
1322 return LB_OKAY;
1323}
1324
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001325
1326/***********************************************************************
1327 * LISTBOX_SelectItemRange
1328 *
1329 * Select a range of items. Should only be used on a MULTIPLESEL listbox.
1330 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001331static LRESULT LISTBOX_SelectItemRange( HWND hwnd, LB_DESCR *descr, INT first,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001332 INT last, BOOL on )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001333{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001334 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001335
1336 /* A few sanity checks */
1337
Andreas Mohr85ba8792001-01-06 00:34:14 +00001338 if (descr->style & LBS_NOSEL) return LB_ERR;
Alexandre Julliard03468f71998-02-15 19:40:49 +00001339 if ((last == -1) && (descr->nb_items == 0)) return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001340 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
1341 if (last == -1) last = descr->nb_items - 1;
1342 if ((first < 0) || (first >= descr->nb_items)) return LB_ERR;
1343 if ((last < 0) || (last >= descr->nb_items)) return LB_ERR;
1344 /* selected_item reflects last selected/unselected item on multiple sel */
1345 descr->selected_item = last;
1346
1347 if (on) /* Turn selection on */
1348 {
1349 for (i = first; i <= last; i++)
1350 {
1351 if (descr->items[i].selected) continue;
1352 descr->items[i].selected = TRUE;
Alexandre Julliardde424282001-08-10 22:51:42 +00001353 LISTBOX_RepaintItem( hwnd, descr, i, ODA_SELECT );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001354 }
Alexandre Julliardde424282001-08-10 22:51:42 +00001355 LISTBOX_SetCaretIndex( hwnd, descr, last, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001356 }
1357 else /* Turn selection off */
1358 {
1359 for (i = first; i <= last; i++)
1360 {
1361 if (!descr->items[i].selected) continue;
1362 descr->items[i].selected = FALSE;
Alexandre Julliardde424282001-08-10 22:51:42 +00001363 LISTBOX_RepaintItem( hwnd, descr, i, ODA_SELECT );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001364 }
1365 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001366 return LB_OKAY;
1367}
1368
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001369/***********************************************************************
1370 * LISTBOX_SetSelection
1371 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001372static LRESULT LISTBOX_SetSelection( HWND hwnd, LB_DESCR *descr, INT index,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001373 BOOL on, BOOL send_notify )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001374{
Dmitry Timoshkove0f493e1999-11-28 19:44:33 +00001375 TRACE( "index=%d notify=%s\n", index, send_notify ? "YES" : "NO" );
1376
Andreas Mohr85ba8792001-01-06 00:34:14 +00001377 if (descr->style & LBS_NOSEL) return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001378 if ((index < -1) || (index >= descr->nb_items)) return LB_ERR;
1379 if (descr->style & LBS_MULTIPLESEL)
1380 {
1381 if (index == -1) /* Select all items */
Alexandre Julliardde424282001-08-10 22:51:42 +00001382 return LISTBOX_SelectItemRange( hwnd, descr, 0, -1, on );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001383 else /* Only one item */
Alexandre Julliardde424282001-08-10 22:51:42 +00001384 return LISTBOX_SelectItemRange( hwnd, descr, index, index, on );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001385 }
1386 else
1387 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001388 INT oldsel = descr->selected_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001389 if (index == oldsel) return LB_OKAY;
1390 if (oldsel != -1) descr->items[oldsel].selected = FALSE;
1391 if (index != -1) descr->items[index].selected = TRUE;
1392 descr->selected_item = index;
Alexandre Julliardde424282001-08-10 22:51:42 +00001393 if (oldsel != -1) LISTBOX_RepaintItem( hwnd, descr, oldsel, ODA_SELECT );
1394 if (index != -1) LISTBOX_RepaintItem( hwnd, descr, index, ODA_SELECT );
1395 if (send_notify && descr->nb_items) SEND_NOTIFICATION( hwnd, descr,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001396 (index != -1) ? LBN_SELCHANGE : LBN_SELCANCEL );
Alex Korobka311d3291999-01-01 18:40:02 +00001397 else
1398 if( descr->lphc ) /* set selection change flag for parent combo */
1399 descr->lphc->wState |= CBF_SELCHANGE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001400 }
1401 return LB_OKAY;
1402}
1403
1404
1405/***********************************************************************
1406 * LISTBOX_MoveCaret
1407 *
1408 * Change the caret position and extend the selection to the new caret.
1409 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001410static void LISTBOX_MoveCaret( HWND hwnd, LB_DESCR *descr, INT index,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001411 BOOL fully_visible )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001412{
Alexandre Julliardde424282001-08-10 22:51:42 +00001413 INT oldfocus = descr->focus_item;
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001414
Alexandre Julliardde424282001-08-10 22:51:42 +00001415 if ((index < 0) || (index >= descr->nb_items))
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001416 return;
1417
1418 /* Important, repaint needs to be done in this order if
1419 you want to mimic Windows behavior:
Vincent BĂ©ron9a624912002-05-31 23:06:46 +00001420 1. Remove the focus and paint the item
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001421 2. Remove the selection and paint the item(s)
1422 3. Set the selection and repaint the item(s)
1423 4. Set the focus to 'index' and repaint the item */
1424
1425 /* 1. remove the focus and repaint the item */
1426 descr->focus_item = -1;
1427 if ((oldfocus != -1) && descr->caret_on && (descr->in_focus))
Alexandre Julliardde424282001-08-10 22:51:42 +00001428 LISTBOX_RepaintItem( hwnd, descr, oldfocus, ODA_FOCUS );
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001429
1430 /* 2. then turn off the previous selection */
1431 /* 3. repaint the new selected item */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001432 if (descr->style & LBS_EXTENDEDSEL)
1433 {
1434 if (descr->anchor_item != -1)
1435 {
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001436 INT first = min( index, descr->anchor_item );
1437 INT last = max( index, descr->anchor_item );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001438 if (first > 0)
Alexandre Julliardde424282001-08-10 22:51:42 +00001439 LISTBOX_SelectItemRange( hwnd, descr, 0, first - 1, FALSE );
1440 LISTBOX_SelectItemRange( hwnd, descr, last + 1, -1, FALSE );
1441 LISTBOX_SelectItemRange( hwnd, descr, first, last, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001442 }
1443 }
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00001444 else if (!(descr->style & LBS_MULTIPLESEL))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001445 {
1446 /* Set selection to new caret item */
Alexandre Julliardde424282001-08-10 22:51:42 +00001447 LISTBOX_SetSelection( hwnd, descr, index, TRUE, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001448 }
Alexandre Julliardde424282001-08-10 22:51:42 +00001449
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001450 /* 4. repaint the new item with the focus */
1451 descr->focus_item = index;
Alexandre Julliardde424282001-08-10 22:51:42 +00001452 LISTBOX_MakeItemVisible( hwnd, descr, index, fully_visible );
Alexandre Julliard72bdd5b2000-06-07 03:17:35 +00001453 if (descr->caret_on && (descr->in_focus))
Alexandre Julliardde424282001-08-10 22:51:42 +00001454 LISTBOX_RepaintItem( hwnd, descr, index, ODA_FOCUS );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001455}
1456
1457
1458/***********************************************************************
1459 * LISTBOX_InsertItem
1460 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001461static LRESULT LISTBOX_InsertItem( HWND hwnd, LB_DESCR *descr, INT index,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001462 LPWSTR str, DWORD data )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001463{
1464 LB_ITEMDATA *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001465 INT max_items;
Gerard Patelc9a6d501999-07-25 13:03:17 +00001466 INT oldfocus = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001467
1468 if (index == -1) index = descr->nb_items;
1469 else if ((index < 0) || (index > descr->nb_items)) return LB_ERR;
1470 if (!descr->items) max_items = 0;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001471 else max_items = HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(*item);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001472 if (descr->nb_items == max_items)
1473 {
1474 /* We need to grow the array */
1475 max_items += LB_ARRAY_GRANULARITY;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001476 if (!(item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001477 max_items * sizeof(LB_ITEMDATA) )))
1478 {
Alexandre Julliardde424282001-08-10 22:51:42 +00001479 SEND_NOTIFICATION( hwnd, descr, LBN_ERRSPACE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001480 return LB_ERRSPACE;
1481 }
1482 descr->items = item;
1483 }
1484
1485 /* Insert the item structure */
1486
1487 item = &descr->items[index];
1488 if (index < descr->nb_items)
1489 RtlMoveMemory( item + 1, item,
1490 (descr->nb_items - index) * sizeof(LB_ITEMDATA) );
1491 item->str = str;
1492 item->data = data;
1493 item->height = 0;
1494 item->selected = FALSE;
1495 descr->nb_items++;
1496
1497 /* Get item height */
1498
1499 if (descr->style & LBS_OWNERDRAWVARIABLE)
1500 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001501 MEASUREITEMSTRUCT mis;
Alexandre Julliardde424282001-08-10 22:51:42 +00001502 UINT id = GetWindowLongA( hwnd, GWL_ID );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001503
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001504 mis.CtlType = ODT_LISTBOX;
Alexandre Julliardde424282001-08-10 22:51:42 +00001505 mis.CtlID = id;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001506 mis.itemID = index;
1507 mis.itemData = descr->items[index].data;
1508 mis.itemHeight = descr->item_height;
Alexandre Julliardde424282001-08-10 22:51:42 +00001509 SendMessageW( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001510 item->height = mis.itemHeight ? mis.itemHeight : 1;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001511 TRACE("[%04x]: measure item %d (%s) = %d\n",
Alexandre Julliardde424282001-08-10 22:51:42 +00001512 hwnd, index, str ? debugstr_w(str) : "", item->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001513 }
1514
1515 /* Repaint the items */
1516
Alexandre Julliardde424282001-08-10 22:51:42 +00001517 LISTBOX_UpdateScroll( hwnd, descr );
1518 LISTBOX_InvalidateItems( hwnd, descr, index );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001519
1520 /* Move selection and focused item */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001521 /* If listbox was empty, set focus to the first item */
Gerard Patelc9a6d501999-07-25 13:03:17 +00001522 if (descr->nb_items == 1)
Alexandre Julliardde424282001-08-10 22:51:42 +00001523 LISTBOX_SetCaretIndex( hwnd, descr, 0, FALSE );
Gerard Patelc9a6d501999-07-25 13:03:17 +00001524 /* single select don't change selection index in win31 */
1525 else if ((ISWIN31) && !(IS_MULTISELECT(descr)))
1526 {
1527 descr->selected_item++;
Alexandre Julliardde424282001-08-10 22:51:42 +00001528 LISTBOX_SetSelection( hwnd, descr, descr->selected_item-1, TRUE, FALSE );
Gerard Patelc9a6d501999-07-25 13:03:17 +00001529 }
1530 else
1531 {
1532 if (index <= descr->selected_item)
1533 {
1534 descr->selected_item++;
1535 descr->focus_item = oldfocus; /* focus not changed */
1536 }
1537 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001538 return LB_OKAY;
1539}
1540
1541
1542/***********************************************************************
1543 * LISTBOX_InsertString
1544 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001545static LRESULT LISTBOX_InsertString( HWND hwnd, LB_DESCR *descr, INT index,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001546 LPCWSTR str )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001547{
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001548 LPWSTR new_str = NULL;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001549 DWORD data = 0;
1550 LRESULT ret;
1551
1552 if (HAS_STRINGS(descr))
1553 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001554 static const WCHAR empty_stringW[] = { 0 };
1555 if (!str) str = empty_stringW;
1556 if (!(new_str = HeapAlloc( GetProcessHeap(), 0, (strlenW(str) + 1) * sizeof(WCHAR) )))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001557 {
Alexandre Julliardde424282001-08-10 22:51:42 +00001558 SEND_NOTIFICATION( hwnd, descr, LBN_ERRSPACE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001559 return LB_ERRSPACE;
1560 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001561 strcpyW(new_str, str);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001562 }
1563 else data = (DWORD)str;
1564
1565 if (index == -1) index = descr->nb_items;
Alexandre Julliardde424282001-08-10 22:51:42 +00001566 if ((ret = LISTBOX_InsertItem( hwnd, descr, index, new_str, data )) != 0)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001567 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001568 if (new_str) HeapFree( GetProcessHeap(), 0, new_str );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001569 return ret;
1570 }
1571
Francois Gougetee285b72001-05-11 20:03:40 +00001572 TRACE("[%04x]: added item %d %s\n",
Alexandre Julliardde424282001-08-10 22:51:42 +00001573 hwnd, index, HAS_STRINGS(descr) ? debugstr_w(new_str) : "" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001574 return index;
1575}
1576
1577
1578/***********************************************************************
1579 * LISTBOX_DeleteItem
1580 *
1581 * Delete the content of an item. 'index' must be a valid index.
1582 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001583static void LISTBOX_DeleteItem( HWND hwnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001584{
1585 /* Note: Win 3.1 only sends DELETEITEM on owner-draw items,
1586 * while Win95 sends it for all items with user data.
1587 * It's probably better to send it too often than not
1588 * often enough, so this is what we do here.
1589 */
1590 if (IS_OWNERDRAW(descr) || descr->items[index].data)
1591 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001592 DELETEITEMSTRUCT dis;
Alexandre Julliardde424282001-08-10 22:51:42 +00001593 UINT id = GetWindowLongA( hwnd, GWL_ID );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001594
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001595 dis.CtlType = ODT_LISTBOX;
Alexandre Julliardde424282001-08-10 22:51:42 +00001596 dis.CtlID = id;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001597 dis.itemID = index;
Alexandre Julliardde424282001-08-10 22:51:42 +00001598 dis.hwndItem = hwnd;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001599 dis.itemData = descr->items[index].data;
Alexandre Julliardde424282001-08-10 22:51:42 +00001600 SendMessageW( descr->owner, WM_DELETEITEM, id, (LPARAM)&dis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001601 }
1602 if (HAS_STRINGS(descr) && descr->items[index].str)
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001603 HeapFree( GetProcessHeap(), 0, descr->items[index].str );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001604}
1605
1606
1607/***********************************************************************
1608 * LISTBOX_RemoveItem
1609 *
1610 * Remove an item from the listbox and delete its content.
1611 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001612static LRESULT LISTBOX_RemoveItem( HWND hwnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001613{
1614 LB_ITEMDATA *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001615 INT max_items;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001616
Aric Stewartfe9a0f02001-01-04 19:27:03 +00001617 if ((index == -1) && (descr->nb_items > 0)) index = descr->nb_items - 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001618 else if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +00001619
1620 /* We need to invalidate the original rect instead of the updated one. */
Alexandre Julliardde424282001-08-10 22:51:42 +00001621 LISTBOX_InvalidateItems( hwnd, descr, index );
Yuxi Zhangf94c3c52000-02-26 19:13:12 +00001622
Alexandre Julliardde424282001-08-10 22:51:42 +00001623 LISTBOX_DeleteItem( hwnd, descr, index );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001624
1625 /* Remove the item */
1626
1627 item = &descr->items[index];
1628 if (index < descr->nb_items-1)
1629 RtlMoveMemory( item, item + 1,
1630 (descr->nb_items - index - 1) * sizeof(LB_ITEMDATA) );
1631 descr->nb_items--;
1632 if (descr->anchor_item == descr->nb_items) descr->anchor_item--;
1633
1634 /* Shrink the item array if possible */
1635
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001636 max_items = HeapSize( GetProcessHeap(), 0, descr->items ) / sizeof(LB_ITEMDATA);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001637 if (descr->nb_items < max_items - 2*LB_ARRAY_GRANULARITY)
1638 {
1639 max_items -= LB_ARRAY_GRANULARITY;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001640 item = HeapReAlloc( GetProcessHeap(), 0, descr->items,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001641 max_items * sizeof(LB_ITEMDATA) );
1642 if (item) descr->items = item;
1643 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001644 /* Repaint the items */
1645
Alexandre Julliardde424282001-08-10 22:51:42 +00001646 LISTBOX_UpdateScroll( hwnd, descr );
Gerard Patelc9a6d501999-07-25 13:03:17 +00001647 /* if we removed the scrollbar, reset the top of the list
1648 (correct for owner-drawn ???) */
1649 if (descr->nb_items == descr->page_size)
Alexandre Julliardde424282001-08-10 22:51:42 +00001650 LISTBOX_SetTopItem( hwnd, descr, 0, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001651
1652 /* Move selection and focused item */
Gerard Patelc9a6d501999-07-25 13:03:17 +00001653 if (!IS_MULTISELECT(descr))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001654 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00001655 if (index == descr->selected_item)
1656 descr->selected_item = -1;
1657 else if (index < descr->selected_item)
1658 {
1659 descr->selected_item--;
1660 if (ISWIN31) /* win 31 do not change the selected item number */
Alexandre Julliardde424282001-08-10 22:51:42 +00001661 LISTBOX_SetSelection( hwnd, descr, descr->selected_item + 1, TRUE, FALSE);
Gerard Patelc9a6d501999-07-25 13:03:17 +00001662 }
1663 }
Yuxi Zhangf94c3c52000-02-26 19:13:12 +00001664
Gerard Patelc9a6d501999-07-25 13:03:17 +00001665 if (descr->focus_item >= descr->nb_items)
1666 {
1667 descr->focus_item = descr->nb_items - 1;
1668 if (descr->focus_item < 0) descr->focus_item = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001669 }
1670 return LB_OKAY;
1671}
1672
1673
1674/***********************************************************************
1675 * LISTBOX_ResetContent
1676 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001677static void LISTBOX_ResetContent( HWND hwnd, LB_DESCR *descr )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001678{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001679 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001680
Alexandre Julliardde424282001-08-10 22:51:42 +00001681 for (i = 0; i < descr->nb_items; i++) LISTBOX_DeleteItem( hwnd, descr, i );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001682 if (descr->items) HeapFree( GetProcessHeap(), 0, descr->items );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001683 descr->nb_items = 0;
1684 descr->top_item = 0;
1685 descr->selected_item = -1;
1686 descr->focus_item = 0;
1687 descr->anchor_item = -1;
1688 descr->items = NULL;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001689}
1690
1691
1692/***********************************************************************
1693 * LISTBOX_SetCount
1694 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001695static LRESULT LISTBOX_SetCount( HWND hwnd, LB_DESCR *descr, INT count )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001696{
1697 LRESULT ret;
1698
1699 if (HAS_STRINGS(descr)) return LB_ERR;
1700 /* FIXME: this is far from optimal... */
1701 if (count > descr->nb_items)
1702 {
1703 while (count > descr->nb_items)
Alexandre Julliardde424282001-08-10 22:51:42 +00001704 if ((ret = LISTBOX_InsertString( hwnd, descr, -1, 0 )) < 0)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001705 return ret;
1706 }
1707 else if (count < descr->nb_items)
1708 {
1709 while (count < descr->nb_items)
Alexandre Julliardde424282001-08-10 22:51:42 +00001710 if ((ret = LISTBOX_RemoveItem( hwnd, descr, -1 )) < 0)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001711 return ret;
1712 }
1713 return LB_OKAY;
1714}
1715
1716
1717/***********************************************************************
1718 * LISTBOX_Directory
1719 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001720static LRESULT LISTBOX_Directory( HWND hwnd, LB_DESCR *descr, UINT attrib,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001721 LPCWSTR filespec, BOOL long_names )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001722{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001723 HANDLE handle;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001724 LRESULT ret = LB_OKAY;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001725 WIN32_FIND_DATAW entry;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001726 int pos;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001727
Ove Kaaven2c691b32000-11-25 03:06:03 +00001728 /* don't scan directory if we just want drives exclusively */
1729 if (attrib != (DDL_DRIVES | DDL_EXCLUSIVE)) {
1730 /* scan directory */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001731 if ((handle = FindFirstFileW(filespec, &entry)) == INVALID_HANDLE_VALUE)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001732 {
Ove Kaaven2c691b32000-11-25 03:06:03 +00001733 if (GetLastError() != ERROR_NO_MORE_FILES) return LB_ERR;
1734 }
1735 else
1736 {
1737 do
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001738 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001739 WCHAR buffer[270];
Ove Kaaven2c691b32000-11-25 03:06:03 +00001740 if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1741 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001742 static const WCHAR bracketW[] = { ']',0 };
1743 static const WCHAR dotW[] = { '.',0 };
Ove Kaaven2c691b32000-11-25 03:06:03 +00001744 if (!(attrib & DDL_DIRECTORY) ||
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001745 !strcmpW( entry.cAlternateFileName, dotW )) continue;
1746 buffer[0] = '[';
1747 if (long_names) strcpyW( buffer + 1, entry.cFileName );
1748 else strcpyW( buffer + 1, entry.cAlternateFileName );
1749 strcatW(buffer, bracketW);
Ove Kaaven2c691b32000-11-25 03:06:03 +00001750 }
1751 else /* not a directory */
1752 {
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001753#define ATTRIBS (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
1754 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE)
1755
Ove Kaaven2c691b32000-11-25 03:06:03 +00001756 if ((attrib & DDL_EXCLUSIVE) &&
1757 ((attrib & ATTRIBS) != (entry.dwFileAttributes & ATTRIBS)))
1758 continue;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001759#undef ATTRIBS
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001760 if (long_names) strcpyW( buffer, entry.cFileName );
1761 else strcpyW( buffer, entry.cAlternateFileName );
Ove Kaaven2c691b32000-11-25 03:06:03 +00001762 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001763 if (!long_names) CharLowerW( buffer );
Alexandre Julliardde424282001-08-10 22:51:42 +00001764 pos = LISTBOX_FindFileStrPos( hwnd, descr, buffer );
1765 if ((ret = LISTBOX_InsertString( hwnd, descr, pos, buffer )) < 0)
Ove Kaaven2c691b32000-11-25 03:06:03 +00001766 break;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001767 } while (FindNextFileW( handle, &entry ));
Ove Kaaven2c691b32000-11-25 03:06:03 +00001768 FindClose( handle );
1769 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001770 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001771
Ove Kaaven2c691b32000-11-25 03:06:03 +00001772 /* scan drives */
Alexandre Julliard889f7421997-04-15 17:19:52 +00001773 if ((ret >= 0) && (attrib & DDL_DRIVES))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001774 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001775 WCHAR buffer[] = {'[','-','a','-',']',0};
1776 WCHAR root[] = {'A',':','\\',0};
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001777 int drive;
Alexandre Julliardbf672592000-12-12 00:44:42 +00001778 for (drive = 0; drive < 26; drive++, buffer[2]++, root[0]++)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001779 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001780 if (GetDriveTypeW(root) <= DRIVE_NO_ROOT_DIR) continue;
Alexandre Julliardde424282001-08-10 22:51:42 +00001781 if ((ret = LISTBOX_InsertString( hwnd, descr, -1, buffer )) < 0)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001782 break;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001783 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001784 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001785 return ret;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001786}
1787
1788
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001789/***********************************************************************
1790 * LISTBOX_HandleVScroll
1791 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001792static LRESULT LISTBOX_HandleVScroll( HWND hwnd, LB_DESCR *descr, WPARAM wParam )
Alexandre Julliard2787be81995-05-22 18:23:01 +00001793{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001794 SCROLLINFO info;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001795
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001796 if (descr->style & LBS_MULTICOLUMN) return 0;
1797 switch(LOWORD(wParam))
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +00001798 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001799 case SB_LINEUP:
Alexandre Julliardde424282001-08-10 22:51:42 +00001800 LISTBOX_SetTopItem( hwnd, descr, descr->top_item - 1, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001801 break;
1802 case SB_LINEDOWN:
Alexandre Julliardde424282001-08-10 22:51:42 +00001803 LISTBOX_SetTopItem( hwnd, descr, descr->top_item + 1, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001804 break;
1805 case SB_PAGEUP:
Alexandre Julliardde424282001-08-10 22:51:42 +00001806 LISTBOX_SetTopItem( hwnd, descr, descr->top_item -
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001807 LISTBOX_GetCurrentPageSize( descr ), TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001808 break;
1809 case SB_PAGEDOWN:
Alexandre Julliardde424282001-08-10 22:51:42 +00001810 LISTBOX_SetTopItem( hwnd, descr, descr->top_item +
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001811 LISTBOX_GetCurrentPageSize( descr ), TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001812 break;
1813 case SB_THUMBPOSITION:
Alexandre Julliardde424282001-08-10 22:51:42 +00001814 LISTBOX_SetTopItem( hwnd, descr, HIWORD(wParam), TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001815 break;
1816 case SB_THUMBTRACK:
1817 info.cbSize = sizeof(info);
1818 info.fMask = SIF_TRACKPOS;
Alexandre Julliardde424282001-08-10 22:51:42 +00001819 GetScrollInfo( hwnd, SB_VERT, &info );
1820 LISTBOX_SetTopItem( hwnd, descr, info.nTrackPos, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001821 break;
1822 case SB_TOP:
Alexandre Julliardde424282001-08-10 22:51:42 +00001823 LISTBOX_SetTopItem( hwnd, descr, 0, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001824 break;
1825 case SB_BOTTOM:
Alexandre Julliardde424282001-08-10 22:51:42 +00001826 LISTBOX_SetTopItem( hwnd, descr, descr->nb_items, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001827 break;
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +00001828 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001829 return 0;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001830}
1831
Alexandre Julliardb817f4f1996-03-14 18:08:34 +00001832
Alexandre Julliard2787be81995-05-22 18:23:01 +00001833/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001834 * LISTBOX_HandleHScroll
Alexandre Julliard2787be81995-05-22 18:23:01 +00001835 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001836static LRESULT LISTBOX_HandleHScroll( HWND hwnd, LB_DESCR *descr, WPARAM wParam )
Alexandre Julliard2787be81995-05-22 18:23:01 +00001837{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001838 SCROLLINFO info;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001839 INT page;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001840
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001841 if (descr->style & LBS_MULTICOLUMN)
1842 {
1843 switch(LOWORD(wParam))
1844 {
1845 case SB_LINELEFT:
Alexandre Julliardde424282001-08-10 22:51:42 +00001846 LISTBOX_SetTopItem( hwnd, descr, descr->top_item-descr->page_size,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001847 TRUE );
1848 break;
1849 case SB_LINERIGHT:
Alexandre Julliardde424282001-08-10 22:51:42 +00001850 LISTBOX_SetTopItem( hwnd, descr, descr->top_item+descr->page_size,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001851 TRUE );
1852 break;
1853 case SB_PAGELEFT:
1854 page = descr->width / descr->column_width;
1855 if (page < 1) page = 1;
Alexandre Julliardde424282001-08-10 22:51:42 +00001856 LISTBOX_SetTopItem( hwnd, descr,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001857 descr->top_item - page * descr->page_size, TRUE );
1858 break;
1859 case SB_PAGERIGHT:
1860 page = descr->width / descr->column_width;
1861 if (page < 1) page = 1;
Alexandre Julliardde424282001-08-10 22:51:42 +00001862 LISTBOX_SetTopItem( hwnd, descr,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001863 descr->top_item + page * descr->page_size, TRUE );
1864 break;
1865 case SB_THUMBPOSITION:
Alexandre Julliardde424282001-08-10 22:51:42 +00001866 LISTBOX_SetTopItem( hwnd, descr, HIWORD(wParam)*descr->page_size,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001867 TRUE );
1868 break;
1869 case SB_THUMBTRACK:
1870 info.cbSize = sizeof(info);
1871 info.fMask = SIF_TRACKPOS;
Alexandre Julliardde424282001-08-10 22:51:42 +00001872 GetScrollInfo( hwnd, SB_VERT, &info );
1873 LISTBOX_SetTopItem( hwnd, descr, info.nTrackPos*descr->page_size,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001874 TRUE );
1875 break;
1876 case SB_LEFT:
Alexandre Julliardde424282001-08-10 22:51:42 +00001877 LISTBOX_SetTopItem( hwnd, descr, 0, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001878 break;
1879 case SB_RIGHT:
Alexandre Julliardde424282001-08-10 22:51:42 +00001880 LISTBOX_SetTopItem( hwnd, descr, descr->nb_items, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001881 break;
1882 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001883 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001884 else if (descr->horz_extent)
1885 {
1886 switch(LOWORD(wParam))
1887 {
1888 case SB_LINELEFT:
Alexandre Julliardde424282001-08-10 22:51:42 +00001889 LISTBOX_SetHorizontalPos( hwnd, descr, descr->horz_pos - 1 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001890 break;
1891 case SB_LINERIGHT:
Alexandre Julliardde424282001-08-10 22:51:42 +00001892 LISTBOX_SetHorizontalPos( hwnd, descr, descr->horz_pos + 1 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001893 break;
1894 case SB_PAGELEFT:
Alexandre Julliardde424282001-08-10 22:51:42 +00001895 LISTBOX_SetHorizontalPos( hwnd, descr,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001896 descr->horz_pos - descr->width );
1897 break;
1898 case SB_PAGERIGHT:
Alexandre Julliardde424282001-08-10 22:51:42 +00001899 LISTBOX_SetHorizontalPos( hwnd, descr,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001900 descr->horz_pos + descr->width );
1901 break;
1902 case SB_THUMBPOSITION:
Alexandre Julliardde424282001-08-10 22:51:42 +00001903 LISTBOX_SetHorizontalPos( hwnd, descr, HIWORD(wParam) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001904 break;
1905 case SB_THUMBTRACK:
1906 info.cbSize = sizeof(info);
1907 info.fMask = SIF_TRACKPOS;
Alexandre Julliardde424282001-08-10 22:51:42 +00001908 GetScrollInfo( hwnd, SB_HORZ, &info );
1909 LISTBOX_SetHorizontalPos( hwnd, descr, info.nTrackPos );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001910 break;
1911 case SB_LEFT:
Alexandre Julliardde424282001-08-10 22:51:42 +00001912 LISTBOX_SetHorizontalPos( hwnd, descr, 0 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001913 break;
1914 case SB_RIGHT:
Alexandre Julliardde424282001-08-10 22:51:42 +00001915 LISTBOX_SetHorizontalPos( hwnd, descr,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001916 descr->horz_extent - descr->width );
1917 break;
1918 }
1919 }
1920 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001921}
1922
Alexandre Julliardde424282001-08-10 22:51:42 +00001923static LRESULT LISTBOX_HandleMouseWheel(HWND hwnd, LB_DESCR *descr, WPARAM wParam )
Stephane Lussier4bdf4af2000-04-18 11:56:33 +00001924{
1925 short gcWheelDelta = 0;
1926 UINT pulScrollLines = 3;
1927
1928 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
1929
1930 gcWheelDelta -= (short) HIWORD(wParam);
1931
1932 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
1933 {
1934 int cLineScroll = (int) min((UINT) descr->page_size, pulScrollLines);
1935 cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
Alexandre Julliardde424282001-08-10 22:51:42 +00001936 LISTBOX_SetTopItem( hwnd, descr, descr->top_item + cLineScroll, TRUE );
Stephane Lussier4bdf4af2000-04-18 11:56:33 +00001937 }
1938 return 0;
1939}
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001940
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001941/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001942 * LISTBOX_HandleLButtonDown
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001943 */
Alexandre Julliardde424282001-08-10 22:51:42 +00001944static LRESULT LISTBOX_HandleLButtonDown( HWND hwnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001945 WPARAM wParam, INT x, INT y )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001946{
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001947 INT index = LISTBOX_GetItemFromPoint( descr, x, y );
Alexandre Julliardde424282001-08-10 22:51:42 +00001948 TRACE("[%04x]: lbuttondown %d,%d item %d\n", hwnd, x, y, index );
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00001949 if (!descr->caret_on && (descr->in_focus)) return 0;
Jason Mawdsley50523d12000-06-11 20:34:07 +00001950
1951 if (!descr->in_focus)
1952 {
Alexandre Julliardde424282001-08-10 22:51:42 +00001953 if( !descr->lphc ) SetFocus( hwnd );
1954 else SetFocus( (descr->lphc->hWndEdit) ? descr->lphc->hWndEdit : descr->lphc->self );
Jason Mawdsley50523d12000-06-11 20:34:07 +00001955 }
1956
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001957 if (index == -1) return 0;
Andreas Mohr2b5d9c62000-08-29 03:52:16 +00001958
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001959 if (descr->style & LBS_EXTENDEDSEL)
1960 {
1961 /* we should perhaps make sure that all items are deselected
1962 FIXME: needed for !LBS_EXTENDEDSEL, too ?
1963 if (!(wParam & (MK_SHIFT|MK_CONTROL)))
Alexandre Julliardde424282001-08-10 22:51:42 +00001964 LISTBOX_SetSelection( hwnd, descr, -1, FALSE, FALSE);
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001965 */
1966
1967 if (!(wParam & MK_SHIFT)) descr->anchor_item = index;
1968 if (wParam & MK_CONTROL)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001969 {
Alexandre Julliardde424282001-08-10 22:51:42 +00001970 LISTBOX_SetCaretIndex( hwnd, descr, index, FALSE );
1971 LISTBOX_SetSelection( hwnd, descr, index,
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001972 !descr->items[index].selected,
1973 (descr->style & LBS_NOTIFY) != 0);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001974 }
Alexandre Julliardde424282001-08-10 22:51:42 +00001975 else LISTBOX_MoveCaret( hwnd, descr, index, FALSE );
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001976 }
1977 else
1978 {
Alexandre Julliardde424282001-08-10 22:51:42 +00001979 LISTBOX_MoveCaret( hwnd, descr, index, FALSE );
1980 LISTBOX_SetSelection( hwnd, descr, index,
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001981 (!(descr->style & LBS_MULTIPLESEL) ||
1982 !descr->items[index].selected),
1983 (descr->style & LBS_NOTIFY) != 0 );
Alexandre Julliard2787be81995-05-22 18:23:01 +00001984 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001985
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00001986 descr->captured = TRUE;
Alexandre Julliardde424282001-08-10 22:51:42 +00001987 SetCapture( hwnd );
Ulrich Czekalla7c55bc02000-12-15 22:58:25 +00001988
1989 if (!descr->lphc)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001990 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001991 if (descr->style & LBS_NOTIFY )
Dmitry Timoshkov74620992001-01-09 21:51:04 +00001992 SendMessageW( descr->owner, WM_LBTRACKPOINT, index,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001993 MAKELPARAM( x, y ) );
Alexandre Julliardde424282001-08-10 22:51:42 +00001994 if (GetWindowLongA( hwnd, GWL_EXSTYLE ) & WS_EX_DRAGDETECT)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001995 {
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00001996 POINT pt;
Alexandre Julliardde424282001-08-10 22:51:42 +00001997
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00001998 pt.x = x;
1999 pt.y = y;
2000
Alexandre Julliardde424282001-08-10 22:51:42 +00002001 if (DragDetect( hwnd, pt ))
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002002 SendMessageW( descr->owner, WM_BEGINDRAG, 0, 0 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002003 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00002004 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002005 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002006}
2007
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002008
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002009/*************************************************************************
Alexandre Julliardde424282001-08-10 22:51:42 +00002010 * LISTBOX_HandleLButtonDownCombo [Internal]
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002011 *
2012 * Process LButtonDown message for the ComboListBox
2013 *
Alexandre Julliardde424282001-08-10 22:51:42 +00002014nn * PARAMS
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002015 * pWnd [I] The windows internal structure
2016 * pDescr [I] The ListBox internal structure
2017 * wParam [I] Key Flag (WM_LBUTTONDOWN doc for more info)
2018 * x [I] X Mouse Coordinate
2019 * y [I] Y Mouse Coordinate
2020 *
2021 * RETURNS
2022 * 0 since we are processing the WM_LBUTTONDOWN Message
2023 *
2024 * NOTES
2025 * This function is only to be used when a ListBox is a ComboListBox
2026 */
2027
Alexandre Julliardde424282001-08-10 22:51:42 +00002028static LRESULT LISTBOX_HandleLButtonDownCombo( HWND hwnd, LB_DESCR *pDescr,
Alexandre Julliard7f90a8c2000-05-23 04:18:12 +00002029 UINT msg, WPARAM wParam, INT x, INT y)
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002030{
2031 RECT clientRect, screenRect;
2032 POINT mousePos;
2033
2034 mousePos.x = x;
2035 mousePos.y = y;
2036
Alexandre Julliardde424282001-08-10 22:51:42 +00002037 GetClientRect(hwnd, &clientRect);
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002038
2039 if(PtInRect(&clientRect, mousePos))
Alexandre Julliardde424282001-08-10 22:51:42 +00002040 {
Alexandre Julliard7f90a8c2000-05-23 04:18:12 +00002041 /* MousePos is in client, resume normal processing */
2042 if (msg == WM_LBUTTONDOWN)
Serge Ivanov07917e42000-06-07 03:46:57 +00002043 {
2044 pDescr->lphc->droppedIndex = pDescr->nb_items ? pDescr->selected_item : -1;
Alexandre Julliardde424282001-08-10 22:51:42 +00002045 return LISTBOX_HandleLButtonDown( hwnd, pDescr, wParam, x, y);
Serge Ivanov07917e42000-06-07 03:46:57 +00002046 }
Alexandre Julliard7f90a8c2000-05-23 04:18:12 +00002047 else if (pDescr->style & LBS_NOTIFY)
Alexandre Julliardde424282001-08-10 22:51:42 +00002048 SEND_NOTIFICATION( hwnd, pDescr, LBN_DBLCLK );
Alexandre Julliard7f90a8c2000-05-23 04:18:12 +00002049 return 0;
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002050 }
2051 else
2052 {
2053 POINT screenMousePos;
2054 HWND hWndOldCapture;
2055
2056 /* Check the Non-Client Area */
2057 screenMousePos = mousePos;
2058 hWndOldCapture = GetCapture();
2059 ReleaseCapture();
Alexandre Julliardde424282001-08-10 22:51:42 +00002060 GetWindowRect(hwnd, &screenRect);
2061 ClientToScreen(hwnd, &screenMousePos);
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002062
2063 if(!PtInRect(&screenRect, screenMousePos))
Alexandre Julliardde424282001-08-10 22:51:42 +00002064 {
2065 LISTBOX_SetCaretIndex( hwnd, pDescr, pDescr->lphc->droppedIndex, FALSE );
2066 LISTBOX_SetSelection( hwnd, pDescr, pDescr->lphc->droppedIndex, FALSE, FALSE );
Serge Ivanov07917e42000-06-07 03:46:57 +00002067 COMBO_FlipListbox( pDescr->lphc, FALSE, FALSE );
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002068 return 0;
2069 }
2070 else
2071 {
2072 /* Check to see the NC is a scrollbar */
2073 INT nHitTestType=0;
Alexandre Julliardde424282001-08-10 22:51:42 +00002074 LONG style = GetWindowLongA( hwnd, GWL_STYLE );
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002075 /* Check Vertical scroll bar */
Alexandre Julliardde424282001-08-10 22:51:42 +00002076 if (style & WS_VSCROLL)
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002077 {
2078 clientRect.right += GetSystemMetrics(SM_CXVSCROLL);
Alexandre Julliardde424282001-08-10 22:51:42 +00002079 if (PtInRect( &clientRect, mousePos ))
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002080 {
2081 nHitTestType = HTVSCROLL;
2082 }
2083 }
2084 /* Check horizontal scroll bar */
Alexandre Julliardde424282001-08-10 22:51:42 +00002085 if (style & WS_HSCROLL)
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002086 {
2087 clientRect.bottom += GetSystemMetrics(SM_CYHSCROLL);
2088 if (PtInRect( &clientRect, mousePos ))
2089 {
2090 nHitTestType = HTHSCROLL;
2091 }
2092 }
Vincent BĂ©ron9a624912002-05-31 23:06:46 +00002093 /* Windows sends this message when a scrollbar is clicked
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002094 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002095
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002096 if(nHitTestType != 0)
2097 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002098 SendMessageW(hwnd, WM_NCLBUTTONDOWN, nHitTestType,
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002099 MAKELONG(screenMousePos.x, screenMousePos.y));
2100 }
Vincent BĂ©ron9a624912002-05-31 23:06:46 +00002101 /* Resume the Capture after scrolling is complete
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002102 */
2103 if(hWndOldCapture != 0)
2104 {
2105 SetCapture(hWndOldCapture);
2106 }
2107 }
2108 }
2109 return 0;
2110}
2111
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002112/***********************************************************************
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002113 * LISTBOX_HandleLButtonUp
2114 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002115static LRESULT LISTBOX_HandleLButtonUp( HWND hwnd, LB_DESCR *descr )
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002116{
2117 if (LISTBOX_Timer != LB_TIMER_NONE)
Alexandre Julliardde424282001-08-10 22:51:42 +00002118 KillSystemTimer( hwnd, LB_TIMER_ID );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002119 LISTBOX_Timer = LB_TIMER_NONE;
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002120 if (descr->captured)
Alexandre Julliard33072e11997-06-29 18:08:02 +00002121 {
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002122 descr->captured = FALSE;
Alexandre Julliardde424282001-08-10 22:51:42 +00002123 if (GetCapture() == hwnd) ReleaseCapture();
Gerard Patelc9a6d501999-07-25 13:03:17 +00002124 if ((descr->style & LBS_NOTIFY) && descr->nb_items)
Alexandre Julliardde424282001-08-10 22:51:42 +00002125 SEND_NOTIFICATION( hwnd, descr, LBN_SELCHANGE );
Alexandre Julliard33072e11997-06-29 18:08:02 +00002126 }
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002127 return 0;
2128}
2129
2130
2131/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002132 * LISTBOX_HandleTimer
Alexandre Julliardade697e1995-11-26 13:59:11 +00002133 *
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002134 * Handle scrolling upon a timer event.
2135 * Return TRUE if scrolling should continue.
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002136 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002137static LRESULT LISTBOX_HandleTimer( HWND hwnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002138 INT index, TIMER_DIRECTION dir )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002139{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002140 switch(dir)
Alexandre Julliardade697e1995-11-26 13:59:11 +00002141 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002142 case LB_TIMER_UP:
2143 if (descr->top_item) index = descr->top_item - 1;
2144 else index = 0;
2145 break;
2146 case LB_TIMER_LEFT:
2147 if (descr->top_item) index -= descr->page_size;
2148 break;
2149 case LB_TIMER_DOWN:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002150 index = descr->top_item + LISTBOX_GetCurrentPageSize( descr );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00002151 if (index == descr->focus_item) index++;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002152 if (index >= descr->nb_items) index = descr->nb_items - 1;
2153 break;
2154 case LB_TIMER_RIGHT:
2155 if (index + descr->page_size < descr->nb_items)
2156 index += descr->page_size;
2157 break;
2158 case LB_TIMER_NONE:
2159 break;
Alexandre Julliardade697e1995-11-26 13:59:11 +00002160 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002161 if (index == descr->focus_item) return FALSE;
Alexandre Julliardde424282001-08-10 22:51:42 +00002162 LISTBOX_MoveCaret( hwnd, descr, index, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002163 return TRUE;
2164}
Alexandre Julliardade697e1995-11-26 13:59:11 +00002165
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002166
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002167/***********************************************************************
2168 * LISTBOX_HandleSystemTimer
2169 *
2170 * WM_SYSTIMER handler.
2171 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002172static LRESULT LISTBOX_HandleSystemTimer( HWND hwnd, LB_DESCR *descr )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002173{
Alexandre Julliardde424282001-08-10 22:51:42 +00002174 if (!LISTBOX_HandleTimer( hwnd, descr, descr->focus_item, LISTBOX_Timer ))
Alexandre Julliardade697e1995-11-26 13:59:11 +00002175 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002176 KillSystemTimer( hwnd, LB_TIMER_ID );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002177 LISTBOX_Timer = LB_TIMER_NONE;
Alexandre Julliardade697e1995-11-26 13:59:11 +00002178 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00002179 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002180}
2181
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002182
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002183/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002184 * LISTBOX_HandleMouseMove
2185 *
2186 * WM_MOUSEMOVE handler.
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002187 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002188static void LISTBOX_HandleMouseMove( HWND hwnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002189 INT x, INT y )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002190{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002191 INT index;
Serge Ivanov07917e42000-06-07 03:46:57 +00002192 TIMER_DIRECTION dir = LB_TIMER_NONE;
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00002193
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002194 if (!descr->captured) return;
2195
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002196 if (descr->style & LBS_MULTICOLUMN)
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00002197 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002198 if (y < 0) y = 0;
2199 else if (y >= descr->item_height * descr->page_size)
2200 y = descr->item_height * descr->page_size - 1;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002201
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002202 if (x < 0)
2203 {
2204 dir = LB_TIMER_LEFT;
2205 x = 0;
2206 }
2207 else if (x >= descr->width)
2208 {
2209 dir = LB_TIMER_RIGHT;
2210 x = descr->width - 1;
2211 }
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00002212 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002213 else
2214 {
2215 if (y < 0) dir = LB_TIMER_UP; /* above */
2216 else if (y >= descr->height) dir = LB_TIMER_DOWN; /* below */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002217 }
2218
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002219 index = LISTBOX_GetItemFromPoint( descr, x, y );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002220 if (index == -1) index = descr->focus_item;
Alexandre Julliardde424282001-08-10 22:51:42 +00002221 if (!LISTBOX_HandleTimer( hwnd, descr, index, dir )) dir = LB_TIMER_NONE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002222
2223 /* Start/stop the system timer */
2224
2225 if (dir != LB_TIMER_NONE)
Alexandre Julliardde424282001-08-10 22:51:42 +00002226 SetSystemTimer( hwnd, LB_TIMER_ID, LB_SCROLL_TIMEOUT, NULL);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002227 else if (LISTBOX_Timer != LB_TIMER_NONE)
Alexandre Julliardde424282001-08-10 22:51:42 +00002228 KillSystemTimer( hwnd, LB_TIMER_ID );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002229 LISTBOX_Timer = dir;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002230}
2231
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002232
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002233/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002234 * LISTBOX_HandleKeyDown
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002235 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002236static LRESULT LISTBOX_HandleKeyDown( HWND hwnd, LB_DESCR *descr, WPARAM wParam )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002237{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002238 INT caret = -1;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002239 BOOL bForceSelection = TRUE; /* select item pointed to by focus_item */
2240 if ((IS_MULTISELECT(descr)) || (descr->selected_item == descr->focus_item))
2241 bForceSelection = FALSE; /* only for single select list */
2242
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002243 if (descr->style & LBS_WANTKEYBOARDINPUT)
2244 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002245 caret = SendMessageW( descr->owner, WM_VKEYTOITEM,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002246 MAKEWPARAM(LOWORD(wParam), descr->focus_item),
Alexandre Julliardde424282001-08-10 22:51:42 +00002247 hwnd );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002248 if (caret == -2) return 0;
2249 }
2250 if (caret == -1) switch(wParam)
2251 {
2252 case VK_LEFT:
2253 if (descr->style & LBS_MULTICOLUMN)
2254 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00002255 bForceSelection = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002256 if (descr->focus_item >= descr->page_size)
2257 caret = descr->focus_item - descr->page_size;
2258 break;
2259 }
2260 /* fall through */
2261 case VK_UP:
2262 caret = descr->focus_item - 1;
2263 if (caret < 0) caret = 0;
2264 break;
2265 case VK_RIGHT:
2266 if (descr->style & LBS_MULTICOLUMN)
2267 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00002268 bForceSelection = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002269 if (descr->focus_item + descr->page_size < descr->nb_items)
2270 caret = descr->focus_item + descr->page_size;
2271 break;
2272 }
2273 /* fall through */
2274 case VK_DOWN:
2275 caret = descr->focus_item + 1;
2276 if (caret >= descr->nb_items) caret = descr->nb_items - 1;
2277 break;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002278
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002279 case VK_PRIOR:
2280 if (descr->style & LBS_MULTICOLUMN)
2281 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002282 INT page = descr->width / descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002283 if (page < 1) page = 1;
2284 caret = descr->focus_item - (page * descr->page_size) + 1;
2285 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002286 else caret = descr->focus_item-LISTBOX_GetCurrentPageSize(descr) + 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002287 if (caret < 0) caret = 0;
2288 break;
2289 case VK_NEXT:
2290 if (descr->style & LBS_MULTICOLUMN)
2291 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002292 INT page = descr->width / descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002293 if (page < 1) page = 1;
2294 caret = descr->focus_item + (page * descr->page_size) - 1;
2295 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002296 else caret = descr->focus_item + LISTBOX_GetCurrentPageSize(descr) - 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002297 if (caret >= descr->nb_items) caret = descr->nb_items - 1;
2298 break;
2299 case VK_HOME:
2300 caret = 0;
2301 break;
2302 case VK_END:
2303 caret = descr->nb_items - 1;
2304 break;
2305 case VK_SPACE:
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002306 if (descr->style & LBS_EXTENDEDSEL) caret = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002307 else if (descr->style & LBS_MULTIPLESEL)
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002308 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002309 LISTBOX_SetSelection( hwnd, descr, descr->focus_item,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002310 !descr->items[descr->focus_item].selected,
2311 (descr->style & LBS_NOTIFY) != 0 );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002312 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002313 break;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002314 default:
2315 bForceSelection = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002316 }
Gerard Patelc9a6d501999-07-25 13:03:17 +00002317 if (bForceSelection) /* focused item is used instead of key */
2318 caret = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002319 if (caret >= 0)
2320 {
2321 if ((descr->style & LBS_EXTENDEDSEL) &&
Alexandre Julliarda3960291999-02-26 11:11:13 +00002322 !(GetKeyState( VK_SHIFT ) & 0x8000))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002323 descr->anchor_item = caret;
Alexandre Julliardde424282001-08-10 22:51:42 +00002324 LISTBOX_MoveCaret( hwnd, descr, caret, TRUE );
2325 LISTBOX_SetSelection( hwnd, descr, caret, TRUE, FALSE);
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002326 if (descr->style & LBS_NOTIFY)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002327 {
Dmitry Timoshkov6df245d2001-04-09 18:30:25 +00002328 if( descr->lphc )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002329 {
2330 /* make sure that combo parent doesn't hide us */
2331 descr->lphc->wState |= CBF_NOROLLUP;
2332 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002333 if (descr->nb_items) SEND_NOTIFICATION( hwnd, descr, LBN_SELCHANGE );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002334 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002335 }
2336 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002337}
2338
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002339
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002340/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002341 * LISTBOX_HandleChar
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002342 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002343static LRESULT LISTBOX_HandleChar( HWND hwnd, LB_DESCR *descr, WCHAR charW )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002344{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002345 INT caret = -1;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002346 WCHAR str[2];
2347
2348 str[0] = charW;
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002349 str[1] = '\0';
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002350
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002351 if (descr->style & LBS_WANTKEYBOARDINPUT)
2352 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002353 caret = SendMessageW( descr->owner, WM_CHARTOITEM,
2354 MAKEWPARAM(charW, descr->focus_item),
Michael Stefaniuc2247af32002-09-04 19:37:01 +00002355 (LPARAM)hwnd );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002356 if (caret == -2) return 0;
2357 }
2358 if (caret == -1)
Alexandre Julliardde424282001-08-10 22:51:42 +00002359 caret = LISTBOX_FindString( hwnd, descr, descr->focus_item, str, FALSE);
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002360 if (caret != -1)
2361 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00002362 if ((!IS_MULTISELECT(descr)) && descr->selected_item == -1)
Alexandre Julliardde424282001-08-10 22:51:42 +00002363 LISTBOX_SetSelection( hwnd, descr, caret, TRUE, FALSE);
2364 LISTBOX_MoveCaret( hwnd, descr, caret, TRUE );
Gerard Patelc9a6d501999-07-25 13:03:17 +00002365 if ((descr->style & LBS_NOTIFY) && descr->nb_items)
Alexandre Julliardde424282001-08-10 22:51:42 +00002366 SEND_NOTIFICATION( hwnd, descr, LBN_SELCHANGE );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002367 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002368 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002369}
2370
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002371
2372/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002373 * LISTBOX_Create
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002374 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002375static BOOL LISTBOX_Create( HWND hwnd, LPHEADCOMBO lphc )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002376{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002377 LB_DESCR *descr;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002378 MEASUREITEMSTRUCT mis;
2379 RECT rect;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002380
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002381 if (!(descr = HeapAlloc( GetProcessHeap(), 0, sizeof(*descr) )))
2382 return FALSE;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002383
Alexandre Julliardde424282001-08-10 22:51:42 +00002384 GetClientRect( hwnd, &rect );
2385 descr->owner = GetParent( hwnd );
2386 descr->style = GetWindowLongA( hwnd, GWL_STYLE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002387 descr->width = rect.right - rect.left;
2388 descr->height = rect.bottom - rect.top;
2389 descr->items = NULL;
2390 descr->nb_items = 0;
2391 descr->top_item = 0;
2392 descr->selected_item = -1;
2393 descr->focus_item = 0;
2394 descr->anchor_item = -1;
2395 descr->item_height = 1;
2396 descr->page_size = 1;
2397 descr->column_width = 150;
Alexandre Julliardde424282001-08-10 22:51:42 +00002398 descr->horz_extent = (descr->style & WS_HSCROLL) ? 1 : 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002399 descr->horz_pos = 0;
2400 descr->nb_tabs = 0;
2401 descr->tabs = NULL;
Serge Ivanov07917e42000-06-07 03:46:57 +00002402 descr->caret_on = lphc ? FALSE : TRUE;
Andreas Mohr85ba8792001-01-06 00:34:14 +00002403 if (descr->style & LBS_NOSEL) descr->caret_on = FALSE;
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002404 descr->in_focus = FALSE;
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002405 descr->captured = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002406 descr->font = 0;
2407 descr->locale = 0; /* FIXME */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002408 descr->lphc = lphc;
2409
Alexandre Julliardde424282001-08-10 22:51:42 +00002410 if (is_old_app(hwnd) && ( descr->style & ( WS_VSCROLL | WS_HSCROLL ) ) )
Nick Hollowayb9ce4fd1999-09-11 16:29:00 +00002411 {
2412 /* Win95 document "List Box Differences" from MSDN:
2413 If a list box in a version 3.x application has either the
2414 WS_HSCROLL or WS_VSCROLL style, the list box receives both
2415 horizontal and vertical scroll bars.
2416 */
2417 descr->style |= WS_VSCROLL | WS_HSCROLL;
2418 }
2419
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002420 if( lphc )
2421 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +00002422 TRACE_(combo)("[%04x]: resetting owner %04x -> %04x\n",
Alexandre Julliardde424282001-08-10 22:51:42 +00002423 hwnd, descr->owner, lphc->self );
2424 descr->owner = lphc->self;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002425 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00002426
Alexandre Julliardde424282001-08-10 22:51:42 +00002427 SetWindowLongA( hwnd, 0, (LONG)descr );
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002428
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002429/* if (wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) descr->style &= ~LBS_NOTIFY;
2430 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002431 if (descr->style & LBS_EXTENDEDSEL) descr->style |= LBS_MULTIPLESEL;
2432 if (descr->style & LBS_MULTICOLUMN) descr->style &= ~LBS_OWNERDRAWVARIABLE;
2433 if (descr->style & LBS_OWNERDRAWVARIABLE) descr->style |= LBS_NOINTEGRALHEIGHT;
Alexandre Julliardde424282001-08-10 22:51:42 +00002434 descr->item_height = LISTBOX_SetFont( hwnd, descr, 0 );
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002435
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002436 if (descr->style & LBS_OWNERDRAWFIXED)
2437 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002438 if( descr->lphc && (descr->lphc->dwStyle & CBS_DROPDOWN))
2439 {
2440 /* WinWord gets VERY unhappy if we send WM_MEASUREITEM from here */
Francis Beaudetf585c611999-04-02 10:37:42 +00002441 descr->item_height = lphc->fixedOwnerDrawHeight;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002442 }
2443 else
2444 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002445 UINT id = GetWindowLongA( hwnd, GWL_ID );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002446 mis.CtlType = ODT_LISTBOX;
Alexandre Julliardde424282001-08-10 22:51:42 +00002447 mis.CtlID = id;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002448 mis.itemID = -1;
2449 mis.itemWidth = 0;
2450 mis.itemData = 0;
2451 mis.itemHeight = descr->item_height;
Alexandre Julliardde424282001-08-10 22:51:42 +00002452 SendMessageW( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002453 descr->item_height = mis.itemHeight ? mis.itemHeight : 1;
2454 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002455 }
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002456
Andreas Mohr85ba8792001-01-06 00:34:14 +00002457 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 +00002458 return TRUE;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002459}
2460
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002461
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002462/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002463 * LISTBOX_Destroy
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002464 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002465static BOOL LISTBOX_Destroy( HWND hwnd, LB_DESCR *descr )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002466{
Alexandre Julliardde424282001-08-10 22:51:42 +00002467 LISTBOX_ResetContent( hwnd, descr );
2468 SetWindowLongA( hwnd, 0, 0 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002469 HeapFree( GetProcessHeap(), 0, descr );
Alexandre Julliard7e56f681996-01-31 19:02:28 +00002470 return TRUE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002471}
2472
2473
2474/***********************************************************************
Alexandre Julliardde424282001-08-10 22:51:42 +00002475 * ListBoxWndProc_common
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002476 */
Alexandre Julliardde424282001-08-10 22:51:42 +00002477static LRESULT WINAPI ListBoxWndProc_common( HWND hwnd, UINT msg,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002478 WPARAM wParam, LPARAM lParam, BOOL unicode )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002479{
2480 LRESULT ret;
2481 LB_DESCR *descr;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002482
Alexandre Julliardde424282001-08-10 22:51:42 +00002483 if (!(descr = (LB_DESCR *)GetWindowLongA( hwnd, 0 )))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002484 {
Bill Medlande79f0762001-07-17 00:55:23 +00002485 if (msg == WM_CREATE)
2486 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002487 if (!LISTBOX_Create( hwnd, NULL ))
Bill Medlande79f0762001-07-17 00:55:23 +00002488 return -1;
Alexandre Julliardde424282001-08-10 22:51:42 +00002489 TRACE("creating wnd=%04x descr=%lx\n", hwnd, GetWindowLongA( hwnd, 0 ) );
Bill Medlande79f0762001-07-17 00:55:23 +00002490 return 0;
2491 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002492 /* Ignore all other messages before we get a WM_CREATE */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002493 return unicode ? DefWindowProcW( hwnd, msg, wParam, lParam ) :
2494 DefWindowProcA( hwnd, msg, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002495 }
2496
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002497 TRACE("[%04x]: msg %s wp %08x lp %08lx\n",
Guy L. Albertellidb9b5492001-09-07 18:38:57 +00002498 hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002499 switch(msg)
2500 {
2501 case LB_RESETCONTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002502 case LB_RESETCONTENT:
Alexandre Julliardde424282001-08-10 22:51:42 +00002503 LISTBOX_ResetContent( hwnd, descr );
2504 LISTBOX_UpdateScroll( hwnd, descr );
2505 InvalidateRect( hwnd, NULL, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002506 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002507
2508 case LB_ADDSTRING16:
Alexandre Julliard982a2232000-12-13 20:20:09 +00002509 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002510 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002511 case LB_ADDSTRING:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002512 {
2513 INT ret;
2514 LPWSTR textW;
2515 if(unicode || !HAS_STRINGS(descr))
2516 textW = (LPWSTR)lParam;
2517 else
2518 {
2519 LPSTR textA = (LPSTR)lParam;
2520 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2521 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2522 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2523 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002524 wParam = LISTBOX_FindStringPos( hwnd, descr, textW, FALSE );
2525 ret = LISTBOX_InsertString( hwnd, descr, wParam, textW );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002526 if (!unicode && HAS_STRINGS(descr))
2527 HeapFree(GetProcessHeap(), 0, textW);
2528 return ret;
2529 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002530
2531 case LB_INSERTSTRING16:
Alexandre Julliard982a2232000-12-13 20:20:09 +00002532 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002533 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002534 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002535 case LB_INSERTSTRING:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002536 {
2537 INT ret;
2538 LPWSTR textW;
2539 if(unicode || !HAS_STRINGS(descr))
2540 textW = (LPWSTR)lParam;
2541 else
2542 {
2543 LPSTR textA = (LPSTR)lParam;
2544 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2545 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2546 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2547 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002548 ret = LISTBOX_InsertString( hwnd, descr, wParam, textW );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002549 if(!unicode && HAS_STRINGS(descr))
2550 HeapFree(GetProcessHeap(), 0, textW);
2551 return ret;
2552 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002553
2554 case LB_ADDFILE16:
Alexandre Julliard982a2232000-12-13 20:20:09 +00002555 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002556 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002557 case LB_ADDFILE:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002558 {
2559 INT ret;
2560 LPWSTR textW;
2561 if(unicode || !HAS_STRINGS(descr))
2562 textW = (LPWSTR)lParam;
2563 else
2564 {
2565 LPSTR textA = (LPSTR)lParam;
2566 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2567 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2568 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2569 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002570 wParam = LISTBOX_FindFileStrPos( hwnd, descr, textW );
2571 ret = LISTBOX_InsertString( hwnd, descr, wParam, textW );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002572 if(!unicode && HAS_STRINGS(descr))
2573 HeapFree(GetProcessHeap(), 0, textW);
2574 return ret;
2575 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002576
2577 case LB_DELETESTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002578 case LB_DELETESTRING:
Alexandre Julliardde424282001-08-10 22:51:42 +00002579 if (LISTBOX_RemoveItem( hwnd, descr, wParam) != LB_ERR)
Gerard Patelc9a6d501999-07-25 13:03:17 +00002580 return descr->nb_items;
2581 else
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002582 return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002583
2584 case LB_GETITEMDATA16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002585 case LB_GETITEMDATA:
2586 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002587 return LB_ERR;
2588 return descr->items[wParam].data;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002589
2590 case LB_SETITEMDATA16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002591 case LB_SETITEMDATA:
2592 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002593 return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002594 descr->items[wParam].data = (DWORD)lParam;
Marcus Meissner9aded511999-05-01 10:23:45 +00002595 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002596
2597 case LB_GETCOUNT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002598 case LB_GETCOUNT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002599 return descr->nb_items;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002600
2601 case LB_GETTEXT16:
Alexandre Julliard982a2232000-12-13 20:20:09 +00002602 lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002603 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002604 case LB_GETTEXT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002605 return LISTBOX_GetText( descr, wParam, lParam, unicode );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002606
2607 case LB_GETTEXTLEN16:
2608 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002609 case LB_GETTEXTLEN:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002610 if ((INT)wParam >= descr->nb_items || (INT)wParam < 0)
Marcus Meissner9aded511999-05-01 10:23:45 +00002611 return LB_ERR;
Alexandre Julliard741325b2002-06-13 19:20:43 +00002612 if (!HAS_STRINGS(descr)) return sizeof(DWORD);
2613 if (unicode) return strlenW( descr->items[wParam].str );
2614 return WideCharToMultiByte( CP_ACP, 0, descr->items[wParam].str,
2615 strlenW(descr->items[wParam].str), NULL, 0, NULL, NULL );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002616
2617 case LB_GETCURSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002618 case LB_GETCURSEL:
Francis Beaudet8730e451999-03-25 13:22:02 +00002619 if (descr->nb_items==0)
Marcus Meissner9aded511999-05-01 10:23:45 +00002620 return LB_ERR;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002621 if (!IS_MULTISELECT(descr))
2622 return descr->selected_item;
Marcus Meissner9aded511999-05-01 10:23:45 +00002623 /* else */
2624 if (descr->selected_item!=-1)
2625 return descr->selected_item;
2626 /* else */
2627 return descr->focus_item;
Lawson Whitney613092a1999-03-22 14:46:43 +00002628 /* otherwise, if the user tries to move the selection with the */
2629 /* arrow keys, we will give the application something to choke on */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002630 case LB_GETTOPINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002631 case LB_GETTOPINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002632 return descr->top_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002633
2634 case LB_GETITEMHEIGHT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002635 case LB_GETITEMHEIGHT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002636 return LISTBOX_GetItemHeight( descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002637
2638 case LB_SETITEMHEIGHT16:
2639 lParam = LOWORD(lParam);
2640 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002641 case LB_SETITEMHEIGHT:
Alexandre Julliardc72a9aa2002-01-31 21:05:05 +00002642 return LISTBOX_SetItemHeight( hwnd, descr, wParam, lParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002643
Alexandre Julliarda3960291999-02-26 11:11:13 +00002644 case LB_ITEMFROMPOINT:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002645 {
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002646 POINT pt;
2647 RECT rect;
2648
2649 pt.x = LOWORD(lParam);
2650 pt.y = HIWORD(lParam);
2651 rect.left = 0;
2652 rect.top = 0;
2653 rect.right = descr->width;
2654 rect.bottom = descr->height;
2655
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002656 return MAKELONG( LISTBOX_GetItemFromPoint(descr, pt.x, pt.y),
Gerard Patel777508a1999-05-08 12:35:17 +00002657 !PtInRect( &rect, pt ) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002658 }
2659
2660 case LB_SETCARETINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002661 case LB_SETCARETINDEX:
Gerard Patelc9a6d501999-07-25 13:03:17 +00002662 if ((!IS_MULTISELECT(descr)) && (descr->selected_item != -1)) return LB_ERR;
Alexandre Julliardde424282001-08-10 22:51:42 +00002663 if (LISTBOX_SetCaretIndex( hwnd, descr, wParam, !lParam ) == LB_ERR)
Gerard Patelc9a6d501999-07-25 13:03:17 +00002664 return LB_ERR;
2665 else if (ISWIN31)
2666 return wParam;
2667 else
2668 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002669
2670 case LB_GETCARETINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002671 case LB_GETCARETINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002672 return descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002673
2674 case LB_SETTOPINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002675 case LB_SETTOPINDEX:
Alexandre Julliardde424282001-08-10 22:51:42 +00002676 return LISTBOX_SetTopItem( hwnd, descr, wParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002677
2678 case LB_SETCOLUMNWIDTH16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002679 case LB_SETCOLUMNWIDTH:
Alexandre Julliardde424282001-08-10 22:51:42 +00002680 return LISTBOX_SetColumnWidth( hwnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002681
2682 case LB_GETITEMRECT16:
2683 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002684 RECT rect;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002685 ret = LISTBOX_GetItemRect( descr, (INT16)wParam, &rect );
Alexandre Julliard982a2232000-12-13 20:20:09 +00002686 CONV_RECT32TO16( &rect, MapSL(lParam) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002687 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002688 return ret;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002689
Alexandre Julliarda3960291999-02-26 11:11:13 +00002690 case LB_GETITEMRECT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002691 return LISTBOX_GetItemRect( descr, wParam, (RECT *)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002692
2693 case LB_FINDSTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002694 wParam = (INT)(INT16)wParam;
Alexandre Julliard982a2232000-12-13 20:20:09 +00002695 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002696 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002697 case LB_FINDSTRING:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002698 {
2699 INT ret;
2700 LPWSTR textW;
2701 if(unicode || !HAS_STRINGS(descr))
2702 textW = (LPWSTR)lParam;
2703 else
2704 {
2705 LPSTR textA = (LPSTR)lParam;
2706 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2707 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2708 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2709 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002710 ret = LISTBOX_FindString( hwnd, descr, wParam, textW, FALSE );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002711 if(!unicode && HAS_STRINGS(descr))
2712 HeapFree(GetProcessHeap(), 0, textW);
2713 return ret;
2714 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002715
2716 case LB_FINDSTRINGEXACT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002717 wParam = (INT)(INT16)wParam;
Alexandre Julliard982a2232000-12-13 20:20:09 +00002718 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002719 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002720 case LB_FINDSTRINGEXACT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002721 {
2722 INT ret;
2723 LPWSTR textW;
2724 if(unicode || !HAS_STRINGS(descr))
2725 textW = (LPWSTR)lParam;
2726 else
2727 {
2728 LPSTR textA = (LPSTR)lParam;
2729 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2730 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2731 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2732 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002733 ret = LISTBOX_FindString( hwnd, descr, wParam, textW, TRUE );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002734 if(!unicode && HAS_STRINGS(descr))
2735 HeapFree(GetProcessHeap(), 0, textW);
2736 return ret;
2737 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002738
2739 case LB_SELECTSTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002740 wParam = (INT)(INT16)wParam;
Alexandre Julliard982a2232000-12-13 20:20:09 +00002741 if (HAS_STRINGS(descr)) lParam = (LPARAM)MapSL(lParam);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002742 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002743 case LB_SELECTSTRING:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002744 {
2745 INT index;
2746 LPWSTR textW;
Dmitry Timoshkove8ffcaa2001-04-16 19:32:19 +00002747
2748 if(HAS_STRINGS(descr))
2749 TRACE("LB_SELECTSTRING: %s\n", unicode ? debugstr_w((LPWSTR)lParam) :
2750 debugstr_a((LPSTR)lParam));
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002751 if(unicode || !HAS_STRINGS(descr))
2752 textW = (LPWSTR)lParam;
2753 else
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002754 {
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002755 LPSTR textA = (LPSTR)lParam;
2756 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2757 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2758 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002759 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002760 index = LISTBOX_FindString( hwnd, descr, wParam, textW, FALSE );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002761 if(!unicode && HAS_STRINGS(descr))
2762 HeapFree(GetProcessHeap(), 0, textW);
2763 if (index != LB_ERR)
Dmitry Timoshkove8ffcaa2001-04-16 19:32:19 +00002764 {
Alexandre Julliardde424282001-08-10 22:51:42 +00002765 LISTBOX_SetCaretIndex( hwnd, descr, index, TRUE );
2766 LISTBOX_SetSelection( hwnd, descr, index, TRUE, FALSE );
Dmitry Timoshkove8ffcaa2001-04-16 19:32:19 +00002767 }
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002768 return index;
2769 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002770
2771 case LB_GETSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002772 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002773 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002774 case LB_GETSEL:
2775 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002776 return LB_ERR;
2777 return descr->items[wParam].selected;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002778
2779 case LB_SETSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002780 lParam = (INT)(INT16)lParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002781 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002782 case LB_SETSEL:
Alexandre Julliardde424282001-08-10 22:51:42 +00002783 return LISTBOX_SetSelection( hwnd, descr, lParam, wParam, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002784
2785 case LB_SETCURSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002786 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002787 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002788 case LB_SETCURSEL:
Gerard Patelc9a6d501999-07-25 13:03:17 +00002789 if (IS_MULTISELECT(descr)) return LB_ERR;
Alexandre Julliardde424282001-08-10 22:51:42 +00002790 LISTBOX_SetCaretIndex( hwnd, descr, wParam, TRUE );
2791 return LISTBOX_SetSelection( hwnd, descr, wParam, TRUE, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002792
2793 case LB_GETSELCOUNT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002794 case LB_GETSELCOUNT:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002795 return LISTBOX_GetSelCount( descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002796
2797 case LB_GETSELITEMS16:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002798 return LISTBOX_GetSelItems16( descr, wParam, (LPINT16)MapSL(lParam) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002799
Alexandre Julliarda3960291999-02-26 11:11:13 +00002800 case LB_GETSELITEMS:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002801 return LISTBOX_GetSelItems( descr, wParam, (LPINT)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002802
2803 case LB_SELITEMRANGE16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002804 case LB_SELITEMRANGE:
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002805 if (LOWORD(lParam) <= HIWORD(lParam))
Alexandre Julliardde424282001-08-10 22:51:42 +00002806 return LISTBOX_SelectItemRange( hwnd, descr, LOWORD(lParam),
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002807 HIWORD(lParam), wParam );
2808 else
Alexandre Julliardde424282001-08-10 22:51:42 +00002809 return LISTBOX_SelectItemRange( hwnd, descr, HIWORD(lParam),
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002810 LOWORD(lParam), wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002811
2812 case LB_SELITEMRANGEEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002813 case LB_SELITEMRANGEEX:
2814 if ((INT)lParam >= (INT)wParam)
Alexandre Julliardde424282001-08-10 22:51:42 +00002815 return LISTBOX_SelectItemRange( hwnd, descr, wParam, lParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002816 else
Alexandre Julliardde424282001-08-10 22:51:42 +00002817 return LISTBOX_SelectItemRange( hwnd, descr, lParam, wParam, FALSE);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002818
2819 case LB_GETHORIZONTALEXTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002820 case LB_GETHORIZONTALEXTENT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002821 return descr->horz_extent;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002822
2823 case LB_SETHORIZONTALEXTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002824 case LB_SETHORIZONTALEXTENT:
Alexandre Julliardde424282001-08-10 22:51:42 +00002825 return LISTBOX_SetHorizontalExtent( hwnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002826
2827 case LB_GETANCHORINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002828 case LB_GETANCHORINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002829 return descr->anchor_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002830
2831 case LB_SETANCHORINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002832 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002833 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002834 case LB_SETANCHORINDEX:
2835 if (((INT)wParam < -1) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002836 return LB_ERR;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002837 descr->anchor_item = (INT)wParam;
Marcus Meissner9aded511999-05-01 10:23:45 +00002838 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002839
2840 case LB_DIR16:
Ove Kaaven2c691b32000-11-25 03:06:03 +00002841 /* according to Win16 docs, DDL_DRIVES should make DDL_EXCLUSIVE
2842 * be set automatically (this is different in Win32) */
2843 if (wParam & DDL_DRIVES) wParam |= DDL_EXCLUSIVE;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002844 lParam = (LPARAM)MapSL(lParam);
2845 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002846 case LB_DIR:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002847 {
2848 INT ret;
2849 LPWSTR textW;
2850 if(unicode)
2851 textW = (LPWSTR)lParam;
2852 else
2853 {
2854 LPSTR textA = (LPSTR)lParam;
2855 INT countW = MultiByteToWideChar(CP_ACP, 0, textA, -1, NULL, 0);
2856 if((textW = HeapAlloc(GetProcessHeap(), 0, countW * sizeof(WCHAR))))
2857 MultiByteToWideChar(CP_ACP, 0, textA, -1, textW, countW);
2858 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002859 ret = LISTBOX_Directory( hwnd, descr, wParam, textW, msg == LB_DIR );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002860 if(!unicode)
2861 HeapFree(GetProcessHeap(), 0, textW);
2862 return ret;
2863 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002864
Alexandre Julliarda3960291999-02-26 11:11:13 +00002865 case LB_GETLOCALE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002866 return descr->locale;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002867
Alexandre Julliarda3960291999-02-26 11:11:13 +00002868 case LB_SETLOCALE:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002869 descr->locale = (LCID)wParam; /* FIXME: should check for valid lcid */
Marcus Meissner9aded511999-05-01 10:23:45 +00002870 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002871
Alexandre Julliarda3960291999-02-26 11:11:13 +00002872 case LB_INITSTORAGE:
Alexandre Julliardde424282001-08-10 22:51:42 +00002873 return LISTBOX_InitStorage( hwnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002874
Alexandre Julliarda3960291999-02-26 11:11:13 +00002875 case LB_SETCOUNT:
Alexandre Julliardde424282001-08-10 22:51:42 +00002876 return LISTBOX_SetCount( hwnd, descr, (INT)wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002877
2878 case LB_SETTABSTOPS16:
Alexandre Julliardde424282001-08-10 22:51:42 +00002879 return LISTBOX_SetTabStops( hwnd, descr, (INT)(INT16)wParam, MapSL(lParam), TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002880
Alexandre Julliarda3960291999-02-26 11:11:13 +00002881 case LB_SETTABSTOPS:
Alexandre Julliardde424282001-08-10 22:51:42 +00002882 return LISTBOX_SetTabStops( hwnd, descr, wParam, (LPINT)lParam, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002883
2884 case LB_CARETON16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002885 case LB_CARETON:
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002886 if (descr->caret_on)
Marcus Meissner9aded511999-05-01 10:23:45 +00002887 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002888 descr->caret_on = TRUE;
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002889 if ((descr->focus_item != -1) && (descr->in_focus))
Alexandre Julliardde424282001-08-10 22:51:42 +00002890 LISTBOX_RepaintItem( hwnd, descr, descr->focus_item, ODA_FOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002891 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002892
2893 case LB_CARETOFF16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002894 case LB_CARETOFF:
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002895 if (!descr->caret_on)
Marcus Meissner9aded511999-05-01 10:23:45 +00002896 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002897 descr->caret_on = FALSE;
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002898 if ((descr->focus_item != -1) && (descr->in_focus))
Alexandre Julliardde424282001-08-10 22:51:42 +00002899 LISTBOX_RepaintItem( hwnd, descr, descr->focus_item, ODA_FOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002900 return LB_OKAY;
Alexandre Julliardde424282001-08-10 22:51:42 +00002901
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002902 case WM_DESTROY:
Alexandre Julliardde424282001-08-10 22:51:42 +00002903 return LISTBOX_Destroy( hwnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002904
2905 case WM_ENABLE:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002906 InvalidateRect( hwnd, NULL, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002907 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002908
2909 case WM_SETREDRAW:
Alexandre Julliardde424282001-08-10 22:51:42 +00002910 LISTBOX_SetRedraw( hwnd, descr, wParam != 0 );
Marcus Meissner9aded511999-05-01 10:23:45 +00002911 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002912
2913 case WM_GETDLGCODE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002914 return DLGC_WANTARROWS | DLGC_WANTCHARS;
2915
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002916 case WM_PAINT:
2917 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002918 PAINTSTRUCT ps;
Alexandre Julliardde424282001-08-10 22:51:42 +00002919 HDC hdc = ( wParam ) ? ((HDC)wParam) : BeginPaint( hwnd, &ps );
2920 ret = LISTBOX_Paint( hwnd, descr, hdc );
Alexandre Julliarda3960291999-02-26 11:11:13 +00002921 if( !wParam ) EndPaint( hwnd, &ps );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002922 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002923 return ret;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002924 case WM_SIZE:
Alexandre Julliardde424282001-08-10 22:51:42 +00002925 LISTBOX_UpdateSize( hwnd, descr );
Marcus Meissner9aded511999-05-01 10:23:45 +00002926 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002927 case WM_GETFONT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002928 return descr->font;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002929 case WM_SETFONT:
Alexandre Julliardde424282001-08-10 22:51:42 +00002930 LISTBOX_SetFont( hwnd, descr, (HFONT)wParam );
2931 if (lParam) InvalidateRect( hwnd, 0, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002932 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002933 case WM_SETFOCUS:
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002934 descr->in_focus = TRUE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002935 descr->caret_on = TRUE;
2936 if (descr->focus_item != -1)
Alexandre Julliardde424282001-08-10 22:51:42 +00002937 LISTBOX_RepaintItem( hwnd, descr, descr->focus_item, ODA_FOCUS );
2938 SEND_NOTIFICATION( hwnd, descr, LBN_SETFOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002939 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002940 case WM_KILLFOCUS:
Alexandre Julliardab2f43f2000-05-26 22:28:34 +00002941 descr->in_focus = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002942 if ((descr->focus_item != -1) && descr->caret_on)
Alexandre Julliardde424282001-08-10 22:51:42 +00002943 LISTBOX_RepaintItem( hwnd, descr, descr->focus_item, ODA_FOCUS );
2944 SEND_NOTIFICATION( hwnd, descr, LBN_KILLFOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002945 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002946 case WM_HSCROLL:
Alexandre Julliardde424282001-08-10 22:51:42 +00002947 return LISTBOX_HandleHScroll( hwnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002948 case WM_VSCROLL:
Alexandre Julliardde424282001-08-10 22:51:42 +00002949 return LISTBOX_HandleVScroll( hwnd, descr, wParam );
Stephane Lussier4bdf4af2000-04-18 11:56:33 +00002950 case WM_MOUSEWHEEL:
2951 if (wParam & (MK_SHIFT | MK_CONTROL))
Alexandre Julliardde424282001-08-10 22:51:42 +00002952 return DefWindowProcW( hwnd, msg, wParam, lParam );
2953 return LISTBOX_HandleMouseWheel( hwnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002954 case WM_LBUTTONDOWN:
Alexandre Julliardde424282001-08-10 22:51:42 +00002955 return LISTBOX_HandleLButtonDown( hwnd, descr, wParam,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002956 (INT16)LOWORD(lParam),
2957 (INT16)HIWORD(lParam) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002958 case WM_LBUTTONDBLCLK:
2959 if (descr->style & LBS_NOTIFY)
Alexandre Julliardde424282001-08-10 22:51:42 +00002960 SEND_NOTIFICATION( hwnd, descr, LBN_DBLCLK );
Marcus Meissner9aded511999-05-01 10:23:45 +00002961 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002962 case WM_MOUSEMOVE:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002963 if (GetCapture() == hwnd)
Alexandre Julliardde424282001-08-10 22:51:42 +00002964 LISTBOX_HandleMouseMove( hwnd, descr, (INT16)LOWORD(lParam),
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002965 (INT16)HIWORD(lParam) );
Marcus Meissner9aded511999-05-01 10:23:45 +00002966 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002967 case WM_LBUTTONUP:
Alexandre Julliardde424282001-08-10 22:51:42 +00002968 return LISTBOX_HandleLButtonUp( hwnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002969 case WM_KEYDOWN:
Alexandre Julliardde424282001-08-10 22:51:42 +00002970 return LISTBOX_HandleKeyDown( hwnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002971 case WM_CHAR:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002972 {
2973 WCHAR charW;
2974 if(unicode)
2975 charW = (WCHAR)wParam;
2976 else
2977 {
2978 CHAR charA = (CHAR)wParam;
2979 MultiByteToWideChar(CP_ACP, 0, &charA, 1, &charW, 1);
2980 }
Alexandre Julliardde424282001-08-10 22:51:42 +00002981 return LISTBOX_HandleChar( hwnd, descr, charW );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002982 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002983 case WM_SYSTIMER:
Alexandre Julliardde424282001-08-10 22:51:42 +00002984 return LISTBOX_HandleSystemTimer( hwnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002985 case WM_ERASEBKGND:
Gerard Patel41b07fb2000-06-15 00:07:20 +00002986 if ((IS_OWNERDRAW(descr)) && !(descr->style & LBS_DISPLAYCHANGED))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002987 {
Luc Tourangeau89147991999-04-18 09:23:56 +00002988 RECT rect;
Dmitry Timoshkov74620992001-01-09 21:51:04 +00002989 HBRUSH hbrush = SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
Alexandre Julliardde424282001-08-10 22:51:42 +00002990 wParam, (LPARAM)hwnd );
Dmitry Timoshkov52ece0e2001-02-26 22:31:55 +00002991 TRACE("hbrush = %04x\n", hbrush);
2992 if(!hbrush)
2993 hbrush = GetSysColorBrush(COLOR_WINDOW);
2994 if(hbrush)
2995 {
2996 GetClientRect(hwnd, &rect);
2997 FillRect((HDC)wParam, &rect, hbrush);
2998 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002999 }
Marcus Meissner9aded511999-05-01 10:23:45 +00003000 return 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003001 case WM_DROPFILES:
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003002 if( !descr->lphc )
3003 return unicode ? SendMessageW( descr->owner, msg, wParam, lParam ) :
3004 SendMessageA( descr->owner, msg, wParam, lParam );
3005 break;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003006
3007 case WM_DROPOBJECT:
3008 case WM_QUERYDROPOBJECT:
3009 case WM_DRAGSELECT:
3010 case WM_DRAGMOVE:
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003011 if( !descr->lphc )
3012 {
Alexandre Julliard982a2232000-12-13 20:20:09 +00003013 LPDRAGINFO16 dragInfo = MapSL( lParam );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003014 dragInfo->l = LISTBOX_GetItemFromPoint( descr, dragInfo->pt.x,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003015 dragInfo->pt.y );
Michael Stefaniuc2247af32002-09-04 19:37:01 +00003016 return SendMessage16( HWND_16(descr->owner), msg, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003017 }
3018 break;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003019
3020 default:
3021 if ((msg >= WM_USER) && (msg < 0xc000))
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00003022 WARN("[%04x]: unknown msg %04x wp %08x lp %08lx\n",
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003023 hwnd, msg, wParam, lParam );
3024 return unicode ? DefWindowProcW( hwnd, msg, wParam, lParam ) :
3025 DefWindowProcA( hwnd, msg, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003026 }
Marcus Meissner9aded511999-05-01 10:23:45 +00003027 return 0;
3028}
3029
3030/***********************************************************************
Alexandre Julliard91222da2000-12-10 23:01:33 +00003031 * ListBoxWndProcA
Marcus Meissner9aded511999-05-01 10:23:45 +00003032 *
3033 * This is just a wrapper for the real wndproc, it only does window locking
3034 * and unlocking.
3035 */
Alexandre Julliard91222da2000-12-10 23:01:33 +00003036static LRESULT WINAPI ListBoxWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
Marcus Meissner9aded511999-05-01 10:23:45 +00003037{
Alexandre Julliardde424282001-08-10 22:51:42 +00003038 if (!IsWindow(hwnd)) return 0;
3039 return ListBoxWndProc_common( hwnd, msg, wParam, lParam, FALSE );
Alexandre Julliard58199531994-04-21 01:20:00 +00003040}
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003041
3042/***********************************************************************
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003043 * ListBoxWndProcW
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003044 */
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003045static LRESULT WINAPI ListBoxWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003046{
Alexandre Julliardde424282001-08-10 22:51:42 +00003047 if (!IsWindow(hwnd)) return 0;
3048 return ListBoxWndProc_common( hwnd, msg, wParam, lParam, TRUE );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003049}
3050
3051/***********************************************************************
Alexandre Julliardde424282001-08-10 22:51:42 +00003052 * ComboLBWndProc_common
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003053 *
Alexandre Julliardde424282001-08-10 22:51:42 +00003054 * The real combo listbox wndproc
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003055 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003056static LRESULT WINAPI ComboLBWndProc_common( HWND hwnd, UINT msg,
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003057 WPARAM wParam, LPARAM lParam, BOOL unicode )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003058{
3059 LRESULT lRet = 0;
Alexandre Julliardebed1b82002-07-05 00:30:05 +00003060 LB_DESCR *descr;
3061 LPHEADCOMBO lphc;
3062
3063 if (!(descr = (LB_DESCR *)GetWindowLongA( hwnd, 0 )))
3064 {
3065 if (msg == WM_CREATE)
3066 {
3067 CREATESTRUCTA *lpcs = (CREATESTRUCTA *)lParam;
3068 TRACE_(combo)("\tpassed parent handle = %p\n",lpcs->lpCreateParams);
3069 lphc = (LPHEADCOMBO)(lpcs->lpCreateParams);
3070 return LISTBOX_Create( hwnd, lphc );
3071 }
3072 /* Ignore all other messages before we get a WM_CREATE */
3073 return unicode ? DefWindowProcW( hwnd, msg, wParam, lParam ) :
3074 DefWindowProcA( hwnd, msg, wParam, lParam );
3075 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003076
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003077 TRACE_(combo)("[%04x]: msg %s wp %08x lp %08lx\n",
Guy L. Albertellidb9b5492001-09-07 18:38:57 +00003078 hwnd, SPY_GetMsgName(msg, hwnd), wParam, lParam );
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003079
Alexandre Julliardebed1b82002-07-05 00:30:05 +00003080 if ((lphc = descr->lphc) != NULL)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003081 {
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003082 switch( msg )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003083 {
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003084 case WM_MOUSEMOVE:
3085 if ( (TWEAK_WineLook > WIN31_LOOK) &&
3086 (CB_GETTYPE(lphc) != CBS_SIMPLE) )
3087 {
3088 POINT mousePos;
3089 BOOL captured;
3090 RECT clientRect;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003091
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003092 mousePos.x = (INT16)LOWORD(lParam);
3093 mousePos.y = (INT16)HIWORD(lParam);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003094
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003095 /*
3096 * If we are in a dropdown combobox, we simulate that
3097 * the mouse is captured to show the tracking of the item.
3098 */
3099 GetClientRect(hwnd, &clientRect);
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003100
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003101 if (PtInRect( &clientRect, mousePos ))
3102 {
3103 captured = descr->captured;
3104 descr->captured = TRUE;
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003105
Alexandre Julliardde424282001-08-10 22:51:42 +00003106 LISTBOX_HandleMouseMove( hwnd, descr,
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003107 mousePos.x, mousePos.y);
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003108
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003109 descr->captured = captured;
Pierre Mageau25c62cc1999-09-11 16:26:03 +00003110
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003111 }
3112 else
3113 {
Alexandre Julliardde424282001-08-10 22:51:42 +00003114 LISTBOX_HandleMouseMove( hwnd, descr,
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003115 mousePos.x, mousePos.y);
3116 }
Pierre Mageau25c62cc1999-09-11 16:26:03 +00003117
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003118 return 0;
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003119
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003120 }
Alexandre Julliardebed1b82002-07-05 00:30:05 +00003121 /* else we are in Win3.1 look, go with the default behavior. */
3122 break;
3123
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003124 case WM_LBUTTONUP:
3125 if (TWEAK_WineLook > WIN31_LOOK)
3126 {
3127 POINT mousePos;
3128 RECT clientRect;
Pierre Mageau25c62cc1999-09-11 16:26:03 +00003129
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003130 /*
3131 * If the mouse button "up" is not in the listbox,
3132 * we make sure there is no selection by re-selecting the
3133 * item that was selected when the listbox was made visible.
3134 */
3135 mousePos.x = (INT16)LOWORD(lParam);
3136 mousePos.y = (INT16)HIWORD(lParam);
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003137
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003138 GetClientRect(hwnd, &clientRect);
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003139
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003140 /*
3141 * When the user clicks outside the combobox and the focus
3142 * is lost, the owning combobox will send a fake buttonup with
3143 * 0xFFFFFFF as the mouse location, we must also revert the
3144 * selection to the original selection.
3145 */
3146 if ( (lParam == (LPARAM)-1) ||
3147 (!PtInRect( &clientRect, mousePos )) )
3148 {
Alexandre Julliardde424282001-08-10 22:51:42 +00003149 LISTBOX_MoveCaret( hwnd, descr, lphc->droppedIndex, FALSE );
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003150 }
3151 }
Alexandre Julliardde424282001-08-10 22:51:42 +00003152 return LISTBOX_HandleLButtonUp( hwnd, descr );
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003153 case WM_LBUTTONDBLCLK:
3154 case WM_LBUTTONDOWN:
Alexandre Julliardde424282001-08-10 22:51:42 +00003155 return LISTBOX_HandleLButtonDownCombo(hwnd, descr, msg, wParam,
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003156 (INT16)LOWORD(lParam),
3157 (INT16)HIWORD(lParam) );
3158 case WM_NCACTIVATE:
3159 return FALSE;
3160 case WM_KEYDOWN:
3161 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
3162 {
3163 /* for some reason(?) Windows makes it possible to
3164 * show/hide ComboLBox by sending it WM_KEYDOWNs */
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00003165
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003166 if( (!(lphc->wState & CBF_EUI) && wParam == VK_F4) ||
3167 ( (lphc->wState & CBF_EUI) && !(lphc->wState & CBF_DROPPED)
3168 && (wParam == VK_DOWN || wParam == VK_UP)) )
3169 {
3170 COMBO_FlipListbox( lphc, FALSE, FALSE );
3171 return 0;
3172 }
3173 }
Alexandre Julliardde424282001-08-10 22:51:42 +00003174 return LISTBOX_HandleKeyDown( hwnd, descr, wParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003175
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003176 case LB_SETCURSEL16:
3177 case LB_SETCURSEL:
3178 lRet = unicode ? ListBoxWndProcW( hwnd, msg, wParam, lParam ) :
3179 ListBoxWndProcA( hwnd, msg, wParam, lParam );
Alexandre Julliardde424282001-08-10 22:51:42 +00003180 lRet =(lRet == LB_ERR) ? lRet : descr->selected_item;
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003181 return lRet;
3182 case WM_NCDESTROY:
3183 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
3184 lphc->hWndLBox = 0;
Alexandre Julliardebed1b82002-07-05 00:30:05 +00003185 break;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003186 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003187 }
Alexandre Julliardebed1b82002-07-05 00:30:05 +00003188
3189 /* default handling: call listbox wnd proc */
3190 lRet = unicode ? ListBoxWndProcW( hwnd, msg, wParam, lParam ) :
3191 ListBoxWndProcA( hwnd, msg, wParam, lParam );
Jukka Heinonen186a79c2001-07-24 01:16:16 +00003192
3193 TRACE_(combo)("\t default on msg [%04x]\n", (UINT16)msg );
3194
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00003195 return lRet;
3196}
3197
Marcus Meissner9aded511999-05-01 10:23:45 +00003198/***********************************************************************
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003199 * ComboLBWndProcA
Marcus Meissner9aded511999-05-01 10:23:45 +00003200 *
Vincent BĂ©ron9a624912002-05-31 23:06:46 +00003201 * NOTE: in Windows, winproc address of the ComboLBox is the same
Marcus Meissner9aded511999-05-01 10:23:45 +00003202 * as that of the Listbox.
Marcus Meissner9aded511999-05-01 10:23:45 +00003203 */
Alexandre Julliardde424282001-08-10 22:51:42 +00003204LRESULT WINAPI ComboLBWndProcA( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
Marcus Meissner9aded511999-05-01 10:23:45 +00003205{
Alexandre Julliardde424282001-08-10 22:51:42 +00003206 if (!IsWindow(hwnd)) return 0;
3207 return ComboLBWndProc_common( hwnd, msg, wParam, lParam, FALSE );
Dmitry Timoshkov74620992001-01-09 21:51:04 +00003208}
3209
3210/***********************************************************************
3211 * ComboLBWndProcW
3212 */
3213LRESULT WINAPI ComboLBWndProcW( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
3214{
Alexandre Julliardde424282001-08-10 22:51:42 +00003215 if (!IsWindow(hwnd)) return 0;
3216 return ComboLBWndProc_common( hwnd, msg, wParam, lParam, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00003217}