blob: a986fa2706ec9517eebd1a0800dbbc9f60819353 [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>
Alex Korobka311d3291999-01-01 18:40:02 +00009#include "wine/winuser16.h"
Nick Hollowayb9ce4fd1999-09-11 16:29:00 +000010#include "wine/winbase16.h"
Alex Korobka311d3291999-01-01 18:40:02 +000011#include "winuser.h"
Alexandre Julliard9ea19e51997-01-01 17:29:55 +000012#include "winerror.h"
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +000013#include "drive.h"
Alexandre Julliarde2bfa4c1996-05-16 18:21:06 +000014#include "heap.h"
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000015#include "spy.h"
16#include "win.h"
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000017#include "combo.h"
Alexandre Julliard06c275a1999-05-02 14:32:27 +000018#include "debugtools.h"
Alexandre Julliardebfc0fe1998-06-28 18:40:26 +000019#include "tweak.h"
Gerard Patelc9a6d501999-07-25 13:03:17 +000020#include "winversion.h"
Alexandre Julliard0e607781993-11-03 19:23:37 +000021
Alexandre Julliard9fe7a251999-05-14 08:17:14 +000022DEFAULT_DEBUG_CHANNEL(listbox)
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000023DECLARE_DEBUG_CHANNEL(combo)
Patrik Stridvallb4b9fae1999-04-19 14:56:29 +000024
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000025/* Unimplemented yet:
26 * - LBS_NOSEL
27 * - LBS_USETABSTOPS
28 * - Unicode
29 * - Locale handling
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000030 */
Alexandre Julliarde2abbb11995-03-19 17:39:39 +000031
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000032/* Items array granularity */
33#define LB_ARRAY_GRANULARITY 16
Alexandre Julliard0e607781993-11-03 19:23:37 +000034
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000035/* Scrolling timeout in ms */
36#define LB_SCROLL_TIMEOUT 50
Alexandre Julliardc981d0b1996-03-31 16:40:13 +000037
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000038/* Listbox system timer id */
39#define LB_TIMER_ID 2
Alexandre Julliardac9c9b01996-07-28 18:50:11 +000040
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000041/* Item structure */
42typedef struct
Alexandre Julliard2787be81995-05-22 18:23:01 +000043{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000044 LPSTR str; /* Item text */
Alexandre Julliarda3960291999-02-26 11:11:13 +000045 BOOL selected; /* Is item selected? */
46 UINT height; /* Item height (only for OWNERDRAWVARIABLE) */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000047 DWORD data; /* User data */
48} LB_ITEMDATA;
Alexandre Julliard2787be81995-05-22 18:23:01 +000049
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000050/* Listbox structure */
51typedef struct
Alexandre Julliard2787be81995-05-22 18:23:01 +000052{
Alexandre Julliarda3960291999-02-26 11:11:13 +000053 HANDLE heap; /* Heap for this listbox */
54 HWND owner; /* Owner window to send notifications to */
55 UINT style; /* Window style */
56 INT width; /* Window width */
57 INT height; /* Window height */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000058 LB_ITEMDATA *items; /* Array of items */
Alexandre Julliarda3960291999-02-26 11:11:13 +000059 INT nb_items; /* Number of items */
60 INT top_item; /* Top visible item */
61 INT selected_item; /* Selected item */
62 INT focus_item; /* Item that has the focus */
63 INT anchor_item; /* Anchor item for extended selection */
64 INT item_height; /* Default item height */
65 INT page_size; /* Items per listbox page */
66 INT column_width; /* Column width for multi-column listboxes */
67 INT horz_extent; /* Horizontal extent (0 if no hscroll) */
68 INT horz_pos; /* Horizontal position */
69 INT nb_tabs; /* Number of tabs in array */
70 INT *tabs; /* Array of tabs */
71 BOOL caret_on; /* Is caret on? */
Luc Tourangeau5ee117b1999-04-04 12:48:21 +000072 BOOL captured; /* Is mouse captured? */
Alexandre Julliarda3960291999-02-26 11:11:13 +000073 HFONT font; /* Current font */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000074 LCID locale; /* Current locale for string comparisons */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000075 LPHEADCOMBO lphc; /* ComboLBox */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000076} LB_DESCR;
Alexandre Julliard2787be81995-05-22 18:23:01 +000077
Alexandre Julliardfa68b751995-04-03 16:55:37 +000078
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000079#define IS_OWNERDRAW(descr) \
80 ((descr)->style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE))
Alexandre Julliardb817f4f1996-03-14 18:08:34 +000081
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000082#define HAS_STRINGS(descr) \
83 (!IS_OWNERDRAW(descr) || ((descr)->style & LBS_HASSTRINGS))
Alexandre Julliard2787be81995-05-22 18:23:01 +000084
Gerard Patelc9a6d501999-07-25 13:03:17 +000085
86#define IS_MULTISELECT(descr) \
87 ((descr)->style & LBS_MULTIPLESEL || ((descr)->style & LBS_EXTENDEDSEL))
88
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000089#define SEND_NOTIFICATION(wnd,descr,code) \
Alexandre Julliarda3960291999-02-26 11:11:13 +000090 (SendMessageA( (descr)->owner, WM_COMMAND, \
Alexandre Julliarddf2673b1997-03-29 17:20:20 +000091 MAKEWPARAM((((descr)->lphc)?ID_CB_LISTBOX:(wnd)->wIDmenu), (code) ), (wnd)->hwndSelf ))
Alexandre Julliardfa68b751995-04-03 16:55:37 +000092
Gerard Patelc9a6d501999-07-25 13:03:17 +000093#define ISWIN31 (LOWORD(GetVersion()) == 0x0a03)
94
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000095/* Current timer status */
96typedef enum
Alexandre Julliardfa68b751995-04-03 16:55:37 +000097{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +000098 LB_TIMER_NONE,
99 LB_TIMER_UP,
100 LB_TIMER_LEFT,
101 LB_TIMER_DOWN,
102 LB_TIMER_RIGHT
103} TIMER_DIRECTION;
Alexandre Julliardfa68b751995-04-03 16:55:37 +0000104
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000105static TIMER_DIRECTION LISTBOX_Timer = LB_TIMER_NONE;
106
107
108/***********************************************************************
109 * LISTBOX_Dump
110 */
111void LISTBOX_Dump( WND *wnd )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000112{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000113 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000114 LB_ITEMDATA *item;
115 LB_DESCR *descr = *(LB_DESCR **)wnd->wExtra;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000116
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000117 TRACE( "Listbox:\n" );
118 TRACE( "hwnd=%04x descr=%08x heap=%08x items=%d top=%d\n",
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000119 wnd->hwndSelf, (UINT)descr, descr->heap, descr->nb_items,
120 descr->top_item );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000121 for (i = 0, item = descr->items; i < descr->nb_items; i++, item++)
122 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000123 TRACE( "%4d: %-40s %d %08lx %3d\n",
Alexandre Julliard06c275a1999-05-02 14:32:27 +0000124 i, item->str, item->selected, item->data, item->height );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000125 }
Alexandre Julliard2787be81995-05-22 18:23:01 +0000126}
127
128
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000129/***********************************************************************
130 * LISTBOX_GetCurrentPageSize
131 *
132 * Return the current page size
133 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000134static INT LISTBOX_GetCurrentPageSize( WND *wnd, LB_DESCR *descr )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000135{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000136 INT i, height;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000137 if (!(descr->style & LBS_OWNERDRAWVARIABLE)) return descr->page_size;
138 for (i = descr->top_item, height = 0; i < descr->nb_items; i++)
139 {
140 if ((height += descr->items[i].height) > descr->height) break;
141 }
142 if (i == descr->top_item) return 1;
143 else return i - descr->top_item;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000144}
145
146
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000147/***********************************************************************
148 * LISTBOX_GetMaxTopIndex
149 *
150 * Return the maximum possible index for the top of the listbox.
151 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000152static INT LISTBOX_GetMaxTopIndex( WND *wnd, LB_DESCR *descr )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000153{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000154 INT max, page;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000155
156 if (descr->style & LBS_OWNERDRAWVARIABLE)
157 {
158 page = descr->height;
159 for (max = descr->nb_items - 1; max >= 0; max--)
160 if ((page -= descr->items[max].height) < 0) break;
161 if (max < descr->nb_items - 1) max++;
162 }
163 else if (descr->style & LBS_MULTICOLUMN)
164 {
165 if ((page = descr->width / descr->column_width) < 1) page = 1;
166 max = (descr->nb_items + descr->page_size - 1) / descr->page_size;
167 max = (max - page) * descr->page_size;
168 }
169 else
170 {
171 max = descr->nb_items - descr->page_size;
172 }
173 if (max < 0) max = 0;
174 return max;
175}
176
177
178/***********************************************************************
179 * LISTBOX_UpdateScroll
180 *
181 * Update the scrollbars. Should be called whenever the content
182 * of the listbox changes.
183 */
184static void LISTBOX_UpdateScroll( WND *wnd, LB_DESCR *descr )
185{
186 SCROLLINFO info;
187
Alexandre Julliarddadf78f1998-05-17 17:13:43 +0000188 if (!(descr->style & WS_VSCROLL)) return;
189 /* It is important that we check descr->style, and not wnd->dwStyle,
190 for WS_VSCROLL, as the former is exactly the one passed in
191 argument to CreateWindow.
192 In Windows (and from now on in Wine :) a listbox created
193 with such a style (no WS_SCROLL) does not update
194 the scrollbar with listbox-related data, thus letting
195 the programmer use it for his/her own purposes. */
196
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000197 if (descr->style & LBS_NOREDRAW) return;
198 info.cbSize = sizeof(info);
199
200 if (descr->style & LBS_MULTICOLUMN)
201 {
202 info.nMin = 0;
203 info.nMax = (descr->nb_items - 1) / descr->page_size;
204 info.nPos = descr->top_item / descr->page_size;
205 info.nPage = descr->width / descr->column_width;
206 if (info.nPage < 1) info.nPage = 1;
207 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
208 if (descr->style & LBS_DISABLENOSCROLL)
209 info.fMask |= SIF_DISABLENOSCROLL;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000210 SetScrollInfo( wnd->hwndSelf, SB_HORZ, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000211 info.nMax = 0;
212 info.fMask = SIF_RANGE;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000213 SetScrollInfo( wnd->hwndSelf, SB_VERT, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000214 }
215 else
216 {
217 info.nMin = 0;
218 info.nMax = descr->nb_items - 1;
219 info.nPos = descr->top_item;
220 info.nPage = LISTBOX_GetCurrentPageSize( wnd, descr );
221 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
222 if (descr->style & LBS_DISABLENOSCROLL)
223 info.fMask |= SIF_DISABLENOSCROLL;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000224 SetScrollInfo( wnd->hwndSelf, SB_VERT, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000225
226 if (descr->horz_extent)
227 {
228 info.nMin = 0;
229 info.nMax = descr->horz_extent - 1;
230 info.nPos = descr->horz_pos;
231 info.nPage = descr->width;
232 info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
233 if (descr->style & LBS_DISABLENOSCROLL)
234 info.fMask |= SIF_DISABLENOSCROLL;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000235 SetScrollInfo( wnd->hwndSelf, SB_HORZ, &info, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000236 }
237 }
238}
239
240
241/***********************************************************************
242 * LISTBOX_SetTopItem
243 *
244 * Set the top item of the listbox, scrolling up or down if necessary.
245 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000246static LRESULT LISTBOX_SetTopItem( WND *wnd, LB_DESCR *descr, INT index,
247 BOOL scroll )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000248{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000249 INT max = LISTBOX_GetMaxTopIndex( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000250 if (index > max) index = max;
251 if (index < 0) index = 0;
252 if (descr->style & LBS_MULTICOLUMN) index -= index % descr->page_size;
253 if (descr->top_item == index) return LB_OKAY;
254 if (descr->style & LBS_MULTICOLUMN)
255 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000256 INT diff = (descr->top_item - index) / descr->page_size * descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000257 if (scroll && (abs(diff) < descr->width))
Alexandre Julliarda3960291999-02-26 11:11:13 +0000258 ScrollWindowEx( wnd->hwndSelf, diff, 0, NULL, NULL, 0, NULL,
NF Stevens762f18d1999-01-24 19:02:16 +0000259 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
260
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000261 else
262 scroll = FALSE;
263 }
264 else if (scroll)
265 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000266 INT diff;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000267 if (descr->style & LBS_OWNERDRAWVARIABLE)
268 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000269 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000270 diff = 0;
271 if (index > descr->top_item)
272 {
273 for (i = index - 1; i >= descr->top_item; i--)
274 diff -= descr->items[i].height;
275 }
276 else
277 {
278 for (i = index; i < descr->top_item; i++)
279 diff += descr->items[i].height;
280 }
281 }
282 else
283 diff = (descr->top_item - index) * descr->item_height;
284
285 if (abs(diff) < descr->height)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000286 ScrollWindowEx( wnd->hwndSelf, 0, diff, NULL, NULL, 0, NULL,
NF Stevens762f18d1999-01-24 19:02:16 +0000287 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000288 else
289 scroll = FALSE;
290 }
Alexandre Julliarda3960291999-02-26 11:11:13 +0000291 if (!scroll) InvalidateRect( wnd->hwndSelf, NULL, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000292 descr->top_item = index;
293 LISTBOX_UpdateScroll( wnd, descr );
294 return LB_OKAY;
295}
296
297
298/***********************************************************************
299 * LISTBOX_UpdatePage
300 *
301 * Update the page size. Should be called when the size of
302 * the client area or the item height changes.
303 */
304static void LISTBOX_UpdatePage( WND *wnd, LB_DESCR *descr )
305{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000306 INT page_size;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000307
Paul Quinn75722071999-05-22 18:45:06 +0000308 if ((descr->item_height == 0) || (page_size = descr->height / descr->item_height) < 1)
309 page_size = 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000310 if (page_size == descr->page_size) return;
311 descr->page_size = page_size;
312 if (descr->style & LBS_MULTICOLUMN)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000313 InvalidateRect( wnd->hwndSelf, NULL, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000314 LISTBOX_SetTopItem( wnd, descr, descr->top_item, FALSE );
315}
316
317
318/***********************************************************************
319 * LISTBOX_UpdateSize
320 *
321 * Update the size of the listbox. Should be called when the size of
322 * the client area changes.
323 */
324static void LISTBOX_UpdateSize( WND *wnd, LB_DESCR *descr )
325{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000326 RECT rect;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000327
Alexandre Julliarda3960291999-02-26 11:11:13 +0000328 GetClientRect( wnd->hwndSelf, &rect );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000329 descr->width = rect.right - rect.left;
330 descr->height = rect.bottom - rect.top;
Alexandre Julliarda0d77311998-09-13 16:32:00 +0000331 if (!(descr->style & LBS_NOINTEGRALHEIGHT) && !IS_OWNERDRAW(descr))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000332 {
333 if ((descr->height > descr->item_height) &&
334 (descr->height % descr->item_height))
335 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000336 TRACE("[%04x]: changing height %d -> %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000337 wnd->hwndSelf, descr->height,
338 descr->height - descr->height%descr->item_height );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000339 SetWindowPos( wnd->hwndSelf, 0, 0, 0,
Alexandre Julliard01d63461997-01-20 19:43:45 +0000340 wnd->rectWindow.right - wnd->rectWindow.left,
341 wnd->rectWindow.bottom - wnd->rectWindow.top -
342 (descr->height % descr->item_height),
343 SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000344 return;
345 }
346 }
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000347 TRACE("[%04x]: new size = %d,%d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000348 wnd->hwndSelf, descr->width, descr->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000349 LISTBOX_UpdatePage( wnd, descr );
350 LISTBOX_UpdateScroll( wnd, descr );
351}
352
353
354/***********************************************************************
355 * LISTBOX_GetItemRect
356 *
357 * Get the rectangle enclosing an item, in listbox client coordinates.
358 * Return 1 if the rectangle is (partially) visible, 0 if hidden, -1 on error.
359 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000360static LRESULT LISTBOX_GetItemRect( WND *wnd, LB_DESCR *descr, INT index,
361 RECT *rect )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000362{
363 /* Index <= 0 is legal even on empty listboxes */
364 if (index && (index >= descr->nb_items)) return -1;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000365 SetRect( rect, 0, 0, descr->width, descr->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000366 if (descr->style & LBS_MULTICOLUMN)
367 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000368 INT col = (index / descr->page_size) -
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000369 (descr->top_item / descr->page_size);
370 rect->left += col * descr->column_width;
371 rect->right = rect->left + descr->column_width;
372 rect->top += (index % descr->page_size) * descr->item_height;
373 rect->bottom = rect->top + descr->item_height;
374 }
375 else if (descr->style & LBS_OWNERDRAWVARIABLE)
376 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000377 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000378 rect->right += descr->horz_pos;
Alexandre Julliard349a9531997-02-02 19:01:52 +0000379 if ((index >= 0) && (index < descr->nb_items))
380 {
381 if (index < descr->top_item)
382 {
383 for (i = descr->top_item-1; i >= index; i--)
384 rect->top -= descr->items[i].height;
385 }
386 else
387 {
388 for (i = descr->top_item; i < index; i++)
389 rect->top += descr->items[i].height;
390 }
391 rect->bottom = rect->top + descr->items[index].height;
392
393 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000394 }
395 else
396 {
397 rect->top += (index - descr->top_item) * descr->item_height;
398 rect->bottom = rect->top + descr->item_height;
399 rect->right += descr->horz_pos;
400 }
401
402 return ((rect->left < descr->width) && (rect->right > 0) &&
403 (rect->top < descr->height) && (rect->bottom > 0));
404}
405
406
407/***********************************************************************
408 * LISTBOX_GetItemFromPoint
409 *
410 * Return the item nearest from point (x,y) (in client coordinates).
411 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000412static INT LISTBOX_GetItemFromPoint( WND *wnd, LB_DESCR *descr,
413 INT x, INT y )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000414{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000415 INT index = descr->top_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000416
417 if (!descr->nb_items) return -1; /* No items */
418 if (descr->style & LBS_OWNERDRAWVARIABLE)
419 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000420 INT pos = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000421 if (y >= 0)
422 {
423 while (index < descr->nb_items)
424 {
425 if ((pos += descr->items[index].height) > y) break;
426 index++;
427 }
428 }
429 else
430 {
431 while (index > 0)
432 {
433 index--;
434 if ((pos -= descr->items[index].height) <= y) break;
435 }
436 }
437 }
438 else if (descr->style & LBS_MULTICOLUMN)
439 {
440 if (y >= descr->item_height * descr->page_size) return -1;
441 if (y >= 0) index += y / descr->item_height;
442 if (x >= 0) index += (x / descr->column_width) * descr->page_size;
443 else index -= (((x + 1) / descr->column_width) - 1) * descr->page_size;
444 }
445 else
446 {
447 index += (y / descr->item_height);
448 }
449 if (index < 0) return 0;
450 if (index >= descr->nb_items) return -1;
451 return index;
452}
453
454
455/***********************************************************************
456 * LISTBOX_PaintItem
457 *
458 * Paint an item.
459 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000460static void LISTBOX_PaintItem( WND *wnd, LB_DESCR *descr, HDC hdc,
461 const RECT *rect, INT index, UINT action )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000462{
463 LB_ITEMDATA *item = NULL;
464 if (index < descr->nb_items) item = &descr->items[index];
465
466 if (IS_OWNERDRAW(descr))
Alexandre Julliard2d93d001996-05-21 15:01:41 +0000467 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000468 DRAWITEMSTRUCT dis;
469 UINT id = (descr->lphc) ? ID_CB_LISTBOX : wnd->wIDmenu;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000470
Marcus Meissner9ad90171999-01-20 14:08:00 +0000471 if (!item)
472 {
473 if (action == ODA_FOCUS)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000474 DrawFocusRect( hdc, rect );
Marcus Meissner9ad90171999-01-20 14:08:00 +0000475 else
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000476 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 +0000477 return;
478 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000479 dis.CtlType = ODT_LISTBOX;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000480 dis.CtlID = id;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000481 dis.hwndItem = wnd->hwndSelf;
482 dis.itemAction = action;
483 dis.hDC = hdc;
484 dis.itemID = index;
485 dis.itemState = 0;
486 if (item && item->selected) dis.itemState |= ODS_SELECTED;
487 if ((descr->focus_item == index) &&
488 (descr->caret_on) &&
Alexandre Julliarda3960291999-02-26 11:11:13 +0000489 (GetFocus() == wnd->hwndSelf)) dis.itemState |= ODS_FOCUS;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000490 if (wnd->dwStyle & WS_DISABLED) dis.itemState |= ODS_DISABLED;
491 dis.itemData = item ? item->data : 0;
492 dis.rcItem = *rect;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000493 TRACE("[%04x]: drawitem %d (%s) action=%02x "
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000494 "state=%02x rect=%d,%d-%d,%d\n",
495 wnd->hwndSelf, index, item ? item->str : "", action,
496 dis.itemState, rect->left, rect->top,
497 rect->right, rect->bottom );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000498 SendMessageA(descr->owner, WM_DRAWITEM, id, (LPARAM)&dis);
Alexandre Julliard2787be81995-05-22 18:23:01 +0000499 }
500 else
Alexandre Julliardac9c9b01996-07-28 18:50:11 +0000501 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000502 COLORREF oldText = 0, oldBk = 0;
503
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000504 if (action == ODA_FOCUS)
505 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000506 DrawFocusRect( hdc, rect );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000507 return;
508 }
509 if (item && item->selected)
510 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000511 oldBk = SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
512 oldText = SetTextColor( hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000513 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000514
Alexandre Julliard9fe7a251999-05-14 08:17:14 +0000515 TRACE("[%04x]: painting %d (%s) action=%02x "
Alexandre Julliarda69b88b1998-03-15 20:29:56 +0000516 "rect=%d,%d-%d,%d\n",
517 wnd->hwndSelf, index, item ? item->str : "", action,
518 rect->left, rect->top, rect->right, rect->bottom );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000519 if (!item)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000520 ExtTextOutA( hdc, rect->left + 1, rect->top + 1,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000521 ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000522 else if (!(descr->style & LBS_USETABSTOPS))
Alexandre Julliarda3960291999-02-26 11:11:13 +0000523 ExtTextOutA( hdc, rect->left + 1, rect->top + 1,
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000524 ETO_OPAQUE | ETO_CLIPPED, rect, item->str,
525 strlen(item->str), NULL );
526 else
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000527 {
528 /* Output empty string to paint background in the full width. */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000529 ExtTextOutA( hdc, rect->left + 1, rect->top + 1,
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000530 ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000531 TabbedTextOutA( hdc, rect->left + 1 , rect->top + 1,
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000532 item->str, strlen(item->str),
533 descr->nb_tabs, descr->tabs, 0);
Alexandre Julliarda0b2b1d1997-11-16 17:38:29 +0000534 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000535 if (item && item->selected)
536 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000537 SetBkColor( hdc, oldBk );
538 SetTextColor( hdc, oldText );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000539 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000540 if ((descr->focus_item == index) &&
541 (descr->caret_on) &&
Alexandre Julliarda3960291999-02-26 11:11:13 +0000542 (GetFocus() == wnd->hwndSelf)) DrawFocusRect( hdc, rect );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000543 }
Alexandre Julliard2787be81995-05-22 18:23:01 +0000544}
545
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000546
547/***********************************************************************
548 * LISTBOX_SetRedraw
549 *
550 * Change the redraw flag.
551 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000552static void LISTBOX_SetRedraw( WND *wnd, LB_DESCR *descr, BOOL on )
Alexandre Julliardac9c9b01996-07-28 18:50:11 +0000553{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000554 if (on)
555 {
556 if (!(descr->style & LBS_NOREDRAW)) return;
557 descr->style &= ~LBS_NOREDRAW;
558 LISTBOX_UpdateScroll( wnd, descr );
Alexandre Julliard2787be81995-05-22 18:23:01 +0000559 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000560 else descr->style |= LBS_NOREDRAW;
561}
Alexandre Julliard2787be81995-05-22 18:23:01 +0000562
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000563
564/***********************************************************************
565 * LISTBOX_RepaintItem
566 *
567 * Repaint a single item synchronously.
568 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000569static void LISTBOX_RepaintItem( WND *wnd, LB_DESCR *descr, INT index,
570 UINT action )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000571{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000572 HDC hdc;
573 RECT rect;
574 HFONT oldFont = 0;
575 HBRUSH hbrush, oldBrush = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000576
Francois Boisvert428d2981999-05-08 09:33:53 +0000577 /* Do not repaint the item if the item is not visible */
578 if ((descr->style & LBS_NOREDRAW) || !IsWindowVisible(wnd->hwndSelf)) return;
579
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000580 if (LISTBOX_GetItemRect( wnd, descr, index, &rect ) != 1) return;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000581 if (!(hdc = GetDCEx( wnd->hwndSelf, 0, DCX_CACHE ))) return;
582 if (descr->font) oldFont = SelectObject( hdc, descr->font );
583 hbrush = SendMessageA( descr->owner, WM_CTLCOLORLISTBOX,
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000584 hdc, (LPARAM)wnd->hwndSelf );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000585 if (hbrush) oldBrush = SelectObject( hdc, hbrush );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000586 if (wnd->dwStyle & WS_DISABLED)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000587 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
588 SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000589 LISTBOX_PaintItem( wnd, descr, hdc, &rect, index, action );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000590 if (oldFont) SelectObject( hdc, oldFont );
591 if (oldBrush) SelectObject( hdc, oldBrush );
592 ReleaseDC( wnd->hwndSelf, hdc );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000593}
594
595
596/***********************************************************************
597 * LISTBOX_InitStorage
598 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000599static LRESULT LISTBOX_InitStorage( WND *wnd, LB_DESCR *descr, INT nb_items,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000600 DWORD bytes )
601{
602 LB_ITEMDATA *item;
603
604 nb_items += LB_ARRAY_GRANULARITY - 1;
605 nb_items -= (nb_items % LB_ARRAY_GRANULARITY);
606 if (descr->items)
607 nb_items += HeapSize( descr->heap, 0, descr->items ) / sizeof(*item);
608 if (!(item = HeapReAlloc( descr->heap, 0, descr->items,
609 nb_items * sizeof(LB_ITEMDATA) )))
610 {
611 SEND_NOTIFICATION( wnd, descr, LBN_ERRSPACE );
612 return LB_ERRSPACE;
613 }
614 descr->items = item;
615 return LB_OKAY;
616}
617
618
619/***********************************************************************
620 * LISTBOX_SetTabStops
621 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000622static BOOL LISTBOX_SetTabStops( WND *wnd, LB_DESCR *descr, INT count,
623 LPINT tabs, BOOL short_ints )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000624{
625 if (!(descr->style & LBS_USETABSTOPS)) return TRUE;
626 if (descr->tabs) HeapFree( descr->heap, 0, descr->tabs );
627 if (!(descr->nb_tabs = count))
628 {
629 descr->tabs = NULL;
630 return TRUE;
631 }
632 /* FIXME: count = 1 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000633 if (!(descr->tabs = (INT *)HeapAlloc( descr->heap, 0,
634 descr->nb_tabs * sizeof(INT) )))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000635 return FALSE;
636 if (short_ints)
637 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000638 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000639 LPINT16 p = (LPINT16)tabs;
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000640
Alexandre Julliard15de6151999-08-04 12:22:42 +0000641 TRACE("[%04x]: settabstops ", wnd->hwndSelf );
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000642 for (i = 0; i < descr->nb_tabs; i++) {
Alexandre Julliarda11d7b11998-03-01 20:05:02 +0000643 descr->tabs[i] = *p++<<1; /* FIXME */
Alexandre Julliard15de6151999-08-04 12:22:42 +0000644 if (TRACE_ON(listbox)) DPRINTF("%hd ", descr->tabs[i]);
Alexandre Julliard3db94ef1997-09-28 17:43:24 +0000645 }
Alexandre Julliard15de6151999-08-04 12:22:42 +0000646 if (TRACE_ON(listbox)) DPRINTF("\n");
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000647 }
Alexandre Julliarda3960291999-02-26 11:11:13 +0000648 else memcpy( descr->tabs, tabs, descr->nb_tabs * sizeof(INT) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000649 /* FIXME: repaint the window? */
Alexandre Julliard2787be81995-05-22 18:23:01 +0000650 return TRUE;
651}
652
653
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000654/***********************************************************************
655 * LISTBOX_GetText
656 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000657static LRESULT LISTBOX_GetText( WND *wnd, LB_DESCR *descr, INT index,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000658 LPSTR buffer )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000659{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000660 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
661 if (HAS_STRINGS(descr))
662 {
Marcus Meissner4f7dc461998-11-22 15:43:34 +0000663 if (!buffer)
664 return strlen(descr->items[index].str);
Alexandre Julliarda3960291999-02-26 11:11:13 +0000665 lstrcpyA( buffer, descr->items[index].str );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000666 return strlen(buffer);
Marcus Meissner4f7dc461998-11-22 15:43:34 +0000667 } else {
668 if (buffer)
669 *((LPDWORD)buffer)=*(LPDWORD)(&descr->items[index].data);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000670 return sizeof(DWORD);
671 }
Alexandre Julliard2787be81995-05-22 18:23:01 +0000672}
673
674
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000675/***********************************************************************
676 * LISTBOX_FindStringPos
677 *
678 * Find the nearest string located before a given string in sort order.
679 * If 'exact' is TRUE, return an error if we don't get an exact match.
680 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000681static INT LISTBOX_FindStringPos( WND *wnd, LB_DESCR *descr, LPCSTR str,
682 BOOL exact )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000683{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000684 INT index, min, max, res = -1;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000685
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000686 if (!(descr->style & LBS_SORT)) return -1; /* Add it at the end */
687 min = 0;
688 max = descr->nb_items;
689 while (min != max)
690 {
691 index = (min + max) / 2;
692 if (HAS_STRINGS(descr))
Alexandre Julliarda3960291999-02-26 11:11:13 +0000693 res = lstrcmpiA( descr->items[index].str, str );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000694 else
695 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000696 COMPAREITEMSTRUCT cis;
697 UINT id = (descr->lphc) ? ID_CB_LISTBOX : wnd->wIDmenu;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000698
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000699 cis.CtlType = ODT_LISTBOX;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000700 cis.CtlID = id;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000701 cis.hwndItem = wnd->hwndSelf;
702 cis.itemID1 = index;
703 cis.itemData1 = descr->items[index].data;
704 cis.itemID2 = -1;
705 cis.itemData2 = (DWORD)str;
706 cis.dwLocaleId = descr->locale;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000707 res = SendMessageA( descr->owner, WM_COMPAREITEM,
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000708 id, (LPARAM)&cis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000709 }
710 if (!res) return index;
711 if (res > 0) max = index;
712 else min = index + 1;
713 }
714 return exact ? -1 : max;
Alexandre Julliard2787be81995-05-22 18:23:01 +0000715}
716
717
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000718/***********************************************************************
719 * LISTBOX_FindFileStrPos
720 *
721 * Find the nearest string located before a given string in directory
722 * sort order (i.e. first files, then directories, then drives).
723 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000724static INT LISTBOX_FindFileStrPos( WND *wnd, LB_DESCR *descr, LPCSTR str )
Alexandre Julliard2787be81995-05-22 18:23:01 +0000725{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000726 INT min, max, res = -1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000727
728 if (!HAS_STRINGS(descr))
729 return LISTBOX_FindStringPos( wnd, descr, str, FALSE );
730 min = 0;
731 max = descr->nb_items;
732 while (min != max)
733 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000734 INT index = (min + max) / 2;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000735 const char *p = descr->items[index].str;
736 if (*p == '[') /* drive or directory */
737 {
738 if (*str != '[') res = -1;
739 else if (p[1] == '-') /* drive */
740 {
741 if (str[1] == '-') res = str[2] - p[2];
742 else res = -1;
743 }
744 else /* directory */
745 {
746 if (str[1] == '-') res = 1;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000747 else res = lstrcmpiA( str, p );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000748 }
749 }
750 else /* filename */
751 {
752 if (*str == '[') res = 1;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000753 else res = lstrcmpiA( str, p );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000754 }
755 if (!res) return index;
756 if (res < 0) max = index;
757 else min = index + 1;
758 }
759 return max;
760}
761
762
763/***********************************************************************
764 * LISTBOX_FindString
765 *
766 * Find the item beginning with a given string.
767 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000768static INT LISTBOX_FindString( WND *wnd, LB_DESCR *descr, INT start,
769 LPCSTR str, BOOL exact )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000770{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000771 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000772 LB_ITEMDATA *item;
773
774 if (start >= descr->nb_items) start = -1;
775 item = descr->items + start + 1;
776 if (HAS_STRINGS(descr))
777 {
Rein Klazesd35c8341999-08-21 13:04:58 +0000778 if (!str || ! str[0] ) return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000779 if (exact)
780 {
781 for (i = start + 1; i < descr->nb_items; i++, item++)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000782 if (!lstrcmpiA( str, item->str )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000783 for (i = 0, item = descr->items; i <= start; i++, item++)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000784 if (!lstrcmpiA( str, item->str )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000785 }
786 else
787 {
788 /* Special case for drives and directories: ignore prefix */
789#define CHECK_DRIVE(item) \
790 if ((item)->str[0] == '[') \
791 { \
Alexandre Julliarda3960291999-02-26 11:11:13 +0000792 if (!lstrncmpiA( str, (item)->str+1, len )) return i; \
793 if (((item)->str[1] == '-') && !lstrncmpiA(str,(item)->str+2,len)) \
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000794 return i; \
795 }
796
Alexandre Julliarda3960291999-02-26 11:11:13 +0000797 INT len = strlen(str);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000798 for (i = start + 1; i < descr->nb_items; i++, item++)
799 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000800 if (!lstrncmpiA( str, item->str, len )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000801 CHECK_DRIVE(item);
802 }
803 for (i = 0, item = descr->items; i <= start; i++, item++)
804 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000805 if (!lstrncmpiA( str, item->str, len )) return i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000806 CHECK_DRIVE(item);
807 }
808#undef CHECK_DRIVE
809 }
810 }
811 else
812 {
813 if (exact && (descr->style & LBS_SORT))
814 /* If sorted, use a WM_COMPAREITEM binary search */
815 return LISTBOX_FindStringPos( wnd, descr, str, TRUE );
816
817 /* Otherwise use a linear search */
818 for (i = start + 1; i < descr->nb_items; i++, item++)
819 if (item->data == (DWORD)str) return i;
820 for (i = 0, item = descr->items; i <= start; i++, item++)
821 if (item->data == (DWORD)str) return i;
822 }
823 return LB_ERR;
824}
825
826
827/***********************************************************************
828 * LISTBOX_GetSelCount
829 */
830static LRESULT LISTBOX_GetSelCount( WND *wnd, LB_DESCR *descr )
831{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000832 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000833 LB_ITEMDATA *item = descr->items;
834
835 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
836 for (i = count = 0; i < descr->nb_items; i++, item++)
837 if (item->selected) count++;
838 return count;
839}
840
841
842/***********************************************************************
843 * LISTBOX_GetSelItems16
844 */
845static LRESULT LISTBOX_GetSelItems16( WND *wnd, LB_DESCR *descr, INT16 max,
846 LPINT16 array )
847{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000848 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000849 LB_ITEMDATA *item = descr->items;
850
851 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
852 for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++)
853 if (item->selected) array[count++] = (INT16)i;
854 return count;
855}
856
857
858/***********************************************************************
859 * LISTBOX_GetSelItems32
860 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000861static LRESULT LISTBOX_GetSelItems( WND *wnd, LB_DESCR *descr, INT max,
862 LPINT array )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000863{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000864 INT i, count;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000865 LB_ITEMDATA *item = descr->items;
866
867 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
868 for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++)
869 if (item->selected) array[count++] = i;
870 return count;
871}
872
873
874/***********************************************************************
875 * LISTBOX_Paint
876 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000877static LRESULT LISTBOX_Paint( WND *wnd, LB_DESCR *descr, HDC hdc )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000878{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000879 INT i, col_pos = descr->page_size - 1;
880 RECT rect;
881 HFONT oldFont = 0;
882 HBRUSH hbrush, oldBrush = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000883
Alexandre Julliarda3960291999-02-26 11:11:13 +0000884 SetRect( &rect, 0, 0, descr->width, descr->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000885 if (descr->style & LBS_NOREDRAW) return 0;
886 if (descr->style & LBS_MULTICOLUMN)
887 rect.right = rect.left + descr->column_width;
888 else if (descr->horz_pos)
889 {
Alexandre Julliarda3960291999-02-26 11:11:13 +0000890 SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000891 rect.right += descr->horz_pos;
892 }
893
Alexandre Julliarda3960291999-02-26 11:11:13 +0000894 if (descr->font) oldFont = SelectObject( hdc, descr->font );
895 hbrush = SendMessageA( descr->owner, WM_CTLCOLORLISTBOX,
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000896 hdc, (LPARAM)wnd->hwndSelf );
Alexandre Julliarda3960291999-02-26 11:11:13 +0000897 if (hbrush) oldBrush = SelectObject( hdc, hbrush );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +0000898 if (wnd->dwStyle & WS_DISABLED)
Alexandre Julliarda3960291999-02-26 11:11:13 +0000899 SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000900
901 if (!descr->nb_items && (descr->focus_item != -1) && descr->caret_on &&
Alexandre Julliarda3960291999-02-26 11:11:13 +0000902 (GetFocus() == wnd->hwndSelf))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000903 {
904 /* Special case for empty listbox: paint focus rect */
905 rect.bottom = rect.top + descr->item_height;
906 LISTBOX_PaintItem( wnd, descr, hdc, &rect, descr->focus_item,
Gerard Patelc979b7b1998-12-24 16:25:50 +0000907 ODA_FOCUS );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000908 rect.top = rect.bottom;
909 }
910
911 for (i = descr->top_item; i < descr->nb_items; i++)
912 {
913 if (!(descr->style & LBS_OWNERDRAWVARIABLE))
914 rect.bottom = rect.top + descr->item_height;
915 else
916 rect.bottom = rect.top + descr->items[i].height;
917
918 LISTBOX_PaintItem( wnd, descr, hdc, &rect, i, ODA_DRAWENTIRE );
919 rect.top = rect.bottom;
920
921 if ((descr->style & LBS_MULTICOLUMN) && !col_pos)
922 {
923 if (!IS_OWNERDRAW(descr))
924 {
925 /* Clear the bottom of the column */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000926 SetBkColor( hdc, GetSysColor( COLOR_WINDOW ) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000927 if (rect.top < descr->height)
928 {
929 rect.bottom = descr->height;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000930 ExtTextOutA( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000931 &rect, NULL, 0, NULL );
932 }
933 }
934
935 /* Go to the next column */
936 rect.left += descr->column_width;
937 rect.right += descr->column_width;
938 rect.top = 0;
939 col_pos = descr->page_size - 1;
940 }
941 else
942 {
943 col_pos--;
944 if (rect.top >= descr->height) break;
945 }
946 }
947
948 if (!IS_OWNERDRAW(descr))
949 {
950 /* Clear the remainder of the client area */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000951 SetBkColor( hdc, GetSysColor( COLOR_WINDOW ) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000952 if (rect.top < descr->height)
953 {
954 rect.bottom = descr->height;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000955 ExtTextOutA( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000956 &rect, NULL, 0, NULL );
957 }
958 if (rect.right < descr->width)
959 {
960 rect.left = rect.right;
961 rect.right = descr->width;
962 rect.top = 0;
963 rect.bottom = descr->height;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000964 ExtTextOutA( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000965 &rect, NULL, 0, NULL );
966 }
967 }
Alexandre Julliarda3960291999-02-26 11:11:13 +0000968 if (oldFont) SelectObject( hdc, oldFont );
969 if (oldBrush) SelectObject( hdc, oldBrush );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000970 return 0;
971}
972
973
974/***********************************************************************
975 * LISTBOX_InvalidateItems
976 *
977 * Invalidate all items from a given item. If the specified item is not
978 * visible, nothing happens.
979 */
Alexandre Julliarda3960291999-02-26 11:11:13 +0000980static void LISTBOX_InvalidateItems( WND *wnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000981{
Alexandre Julliarda3960291999-02-26 11:11:13 +0000982 RECT rect;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000983
984 if (LISTBOX_GetItemRect( wnd, descr, index, &rect ) == 1)
985 {
986 rect.bottom = descr->height;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000987 InvalidateRect( wnd->hwndSelf, &rect, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000988 if (descr->style & LBS_MULTICOLUMN)
989 {
990 /* Repaint the other columns */
991 rect.left = rect.right;
992 rect.right = descr->width;
993 rect.top = 0;
Alexandre Julliarda3960291999-02-26 11:11:13 +0000994 InvalidateRect( wnd->hwndSelf, &rect, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +0000995 }
996 }
997}
998
999
1000/***********************************************************************
1001 * LISTBOX_GetItemHeight
1002 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001003static LRESULT LISTBOX_GetItemHeight( WND *wnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001004{
1005 if (descr->style & LBS_OWNERDRAWVARIABLE)
1006 {
1007 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
1008 return descr->items[index].height;
1009 }
1010 else return descr->item_height;
1011}
1012
1013
1014/***********************************************************************
1015 * LISTBOX_SetItemHeight
1016 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001017static LRESULT LISTBOX_SetItemHeight( WND *wnd, LB_DESCR *descr, INT index,
1018 UINT height )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001019{
1020 if (!height) height = 1;
1021
1022 if (descr->style & LBS_OWNERDRAWVARIABLE)
1023 {
1024 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001025 TRACE("[%04x]: item %d height = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001026 wnd->hwndSelf, index, height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001027 descr->items[index].height = height;
1028 LISTBOX_UpdateScroll( wnd, descr );
1029 LISTBOX_InvalidateItems( wnd, descr, index );
1030 }
1031 else if (height != descr->item_height)
1032 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001033 TRACE("[%04x]: new height = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001034 wnd->hwndSelf, height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001035 descr->item_height = height;
1036 LISTBOX_UpdatePage( wnd, descr );
1037 LISTBOX_UpdateScroll( wnd, descr );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001038 InvalidateRect( wnd->hwndSelf, 0, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001039 }
1040 return LB_OKAY;
1041}
1042
1043
1044/***********************************************************************
1045 * LISTBOX_SetHorizontalPos
1046 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001047static void LISTBOX_SetHorizontalPos( WND *wnd, LB_DESCR *descr, INT pos )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001048{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001049 INT diff;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001050
1051 if (pos > descr->horz_extent - descr->width)
1052 pos = descr->horz_extent - descr->width;
1053 if (pos < 0) pos = 0;
1054 if (!(diff = descr->horz_pos - pos)) return;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001055 TRACE("[%04x]: new horz pos = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001056 wnd->hwndSelf, pos );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001057 descr->horz_pos = pos;
1058 LISTBOX_UpdateScroll( wnd, descr );
1059 if (abs(diff) < descr->width)
Alexandre Julliarda3960291999-02-26 11:11:13 +00001060 ScrollWindowEx( wnd->hwndSelf, diff, 0, NULL, NULL, 0, NULL,
NF Stevens762f18d1999-01-24 19:02:16 +00001061 SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001062 else
Alexandre Julliarda3960291999-02-26 11:11:13 +00001063 InvalidateRect( wnd->hwndSelf, NULL, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001064}
1065
1066
1067/***********************************************************************
1068 * LISTBOX_SetHorizontalExtent
1069 */
1070static LRESULT LISTBOX_SetHorizontalExtent( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001071 UINT extent )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001072{
1073 if (!descr->horz_extent || (descr->style & LBS_MULTICOLUMN))
1074 return LB_OKAY;
1075 if (extent <= 0) extent = 1;
1076 if (extent == descr->horz_extent) return LB_OKAY;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001077 TRACE("[%04x]: new horz extent = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001078 wnd->hwndSelf, extent );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001079 descr->horz_extent = extent;
1080 if (descr->horz_pos > extent - descr->width)
1081 LISTBOX_SetHorizontalPos( wnd, descr, extent - descr->width );
1082 else
1083 LISTBOX_UpdateScroll( wnd, descr );
1084 return LB_OKAY;
1085}
1086
1087
1088/***********************************************************************
1089 * LISTBOX_SetColumnWidth
1090 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001091static LRESULT LISTBOX_SetColumnWidth( WND *wnd, LB_DESCR *descr, UINT width)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001092{
1093 width += 2; /* For left and right margin */
1094 if (width == descr->column_width) return LB_OKAY;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001095 TRACE("[%04x]: new column width = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001096 wnd->hwndSelf, width );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001097 descr->column_width = width;
1098 LISTBOX_UpdatePage( wnd, descr );
1099 return LB_OKAY;
1100}
1101
1102
1103/***********************************************************************
1104 * LISTBOX_SetFont
1105 *
1106 * Returns the item height.
1107 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001108static INT LISTBOX_SetFont( WND *wnd, LB_DESCR *descr, HFONT font )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001109{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001110 HDC hdc;
1111 HFONT oldFont = 0;
1112 TEXTMETRICA tm;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001113
1114 descr->font = font;
1115
Alexandre Julliarda3960291999-02-26 11:11:13 +00001116 if (!(hdc = GetDCEx( wnd->hwndSelf, 0, DCX_CACHE )))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001117 {
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001118 ERR("unable to get DC.\n" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001119 return 16;
1120 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001121 if (font) oldFont = SelectObject( hdc, font );
1122 GetTextMetricsA( hdc, &tm );
1123 if (oldFont) SelectObject( hdc, oldFont );
1124 ReleaseDC( wnd->hwndSelf, hdc );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001125 if (!IS_OWNERDRAW(descr))
Alexandre Julliarddadf78f1998-05-17 17:13:43 +00001126 LISTBOX_SetItemHeight( wnd, descr, 0, tm.tmHeight );
1127 return tm.tmHeight ;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001128}
1129
1130
1131/***********************************************************************
1132 * LISTBOX_MakeItemVisible
1133 *
1134 * Make sure that a given item is partially or fully visible.
1135 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001136static void LISTBOX_MakeItemVisible( WND *wnd, LB_DESCR *descr, INT index,
1137 BOOL fully )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001138{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001139 INT top;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001140
1141 if (index <= descr->top_item) top = index;
1142 else if (descr->style & LBS_MULTICOLUMN)
1143 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001144 INT cols = descr->width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001145 if (!fully) cols += descr->column_width - 1;
1146 if (cols >= descr->column_width) cols /= descr->column_width;
1147 else cols = 1;
1148 if (index < descr->top_item + (descr->page_size * cols)) return;
1149 top = index - descr->page_size * (cols - 1);
1150 }
1151 else if (descr->style & LBS_OWNERDRAWVARIABLE)
1152 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001153 INT height = fully ? descr->items[index].height : 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001154 for (top = index; top > descr->top_item; top--)
1155 if ((height += descr->items[top-1].height) > descr->height) break;
1156 }
1157 else
1158 {
1159 if (index < descr->top_item + descr->page_size) return;
1160 if (!fully && (index == descr->top_item + descr->page_size) &&
1161 (descr->height > (descr->page_size * descr->item_height))) return;
1162 top = index - descr->page_size + 1;
1163 }
1164 LISTBOX_SetTopItem( wnd, descr, top, TRUE );
1165}
1166
1167
1168/***********************************************************************
1169 * LISTBOX_SelectItemRange
1170 *
1171 * Select a range of items. Should only be used on a MULTIPLESEL listbox.
1172 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001173static LRESULT LISTBOX_SelectItemRange( WND *wnd, LB_DESCR *descr, INT first,
1174 INT last, BOOL on )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001175{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001176 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001177
1178 /* A few sanity checks */
1179
Alexandre Julliard03468f71998-02-15 19:40:49 +00001180 if ((last == -1) && (descr->nb_items == 0)) return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001181 if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
1182 if (last == -1) last = descr->nb_items - 1;
1183 if ((first < 0) || (first >= descr->nb_items)) return LB_ERR;
1184 if ((last < 0) || (last >= descr->nb_items)) return LB_ERR;
1185 /* selected_item reflects last selected/unselected item on multiple sel */
1186 descr->selected_item = last;
1187
1188 if (on) /* Turn selection on */
1189 {
1190 for (i = first; i <= last; i++)
1191 {
1192 if (descr->items[i].selected) continue;
1193 descr->items[i].selected = TRUE;
1194 LISTBOX_RepaintItem( wnd, descr, i, ODA_SELECT );
1195 }
1196 }
1197 else /* Turn selection off */
1198 {
1199 for (i = first; i <= last; i++)
1200 {
1201 if (!descr->items[i].selected) continue;
1202 descr->items[i].selected = FALSE;
1203 LISTBOX_RepaintItem( wnd, descr, i, ODA_SELECT );
1204 }
1205 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001206 return LB_OKAY;
1207}
1208
1209
1210/***********************************************************************
1211 * LISTBOX_SetCaretIndex
Alexandre Julliard638f1691999-01-17 16:32:32 +00001212 *
1213 * NOTES
1214 * index must be between 0 and descr->nb_items-1, or LB_ERR is returned.
1215 *
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001216 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001217static LRESULT LISTBOX_SetCaretIndex( WND *wnd, LB_DESCR *descr, INT index,
1218 BOOL fully_visible )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001219{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001220 INT oldfocus = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001221
Alexandre Julliard638f1691999-01-17 16:32:32 +00001222 if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001223 if (index == oldfocus) return LB_OKAY;
1224 descr->focus_item = index;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001225 if ((oldfocus != -1) && descr->caret_on && (GetFocus() == wnd->hwndSelf))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001226 LISTBOX_RepaintItem( wnd, descr, oldfocus, ODA_FOCUS );
Alexandre Julliard638f1691999-01-17 16:32:32 +00001227
1228 LISTBOX_MakeItemVisible( wnd, descr, index, fully_visible );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001229 if (descr->caret_on && (GetFocus() == wnd->hwndSelf))
Alexandre Julliard638f1691999-01-17 16:32:32 +00001230 LISTBOX_RepaintItem( wnd, descr, index, ODA_FOCUS );
1231
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001232 return LB_OKAY;
1233}
1234
1235
1236/***********************************************************************
1237 * LISTBOX_SetSelection
1238 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001239static LRESULT LISTBOX_SetSelection( WND *wnd, LB_DESCR *descr, INT index,
1240 BOOL on, BOOL send_notify )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001241{
1242 if ((index < -1) || (index >= descr->nb_items)) return LB_ERR;
1243 if (descr->style & LBS_MULTIPLESEL)
1244 {
1245 if (index == -1) /* Select all items */
1246 return LISTBOX_SelectItemRange( wnd, descr, 0, -1, on );
1247 else /* Only one item */
1248 return LISTBOX_SelectItemRange( wnd, descr, index, index, on );
1249 }
1250 else
1251 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001252 INT oldsel = descr->selected_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001253 if (index == oldsel) return LB_OKAY;
1254 if (oldsel != -1) descr->items[oldsel].selected = FALSE;
1255 if (index != -1) descr->items[index].selected = TRUE;
1256 descr->selected_item = index;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001257 if (oldsel != -1) LISTBOX_RepaintItem( wnd, descr, oldsel, ODA_SELECT);
1258 if (index != -1) LISTBOX_RepaintItem( wnd, descr, index, ODA_SELECT );
Gerard Patelc9a6d501999-07-25 13:03:17 +00001259 if (send_notify && descr->nb_items) SEND_NOTIFICATION( wnd, descr,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001260 (index != -1) ? LBN_SELCHANGE : LBN_SELCANCEL );
Alex Korobka311d3291999-01-01 18:40:02 +00001261 else
1262 if( descr->lphc ) /* set selection change flag for parent combo */
1263 descr->lphc->wState |= CBF_SELCHANGE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001264 }
1265 return LB_OKAY;
1266}
1267
1268
1269/***********************************************************************
1270 * LISTBOX_MoveCaret
1271 *
1272 * Change the caret position and extend the selection to the new caret.
1273 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001274static void LISTBOX_MoveCaret( WND *wnd, LB_DESCR *descr, INT index,
1275 BOOL fully_visible )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001276{
1277 LISTBOX_SetCaretIndex( wnd, descr, index, fully_visible );
1278 if (descr->style & LBS_EXTENDEDSEL)
1279 {
1280 if (descr->anchor_item != -1)
1281 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001282 INT first = MIN( descr->focus_item, descr->anchor_item );
1283 INT last = MAX( descr->focus_item, descr->anchor_item );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001284 if (first > 0)
1285 LISTBOX_SelectItemRange( wnd, descr, 0, first - 1, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001286 LISTBOX_SelectItemRange( wnd, descr, last + 1, -1, FALSE );
Alexandre Julliardb1bac321996-12-15 19:45:59 +00001287 LISTBOX_SelectItemRange( wnd, descr, first, last, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001288 }
1289 }
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00001290 else if (!(descr->style & LBS_MULTIPLESEL))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001291 {
1292 /* Set selection to new caret item */
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00001293 LISTBOX_SetSelection( wnd, descr, index, TRUE, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001294 }
1295}
1296
1297
1298/***********************************************************************
1299 * LISTBOX_InsertItem
1300 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001301static LRESULT LISTBOX_InsertItem( WND *wnd, LB_DESCR *descr, INT index,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001302 LPSTR str, DWORD data )
1303{
1304 LB_ITEMDATA *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001305 INT max_items;
Gerard Patelc9a6d501999-07-25 13:03:17 +00001306 INT oldfocus = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001307
1308 if (index == -1) index = descr->nb_items;
1309 else if ((index < 0) || (index > descr->nb_items)) return LB_ERR;
1310 if (!descr->items) max_items = 0;
1311 else max_items = HeapSize( descr->heap, 0, descr->items ) / sizeof(*item);
1312 if (descr->nb_items == max_items)
1313 {
1314 /* We need to grow the array */
1315 max_items += LB_ARRAY_GRANULARITY;
1316 if (!(item = HeapReAlloc( descr->heap, 0, descr->items,
1317 max_items * sizeof(LB_ITEMDATA) )))
1318 {
1319 SEND_NOTIFICATION( wnd, descr, LBN_ERRSPACE );
1320 return LB_ERRSPACE;
1321 }
1322 descr->items = item;
1323 }
1324
1325 /* Insert the item structure */
1326
1327 item = &descr->items[index];
1328 if (index < descr->nb_items)
1329 RtlMoveMemory( item + 1, item,
1330 (descr->nb_items - index) * sizeof(LB_ITEMDATA) );
1331 item->str = str;
1332 item->data = data;
1333 item->height = 0;
1334 item->selected = FALSE;
1335 descr->nb_items++;
1336
1337 /* Get item height */
1338
1339 if (descr->style & LBS_OWNERDRAWVARIABLE)
1340 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001341 MEASUREITEMSTRUCT mis;
1342 UINT id = (descr->lphc) ? ID_CB_LISTBOX : wnd->wIDmenu;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001343
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001344 mis.CtlType = ODT_LISTBOX;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001345 mis.CtlID = id;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001346 mis.itemID = index;
1347 mis.itemData = descr->items[index].data;
1348 mis.itemHeight = descr->item_height;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001349 SendMessageA( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001350 item->height = mis.itemHeight ? mis.itemHeight : 1;
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001351 TRACE("[%04x]: measure item %d (%s) = %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001352 wnd->hwndSelf, index, str ? str : "", item->height );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001353 }
1354
1355 /* Repaint the items */
1356
1357 LISTBOX_UpdateScroll( wnd, descr );
1358 LISTBOX_InvalidateItems( wnd, descr, index );
1359
1360 /* Move selection and focused item */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001361 /* If listbox was empty, set focus to the first item */
Gerard Patelc9a6d501999-07-25 13:03:17 +00001362 if (descr->nb_items == 1)
1363 LISTBOX_SetCaretIndex( wnd, descr, 0, FALSE );
1364 /* single select don't change selection index in win31 */
1365 else if ((ISWIN31) && !(IS_MULTISELECT(descr)))
1366 {
1367 descr->selected_item++;
1368 LISTBOX_SetSelection( wnd, descr, descr->selected_item-1, TRUE, FALSE );
1369 }
1370 else
1371 {
1372 if (index <= descr->selected_item)
1373 {
1374 descr->selected_item++;
1375 descr->focus_item = oldfocus; /* focus not changed */
1376 }
1377 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001378 return LB_OKAY;
1379}
1380
1381
1382/***********************************************************************
1383 * LISTBOX_InsertString
1384 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001385static LRESULT LISTBOX_InsertString( WND *wnd, LB_DESCR *descr, INT index,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001386 LPCSTR str )
1387{
1388 LPSTR new_str = NULL;
1389 DWORD data = 0;
1390 LRESULT ret;
1391
1392 if (HAS_STRINGS(descr))
1393 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00001394 if (!str) str="";
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001395 if (!(new_str = HEAP_strdupA( descr->heap, 0, str )))
1396 {
1397 SEND_NOTIFICATION( wnd, descr, LBN_ERRSPACE );
1398 return LB_ERRSPACE;
1399 }
1400 }
1401 else data = (DWORD)str;
1402
1403 if (index == -1) index = descr->nb_items;
1404 if ((ret = LISTBOX_InsertItem( wnd, descr, index, new_str, data )) != 0)
1405 {
1406 if (new_str) HeapFree( descr->heap, 0, new_str );
1407 return ret;
1408 }
1409
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001410 TRACE("[%04x]: added item %d '%s'\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001411 wnd->hwndSelf, index, HAS_STRINGS(descr) ? new_str : "" );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001412 return index;
1413}
1414
1415
1416/***********************************************************************
1417 * LISTBOX_DeleteItem
1418 *
1419 * Delete the content of an item. 'index' must be a valid index.
1420 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001421static void LISTBOX_DeleteItem( WND *wnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001422{
1423 /* Note: Win 3.1 only sends DELETEITEM on owner-draw items,
1424 * while Win95 sends it for all items with user data.
1425 * It's probably better to send it too often than not
1426 * often enough, so this is what we do here.
1427 */
1428 if (IS_OWNERDRAW(descr) || descr->items[index].data)
1429 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001430 DELETEITEMSTRUCT dis;
1431 UINT id = (descr->lphc) ? ID_CB_LISTBOX : wnd->wIDmenu;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001432
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001433 dis.CtlType = ODT_LISTBOX;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001434 dis.CtlID = id;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001435 dis.itemID = index;
1436 dis.hwndItem = wnd->hwndSelf;
1437 dis.itemData = descr->items[index].data;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001438 SendMessageA( descr->owner, WM_DELETEITEM, id, (LPARAM)&dis );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001439 }
1440 if (HAS_STRINGS(descr) && descr->items[index].str)
1441 HeapFree( descr->heap, 0, descr->items[index].str );
1442}
1443
1444
1445/***********************************************************************
1446 * LISTBOX_RemoveItem
1447 *
1448 * Remove an item from the listbox and delete its content.
1449 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001450static LRESULT LISTBOX_RemoveItem( WND *wnd, LB_DESCR *descr, INT index )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001451{
1452 LB_ITEMDATA *item;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001453 INT max_items;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001454
1455 if (index == -1) index = descr->nb_items - 1;
1456 else if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
1457 LISTBOX_DeleteItem( wnd, descr, index );
1458
1459 /* Remove the item */
1460
1461 item = &descr->items[index];
1462 if (index < descr->nb_items-1)
1463 RtlMoveMemory( item, item + 1,
1464 (descr->nb_items - index - 1) * sizeof(LB_ITEMDATA) );
1465 descr->nb_items--;
1466 if (descr->anchor_item == descr->nb_items) descr->anchor_item--;
1467
1468 /* Shrink the item array if possible */
1469
1470 max_items = HeapSize( descr->heap, 0, descr->items ) / sizeof(LB_ITEMDATA);
1471 if (descr->nb_items < max_items - 2*LB_ARRAY_GRANULARITY)
1472 {
1473 max_items -= LB_ARRAY_GRANULARITY;
1474 item = HeapReAlloc( descr->heap, 0, descr->items,
1475 max_items * sizeof(LB_ITEMDATA) );
1476 if (item) descr->items = item;
1477 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001478 /* Repaint the items */
1479
1480 LISTBOX_UpdateScroll( wnd, descr );
Gerard Patelc9a6d501999-07-25 13:03:17 +00001481 /* if we removed the scrollbar, reset the top of the list
1482 (correct for owner-drawn ???) */
1483 if (descr->nb_items == descr->page_size)
1484 LISTBOX_SetTopItem( wnd, descr, 0, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001485
1486 /* Move selection and focused item */
Gerard Patelc9a6d501999-07-25 13:03:17 +00001487 if (!IS_MULTISELECT(descr))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001488 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00001489 if (index == descr->selected_item)
1490 descr->selected_item = -1;
1491 else if (index < descr->selected_item)
1492 {
1493 descr->selected_item--;
1494 if (ISWIN31) /* win 31 do not change the selected item number */
1495 LISTBOX_SetSelection( wnd, descr, descr->selected_item + 1, TRUE, FALSE);
1496 }
1497 }
1498 LISTBOX_InvalidateItems( wnd, descr, index );
1499 if (descr->focus_item >= descr->nb_items)
1500 {
1501 descr->focus_item = descr->nb_items - 1;
1502 if (descr->focus_item < 0) descr->focus_item = 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001503 }
1504 return LB_OKAY;
1505}
1506
1507
1508/***********************************************************************
1509 * LISTBOX_ResetContent
1510 */
1511static void LISTBOX_ResetContent( WND *wnd, LB_DESCR *descr )
1512{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001513 INT i;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001514
1515 for (i = 0; i < descr->nb_items; i++) LISTBOX_DeleteItem( wnd, descr, i );
1516 if (descr->items) HeapFree( descr->heap, 0, descr->items );
1517 descr->nb_items = 0;
1518 descr->top_item = 0;
1519 descr->selected_item = -1;
1520 descr->focus_item = 0;
1521 descr->anchor_item = -1;
1522 descr->items = NULL;
1523 LISTBOX_UpdateScroll( wnd, descr );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001524 InvalidateRect( wnd->hwndSelf, NULL, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001525}
1526
1527
1528/***********************************************************************
1529 * LISTBOX_SetCount
1530 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001531static LRESULT LISTBOX_SetCount( WND *wnd, LB_DESCR *descr, INT count )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001532{
1533 LRESULT ret;
1534
1535 if (HAS_STRINGS(descr)) return LB_ERR;
1536 /* FIXME: this is far from optimal... */
1537 if (count > descr->nb_items)
1538 {
1539 while (count > descr->nb_items)
1540 if ((ret = LISTBOX_InsertString( wnd, descr, -1, 0 )) < 0)
1541 return ret;
1542 }
1543 else if (count < descr->nb_items)
1544 {
1545 while (count < descr->nb_items)
1546 if ((ret = LISTBOX_RemoveItem( wnd, descr, -1 )) < 0)
1547 return ret;
1548 }
1549 return LB_OKAY;
1550}
1551
1552
1553/***********************************************************************
1554 * LISTBOX_Directory
1555 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00001556static LRESULT LISTBOX_Directory( WND *wnd, LB_DESCR *descr, UINT attrib,
1557 LPCSTR filespec, BOOL long_names )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001558{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001559 HANDLE handle;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001560 LRESULT ret = LB_OKAY;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001561 WIN32_FIND_DATAA entry;
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001562 int pos;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001563
Alexandre Julliarda3960291999-02-26 11:11:13 +00001564 if ((handle = FindFirstFileA(filespec,&entry)) == INVALID_HANDLE_VALUE)
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001565 {
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001566 if (GetLastError() != ERROR_NO_MORE_FILES) return LB_ERR;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001567 }
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001568 else
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001569 {
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001570 do
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001571 {
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001572 char buffer[270];
1573 if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1574 {
1575 if (!(attrib & DDL_DIRECTORY) ||
1576 !strcmp( entry.cAlternateFileName, "." )) continue;
1577 if (long_names) sprintf( buffer, "[%s]", entry.cFileName );
1578 else sprintf( buffer, "[%s]", entry.cAlternateFileName );
1579 }
1580 else /* not a directory */
1581 {
1582#define ATTRIBS (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
1583 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE)
1584
1585 if ((attrib & DDL_EXCLUSIVE) &&
1586 ((attrib & ATTRIBS) != (entry.dwFileAttributes & ATTRIBS)))
1587 continue;
1588#undef ATTRIBS
1589 if (long_names) strcpy( buffer, entry.cFileName );
1590 else strcpy( buffer, entry.cAlternateFileName );
1591 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00001592 if (!long_names) CharLowerA( buffer );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001593 pos = LISTBOX_FindFileStrPos( wnd, descr, buffer );
1594 if ((ret = LISTBOX_InsertString( wnd, descr, pos, buffer )) < 0)
1595 break;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001596 } while (FindNextFileA( handle, &entry ));
1597 FindClose( handle );
Alexandre Julliard2787be81995-05-22 18:23:01 +00001598 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001599
Alexandre Julliard889f7421997-04-15 17:19:52 +00001600 if ((ret >= 0) && (attrib & DDL_DRIVES))
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001601 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001602 char buffer[] = "[-a-]";
1603 int drive;
1604 for (drive = 0; drive < MAX_DOS_DRIVES; drive++, buffer[2]++)
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001605 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001606 if (!DRIVE_IsValid(drive)) continue;
1607 if ((ret = LISTBOX_InsertString( wnd, descr, -1, buffer )) < 0)
1608 break;
Alexandre Julliard4f8c37b1996-01-14 18:12:01 +00001609 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001610 }
Alexandre Julliard7e56f681996-01-31 19:02:28 +00001611 return ret;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001612}
1613
1614
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001615/***********************************************************************
1616 * LISTBOX_HandleVScroll
1617 */
1618static LRESULT LISTBOX_HandleVScroll( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001619 WPARAM wParam, LPARAM lParam )
Alexandre Julliard2787be81995-05-22 18:23:01 +00001620{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001621 SCROLLINFO info;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001622
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001623 if (descr->style & LBS_MULTICOLUMN) return 0;
1624 switch(LOWORD(wParam))
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +00001625 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001626 case SB_LINEUP:
1627 LISTBOX_SetTopItem( wnd, descr, descr->top_item - 1, TRUE );
1628 break;
1629 case SB_LINEDOWN:
1630 LISTBOX_SetTopItem( wnd, descr, descr->top_item + 1, TRUE );
1631 break;
1632 case SB_PAGEUP:
1633 LISTBOX_SetTopItem( wnd, descr, descr->top_item -
1634 LISTBOX_GetCurrentPageSize( wnd, descr ), TRUE );
1635 break;
1636 case SB_PAGEDOWN:
1637 LISTBOX_SetTopItem( wnd, descr, descr->top_item +
1638 LISTBOX_GetCurrentPageSize( wnd, descr ), TRUE );
1639 break;
1640 case SB_THUMBPOSITION:
1641 LISTBOX_SetTopItem( wnd, descr, HIWORD(wParam), TRUE );
1642 break;
1643 case SB_THUMBTRACK:
1644 info.cbSize = sizeof(info);
1645 info.fMask = SIF_TRACKPOS;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001646 GetScrollInfo( wnd->hwndSelf, SB_VERT, &info );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001647 LISTBOX_SetTopItem( wnd, descr, info.nTrackPos, TRUE );
1648 break;
1649 case SB_TOP:
1650 LISTBOX_SetTopItem( wnd, descr, 0, TRUE );
1651 break;
1652 case SB_BOTTOM:
1653 LISTBOX_SetTopItem( wnd, descr, descr->nb_items, TRUE );
1654 break;
Alexandre Julliard2c69f6d1996-09-28 18:11:01 +00001655 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001656 return 0;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001657}
1658
Alexandre Julliardb817f4f1996-03-14 18:08:34 +00001659
Alexandre Julliard2787be81995-05-22 18:23:01 +00001660/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001661 * LISTBOX_HandleHScroll
Alexandre Julliard2787be81995-05-22 18:23:01 +00001662 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001663static LRESULT LISTBOX_HandleHScroll( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001664 WPARAM wParam, LPARAM lParam )
Alexandre Julliard2787be81995-05-22 18:23:01 +00001665{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001666 SCROLLINFO info;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001667 INT page;
Alexandre Julliard2787be81995-05-22 18:23:01 +00001668
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001669 if (descr->style & LBS_MULTICOLUMN)
1670 {
1671 switch(LOWORD(wParam))
1672 {
1673 case SB_LINELEFT:
1674 LISTBOX_SetTopItem( wnd, descr, descr->top_item-descr->page_size,
1675 TRUE );
1676 break;
1677 case SB_LINERIGHT:
1678 LISTBOX_SetTopItem( wnd, descr, descr->top_item+descr->page_size,
1679 TRUE );
1680 break;
1681 case SB_PAGELEFT:
1682 page = descr->width / descr->column_width;
1683 if (page < 1) page = 1;
1684 LISTBOX_SetTopItem( wnd, descr,
1685 descr->top_item - page * descr->page_size, TRUE );
1686 break;
1687 case SB_PAGERIGHT:
1688 page = descr->width / descr->column_width;
1689 if (page < 1) page = 1;
1690 LISTBOX_SetTopItem( wnd, descr,
1691 descr->top_item + page * descr->page_size, TRUE );
1692 break;
1693 case SB_THUMBPOSITION:
1694 LISTBOX_SetTopItem( wnd, descr, HIWORD(wParam)*descr->page_size,
1695 TRUE );
1696 break;
1697 case SB_THUMBTRACK:
1698 info.cbSize = sizeof(info);
1699 info.fMask = SIF_TRACKPOS;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001700 GetScrollInfo( wnd->hwndSelf, SB_VERT, &info );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001701 LISTBOX_SetTopItem( wnd, descr, info.nTrackPos*descr->page_size,
1702 TRUE );
1703 break;
1704 case SB_LEFT:
1705 LISTBOX_SetTopItem( wnd, descr, 0, TRUE );
1706 break;
1707 case SB_RIGHT:
1708 LISTBOX_SetTopItem( wnd, descr, descr->nb_items, TRUE );
1709 break;
1710 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001711 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001712 else if (descr->horz_extent)
1713 {
1714 switch(LOWORD(wParam))
1715 {
1716 case SB_LINELEFT:
1717 LISTBOX_SetHorizontalPos( wnd, descr, descr->horz_pos - 1 );
1718 break;
1719 case SB_LINERIGHT:
1720 LISTBOX_SetHorizontalPos( wnd, descr, descr->horz_pos + 1 );
1721 break;
1722 case SB_PAGELEFT:
1723 LISTBOX_SetHorizontalPos( wnd, descr,
1724 descr->horz_pos - descr->width );
1725 break;
1726 case SB_PAGERIGHT:
1727 LISTBOX_SetHorizontalPos( wnd, descr,
1728 descr->horz_pos + descr->width );
1729 break;
1730 case SB_THUMBPOSITION:
1731 LISTBOX_SetHorizontalPos( wnd, descr, HIWORD(wParam) );
1732 break;
1733 case SB_THUMBTRACK:
1734 info.cbSize = sizeof(info);
1735 info.fMask = SIF_TRACKPOS;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001736 GetScrollInfo( wnd->hwndSelf, SB_HORZ, &info );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001737 LISTBOX_SetHorizontalPos( wnd, descr, info.nTrackPos );
1738 break;
1739 case SB_LEFT:
1740 LISTBOX_SetHorizontalPos( wnd, descr, 0 );
1741 break;
1742 case SB_RIGHT:
1743 LISTBOX_SetHorizontalPos( wnd, descr,
1744 descr->horz_extent - descr->width );
1745 break;
1746 }
1747 }
1748 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001749}
1750
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001751
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001752/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001753 * LISTBOX_HandleLButtonDown
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001754 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001755static LRESULT LISTBOX_HandleLButtonDown( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001756 WPARAM wParam, INT x, INT y )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001757{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001758 INT index = LISTBOX_GetItemFromPoint( wnd, descr, x, y );
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00001759 TRACE("[%04x]: lbuttondown %d,%d item %d\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00001760 wnd->hwndSelf, x, y, index );
Alexandre Julliarda3960291999-02-26 11:11:13 +00001761 if (!descr->caret_on && (GetFocus() == wnd->hwndSelf)) return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001762 if (index != -1)
1763 {
1764 if (descr->style & LBS_EXTENDEDSEL)
1765 {
1766 if (!(wParam & MK_SHIFT)) descr->anchor_item = index;
1767 if (wParam & MK_CONTROL)
1768 {
1769 LISTBOX_SetCaretIndex( wnd, descr, index, FALSE );
1770 LISTBOX_SetSelection( wnd, descr, index,
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00001771 !descr->items[index].selected, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001772 }
1773 else LISTBOX_MoveCaret( wnd, descr, index, FALSE );
1774 }
1775 else
1776 {
1777 LISTBOX_MoveCaret( wnd, descr, index, FALSE );
1778 LISTBOX_SetSelection( wnd, descr, index,
1779 (!(descr->style & LBS_MULTIPLESEL) ||
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00001780 !descr->items[index].selected), FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001781 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001782 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001783
Alexandre Julliarda3960291999-02-26 11:11:13 +00001784 if( !descr->lphc ) SetFocus( wnd->hwndSelf );
1785 else SetFocus( (descr->lphc->hWndEdit) ? descr->lphc->hWndEdit
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001786 : descr->lphc->self->hwndSelf ) ;
1787
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00001788 descr->captured = TRUE;
Alexandre Julliarda3960291999-02-26 11:11:13 +00001789 SetCapture( wnd->hwndSelf );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001790 if (index != -1 && !descr->lphc)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001791 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00001792 if (descr->style & LBS_NOTIFY )
Alexandre Julliarda3960291999-02-26 11:11:13 +00001793 SendMessageA( descr->owner, WM_LBTRACKPOINT, index,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001794 MAKELPARAM( x, y ) );
1795 if (wnd->dwExStyle & WS_EX_DRAGDETECT)
1796 {
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00001797 POINT pt;
1798
1799 pt.x = x;
1800 pt.y = y;
1801
Alexandre Julliarda3960291999-02-26 11:11:13 +00001802 if (DragDetect( wnd->hwndSelf, pt ))
1803 SendMessageA( descr->owner, WM_BEGINDRAG, 0, 0 );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001804 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001805 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001806 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001807}
1808
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001809
Pierre Mageau25c62cc1999-09-11 16:26:03 +00001810/*************************************************************************
1811 * LISTBOX_HandleLButtonDownCombo [Internal]
1812 *
1813 * Process LButtonDown message for the ComboListBox
1814 *
1815 * PARAMS
1816 * pWnd [I] The windows internal structure
1817 * pDescr [I] The ListBox internal structure
1818 * wParam [I] Key Flag (WM_LBUTTONDOWN doc for more info)
1819 * x [I] X Mouse Coordinate
1820 * y [I] Y Mouse Coordinate
1821 *
1822 * RETURNS
1823 * 0 since we are processing the WM_LBUTTONDOWN Message
1824 *
1825 * NOTES
1826 * This function is only to be used when a ListBox is a ComboListBox
1827 */
1828
1829static LRESULT LISTBOX_HandleLButtonDownCombo( WND *pWnd, LB_DESCR *pDescr,
1830 WPARAM wParam, INT x, INT y)
1831{
1832 RECT clientRect, screenRect;
1833 POINT mousePos;
1834
1835 mousePos.x = x;
1836 mousePos.y = y;
1837
1838 GetClientRect(pWnd->hwndSelf, &clientRect);
1839
1840 if(PtInRect(&clientRect, mousePos))
1841 {
1842 /* MousePos is in client, resume normal processing */
1843 return LISTBOX_HandleLButtonDown( pWnd, pDescr, wParam, x, y);
1844 }
1845 else
1846 {
1847 POINT screenMousePos;
1848 HWND hWndOldCapture;
1849
1850 /* Check the Non-Client Area */
1851 screenMousePos = mousePos;
1852 hWndOldCapture = GetCapture();
1853 ReleaseCapture();
1854 GetWindowRect(pWnd->hwndSelf, &screenRect);
1855 ClientToScreen(pWnd->hwndSelf, &screenMousePos);
1856
1857 if(!PtInRect(&screenRect, screenMousePos))
1858 {
1859 /* Close The Drop Down */
1860 SEND_NOTIFICATION( pWnd, pDescr, LBN_SELCANCEL );
1861 return 0;
1862 }
1863 else
1864 {
1865 /* Check to see the NC is a scrollbar */
1866 INT nHitTestType=0;
1867 /* Check Vertical scroll bar */
1868 if (pWnd->dwStyle & WS_VSCROLL)
1869 {
1870 clientRect.right += GetSystemMetrics(SM_CXVSCROLL);
1871 if (PtInRect( &clientRect, mousePos ))
1872 {
1873 nHitTestType = HTVSCROLL;
1874 }
1875 }
1876 /* Check horizontal scroll bar */
1877 if (pWnd->dwStyle & WS_HSCROLL)
1878 {
1879 clientRect.bottom += GetSystemMetrics(SM_CYHSCROLL);
1880 if (PtInRect( &clientRect, mousePos ))
1881 {
1882 nHitTestType = HTHSCROLL;
1883 }
1884 }
1885 /* Windows sends this message when a scrollbar is clicked
1886 */
1887
1888 if(nHitTestType != 0)
1889 {
1890 SendMessageA(pWnd->hwndSelf, WM_NCLBUTTONDOWN, nHitTestType,
1891 MAKELONG(screenMousePos.x, screenMousePos.y));
1892 }
1893 /* Resume the Capture after scrolling is complete
1894 */
1895 if(hWndOldCapture != 0)
1896 {
1897 SetCapture(hWndOldCapture);
1898 }
1899 }
1900 }
1901 return 0;
1902}
1903
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001904/***********************************************************************
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00001905 * LISTBOX_HandleLButtonUp
1906 */
1907static LRESULT LISTBOX_HandleLButtonUp( WND *wnd, LB_DESCR *descr )
1908{
1909 if (LISTBOX_Timer != LB_TIMER_NONE)
Alexandre Julliarda3960291999-02-26 11:11:13 +00001910 KillSystemTimer( wnd->hwndSelf, LB_TIMER_ID );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00001911 LISTBOX_Timer = LB_TIMER_NONE;
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00001912 if (descr->captured)
Alexandre Julliard33072e11997-06-29 18:08:02 +00001913 {
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00001914 descr->captured = FALSE;
1915 if (GetCapture() == wnd->hwndSelf) ReleaseCapture();
Gerard Patelc9a6d501999-07-25 13:03:17 +00001916 if ((descr->style & LBS_NOTIFY) && descr->nb_items)
Alexandre Julliard33072e11997-06-29 18:08:02 +00001917 SEND_NOTIFICATION( wnd, descr, LBN_SELCHANGE );
1918 }
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00001919 return 0;
1920}
1921
1922
1923/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001924 * LISTBOX_HandleTimer
Alexandre Julliardade697e1995-11-26 13:59:11 +00001925 *
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001926 * Handle scrolling upon a timer event.
1927 * Return TRUE if scrolling should continue.
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001928 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001929static LRESULT LISTBOX_HandleTimer( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001930 INT index, TIMER_DIRECTION dir )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001931{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001932 switch(dir)
Alexandre Julliardade697e1995-11-26 13:59:11 +00001933 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001934 case LB_TIMER_UP:
1935 if (descr->top_item) index = descr->top_item - 1;
1936 else index = 0;
1937 break;
1938 case LB_TIMER_LEFT:
1939 if (descr->top_item) index -= descr->page_size;
1940 break;
1941 case LB_TIMER_DOWN:
1942 index = descr->top_item + LISTBOX_GetCurrentPageSize( wnd, descr );
Alexandre Julliard9ea19e51997-01-01 17:29:55 +00001943 if (index == descr->focus_item) index++;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001944 if (index >= descr->nb_items) index = descr->nb_items - 1;
1945 break;
1946 case LB_TIMER_RIGHT:
1947 if (index + descr->page_size < descr->nb_items)
1948 index += descr->page_size;
1949 break;
1950 case LB_TIMER_NONE:
1951 break;
Alexandre Julliardade697e1995-11-26 13:59:11 +00001952 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001953 if (index == descr->focus_item) return FALSE;
1954 LISTBOX_MoveCaret( wnd, descr, index, FALSE );
1955 return TRUE;
1956}
Alexandre Julliardade697e1995-11-26 13:59:11 +00001957
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001958
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001959/***********************************************************************
1960 * LISTBOX_HandleSystemTimer
1961 *
1962 * WM_SYSTIMER handler.
1963 */
1964static LRESULT LISTBOX_HandleSystemTimer( WND *wnd, LB_DESCR *descr )
1965{
1966 if (!LISTBOX_HandleTimer( wnd, descr, descr->focus_item, LISTBOX_Timer ))
Alexandre Julliardade697e1995-11-26 13:59:11 +00001967 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00001968 KillSystemTimer( wnd->hwndSelf, LB_TIMER_ID );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001969 LISTBOX_Timer = LB_TIMER_NONE;
Alexandre Julliardade697e1995-11-26 13:59:11 +00001970 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00001971 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001972}
1973
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001974
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001975/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001976 * LISTBOX_HandleMouseMove
1977 *
1978 * WM_MOUSEMOVE handler.
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001979 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001980static void LISTBOX_HandleMouseMove( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00001981 INT x, INT y )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001982{
Alexandre Julliarda3960291999-02-26 11:11:13 +00001983 INT index;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001984 TIMER_DIRECTION dir;
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00001985
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00001986 if (!descr->captured) return;
1987
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001988 if (descr->style & LBS_MULTICOLUMN)
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00001989 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001990 if (y < 0) y = 0;
1991 else if (y >= descr->item_height * descr->page_size)
1992 y = descr->item_height * descr->page_size - 1;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00001993
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00001994 if (x < 0)
1995 {
1996 dir = LB_TIMER_LEFT;
1997 x = 0;
1998 }
1999 else if (x >= descr->width)
2000 {
2001 dir = LB_TIMER_RIGHT;
2002 x = descr->width - 1;
2003 }
2004 else dir = LB_TIMER_NONE; /* inside */
Alexandre Julliard7d654eb1996-02-25 11:36:22 +00002005 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002006 else
2007 {
2008 if (y < 0) dir = LB_TIMER_UP; /* above */
2009 else if (y >= descr->height) dir = LB_TIMER_DOWN; /* below */
2010 else dir = LB_TIMER_NONE; /* inside */
2011 }
2012
2013 index = LISTBOX_GetItemFromPoint( wnd, descr, x, y );
2014 if (index == -1) index = descr->focus_item;
2015 if (!LISTBOX_HandleTimer( wnd, descr, index, dir )) dir = LB_TIMER_NONE;
2016
2017 /* Start/stop the system timer */
2018
2019 if (dir != LB_TIMER_NONE)
Alexandre Julliarda3960291999-02-26 11:11:13 +00002020 SetSystemTimer( wnd->hwndSelf, LB_TIMER_ID, LB_SCROLL_TIMEOUT, NULL);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002021 else if (LISTBOX_Timer != LB_TIMER_NONE)
Alexandre Julliarda3960291999-02-26 11:11:13 +00002022 KillSystemTimer( wnd->hwndSelf, LB_TIMER_ID );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002023 LISTBOX_Timer = dir;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002024}
2025
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002026
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002027/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002028 * LISTBOX_HandleKeyDown
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002029 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002030static LRESULT LISTBOX_HandleKeyDown( WND *wnd, LB_DESCR *descr, WPARAM wParam )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002031{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002032 INT caret = -1;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002033 BOOL bForceSelection = TRUE; /* select item pointed to by focus_item */
2034 if ((IS_MULTISELECT(descr)) || (descr->selected_item == descr->focus_item))
2035 bForceSelection = FALSE; /* only for single select list */
2036
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002037 if (descr->style & LBS_WANTKEYBOARDINPUT)
2038 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002039 caret = SendMessageA( descr->owner, WM_VKEYTOITEM,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002040 MAKEWPARAM(LOWORD(wParam), descr->focus_item),
2041 wnd->hwndSelf );
2042 if (caret == -2) return 0;
2043 }
2044 if (caret == -1) switch(wParam)
2045 {
2046 case VK_LEFT:
2047 if (descr->style & LBS_MULTICOLUMN)
2048 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00002049 bForceSelection = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002050 if (descr->focus_item >= descr->page_size)
2051 caret = descr->focus_item - descr->page_size;
2052 break;
2053 }
2054 /* fall through */
2055 case VK_UP:
2056 caret = descr->focus_item - 1;
2057 if (caret < 0) caret = 0;
2058 break;
2059 case VK_RIGHT:
2060 if (descr->style & LBS_MULTICOLUMN)
2061 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00002062 bForceSelection = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002063 if (descr->focus_item + descr->page_size < descr->nb_items)
2064 caret = descr->focus_item + descr->page_size;
2065 break;
2066 }
2067 /* fall through */
2068 case VK_DOWN:
2069 caret = descr->focus_item + 1;
2070 if (caret >= descr->nb_items) caret = descr->nb_items - 1;
2071 break;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002072
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002073 case VK_PRIOR:
2074 if (descr->style & LBS_MULTICOLUMN)
2075 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002076 INT page = descr->width / descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002077 if (page < 1) page = 1;
2078 caret = descr->focus_item - (page * descr->page_size) + 1;
2079 }
2080 else caret = descr->focus_item-LISTBOX_GetCurrentPageSize(wnd,descr)+1;
2081 if (caret < 0) caret = 0;
2082 break;
2083 case VK_NEXT:
2084 if (descr->style & LBS_MULTICOLUMN)
2085 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002086 INT page = descr->width / descr->column_width;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002087 if (page < 1) page = 1;
2088 caret = descr->focus_item + (page * descr->page_size) - 1;
2089 }
2090 else caret = descr->focus_item+LISTBOX_GetCurrentPageSize(wnd,descr)-1;
2091 if (caret >= descr->nb_items) caret = descr->nb_items - 1;
2092 break;
2093 case VK_HOME:
2094 caret = 0;
2095 break;
2096 case VK_END:
2097 caret = descr->nb_items - 1;
2098 break;
2099 case VK_SPACE:
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002100 if (descr->style & LBS_EXTENDEDSEL) caret = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002101 else if (descr->style & LBS_MULTIPLESEL)
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002102 {
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002103 LISTBOX_SetSelection( wnd, descr, descr->focus_item,
2104 !descr->items[descr->focus_item].selected,
2105 (descr->style & LBS_NOTIFY) != 0 );
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002106 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002107 break;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002108 default:
2109 bForceSelection = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002110 }
Gerard Patelc9a6d501999-07-25 13:03:17 +00002111 if (bForceSelection) /* focused item is used instead of key */
2112 caret = descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002113 if (caret >= 0)
2114 {
2115 if ((descr->style & LBS_EXTENDEDSEL) &&
Alexandre Julliarda3960291999-02-26 11:11:13 +00002116 !(GetKeyState( VK_SHIFT ) & 0x8000))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002117 descr->anchor_item = caret;
2118 LISTBOX_MoveCaret( wnd, descr, caret, TRUE );
Gerard Patelc9a6d501999-07-25 13:03:17 +00002119 LISTBOX_SetSelection( wnd, descr, caret, TRUE, FALSE);
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002120 if (descr->style & LBS_NOTIFY)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002121 {
2122 if( descr->lphc && CB_GETTYPE(descr->lphc) != CBS_SIMPLE )
2123 {
2124 /* make sure that combo parent doesn't hide us */
2125 descr->lphc->wState |= CBF_NOROLLUP;
2126 }
Gerard Patelc9a6d501999-07-25 13:03:17 +00002127 if (descr->nb_items) SEND_NOTIFICATION( wnd, descr, LBN_SELCHANGE );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002128 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002129 }
2130 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002131}
2132
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002133
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002134/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002135 * LISTBOX_HandleChar
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002136 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002137static LRESULT LISTBOX_HandleChar( WND *wnd, LB_DESCR *descr,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002138 WPARAM wParam )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002139{
Alexandre Julliarda3960291999-02-26 11:11:13 +00002140 INT caret = -1;
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002141 char str[2];
2142
2143 str[0] = wParam & 0xff;
2144 str[1] = '\0';
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002145
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002146 if (descr->style & LBS_WANTKEYBOARDINPUT)
2147 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002148 caret = SendMessageA( descr->owner, WM_CHARTOITEM,
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002149 MAKEWPARAM(LOWORD(wParam), descr->focus_item),
2150 wnd->hwndSelf );
2151 if (caret == -2) return 0;
2152 }
2153 if (caret == -1)
2154 caret = LISTBOX_FindString( wnd, descr, descr->focus_item, str, FALSE);
2155 if (caret != -1)
2156 {
Gerard Patelc9a6d501999-07-25 13:03:17 +00002157 if ((!IS_MULTISELECT(descr)) && descr->selected_item == -1)
2158 LISTBOX_SetSelection( wnd, descr, caret, TRUE, FALSE);
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002159 LISTBOX_MoveCaret( wnd, descr, caret, TRUE );
Gerard Patelc9a6d501999-07-25 13:03:17 +00002160 if ((descr->style & LBS_NOTIFY) && descr->nb_items)
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002161 SEND_NOTIFICATION( wnd, descr, LBN_SELCHANGE );
2162 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002163 return 0;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002164}
2165
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002166
2167/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002168 * LISTBOX_Create
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002169 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002170static BOOL LISTBOX_Create( WND *wnd, LPHEADCOMBO lphc )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002171{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002172 LB_DESCR *descr;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002173 MEASUREITEMSTRUCT mis;
2174 RECT rect;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002175
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002176 if (!(descr = HeapAlloc( GetProcessHeap(), 0, sizeof(*descr) )))
2177 return FALSE;
2178 if (!(descr->heap = HeapCreate( 0, 0x10000, 0 )))
2179 {
2180 HeapFree( GetProcessHeap(), 0, descr );
2181 return FALSE;
2182 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00002183 GetClientRect( wnd->hwndSelf, &rect );
2184 descr->owner = GetParent( wnd->hwndSelf );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002185 descr->style = wnd->dwStyle;
2186 descr->width = rect.right - rect.left;
2187 descr->height = rect.bottom - rect.top;
2188 descr->items = NULL;
2189 descr->nb_items = 0;
2190 descr->top_item = 0;
2191 descr->selected_item = -1;
2192 descr->focus_item = 0;
2193 descr->anchor_item = -1;
2194 descr->item_height = 1;
2195 descr->page_size = 1;
2196 descr->column_width = 150;
2197 descr->horz_extent = (wnd->dwStyle & WS_HSCROLL) ? 1 : 0;
2198 descr->horz_pos = 0;
2199 descr->nb_tabs = 0;
2200 descr->tabs = NULL;
2201 descr->caret_on = TRUE;
Luc Tourangeau5ee117b1999-04-04 12:48:21 +00002202 descr->captured = FALSE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002203 descr->font = 0;
2204 descr->locale = 0; /* FIXME */
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002205 descr->lphc = lphc;
2206
Nick Hollowayb9ce4fd1999-09-11 16:29:00 +00002207 if( ( GetExpWinVer16( wnd->hInstance ) & 0xFF00 ) == 0x0300
2208 && ( descr->style & ( WS_VSCROLL | WS_HSCROLL ) ) )
2209 {
2210 /* Win95 document "List Box Differences" from MSDN:
2211 If a list box in a version 3.x application has either the
2212 WS_HSCROLL or WS_VSCROLL style, the list box receives both
2213 horizontal and vertical scroll bars.
2214 */
2215 descr->style |= WS_VSCROLL | WS_HSCROLL;
2216 }
2217
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002218 if( lphc )
2219 {
Alexandre Julliard06c275a1999-05-02 14:32:27 +00002220 TRACE_(combo)("[%04x]: resetting owner %04x -> %04x\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002221 wnd->hwndSelf, descr->owner, lphc->self->hwndSelf );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002222 descr->owner = lphc->self->hwndSelf;
2223 }
Alexandre Julliard2787be81995-05-22 18:23:01 +00002224
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002225 *(LB_DESCR **)wnd->wExtra = descr;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002226
Alexandre Julliard670cdc41997-08-24 16:00:30 +00002227/* if (wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) descr->style &= ~LBS_NOTIFY;
2228 */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002229 if (descr->style & LBS_EXTENDEDSEL) descr->style |= LBS_MULTIPLESEL;
2230 if (descr->style & LBS_MULTICOLUMN) descr->style &= ~LBS_OWNERDRAWVARIABLE;
2231 if (descr->style & LBS_OWNERDRAWVARIABLE) descr->style |= LBS_NOINTEGRALHEIGHT;
2232 descr->item_height = LISTBOX_SetFont( wnd, descr, 0 );
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002233
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002234 if (descr->style & LBS_OWNERDRAWFIXED)
2235 {
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002236 if( descr->lphc && (descr->lphc->dwStyle & CBS_DROPDOWN))
2237 {
2238 /* WinWord gets VERY unhappy if we send WM_MEASUREITEM from here */
Francis Beaudetf585c611999-04-02 10:37:42 +00002239 descr->item_height = lphc->fixedOwnerDrawHeight;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002240 }
2241 else
2242 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002243 UINT id = (descr->lphc ) ? ID_CB_LISTBOX : wnd->wIDmenu;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002244
2245 mis.CtlType = ODT_LISTBOX;
2246 mis.CtlID = id;
2247 mis.itemID = -1;
2248 mis.itemWidth = 0;
2249 mis.itemData = 0;
2250 mis.itemHeight = descr->item_height;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002251 SendMessageA( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002252 descr->item_height = mis.itemHeight ? mis.itemHeight : 1;
2253 }
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002254 }
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002255
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002256 return TRUE;
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002257}
2258
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002259
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002260/***********************************************************************
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002261 * LISTBOX_Destroy
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002262 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002263static BOOL LISTBOX_Destroy( WND *wnd, LB_DESCR *descr )
Alexandre Julliardfa68b751995-04-03 16:55:37 +00002264{
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002265 LISTBOX_ResetContent( wnd, descr );
2266 HeapDestroy( descr->heap );
2267 HeapFree( GetProcessHeap(), 0, descr );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002268 wnd->wExtra[0] = 0;
Alexandre Julliard7e56f681996-01-31 19:02:28 +00002269 return TRUE;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002270}
2271
2272
2273/***********************************************************************
2274 * ListBoxWndProc
2275 */
Marcus Meissner9aded511999-05-01 10:23:45 +00002276static inline LRESULT WINAPI ListBoxWndProc_locked( WND* wnd, UINT msg,
2277 WPARAM wParam, LPARAM lParam )
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002278{
2279 LRESULT ret;
2280 LB_DESCR *descr;
Marcus Meissner9aded511999-05-01 10:23:45 +00002281 HWND hwnd = wnd->hwndSelf;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002282
2283 if (!wnd) return 0;
2284 if (!(descr = *(LB_DESCR **)wnd->wExtra))
2285 {
Francis Beaudetf6a225b1999-07-30 17:58:24 +00002286 switch (msg)
2287 {
2288 case WM_CREATE:
2289 {
2290 if (!LISTBOX_Create( wnd, NULL ))
2291 return -1;
2292 TRACE("creating wnd=%04x descr=%p\n",
2293 hwnd, *(LB_DESCR **)wnd->wExtra );
2294 return 0;
2295 }
2296 case WM_NCCREATE:
2297 {
2298 /*
2299 * When a listbox is not in a combobox and the look
2300 * is win95, the WS_BORDER style is replaced with
2301 * the WS_EX_CLIENTEDGE style.
2302 */
2303 if ( (TWEAK_WineLook > WIN31_LOOK) &&
2304 (wnd->dwStyle & WS_BORDER) )
2305 {
2306 wnd->dwExStyle |= WS_EX_CLIENTEDGE;
2307 wnd->dwStyle &= ~ WS_BORDER;
2308 }
2309 }
2310 }
2311
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002312 /* Ignore all other messages before we get a WM_CREATE */
Marcus Meissner9aded511999-05-01 10:23:45 +00002313 return DefWindowProcA( hwnd, msg, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002314 }
2315
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002316 TRACE("[%04x]: msg %s wp %08x lp %08lx\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002317 wnd->hwndSelf, SPY_GetMsgName(msg), wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002318 switch(msg)
2319 {
2320 case LB_RESETCONTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002321 case LB_RESETCONTENT:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002322 LISTBOX_ResetContent( wnd, descr );
Marcus Meissner9aded511999-05-01 10:23:45 +00002323 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002324
2325 case LB_ADDSTRING16:
2326 if (HAS_STRINGS(descr)) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
2327 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002328 case LB_ADDSTRING:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002329 wParam = LISTBOX_FindStringPos( wnd, descr, (LPCSTR)lParam, FALSE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002330 return LISTBOX_InsertString( wnd, descr, wParam, (LPCSTR)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002331
2332 case LB_INSERTSTRING16:
2333 if (HAS_STRINGS(descr)) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002334 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002335 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002336 case LB_INSERTSTRING:
Marcus Meissner9aded511999-05-01 10:23:45 +00002337 return LISTBOX_InsertString( wnd, descr, wParam, (LPCSTR)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002338
2339 case LB_ADDFILE16:
2340 if (HAS_STRINGS(descr)) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
2341 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002342 case LB_ADDFILE:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002343 wParam = LISTBOX_FindFileStrPos( wnd, descr, (LPCSTR)lParam );
Marcus Meissner9aded511999-05-01 10:23:45 +00002344 return LISTBOX_InsertString( wnd, descr, wParam, (LPCSTR)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002345
2346 case LB_DELETESTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002347 case LB_DELETESTRING:
Gerard Patelc9a6d501999-07-25 13:03:17 +00002348 if (LISTBOX_RemoveItem( wnd, descr, wParam) != LB_ERR)
2349 return descr->nb_items;
2350 else
2351 return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002352
2353 case LB_GETITEMDATA16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002354 case LB_GETITEMDATA:
2355 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002356 return LB_ERR;
2357 return descr->items[wParam].data;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002358
2359 case LB_SETITEMDATA16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002360 case LB_SETITEMDATA:
2361 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002362 return LB_ERR;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002363 descr->items[wParam].data = (DWORD)lParam;
Marcus Meissner9aded511999-05-01 10:23:45 +00002364 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002365
2366 case LB_GETCOUNT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002367 case LB_GETCOUNT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002368 return descr->nb_items;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002369
2370 case LB_GETTEXT16:
2371 lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
2372 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002373 case LB_GETTEXT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002374 return LISTBOX_GetText( wnd, descr, wParam, (LPSTR)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002375
2376 case LB_GETTEXTLEN16:
2377 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002378 case LB_GETTEXTLEN:
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002379 if (wParam >= descr->nb_items)
Marcus Meissner9aded511999-05-01 10:23:45 +00002380 return LB_ERR;
2381 return (HAS_STRINGS(descr) ? strlen(descr->items[wParam].str)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002382 : sizeof(DWORD));
2383
2384 case LB_GETCURSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002385 case LB_GETCURSEL:
Francis Beaudet8730e451999-03-25 13:22:02 +00002386 if (descr->nb_items==0)
Marcus Meissner9aded511999-05-01 10:23:45 +00002387 return LB_ERR;
Gerard Patelc9a6d501999-07-25 13:03:17 +00002388 if (!IS_MULTISELECT(descr))
2389 return descr->selected_item;
Marcus Meissner9aded511999-05-01 10:23:45 +00002390 /* else */
2391 if (descr->selected_item!=-1)
2392 return descr->selected_item;
2393 /* else */
2394 return descr->focus_item;
Lawson Whitney613092a1999-03-22 14:46:43 +00002395 /* otherwise, if the user tries to move the selection with the */
2396 /* arrow keys, we will give the application something to choke on */
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002397 case LB_GETTOPINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002398 case LB_GETTOPINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002399 return descr->top_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002400
2401 case LB_GETITEMHEIGHT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002402 case LB_GETITEMHEIGHT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002403 return LISTBOX_GetItemHeight( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002404
2405 case LB_SETITEMHEIGHT16:
2406 lParam = LOWORD(lParam);
2407 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002408 case LB_SETITEMHEIGHT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002409 return LISTBOX_SetItemHeight( wnd, descr, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002410
Alexandre Julliarda3960291999-02-26 11:11:13 +00002411 case LB_ITEMFROMPOINT:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002412 {
Patrik Stridvall0f8bc5b1999-04-22 16:27:50 +00002413 POINT pt;
2414 RECT rect;
2415
2416 pt.x = LOWORD(lParam);
2417 pt.y = HIWORD(lParam);
2418 rect.left = 0;
2419 rect.top = 0;
2420 rect.right = descr->width;
2421 rect.bottom = descr->height;
2422
Marcus Meissner9aded511999-05-01 10:23:45 +00002423 return MAKELONG( LISTBOX_GetItemFromPoint(wnd, descr, pt.x, pt.y),
Gerard Patel777508a1999-05-08 12:35:17 +00002424 !PtInRect( &rect, pt ) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002425 }
2426
2427 case LB_SETCARETINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002428 case LB_SETCARETINDEX:
Gerard Patelc9a6d501999-07-25 13:03:17 +00002429 if ((!IS_MULTISELECT(descr)) && (descr->selected_item != -1)) return LB_ERR;
2430 if (LISTBOX_SetCaretIndex( wnd, descr, wParam, !lParam ) == LB_ERR)
2431 return LB_ERR;
2432 else if (ISWIN31)
2433 return wParam;
2434 else
2435 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002436
2437 case LB_GETCARETINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002438 case LB_GETCARETINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002439 return descr->focus_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002440
2441 case LB_SETTOPINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002442 case LB_SETTOPINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002443 return LISTBOX_SetTopItem( wnd, descr, wParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002444
2445 case LB_SETCOLUMNWIDTH16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002446 case LB_SETCOLUMNWIDTH:
Marcus Meissner9aded511999-05-01 10:23:45 +00002447 return LISTBOX_SetColumnWidth( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002448
2449 case LB_GETITEMRECT16:
2450 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002451 RECT rect;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002452 ret = LISTBOX_GetItemRect( wnd, descr, (INT16)wParam, &rect );
2453 CONV_RECT32TO16( &rect, (RECT16 *)PTR_SEG_TO_LIN(lParam) );
2454 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002455 return ret;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002456
Alexandre Julliarda3960291999-02-26 11:11:13 +00002457 case LB_GETITEMRECT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002458 return LISTBOX_GetItemRect( wnd, descr, wParam, (RECT *)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002459
2460 case LB_FINDSTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002461 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002462 if (HAS_STRINGS(descr)) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
2463 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002464 case LB_FINDSTRING:
Marcus Meissner9aded511999-05-01 10:23:45 +00002465 return LISTBOX_FindString( wnd, descr, wParam, (LPCSTR)lParam, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002466
2467 case LB_FINDSTRINGEXACT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002468 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002469 if (HAS_STRINGS(descr)) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
2470 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002471 case LB_FINDSTRINGEXACT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002472 return LISTBOX_FindString( wnd, descr, wParam, (LPCSTR)lParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002473
2474 case LB_SELECTSTRING16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002475 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002476 if (HAS_STRINGS(descr)) lParam = (LPARAM)PTR_SEG_TO_LIN(lParam);
2477 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002478 case LB_SELECTSTRING:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002479 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002480 INT index = LISTBOX_FindString( wnd, descr, wParam,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002481 (LPCSTR)lParam, FALSE );
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002482 if (index == LB_ERR)
Marcus Meissner9aded511999-05-01 10:23:45 +00002483 return LB_ERR;
Alexandre Julliard7e6ae4b1996-12-08 19:25:27 +00002484 LISTBOX_SetSelection( wnd, descr, index, TRUE, FALSE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002485 return index;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002486 }
2487
2488 case LB_GETSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002489 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002490 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002491 case LB_GETSEL:
2492 if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002493 return LB_ERR;
2494 return descr->items[wParam].selected;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002495
2496 case LB_SETSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002497 lParam = (INT)(INT16)lParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002498 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002499 case LB_SETSEL:
Marcus Meissner9aded511999-05-01 10:23:45 +00002500 return LISTBOX_SetSelection( wnd, descr, lParam, wParam, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002501
2502 case LB_SETCURSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002503 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002504 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002505 case LB_SETCURSEL:
Gerard Patelc9a6d501999-07-25 13:03:17 +00002506 if (IS_MULTISELECT(descr)) return LB_ERR;
Alexandre Julliard638f1691999-01-17 16:32:32 +00002507 LISTBOX_SetCaretIndex( wnd, descr, wParam, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002508 return LISTBOX_SetSelection( wnd, descr, wParam, TRUE, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002509
2510 case LB_GETSELCOUNT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002511 case LB_GETSELCOUNT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002512 return LISTBOX_GetSelCount( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002513
2514 case LB_GETSELITEMS16:
Marcus Meissner9aded511999-05-01 10:23:45 +00002515 return LISTBOX_GetSelItems16( wnd, descr, wParam,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002516 (LPINT16)PTR_SEG_TO_LIN(lParam) );
2517
Alexandre Julliarda3960291999-02-26 11:11:13 +00002518 case LB_GETSELITEMS:
Marcus Meissner9aded511999-05-01 10:23:45 +00002519 return LISTBOX_GetSelItems( wnd, descr, wParam, (LPINT)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002520
2521 case LB_SELITEMRANGE16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002522 case LB_SELITEMRANGE:
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002523 if (LOWORD(lParam) <= HIWORD(lParam))
Marcus Meissner9aded511999-05-01 10:23:45 +00002524 return LISTBOX_SelectItemRange( wnd, descr, LOWORD(lParam),
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002525 HIWORD(lParam), wParam );
2526 else
Marcus Meissner9aded511999-05-01 10:23:45 +00002527 return LISTBOX_SelectItemRange( wnd, descr, HIWORD(lParam),
Alexandre Julliardc6c09441997-01-12 18:32:19 +00002528 LOWORD(lParam), wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002529
2530 case LB_SELITEMRANGEEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002531 case LB_SELITEMRANGEEX:
2532 if ((INT)lParam >= (INT)wParam)
Marcus Meissner9aded511999-05-01 10:23:45 +00002533 return LISTBOX_SelectItemRange( wnd, descr, wParam, lParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002534 else
Marcus Meissner9aded511999-05-01 10:23:45 +00002535 return LISTBOX_SelectItemRange( wnd, descr, lParam, wParam, FALSE);
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002536
2537 case LB_GETHORIZONTALEXTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002538 case LB_GETHORIZONTALEXTENT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002539 return descr->horz_extent;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002540
2541 case LB_SETHORIZONTALEXTENT16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002542 case LB_SETHORIZONTALEXTENT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002543 return LISTBOX_SetHorizontalExtent( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002544
2545 case LB_GETANCHORINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002546 case LB_GETANCHORINDEX:
Marcus Meissner9aded511999-05-01 10:23:45 +00002547 return descr->anchor_item;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002548
2549 case LB_SETANCHORINDEX16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002550 wParam = (INT)(INT16)wParam;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002551 /* fall through */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002552 case LB_SETANCHORINDEX:
2553 if (((INT)wParam < -1) || ((INT)wParam >= descr->nb_items))
Marcus Meissner9aded511999-05-01 10:23:45 +00002554 return LB_ERR;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002555 descr->anchor_item = (INT)wParam;
Marcus Meissner9aded511999-05-01 10:23:45 +00002556 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002557
2558 case LB_DIR16:
Marcus Meissner9aded511999-05-01 10:23:45 +00002559 return LISTBOX_Directory( wnd, descr, wParam,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002560 (LPCSTR)PTR_SEG_TO_LIN(lParam), FALSE );
2561
Alexandre Julliarda3960291999-02-26 11:11:13 +00002562 case LB_DIR:
Marcus Meissner9aded511999-05-01 10:23:45 +00002563 return LISTBOX_Directory( wnd, descr, wParam, (LPCSTR)lParam, TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002564
Alexandre Julliarda3960291999-02-26 11:11:13 +00002565 case LB_GETLOCALE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002566 return descr->locale;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002567
Alexandre Julliarda3960291999-02-26 11:11:13 +00002568 case LB_SETLOCALE:
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002569 descr->locale = (LCID)wParam; /* FIXME: should check for valid lcid */
Marcus Meissner9aded511999-05-01 10:23:45 +00002570 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002571
Alexandre Julliarda3960291999-02-26 11:11:13 +00002572 case LB_INITSTORAGE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002573 return LISTBOX_InitStorage( wnd, descr, wParam, (DWORD)lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002574
Alexandre Julliarda3960291999-02-26 11:11:13 +00002575 case LB_SETCOUNT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002576 return LISTBOX_SetCount( wnd, descr, (INT)wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002577
2578 case LB_SETTABSTOPS16:
Marcus Meissner9aded511999-05-01 10:23:45 +00002579 return LISTBOX_SetTabStops( wnd, descr, (INT)(INT16)wParam,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002580 (LPINT)PTR_SEG_TO_LIN(lParam), TRUE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002581
Alexandre Julliarda3960291999-02-26 11:11:13 +00002582 case LB_SETTABSTOPS:
Marcus Meissner9aded511999-05-01 10:23:45 +00002583 return LISTBOX_SetTabStops( wnd, descr, wParam, (LPINT)lParam, FALSE );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002584
2585 case LB_CARETON16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002586 case LB_CARETON:
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002587 if (descr->caret_on)
Marcus Meissner9aded511999-05-01 10:23:45 +00002588 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002589 descr->caret_on = TRUE;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002590 if ((descr->focus_item != -1) && (GetFocus() == wnd->hwndSelf))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002591 LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002592 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002593
2594 case LB_CARETOFF16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002595 case LB_CARETOFF:
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002596 if (!descr->caret_on)
Marcus Meissner9aded511999-05-01 10:23:45 +00002597 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002598 descr->caret_on = FALSE;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002599 if ((descr->focus_item != -1) && (GetFocus() == wnd->hwndSelf))
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002600 LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002601 return LB_OKAY;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002602
2603 case WM_DESTROY:
Marcus Meissner9aded511999-05-01 10:23:45 +00002604 return LISTBOX_Destroy( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002605
2606 case WM_ENABLE:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002607 InvalidateRect( hwnd, NULL, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002608 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002609
2610 case WM_SETREDRAW:
2611 LISTBOX_SetRedraw( wnd, descr, wParam != 0 );
Marcus Meissner9aded511999-05-01 10:23:45 +00002612 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002613
2614 case WM_GETDLGCODE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002615 return DLGC_WANTARROWS | DLGC_WANTCHARS;
2616
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002617 case WM_PAINT:
2618 {
Alexandre Julliarda3960291999-02-26 11:11:13 +00002619 PAINTSTRUCT ps;
2620 HDC hdc = ( wParam ) ? ((HDC)wParam)
2621 : BeginPaint( hwnd, &ps );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002622 ret = LISTBOX_Paint( wnd, descr, hdc );
Alexandre Julliarda3960291999-02-26 11:11:13 +00002623 if( !wParam ) EndPaint( hwnd, &ps );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002624 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002625 return ret;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002626 case WM_SIZE:
2627 LISTBOX_UpdateSize( wnd, descr );
Marcus Meissner9aded511999-05-01 10:23:45 +00002628 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002629 case WM_GETFONT:
Marcus Meissner9aded511999-05-01 10:23:45 +00002630 return descr->font;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002631 case WM_SETFONT:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002632 LISTBOX_SetFont( wnd, descr, (HFONT)wParam );
2633 if (lParam) InvalidateRect( wnd->hwndSelf, 0, TRUE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002634 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002635 case WM_SETFOCUS:
2636 descr->caret_on = TRUE;
2637 if (descr->focus_item != -1)
2638 LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
2639 SEND_NOTIFICATION( wnd, descr, LBN_SETFOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002640 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002641 case WM_KILLFOCUS:
2642 if ((descr->focus_item != -1) && descr->caret_on)
2643 LISTBOX_RepaintItem( wnd, descr, descr->focus_item, ODA_FOCUS );
2644 SEND_NOTIFICATION( wnd, descr, LBN_KILLFOCUS );
Marcus Meissner9aded511999-05-01 10:23:45 +00002645 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002646 case WM_HSCROLL:
Marcus Meissner9aded511999-05-01 10:23:45 +00002647 return LISTBOX_HandleHScroll( wnd, descr, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002648 case WM_VSCROLL:
Marcus Meissner9aded511999-05-01 10:23:45 +00002649 return LISTBOX_HandleVScroll( wnd, descr, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002650 case WM_LBUTTONDOWN:
Marcus Meissner9aded511999-05-01 10:23:45 +00002651 return LISTBOX_HandleLButtonDown( wnd, descr, wParam,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002652 (INT16)LOWORD(lParam),
2653 (INT16)HIWORD(lParam) );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002654 case WM_LBUTTONDBLCLK:
2655 if (descr->style & LBS_NOTIFY)
2656 SEND_NOTIFICATION( wnd, descr, LBN_DBLCLK );
Marcus Meissner9aded511999-05-01 10:23:45 +00002657 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002658 case WM_MOUSEMOVE:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002659 if (GetCapture() == hwnd)
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002660 LISTBOX_HandleMouseMove( wnd, descr, (INT16)LOWORD(lParam),
2661 (INT16)HIWORD(lParam) );
Marcus Meissner9aded511999-05-01 10:23:45 +00002662 return 0;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002663 case WM_LBUTTONUP:
Marcus Meissner9aded511999-05-01 10:23:45 +00002664 return LISTBOX_HandleLButtonUp( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002665 case WM_KEYDOWN:
Marcus Meissner9aded511999-05-01 10:23:45 +00002666 return LISTBOX_HandleKeyDown( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002667 case WM_CHAR:
Marcus Meissner9aded511999-05-01 10:23:45 +00002668 return LISTBOX_HandleChar( wnd, descr, wParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002669 case WM_SYSTIMER:
Marcus Meissner9aded511999-05-01 10:23:45 +00002670 return LISTBOX_HandleSystemTimer( wnd, descr );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002671 case WM_ERASEBKGND:
2672 if (IS_OWNERDRAW(descr))
2673 {
Luc Tourangeau89147991999-04-18 09:23:56 +00002674 RECT rect;
Alexandre Julliarda3960291999-02-26 11:11:13 +00002675 HBRUSH hbrush = SendMessageA( descr->owner, WM_CTLCOLORLISTBOX,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002676 wParam, (LPARAM)wnd->hwndSelf );
Luc Tourangeau89147991999-04-18 09:23:56 +00002677 GetClientRect(hwnd, &rect);
Alexandre Julliarda3960291999-02-26 11:11:13 +00002678 if (hbrush) FillRect( (HDC)wParam, &rect, hbrush );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002679 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002680 return 1;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002681 case WM_DROPFILES:
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002682 if( !descr->lphc )
Marcus Meissner9aded511999-05-01 10:23:45 +00002683 return SendMessageA( descr->owner, msg, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002684 break;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002685
2686 case WM_DROPOBJECT:
2687 case WM_QUERYDROPOBJECT:
2688 case WM_DRAGSELECT:
2689 case WM_DRAGMOVE:
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002690 if( !descr->lphc )
2691 {
2692 LPDRAGINFO dragInfo = (LPDRAGINFO)PTR_SEG_TO_LIN( (SEGPTR)lParam );
2693 dragInfo->l = LISTBOX_GetItemFromPoint( wnd, descr, dragInfo->pt.x,
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002694 dragInfo->pt.y );
Marcus Meissner9aded511999-05-01 10:23:45 +00002695 return SendMessageA( descr->owner, msg, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002696 }
2697 break;
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002698
2699 default:
2700 if ((msg >= WM_USER) && (msg < 0xc000))
Alexandre Julliard9fe7a251999-05-14 08:17:14 +00002701 WARN("[%04x]: unknown msg %04x wp %08x lp %08lx\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002702 hwnd, msg, wParam, lParam );
Marcus Meissner9aded511999-05-01 10:23:45 +00002703 return DefWindowProcA( hwnd, msg, wParam, lParam );
Alexandre Julliardda0cfb31996-12-01 17:17:47 +00002704 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002705 return 0;
2706}
2707
2708/***********************************************************************
2709 * ListBoxWndProc
2710 *
2711 * This is just a wrapper for the real wndproc, it only does window locking
2712 * and unlocking.
2713 */
2714LRESULT WINAPI ListBoxWndProc( HWND hwnd, UINT msg,
2715 WPARAM wParam, LPARAM lParam )
2716{
2717 WND* wndPtr = WIN_FindWndPtr( hwnd );
2718 LRESULT res = ListBoxWndProc_locked(wndPtr,msg,wParam,lParam);
2719
2720 WIN_ReleaseWndPtr(wndPtr);
2721 return res;
Alexandre Julliard58199531994-04-21 01:20:00 +00002722}
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002723
2724/***********************************************************************
2725 * COMBO_Directory
2726 */
Alexandre Julliarda3960291999-02-26 11:11:13 +00002727LRESULT COMBO_Directory( LPHEADCOMBO lphc, UINT attrib, LPSTR dir, BOOL bLong)
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002728{
2729 WND *wnd = WIN_FindWndPtr( lphc->hWndLBox );
2730
2731 if( wnd )
2732 {
2733 LB_DESCR *descr = *(LB_DESCR **)wnd->wExtra;
2734 if( descr )
2735 {
2736 LRESULT lRet = LISTBOX_Directory( wnd, descr, attrib, dir, bLong );
2737
Alexandre Julliarda3960291999-02-26 11:11:13 +00002738 RedrawWindow( lphc->self->hwndSelf, NULL, 0,
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002739 RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002740 WIN_ReleaseWndPtr(wnd);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002741 return lRet;
2742 }
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002743 WIN_ReleaseWndPtr(wnd);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002744 }
2745 return CB_ERR;
2746}
2747
2748/***********************************************************************
Marcus Meissner9aded511999-05-01 10:23:45 +00002749 * ComboLBWndProc_locked
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002750 *
Marcus Meissner9aded511999-05-01 10:23:45 +00002751 * The real combo listbox wndproc, but called with locked WND struct.
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002752 */
Marcus Meissner9aded511999-05-01 10:23:45 +00002753static inline LRESULT WINAPI ComboLBWndProc_locked( WND* wnd, UINT msg,
Alexandre Julliarda3960291999-02-26 11:11:13 +00002754 WPARAM wParam, LPARAM lParam )
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002755{
2756 LRESULT lRet = 0;
Marcus Meissner9aded511999-05-01 10:23:45 +00002757 HWND hwnd = wnd->hwndSelf;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002758
2759 if (wnd)
2760 {
2761 LB_DESCR *descr = *(LB_DESCR **)wnd->wExtra;
2762
Alexandre Julliard06c275a1999-05-02 14:32:27 +00002763 TRACE_(combo)("[%04x]: msg %s wp %08x lp %08lx\n",
Alexandre Julliarda69b88b1998-03-15 20:29:56 +00002764 wnd->hwndSelf, SPY_GetMsgName(msg), wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002765
2766 if( descr || msg == WM_CREATE )
2767 {
2768 LPHEADCOMBO lphc = (descr) ? descr->lphc : NULL;
2769
2770 switch( msg )
2771 {
2772 case WM_CREATE:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002773#define lpcs ((LPCREATESTRUCTA)lParam)
Alexandre Julliard06c275a1999-05-02 14:32:27 +00002774 TRACE_(combo)("\tpassed parent handle = 0x%08x\n",
Alexandre Julliarda3960291999-02-26 11:11:13 +00002775 (UINT)lpcs->lpCreateParams);
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002776
2777 lphc = (LPHEADCOMBO)(lpcs->lpCreateParams);
2778#undef lpcs
Marcus Meissner9aded511999-05-01 10:23:45 +00002779 return LISTBOX_Create( wnd, lphc );
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00002780 case WM_MOUSEMOVE:
2781 if ( (TWEAK_WineLook > WIN31_LOOK) &&
2782 (CB_GETTYPE(lphc) != CBS_SIMPLE) )
2783 {
2784 POINT mousePos;
2785 BOOL captured;
2786 RECT clientRect;
2787
2788 mousePos.x = (INT16)LOWORD(lParam);
2789 mousePos.y = (INT16)HIWORD(lParam);
2790
2791 /*
2792 * If we are in a dropdown combobox, we simulate that
2793 * the mouse is captured to show the tracking of the item.
2794 */
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00002795 GetClientRect(hwnd, &clientRect);
2796
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002797 if (PtInRect( &clientRect, mousePos ))
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00002798 {
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002799 captured = descr->captured;
2800 descr->captured = TRUE;
2801
2802 LISTBOX_HandleMouseMove( wnd, descr,
2803 mousePos.x, mousePos.y);
2804
2805 descr->captured = captured;
2806
2807 }
2808 else
2809 {
2810 LISTBOX_HandleMouseMove( wnd, descr,
2811 mousePos.x, mousePos.y);
2812 }
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00002813
2814 return 0;
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002815
Francis Beaudet6ec3eaf1999-06-12 10:51:19 +00002816 }
2817 else
2818 {
2819 /*
2820 * If we are in Win3.1 look, go with the default behavior.
2821 */
2822 return ListBoxWndProc( hwnd, msg, wParam, lParam );
2823 }
2824 case WM_LBUTTONUP:
2825 if (TWEAK_WineLook > WIN31_LOOK)
2826 {
2827 POINT mousePos;
2828 RECT clientRect;
2829
2830 /*
2831 * If the mouse button "up" is not in the listbox,
2832 * we make sure there is no selection by re-selecting the
2833 * item that was selected when the listbox was made visible.
2834 */
2835 mousePos.x = (INT16)LOWORD(lParam);
2836 mousePos.y = (INT16)HIWORD(lParam);
2837
2838 GetClientRect(hwnd, &clientRect);
2839
2840 /*
2841 * When the user clicks outside the combobox and the focus
2842 * is lost, the owning combobox will send a fake buttonup with
2843 * 0xFFFFFFF as the mouse location, we must also revert the
2844 * selection to the original selection.
2845 */
2846 if ( (lParam == 0xFFFFFFFF) ||
2847 (!PtInRect( &clientRect, mousePos )) )
2848 {
2849 LISTBOX_MoveCaret( wnd,
2850 descr,
2851 lphc->droppedIndex,
2852 FALSE );
2853 }
2854 }
2855 return LISTBOX_HandleLButtonUp( wnd, descr );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002856 case WM_LBUTTONDOWN:
Pierre Mageau25c62cc1999-09-11 16:26:03 +00002857 return LISTBOX_HandleLButtonDownCombo(wnd, descr, wParam,
2858 (INT16)LOWORD(lParam),
2859 (INT16)HIWORD(lParam) );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002860 case WM_MOUSEACTIVATE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002861 return MA_NOACTIVATE;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002862 case WM_NCACTIVATE:
Marcus Meissner9aded511999-05-01 10:23:45 +00002863 return FALSE;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002864 case WM_KEYDOWN:
2865 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
2866 {
2867 /* for some reason(?) Windows makes it possible to
2868 * show/hide ComboLBox by sending it WM_KEYDOWNs */
2869
2870 if( (!(lphc->wState & CBF_EUI) && wParam == VK_F4) ||
2871 ( (lphc->wState & CBF_EUI) && !(lphc->wState & CBF_DROPPED)
2872 && (wParam == VK_DOWN || wParam == VK_UP)) )
2873 {
2874 COMBO_FlipListbox( lphc, FALSE );
Marcus Meissner9aded511999-05-01 10:23:45 +00002875 return 0;
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002876 }
2877 }
Marcus Meissner9aded511999-05-01 10:23:45 +00002878 return LISTBOX_HandleKeyDown( wnd, descr, wParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002879
Alex Korobka311d3291999-01-01 18:40:02 +00002880 case LB_SETCURSEL16:
Alexandre Julliarda3960291999-02-26 11:11:13 +00002881 case LB_SETCURSEL:
Alex Korobka311d3291999-01-01 18:40:02 +00002882 lRet = ListBoxWndProc( hwnd, msg, wParam, lParam );
Francois Boisvert6b1b41c1999-03-14 17:25:32 +00002883 lRet =(lRet == LB_ERR) ? lRet : descr->selected_item;
Marcus Meissner9aded511999-05-01 10:23:45 +00002884 return lRet;
Alexandre Julliard60ce85c1998-02-01 18:33:27 +00002885 case WM_NCDESTROY:
2886 if( CB_GETTYPE(lphc) != CBS_SIMPLE )
2887 lphc->hWndLBox = 0;
2888 /* fall through */
2889
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002890 default:
Marcus Meissner9aded511999-05-01 10:23:45 +00002891 return ListBoxWndProc( hwnd, msg, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002892 }
2893 }
Alexandre Julliarda3960291999-02-26 11:11:13 +00002894 lRet = DefWindowProcA( hwnd, msg, wParam, lParam );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002895
Alexandre Julliard06c275a1999-05-02 14:32:27 +00002896 TRACE_(combo)("\t default on msg [%04x]\n", (UINT16)msg );
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002897 }
Alexandre Julliarddf2673b1997-03-29 17:20:20 +00002898 return lRet;
2899}
2900
Marcus Meissner9aded511999-05-01 10:23:45 +00002901/***********************************************************************
2902 * ComboLBWndProc
2903 *
2904 * NOTE: in Windows, winproc address of the ComboLBox is the same
2905 * as that of the Listbox.
2906 *
2907 * This is just a wrapper for the real wndproc, it only does window locking
2908 * and unlocking.
2909 */
2910LRESULT WINAPI ComboLBWndProc( HWND hwnd, UINT msg,
2911 WPARAM wParam, LPARAM lParam )
2912{
2913 WND *wnd = WIN_FindWndPtr( hwnd );
2914 LRESULT res = ComboLBWndProc_locked(wnd,msg,wParam,lParam);
2915
2916 WIN_ReleaseWndPtr(wnd);
2917 return res;
2918}