blob: eaabe720dc9d703b6f9f85b904bc0fc6a83fb6e5 [file] [log] [blame]
Alexandre Julliard0e607781993-11-03 19:23:37 +00001/*
Alexandre Julliard2787be81995-05-22 18:23:01 +00002 * Listbox controls
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00003 *
4 * Copyright 1996 Alexandre Julliard
Alexandre Julliard2787be81995-05-22 18:23:01 +00005 */
6
Alexandre Julliarde2abbb11995-03-19 17:39:39 +00007#include <string.h>
David Luyeree517e81999-02-28 12:27:56 +00008#include <stdlib.h>
Jeremy Whited3e22d92000-02-10 19:03:02 +00009#include <stdio.h>
10#include "windef.h"
11#include "wingdi.h"
Alex Korobka311d3291999-01-01 18:40:02 +000012#include "wine/winuser16.h"
Nick Hollowayb9ce4fd1999-09-11 16:29:00 +000013#include "wine/winbase16.h"
Alex Korobka311d3291999-01-01 18:40:02 +000014#include "winuser.h"
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000015#include "winerror.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000016#include "drive.h"
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +000017#include "heap.h"
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000018#include "spy.h"
Alexandre Julliard916f9752000-02-26 16:51:13 +000019#include "selectors.h"
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000020#include "win.h"
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000021#include "combo.h"
Alexandre Julliard06c275a1999-05-02 14:32:27 +000022#include "debugtools.h"
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +000023#include "tweak.h"
Alexandre Julliard0e607781993-11-03 19:23:37 +000024
Jeremy Whited3e22d92000-02-10 19:03:02 +000025DEFAULT_DEBUG_CHANNEL(listbox);
26DECLARE_DEBUG_CHANNEL(combo);
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000027
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000028/* Unimplemented yet:
29 * - LBS_NOSEL
30 * - LBS_USETABSTOPS
31 * - Unicode
32 * - Locale handling
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000033 */
Alexandre Julliarde2abbb11995-03-19 17:39:39 +000034
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000035/* Items array granularity */
36#define LB_ARRAY_GRANULARITY 16
Alexandre Julliard0e607781993-11-03 19:23:37 +000037
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000038/* Scrolling timeout in ms */
39#define LB_SCROLL_TIMEOUT 50
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000040
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000041/* Listbox system timer id */
42#define LB_TIMER_ID 2
Alexandre Julliardac9c9b01996-07-28 18:50:11 +000043
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000044/* Item structure */
45typedef struct
Alexandre Julliard2787be81995-05-22 18:23:01 +000046{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000047 LPSTR str; /* Item text */
Alexandre Julliarda3960291999-02-26 11:11:13 +000048 BOOL selected; /* Is item selected? */
49 UINT height; /* Item height (only for OWNERDRAWVARIABLE) */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000050 DWORD data; /* User data */
51} LB_ITEMDATA;
Alexandre Julliard2787be81995-05-22 18:23:01 +000052
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000053/* Listbox structure */
54typedef struct
Alexandre Julliard2787be81995-05-22 18:23:01 +000055{
Alexandre Julliarda3960291999-02-26 11:11:13 +000056 HANDLE heap; /* Heap for this listbox */
57 HWND owner; /* Owner window to send notifications to */
58 UINT style; /* Window style */
59 INT width; /* Window width */
60 INT height; /* Window height */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000061 LB_ITEMDATA *items; /* Array of items */
Alexandre Julliarda3960291999-02-26 11:11:13 +000062 INT nb_items; /* Number of items */
63 INT top_item; /* Top visible item */
64 INT selected_item; /* Selected item */
65 INT focus_item; /* Item that has the focus */
66 INT anchor_item; /* Anchor item for extended selection */
67 INT item_height; /* Default item height */
68 INT page_size; /* Items per listbox page */
69 INT column_width; /* Column width for multi-column listboxes */
70 INT horz_extent; /* Horizontal extent (0 if no hscroll) */
71 INT horz_pos; /* Horizontal position */
72 INT nb_tabs; /* Number of tabs in array */
73 INT *tabs; /* Array of tabs */
74 BOOL caret_on; /* Is caret on? */
Luc Tourangeau5ee117b1999-04-04 12:48:21 +000075 BOOL captured; /* Is mouse captured? */
Alexandre Julliarda3960291999-02-26 11:11:13 +000076 HFONT font; /* Current font */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000077 LCID locale; /* Current locale for string comparisons */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000078 LPHEADCOMBO lphc; /* ComboLBox */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000079} LB_DESCR;
Alexandre Julliard2787be81995-05-22 18:23:01 +000080
Alexandre Julliardfa68b751995-04-03 16:55:37 +000081
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000082#define IS_OWNERDRAW(descr) \
83 ((descr)->style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE))
Alexandre Julliardb817f4f1996-03-14 18:08:34 +000084
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000085#define HAS_STRINGS(descr) \
86 (!IS_OWNERDRAW(descr) || ((descr)->style & LBS_HASSTRINGS))
Alexandre Julliard2787be81995-05-22 18:23:01 +000087
Gerard Patelc9a6d501999-07-25 13:03:17 +000088
89#define IS_MULTISELECT(descr) \
90 ((descr)->style & LBS_MULTIPLESEL || ((descr)->style & LBS_EXTENDEDSEL))
91
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000092#define SEND_NOTIFICATION(wnd,descr,code) \
Alexandre Julliarda3960291999-02-26 11:11:13 +000093 (SendMessageA( (descr)->owner, WM_COMMAND, \
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000094 MAKEWPARAM((((descr)->lphc)?ID_CB_LISTBOX:(wnd)->wIDmenu), (code) ), (wnd)->hwndSelf ))
Alexandre Julliardfa68b751995-04-03 16:55:37 +000095
Gerard Patelc9a6d501999-07-25 13:03:17 +000096#define ISWIN31 (LOWORD(GetVersion()) == 0x0a03)
97
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000098/* Current timer status */
99typedef enum
Alexandre Julliardfa68b751995-04-03 16:55:37 +0000100{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000101 LB_TIMER_NONE,
102 LB_TIMER_UP,
103 LB_TIMER_LEFT,
104 LB_TIMER_DOWN,
105 LB_TIMER_RIGHT
106} TIMER_DIRECTION;
Alexandre Julliardfa68b751995-04-03 16:55:37 +0000107
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000108static TIMER_DIRECTION LISTBOX_Timer = LB_TIMER_NONE;
109
110
111/***********************************************************************
112 * LISTBOX_Dump
113 */
114void LISTBOX_Dump( WND *wnd )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000115{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000116 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000117 LB_ITEMDATA *item;
118 LB_DESCR *descr = *(LB_DESCR **)wnd->wExtra;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000119
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000120 TRACE( "Listbox:\n" );
121 TRACE( "hwnd=%04x descr=%08x heap=%08x items=%d top=%d\n",
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000122 wnd->hwndSelf, (UINT)descr, descr->heap, descr->nb_items,
123 descr->top_item );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000124 for (i = 0, item = descr->items; i < descr->nb_items; i++, item++)
125 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000126 TRACE( "%4d: %-40s %d %08lx %3d\n",
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000127 i, item->str, item->selected, item->data, item->height );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000128 }
Alexandre Julliard2787be81995-05-22 18:23:01 +0000129}
130
131
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000132/***********************************************************************
133 * LISTBOX_GetCurrentPageSize
134 *
135 * Return the current page size
136 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000137static INT LISTBOX_GetCurrentPageSize( WND *wnd, LB_DESCR *descr )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000138{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000139 INT i, height;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000140 if (!(descr->style & LBS_OWNERDRAWVARIABLE)) return descr->page_size;
141 for (i = descr->top_item, height = 0; i < descr->nb_items; i++)
142 {
143 if ((height += descr->items[i].height) > descr->height) break;
144 }
145 if (i == descr->top_item) return 1;
146 else return i - descr->top_item;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000147}
148
149
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000150/***********************************************************************
151 * LISTBOX_GetMaxTopIndex
152 *
153 * Return the maximum possible index for the top of the listbox.
154 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000155static INT LISTBOX_GetMaxTopIndex( WND *wnd, LB_DESCR *descr )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000156{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000157 INT max, page;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000158
159 if (descr->style & LBS_OWNERDRAWVARIABLE)
160 {
161 page = descr->height;
162 for (max = descr->nb_items - 1; max >= 0; max--)
163 if ((page -= descr->items[max].height) < 0) break;
164 if (max < descr->nb_items - 1) max++;
165 }
166 else if (descr->style & LBS_MULTICOLUMN)
167 {
168 if ((page = descr->width / descr->column_width) < 1) page = 1;
169 max = (descr->nb_items + descr->page_size - 1) / descr->page_size;
170 max = (max - page) * descr->page_size;
171 }
172 else
173 {
174 max = descr->nb_items - descr->page_size;
175 }
176 if (max < 0) max = 0;
177 return max;
178}
179
180
181/***********************************************************************
182 * LISTBOX_UpdateScroll
183 *
184 * Update the scrollbars. Should be called whenever the content
185 * of the listbox changes.
186 */
187static void LISTBOX_UpdateScroll( WND *wnd, LB_DESCR *descr )
188{
189 SCROLLINFO info;
190
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000191 /* Check the listbox scroll bar flags individually before we call
192 SetScrollInfo otherwise when the listbox style is WS_HSCROLL and
193 no WS_VSCROLL, we end up with an uninitialized, visible horizontal
194 scroll bar when we do not need one.
195 if (!(descr->style & WS_VSCROLL)) return;
196 */
197
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000198 /* It is important that we check descr->style, and not wnd->dwStyle,
199 for WS_VSCROLL, as the former is exactly the one passed in
200 argument to CreateWindow.
201 In Windows (and from now on in Wine :) a listbox created
202 with such a style (no WS_SCROLL) does not update
203 the scrollbar with listbox-related data, thus letting
204 the programmer use it for his/her own purposes. */
205
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000206 if (descr->style & LBS_NOREDRAW) return;
207 info.cbSize = sizeof(info);
208
209 if (descr->style & LBS_MULTICOLUMN)
210 {
211 info.nMin = 0;
212 info.nMax = (descr->nb_items - 1) / descr->page_size;
213 info.nPos = descr->top_item / descr->page_size;
214 info.nPage = descr->width / descr->column_width;
215 if (info.nPage < 1) info.nPage = 1;
216 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
217 if (descr->style & LBS_DISABLENOSCROLL)
218 info.fMask |= SIF_DISABLENOSCROLL;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000219 if (descr->style & WS_HSCROLL)
220 SetScrollInfo( wnd->hwndSelf, SB_HORZ, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000221 info.nMax = 0;
222 info.fMask = SIF_RANGE;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000223 if (descr->style & WS_VSCROLL)
224 SetScrollInfo( wnd->hwndSelf, SB_VERT, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000225 }
226 else
227 {
228 info.nMin = 0;
229 info.nMax = descr->nb_items - 1;
230 info.nPos = descr->top_item;
231 info.nPage = LISTBOX_GetCurrentPageSize( wnd, descr );
232 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
233 if (descr->style & LBS_DISABLENOSCROLL)
234 info.fMask |= SIF_DISABLENOSCROLL;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000235 if (descr->style & WS_VSCROLL)
236 SetScrollInfo( wnd->hwndSelf, SB_VERT, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000237
238 if (descr->horz_extent)
239 {
240 info.nMin = 0;
241 info.nMax = descr->horz_extent - 1;
242 info.nPos = descr->horz_pos;
243 info.nPage = descr->width;
244 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
245 if (descr->style & LBS_DISABLENOSCROLL)
246 info.fMask |= SIF_DISABLENOSCROLL;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +0000247 if (descr->style & WS_HSCROLL)
248 SetScrollInfo( wnd->hwndSelf, SB_HORZ, &info, TRUE );
249
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000250 }
251 }
252}
253
254
255/***********************************************************************
256 * LISTBOX_SetTopItem
257 *
258 * Set the top item of the listbox, scrolling up or down if necessary.
259 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000260static LRESULT LISTBOX_SetTopItem( WND *wnd, LB_DESCR *descr, INT index,
261 BOOL scroll )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000262{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000263 INT max = LISTBOX_GetMaxTopIndex( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000264 if (index > max) index = max;
265 if (index < 0) index = 0;
266 if (descr->style & LBS_MULTICOLUMN) index -= index % descr->page_size;
267 if (descr->top_item == index) return LB_OKAY;
268 if (descr->style & LBS_MULTICOLUMN)
269 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000270 INT diff = (descr->top_item - index) / descr->page_size * descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000271 if (scroll && (abs(diff) < descr->width))
Alexandre Julliarda3960291999-02-26 11:11:13 +0000272 ScrollWindowEx( wnd->hwndSelf, diff, 0, NULL, NULL, 0, NULL,
NF Stevens762f18d1999-01-24 19:02:16 +0000273 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
274
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000275 else
276 scroll = FALSE;
277 }
278 else if (scroll)
279 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000280 INT diff;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000281 if (descr->style & LBS_OWNERDRAWVARIABLE)
282 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000283 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000284 diff = 0;
285 if (index > descr->top_item)
286 {
287 for (i = index - 1; i >= descr->top_item; i--)
288 diff -= descr->items[i].height;
289 }
290 else
291 {
292 for (i = index; i < descr->top_item; i++)
293 diff += descr->items[i].height;
294 }
295 }
296 else
297 diff = (descr->top_item - index) * descr->item_height;
298
299 if (abs(diff) < descr->height)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000300 ScrollWindowEx( wnd->hwndSelf, 0, diff, NULL, NULL, 0, NULL,
NF Stevens762f18d1999-01-24 19:02:16 +0000301 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000302 else
303 scroll = FALSE;
304 }
Alexandre Julliarda3960291999-02-26 11:11:13 +0000305 if (!scroll) InvalidateRect( wnd->hwndSelf, NULL, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000306 descr->top_item = index;
307 LISTBOX_UpdateScroll( wnd, descr );
308 return LB_OKAY;
309}
310
311
312/***********************************************************************
313 * LISTBOX_UpdatePage
314 *
315 * Update the page size. Should be called when the size of
316 * the client area or the item height changes.
317 */
318static void LISTBOX_UpdatePage( WND *wnd, LB_DESCR *descr )
319{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000320 INT page_size;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000321
Paul Quinn75722071999-05-22 18:45:06 +0000322 if ((descr->item_height == 0) || (page_size = descr->height / descr->item_height) < 1)
323 page_size = 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000324 if (page_size == descr->page_size) return;
325 descr->page_size = page_size;
326 if (descr->style & LBS_MULTICOLUMN)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000327 InvalidateRect( wnd->hwndSelf, NULL, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000328 LISTBOX_SetTopItem( wnd, descr, descr->top_item, FALSE );
329}
330
331
332/***********************************************************************
333 * LISTBOX_UpdateSize
334 *
335 * Update the size of the listbox. Should be called when the size of
336 * the client area changes.
337 */
338static void LISTBOX_UpdateSize( WND *wnd, LB_DESCR *descr )
339{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000340 RECT rect;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000341
Alexandre Julliarda3960291999-02-26 11:11:13 +0000342 GetClientRect( wnd->hwndSelf, &rect );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000343 descr->width = rect.right - rect.left;
344 descr->height = rect.bottom - rect.top;
Alexandre Julliarda0d77311998-09-13 16:32:00 +0000345 if (!(descr->style & LBS_NOINTEGRALHEIGHT) && !IS_OWNERDRAW(descr))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000346 {
347 if ((descr->height > descr->item_height) &&
348 (descr->height % descr->item_height))
349 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000350 TRACE("[%04x]: changing height %d -> %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000351 wnd->hwndSelf, descr->height,
352 descr->height - descr->height%descr->item_height );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000353 SetWindowPos( wnd->hwndSelf, 0, 0, 0,
Alexandre Julliard01d63461997-01-20 19:43:45 +0000354 wnd->rectWindow.right - wnd->rectWindow.left,
355 wnd->rectWindow.bottom - wnd->rectWindow.top -
356 (descr->height % descr->item_height),
357 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000358 return;
359 }
360 }
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000361 TRACE("[%04x]: new size = %d,%d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000362 wnd->hwndSelf, descr->width, descr->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000363 LISTBOX_UpdatePage( wnd, descr );
364 LISTBOX_UpdateScroll( wnd, descr );
365}
366
367
368/***********************************************************************
369 * LISTBOX_GetItemRect
370 *
371 * Get the rectangle enclosing an item, in listbox client coordinates.
372 * Return 1 if the rectangle is (partially) visible, 0 if hidden, -1 on error.
373 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000374static LRESULT LISTBOX_GetItemRect( WND *wnd, LB_DESCR *descr, INT index,
375 RECT *rect )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000376{
377 /* Index <= 0 is legal even on empty listboxes */
378 if (index && (index >= descr->nb_items)) return -1;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000379 SetRect( rect, 0, 0, descr->width, descr->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000380 if (descr->style & LBS_MULTICOLUMN)
381 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000382 INT col = (index / descr->page_size) -
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000383 (descr->top_item / descr->page_size);
384 rect->left += col * descr->column_width;
385 rect->right = rect->left + descr->column_width;
386 rect->top += (index % descr->page_size) * descr->item_height;
387 rect->bottom = rect->top + descr->item_height;
388 }
389 else if (descr->style & LBS_OWNERDRAWVARIABLE)
390 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000391 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000392 rect->right += descr->horz_pos;
Alexandre Julliard349a9531997-02-02 19:01:52 +0000393 if ((index >= 0) && (index < descr->nb_items))
394 {
395 if (index < descr->top_item)
396 {
397 for (i = descr->top_item-1; i >= index; i--)
398 rect->top -= descr->items[i].height;
399 }
400 else
401 {
402 for (i = descr->top_item; i < index; i++)
403 rect->top += descr->items[i].height;
404 }
405 rect->bottom = rect->top + descr->items[index].height;
406
407 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000408 }
409 else
410 {
411 rect->top += (index - descr->top_item) * descr->item_height;
412 rect->bottom = rect->top + descr->item_height;
413 rect->right += descr->horz_pos;
414 }
415
416 return ((rect->left < descr->width) && (rect->right > 0) &&
417 (rect->top < descr->height) && (rect->bottom > 0));
418}
419
420
421/***********************************************************************
422 * LISTBOX_GetItemFromPoint
423 *
424 * Return the item nearest from point (x,y) (in client coordinates).
425 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000426static INT LISTBOX_GetItemFromPoint( WND *wnd, LB_DESCR *descr,
427 INT x, INT y )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000428{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000429 INT index = descr->top_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000430
431 if (!descr->nb_items) return -1; /* No items */
432 if (descr->style & LBS_OWNERDRAWVARIABLE)
433 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000434 INT pos = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000435 if (y >= 0)
436 {
437 while (index < descr->nb_items)
438 {
439 if ((pos += descr->items[index].height) > y) break;
440 index++;
441 }
442 }
443 else
444 {
445 while (index > 0)
446 {
447 index--;
448 if ((pos -= descr->items[index].height) <= y) break;
449 }
450 }
451 }
452 else if (descr->style & LBS_MULTICOLUMN)
453 {
454 if (y >= descr->item_height * descr->page_size) return -1;
455 if (y >= 0) index += y / descr->item_height;
456 if (x >= 0) index += (x / descr->column_width) * descr->page_size;
457 else index -= (((x + 1) / descr->column_width) - 1) * descr->page_size;
458 }
459 else
460 {
461 index += (y / descr->item_height);
462 }
463 if (index < 0) return 0;
464 if (index >= descr->nb_items) return -1;
465 return index;
466}
467
468
469/***********************************************************************
470 * LISTBOX_PaintItem
471 *
472 * Paint an item.
473 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000474static void LISTBOX_PaintItem( WND *wnd, LB_DESCR *descr, HDC hdc,
475 const RECT *rect, INT index, UINT action )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000476{
477 LB_ITEMDATA *item = NULL;
478 if (index < descr->nb_items) item = &descr->items[index];
479
480 if (IS_OWNERDRAW(descr))
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000481 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000482 DRAWITEMSTRUCT dis;
483 UINT id = (descr->lphc) ? ID_CB_LISTBOX : wnd->wIDmenu;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000484
Marcus Meissner9ad90171999-01-20 14:08:00 +0000485 if (!item)
486 {
487 if (action == ODA_FOCUS)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000488 DrawFocusRect( hdc, rect );
Marcus Meissner9ad90171999-01-20 14:08:00 +0000489 else
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000490 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 +0000491 return;
492 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000493 dis.CtlType = ODT_LISTBOX;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000494 dis.CtlID = id;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000495 dis.hwndItem = wnd->hwndSelf;
496 dis.itemAction = action;
497 dis.hDC = hdc;
498 dis.itemID = index;
499 dis.itemState = 0;
500 if (item && item->selected) dis.itemState |= ODS_SELECTED;
501 if ((descr->focus_item == index) &&
502 (descr->caret_on) &&
Alexandre Julliarda3960291999-02-26 11:11:13 +0000503 (GetFocus() == wnd->hwndSelf)) dis.itemState |= ODS_FOCUS;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000504 if (wnd->dwStyle & WS_DISABLED) dis.itemState |= ODS_DISABLED;
505 dis.itemData = item ? item->data : 0;
506 dis.rcItem = *rect;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000507 TRACE("[%04x]: drawitem %d (%s) action=%02x "
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000508 "state=%02x rect=%d,%d-%d,%d\n",
509 wnd->hwndSelf, index, item ? item->str : "", action,
510 dis.itemState, rect->left, rect->top,
511 rect->right, rect->bottom );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000512 SendMessageA(descr->owner, WM_DRAWITEM, id, (LPARAM)&dis);
Alexandre Julliard2787be81995-05-22 18:23:01 +0000513 }
514 else
Alexandre Julliardac9c9b01996-07-28 18:50:11 +0000515 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000516 COLORREF oldText = 0, oldBk = 0;
517
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000518 if (action == ODA_FOCUS)
519 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000520 DrawFocusRect( hdc, rect );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000521 return;
522 }
523 if (item && item->selected)
524 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000525 oldBk = SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
526 oldText = SetTextColor( hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000527 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000528
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000529 TRACE("[%04x]: painting %d (%s) action=%02x "
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000530 "rect=%d,%d-%d,%d\n",
531 wnd->hwndSelf, index, item ? item->str : "", action,
532 rect->left, rect->top, rect->right, rect->bottom );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000533 if (!item)
Abey George889a3be1999-10-23 17:12:24 +0000534 ExtTextOutA( hdc, rect->left + 1, rect->top,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000535 ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000536 else if (!(descr->style & LBS_USETABSTOPS))
Abey George889a3be1999-10-23 17:12:24 +0000537 ExtTextOutA( hdc, rect->left + 1, rect->top,
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000538 ETO_OPAQUE | ETO_CLIPPED, rect, item->str,
539 strlen(item->str), NULL );
540 else
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000541 {
542 /* Output empty string to paint background in the full width. */
Abey George889a3be1999-10-23 17:12:24 +0000543 ExtTextOutA( hdc, rect->left + 1, rect->top,
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000544 ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
Abey George889a3be1999-10-23 17:12:24 +0000545 TabbedTextOutA( hdc, rect->left + 1 , rect->top,
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000546 item->str, strlen(item->str),
547 descr->nb_tabs, descr->tabs, 0);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000548 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000549 if (item && item->selected)
550 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000551 SetBkColor( hdc, oldBk );
552 SetTextColor( hdc, oldText );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000553 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000554 if ((descr->focus_item == index) &&
555 (descr->caret_on) &&
Alexandre Julliarda3960291999-02-26 11:11:13 +0000556 (GetFocus() == wnd->hwndSelf)) DrawFocusRect( hdc, rect );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000557 }
Alexandre Julliard2787be81995-05-22 18:23:01 +0000558}
559
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000560
561/***********************************************************************
562 * LISTBOX_SetRedraw
563 *
564 * Change the redraw flag.
565 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000566static void LISTBOX_SetRedraw( WND *wnd, LB_DESCR *descr, BOOL on )
Alexandre Julliardac9c9b01996-07-28 18:50:11 +0000567{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000568 if (on)
569 {
570 if (!(descr->style & LBS_NOREDRAW)) return;
571 descr->style &= ~LBS_NOREDRAW;
572 LISTBOX_UpdateScroll( wnd, descr );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000573 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000574 else descr->style |= LBS_NOREDRAW;
575}
Alexandre Julliard2787be81995-05-22 18:23:01 +0000576
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000577
578/***********************************************************************
579 * LISTBOX_RepaintItem
580 *
581 * Repaint a single item synchronously.
582 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000583static void LISTBOX_RepaintItem( WND *wnd, LB_DESCR *descr, INT index,
584 UINT action )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000585{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000586 HDC hdc;
587 RECT rect;
588 HFONT oldFont = 0;
589 HBRUSH hbrush, oldBrush = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000590
Francois Boisvert428d2981999-05-08 09:33:53 +0000591 /* Do not repaint the item if the item is not visible */
592 if ((descr->style & LBS_NOREDRAW) || !IsWindowVisible(wnd->hwndSelf)) return;
593
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000594 if (LISTBOX_GetItemRect( wnd, descr, index, &rect ) != 1) return;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000595 if (!(hdc = GetDCEx( wnd->hwndSelf, 0, DCX_CACHE ))) return;
596 if (descr->font) oldFont = SelectObject( hdc, descr->font );
597 hbrush = SendMessageA( descr->owner, WM_CTLCOLORLISTBOX,
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000598 hdc, (LPARAM)wnd->hwndSelf );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000599 if (hbrush) oldBrush = SelectObject( hdc, hbrush );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000600 if (wnd->dwStyle & WS_DISABLED)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000601 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
602 SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000603 LISTBOX_PaintItem( wnd, descr, hdc, &rect, index, action );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000604 if (oldFont) SelectObject( hdc, oldFont );
605 if (oldBrush) SelectObject( hdc, oldBrush );
606 ReleaseDC( wnd->hwndSelf, hdc );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000607}
608
609
610/***********************************************************************
611 * LISTBOX_InitStorage
612 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000613static LRESULT LISTBOX_InitStorage( WND *wnd, LB_DESCR *descr, INT nb_items,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000614 DWORD bytes )
615{
616 LB_ITEMDATA *item;
617
618 nb_items += LB_ARRAY_GRANULARITY - 1;
619 nb_items -= (nb_items % LB_ARRAY_GRANULARITY);
620 if (descr->items)
621 nb_items += HeapSize( descr->heap, 0, descr->items ) / sizeof(*item);
622 if (!(item = HeapReAlloc( descr->heap, 0, descr->items,
623 nb_items * sizeof(LB_ITEMDATA) )))
624 {
625 SEND_NOTIFICATION( wnd, descr, LBN_ERRSPACE );
626 return LB_ERRSPACE;
627 }
628 descr->items = item;
629 return LB_OKAY;
630}
631
632
633/***********************************************************************
634 * LISTBOX_SetTabStops
635 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000636static BOOL LISTBOX_SetTabStops( WND *wnd, LB_DESCR *descr, INT count,
637 LPINT tabs, BOOL short_ints )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000638{
639 if (!(descr->style & LBS_USETABSTOPS)) return TRUE;
640 if (descr->tabs) HeapFree( descr->heap, 0, descr->tabs );
641 if (!(descr->nb_tabs = count))
642 {
643 descr->tabs = NULL;
644 return TRUE;
645 }
646 /* FIXME: count = 1 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000647 if (!(descr->tabs = (INT *)HeapAlloc( descr->heap, 0,
648 descr->nb_tabs * sizeof(INT) )))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000649 return FALSE;
650 if (short_ints)
651 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000652 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000653 LPINT16 p = (LPINT16)tabs;
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000654
Alexandre Julliard15de6151999-08-04 12:22:42 +0000655 TRACE("[%04x]: settabstops ", wnd->hwndSelf );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000656 for (i = 0; i < descr->nb_tabs; i++) {
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000657 descr->tabs[i] = *p++<<1; /* FIXME */
Alexandre Julliard15de6151999-08-04 12:22:42 +0000658 if (TRACE_ON(listbox)) DPRINTF("%hd ", descr->tabs[i]);
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000659 }
Alexandre Julliard15de6151999-08-04 12:22:42 +0000660 if (TRACE_ON(listbox)) DPRINTF("\n");
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000661 }
Alexandre Julliarda3960291999-02-26 11:11:13 +0000662 else memcpy( descr->tabs, tabs, descr->nb_tabs * sizeof(INT) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000663 /* FIXME: repaint the window? */
Alexandre Julliard2787be81995-05-22 18:23:01 +0000664 return TRUE;
665}
666
667
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000668/***********************************************************************
669 * LISTBOX_GetText
670 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000671static LRESULT LISTBOX_GetText( WND *wnd, LB_DESCR *descr, INT index,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000672 LPSTR buffer )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000673{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000674 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
675 if (HAS_STRINGS(descr))
676 {
Marcus Meissner4f7dc461998-11-22 15:43:34 +0000677 if (!buffer)
678 return strlen(descr->items[index].str);
Alexandre Julliarda3960291999-02-26 11:11:13 +0000679 lstrcpyA( buffer, descr->items[index].str );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000680 return strlen(buffer);
Marcus Meissner4f7dc461998-11-22 15:43:34 +0000681 } else {
682 if (buffer)
683 *((LPDWORD)buffer)=*(LPDWORD)(&descr->items[index].data);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000684 return sizeof(DWORD);
685 }
Alexandre Julliard2787be81995-05-22 18:23:01 +0000686}
687
688
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000689/***********************************************************************
690 * LISTBOX_FindStringPos
691 *
692 * Find the nearest string located before a given string in sort order.
693 * If 'exact' is TRUE, return an error if we don't get an exact match.
694 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000695static INT LISTBOX_FindStringPos( WND *wnd, LB_DESCR *descr, LPCSTR str,
696 BOOL exact )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000697{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000698 INT index, min, max, res = -1;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000699
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000700 if (!(descr->style & LBS_SORT)) return -1; /* Add it at the end */
701 min = 0;
702 max = descr->nb_items;
703 while (min != max)
704 {
705 index = (min + max) / 2;
706 if (HAS_STRINGS(descr))
Alexandre Julliarda3960291999-02-26 11:11:13 +0000707 res = lstrcmpiA( descr->items[index].str, str );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000708 else
709 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000710 COMPAREITEMSTRUCT cis;
711 UINT id = (descr->lphc) ? ID_CB_LISTBOX : wnd->wIDmenu;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000712
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000713 cis.CtlType = ODT_LISTBOX;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000714 cis.CtlID = id;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000715 cis.hwndItem = wnd->hwndSelf;
716 cis.itemID1 = index;
717 cis.itemData1 = descr->items[index].data;
718 cis.itemID2 = -1;
719 cis.itemData2 = (DWORD)str;
720 cis.dwLocaleId = descr->locale;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000721 res = SendMessageA( descr->owner, WM_COMPAREITEM,
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000722 id, (LPARAM)&cis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000723 }
724 if (!res) return index;
725 if (res > 0) max = index;
726 else min = index + 1;
727 }
728 return exact ? -1 : max;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000729}
730
731
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000732/***********************************************************************
733 * LISTBOX_FindFileStrPos
734 *
735 * Find the nearest string located before a given string in directory
736 * sort order (i.e. first files, then directories, then drives).
737 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000738static INT LISTBOX_FindFileStrPos( WND *wnd, LB_DESCR *descr, LPCSTR str )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000739{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000740 INT min, max, res = -1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000741
742 if (!HAS_STRINGS(descr))
743 return LISTBOX_FindStringPos( wnd, descr, str, FALSE );
744 min = 0;
745 max = descr->nb_items;
746 while (min != max)
747 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000748 INT index = (min + max) / 2;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000749 const char *p = descr->items[index].str;
750 if (*p == '[') /* drive or directory */
751 {
752 if (*str != '[') res = -1;
753 else if (p[1] == '-') /* drive */
754 {
755 if (str[1] == '-') res = str[2] - p[2];
756 else res = -1;
757 }
758 else /* directory */
759 {
760 if (str[1] == '-') res = 1;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000761 else res = lstrcmpiA( str, p );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000762 }
763 }
764 else /* filename */
765 {
766 if (*str == '[') res = 1;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000767 else res = lstrcmpiA( str, p );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000768 }
769 if (!res) return index;
770 if (res < 0) max = index;
771 else min = index + 1;
772 }
773 return max;
774}
775
776
777/***********************************************************************
778 * LISTBOX_FindString
779 *
780 * Find the item beginning with a given string.
781 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000782static INT LISTBOX_FindString( WND *wnd, LB_DESCR *descr, INT start,
783 LPCSTR str, BOOL exact )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000784{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000785 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000786 LB_ITEMDATA *item;
787
788 if (start >= descr->nb_items) start = -1;
789 item = descr->items + start + 1;
790 if (HAS_STRINGS(descr))
791 {
Rein Klazesd35c8341999-08-21 13:04:58 +0000792 if (!str || ! str[0] ) return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000793 if (exact)
794 {
795 for (i = start + 1; i < descr->nb_items; i++, item++)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000796 if (!lstrcmpiA( str, item->str )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000797 for (i = 0, item = descr->items; i <= start; i++, item++)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000798 if (!lstrcmpiA( str, item->str )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000799 }
800 else
801 {
802 /* Special case for drives and directories: ignore prefix */
803#define CHECK_DRIVE(item) \
804 if ((item)->str[0] == '[') \
805 { \
Alexandre Julliarda3960291999-02-26 11:11:13 +0000806 if (!lstrncmpiA( str, (item)->str+1, len )) return i; \
807 if (((item)->str[1] == '-') && !lstrncmpiA(str,(item)->str+2,len)) \
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000808 return i; \
809 }
810
Alexandre Julliarda3960291999-02-26 11:11:13 +0000811 INT len = strlen(str);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000812 for (i = start + 1; i < descr->nb_items; i++, item++)
813 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000814 if (!lstrncmpiA( str, item->str, len )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000815 CHECK_DRIVE(item);
816 }
817 for (i = 0, item = descr->items; i <= start; i++, item++)
818 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000819 if (!lstrncmpiA( str, item->str, len )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000820 CHECK_DRIVE(item);
821 }
822#undef CHECK_DRIVE
823 }
824 }
825 else
826 {
827 if (exact && (descr->style & LBS_SORT))
828 /* If sorted, use a WM_COMPAREITEM binary search */
829 return LISTBOX_FindStringPos( wnd, descr, str, TRUE );
830
831 /* Otherwise use a linear search */
832 for (i = start + 1; i < descr->nb_items; i++, item++)
833 if (item->data == (DWORD)str) return i;
834 for (i = 0, item = descr->items; i <= start; i++, item++)
835 if (item->data == (DWORD)str) return i;
836 }
837 return LB_ERR;
838}
839
840
841/***********************************************************************
842 * LISTBOX_GetSelCount
843 */
844static LRESULT LISTBOX_GetSelCount( WND *wnd, LB_DESCR *descr )
845{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000846 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000847 LB_ITEMDATA *item = descr->items;
848
849 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
850 for (i = count = 0; i < descr->nb_items; i++, item++)
851 if (item->selected) count++;
852 return count;
853}
854
855
856/***********************************************************************
857 * LISTBOX_GetSelItems16
858 */
859static LRESULT LISTBOX_GetSelItems16( WND *wnd, LB_DESCR *descr, INT16 max,
860 LPINT16 array )
861{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000862 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000863 LB_ITEMDATA *item = descr->items;
864
865 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
866 for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++)
867 if (item->selected) array[count++] = (INT16)i;
868 return count;
869}
870
871
872/***********************************************************************
873 * LISTBOX_GetSelItems32
874 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000875static LRESULT LISTBOX_GetSelItems( WND *wnd, LB_DESCR *descr, INT max,
876 LPINT array )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000877{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000878 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000879 LB_ITEMDATA *item = descr->items;
880
881 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
882 for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++)
883 if (item->selected) array[count++] = i;
884 return count;
885}
886
887
888/***********************************************************************
889 * LISTBOX_Paint
890 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000891static LRESULT LISTBOX_Paint( WND *wnd, LB_DESCR *descr, HDC hdc )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000892{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000893 INT i, col_pos = descr->page_size - 1;
894 RECT rect;
895 HFONT oldFont = 0;
896 HBRUSH hbrush, oldBrush = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000897
Alexandre Julliarda3960291999-02-26 11:11:13 +0000898 SetRect( &rect, 0, 0, descr->width, descr->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000899 if (descr->style & LBS_NOREDRAW) return 0;
900 if (descr->style & LBS_MULTICOLUMN)
901 rect.right = rect.left + descr->column_width;
902 else if (descr->horz_pos)
903 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000904 SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000905 rect.right += descr->horz_pos;
906 }
907
Alexandre Julliarda3960291999-02-26 11:11:13 +0000908 if (descr->font) oldFont = SelectObject( hdc, descr->font );
909 hbrush = SendMessageA( descr->owner, WM_CTLCOLORLISTBOX,
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000910 hdc, (LPARAM)wnd->hwndSelf );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000911 if (hbrush) oldBrush = SelectObject( hdc, hbrush );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000912 if (wnd->dwStyle & WS_DISABLED)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000913 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000914
915 if (!descr->nb_items && (descr->focus_item != -1) && descr->caret_on &&
Alexandre Julliarda3960291999-02-26 11:11:13 +0000916 (GetFocus() == wnd->hwndSelf))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000917 {
918 /* Special case for empty listbox: paint focus rect */
919 rect.bottom = rect.top + descr->item_height;
920 LISTBOX_PaintItem( wnd, descr, hdc, &rect, descr->focus_item,
Gerard Patelc979b7b1998-12-24 16:25:50 +0000921 ODA_FOCUS );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000922 rect.top = rect.bottom;
923 }
924
925 for (i = descr->top_item; i < descr->nb_items; i++)
926 {
927 if (!(descr->style & LBS_OWNERDRAWVARIABLE))
928 rect.bottom = rect.top + descr->item_height;
929 else
930 rect.bottom = rect.top + descr->items[i].height;
931
932 LISTBOX_PaintItem( wnd, descr, hdc, &rect, i, ODA_DRAWENTIRE );
933 rect.top = rect.bottom;
934
935 if ((descr->style & LBS_MULTICOLUMN) && !col_pos)
936 {
937 if (!IS_OWNERDRAW(descr))
938 {
939 /* Clear the bottom of the column */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000940 SetBkColor( hdc, GetSysColor( COLOR_WINDOW ) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000941 if (rect.top < descr->height)
942 {
943 rect.bottom = descr->height;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000944 ExtTextOutA( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000945 &rect, NULL, 0, NULL );
946 }
947 }
948
949 /* Go to the next column */
950 rect.left += descr->column_width;
951 rect.right += descr->column_width;
952 rect.top = 0;
953 col_pos = descr->page_size - 1;
954 }
955 else
956 {
957 col_pos--;
958 if (rect.top >= descr->height) break;
959 }
960 }
961
962 if (!IS_OWNERDRAW(descr))
963 {
964 /* Clear the remainder of the client area */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000965 SetBkColor( hdc, GetSysColor( COLOR_WINDOW ) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000966 if (rect.top < descr->height)
967 {
968 rect.bottom = descr->height;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000969 ExtTextOutA( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000970 &rect, NULL, 0, NULL );
971 }
972 if (rect.right < descr->width)
973 {
974 rect.left = rect.right;
975 rect.right = descr->width;
976 rect.top = 0;
977 rect.bottom = descr->height;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000978 ExtTextOutA( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000979 &rect, NULL, 0, NULL );
980 }
981 }
Alexandre Julliarda3960291999-02-26 11:11:13 +0000982 if (oldFont) SelectObject( hdc, oldFont );
983 if (oldBrush) SelectObject( hdc, oldBrush );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000984 return 0;
985}
986
987
988/***********************************************************************
989 * LISTBOX_InvalidateItems
990 *
991 * Invalidate all items from a given item. If the specified item is not
992 * visible, nothing happens.
993 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000994static void LISTBOX_InvalidateItems( WND *wnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000995{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000996 RECT rect;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000997
998 if (LISTBOX_GetItemRect( wnd, descr, index, &rect ) == 1)
999 {
1000 rect.bottom = descr->height;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001001 InvalidateRect( wnd->hwndSelf, &rect, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001002 if (descr->style & LBS_MULTICOLUMN)
1003 {
1004 /* Repaint the other columns */
1005 rect.left = rect.right;
1006 rect.right = descr->width;
1007 rect.top = 0;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001008 InvalidateRect( wnd->hwndSelf, &rect, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001009 }
1010 }
1011}
1012
1013
1014/***********************************************************************
1015 * LISTBOX_GetItemHeight
1016 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001017static LRESULT LISTBOX_GetItemHeight( WND *wnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001018{
1019 if (descr->style & LBS_OWNERDRAWVARIABLE)
1020 {
1021 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
1022 return descr->items[index].height;
1023 }
1024 else return descr->item_height;
1025}
1026
1027
1028/***********************************************************************
1029 * LISTBOX_SetItemHeight
1030 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001031static LRESULT LISTBOX_SetItemHeight( WND *wnd, LB_DESCR *descr, INT index,
1032 UINT height )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001033{
1034 if (!height) height = 1;
1035
1036 if (descr->style & LBS_OWNERDRAWVARIABLE)
1037 {
1038 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001039 TRACE("[%04x]: item %d height = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001040 wnd->hwndSelf, index, height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001041 descr->items[index].height = height;
1042 LISTBOX_UpdateScroll( wnd, descr );
1043 LISTBOX_InvalidateItems( wnd, descr, index );
1044 }
1045 else if (height != descr->item_height)
1046 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001047 TRACE("[%04x]: new height = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001048 wnd->hwndSelf, height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001049 descr->item_height = height;
1050 LISTBOX_UpdatePage( wnd, descr );
1051 LISTBOX_UpdateScroll( wnd, descr );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001052 InvalidateRect( wnd->hwndSelf, 0, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001053 }
1054 return LB_OKAY;
1055}
1056
1057
1058/***********************************************************************
1059 * LISTBOX_SetHorizontalPos
1060 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001061static void LISTBOX_SetHorizontalPos( WND *wnd, LB_DESCR *descr, INT pos )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001062{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001063 INT diff;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001064
1065 if (pos > descr->horz_extent - descr->width)
1066 pos = descr->horz_extent - descr->width;
1067 if (pos < 0) pos = 0;
1068 if (!(diff = descr->horz_pos - pos)) return;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001069 TRACE("[%04x]: new horz pos = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001070 wnd->hwndSelf, pos );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001071 descr->horz_pos = pos;
1072 LISTBOX_UpdateScroll( wnd, descr );
1073 if (abs(diff) < descr->width)
Alexandre Julliarda3960291999-02-26 11:11:13 +00001074 ScrollWindowEx( wnd->hwndSelf, diff, 0, NULL, NULL, 0, NULL,
NF Stevens762f18d1999-01-24 19:02:16 +00001075 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001076 else
Alexandre Julliarda3960291999-02-26 11:11:13 +00001077 InvalidateRect( wnd->hwndSelf, NULL, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001078}
1079
1080
1081/***********************************************************************
1082 * LISTBOX_SetHorizontalExtent
1083 */
1084static LRESULT LISTBOX_SetHorizontalExtent( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001085 UINT extent )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001086{
1087 if (!descr->horz_extent || (descr->style & LBS_MULTICOLUMN))
1088 return LB_OKAY;
1089 if (extent <= 0) extent = 1;
1090 if (extent == descr->horz_extent) return LB_OKAY;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001091 TRACE("[%04x]: new horz extent = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001092 wnd->hwndSelf, extent );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001093 descr->horz_extent = extent;
1094 if (descr->horz_pos > extent - descr->width)
1095 LISTBOX_SetHorizontalPos( wnd, descr, extent - descr->width );
1096 else
1097 LISTBOX_UpdateScroll( wnd, descr );
1098 return LB_OKAY;
1099}
1100
1101
1102/***********************************************************************
1103 * LISTBOX_SetColumnWidth
1104 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001105static LRESULT LISTBOX_SetColumnWidth( WND *wnd, LB_DESCR *descr, UINT width)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001106{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001107 if (width == descr->column_width) return LB_OKAY;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001108 TRACE("[%04x]: new column width = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001109 wnd->hwndSelf, width );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001110 descr->column_width = width;
1111 LISTBOX_UpdatePage( wnd, descr );
1112 return LB_OKAY;
1113}
1114
1115
1116/***********************************************************************
1117 * LISTBOX_SetFont
1118 *
1119 * Returns the item height.
1120 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001121static INT LISTBOX_SetFont( WND *wnd, LB_DESCR *descr, HFONT font )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001122{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001123 HDC hdc;
1124 HFONT oldFont = 0;
1125 TEXTMETRICA tm;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001126
1127 descr->font = font;
1128
Alexandre Julliarda3960291999-02-26 11:11:13 +00001129 if (!(hdc = GetDCEx( wnd->hwndSelf, 0, DCX_CACHE )))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001130 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001131 ERR("unable to get DC.\n" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001132 return 16;
1133 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001134 if (font) oldFont = SelectObject( hdc, font );
1135 GetTextMetricsA( hdc, &tm );
1136 if (oldFont) SelectObject( hdc, oldFont );
1137 ReleaseDC( wnd->hwndSelf, hdc );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001138 if (!IS_OWNERDRAW(descr))
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001139 LISTBOX_SetItemHeight( wnd, descr, 0, tm.tmHeight );
1140 return tm.tmHeight ;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001141}
1142
1143
1144/***********************************************************************
1145 * LISTBOX_MakeItemVisible
1146 *
1147 * Make sure that a given item is partially or fully visible.
1148 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001149static void LISTBOX_MakeItemVisible( WND *wnd, LB_DESCR *descr, INT index,
1150 BOOL fully )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001151{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001152 INT top;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001153
1154 if (index <= descr->top_item) top = index;
1155 else if (descr->style & LBS_MULTICOLUMN)
1156 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001157 INT cols = descr->width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001158 if (!fully) cols += descr->column_width - 1;
1159 if (cols >= descr->column_width) cols /= descr->column_width;
1160 else cols = 1;
1161 if (index < descr->top_item + (descr->page_size * cols)) return;
1162 top = index - descr->page_size * (cols - 1);
1163 }
1164 else if (descr->style & LBS_OWNERDRAWVARIABLE)
1165 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001166 INT height = fully ? descr->items[index].height : 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001167 for (top = index; top > descr->top_item; top--)
1168 if ((height += descr->items[top-1].height) > descr->height) break;
1169 }
1170 else
1171 {
1172 if (index < descr->top_item + descr->page_size) return;
1173 if (!fully && (index == descr->top_item + descr->page_size) &&
1174 (descr->height > (descr->page_size * descr->item_height))) return;
1175 top = index - descr->page_size + 1;
1176 }
1177 LISTBOX_SetTopItem( wnd, descr, top, TRUE );
1178}
1179
1180
1181/***********************************************************************
1182 * LISTBOX_SelectItemRange
1183 *
1184 * Select a range of items. Should only be used on a MULTIPLESEL listbox.
1185 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001186static LRESULT LISTBOX_SelectItemRange( WND *wnd, LB_DESCR *descr, INT first,
1187 INT last, BOOL on )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001188{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001189 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001190
1191 /* A few sanity checks */
1192
Alexandre Julliard03468f71998-02-15 19:40:49 +00001193 if ((last == -1) && (descr->nb_items == 0)) return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001194 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
1195 if (last == -1) last = descr->nb_items - 1;
1196 if ((first < 0) || (first >= descr->nb_items)) return LB_ERR;
1197 if ((last < 0) || (last >= descr->nb_items)) return LB_ERR;
1198 /* selected_item reflects last selected/unselected item on multiple sel */
1199 descr->selected_item = last;
1200
1201 if (on) /* Turn selection on */
1202 {
1203 for (i = first; i <= last; i++)
1204 {
1205 if (descr->items[i].selected) continue;
1206 descr->items[i].selected = TRUE;
1207 LISTBOX_RepaintItem( wnd, descr, i, ODA_SELECT );
1208 }
1209 }
1210 else /* Turn selection off */
1211 {
1212 for (i = first; i <= last; i++)
1213 {
1214 if (!descr->items[i].selected) continue;
1215 descr->items[i].selected = FALSE;
1216 LISTBOX_RepaintItem( wnd, descr, i, ODA_SELECT );
1217 }
1218 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001219 return LB_OKAY;
1220}
1221
1222
1223/***********************************************************************
1224 * LISTBOX_SetCaretIndex
Alexandre Julliard638f1691999-01-17 16:32:32 +00001225 *
1226 * NOTES
1227 * index must be between 0 and descr->nb_items-1, or LB_ERR is returned.
1228 *
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001229 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001230static LRESULT LISTBOX_SetCaretIndex( WND *wnd, LB_DESCR *descr, INT index,
1231 BOOL fully_visible )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001232{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001233 INT oldfocus = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001234
Alexandre Julliard638f1691999-01-17 16:32:32 +00001235 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001236 if (index == oldfocus) return LB_OKAY;
1237 descr->focus_item = index;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001238 if ((oldfocus != -1) && descr->caret_on && (GetFocus() == wnd->hwndSelf))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001239 LISTBOX_RepaintItem( wnd, descr, oldfocus, ODA_FOCUS );
Alexandre Julliard638f1691999-01-17 16:32:32 +00001240
1241 LISTBOX_MakeItemVisible( wnd, descr, index, fully_visible );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001242 if (descr->caret_on && (GetFocus() == wnd->hwndSelf))
Alexandre Julliard638f1691999-01-17 16:32:32 +00001243 LISTBOX_RepaintItem( wnd, descr, index, ODA_FOCUS );
1244
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001245 return LB_OKAY;
1246}
1247
1248
1249/***********************************************************************
1250 * LISTBOX_SetSelection
1251 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001252static LRESULT LISTBOX_SetSelection( WND *wnd, LB_DESCR *descr, INT index,
1253 BOOL on, BOOL send_notify )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001254{
Dmitry Timoshkove0f493e1999-11-28 19:44:33 +00001255 TRACE( "index=%d notify=%s\n", index, send_notify ? "YES" : "NO" );
1256
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001257 if ((index < -1) || (index >= descr->nb_items)) return LB_ERR;
1258 if (descr->style & LBS_MULTIPLESEL)
1259 {
1260 if (index == -1) /* Select all items */
1261 return LISTBOX_SelectItemRange( wnd, descr, 0, -1, on );
1262 else /* Only one item */
1263 return LISTBOX_SelectItemRange( wnd, descr, index, index, on );
1264 }
1265 else
1266 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001267 INT oldsel = descr->selected_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001268 if (index == oldsel) return LB_OKAY;
1269 if (oldsel != -1) descr->items[oldsel].selected = FALSE;
1270 if (index != -1) descr->items[index].selected = TRUE;
1271 descr->selected_item = index;
Huw D M Davies65a0fa62000-03-25 21:41:17 +00001272 if (oldsel != -1) LISTBOX_RepaintItem( wnd, descr, oldsel, ODA_SELECT );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001273 if (index != -1) LISTBOX_RepaintItem( wnd, descr, index, ODA_SELECT );
Gerard Patelc9a6d501999-07-25 13:03:17 +00001274 if (send_notify && descr->nb_items) SEND_NOTIFICATION( wnd, descr,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001275 (index != -1) ? LBN_SELCHANGE : LBN_SELCANCEL );
Alex Korobka311d3291999-01-01 18:40:02 +00001276 else
1277 if( descr->lphc ) /* set selection change flag for parent combo */
1278 descr->lphc->wState |= CBF_SELCHANGE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001279 }
1280 return LB_OKAY;
1281}
1282
1283
1284/***********************************************************************
1285 * LISTBOX_MoveCaret
1286 *
1287 * Change the caret position and extend the selection to the new caret.
1288 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001289static void LISTBOX_MoveCaret( WND *wnd, LB_DESCR *descr, INT index,
1290 BOOL fully_visible )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001291{
1292 LISTBOX_SetCaretIndex( wnd, descr, index, fully_visible );
1293 if (descr->style & LBS_EXTENDEDSEL)
1294 {
1295 if (descr->anchor_item != -1)
1296 {
Huw D M Davies65a0fa62000-03-25 21:41:17 +00001297 INT first = min( descr->focus_item, descr->anchor_item );
1298 INT last = max( descr->focus_item, descr->anchor_item );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001299 if (first > 0)
1300 LISTBOX_SelectItemRange( wnd, descr, 0, first - 1, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001301 LISTBOX_SelectItemRange( wnd, descr, last + 1, -1, FALSE );
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001302 LISTBOX_SelectItemRange( wnd, descr, first, last, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001303 }
1304 }
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00001305 else if (!(descr->style & LBS_MULTIPLESEL))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001306 {
1307 /* Set selection to new caret item */
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00001308 LISTBOX_SetSelection( wnd, descr, index, TRUE, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001309 }
1310}
1311
1312
1313/***********************************************************************
1314 * LISTBOX_InsertItem
1315 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001316static LRESULT LISTBOX_InsertItem( WND *wnd, LB_DESCR *descr, INT index,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001317 LPSTR str, DWORD data )
1318{
1319 LB_ITEMDATA *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001320 INT max_items;
Gerard Patelc9a6d501999-07-25 13:03:17 +00001321 INT oldfocus = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001322
1323 if (index == -1) index = descr->nb_items;
1324 else if ((index < 0) || (index > descr->nb_items)) return LB_ERR;
1325 if (!descr->items) max_items = 0;
1326 else max_items = HeapSize( descr->heap, 0, descr->items ) / sizeof(*item);
1327 if (descr->nb_items == max_items)
1328 {
1329 /* We need to grow the array */
1330 max_items += LB_ARRAY_GRANULARITY;
1331 if (!(item = HeapReAlloc( descr->heap, 0, descr->items,
1332 max_items * sizeof(LB_ITEMDATA) )))
1333 {
1334 SEND_NOTIFICATION( wnd, descr, LBN_ERRSPACE );
1335 return LB_ERRSPACE;
1336 }
1337 descr->items = item;
1338 }
1339
1340 /* Insert the item structure */
1341
1342 item = &descr->items[index];
1343 if (index < descr->nb_items)
1344 RtlMoveMemory( item + 1, item,
1345 (descr->nb_items - index) * sizeof(LB_ITEMDATA) );
1346 item->str = str;
1347 item->data = data;
1348 item->height = 0;
1349 item->selected = FALSE;
1350 descr->nb_items++;
1351
1352 /* Get item height */
1353
1354 if (descr->style & LBS_OWNERDRAWVARIABLE)
1355 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001356 MEASUREITEMSTRUCT mis;
1357 UINT id = (descr->lphc) ? ID_CB_LISTBOX : wnd->wIDmenu;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001358
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001359 mis.CtlType = ODT_LISTBOX;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001360 mis.CtlID = id;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001361 mis.itemID = index;
1362 mis.itemData = descr->items[index].data;
1363 mis.itemHeight = descr->item_height;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001364 SendMessageA( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001365 item->height = mis.itemHeight ? mis.itemHeight : 1;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001366 TRACE("[%04x]: measure item %d (%s) = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001367 wnd->hwndSelf, index, str ? str : "", item->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001368 }
1369
1370 /* Repaint the items */
1371
1372 LISTBOX_UpdateScroll( wnd, descr );
1373 LISTBOX_InvalidateItems( wnd, descr, index );
1374
1375 /* Move selection and focused item */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001376 /* If listbox was empty, set focus to the first item */
Gerard Patelc9a6d501999-07-25 13:03:17 +00001377 if (descr->nb_items == 1)
1378 LISTBOX_SetCaretIndex( wnd, descr, 0, FALSE );
1379 /* single select don't change selection index in win31 */
1380 else if ((ISWIN31) && !(IS_MULTISELECT(descr)))
1381 {
1382 descr->selected_item++;
1383 LISTBOX_SetSelection( wnd, descr, descr->selected_item-1, TRUE, FALSE );
1384 }
1385 else
1386 {
1387 if (index <= descr->selected_item)
1388 {
1389 descr->selected_item++;
1390 descr->focus_item = oldfocus; /* focus not changed */
1391 }
1392 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001393 return LB_OKAY;
1394}
1395
1396
1397/***********************************************************************
1398 * LISTBOX_InsertString
1399 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001400static LRESULT LISTBOX_InsertString( WND *wnd, LB_DESCR *descr, INT index,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001401 LPCSTR str )
1402{
1403 LPSTR new_str = NULL;
1404 DWORD data = 0;
1405 LRESULT ret;
1406
1407 if (HAS_STRINGS(descr))
1408 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00001409 if (!str) str="";
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001410 if (!(new_str = HEAP_strdupA( descr->heap, 0, str )))
1411 {
1412 SEND_NOTIFICATION( wnd, descr, LBN_ERRSPACE );
1413 return LB_ERRSPACE;
1414 }
1415 }
1416 else data = (DWORD)str;
1417
1418 if (index == -1) index = descr->nb_items;
1419 if ((ret = LISTBOX_InsertItem( wnd, descr, index, new_str, data )) != 0)
1420 {
1421 if (new_str) HeapFree( descr->heap, 0, new_str );
1422 return ret;
1423 }
1424
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001425 TRACE("[%04x]: added item %d '%s'\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001426 wnd->hwndSelf, index, HAS_STRINGS(descr) ? new_str : "" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001427 return index;
1428}
1429
1430
1431/***********************************************************************
1432 * LISTBOX_DeleteItem
1433 *
1434 * Delete the content of an item. 'index' must be a valid index.
1435 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001436static void LISTBOX_DeleteItem( WND *wnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001437{
1438 /* Note: Win 3.1 only sends DELETEITEM on owner-draw items,
1439 * while Win95 sends it for all items with user data.
1440 * It's probably better to send it too often than not
1441 * often enough, so this is what we do here.
1442 */
1443 if (IS_OWNERDRAW(descr) || descr->items[index].data)
1444 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001445 DELETEITEMSTRUCT dis;
1446 UINT id = (descr->lphc) ? ID_CB_LISTBOX : wnd->wIDmenu;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001447
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001448 dis.CtlType = ODT_LISTBOX;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001449 dis.CtlID = id;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001450 dis.itemID = index;
1451 dis.hwndItem = wnd->hwndSelf;
1452 dis.itemData = descr->items[index].data;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001453 SendMessageA( descr->owner, WM_DELETEITEM, id, (LPARAM)&dis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001454 }
1455 if (HAS_STRINGS(descr) && descr->items[index].str)
1456 HeapFree( descr->heap, 0, descr->items[index].str );
1457}
1458
1459
1460/***********************************************************************
1461 * LISTBOX_RemoveItem
1462 *
1463 * Remove an item from the listbox and delete its content.
1464 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001465static LRESULT LISTBOX_RemoveItem( WND *wnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001466{
1467 LB_ITEMDATA *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001468 INT max_items;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001469
1470 if (index == -1) index = descr->nb_items - 1;
1471 else if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
Yuxi Zhangf94c3c52000-02-26 19:13:12 +00001472
1473 /* We need to invalidate the original rect instead of the updated one. */
1474 LISTBOX_InvalidateItems( wnd, descr, index );
1475
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001476 LISTBOX_DeleteItem( wnd, descr, index );
1477
1478 /* Remove the item */
1479
1480 item = &descr->items[index];
1481 if (index < descr->nb_items-1)
1482 RtlMoveMemory( item, item + 1,
1483 (descr->nb_items - index - 1) * sizeof(LB_ITEMDATA) );
1484 descr->nb_items--;
1485 if (descr->anchor_item == descr->nb_items) descr->anchor_item--;
1486
1487 /* Shrink the item array if possible */
1488
1489 max_items = HeapSize( descr->heap, 0, descr->items ) / sizeof(LB_ITEMDATA);
1490 if (descr->nb_items < max_items - 2*LB_ARRAY_GRANULARITY)
1491 {
1492 max_items -= LB_ARRAY_GRANULARITY;
1493 item = HeapReAlloc( descr->heap, 0, descr->items,
1494 max_items * sizeof(LB_ITEMDATA) );
1495 if (item) descr->items = item;
1496 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001497 /* Repaint the items */
1498
1499 LISTBOX_UpdateScroll( wnd, descr );
Gerard Patelc9a6d501999-07-25 13:03:17 +00001500 /* if we removed the scrollbar, reset the top of the list
1501 (correct for owner-drawn ???) */
1502 if (descr->nb_items == descr->page_size)
1503 LISTBOX_SetTopItem( wnd, descr, 0, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001504
1505 /* Move selection and focused item */
Gerard Patelc9a6d501999-07-25 13:03:17 +00001506 if (!IS_MULTISELECT(descr))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001507 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00001508 if (index == descr->selected_item)
1509 descr->selected_item = -1;
1510 else if (index < descr->selected_item)
1511 {
1512 descr->selected_item--;
1513 if (ISWIN31) /* win 31 do not change the selected item number */
1514 LISTBOX_SetSelection( wnd, descr, descr->selected_item + 1, TRUE, FALSE);
1515 }
1516 }
Yuxi Zhangf94c3c52000-02-26 19:13:12 +00001517
Gerard Patelc9a6d501999-07-25 13:03:17 +00001518 if (descr->focus_item >= descr->nb_items)
1519 {
1520 descr->focus_item = descr->nb_items - 1;
1521 if (descr->focus_item < 0) descr->focus_item = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001522 }
1523 return LB_OKAY;
1524}
1525
1526
1527/***********************************************************************
1528 * LISTBOX_ResetContent
1529 */
1530static void LISTBOX_ResetContent( WND *wnd, LB_DESCR *descr )
1531{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001532 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001533
1534 for (i = 0; i < descr->nb_items; i++) LISTBOX_DeleteItem( wnd, descr, i );
1535 if (descr->items) HeapFree( descr->heap, 0, descr->items );
1536 descr->nb_items = 0;
1537 descr->top_item = 0;
1538 descr->selected_item = -1;
1539 descr->focus_item = 0;
1540 descr->anchor_item = -1;
1541 descr->items = NULL;
1542 LISTBOX_UpdateScroll( wnd, descr );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001543 InvalidateRect( wnd->hwndSelf, NULL, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001544}
1545
1546
1547/***********************************************************************
1548 * LISTBOX_SetCount
1549 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001550static LRESULT LISTBOX_SetCount( WND *wnd, LB_DESCR *descr, INT count )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001551{
1552 LRESULT ret;
1553
1554 if (HAS_STRINGS(descr)) return LB_ERR;
1555 /* FIXME: this is far from optimal... */
1556 if (count > descr->nb_items)
1557 {
1558 while (count > descr->nb_items)
1559 if ((ret = LISTBOX_InsertString( wnd, descr, -1, 0 )) < 0)
1560 return ret;
1561 }
1562 else if (count < descr->nb_items)
1563 {
1564 while (count < descr->nb_items)
1565 if ((ret = LISTBOX_RemoveItem( wnd, descr, -1 )) < 0)
1566 return ret;
1567 }
1568 return LB_OKAY;
1569}
1570
1571
1572/***********************************************************************
1573 * LISTBOX_Directory
1574 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001575static LRESULT LISTBOX_Directory( WND *wnd, LB_DESCR *descr, UINT attrib,
1576 LPCSTR filespec, BOOL long_names )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001577{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001578 HANDLE handle;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001579 LRESULT ret = LB_OKAY;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001580 WIN32_FIND_DATAA entry;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001581 int pos;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001582
Alexandre Julliarda3960291999-02-26 11:11:13 +00001583 if ((handle = FindFirstFileA(filespec,&entry)) == INVALID_HANDLE_VALUE)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001584 {
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001585 if (GetLastError() != ERROR_NO_MORE_FILES) return LB_ERR;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001586 }
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001587 else
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001588 {
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001589 do
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001590 {
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001591 char buffer[270];
1592 if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1593 {
1594 if (!(attrib & DDL_DIRECTORY) ||
1595 !strcmp( entry.cAlternateFileName, "." )) continue;
1596 if (long_names) sprintf( buffer, "[%s]", entry.cFileName );
1597 else sprintf( buffer, "[%s]", entry.cAlternateFileName );
1598 }
1599 else /* not a directory */
1600 {
1601#define ATTRIBS (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
1602 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE)
1603
1604 if ((attrib & DDL_EXCLUSIVE) &&
1605 ((attrib & ATTRIBS) != (entry.dwFileAttributes & ATTRIBS)))
1606 continue;
1607#undef ATTRIBS
1608 if (long_names) strcpy( buffer, entry.cFileName );
1609 else strcpy( buffer, entry.cAlternateFileName );
1610 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001611 if (!long_names) CharLowerA( buffer );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001612 pos = LISTBOX_FindFileStrPos( wnd, descr, buffer );
1613 if ((ret = LISTBOX_InsertString( wnd, descr, pos, buffer )) < 0)
1614 break;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001615 } while (FindNextFileA( handle, &entry ));
1616 FindClose( handle );
Alexandre Julliard2787be81995-05-22 18:23:01 +00001617 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001618
Alexandre Julliard889f7421997-04-15 17:19:52 +00001619 if ((ret >= 0) && (attrib & DDL_DRIVES))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001620 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001621 char buffer[] = "[-a-]";
1622 int drive;
1623 for (drive = 0; drive < MAX_DOS_DRIVES; drive++, buffer[2]++)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001624 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001625 if (!DRIVE_IsValid(drive)) continue;
1626 if ((ret = LISTBOX_InsertString( wnd, descr, -1, buffer )) < 0)
1627 break;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001628 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001629 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001630 return ret;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001631}
1632
1633
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001634/***********************************************************************
1635 * LISTBOX_HandleVScroll
1636 */
1637static LRESULT LISTBOX_HandleVScroll( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001638 WPARAM wParam, LPARAM lParam )
Alexandre Julliard2787be81995-05-22 18:23:01 +00001639{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001640 SCROLLINFO info;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001641
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001642 if (descr->style & LBS_MULTICOLUMN) return 0;
1643 switch(LOWORD(wParam))
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +00001644 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001645 case SB_LINEUP:
1646 LISTBOX_SetTopItem( wnd, descr, descr->top_item - 1, TRUE );
1647 break;
1648 case SB_LINEDOWN:
1649 LISTBOX_SetTopItem( wnd, descr, descr->top_item + 1, TRUE );
1650 break;
1651 case SB_PAGEUP:
1652 LISTBOX_SetTopItem( wnd, descr, descr->top_item -
1653 LISTBOX_GetCurrentPageSize( wnd, descr ), TRUE );
1654 break;
1655 case SB_PAGEDOWN:
1656 LISTBOX_SetTopItem( wnd, descr, descr->top_item +
1657 LISTBOX_GetCurrentPageSize( wnd, descr ), TRUE );
1658 break;
1659 case SB_THUMBPOSITION:
1660 LISTBOX_SetTopItem( wnd, descr, HIWORD(wParam), TRUE );
1661 break;
1662 case SB_THUMBTRACK:
1663 info.cbSize = sizeof(info);
1664 info.fMask = SIF_TRACKPOS;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001665 GetScrollInfo( wnd->hwndSelf, SB_VERT, &info );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001666 LISTBOX_SetTopItem( wnd, descr, info.nTrackPos, TRUE );
1667 break;
1668 case SB_TOP:
1669 LISTBOX_SetTopItem( wnd, descr, 0, TRUE );
1670 break;
1671 case SB_BOTTOM:
1672 LISTBOX_SetTopItem( wnd, descr, descr->nb_items, TRUE );
1673 break;
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +00001674 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001675 return 0;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001676}
1677
Alexandre Julliardb817f4f1996-03-14 18:08:34 +00001678
Alexandre Julliard2787be81995-05-22 18:23:01 +00001679/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001680 * LISTBOX_HandleHScroll
Alexandre Julliard2787be81995-05-22 18:23:01 +00001681 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001682static LRESULT LISTBOX_HandleHScroll( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001683 WPARAM wParam, LPARAM lParam )
Alexandre Julliard2787be81995-05-22 18:23:01 +00001684{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001685 SCROLLINFO info;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001686 INT page;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001687
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001688 if (descr->style & LBS_MULTICOLUMN)
1689 {
1690 switch(LOWORD(wParam))
1691 {
1692 case SB_LINELEFT:
1693 LISTBOX_SetTopItem( wnd, descr, descr->top_item-descr->page_size,
1694 TRUE );
1695 break;
1696 case SB_LINERIGHT:
1697 LISTBOX_SetTopItem( wnd, descr, descr->top_item+descr->page_size,
1698 TRUE );
1699 break;
1700 case SB_PAGELEFT:
1701 page = descr->width / descr->column_width;
1702 if (page < 1) page = 1;
1703 LISTBOX_SetTopItem( wnd, descr,
1704 descr->top_item - page * descr->page_size, TRUE );
1705 break;
1706 case SB_PAGERIGHT:
1707 page = descr->width / descr->column_width;
1708 if (page < 1) page = 1;
1709 LISTBOX_SetTopItem( wnd, descr,
1710 descr->top_item + page * descr->page_size, TRUE );
1711 break;
1712 case SB_THUMBPOSITION:
1713 LISTBOX_SetTopItem( wnd, descr, HIWORD(wParam)*descr->page_size,
1714 TRUE );
1715 break;
1716 case SB_THUMBTRACK:
1717 info.cbSize = sizeof(info);
1718 info.fMask = SIF_TRACKPOS;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001719 GetScrollInfo( wnd->hwndSelf, SB_VERT, &info );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001720 LISTBOX_SetTopItem( wnd, descr, info.nTrackPos*descr->page_size,
1721 TRUE );
1722 break;
1723 case SB_LEFT:
1724 LISTBOX_SetTopItem( wnd, descr, 0, TRUE );
1725 break;
1726 case SB_RIGHT:
1727 LISTBOX_SetTopItem( wnd, descr, descr->nb_items, TRUE );
1728 break;
1729 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001730 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001731 else if (descr->horz_extent)
1732 {
1733 switch(LOWORD(wParam))
1734 {
1735 case SB_LINELEFT:
1736 LISTBOX_SetHorizontalPos( wnd, descr, descr->horz_pos - 1 );
1737 break;
1738 case SB_LINERIGHT:
1739 LISTBOX_SetHorizontalPos( wnd, descr, descr->horz_pos + 1 );
1740 break;
1741 case SB_PAGELEFT:
1742 LISTBOX_SetHorizontalPos( wnd, descr,
1743 descr->horz_pos - descr->width );
1744 break;
1745 case SB_PAGERIGHT:
1746 LISTBOX_SetHorizontalPos( wnd, descr,
1747 descr->horz_pos + descr->width );
1748 break;
1749 case SB_THUMBPOSITION:
1750 LISTBOX_SetHorizontalPos( wnd, descr, HIWORD(wParam) );
1751 break;
1752 case SB_THUMBTRACK:
1753 info.cbSize = sizeof(info);
1754 info.fMask = SIF_TRACKPOS;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001755 GetScrollInfo( wnd->hwndSelf, SB_HORZ, &info );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001756 LISTBOX_SetHorizontalPos( wnd, descr, info.nTrackPos );
1757 break;
1758 case SB_LEFT:
1759 LISTBOX_SetHorizontalPos( wnd, descr, 0 );
1760 break;
1761 case SB_RIGHT:
1762 LISTBOX_SetHorizontalPos( wnd, descr,
1763 descr->horz_extent - descr->width );
1764 break;
1765 }
1766 }
1767 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001768}
1769
Stephane Lussier4bdf4af2000-04-18 11:56:33 +00001770static LRESULT LISTBOX_HandleMouseWheel(WND *wnd, LB_DESCR *descr,WPARAM wParam, LPARAM lParam )
1771{
1772 short gcWheelDelta = 0;
1773 UINT pulScrollLines = 3;
1774
1775 SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
1776
1777 gcWheelDelta -= (short) HIWORD(wParam);
1778
1779 if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
1780 {
1781 int cLineScroll = (int) min((UINT) descr->page_size, pulScrollLines);
1782 cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
1783 LISTBOX_SetTopItem( wnd, descr, descr->top_item + cLineScroll, TRUE );
1784 }
1785 return 0;
1786}
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001787
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001788/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001789 * LISTBOX_HandleLButtonDown
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001790 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001791static LRESULT LISTBOX_HandleLButtonDown( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001792 WPARAM wParam, INT x, INT y )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001793{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001794 INT index = LISTBOX_GetItemFromPoint( wnd, descr, x, y );
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001795 TRACE("[%04x]: lbuttondown %d,%d item %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001796 wnd->hwndSelf, x, y, index );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001797 if (!descr->caret_on && (GetFocus() == wnd->hwndSelf)) return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001798 if (index != -1)
1799 {
1800 if (descr->style & LBS_EXTENDEDSEL)
1801 {
1802 if (!(wParam & MK_SHIFT)) descr->anchor_item = index;
1803 if (wParam & MK_CONTROL)
1804 {
1805 LISTBOX_SetCaretIndex( wnd, descr, index, FALSE );
1806 LISTBOX_SetSelection( wnd, descr, index,
Dmitry Timoshkove0f493e1999-11-28 19:44:33 +00001807 !descr->items[index].selected,
1808 (descr->style & LBS_NOTIFY) != 0);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001809 }
1810 else LISTBOX_MoveCaret( wnd, descr, index, FALSE );
1811 }
1812 else
1813 {
1814 LISTBOX_MoveCaret( wnd, descr, index, FALSE );
1815 LISTBOX_SetSelection( wnd, descr, index,
Dmitry Timoshkove0f493e1999-11-28 19:44:33 +00001816 (!(descr->style & LBS_MULTIPLESEL) ||
1817 !descr->items[index].selected),
1818 (descr->style & LBS_NOTIFY) != 0 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001819 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001820 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001821
Alexandre Julliarda3960291999-02-26 11:11:13 +00001822 if( !descr->lphc ) SetFocus( wnd->hwndSelf );
1823 else SetFocus( (descr->lphc->hWndEdit) ? descr->lphc->hWndEdit
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001824 : descr->lphc->self->hwndSelf ) ;
1825
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00001826 descr->captured = TRUE;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001827 SetCapture( wnd->hwndSelf );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001828 if (index != -1 && !descr->lphc)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001829 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001830 if (descr->style & LBS_NOTIFY )
Alexandre Julliarda3960291999-02-26 11:11:13 +00001831 SendMessageA( descr->owner, WM_LBTRACKPOINT, index,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001832 MAKELPARAM( x, y ) );
1833 if (wnd->dwExStyle & WS_EX_DRAGDETECT)
1834 {
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00001835 POINT pt;
1836
1837 pt.x = x;
1838 pt.y = y;
1839
Alexandre Julliarda3960291999-02-26 11:11:13 +00001840 if (DragDetect( wnd->hwndSelf, pt ))
1841 SendMessageA( descr->owner, WM_BEGINDRAG, 0, 0 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001842 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001843 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001844 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001845}
1846
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001847
Pierre Mageau25c62cc1999-09-11 16:26:03 +00001848/*************************************************************************
1849 * LISTBOX_HandleLButtonDownCombo [Internal]
1850 *
1851 * Process LButtonDown message for the ComboListBox
1852 *
1853 * PARAMS
1854 * pWnd [I] The windows internal structure
1855 * pDescr [I] The ListBox internal structure
1856 * wParam [I] Key Flag (WM_LBUTTONDOWN doc for more info)
1857 * x [I] X Mouse Coordinate
1858 * y [I] Y Mouse Coordinate
1859 *
1860 * RETURNS
1861 * 0 since we are processing the WM_LBUTTONDOWN Message
1862 *
1863 * NOTES
1864 * This function is only to be used when a ListBox is a ComboListBox
1865 */
1866
1867static LRESULT LISTBOX_HandleLButtonDownCombo( WND *pWnd, LB_DESCR *pDescr,
1868 WPARAM wParam, INT x, INT y)
1869{
1870 RECT clientRect, screenRect;
1871 POINT mousePos;
1872
1873 mousePos.x = x;
1874 mousePos.y = y;
1875
1876 GetClientRect(pWnd->hwndSelf, &clientRect);
1877
1878 if(PtInRect(&clientRect, mousePos))
1879 {
1880 /* MousePos is in client, resume normal processing */
1881 return LISTBOX_HandleLButtonDown( pWnd, pDescr, wParam, x, y);
1882 }
1883 else
1884 {
1885 POINT screenMousePos;
1886 HWND hWndOldCapture;
1887
1888 /* Check the Non-Client Area */
1889 screenMousePos = mousePos;
1890 hWndOldCapture = GetCapture();
1891 ReleaseCapture();
1892 GetWindowRect(pWnd->hwndSelf, &screenRect);
1893 ClientToScreen(pWnd->hwndSelf, &screenMousePos);
1894
1895 if(!PtInRect(&screenRect, screenMousePos))
1896 {
1897 /* Close The Drop Down */
1898 SEND_NOTIFICATION( pWnd, pDescr, LBN_SELCANCEL );
1899 return 0;
1900 }
1901 else
1902 {
1903 /* Check to see the NC is a scrollbar */
1904 INT nHitTestType=0;
1905 /* Check Vertical scroll bar */
1906 if (pWnd->dwStyle & WS_VSCROLL)
1907 {
1908 clientRect.right += GetSystemMetrics(SM_CXVSCROLL);
1909 if (PtInRect( &clientRect, mousePos ))
1910 {
1911 nHitTestType = HTVSCROLL;
1912 }
1913 }
1914 /* Check horizontal scroll bar */
1915 if (pWnd->dwStyle & WS_HSCROLL)
1916 {
1917 clientRect.bottom += GetSystemMetrics(SM_CYHSCROLL);
1918 if (PtInRect( &clientRect, mousePos ))
1919 {
1920 nHitTestType = HTHSCROLL;
1921 }
1922 }
1923 /* Windows sends this message when a scrollbar is clicked
1924 */
1925
1926 if(nHitTestType != 0)
1927 {
1928 SendMessageA(pWnd->hwndSelf, WM_NCLBUTTONDOWN, nHitTestType,
1929 MAKELONG(screenMousePos.x, screenMousePos.y));
1930 }
1931 /* Resume the Capture after scrolling is complete
1932 */
1933 if(hWndOldCapture != 0)
1934 {
1935 SetCapture(hWndOldCapture);
1936 }
1937 }
1938 }
1939 return 0;
1940}
1941
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001942/***********************************************************************
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00001943 * LISTBOX_HandleLButtonUp
1944 */
1945static LRESULT LISTBOX_HandleLButtonUp( WND *wnd, LB_DESCR *descr )
1946{
1947 if (LISTBOX_Timer != LB_TIMER_NONE)
Alexandre Julliarda3960291999-02-26 11:11:13 +00001948 KillSystemTimer( wnd->hwndSelf, LB_TIMER_ID );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00001949 LISTBOX_Timer = LB_TIMER_NONE;
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00001950 if (descr->captured)
Alexandre Julliard33072e11997-06-29 18:08:02 +00001951 {
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00001952 descr->captured = FALSE;
1953 if (GetCapture() == wnd->hwndSelf) ReleaseCapture();
Gerard Patelc9a6d501999-07-25 13:03:17 +00001954 if ((descr->style & LBS_NOTIFY) && descr->nb_items)
Alexandre Julliard33072e11997-06-29 18:08:02 +00001955 SEND_NOTIFICATION( wnd, descr, LBN_SELCHANGE );
1956 }
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00001957 return 0;
1958}
1959
1960
1961/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001962 * LISTBOX_HandleTimer
Alexandre Julliardade697e1995-11-26 13:59:11 +00001963 *
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001964 * Handle scrolling upon a timer event.
1965 * Return TRUE if scrolling should continue.
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001966 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001967static LRESULT LISTBOX_HandleTimer( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001968 INT index, TIMER_DIRECTION dir )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001969{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001970 switch(dir)
Alexandre Julliardade697e1995-11-26 13:59:11 +00001971 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001972 case LB_TIMER_UP:
1973 if (descr->top_item) index = descr->top_item - 1;
1974 else index = 0;
1975 break;
1976 case LB_TIMER_LEFT:
1977 if (descr->top_item) index -= descr->page_size;
1978 break;
1979 case LB_TIMER_DOWN:
1980 index = descr->top_item + LISTBOX_GetCurrentPageSize( wnd, descr );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001981 if (index == descr->focus_item) index++;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001982 if (index >= descr->nb_items) index = descr->nb_items - 1;
1983 break;
1984 case LB_TIMER_RIGHT:
1985 if (index + descr->page_size < descr->nb_items)
1986 index += descr->page_size;
1987 break;
1988 case LB_TIMER_NONE:
1989 break;
Alexandre Julliardade697e1995-11-26 13:59:11 +00001990 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001991 if (index == descr->focus_item) return FALSE;
1992 LISTBOX_MoveCaret( wnd, descr, index, FALSE );
1993 return TRUE;
1994}
Alexandre Julliardade697e1995-11-26 13:59:11 +00001995
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001996
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001997/***********************************************************************
1998 * LISTBOX_HandleSystemTimer
1999 *
2000 * WM_SYSTIMER handler.
2001 */
2002static LRESULT LISTBOX_HandleSystemTimer( WND *wnd, LB_DESCR *descr )
2003{
2004 if (!LISTBOX_HandleTimer( wnd, descr, descr->focus_item, LISTBOX_Timer ))
Alexandre Julliardade697e1995-11-26 13:59:11 +00002005 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002006 KillSystemTimer( wnd->hwndSelf, LB_TIMER_ID );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002007 LISTBOX_Timer = LB_TIMER_NONE;
Alexandre Julliardade697e1995-11-26 13:59:11 +00002008 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00002009 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002010}
2011
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002012
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002013/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002014 * LISTBOX_HandleMouseMove
2015 *
2016 * WM_MOUSEMOVE handler.
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002017 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002018static void LISTBOX_HandleMouseMove( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002019 INT x, INT y )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002020{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002021 INT index;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002022 TIMER_DIRECTION dir;
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00002023
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002024 if (!descr->captured) return;
2025
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002026 if (descr->style & LBS_MULTICOLUMN)
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00002027 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002028 if (y < 0) y = 0;
2029 else if (y >= descr->item_height * descr->page_size)
2030 y = descr->item_height * descr->page_size - 1;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002031
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002032 if (x < 0)
2033 {
2034 dir = LB_TIMER_LEFT;
2035 x = 0;
2036 }
2037 else if (x >= descr->width)
2038 {
2039 dir = LB_TIMER_RIGHT;
2040 x = descr->width - 1;
2041 }
2042 else dir = LB_TIMER_NONE; /* inside */
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00002043 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002044 else
2045 {
2046 if (y < 0) dir = LB_TIMER_UP; /* above */
2047 else if (y >= descr->height) dir = LB_TIMER_DOWN; /* below */
2048 else dir = LB_TIMER_NONE; /* inside */
2049 }
2050
2051 index = LISTBOX_GetItemFromPoint( wnd, descr, x, y );
2052 if (index == -1) index = descr->focus_item;
2053 if (!LISTBOX_HandleTimer( wnd, descr, index, dir )) dir = LB_TIMER_NONE;
2054
2055 /* Start/stop the system timer */
2056
2057 if (dir != LB_TIMER_NONE)
Alexandre Julliarda3960291999-02-26 11:11:13 +00002058 SetSystemTimer( wnd->hwndSelf, LB_TIMER_ID, LB_SCROLL_TIMEOUT, NULL);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002059 else if (LISTBOX_Timer != LB_TIMER_NONE)
Alexandre Julliarda3960291999-02-26 11:11:13 +00002060 KillSystemTimer( wnd->hwndSelf, LB_TIMER_ID );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002061 LISTBOX_Timer = dir;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002062}
2063
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002064
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002065/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002066 * LISTBOX_HandleKeyDown
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002067 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002068static LRESULT LISTBOX_HandleKeyDown( WND *wnd, LB_DESCR *descr, WPARAM wParam )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002069{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002070 INT caret = -1;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002071 BOOL bForceSelection = TRUE; /* select item pointed to by focus_item */
2072 if ((IS_MULTISELECT(descr)) || (descr->selected_item == descr->focus_item))
2073 bForceSelection = FALSE; /* only for single select list */
2074
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002075 if (descr->style & LBS_WANTKEYBOARDINPUT)
2076 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002077 caret = SendMessageA( descr->owner, WM_VKEYTOITEM,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002078 MAKEWPARAM(LOWORD(wParam), descr->focus_item),
2079 wnd->hwndSelf );
2080 if (caret == -2) return 0;
2081 }
2082 if (caret == -1) switch(wParam)
2083 {
2084 case VK_LEFT:
2085 if (descr->style & LBS_MULTICOLUMN)
2086 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00002087 bForceSelection = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002088 if (descr->focus_item >= descr->page_size)
2089 caret = descr->focus_item - descr->page_size;
2090 break;
2091 }
2092 /* fall through */
2093 case VK_UP:
2094 caret = descr->focus_item - 1;
2095 if (caret < 0) caret = 0;
2096 break;
2097 case VK_RIGHT:
2098 if (descr->style & LBS_MULTICOLUMN)
2099 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00002100 bForceSelection = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002101 if (descr->focus_item + descr->page_size < descr->nb_items)
2102 caret = descr->focus_item + descr->page_size;
2103 break;
2104 }
2105 /* fall through */
2106 case VK_DOWN:
2107 caret = descr->focus_item + 1;
2108 if (caret >= descr->nb_items) caret = descr->nb_items - 1;
2109 break;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002110
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002111 case VK_PRIOR:
2112 if (descr->style & LBS_MULTICOLUMN)
2113 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002114 INT page = descr->width / descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002115 if (page < 1) page = 1;
2116 caret = descr->focus_item - (page * descr->page_size) + 1;
2117 }
2118 else caret = descr->focus_item-LISTBOX_GetCurrentPageSize(wnd,descr)+1;
2119 if (caret < 0) caret = 0;
2120 break;
2121 case VK_NEXT:
2122 if (descr->style & LBS_MULTICOLUMN)
2123 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002124 INT page = descr->width / descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002125 if (page < 1) page = 1;
2126 caret = descr->focus_item + (page * descr->page_size) - 1;
2127 }
2128 else caret = descr->focus_item+LISTBOX_GetCurrentPageSize(wnd,descr)-1;
2129 if (caret >= descr->nb_items) caret = descr->nb_items - 1;
2130 break;
2131 case VK_HOME:
2132 caret = 0;
2133 break;
2134 case VK_END:
2135 caret = descr->nb_items - 1;
2136 break;
2137 case VK_SPACE:
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002138 if (descr->style & LBS_EXTENDEDSEL) caret = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002139 else if (descr->style & LBS_MULTIPLESEL)
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002140 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002141 LISTBOX_SetSelection( wnd, descr, descr->focus_item,
2142 !descr->items[descr->focus_item].selected,
2143 (descr->style & LBS_NOTIFY) != 0 );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002144 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002145 break;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002146 default:
2147 bForceSelection = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002148 }
Gerard Patelc9a6d501999-07-25 13:03:17 +00002149 if (bForceSelection) /* focused item is used instead of key */
2150 caret = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002151 if (caret >= 0)
2152 {
2153 if ((descr->style & LBS_EXTENDEDSEL) &&
Alexandre Julliarda3960291999-02-26 11:11:13 +00002154 !(GetKeyState( VK_SHIFT ) & 0x8000))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002155 descr->anchor_item = caret;
2156 LISTBOX_MoveCaret( wnd, descr, caret, TRUE );
Gerard Patelc9a6d501999-07-25 13:03:17 +00002157 LISTBOX_SetSelection( wnd, descr, caret, TRUE, FALSE);
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002158 if (descr->style & LBS_NOTIFY)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002159 {
2160 if( descr->lphc && CB_GETTYPE(descr->lphc) != CBS_SIMPLE )
2161 {
2162 /* make sure that combo parent doesn't hide us */
2163 descr->lphc->wState |= CBF_NOROLLUP;
2164 }
Gerard Patelc9a6d501999-07-25 13:03:17 +00002165 if (descr->nb_items) SEND_NOTIFICATION( wnd, descr, LBN_SELCHANGE );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002166 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002167 }
2168 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002169}
2170
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002171
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002172/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002173 * LISTBOX_HandleChar
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002174 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002175static LRESULT LISTBOX_HandleChar( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002176 WPARAM wParam )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002177{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002178 INT caret = -1;
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002179 char str[2];
2180
2181 str[0] = wParam & 0xff;
2182 str[1] = '\0';
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002183
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002184 if (descr->style & LBS_WANTKEYBOARDINPUT)
2185 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002186 caret = SendMessageA( descr->owner, WM_CHARTOITEM,
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002187 MAKEWPARAM(LOWORD(wParam), descr->focus_item),
2188 wnd->hwndSelf );
2189 if (caret == -2) return 0;
2190 }
2191 if (caret == -1)
2192 caret = LISTBOX_FindString( wnd, descr, descr->focus_item, str, FALSE);
2193 if (caret != -1)
2194 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00002195 if ((!IS_MULTISELECT(descr)) && descr->selected_item == -1)
2196 LISTBOX_SetSelection( wnd, descr, caret, TRUE, FALSE);
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002197 LISTBOX_MoveCaret( wnd, descr, caret, TRUE );
Gerard Patelc9a6d501999-07-25 13:03:17 +00002198 if ((descr->style & LBS_NOTIFY) && descr->nb_items)
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002199 SEND_NOTIFICATION( wnd, descr, LBN_SELCHANGE );
2200 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002201 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002202}
2203
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002204
2205/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002206 * LISTBOX_Create
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002207 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002208static BOOL LISTBOX_Create( WND *wnd, LPHEADCOMBO lphc )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002209{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002210 LB_DESCR *descr;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002211 MEASUREITEMSTRUCT mis;
2212 RECT rect;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002213
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002214 if (!(descr = HeapAlloc( GetProcessHeap(), 0, sizeof(*descr) )))
2215 return FALSE;
2216 if (!(descr->heap = HeapCreate( 0, 0x10000, 0 )))
2217 {
2218 HeapFree( GetProcessHeap(), 0, descr );
2219 return FALSE;
2220 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00002221 GetClientRect( wnd->hwndSelf, &rect );
2222 descr->owner = GetParent( wnd->hwndSelf );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002223 descr->style = wnd->dwStyle;
2224 descr->width = rect.right - rect.left;
2225 descr->height = rect.bottom - rect.top;
2226 descr->items = NULL;
2227 descr->nb_items = 0;
2228 descr->top_item = 0;
2229 descr->selected_item = -1;
2230 descr->focus_item = 0;
2231 descr->anchor_item = -1;
2232 descr->item_height = 1;
2233 descr->page_size = 1;
2234 descr->column_width = 150;
2235 descr->horz_extent = (wnd->dwStyle & WS_HSCROLL) ? 1 : 0;
2236 descr->horz_pos = 0;
2237 descr->nb_tabs = 0;
2238 descr->tabs = NULL;
2239 descr->caret_on = TRUE;
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002240 descr->captured = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002241 descr->font = 0;
2242 descr->locale = 0; /* FIXME */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002243 descr->lphc = lphc;
2244
Nick Hollowayb9ce4fd1999-09-11 16:29:00 +00002245 if( ( GetExpWinVer16( wnd->hInstance ) & 0xFF00 ) == 0x0300
2246 && ( descr->style & ( WS_VSCROLL | WS_HSCROLL ) ) )
2247 {
2248 /* Win95 document "List Box Differences" from MSDN:
2249 If a list box in a version 3.x application has either the
2250 WS_HSCROLL or WS_VSCROLL style, the list box receives both
2251 horizontal and vertical scroll bars.
2252 */
2253 descr->style |= WS_VSCROLL | WS_HSCROLL;
2254 }
2255
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002256 if( lphc )
2257 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +00002258 TRACE_(combo)("[%04x]: resetting owner %04x -> %04x\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002259 wnd->hwndSelf, descr->owner, lphc->self->hwndSelf );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002260 descr->owner = lphc->self->hwndSelf;
2261 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00002262
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002263 *(LB_DESCR **)wnd->wExtra = descr;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002264
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002265/* if (wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) descr->style &= ~LBS_NOTIFY;
2266 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002267 if (descr->style & LBS_EXTENDEDSEL) descr->style |= LBS_MULTIPLESEL;
2268 if (descr->style & LBS_MULTICOLUMN) descr->style &= ~LBS_OWNERDRAWVARIABLE;
2269 if (descr->style & LBS_OWNERDRAWVARIABLE) descr->style |= LBS_NOINTEGRALHEIGHT;
2270 descr->item_height = LISTBOX_SetFont( wnd, descr, 0 );
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002271
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002272 if (descr->style & LBS_OWNERDRAWFIXED)
2273 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002274 if( descr->lphc && (descr->lphc->dwStyle & CBS_DROPDOWN))
2275 {
2276 /* WinWord gets VERY unhappy if we send WM_MEASUREITEM from here */
Francis Beaudetf585c611999-04-02 10:37:42 +00002277 descr->item_height = lphc->fixedOwnerDrawHeight;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002278 }
2279 else
2280 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002281 UINT id = (descr->lphc ) ? ID_CB_LISTBOX : wnd->wIDmenu;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002282
2283 mis.CtlType = ODT_LISTBOX;
2284 mis.CtlID = id;
2285 mis.itemID = -1;
2286 mis.itemWidth = 0;
2287 mis.itemData = 0;
2288 mis.itemHeight = descr->item_height;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002289 SendMessageA( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002290 descr->item_height = mis.itemHeight ? mis.itemHeight : 1;
2291 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002292 }
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002293
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002294 return TRUE;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002295}
2296
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002297
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002298/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002299 * LISTBOX_Destroy
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002300 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002301static BOOL LISTBOX_Destroy( WND *wnd, LB_DESCR *descr )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002302{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002303 LISTBOX_ResetContent( wnd, descr );
2304 HeapDestroy( descr->heap );
2305 HeapFree( GetProcessHeap(), 0, descr );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002306 wnd->wExtra[0] = 0;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00002307 return TRUE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002308}
2309
2310
2311/***********************************************************************
2312 * ListBoxWndProc
2313 */
Marcus Meissner9aded511999-05-01 10:23:45 +00002314static inline LRESULT WINAPI ListBoxWndProc_locked( WND* wnd, UINT msg,
2315 WPARAM wParam, LPARAM lParam )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002316{
2317 LRESULT ret;
2318 LB_DESCR *descr;
Marcus Meissner9aded511999-05-01 10:23:45 +00002319 HWND hwnd = wnd->hwndSelf;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002320
2321 if (!wnd) return 0;
2322 if (!(descr = *(LB_DESCR **)wnd->wExtra))
2323 {
Francis Beaudetf6a225b1999-07-30 17:58:24 +00002324 switch (msg)
2325 {
2326 case WM_CREATE:
2327 {
2328 if (!LISTBOX_Create( wnd, NULL ))
2329 return -1;
2330 TRACE("creating wnd=%04x descr=%p\n",
2331 hwnd, *(LB_DESCR **)wnd->wExtra );
2332 return 0;
2333 }
2334 case WM_NCCREATE:
2335 {
2336 /*
2337 * When a listbox is not in a combobox and the look
2338 * is win95, the WS_BORDER style is replaced with
2339 * the WS_EX_CLIENTEDGE style.
2340 */
2341 if ( (TWEAK_WineLook > WIN31_LOOK) &&
2342 (wnd->dwStyle & WS_BORDER) )
2343 {
2344 wnd->dwExStyle |= WS_EX_CLIENTEDGE;
2345 wnd->dwStyle &= ~ WS_BORDER;
2346 }
2347 }
2348 }
2349
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002350 /* Ignore all other messages before we get a WM_CREATE */
Marcus Meissner9aded511999-05-01 10:23:45 +00002351 return DefWindowProcA( hwnd, msg, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002352 }
2353
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002354 TRACE("[%04x]: msg %s wp %08x lp %08lx\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002355 wnd->hwndSelf, SPY_GetMsgName(msg), wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002356 switch(msg)
2357 {
2358 case LB_RESETCONTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002359 case LB_RESETCONTENT:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002360 LISTBOX_ResetContent( wnd, descr );
Marcus Meissner9aded511999-05-01 10:23:45 +00002361 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002362
2363 case LB_ADDSTRING16:
2364 if (HAS_STRINGS(descr)) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
2365 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002366 case LB_ADDSTRING:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002367 wParam = LISTBOX_FindStringPos( wnd, descr, (LPCSTR)lParam, FALSE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002368 return LISTBOX_InsertString( wnd, descr, wParam, (LPCSTR)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002369
2370 case LB_INSERTSTRING16:
2371 if (HAS_STRINGS(descr)) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002372 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002373 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002374 case LB_INSERTSTRING:
Marcus Meissner9aded511999-05-01 10:23:45 +00002375 return LISTBOX_InsertString( wnd, descr, wParam, (LPCSTR)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002376
2377 case LB_ADDFILE16:
2378 if (HAS_STRINGS(descr)) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
2379 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002380 case LB_ADDFILE:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002381 wParam = LISTBOX_FindFileStrPos( wnd, descr, (LPCSTR)lParam );
Marcus Meissner9aded511999-05-01 10:23:45 +00002382 return LISTBOX_InsertString( wnd, descr, wParam, (LPCSTR)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002383
2384 case LB_DELETESTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002385 case LB_DELETESTRING:
Gerard Patelc9a6d501999-07-25 13:03:17 +00002386 if (LISTBOX_RemoveItem( wnd, descr, wParam) != LB_ERR)
2387 return descr->nb_items;
2388 else
2389 return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002390
2391 case LB_GETITEMDATA16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002392 case LB_GETITEMDATA:
2393 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002394 return LB_ERR;
2395 return descr->items[wParam].data;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002396
2397 case LB_SETITEMDATA16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002398 case LB_SETITEMDATA:
2399 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002400 return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002401 descr->items[wParam].data = (DWORD)lParam;
Marcus Meissner9aded511999-05-01 10:23:45 +00002402 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002403
2404 case LB_GETCOUNT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002405 case LB_GETCOUNT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002406 return descr->nb_items;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002407
2408 case LB_GETTEXT16:
2409 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
2410 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002411 case LB_GETTEXT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002412 return LISTBOX_GetText( wnd, descr, wParam, (LPSTR)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002413
2414 case LB_GETTEXTLEN16:
2415 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002416 case LB_GETTEXTLEN:
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002417 if (wParam >= descr->nb_items)
Marcus Meissner9aded511999-05-01 10:23:45 +00002418 return LB_ERR;
2419 return (HAS_STRINGS(descr) ? strlen(descr->items[wParam].str)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002420 : sizeof(DWORD));
2421
2422 case LB_GETCURSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002423 case LB_GETCURSEL:
Francis Beaudet8730e451999-03-25 13:22:02 +00002424 if (descr->nb_items==0)
Marcus Meissner9aded511999-05-01 10:23:45 +00002425 return LB_ERR;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002426 if (!IS_MULTISELECT(descr))
2427 return descr->selected_item;
Marcus Meissner9aded511999-05-01 10:23:45 +00002428 /* else */
2429 if (descr->selected_item!=-1)
2430 return descr->selected_item;
2431 /* else */
2432 return descr->focus_item;
Lawson Whitney613092a1999-03-22 14:46:43 +00002433 /* otherwise, if the user tries to move the selection with the */
2434 /* arrow keys, we will give the application something to choke on */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002435 case LB_GETTOPINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002436 case LB_GETTOPINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002437 return descr->top_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002438
2439 case LB_GETITEMHEIGHT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002440 case LB_GETITEMHEIGHT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002441 return LISTBOX_GetItemHeight( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002442
2443 case LB_SETITEMHEIGHT16:
2444 lParam = LOWORD(lParam);
2445 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002446 case LB_SETITEMHEIGHT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002447 return LISTBOX_SetItemHeight( wnd, descr, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002448
Alexandre Julliarda3960291999-02-26 11:11:13 +00002449 case LB_ITEMFROMPOINT:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002450 {
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002451 POINT pt;
2452 RECT rect;
2453
2454 pt.x = LOWORD(lParam);
2455 pt.y = HIWORD(lParam);
2456 rect.left = 0;
2457 rect.top = 0;
2458 rect.right = descr->width;
2459 rect.bottom = descr->height;
2460
Marcus Meissner9aded511999-05-01 10:23:45 +00002461 return MAKELONG( LISTBOX_GetItemFromPoint(wnd, descr, pt.x, pt.y),
Gerard Patel777508a1999-05-08 12:35:17 +00002462 !PtInRect( &rect, pt ) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002463 }
2464
2465 case LB_SETCARETINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002466 case LB_SETCARETINDEX:
Gerard Patelc9a6d501999-07-25 13:03:17 +00002467 if ((!IS_MULTISELECT(descr)) && (descr->selected_item != -1)) return LB_ERR;
2468 if (LISTBOX_SetCaretIndex( wnd, descr, wParam, !lParam ) == LB_ERR)
2469 return LB_ERR;
2470 else if (ISWIN31)
2471 return wParam;
2472 else
2473 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002474
2475 case LB_GETCARETINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002476 case LB_GETCARETINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002477 return descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002478
2479 case LB_SETTOPINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002480 case LB_SETTOPINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002481 return LISTBOX_SetTopItem( wnd, descr, wParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002482
2483 case LB_SETCOLUMNWIDTH16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002484 case LB_SETCOLUMNWIDTH:
Marcus Meissner9aded511999-05-01 10:23:45 +00002485 return LISTBOX_SetColumnWidth( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002486
2487 case LB_GETITEMRECT16:
2488 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002489 RECT rect;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002490 ret = LISTBOX_GetItemRect( wnd, descr, (INT16)wParam, &rect );
2491 CONV_RECT32TO16( &rect, (RECT16 *)PTR_SEG_TO_LIN(lParam) );
2492 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002493 return ret;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002494
Alexandre Julliarda3960291999-02-26 11:11:13 +00002495 case LB_GETITEMRECT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002496 return LISTBOX_GetItemRect( wnd, descr, wParam, (RECT *)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002497
2498 case LB_FINDSTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002499 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002500 if (HAS_STRINGS(descr)) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
2501 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002502 case LB_FINDSTRING:
Marcus Meissner9aded511999-05-01 10:23:45 +00002503 return LISTBOX_FindString( wnd, descr, wParam, (LPCSTR)lParam, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002504
2505 case LB_FINDSTRINGEXACT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002506 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002507 if (HAS_STRINGS(descr)) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
2508 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002509 case LB_FINDSTRINGEXACT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002510 return LISTBOX_FindString( wnd, descr, wParam, (LPCSTR)lParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002511
2512 case LB_SELECTSTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002513 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002514 if (HAS_STRINGS(descr)) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
2515 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002516 case LB_SELECTSTRING:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002517 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002518 INT index = LISTBOX_FindString( wnd, descr, wParam,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002519 (LPCSTR)lParam, FALSE );
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002520 if (index == LB_ERR)
Marcus Meissner9aded511999-05-01 10:23:45 +00002521 return LB_ERR;
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002522 LISTBOX_SetSelection( wnd, descr, index, TRUE, FALSE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002523 return index;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002524 }
2525
2526 case LB_GETSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002527 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002528 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002529 case LB_GETSEL:
2530 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002531 return LB_ERR;
2532 return descr->items[wParam].selected;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002533
2534 case LB_SETSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002535 lParam = (INT)(INT16)lParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002536 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002537 case LB_SETSEL:
Marcus Meissner9aded511999-05-01 10:23:45 +00002538 return LISTBOX_SetSelection( wnd, descr, lParam, wParam, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002539
2540 case LB_SETCURSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002541 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002542 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002543 case LB_SETCURSEL:
Gerard Patelc9a6d501999-07-25 13:03:17 +00002544 if (IS_MULTISELECT(descr)) return LB_ERR;
Alexandre Julliard638f1691999-01-17 16:32:32 +00002545 LISTBOX_SetCaretIndex( wnd, descr, wParam, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002546 return LISTBOX_SetSelection( wnd, descr, wParam, TRUE, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002547
2548 case LB_GETSELCOUNT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002549 case LB_GETSELCOUNT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002550 return LISTBOX_GetSelCount( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002551
2552 case LB_GETSELITEMS16:
Marcus Meissner9aded511999-05-01 10:23:45 +00002553 return LISTBOX_GetSelItems16( wnd, descr, wParam,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002554 (LPINT16)PTR_SEG_TO_LIN(lParam) );
2555
Alexandre Julliarda3960291999-02-26 11:11:13 +00002556 case LB_GETSELITEMS:
Marcus Meissner9aded511999-05-01 10:23:45 +00002557 return LISTBOX_GetSelItems( wnd, descr, wParam, (LPINT)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002558
2559 case LB_SELITEMRANGE16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002560 case LB_SELITEMRANGE:
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002561 if (LOWORD(lParam) <= HIWORD(lParam))
Marcus Meissner9aded511999-05-01 10:23:45 +00002562 return LISTBOX_SelectItemRange( wnd, descr, LOWORD(lParam),
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002563 HIWORD(lParam), wParam );
2564 else
Marcus Meissner9aded511999-05-01 10:23:45 +00002565 return LISTBOX_SelectItemRange( wnd, descr, HIWORD(lParam),
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002566 LOWORD(lParam), wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002567
2568 case LB_SELITEMRANGEEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002569 case LB_SELITEMRANGEEX:
2570 if ((INT)lParam >= (INT)wParam)
Marcus Meissner9aded511999-05-01 10:23:45 +00002571 return LISTBOX_SelectItemRange( wnd, descr, wParam, lParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002572 else
Marcus Meissner9aded511999-05-01 10:23:45 +00002573 return LISTBOX_SelectItemRange( wnd, descr, lParam, wParam, FALSE);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002574
2575 case LB_GETHORIZONTALEXTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002576 case LB_GETHORIZONTALEXTENT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002577 return descr->horz_extent;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002578
2579 case LB_SETHORIZONTALEXTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002580 case LB_SETHORIZONTALEXTENT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002581 return LISTBOX_SetHorizontalExtent( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002582
2583 case LB_GETANCHORINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002584 case LB_GETANCHORINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002585 return descr->anchor_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002586
2587 case LB_SETANCHORINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002588 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002589 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002590 case LB_SETANCHORINDEX:
2591 if (((INT)wParam < -1) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002592 return LB_ERR;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002593 descr->anchor_item = (INT)wParam;
Marcus Meissner9aded511999-05-01 10:23:45 +00002594 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002595
2596 case LB_DIR16:
Marcus Meissner9aded511999-05-01 10:23:45 +00002597 return LISTBOX_Directory( wnd, descr, wParam,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002598 (LPCSTR)PTR_SEG_TO_LIN(lParam), FALSE );
2599
Alexandre Julliarda3960291999-02-26 11:11:13 +00002600 case LB_DIR:
Marcus Meissner9aded511999-05-01 10:23:45 +00002601 return LISTBOX_Directory( wnd, descr, wParam, (LPCSTR)lParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002602
Alexandre Julliarda3960291999-02-26 11:11:13 +00002603 case LB_GETLOCALE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002604 return descr->locale;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002605
Alexandre Julliarda3960291999-02-26 11:11:13 +00002606 case LB_SETLOCALE:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002607 descr->locale = (LCID)wParam; /* FIXME: should check for valid lcid */
Marcus Meissner9aded511999-05-01 10:23:45 +00002608 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002609
Alexandre Julliarda3960291999-02-26 11:11:13 +00002610 case LB_INITSTORAGE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002611 return LISTBOX_InitStorage( wnd, descr, wParam, (DWORD)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002612
Alexandre Julliarda3960291999-02-26 11:11:13 +00002613 case LB_SETCOUNT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002614 return LISTBOX_SetCount( wnd, descr, (INT)wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002615
2616 case LB_SETTABSTOPS16:
Marcus Meissner9aded511999-05-01 10:23:45 +00002617 return LISTBOX_SetTabStops( wnd, descr, (INT)(INT16)wParam,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002618 (LPINT)PTR_SEG_TO_LIN(lParam), TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002619
Alexandre Julliarda3960291999-02-26 11:11:13 +00002620 case LB_SETTABSTOPS:
Marcus Meissner9aded511999-05-01 10:23:45 +00002621 return LISTBOX_SetTabStops( wnd, descr, wParam, (LPINT)lParam, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002622
2623 case LB_CARETON16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002624 case LB_CARETON:
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002625 if (descr->caret_on)
Marcus Meissner9aded511999-05-01 10:23:45 +00002626 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002627 descr->caret_on = TRUE;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002628 if ((descr->focus_item != -1) && (GetFocus() == wnd->hwndSelf))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002629 LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002630 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002631
2632 case LB_CARETOFF16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002633 case LB_CARETOFF:
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002634 if (!descr->caret_on)
Marcus Meissner9aded511999-05-01 10:23:45 +00002635 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002636 descr->caret_on = FALSE;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002637 if ((descr->focus_item != -1) && (GetFocus() == wnd->hwndSelf))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002638 LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002639 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002640
2641 case WM_DESTROY:
Marcus Meissner9aded511999-05-01 10:23:45 +00002642 return LISTBOX_Destroy( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002643
2644 case WM_ENABLE:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002645 InvalidateRect( hwnd, NULL, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002646 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002647
2648 case WM_SETREDRAW:
2649 LISTBOX_SetRedraw( wnd, descr, wParam != 0 );
Marcus Meissner9aded511999-05-01 10:23:45 +00002650 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002651
2652 case WM_GETDLGCODE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002653 return DLGC_WANTARROWS | DLGC_WANTCHARS;
2654
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002655 case WM_PAINT:
2656 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002657 PAINTSTRUCT ps;
2658 HDC hdc = ( wParam ) ? ((HDC)wParam)
2659 : BeginPaint( hwnd, &ps );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002660 ret = LISTBOX_Paint( wnd, descr, hdc );
Alexandre Julliarda3960291999-02-26 11:11:13 +00002661 if( !wParam ) EndPaint( hwnd, &ps );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002662 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002663 return ret;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002664 case WM_SIZE:
2665 LISTBOX_UpdateSize( wnd, descr );
Marcus Meissner9aded511999-05-01 10:23:45 +00002666 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002667 case WM_GETFONT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002668 return descr->font;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002669 case WM_SETFONT:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002670 LISTBOX_SetFont( wnd, descr, (HFONT)wParam );
2671 if (lParam) InvalidateRect( wnd->hwndSelf, 0, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002672 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002673 case WM_SETFOCUS:
2674 descr->caret_on = TRUE;
2675 if (descr->focus_item != -1)
2676 LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
2677 SEND_NOTIFICATION( wnd, descr, LBN_SETFOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002678 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002679 case WM_KILLFOCUS:
2680 if ((descr->focus_item != -1) && descr->caret_on)
2681 LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
2682 SEND_NOTIFICATION( wnd, descr, LBN_KILLFOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002683 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002684 case WM_HSCROLL:
Marcus Meissner9aded511999-05-01 10:23:45 +00002685 return LISTBOX_HandleHScroll( wnd, descr, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002686 case WM_VSCROLL:
Marcus Meissner9aded511999-05-01 10:23:45 +00002687 return LISTBOX_HandleVScroll( wnd, descr, wParam, lParam );
Stephane Lussier4bdf4af2000-04-18 11:56:33 +00002688 case WM_MOUSEWHEEL:
2689 if (wParam & (MK_SHIFT | MK_CONTROL))
2690 return DefWindowProcA( hwnd, msg, wParam, lParam );
2691 return LISTBOX_HandleMouseWheel( wnd, descr, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002692 case WM_LBUTTONDOWN:
Marcus Meissner9aded511999-05-01 10:23:45 +00002693 return LISTBOX_HandleLButtonDown( wnd, descr, wParam,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002694 (INT16)LOWORD(lParam),
2695 (INT16)HIWORD(lParam) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002696 case WM_LBUTTONDBLCLK:
2697 if (descr->style & LBS_NOTIFY)
2698 SEND_NOTIFICATION( wnd, descr, LBN_DBLCLK );
Marcus Meissner9aded511999-05-01 10:23:45 +00002699 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002700 case WM_MOUSEMOVE:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002701 if (GetCapture() == hwnd)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002702 LISTBOX_HandleMouseMove( wnd, descr, (INT16)LOWORD(lParam),
2703 (INT16)HIWORD(lParam) );
Marcus Meissner9aded511999-05-01 10:23:45 +00002704 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002705 case WM_LBUTTONUP:
Marcus Meissner9aded511999-05-01 10:23:45 +00002706 return LISTBOX_HandleLButtonUp( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002707 case WM_KEYDOWN:
Marcus Meissner9aded511999-05-01 10:23:45 +00002708 return LISTBOX_HandleKeyDown( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002709 case WM_CHAR:
Marcus Meissner9aded511999-05-01 10:23:45 +00002710 return LISTBOX_HandleChar( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002711 case WM_SYSTIMER:
Marcus Meissner9aded511999-05-01 10:23:45 +00002712 return LISTBOX_HandleSystemTimer( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002713 case WM_ERASEBKGND:
2714 if (IS_OWNERDRAW(descr))
2715 {
Luc Tourangeau89147991999-04-18 09:23:56 +00002716 RECT rect;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002717 HBRUSH hbrush = SendMessageA( descr->owner, WM_CTLCOLORLISTBOX,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002718 wParam, (LPARAM)wnd->hwndSelf );
Luc Tourangeau89147991999-04-18 09:23:56 +00002719 GetClientRect(hwnd, &rect);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002720 if (hbrush) FillRect( (HDC)wParam, &rect, hbrush );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002721 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002722 return 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002723 case WM_DROPFILES:
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002724 if( !descr->lphc )
Marcus Meissner9aded511999-05-01 10:23:45 +00002725 return SendMessageA( descr->owner, msg, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002726 break;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002727
2728 case WM_DROPOBJECT:
2729 case WM_QUERYDROPOBJECT:
2730 case WM_DRAGSELECT:
2731 case WM_DRAGMOVE:
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002732 if( !descr->lphc )
2733 {
2734 LPDRAGINFO dragInfo = (LPDRAGINFO)PTR_SEG_TO_LIN( (SEGPTR)lParam );
2735 dragInfo->l = LISTBOX_GetItemFromPoint( wnd, descr, dragInfo->pt.x,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002736 dragInfo->pt.y );
Marcus Meissner9aded511999-05-01 10:23:45 +00002737 return SendMessageA( descr->owner, msg, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002738 }
2739 break;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002740
2741 default:
2742 if ((msg >= WM_USER) && (msg < 0xc000))
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002743 WARN("[%04x]: unknown msg %04x wp %08x lp %08lx\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002744 hwnd, msg, wParam, lParam );
Marcus Meissner9aded511999-05-01 10:23:45 +00002745 return DefWindowProcA( hwnd, msg, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002746 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002747 return 0;
2748}
2749
2750/***********************************************************************
2751 * ListBoxWndProc
2752 *
2753 * This is just a wrapper for the real wndproc, it only does window locking
2754 * and unlocking.
2755 */
2756LRESULT WINAPI ListBoxWndProc( HWND hwnd, UINT msg,
2757 WPARAM wParam, LPARAM lParam )
2758{
2759 WND* wndPtr = WIN_FindWndPtr( hwnd );
2760 LRESULT res = ListBoxWndProc_locked(wndPtr,msg,wParam,lParam);
2761
2762 WIN_ReleaseWndPtr(wndPtr);
2763 return res;
Alexandre Julliard58199531994-04-21 01:20:00 +00002764}
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002765
2766/***********************************************************************
2767 * COMBO_Directory
2768 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002769LRESULT COMBO_Directory( LPHEADCOMBO lphc, UINT attrib, LPSTR dir, BOOL bLong)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002770{
2771 WND *wnd = WIN_FindWndPtr( lphc->hWndLBox );
2772
2773 if( wnd )
2774 {
2775 LB_DESCR *descr = *(LB_DESCR **)wnd->wExtra;
2776 if( descr )
2777 {
2778 LRESULT lRet = LISTBOX_Directory( wnd, descr, attrib, dir, bLong );
2779
Alexandre Julliarda3960291999-02-26 11:11:13 +00002780 RedrawWindow( lphc->self->hwndSelf, NULL, 0,
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002781 RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002782 WIN_ReleaseWndPtr(wnd);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002783 return lRet;
2784 }
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002785 WIN_ReleaseWndPtr(wnd);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002786 }
2787 return CB_ERR;
2788}
2789
2790/***********************************************************************
Marcus Meissner9aded511999-05-01 10:23:45 +00002791 * ComboLBWndProc_locked
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002792 *
Marcus Meissner9aded511999-05-01 10:23:45 +00002793 * The real combo listbox wndproc, but called with locked WND struct.
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002794 */
Marcus Meissner9aded511999-05-01 10:23:45 +00002795static inline LRESULT WINAPI ComboLBWndProc_locked( WND* wnd, UINT msg,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002796 WPARAM wParam, LPARAM lParam )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002797{
2798 LRESULT lRet = 0;
Marcus Meissner9aded511999-05-01 10:23:45 +00002799 HWND hwnd = wnd->hwndSelf;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002800
2801 if (wnd)
2802 {
2803 LB_DESCR *descr = *(LB_DESCR **)wnd->wExtra;
2804
Alexandre Julliard06c275a1999-05-02 14:32:27 +00002805 TRACE_(combo)("[%04x]: msg %s wp %08x lp %08lx\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002806 wnd->hwndSelf, SPY_GetMsgName(msg), wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002807
2808 if( descr || msg == WM_CREATE )
2809 {
2810 LPHEADCOMBO lphc = (descr) ? descr->lphc : NULL;
2811
2812 switch( msg )
2813 {
2814 case WM_CREATE:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002815#define lpcs ((LPCREATESTRUCTA)lParam)
Alexandre Julliard06c275a1999-05-02 14:32:27 +00002816 TRACE_(combo)("\tpassed parent handle = 0x%08x\n",
Alexandre Julliarda3960291999-02-26 11:11:13 +00002817 (UINT)lpcs->lpCreateParams);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002818
2819 lphc = (LPHEADCOMBO)(lpcs->lpCreateParams);
2820#undef lpcs
Marcus Meissner9aded511999-05-01 10:23:45 +00002821 return LISTBOX_Create( wnd, lphc );
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00002822 case WM_MOUSEMOVE:
2823 if ( (TWEAK_WineLook > WIN31_LOOK) &&
2824 (CB_GETTYPE(lphc) != CBS_SIMPLE) )
2825 {
2826 POINT mousePos;
2827 BOOL captured;
2828 RECT clientRect;
2829
2830 mousePos.x = (INT16)LOWORD(lParam);
2831 mousePos.y = (INT16)HIWORD(lParam);
2832
2833 /*
2834 * If we are in a dropdown combobox, we simulate that
2835 * the mouse is captured to show the tracking of the item.
2836 */
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00002837 GetClientRect(hwnd, &clientRect);
2838
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002839 if (PtInRect( &clientRect, mousePos ))
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00002840 {
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002841 captured = descr->captured;
2842 descr->captured = TRUE;
2843
2844 LISTBOX_HandleMouseMove( wnd, descr,
2845 mousePos.x, mousePos.y);
2846
2847 descr->captured = captured;
2848
2849 }
2850 else
2851 {
2852 LISTBOX_HandleMouseMove( wnd, descr,
2853 mousePos.x, mousePos.y);
2854 }
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00002855
2856 return 0;
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002857
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00002858 }
2859 else
2860 {
2861 /*
2862 * If we are in Win3.1 look, go with the default behavior.
2863 */
2864 return ListBoxWndProc( hwnd, msg, wParam, lParam );
2865 }
2866 case WM_LBUTTONUP:
2867 if (TWEAK_WineLook > WIN31_LOOK)
2868 {
2869 POINT mousePos;
2870 RECT clientRect;
2871
2872 /*
2873 * If the mouse button "up" is not in the listbox,
2874 * we make sure there is no selection by re-selecting the
2875 * item that was selected when the listbox was made visible.
2876 */
2877 mousePos.x = (INT16)LOWORD(lParam);
2878 mousePos.y = (INT16)HIWORD(lParam);
2879
2880 GetClientRect(hwnd, &clientRect);
2881
2882 /*
2883 * When the user clicks outside the combobox and the focus
2884 * is lost, the owning combobox will send a fake buttonup with
2885 * 0xFFFFFFF as the mouse location, we must also revert the
2886 * selection to the original selection.
2887 */
2888 if ( (lParam == 0xFFFFFFFF) ||
2889 (!PtInRect( &clientRect, mousePos )) )
2890 {
2891 LISTBOX_MoveCaret( wnd,
2892 descr,
2893 lphc->droppedIndex,
2894 FALSE );
2895 }
2896 }
2897 return LISTBOX_HandleLButtonUp( wnd, descr );
Chris Morganc0872e32000-05-07 18:24:36 +00002898 case WM_LBUTTONDBLCLK:
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002899 case WM_LBUTTONDOWN:
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002900 return LISTBOX_HandleLButtonDownCombo(wnd, descr, wParam,
2901 (INT16)LOWORD(lParam),
2902 (INT16)HIWORD(lParam) );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002903 case WM_MOUSEACTIVATE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002904 return MA_NOACTIVATE;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002905 case WM_NCACTIVATE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002906 return FALSE;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002907 case WM_KEYDOWN:
2908 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
2909 {
2910 /* for some reason(?) Windows makes it possible to
2911 * show/hide ComboLBox by sending it WM_KEYDOWNs */
2912
2913 if( (!(lphc->wState & CBF_EUI) && wParam == VK_F4) ||
2914 ( (lphc->wState & CBF_EUI) && !(lphc->wState & CBF_DROPPED)
2915 && (wParam == VK_DOWN || wParam == VK_UP)) )
2916 {
2917 COMBO_FlipListbox( lphc, FALSE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002918 return 0;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002919 }
2920 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002921 return LISTBOX_HandleKeyDown( wnd, descr, wParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002922
Alex Korobka311d3291999-01-01 18:40:02 +00002923 case LB_SETCURSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002924 case LB_SETCURSEL:
Alex Korobka311d3291999-01-01 18:40:02 +00002925 lRet = ListBoxWndProc( hwnd, msg, wParam, lParam );
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002926 lRet =(lRet == LB_ERR) ? lRet : descr->selected_item;
Marcus Meissner9aded511999-05-01 10:23:45 +00002927 return lRet;
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00002928 case WM_NCDESTROY:
2929 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
2930 lphc->hWndLBox = 0;
2931 /* fall through */
2932
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002933 default:
Marcus Meissner9aded511999-05-01 10:23:45 +00002934 return ListBoxWndProc( hwnd, msg, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002935 }
2936 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00002937 lRet = DefWindowProcA( hwnd, msg, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002938
Alexandre Julliard06c275a1999-05-02 14:32:27 +00002939 TRACE_(combo)("\t default on msg [%04x]\n", (UINT16)msg );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002940 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002941 return lRet;
2942}
2943
Marcus Meissner9aded511999-05-01 10:23:45 +00002944/***********************************************************************
2945 * ComboLBWndProc
2946 *
2947 * NOTE: in Windows, winproc address of the ComboLBox is the same
2948 * as that of the Listbox.
2949 *
2950 * This is just a wrapper for the real wndproc, it only does window locking
2951 * and unlocking.
2952 */
2953LRESULT WINAPI ComboLBWndProc( HWND hwnd, UINT msg,
2954 WPARAM wParam, LPARAM lParam )
2955{
2956 WND *wnd = WIN_FindWndPtr( hwnd );
2957 LRESULT res = ComboLBWndProc_locked(wnd,msg,wParam,lParam);
2958
2959 WIN_ReleaseWndPtr(wnd);
2960 return res;
2961}