xref: /reactos/dll/win32/comctl32/listbox.c (revision 0707475f)
1b3fb8555SGiannis Adamopoulos /*
2b3fb8555SGiannis Adamopoulos  * Listbox controls
3b3fb8555SGiannis Adamopoulos  *
4b3fb8555SGiannis Adamopoulos  * Copyright 1996 Alexandre Julliard
5b3fb8555SGiannis Adamopoulos  * Copyright 2005 Frank Richter
6b3fb8555SGiannis Adamopoulos  *
7b3fb8555SGiannis Adamopoulos  * This library is free software; you can redistribute it and/or
8b3fb8555SGiannis Adamopoulos  * modify it under the terms of the GNU Lesser General Public
9b3fb8555SGiannis Adamopoulos  * License as published by the Free Software Foundation; either
10b3fb8555SGiannis Adamopoulos  * version 2.1 of the License, or (at your option) any later version.
11b3fb8555SGiannis Adamopoulos  *
12b3fb8555SGiannis Adamopoulos  * This library is distributed in the hope that it will be useful,
13b3fb8555SGiannis Adamopoulos  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14b3fb8555SGiannis Adamopoulos  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15b3fb8555SGiannis Adamopoulos  * Lesser General Public License for more details.
16b3fb8555SGiannis Adamopoulos  *
17b3fb8555SGiannis Adamopoulos  * You should have received a copy of the GNU Lesser General Public
18b3fb8555SGiannis Adamopoulos  * License along with this library; if not, write to the Free Software
19b3fb8555SGiannis Adamopoulos  * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
20b3fb8555SGiannis Adamopoulos  *
21b3fb8555SGiannis Adamopoulos  */
22b3fb8555SGiannis Adamopoulos 
23b3fb8555SGiannis Adamopoulos #include <string.h>
24b3fb8555SGiannis Adamopoulos #include <stdlib.h>
25b3fb8555SGiannis Adamopoulos #include <stdarg.h>
26b3fb8555SGiannis Adamopoulos #include <stdio.h>
27b3fb8555SGiannis Adamopoulos #include "windef.h"
28b3fb8555SGiannis Adamopoulos #include "winbase.h"
29b3fb8555SGiannis Adamopoulos #include "wingdi.h"
30b3fb8555SGiannis Adamopoulos #include "winuser.h"
31b3fb8555SGiannis Adamopoulos #include "commctrl.h"
32b3fb8555SGiannis Adamopoulos #include "uxtheme.h"
33b3fb8555SGiannis Adamopoulos #include "vssym32.h"
34b3fb8555SGiannis Adamopoulos #include "wine/exception.h"
35b3fb8555SGiannis Adamopoulos #include "wine/debug.h"
36*0707475fSJustin Miller #include "wine/heap.h"
37b3fb8555SGiannis Adamopoulos 
38b3fb8555SGiannis Adamopoulos #include "comctl32.h"
39b3fb8555SGiannis Adamopoulos 
40*0707475fSJustin Miller WINE_DEFAULT_DEBUG_CHANNEL(listbox);
41b3fb8555SGiannis Adamopoulos 
42*0707475fSJustin Miller /* Items array granularity (must be power of 2) */
43b3fb8555SGiannis Adamopoulos #define LB_ARRAY_GRANULARITY 16
44b3fb8555SGiannis Adamopoulos 
45b3fb8555SGiannis Adamopoulos /* Scrolling timeout in ms */
46b3fb8555SGiannis Adamopoulos #define LB_SCROLL_TIMEOUT 50
47b3fb8555SGiannis Adamopoulos 
48b3fb8555SGiannis Adamopoulos /* Listbox system timer id */
49b3fb8555SGiannis Adamopoulos #define LB_TIMER_ID  2
50b3fb8555SGiannis Adamopoulos 
51b3fb8555SGiannis Adamopoulos /* flag listbox changed while setredraw false - internal style */
52b3fb8555SGiannis Adamopoulos #define LBS_DISPLAYCHANGED 0x80000000
53b3fb8555SGiannis Adamopoulos 
54b3fb8555SGiannis Adamopoulos /* Item structure */
55b3fb8555SGiannis Adamopoulos typedef struct
56b3fb8555SGiannis Adamopoulos {
57b3fb8555SGiannis Adamopoulos     LPWSTR    str;       /* Item text */
58b3fb8555SGiannis Adamopoulos     BOOL      selected;  /* Is item selected? */
59b3fb8555SGiannis Adamopoulos     UINT      height;    /* Item height (only for OWNERDRAWVARIABLE) */
60b3fb8555SGiannis Adamopoulos     ULONG_PTR data;      /* User data */
61b3fb8555SGiannis Adamopoulos } LB_ITEMDATA;
62b3fb8555SGiannis Adamopoulos 
63b3fb8555SGiannis Adamopoulos /* Listbox structure */
64b3fb8555SGiannis Adamopoulos typedef struct
65b3fb8555SGiannis Adamopoulos {
66b3fb8555SGiannis Adamopoulos     HWND        self;           /* Our own window handle */
67b3fb8555SGiannis Adamopoulos     HWND        owner;          /* Owner window to send notifications to */
68b3fb8555SGiannis Adamopoulos     UINT        style;          /* Window style */
69b3fb8555SGiannis Adamopoulos     INT         width;          /* Window width */
70b3fb8555SGiannis Adamopoulos     INT         height;         /* Window height */
71*0707475fSJustin Miller     union
72*0707475fSJustin Miller     {
73b3fb8555SGiannis Adamopoulos         LB_ITEMDATA *items;     /* Array of items */
74*0707475fSJustin Miller         BYTE *nodata_items;     /* For multi-selection LBS_NODATA */
75*0707475fSJustin Miller     } u;
76b3fb8555SGiannis Adamopoulos     INT         nb_items;       /* Number of items */
77*0707475fSJustin Miller     UINT        items_size;     /* Total number of allocated items in the array */
78b3fb8555SGiannis Adamopoulos     INT         top_item;       /* Top visible item */
79b3fb8555SGiannis Adamopoulos     INT         selected_item;  /* Selected item */
80b3fb8555SGiannis Adamopoulos     INT         focus_item;     /* Item that has the focus */
81b3fb8555SGiannis Adamopoulos     INT         anchor_item;    /* Anchor item for extended selection */
82b3fb8555SGiannis Adamopoulos     INT         item_height;    /* Default item height */
83b3fb8555SGiannis Adamopoulos     INT         page_size;      /* Items per listbox page */
84b3fb8555SGiannis Adamopoulos     INT         column_width;   /* Column width for multi-column listboxes */
85b3fb8555SGiannis Adamopoulos     INT         horz_extent;    /* Horizontal extent */
86b3fb8555SGiannis Adamopoulos     INT         horz_pos;       /* Horizontal position */
87b3fb8555SGiannis Adamopoulos     INT         nb_tabs;        /* Number of tabs in array */
88b3fb8555SGiannis Adamopoulos     INT        *tabs;           /* Array of tabs */
89b3fb8555SGiannis Adamopoulos     INT         avg_char_width; /* Average width of characters */
90b3fb8555SGiannis Adamopoulos     INT         wheel_remain;   /* Left over scroll amount */
91b3fb8555SGiannis Adamopoulos     BOOL        caret_on;       /* Is caret on? */
92b3fb8555SGiannis Adamopoulos     BOOL        captured;       /* Is mouse captured? */
93b3fb8555SGiannis Adamopoulos     BOOL        in_focus;
94b3fb8555SGiannis Adamopoulos     HFONT       font;           /* Current font */
95b3fb8555SGiannis Adamopoulos     LCID        locale;         /* Current locale for string comparisons */
96b3fb8555SGiannis Adamopoulos     HEADCOMBO  *lphc;           /* ComboLBox */
97b3fb8555SGiannis Adamopoulos } LB_DESCR;
98b3fb8555SGiannis Adamopoulos 
99b3fb8555SGiannis Adamopoulos 
100b3fb8555SGiannis Adamopoulos #define IS_OWNERDRAW(descr) \
101b3fb8555SGiannis Adamopoulos     ((descr)->style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE))
102b3fb8555SGiannis Adamopoulos 
103b3fb8555SGiannis Adamopoulos #define HAS_STRINGS(descr) \
104b3fb8555SGiannis Adamopoulos     (!IS_OWNERDRAW(descr) || ((descr)->style & LBS_HASSTRINGS))
105b3fb8555SGiannis Adamopoulos 
106b3fb8555SGiannis Adamopoulos 
107b3fb8555SGiannis Adamopoulos #define IS_MULTISELECT(descr) \
108b3fb8555SGiannis Adamopoulos     ((descr)->style & (LBS_MULTIPLESEL|LBS_EXTENDEDSEL) && \
109b3fb8555SGiannis Adamopoulos      !((descr)->style & LBS_NOSEL))
110b3fb8555SGiannis Adamopoulos 
111b3fb8555SGiannis Adamopoulos #define SEND_NOTIFICATION(descr,code) \
112b3fb8555SGiannis Adamopoulos     (SendMessageW( (descr)->owner, WM_COMMAND, \
113b3fb8555SGiannis Adamopoulos      MAKEWPARAM( GetWindowLongPtrW((descr->self),GWLP_ID), (code)), (LPARAM)(descr->self) ))
114b3fb8555SGiannis Adamopoulos 
115b3fb8555SGiannis Adamopoulos #define ISWIN31 (LOWORD(GetVersion()) == 0x0a03)
116b3fb8555SGiannis Adamopoulos 
117b3fb8555SGiannis Adamopoulos /* Current timer status */
118b3fb8555SGiannis Adamopoulos typedef enum
119b3fb8555SGiannis Adamopoulos {
120b3fb8555SGiannis Adamopoulos     LB_TIMER_NONE,
121b3fb8555SGiannis Adamopoulos     LB_TIMER_UP,
122b3fb8555SGiannis Adamopoulos     LB_TIMER_LEFT,
123b3fb8555SGiannis Adamopoulos     LB_TIMER_DOWN,
124b3fb8555SGiannis Adamopoulos     LB_TIMER_RIGHT
125b3fb8555SGiannis Adamopoulos } TIMER_DIRECTION;
126b3fb8555SGiannis Adamopoulos 
127b3fb8555SGiannis Adamopoulos static TIMER_DIRECTION LISTBOX_Timer = LB_TIMER_NONE;
128b3fb8555SGiannis Adamopoulos 
129b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_GetItemRect( const LB_DESCR *descr, INT index, RECT *rect );
130b3fb8555SGiannis Adamopoulos 
131*0707475fSJustin Miller /*
132*0707475fSJustin Miller    For listboxes without LBS_NODATA, an array of LB_ITEMDATA is allocated
133*0707475fSJustin Miller    to store the states of each item into descr->u.items.
134*0707475fSJustin Miller 
135*0707475fSJustin Miller    For single-selection LBS_NODATA listboxes, no storage is allocated,
136*0707475fSJustin Miller    and thus descr->u.nodata_items will always be NULL.
137*0707475fSJustin Miller 
138*0707475fSJustin Miller    For multi-selection LBS_NODATA listboxes, one byte per item is stored
139*0707475fSJustin Miller    for the item's selection state into descr->u.nodata_items.
140*0707475fSJustin Miller */
get_sizeof_item(const LB_DESCR * descr)141*0707475fSJustin Miller static size_t get_sizeof_item( const LB_DESCR *descr )
142*0707475fSJustin Miller {
143*0707475fSJustin Miller     return (descr->style & LBS_NODATA) ? sizeof(BYTE) : sizeof(LB_ITEMDATA);
144*0707475fSJustin Miller }
145*0707475fSJustin Miller 
resize_storage(LB_DESCR * descr,UINT items_size)146*0707475fSJustin Miller static BOOL resize_storage(LB_DESCR *descr, UINT items_size)
147*0707475fSJustin Miller {
148*0707475fSJustin Miller     LB_ITEMDATA *items;
149*0707475fSJustin Miller 
150*0707475fSJustin Miller     if (items_size > descr->items_size ||
151*0707475fSJustin Miller         items_size + LB_ARRAY_GRANULARITY * 2 < descr->items_size)
152*0707475fSJustin Miller     {
153*0707475fSJustin Miller         items_size = (items_size + LB_ARRAY_GRANULARITY - 1) & ~(LB_ARRAY_GRANULARITY - 1);
154*0707475fSJustin Miller         if ((descr->style & (LBS_NODATA | LBS_MULTIPLESEL | LBS_EXTENDEDSEL)) != LBS_NODATA)
155*0707475fSJustin Miller         {
156*0707475fSJustin Miller             items = heap_realloc(descr->u.items, items_size * get_sizeof_item(descr));
157*0707475fSJustin Miller             if (!items)
158*0707475fSJustin Miller             {
159*0707475fSJustin Miller                 SEND_NOTIFICATION(descr, LBN_ERRSPACE);
160*0707475fSJustin Miller                 return FALSE;
161*0707475fSJustin Miller             }
162*0707475fSJustin Miller             descr->u.items = items;
163*0707475fSJustin Miller         }
164*0707475fSJustin Miller         descr->items_size = items_size;
165*0707475fSJustin Miller     }
166*0707475fSJustin Miller 
167*0707475fSJustin Miller     if ((descr->style & LBS_NODATA) && descr->u.nodata_items && items_size > descr->nb_items)
168*0707475fSJustin Miller     {
169*0707475fSJustin Miller         memset(descr->u.nodata_items + descr->nb_items, 0,
170*0707475fSJustin Miller                (items_size - descr->nb_items) * get_sizeof_item(descr));
171*0707475fSJustin Miller     }
172*0707475fSJustin Miller     return TRUE;
173*0707475fSJustin Miller }
174*0707475fSJustin Miller 
get_item_data(const LB_DESCR * descr,UINT index)175*0707475fSJustin Miller static ULONG_PTR get_item_data( const LB_DESCR *descr, UINT index )
176*0707475fSJustin Miller {
177*0707475fSJustin Miller     return (descr->style & LBS_NODATA) ? 0 : descr->u.items[index].data;
178*0707475fSJustin Miller }
179*0707475fSJustin Miller 
set_item_data(LB_DESCR * descr,UINT index,ULONG_PTR data)180*0707475fSJustin Miller static void set_item_data( LB_DESCR *descr, UINT index, ULONG_PTR data )
181*0707475fSJustin Miller {
182*0707475fSJustin Miller     if (!(descr->style & LBS_NODATA)) descr->u.items[index].data = data;
183*0707475fSJustin Miller }
184*0707475fSJustin Miller 
get_item_string(const LB_DESCR * descr,UINT index)185*0707475fSJustin Miller static WCHAR *get_item_string( const LB_DESCR *descr, UINT index )
186*0707475fSJustin Miller {
187*0707475fSJustin Miller     return HAS_STRINGS(descr) ? descr->u.items[index].str : NULL;
188*0707475fSJustin Miller }
189*0707475fSJustin Miller 
set_item_string(const LB_DESCR * descr,UINT index,WCHAR * string)190*0707475fSJustin Miller static void set_item_string( const LB_DESCR *descr, UINT index, WCHAR *string )
191*0707475fSJustin Miller {
192*0707475fSJustin Miller     if (!(descr->style & LBS_NODATA)) descr->u.items[index].str = string;
193*0707475fSJustin Miller }
194*0707475fSJustin Miller 
get_item_height(const LB_DESCR * descr,UINT index)195*0707475fSJustin Miller static UINT get_item_height( const LB_DESCR *descr, UINT index )
196*0707475fSJustin Miller {
197*0707475fSJustin Miller     return (descr->style & LBS_NODATA) ? 0 : descr->u.items[index].height;
198*0707475fSJustin Miller }
199*0707475fSJustin Miller 
set_item_height(LB_DESCR * descr,UINT index,UINT height)200*0707475fSJustin Miller static void set_item_height( LB_DESCR *descr, UINT index, UINT height )
201*0707475fSJustin Miller {
202*0707475fSJustin Miller     if (!(descr->style & LBS_NODATA)) descr->u.items[index].height = height;
203*0707475fSJustin Miller }
204*0707475fSJustin Miller 
is_item_selected(const LB_DESCR * descr,UINT index)205*0707475fSJustin Miller static BOOL is_item_selected( const LB_DESCR *descr, UINT index )
206*0707475fSJustin Miller {
207*0707475fSJustin Miller     if (!(descr->style & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL)))
208*0707475fSJustin Miller         return index == descr->selected_item;
209*0707475fSJustin Miller     if (descr->style & LBS_NODATA)
210*0707475fSJustin Miller         return descr->u.nodata_items[index];
211*0707475fSJustin Miller     else
212*0707475fSJustin Miller         return descr->u.items[index].selected;
213*0707475fSJustin Miller }
214*0707475fSJustin Miller 
set_item_selected_state(LB_DESCR * descr,UINT index,BOOL state)215*0707475fSJustin Miller static void set_item_selected_state(LB_DESCR *descr, UINT index, BOOL state)
216*0707475fSJustin Miller {
217*0707475fSJustin Miller     if (descr->style & (LBS_MULTIPLESEL | LBS_EXTENDEDSEL))
218*0707475fSJustin Miller     {
219*0707475fSJustin Miller         if (descr->style & LBS_NODATA)
220*0707475fSJustin Miller             descr->u.nodata_items[index] = state;
221*0707475fSJustin Miller         else
222*0707475fSJustin Miller             descr->u.items[index].selected = state;
223*0707475fSJustin Miller     }
224*0707475fSJustin Miller }
225*0707475fSJustin Miller 
insert_item_data(LB_DESCR * descr,UINT index)226*0707475fSJustin Miller static void insert_item_data(LB_DESCR *descr, UINT index)
227*0707475fSJustin Miller {
228*0707475fSJustin Miller     size_t size = get_sizeof_item(descr);
229*0707475fSJustin Miller     BYTE *p = descr->u.nodata_items + index * size;
230*0707475fSJustin Miller 
231*0707475fSJustin Miller     if (!descr->u.items) return;
232*0707475fSJustin Miller 
233*0707475fSJustin Miller     if (index < descr->nb_items)
234*0707475fSJustin Miller         memmove(p + size, p, (descr->nb_items - index) * size);
235*0707475fSJustin Miller }
236*0707475fSJustin Miller 
remove_item_data(LB_DESCR * descr,UINT index)237*0707475fSJustin Miller static void remove_item_data(LB_DESCR *descr, UINT index)
238*0707475fSJustin Miller {
239*0707475fSJustin Miller     size_t size = get_sizeof_item(descr);
240*0707475fSJustin Miller     BYTE *p = descr->u.nodata_items + index * size;
241*0707475fSJustin Miller 
242*0707475fSJustin Miller     if (!descr->u.items) return;
243*0707475fSJustin Miller 
244*0707475fSJustin Miller     if (index < descr->nb_items)
245*0707475fSJustin Miller         memmove(p, p + size, (descr->nb_items - index) * size);
246*0707475fSJustin Miller }
247*0707475fSJustin Miller 
248b3fb8555SGiannis Adamopoulos /***********************************************************************
249b3fb8555SGiannis Adamopoulos  *           LISTBOX_GetCurrentPageSize
250b3fb8555SGiannis Adamopoulos  *
251b3fb8555SGiannis Adamopoulos  * Return the current page size
252b3fb8555SGiannis Adamopoulos  */
LISTBOX_GetCurrentPageSize(const LB_DESCR * descr)253b3fb8555SGiannis Adamopoulos static INT LISTBOX_GetCurrentPageSize( const LB_DESCR *descr )
254b3fb8555SGiannis Adamopoulos {
255b3fb8555SGiannis Adamopoulos     INT i, height;
256b3fb8555SGiannis Adamopoulos     if (!(descr->style & LBS_OWNERDRAWVARIABLE)) return descr->page_size;
257b3fb8555SGiannis Adamopoulos     for (i = descr->top_item, height = 0; i < descr->nb_items; i++)
258b3fb8555SGiannis Adamopoulos     {
259*0707475fSJustin Miller         if ((height += get_item_height(descr, i)) > descr->height) break;
260b3fb8555SGiannis Adamopoulos     }
261b3fb8555SGiannis Adamopoulos     if (i == descr->top_item) return 1;
262b3fb8555SGiannis Adamopoulos     else return i - descr->top_item;
263b3fb8555SGiannis Adamopoulos }
264b3fb8555SGiannis Adamopoulos 
265b3fb8555SGiannis Adamopoulos 
266b3fb8555SGiannis Adamopoulos /***********************************************************************
267b3fb8555SGiannis Adamopoulos  *           LISTBOX_GetMaxTopIndex
268b3fb8555SGiannis Adamopoulos  *
269b3fb8555SGiannis Adamopoulos  * Return the maximum possible index for the top of the listbox.
270b3fb8555SGiannis Adamopoulos  */
LISTBOX_GetMaxTopIndex(const LB_DESCR * descr)271b3fb8555SGiannis Adamopoulos static INT LISTBOX_GetMaxTopIndex( const LB_DESCR *descr )
272b3fb8555SGiannis Adamopoulos {
273b3fb8555SGiannis Adamopoulos     INT max, page;
274b3fb8555SGiannis Adamopoulos 
275b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_OWNERDRAWVARIABLE)
276b3fb8555SGiannis Adamopoulos     {
277b3fb8555SGiannis Adamopoulos         page = descr->height;
278b3fb8555SGiannis Adamopoulos         for (max = descr->nb_items - 1; max >= 0; max--)
279*0707475fSJustin Miller             if ((page -= get_item_height(descr, max)) < 0) break;
280b3fb8555SGiannis Adamopoulos         if (max < descr->nb_items - 1) max++;
281b3fb8555SGiannis Adamopoulos     }
282b3fb8555SGiannis Adamopoulos     else if (descr->style & LBS_MULTICOLUMN)
283b3fb8555SGiannis Adamopoulos     {
284b3fb8555SGiannis Adamopoulos         if ((page = descr->width / descr->column_width) < 1) page = 1;
285b3fb8555SGiannis Adamopoulos         max = (descr->nb_items + descr->page_size - 1) / descr->page_size;
286b3fb8555SGiannis Adamopoulos         max = (max - page) * descr->page_size;
287b3fb8555SGiannis Adamopoulos     }
288b3fb8555SGiannis Adamopoulos     else
289b3fb8555SGiannis Adamopoulos     {
290b3fb8555SGiannis Adamopoulos         max = descr->nb_items - descr->page_size;
291b3fb8555SGiannis Adamopoulos     }
292b3fb8555SGiannis Adamopoulos     if (max < 0) max = 0;
293b3fb8555SGiannis Adamopoulos     return max;
294b3fb8555SGiannis Adamopoulos }
295b3fb8555SGiannis Adamopoulos 
296b3fb8555SGiannis Adamopoulos 
297b3fb8555SGiannis Adamopoulos /***********************************************************************
298b3fb8555SGiannis Adamopoulos  *           LISTBOX_UpdateScroll
299b3fb8555SGiannis Adamopoulos  *
300b3fb8555SGiannis Adamopoulos  * Update the scrollbars. Should be called whenever the content
301b3fb8555SGiannis Adamopoulos  * of the listbox changes.
302b3fb8555SGiannis Adamopoulos  */
LISTBOX_UpdateScroll(LB_DESCR * descr)303b3fb8555SGiannis Adamopoulos static void LISTBOX_UpdateScroll( LB_DESCR *descr )
304b3fb8555SGiannis Adamopoulos {
305b3fb8555SGiannis Adamopoulos     SCROLLINFO info;
306b3fb8555SGiannis Adamopoulos 
307b3fb8555SGiannis Adamopoulos     /* Check the listbox scroll bar flags individually before we call
308b3fb8555SGiannis Adamopoulos        SetScrollInfo otherwise when the listbox style is WS_HSCROLL and
309b3fb8555SGiannis Adamopoulos        no WS_VSCROLL, we end up with an uninitialized, visible horizontal
310b3fb8555SGiannis Adamopoulos        scroll bar when we do not need one.
311b3fb8555SGiannis Adamopoulos     if (!(descr->style & WS_VSCROLL)) return;
312b3fb8555SGiannis Adamopoulos     */
313b3fb8555SGiannis Adamopoulos 
314b3fb8555SGiannis Adamopoulos     /*   It is important that we check descr->style, and not wnd->dwStyle,
315b3fb8555SGiannis Adamopoulos        for WS_VSCROLL, as the former is exactly the one passed in
316b3fb8555SGiannis Adamopoulos        argument to CreateWindow.
317b3fb8555SGiannis Adamopoulos          In Windows (and from now on in Wine :) a listbox created
318b3fb8555SGiannis Adamopoulos        with such a style (no WS_SCROLL) does not update
319b3fb8555SGiannis Adamopoulos        the scrollbar with listbox-related data, thus letting
320b3fb8555SGiannis Adamopoulos        the programmer use it for his/her own purposes. */
321b3fb8555SGiannis Adamopoulos 
322b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_NOREDRAW) return;
323b3fb8555SGiannis Adamopoulos     info.cbSize = sizeof(info);
324b3fb8555SGiannis Adamopoulos 
325b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_MULTICOLUMN)
326b3fb8555SGiannis Adamopoulos     {
327b3fb8555SGiannis Adamopoulos         info.nMin  = 0;
328b3fb8555SGiannis Adamopoulos         info.nMax  = (descr->nb_items - 1) / descr->page_size;
329b3fb8555SGiannis Adamopoulos         info.nPos  = descr->top_item / descr->page_size;
330b3fb8555SGiannis Adamopoulos         info.nPage = descr->width / descr->column_width;
331b3fb8555SGiannis Adamopoulos         if (info.nPage < 1) info.nPage = 1;
332b3fb8555SGiannis Adamopoulos         info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
333b3fb8555SGiannis Adamopoulos         if (descr->style & LBS_DISABLENOSCROLL)
334b3fb8555SGiannis Adamopoulos             info.fMask |= SIF_DISABLENOSCROLL;
335b3fb8555SGiannis Adamopoulos         if (descr->style & WS_HSCROLL)
336b3fb8555SGiannis Adamopoulos             SetScrollInfo( descr->self, SB_HORZ, &info, TRUE );
337b3fb8555SGiannis Adamopoulos         info.nMax = 0;
338b3fb8555SGiannis Adamopoulos         info.fMask = SIF_RANGE;
339b3fb8555SGiannis Adamopoulos         if (descr->style & WS_VSCROLL)
340b3fb8555SGiannis Adamopoulos             SetScrollInfo( descr->self, SB_VERT, &info, TRUE );
341b3fb8555SGiannis Adamopoulos     }
342b3fb8555SGiannis Adamopoulos     else
343b3fb8555SGiannis Adamopoulos     {
344b3fb8555SGiannis Adamopoulos         info.nMin  = 0;
345b3fb8555SGiannis Adamopoulos         info.nMax  = descr->nb_items - 1;
346b3fb8555SGiannis Adamopoulos         info.nPos  = descr->top_item;
347b3fb8555SGiannis Adamopoulos         info.nPage = LISTBOX_GetCurrentPageSize( descr );
348b3fb8555SGiannis Adamopoulos         info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
349b3fb8555SGiannis Adamopoulos         if (descr->style & LBS_DISABLENOSCROLL)
350b3fb8555SGiannis Adamopoulos             info.fMask |= SIF_DISABLENOSCROLL;
351b3fb8555SGiannis Adamopoulos         if (descr->style & WS_VSCROLL)
352b3fb8555SGiannis Adamopoulos             SetScrollInfo( descr->self, SB_VERT, &info, TRUE );
353b3fb8555SGiannis Adamopoulos 
354b3fb8555SGiannis Adamopoulos         if ((descr->style & WS_HSCROLL) && descr->horz_extent)
355b3fb8555SGiannis Adamopoulos         {
356b3fb8555SGiannis Adamopoulos             info.nPos  = descr->horz_pos;
357b3fb8555SGiannis Adamopoulos             info.nPage = descr->width;
358b3fb8555SGiannis Adamopoulos             info.fMask = SIF_POS | SIF_PAGE;
359b3fb8555SGiannis Adamopoulos             if (descr->style & LBS_DISABLENOSCROLL)
360b3fb8555SGiannis Adamopoulos                 info.fMask |= SIF_DISABLENOSCROLL;
361b3fb8555SGiannis Adamopoulos             SetScrollInfo( descr->self, SB_HORZ, &info, TRUE );
362b3fb8555SGiannis Adamopoulos         }
363b3fb8555SGiannis Adamopoulos         else
364b3fb8555SGiannis Adamopoulos         {
365b3fb8555SGiannis Adamopoulos             if (descr->style & LBS_DISABLENOSCROLL)
366b3fb8555SGiannis Adamopoulos             {
367b3fb8555SGiannis Adamopoulos                 info.nMin  = 0;
368b3fb8555SGiannis Adamopoulos                 info.nMax  = 0;
369b3fb8555SGiannis Adamopoulos                 info.fMask = SIF_RANGE | SIF_DISABLENOSCROLL;
370b3fb8555SGiannis Adamopoulos                 SetScrollInfo( descr->self, SB_HORZ, &info, TRUE );
371b3fb8555SGiannis Adamopoulos             }
372b3fb8555SGiannis Adamopoulos             else
373b3fb8555SGiannis Adamopoulos             {
374b3fb8555SGiannis Adamopoulos                 ShowScrollBar( descr->self, SB_HORZ, FALSE );
375b3fb8555SGiannis Adamopoulos             }
376b3fb8555SGiannis Adamopoulos         }
377b3fb8555SGiannis Adamopoulos     }
378b3fb8555SGiannis Adamopoulos }
379b3fb8555SGiannis Adamopoulos 
380b3fb8555SGiannis Adamopoulos 
381b3fb8555SGiannis Adamopoulos /***********************************************************************
382b3fb8555SGiannis Adamopoulos  *           LISTBOX_SetTopItem
383b3fb8555SGiannis Adamopoulos  *
384b3fb8555SGiannis Adamopoulos  * Set the top item of the listbox, scrolling up or down if necessary.
385b3fb8555SGiannis Adamopoulos  */
LISTBOX_SetTopItem(LB_DESCR * descr,INT index,BOOL scroll)386b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_SetTopItem( LB_DESCR *descr, INT index, BOOL scroll )
387b3fb8555SGiannis Adamopoulos {
388b3fb8555SGiannis Adamopoulos     INT max = LISTBOX_GetMaxTopIndex( descr );
389b3fb8555SGiannis Adamopoulos 
390b3fb8555SGiannis Adamopoulos     TRACE("setting top item %d, scroll %d\n", index, scroll);
391b3fb8555SGiannis Adamopoulos 
392b3fb8555SGiannis Adamopoulos     if (index > max) index = max;
393b3fb8555SGiannis Adamopoulos     if (index < 0) index = 0;
394b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_MULTICOLUMN) index -= index % descr->page_size;
395b3fb8555SGiannis Adamopoulos     if (descr->top_item == index) return LB_OKAY;
396b3fb8555SGiannis Adamopoulos     if (scroll)
397b3fb8555SGiannis Adamopoulos     {
398*0707475fSJustin Miller         INT dx = 0, dy = 0;
399b3fb8555SGiannis Adamopoulos         if (descr->style & LBS_MULTICOLUMN)
400*0707475fSJustin Miller             dx = (descr->top_item - index) / descr->page_size * descr->column_width;
401b3fb8555SGiannis Adamopoulos         else if (descr->style & LBS_OWNERDRAWVARIABLE)
402b3fb8555SGiannis Adamopoulos         {
403b3fb8555SGiannis Adamopoulos             INT i;
404b3fb8555SGiannis Adamopoulos             if (index > descr->top_item)
405b3fb8555SGiannis Adamopoulos             {
406b3fb8555SGiannis Adamopoulos                 for (i = index - 1; i >= descr->top_item; i--)
407*0707475fSJustin Miller                     dy -= get_item_height(descr, i);
408b3fb8555SGiannis Adamopoulos             }
409b3fb8555SGiannis Adamopoulos             else
410b3fb8555SGiannis Adamopoulos             {
411b3fb8555SGiannis Adamopoulos                 for (i = index; i < descr->top_item; i++)
412*0707475fSJustin Miller                     dy += get_item_height(descr, i);
413b3fb8555SGiannis Adamopoulos             }
414b3fb8555SGiannis Adamopoulos         }
415b3fb8555SGiannis Adamopoulos         else
416*0707475fSJustin Miller             dy = (descr->top_item - index) * descr->item_height;
417b3fb8555SGiannis Adamopoulos 
418*0707475fSJustin Miller         ScrollWindowEx( descr->self, dx, dy, NULL, NULL, 0, NULL,
419b3fb8555SGiannis Adamopoulos                         SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
420b3fb8555SGiannis Adamopoulos     }
421b3fb8555SGiannis Adamopoulos     else
422b3fb8555SGiannis Adamopoulos         InvalidateRect( descr->self, NULL, TRUE );
423b3fb8555SGiannis Adamopoulos     descr->top_item = index;
424b3fb8555SGiannis Adamopoulos     LISTBOX_UpdateScroll( descr );
425b3fb8555SGiannis Adamopoulos     return LB_OKAY;
426b3fb8555SGiannis Adamopoulos }
427b3fb8555SGiannis Adamopoulos 
428b3fb8555SGiannis Adamopoulos 
429b3fb8555SGiannis Adamopoulos /***********************************************************************
430b3fb8555SGiannis Adamopoulos  *           LISTBOX_UpdatePage
431b3fb8555SGiannis Adamopoulos  *
432b3fb8555SGiannis Adamopoulos  * Update the page size. Should be called when the size of
433b3fb8555SGiannis Adamopoulos  * the client area or the item height changes.
434b3fb8555SGiannis Adamopoulos  */
LISTBOX_UpdatePage(LB_DESCR * descr)435b3fb8555SGiannis Adamopoulos static void LISTBOX_UpdatePage( LB_DESCR *descr )
436b3fb8555SGiannis Adamopoulos {
437b3fb8555SGiannis Adamopoulos     INT page_size;
438b3fb8555SGiannis Adamopoulos 
439b3fb8555SGiannis Adamopoulos     if ((descr->item_height == 0) || (page_size = descr->height / descr->item_height) < 1)
440b3fb8555SGiannis Adamopoulos                        page_size = 1;
441b3fb8555SGiannis Adamopoulos     if (page_size == descr->page_size) return;
442b3fb8555SGiannis Adamopoulos     descr->page_size = page_size;
443b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_MULTICOLUMN)
444b3fb8555SGiannis Adamopoulos         InvalidateRect( descr->self, NULL, TRUE );
445b3fb8555SGiannis Adamopoulos     LISTBOX_SetTopItem( descr, descr->top_item, FALSE );
446b3fb8555SGiannis Adamopoulos }
447b3fb8555SGiannis Adamopoulos 
448b3fb8555SGiannis Adamopoulos 
449b3fb8555SGiannis Adamopoulos /***********************************************************************
450b3fb8555SGiannis Adamopoulos  *           LISTBOX_UpdateSize
451b3fb8555SGiannis Adamopoulos  *
452b3fb8555SGiannis Adamopoulos  * Update the size of the listbox. Should be called when the size of
453b3fb8555SGiannis Adamopoulos  * the client area changes.
454b3fb8555SGiannis Adamopoulos  */
LISTBOX_UpdateSize(LB_DESCR * descr)455b3fb8555SGiannis Adamopoulos static void LISTBOX_UpdateSize( LB_DESCR *descr )
456b3fb8555SGiannis Adamopoulos {
457b3fb8555SGiannis Adamopoulos     RECT rect;
458b3fb8555SGiannis Adamopoulos 
459b3fb8555SGiannis Adamopoulos     GetClientRect( descr->self, &rect );
460b3fb8555SGiannis Adamopoulos     descr->width  = rect.right - rect.left;
461b3fb8555SGiannis Adamopoulos     descr->height = rect.bottom - rect.top;
462b3fb8555SGiannis Adamopoulos     if (!(descr->style & LBS_NOINTEGRALHEIGHT) && !(descr->style & LBS_OWNERDRAWVARIABLE))
463b3fb8555SGiannis Adamopoulos     {
464b3fb8555SGiannis Adamopoulos         INT remaining;
465b3fb8555SGiannis Adamopoulos         RECT rect;
466b3fb8555SGiannis Adamopoulos 
467b3fb8555SGiannis Adamopoulos         GetWindowRect( descr->self, &rect );
468b3fb8555SGiannis Adamopoulos         if(descr->item_height != 0)
469b3fb8555SGiannis Adamopoulos             remaining = descr->height % descr->item_height;
470b3fb8555SGiannis Adamopoulos         else
471b3fb8555SGiannis Adamopoulos             remaining = 0;
472b3fb8555SGiannis Adamopoulos         if ((descr->height > descr->item_height) && remaining)
473b3fb8555SGiannis Adamopoulos         {
474b3fb8555SGiannis Adamopoulos             TRACE("[%p]: changing height %d -> %d\n",
475b3fb8555SGiannis Adamopoulos                   descr->self, descr->height, descr->height - remaining );
476b3fb8555SGiannis Adamopoulos             SetWindowPos( descr->self, 0, 0, 0, rect.right - rect.left,
477b3fb8555SGiannis Adamopoulos                           rect.bottom - rect.top - remaining,
478b3fb8555SGiannis Adamopoulos                           SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE );
479b3fb8555SGiannis Adamopoulos             return;
480b3fb8555SGiannis Adamopoulos         }
481b3fb8555SGiannis Adamopoulos     }
482b3fb8555SGiannis Adamopoulos     TRACE("[%p]: new size = %d,%d\n", descr->self, descr->width, descr->height );
483b3fb8555SGiannis Adamopoulos     LISTBOX_UpdatePage( descr );
484b3fb8555SGiannis Adamopoulos     LISTBOX_UpdateScroll( descr );
485b3fb8555SGiannis Adamopoulos 
486b3fb8555SGiannis Adamopoulos     /* Invalidate the focused item so it will be repainted correctly */
487b3fb8555SGiannis Adamopoulos     if (LISTBOX_GetItemRect( descr, descr->focus_item, &rect ) == 1)
488b3fb8555SGiannis Adamopoulos     {
489b3fb8555SGiannis Adamopoulos         InvalidateRect( descr->self, &rect, FALSE );
490b3fb8555SGiannis Adamopoulos     }
491b3fb8555SGiannis Adamopoulos }
492b3fb8555SGiannis Adamopoulos 
493b3fb8555SGiannis Adamopoulos 
494b3fb8555SGiannis Adamopoulos /***********************************************************************
495b3fb8555SGiannis Adamopoulos  *           LISTBOX_GetItemRect
496b3fb8555SGiannis Adamopoulos  *
497b3fb8555SGiannis Adamopoulos  * Get the rectangle enclosing an item, in listbox client coordinates.
498b3fb8555SGiannis Adamopoulos  * Return 1 if the rectangle is (partially) visible, 0 if hidden, -1 on error.
499b3fb8555SGiannis Adamopoulos  */
LISTBOX_GetItemRect(const LB_DESCR * descr,INT index,RECT * rect)500b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_GetItemRect( const LB_DESCR *descr, INT index, RECT *rect )
501b3fb8555SGiannis Adamopoulos {
502b3fb8555SGiannis Adamopoulos     /* Index <= 0 is legal even on empty listboxes */
503b3fb8555SGiannis Adamopoulos     if (index && (index >= descr->nb_items))
504b3fb8555SGiannis Adamopoulos     {
505b3fb8555SGiannis Adamopoulos         SetRectEmpty(rect);
506b3fb8555SGiannis Adamopoulos         SetLastError(ERROR_INVALID_INDEX);
507b3fb8555SGiannis Adamopoulos         return LB_ERR;
508b3fb8555SGiannis Adamopoulos     }
509b3fb8555SGiannis Adamopoulos     SetRect( rect, 0, 0, descr->width, descr->height );
510b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_MULTICOLUMN)
511b3fb8555SGiannis Adamopoulos     {
512b3fb8555SGiannis Adamopoulos         INT col = (index / descr->page_size) -
513b3fb8555SGiannis Adamopoulos                         (descr->top_item / descr->page_size);
514b3fb8555SGiannis Adamopoulos         rect->left += col * descr->column_width;
515b3fb8555SGiannis Adamopoulos         rect->right = rect->left + descr->column_width;
516b3fb8555SGiannis Adamopoulos         rect->top += (index % descr->page_size) * descr->item_height;
517b3fb8555SGiannis Adamopoulos         rect->bottom = rect->top + descr->item_height;
518b3fb8555SGiannis Adamopoulos     }
519b3fb8555SGiannis Adamopoulos     else if (descr->style & LBS_OWNERDRAWVARIABLE)
520b3fb8555SGiannis Adamopoulos     {
521b3fb8555SGiannis Adamopoulos         INT i;
522b3fb8555SGiannis Adamopoulos         rect->right += descr->horz_pos;
523b3fb8555SGiannis Adamopoulos         if ((index >= 0) && (index < descr->nb_items))
524b3fb8555SGiannis Adamopoulos         {
525b3fb8555SGiannis Adamopoulos             if (index < descr->top_item)
526b3fb8555SGiannis Adamopoulos             {
527b3fb8555SGiannis Adamopoulos                 for (i = descr->top_item-1; i >= index; i--)
528*0707475fSJustin Miller                     rect->top -= get_item_height(descr, i);
529b3fb8555SGiannis Adamopoulos             }
530b3fb8555SGiannis Adamopoulos             else
531b3fb8555SGiannis Adamopoulos             {
532b3fb8555SGiannis Adamopoulos                 for (i = descr->top_item; i < index; i++)
533*0707475fSJustin Miller                     rect->top += get_item_height(descr, i);
534b3fb8555SGiannis Adamopoulos             }
535*0707475fSJustin Miller             rect->bottom = rect->top + get_item_height(descr, index);
536b3fb8555SGiannis Adamopoulos 
537b3fb8555SGiannis Adamopoulos         }
538b3fb8555SGiannis Adamopoulos     }
539b3fb8555SGiannis Adamopoulos     else
540b3fb8555SGiannis Adamopoulos     {
541b3fb8555SGiannis Adamopoulos         rect->top += (index - descr->top_item) * descr->item_height;
542b3fb8555SGiannis Adamopoulos         rect->bottom = rect->top + descr->item_height;
543b3fb8555SGiannis Adamopoulos         rect->right += descr->horz_pos;
544b3fb8555SGiannis Adamopoulos     }
545b3fb8555SGiannis Adamopoulos 
546b3fb8555SGiannis Adamopoulos     TRACE("item %d, rect %s\n", index, wine_dbgstr_rect(rect));
547b3fb8555SGiannis Adamopoulos 
548b3fb8555SGiannis Adamopoulos     return ((rect->left < descr->width) && (rect->right > 0) &&
549b3fb8555SGiannis Adamopoulos             (rect->top < descr->height) && (rect->bottom > 0));
550b3fb8555SGiannis Adamopoulos }
551b3fb8555SGiannis Adamopoulos 
552b3fb8555SGiannis Adamopoulos 
553b3fb8555SGiannis Adamopoulos /***********************************************************************
554b3fb8555SGiannis Adamopoulos  *           LISTBOX_GetItemFromPoint
555b3fb8555SGiannis Adamopoulos  *
556b3fb8555SGiannis Adamopoulos  * Return the item nearest from point (x,y) (in client coordinates).
557b3fb8555SGiannis Adamopoulos  */
LISTBOX_GetItemFromPoint(const LB_DESCR * descr,INT x,INT y)558b3fb8555SGiannis Adamopoulos static INT LISTBOX_GetItemFromPoint( const LB_DESCR *descr, INT x, INT y )
559b3fb8555SGiannis Adamopoulos {
560b3fb8555SGiannis Adamopoulos     INT index = descr->top_item;
561b3fb8555SGiannis Adamopoulos 
562b3fb8555SGiannis Adamopoulos     if (!descr->nb_items) return -1;  /* No items */
563b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_OWNERDRAWVARIABLE)
564b3fb8555SGiannis Adamopoulos     {
565b3fb8555SGiannis Adamopoulos         INT pos = 0;
566b3fb8555SGiannis Adamopoulos         if (y >= 0)
567b3fb8555SGiannis Adamopoulos         {
568b3fb8555SGiannis Adamopoulos             while (index < descr->nb_items)
569b3fb8555SGiannis Adamopoulos             {
570*0707475fSJustin Miller                 if ((pos += get_item_height(descr, index)) > y) break;
571b3fb8555SGiannis Adamopoulos                 index++;
572b3fb8555SGiannis Adamopoulos             }
573b3fb8555SGiannis Adamopoulos         }
574b3fb8555SGiannis Adamopoulos         else
575b3fb8555SGiannis Adamopoulos         {
576b3fb8555SGiannis Adamopoulos             while (index > 0)
577b3fb8555SGiannis Adamopoulos             {
578b3fb8555SGiannis Adamopoulos                 index--;
579*0707475fSJustin Miller                 if ((pos -= get_item_height(descr, index)) <= y) break;
580b3fb8555SGiannis Adamopoulos             }
581b3fb8555SGiannis Adamopoulos         }
582b3fb8555SGiannis Adamopoulos     }
583b3fb8555SGiannis Adamopoulos     else if (descr->style & LBS_MULTICOLUMN)
584b3fb8555SGiannis Adamopoulos     {
585b3fb8555SGiannis Adamopoulos         if (y >= descr->item_height * descr->page_size) return -1;
586b3fb8555SGiannis Adamopoulos         if (y >= 0) index += y / descr->item_height;
587b3fb8555SGiannis Adamopoulos         if (x >= 0) index += (x / descr->column_width) * descr->page_size;
588b3fb8555SGiannis Adamopoulos         else index -= (((x + 1) / descr->column_width) - 1) * descr->page_size;
589b3fb8555SGiannis Adamopoulos     }
590b3fb8555SGiannis Adamopoulos     else
591b3fb8555SGiannis Adamopoulos     {
592b3fb8555SGiannis Adamopoulos         index += (y / descr->item_height);
593b3fb8555SGiannis Adamopoulos     }
594b3fb8555SGiannis Adamopoulos     if (index < 0) return 0;
595b3fb8555SGiannis Adamopoulos     if (index >= descr->nb_items) return -1;
596b3fb8555SGiannis Adamopoulos     return index;
597b3fb8555SGiannis Adamopoulos }
598b3fb8555SGiannis Adamopoulos 
599b3fb8555SGiannis Adamopoulos 
600b3fb8555SGiannis Adamopoulos /***********************************************************************
601b3fb8555SGiannis Adamopoulos  *           LISTBOX_PaintItem
602b3fb8555SGiannis Adamopoulos  *
603b3fb8555SGiannis Adamopoulos  * Paint an item.
604b3fb8555SGiannis Adamopoulos  */
LISTBOX_PaintItem(LB_DESCR * descr,HDC hdc,const RECT * rect,INT index,UINT action,BOOL ignoreFocus)605b3fb8555SGiannis Adamopoulos static void LISTBOX_PaintItem( LB_DESCR *descr, HDC hdc, const RECT *rect,
606b3fb8555SGiannis Adamopoulos 			       INT index, UINT action, BOOL ignoreFocus )
607b3fb8555SGiannis Adamopoulos {
608*0707475fSJustin Miller     BOOL selected = FALSE, focused;
609*0707475fSJustin Miller     WCHAR *item_str = NULL;
610*0707475fSJustin Miller 
611*0707475fSJustin Miller     if (index < descr->nb_items)
612*0707475fSJustin Miller     {
613*0707475fSJustin Miller         item_str = get_item_string(descr, index);
614*0707475fSJustin Miller         selected = is_item_selected(descr, index);
615*0707475fSJustin Miller     }
616*0707475fSJustin Miller 
617*0707475fSJustin Miller     focused = !ignoreFocus && descr->focus_item == index && descr->caret_on && descr->in_focus;
618b3fb8555SGiannis Adamopoulos 
619b3fb8555SGiannis Adamopoulos     if (IS_OWNERDRAW(descr))
620b3fb8555SGiannis Adamopoulos     {
621b3fb8555SGiannis Adamopoulos         DRAWITEMSTRUCT dis;
622b3fb8555SGiannis Adamopoulos         RECT r;
623b3fb8555SGiannis Adamopoulos         HRGN hrgn;
624b3fb8555SGiannis Adamopoulos 
625*0707475fSJustin Miller 	if (index >= descr->nb_items)
626b3fb8555SGiannis Adamopoulos 	{
627b3fb8555SGiannis Adamopoulos 	    if (action == ODA_FOCUS)
628b3fb8555SGiannis Adamopoulos 		DrawFocusRect( hdc, rect );
629b3fb8555SGiannis Adamopoulos 	    else
630b3fb8555SGiannis Adamopoulos 	        ERR("called with an out of bounds index %d(%d) in owner draw, Not good.\n",index,descr->nb_items);
631b3fb8555SGiannis Adamopoulos 	    return;
632b3fb8555SGiannis Adamopoulos 	}
633b3fb8555SGiannis Adamopoulos 
634b3fb8555SGiannis Adamopoulos         /* some programs mess with the clipping region when
635b3fb8555SGiannis Adamopoulos         drawing the item, *and* restore the previous region
636b3fb8555SGiannis Adamopoulos         after they are done, so a region has better to exist
637b3fb8555SGiannis Adamopoulos         else everything ends clipped */
638b3fb8555SGiannis Adamopoulos         GetClientRect(descr->self, &r);
639b3fb8555SGiannis Adamopoulos         hrgn = set_control_clipping( hdc, &r );
640b3fb8555SGiannis Adamopoulos 
641b3fb8555SGiannis Adamopoulos         dis.CtlType      = ODT_LISTBOX;
642b3fb8555SGiannis Adamopoulos         dis.CtlID        = GetWindowLongPtrW( descr->self, GWLP_ID );
643b3fb8555SGiannis Adamopoulos         dis.hwndItem     = descr->self;
644b3fb8555SGiannis Adamopoulos         dis.itemAction   = action;
645b3fb8555SGiannis Adamopoulos         dis.hDC          = hdc;
646b3fb8555SGiannis Adamopoulos         dis.itemID       = index;
647b3fb8555SGiannis Adamopoulos         dis.itemState    = 0;
648*0707475fSJustin Miller         if (selected)
649*0707475fSJustin Miller             dis.itemState |= ODS_SELECTED;
650*0707475fSJustin Miller         if (focused)
651*0707475fSJustin Miller             dis.itemState |= ODS_FOCUS;
652b3fb8555SGiannis Adamopoulos         if (!IsWindowEnabled(descr->self)) dis.itemState |= ODS_DISABLED;
653*0707475fSJustin Miller         dis.itemData     = get_item_data(descr, index);
654b3fb8555SGiannis Adamopoulos         dis.rcItem       = *rect;
655b3fb8555SGiannis Adamopoulos         TRACE("[%p]: drawitem %d (%s) action=%02x state=%02x rect=%s\n",
656*0707475fSJustin Miller               descr->self, index, debugstr_w(item_str), action,
657b3fb8555SGiannis Adamopoulos               dis.itemState, wine_dbgstr_rect(rect) );
658b3fb8555SGiannis Adamopoulos         SendMessageW(descr->owner, WM_DRAWITEM, dis.CtlID, (LPARAM)&dis);
659b3fb8555SGiannis Adamopoulos         SelectClipRgn( hdc, hrgn );
660b3fb8555SGiannis Adamopoulos         if (hrgn) DeleteObject( hrgn );
661b3fb8555SGiannis Adamopoulos     }
662b3fb8555SGiannis Adamopoulos     else
663b3fb8555SGiannis Adamopoulos     {
664b3fb8555SGiannis Adamopoulos         COLORREF oldText = 0, oldBk = 0;
665b3fb8555SGiannis Adamopoulos 
666b3fb8555SGiannis Adamopoulos         if (action == ODA_FOCUS)
667b3fb8555SGiannis Adamopoulos         {
668b3fb8555SGiannis Adamopoulos             DrawFocusRect( hdc, rect );
669b3fb8555SGiannis Adamopoulos             return;
670b3fb8555SGiannis Adamopoulos         }
671*0707475fSJustin Miller         if (selected)
672b3fb8555SGiannis Adamopoulos         {
673b3fb8555SGiannis Adamopoulos             oldBk = SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
674b3fb8555SGiannis Adamopoulos             oldText = SetTextColor( hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
675b3fb8555SGiannis Adamopoulos         }
676b3fb8555SGiannis Adamopoulos 
677b3fb8555SGiannis Adamopoulos         TRACE("[%p]: painting %d (%s) action=%02x rect=%s\n",
678*0707475fSJustin Miller               descr->self, index, debugstr_w(item_str), action,
679b3fb8555SGiannis Adamopoulos               wine_dbgstr_rect(rect) );
680*0707475fSJustin Miller         if (!item_str)
681b3fb8555SGiannis Adamopoulos             ExtTextOutW( hdc, rect->left + 1, rect->top,
682b3fb8555SGiannis Adamopoulos                            ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
683b3fb8555SGiannis Adamopoulos         else if (!(descr->style & LBS_USETABSTOPS))
684b3fb8555SGiannis Adamopoulos             ExtTextOutW( hdc, rect->left + 1, rect->top,
685*0707475fSJustin Miller                          ETO_OPAQUE | ETO_CLIPPED, rect, item_str,
686*0707475fSJustin Miller                          lstrlenW(item_str), NULL );
687b3fb8555SGiannis Adamopoulos         else
688b3fb8555SGiannis Adamopoulos 	{
689b3fb8555SGiannis Adamopoulos 	    /* Output empty string to paint background in the full width. */
690b3fb8555SGiannis Adamopoulos             ExtTextOutW( hdc, rect->left + 1, rect->top,
691b3fb8555SGiannis Adamopoulos                          ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
692b3fb8555SGiannis Adamopoulos             TabbedTextOutW( hdc, rect->left + 1 , rect->top,
693*0707475fSJustin Miller                             item_str, lstrlenW(item_str),
694b3fb8555SGiannis Adamopoulos                             descr->nb_tabs, descr->tabs, 0);
695b3fb8555SGiannis Adamopoulos 	}
696*0707475fSJustin Miller         if (selected)
697b3fb8555SGiannis Adamopoulos         {
698b3fb8555SGiannis Adamopoulos             SetBkColor( hdc, oldBk );
699b3fb8555SGiannis Adamopoulos             SetTextColor( hdc, oldText );
700b3fb8555SGiannis Adamopoulos         }
701*0707475fSJustin Miller         if (focused)
702*0707475fSJustin Miller             DrawFocusRect( hdc, rect );
703b3fb8555SGiannis Adamopoulos     }
704b3fb8555SGiannis Adamopoulos }
705b3fb8555SGiannis Adamopoulos 
706b3fb8555SGiannis Adamopoulos 
707b3fb8555SGiannis Adamopoulos /***********************************************************************
708b3fb8555SGiannis Adamopoulos  *           LISTBOX_SetRedraw
709b3fb8555SGiannis Adamopoulos  *
710b3fb8555SGiannis Adamopoulos  * Change the redraw flag.
711b3fb8555SGiannis Adamopoulos  */
LISTBOX_SetRedraw(LB_DESCR * descr,BOOL on)712b3fb8555SGiannis Adamopoulos static void LISTBOX_SetRedraw( LB_DESCR *descr, BOOL on )
713b3fb8555SGiannis Adamopoulos {
714b3fb8555SGiannis Adamopoulos     if (on)
715b3fb8555SGiannis Adamopoulos     {
716b3fb8555SGiannis Adamopoulos         if (!(descr->style & LBS_NOREDRAW)) return;
717b3fb8555SGiannis Adamopoulos         descr->style &= ~LBS_NOREDRAW;
718b3fb8555SGiannis Adamopoulos         if (descr->style & LBS_DISPLAYCHANGED)
719b3fb8555SGiannis Adamopoulos         {     /* page was changed while setredraw false, refresh automatically */
720b3fb8555SGiannis Adamopoulos             InvalidateRect(descr->self, NULL, TRUE);
721b3fb8555SGiannis Adamopoulos             if ((descr->top_item + descr->page_size) > descr->nb_items)
722b3fb8555SGiannis Adamopoulos             {      /* reset top of page if less than number of items/page */
723b3fb8555SGiannis Adamopoulos                 descr->top_item = descr->nb_items - descr->page_size;
724b3fb8555SGiannis Adamopoulos                 if (descr->top_item < 0) descr->top_item = 0;
725b3fb8555SGiannis Adamopoulos             }
726b3fb8555SGiannis Adamopoulos             descr->style &= ~LBS_DISPLAYCHANGED;
727b3fb8555SGiannis Adamopoulos         }
728b3fb8555SGiannis Adamopoulos         LISTBOX_UpdateScroll( descr );
729b3fb8555SGiannis Adamopoulos     }
730b3fb8555SGiannis Adamopoulos     else descr->style |= LBS_NOREDRAW;
731b3fb8555SGiannis Adamopoulos }
732b3fb8555SGiannis Adamopoulos 
733b3fb8555SGiannis Adamopoulos 
734b3fb8555SGiannis Adamopoulos /***********************************************************************
735b3fb8555SGiannis Adamopoulos  *           LISTBOX_RepaintItem
736b3fb8555SGiannis Adamopoulos  *
737b3fb8555SGiannis Adamopoulos  * Repaint a single item synchronously.
738b3fb8555SGiannis Adamopoulos  */
LISTBOX_RepaintItem(LB_DESCR * descr,INT index,UINT action)739b3fb8555SGiannis Adamopoulos static void LISTBOX_RepaintItem( LB_DESCR *descr, INT index, UINT action )
740b3fb8555SGiannis Adamopoulos {
741b3fb8555SGiannis Adamopoulos     HDC hdc;
742b3fb8555SGiannis Adamopoulos     RECT rect;
743b3fb8555SGiannis Adamopoulos     HFONT oldFont = 0;
744b3fb8555SGiannis Adamopoulos     HBRUSH hbrush, oldBrush = 0;
745b3fb8555SGiannis Adamopoulos 
746b3fb8555SGiannis Adamopoulos     /* Do not repaint the item if the item is not visible */
747b3fb8555SGiannis Adamopoulos     if (!IsWindowVisible(descr->self)) return;
748b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_NOREDRAW)
749b3fb8555SGiannis Adamopoulos     {
750b3fb8555SGiannis Adamopoulos         descr->style |= LBS_DISPLAYCHANGED;
751b3fb8555SGiannis Adamopoulos         return;
752b3fb8555SGiannis Adamopoulos     }
753b3fb8555SGiannis Adamopoulos     if (LISTBOX_GetItemRect( descr, index, &rect ) != 1) return;
754b3fb8555SGiannis Adamopoulos     if (!(hdc = GetDCEx( descr->self, 0, DCX_CACHE ))) return;
755b3fb8555SGiannis Adamopoulos     if (descr->font) oldFont = SelectObject( hdc, descr->font );
756b3fb8555SGiannis Adamopoulos     hbrush = (HBRUSH)SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
757b3fb8555SGiannis Adamopoulos 				   (WPARAM)hdc, (LPARAM)descr->self );
758b3fb8555SGiannis Adamopoulos     if (hbrush) oldBrush = SelectObject( hdc, hbrush );
759b3fb8555SGiannis Adamopoulos     if (!IsWindowEnabled(descr->self))
760b3fb8555SGiannis Adamopoulos         SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
761b3fb8555SGiannis Adamopoulos     SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
762b3fb8555SGiannis Adamopoulos     LISTBOX_PaintItem( descr, hdc, &rect, index, action, TRUE );
763b3fb8555SGiannis Adamopoulos     if (oldFont) SelectObject( hdc, oldFont );
764b3fb8555SGiannis Adamopoulos     if (oldBrush) SelectObject( hdc, oldBrush );
765b3fb8555SGiannis Adamopoulos     ReleaseDC( descr->self, hdc );
766b3fb8555SGiannis Adamopoulos }
767b3fb8555SGiannis Adamopoulos 
768b3fb8555SGiannis Adamopoulos 
769b3fb8555SGiannis Adamopoulos /***********************************************************************
770b3fb8555SGiannis Adamopoulos  *           LISTBOX_DrawFocusRect
771b3fb8555SGiannis Adamopoulos  */
LISTBOX_DrawFocusRect(LB_DESCR * descr,BOOL on)772b3fb8555SGiannis Adamopoulos static void LISTBOX_DrawFocusRect( LB_DESCR *descr, BOOL on )
773b3fb8555SGiannis Adamopoulos {
774b3fb8555SGiannis Adamopoulos     HDC hdc;
775b3fb8555SGiannis Adamopoulos     RECT rect;
776b3fb8555SGiannis Adamopoulos     HFONT oldFont = 0;
777b3fb8555SGiannis Adamopoulos 
778b3fb8555SGiannis Adamopoulos     /* Do not repaint the item if the item is not visible */
779b3fb8555SGiannis Adamopoulos     if (!IsWindowVisible(descr->self)) return;
780b3fb8555SGiannis Adamopoulos 
781b3fb8555SGiannis Adamopoulos     if (descr->focus_item == -1) return;
782b3fb8555SGiannis Adamopoulos     if (!descr->caret_on || !descr->in_focus) return;
783b3fb8555SGiannis Adamopoulos 
784b3fb8555SGiannis Adamopoulos     if (LISTBOX_GetItemRect( descr, descr->focus_item, &rect ) != 1) return;
785b3fb8555SGiannis Adamopoulos     if (!(hdc = GetDCEx( descr->self, 0, DCX_CACHE ))) return;
786b3fb8555SGiannis Adamopoulos     if (descr->font) oldFont = SelectObject( hdc, descr->font );
787b3fb8555SGiannis Adamopoulos     if (!IsWindowEnabled(descr->self))
788b3fb8555SGiannis Adamopoulos         SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
789b3fb8555SGiannis Adamopoulos     SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
790b3fb8555SGiannis Adamopoulos     LISTBOX_PaintItem( descr, hdc, &rect, descr->focus_item, ODA_FOCUS, !on );
791b3fb8555SGiannis Adamopoulos     if (oldFont) SelectObject( hdc, oldFont );
792b3fb8555SGiannis Adamopoulos     ReleaseDC( descr->self, hdc );
793b3fb8555SGiannis Adamopoulos }
794b3fb8555SGiannis Adamopoulos 
795b3fb8555SGiannis Adamopoulos 
796b3fb8555SGiannis Adamopoulos /***********************************************************************
797b3fb8555SGiannis Adamopoulos  *           LISTBOX_InitStorage
798b3fb8555SGiannis Adamopoulos  */
LISTBOX_InitStorage(LB_DESCR * descr,INT nb_items)799b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_InitStorage( LB_DESCR *descr, INT nb_items )
800b3fb8555SGiannis Adamopoulos {
801*0707475fSJustin Miller     UINT new_size = descr->nb_items + nb_items;
802b3fb8555SGiannis Adamopoulos 
803*0707475fSJustin Miller     if (new_size > descr->items_size && !resize_storage(descr, new_size))
804b3fb8555SGiannis Adamopoulos         return LB_ERRSPACE;
805*0707475fSJustin Miller     return descr->items_size;
806b3fb8555SGiannis Adamopoulos }
807b3fb8555SGiannis Adamopoulos 
808b3fb8555SGiannis Adamopoulos 
809b3fb8555SGiannis Adamopoulos /***********************************************************************
810b3fb8555SGiannis Adamopoulos  *           LISTBOX_SetTabStops
811b3fb8555SGiannis Adamopoulos  */
LISTBOX_SetTabStops(LB_DESCR * descr,INT count,LPINT tabs)812b3fb8555SGiannis Adamopoulos static BOOL LISTBOX_SetTabStops( LB_DESCR *descr, INT count, LPINT tabs )
813b3fb8555SGiannis Adamopoulos {
814b3fb8555SGiannis Adamopoulos     INT i;
815b3fb8555SGiannis Adamopoulos 
816b3fb8555SGiannis Adamopoulos     if (!(descr->style & LBS_USETABSTOPS))
817b3fb8555SGiannis Adamopoulos     {
818b3fb8555SGiannis Adamopoulos         SetLastError(ERROR_LB_WITHOUT_TABSTOPS);
819b3fb8555SGiannis Adamopoulos         return FALSE;
820b3fb8555SGiannis Adamopoulos     }
821b3fb8555SGiannis Adamopoulos 
822b3fb8555SGiannis Adamopoulos     HeapFree( GetProcessHeap(), 0, descr->tabs );
823b3fb8555SGiannis Adamopoulos     if (!(descr->nb_tabs = count))
824b3fb8555SGiannis Adamopoulos     {
825b3fb8555SGiannis Adamopoulos         descr->tabs = NULL;
826b3fb8555SGiannis Adamopoulos         return TRUE;
827b3fb8555SGiannis Adamopoulos     }
828b3fb8555SGiannis Adamopoulos     if (!(descr->tabs = HeapAlloc( GetProcessHeap(), 0,
829b3fb8555SGiannis Adamopoulos                                             descr->nb_tabs * sizeof(INT) )))
830b3fb8555SGiannis Adamopoulos         return FALSE;
831b3fb8555SGiannis Adamopoulos     memcpy( descr->tabs, tabs, descr->nb_tabs * sizeof(INT) );
832b3fb8555SGiannis Adamopoulos 
833b3fb8555SGiannis Adamopoulos     /* convert into "dialog units"*/
834b3fb8555SGiannis Adamopoulos     for (i = 0; i < descr->nb_tabs; i++)
835b3fb8555SGiannis Adamopoulos         descr->tabs[i] = MulDiv(descr->tabs[i], descr->avg_char_width, 4);
836b3fb8555SGiannis Adamopoulos 
837b3fb8555SGiannis Adamopoulos     return TRUE;
838b3fb8555SGiannis Adamopoulos }
839b3fb8555SGiannis Adamopoulos 
840b3fb8555SGiannis Adamopoulos 
841b3fb8555SGiannis Adamopoulos /***********************************************************************
842b3fb8555SGiannis Adamopoulos  *           LISTBOX_GetText
843b3fb8555SGiannis Adamopoulos  */
LISTBOX_GetText(LB_DESCR * descr,INT index,LPWSTR buffer,BOOL unicode)844b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_GetText( LB_DESCR *descr, INT index, LPWSTR buffer, BOOL unicode )
845b3fb8555SGiannis Adamopoulos {
846b3fb8555SGiannis Adamopoulos     DWORD len;
847b3fb8555SGiannis Adamopoulos 
848b3fb8555SGiannis Adamopoulos     if ((index < 0) || (index >= descr->nb_items))
849b3fb8555SGiannis Adamopoulos     {
850b3fb8555SGiannis Adamopoulos         SetLastError(ERROR_INVALID_INDEX);
851b3fb8555SGiannis Adamopoulos         return LB_ERR;
852b3fb8555SGiannis Adamopoulos     }
853b3fb8555SGiannis Adamopoulos 
854b3fb8555SGiannis Adamopoulos     if (HAS_STRINGS(descr))
855b3fb8555SGiannis Adamopoulos     {
856*0707475fSJustin Miller         WCHAR *str = get_item_string(descr, index);
857b3fb8555SGiannis Adamopoulos 
858*0707475fSJustin Miller         if (!buffer)
859*0707475fSJustin Miller             return lstrlenW(str);
860*0707475fSJustin Miller 
861*0707475fSJustin Miller         TRACE("index %d (0x%04x) %s\n", index, index, debugstr_w(str));
862b3fb8555SGiannis Adamopoulos 
863b3fb8555SGiannis Adamopoulos         __TRY  /* hide a Delphi bug that passes a read-only buffer */
864b3fb8555SGiannis Adamopoulos         {
865*0707475fSJustin Miller             lstrcpyW(buffer, str);
866*0707475fSJustin Miller             len = lstrlenW(buffer);
867b3fb8555SGiannis Adamopoulos         }
868b3fb8555SGiannis Adamopoulos         __EXCEPT_PAGE_FAULT
869b3fb8555SGiannis Adamopoulos         {
870b3fb8555SGiannis Adamopoulos             WARN( "got an invalid buffer (Delphi bug?)\n" );
871b3fb8555SGiannis Adamopoulos             SetLastError( ERROR_INVALID_PARAMETER );
872b3fb8555SGiannis Adamopoulos             return LB_ERR;
873b3fb8555SGiannis Adamopoulos         }
874b3fb8555SGiannis Adamopoulos         __ENDTRY
875b3fb8555SGiannis Adamopoulos     } else
876b3fb8555SGiannis Adamopoulos     {
877b3fb8555SGiannis Adamopoulos         if (buffer)
878*0707475fSJustin Miller             *((ULONG_PTR *)buffer) = get_item_data(descr, index);
879*0707475fSJustin Miller         len = sizeof(ULONG_PTR);
880b3fb8555SGiannis Adamopoulos     }
881b3fb8555SGiannis Adamopoulos     return len;
882b3fb8555SGiannis Adamopoulos }
883b3fb8555SGiannis Adamopoulos 
LISTBOX_lstrcmpiW(LCID lcid,LPCWSTR str1,LPCWSTR str2)884b3fb8555SGiannis Adamopoulos static inline INT LISTBOX_lstrcmpiW( LCID lcid, LPCWSTR str1, LPCWSTR str2 )
885b3fb8555SGiannis Adamopoulos {
886b3fb8555SGiannis Adamopoulos     INT ret = CompareStringW( lcid, NORM_IGNORECASE, str1, -1, str2, -1 );
887b3fb8555SGiannis Adamopoulos     if (ret == CSTR_LESS_THAN)
888b3fb8555SGiannis Adamopoulos         return -1;
889b3fb8555SGiannis Adamopoulos     if (ret == CSTR_EQUAL)
890b3fb8555SGiannis Adamopoulos         return 0;
891b3fb8555SGiannis Adamopoulos     if (ret == CSTR_GREATER_THAN)
892b3fb8555SGiannis Adamopoulos         return 1;
893b3fb8555SGiannis Adamopoulos     return -1;
894b3fb8555SGiannis Adamopoulos }
895b3fb8555SGiannis Adamopoulos 
896b3fb8555SGiannis Adamopoulos /***********************************************************************
897b3fb8555SGiannis Adamopoulos  *           LISTBOX_FindStringPos
898b3fb8555SGiannis Adamopoulos  *
899b3fb8555SGiannis Adamopoulos  * Find the nearest string located before a given string in sort order.
900b3fb8555SGiannis Adamopoulos  * If 'exact' is TRUE, return an error if we don't get an exact match.
901b3fb8555SGiannis Adamopoulos  */
LISTBOX_FindStringPos(LB_DESCR * descr,LPCWSTR str,BOOL exact)902b3fb8555SGiannis Adamopoulos static INT LISTBOX_FindStringPos( LB_DESCR *descr, LPCWSTR str, BOOL exact )
903b3fb8555SGiannis Adamopoulos {
904b3fb8555SGiannis Adamopoulos     INT index, min, max, res;
905b3fb8555SGiannis Adamopoulos 
906*0707475fSJustin Miller     if (!descr->nb_items || !(descr->style & LBS_SORT)) return -1;  /* Add it at the end */
907*0707475fSJustin Miller 
908b3fb8555SGiannis Adamopoulos     min = 0;
909*0707475fSJustin Miller     max = descr->nb_items - 1;
910*0707475fSJustin Miller     while (min <= max)
911b3fb8555SGiannis Adamopoulos     {
912b3fb8555SGiannis Adamopoulos         index = (min + max) / 2;
913b3fb8555SGiannis Adamopoulos         if (HAS_STRINGS(descr))
914*0707475fSJustin Miller             res = LISTBOX_lstrcmpiW( descr->locale, get_item_string(descr, index), str );
915b3fb8555SGiannis Adamopoulos         else
916b3fb8555SGiannis Adamopoulos         {
917b3fb8555SGiannis Adamopoulos             COMPAREITEMSTRUCT cis;
918b3fb8555SGiannis Adamopoulos             UINT id = (UINT)GetWindowLongPtrW( descr->self, GWLP_ID );
919b3fb8555SGiannis Adamopoulos 
920b3fb8555SGiannis Adamopoulos             cis.CtlType    = ODT_LISTBOX;
921b3fb8555SGiannis Adamopoulos             cis.CtlID      = id;
922b3fb8555SGiannis Adamopoulos             cis.hwndItem   = descr->self;
923b3fb8555SGiannis Adamopoulos             /* note that some application (MetaStock) expects the second item
924b3fb8555SGiannis Adamopoulos              * to be in the listbox */
925*0707475fSJustin Miller             cis.itemID1    = index;
926*0707475fSJustin Miller             cis.itemData1  = get_item_data(descr, index);
927*0707475fSJustin Miller             cis.itemID2    = -1;
928*0707475fSJustin Miller             cis.itemData2  = (ULONG_PTR)str;
929b3fb8555SGiannis Adamopoulos             cis.dwLocaleId = descr->locale;
930b3fb8555SGiannis Adamopoulos             res = SendMessageW( descr->owner, WM_COMPAREITEM, id, (LPARAM)&cis );
931b3fb8555SGiannis Adamopoulos         }
932b3fb8555SGiannis Adamopoulos         if (!res) return index;
933*0707475fSJustin Miller         if (res > 0) max = index - 1;
934b3fb8555SGiannis Adamopoulos         else min = index + 1;
935b3fb8555SGiannis Adamopoulos     }
936*0707475fSJustin Miller     return exact ? -1 : min;
937b3fb8555SGiannis Adamopoulos }
938b3fb8555SGiannis Adamopoulos 
939b3fb8555SGiannis Adamopoulos 
940b3fb8555SGiannis Adamopoulos /***********************************************************************
941b3fb8555SGiannis Adamopoulos  *           LISTBOX_FindFileStrPos
942b3fb8555SGiannis Adamopoulos  *
943b3fb8555SGiannis Adamopoulos  * Find the nearest string located before a given string in directory
944b3fb8555SGiannis Adamopoulos  * sort order (i.e. first files, then directories, then drives).
945b3fb8555SGiannis Adamopoulos  */
LISTBOX_FindFileStrPos(LB_DESCR * descr,LPCWSTR str)946b3fb8555SGiannis Adamopoulos static INT LISTBOX_FindFileStrPos( LB_DESCR *descr, LPCWSTR str )
947b3fb8555SGiannis Adamopoulos {
948b3fb8555SGiannis Adamopoulos     INT min, max, res;
949b3fb8555SGiannis Adamopoulos 
950b3fb8555SGiannis Adamopoulos     if (!HAS_STRINGS(descr))
951b3fb8555SGiannis Adamopoulos         return LISTBOX_FindStringPos( descr, str, FALSE );
952b3fb8555SGiannis Adamopoulos     min = 0;
953b3fb8555SGiannis Adamopoulos     max = descr->nb_items;
954b3fb8555SGiannis Adamopoulos     while (min != max)
955b3fb8555SGiannis Adamopoulos     {
956b3fb8555SGiannis Adamopoulos         INT index = (min + max) / 2;
957*0707475fSJustin Miller         LPCWSTR p = get_item_string(descr, index);
958b3fb8555SGiannis Adamopoulos         if (*p == '[')  /* drive or directory */
959b3fb8555SGiannis Adamopoulos         {
960b3fb8555SGiannis Adamopoulos             if (*str != '[') res = -1;
961b3fb8555SGiannis Adamopoulos             else if (p[1] == '-')  /* drive */
962b3fb8555SGiannis Adamopoulos             {
963b3fb8555SGiannis Adamopoulos                 if (str[1] == '-') res = str[2] - p[2];
964b3fb8555SGiannis Adamopoulos                 else res = -1;
965b3fb8555SGiannis Adamopoulos             }
966b3fb8555SGiannis Adamopoulos             else  /* directory */
967b3fb8555SGiannis Adamopoulos             {
968b3fb8555SGiannis Adamopoulos                 if (str[1] == '-') res = 1;
969b3fb8555SGiannis Adamopoulos                 else res = LISTBOX_lstrcmpiW( descr->locale, str, p );
970b3fb8555SGiannis Adamopoulos             }
971b3fb8555SGiannis Adamopoulos         }
972b3fb8555SGiannis Adamopoulos         else  /* filename */
973b3fb8555SGiannis Adamopoulos         {
974b3fb8555SGiannis Adamopoulos             if (*str == '[') res = 1;
975b3fb8555SGiannis Adamopoulos             else res = LISTBOX_lstrcmpiW( descr->locale, str, p );
976b3fb8555SGiannis Adamopoulos         }
977b3fb8555SGiannis Adamopoulos         if (!res) return index;
978b3fb8555SGiannis Adamopoulos         if (res < 0) max = index;
979b3fb8555SGiannis Adamopoulos         else min = index + 1;
980b3fb8555SGiannis Adamopoulos     }
981b3fb8555SGiannis Adamopoulos     return max;
982b3fb8555SGiannis Adamopoulos }
983b3fb8555SGiannis Adamopoulos 
984b3fb8555SGiannis Adamopoulos 
985b3fb8555SGiannis Adamopoulos /***********************************************************************
986b3fb8555SGiannis Adamopoulos  *           LISTBOX_FindString
987b3fb8555SGiannis Adamopoulos  *
988b3fb8555SGiannis Adamopoulos  * Find the item beginning with a given string.
989b3fb8555SGiannis Adamopoulos  */
LISTBOX_FindString(LB_DESCR * descr,INT start,LPCWSTR str,BOOL exact)990b3fb8555SGiannis Adamopoulos static INT LISTBOX_FindString( LB_DESCR *descr, INT start, LPCWSTR str, BOOL exact )
991b3fb8555SGiannis Adamopoulos {
992*0707475fSJustin Miller     INT i, index;
993b3fb8555SGiannis Adamopoulos 
994*0707475fSJustin Miller     if (descr->style & LBS_NODATA) return LB_ERR;
995*0707475fSJustin Miller 
996*0707475fSJustin Miller     start++;
997*0707475fSJustin Miller     if (start >= descr->nb_items) start = 0;
998b3fb8555SGiannis Adamopoulos     if (HAS_STRINGS(descr))
999b3fb8555SGiannis Adamopoulos     {
1000b3fb8555SGiannis Adamopoulos         if (!str || ! str[0] ) return LB_ERR;
1001b3fb8555SGiannis Adamopoulos         if (exact)
1002b3fb8555SGiannis Adamopoulos         {
1003*0707475fSJustin Miller             for (i = 0, index = start; i < descr->nb_items; i++, index++)
1004*0707475fSJustin Miller             {
1005*0707475fSJustin Miller                 if (index == descr->nb_items) index = 0;
1006*0707475fSJustin Miller                 if (!LISTBOX_lstrcmpiW(descr->locale, str, get_item_string(descr, index)))
1007*0707475fSJustin Miller                     return index;
1008*0707475fSJustin Miller             }
1009b3fb8555SGiannis Adamopoulos         }
1010b3fb8555SGiannis Adamopoulos         else
1011b3fb8555SGiannis Adamopoulos         {
1012b3fb8555SGiannis Adamopoulos             /* Special case for drives and directories: ignore prefix */
1013*0707475fSJustin Miller             INT len = lstrlenW(str);
1014*0707475fSJustin Miller             WCHAR *item_str;
1015b3fb8555SGiannis Adamopoulos 
1016*0707475fSJustin Miller             for (i = 0, index = start; i < descr->nb_items; i++, index++)
1017b3fb8555SGiannis Adamopoulos             {
1018*0707475fSJustin Miller                 if (index == descr->nb_items) index = 0;
1019*0707475fSJustin Miller                 item_str = get_item_string(descr, index);
1020*0707475fSJustin Miller 
1021*0707475fSJustin Miller                 if (!wcsnicmp(str, item_str, len)) return index;
1022*0707475fSJustin Miller                 if (item_str[0] == '[')
1023b3fb8555SGiannis Adamopoulos                 {
1024*0707475fSJustin Miller                     if (!wcsnicmp(str, item_str + 1, len)) return index;
1025*0707475fSJustin Miller                     if (item_str[1] == '-' && !wcsnicmp(str, item_str + 2, len)) return index;
1026b3fb8555SGiannis Adamopoulos                 }
1027*0707475fSJustin Miller             }
1028b3fb8555SGiannis Adamopoulos         }
1029b3fb8555SGiannis Adamopoulos     }
1030b3fb8555SGiannis Adamopoulos     else
1031b3fb8555SGiannis Adamopoulos     {
1032b3fb8555SGiannis Adamopoulos         if (exact && (descr->style & LBS_SORT))
1033b3fb8555SGiannis Adamopoulos             /* If sorted, use a WM_COMPAREITEM binary search */
1034b3fb8555SGiannis Adamopoulos             return LISTBOX_FindStringPos( descr, str, TRUE );
1035b3fb8555SGiannis Adamopoulos 
1036b3fb8555SGiannis Adamopoulos         /* Otherwise use a linear search */
1037*0707475fSJustin Miller         for (i = 0, index = start; i < descr->nb_items; i++, index++)
1038*0707475fSJustin Miller         {
1039*0707475fSJustin Miller             if (index == descr->nb_items) index = 0;
1040*0707475fSJustin Miller             if (get_item_data(descr, index) == (ULONG_PTR)str) return index;
1041*0707475fSJustin Miller         }
1042b3fb8555SGiannis Adamopoulos     }
1043b3fb8555SGiannis Adamopoulos     return LB_ERR;
1044b3fb8555SGiannis Adamopoulos }
1045b3fb8555SGiannis Adamopoulos 
1046b3fb8555SGiannis Adamopoulos 
1047b3fb8555SGiannis Adamopoulos /***********************************************************************
1048b3fb8555SGiannis Adamopoulos  *           LISTBOX_GetSelCount
1049b3fb8555SGiannis Adamopoulos  */
LISTBOX_GetSelCount(const LB_DESCR * descr)1050b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_GetSelCount( const LB_DESCR *descr )
1051b3fb8555SGiannis Adamopoulos {
1052b3fb8555SGiannis Adamopoulos     INT i, count;
1053b3fb8555SGiannis Adamopoulos 
1054b3fb8555SGiannis Adamopoulos     if (!(descr->style & LBS_MULTIPLESEL) ||
1055b3fb8555SGiannis Adamopoulos         (descr->style & LBS_NOSEL))
1056b3fb8555SGiannis Adamopoulos       return LB_ERR;
1057*0707475fSJustin Miller     for (i = count = 0; i < descr->nb_items; i++)
1058*0707475fSJustin Miller         if (is_item_selected(descr, i)) count++;
1059b3fb8555SGiannis Adamopoulos     return count;
1060b3fb8555SGiannis Adamopoulos }
1061b3fb8555SGiannis Adamopoulos 
1062b3fb8555SGiannis Adamopoulos 
1063b3fb8555SGiannis Adamopoulos /***********************************************************************
1064b3fb8555SGiannis Adamopoulos  *           LISTBOX_GetSelItems
1065b3fb8555SGiannis Adamopoulos  */
LISTBOX_GetSelItems(const LB_DESCR * descr,INT max,LPINT array)1066b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_GetSelItems( const LB_DESCR *descr, INT max, LPINT array )
1067b3fb8555SGiannis Adamopoulos {
1068b3fb8555SGiannis Adamopoulos     INT i, count;
1069b3fb8555SGiannis Adamopoulos 
1070b3fb8555SGiannis Adamopoulos     if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
1071*0707475fSJustin Miller     for (i = count = 0; (i < descr->nb_items) && (count < max); i++)
1072*0707475fSJustin Miller         if (is_item_selected(descr, i)) array[count++] = i;
1073b3fb8555SGiannis Adamopoulos     return count;
1074b3fb8555SGiannis Adamopoulos }
1075b3fb8555SGiannis Adamopoulos 
1076b3fb8555SGiannis Adamopoulos 
1077b3fb8555SGiannis Adamopoulos /***********************************************************************
1078b3fb8555SGiannis Adamopoulos  *           LISTBOX_Paint
1079b3fb8555SGiannis Adamopoulos  */
LISTBOX_Paint(LB_DESCR * descr,HDC hdc)1080b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_Paint( LB_DESCR *descr, HDC hdc )
1081b3fb8555SGiannis Adamopoulos {
1082b3fb8555SGiannis Adamopoulos     INT i, col_pos = descr->page_size - 1;
1083b3fb8555SGiannis Adamopoulos     RECT rect;
1084b3fb8555SGiannis Adamopoulos     RECT focusRect = {-1, -1, -1, -1};
1085b3fb8555SGiannis Adamopoulos     HFONT oldFont = 0;
1086b3fb8555SGiannis Adamopoulos     HBRUSH hbrush, oldBrush = 0;
1087b3fb8555SGiannis Adamopoulos 
1088b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_NOREDRAW) return 0;
1089b3fb8555SGiannis Adamopoulos 
1090b3fb8555SGiannis Adamopoulos     SetRect( &rect, 0, 0, descr->width, descr->height );
1091b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_MULTICOLUMN)
1092b3fb8555SGiannis Adamopoulos         rect.right = rect.left + descr->column_width;
1093b3fb8555SGiannis Adamopoulos     else if (descr->horz_pos)
1094b3fb8555SGiannis Adamopoulos     {
1095b3fb8555SGiannis Adamopoulos         SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
1096b3fb8555SGiannis Adamopoulos         rect.right += descr->horz_pos;
1097b3fb8555SGiannis Adamopoulos     }
1098b3fb8555SGiannis Adamopoulos 
1099b3fb8555SGiannis Adamopoulos     if (descr->font) oldFont = SelectObject( hdc, descr->font );
1100b3fb8555SGiannis Adamopoulos     hbrush = (HBRUSH)SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
1101b3fb8555SGiannis Adamopoulos 				   (WPARAM)hdc, (LPARAM)descr->self );
1102b3fb8555SGiannis Adamopoulos     if (hbrush) oldBrush = SelectObject( hdc, hbrush );
1103b3fb8555SGiannis Adamopoulos     if (!IsWindowEnabled(descr->self)) SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
1104b3fb8555SGiannis Adamopoulos 
1105b3fb8555SGiannis Adamopoulos     if (!descr->nb_items && (descr->focus_item != -1) && descr->caret_on &&
1106b3fb8555SGiannis Adamopoulos         (descr->in_focus))
1107b3fb8555SGiannis Adamopoulos     {
1108b3fb8555SGiannis Adamopoulos         /* Special case for empty listbox: paint focus rect */
1109b3fb8555SGiannis Adamopoulos         rect.bottom = rect.top + descr->item_height;
1110b3fb8555SGiannis Adamopoulos         ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
1111b3fb8555SGiannis Adamopoulos                      &rect, NULL, 0, NULL );
1112b3fb8555SGiannis Adamopoulos         LISTBOX_PaintItem( descr, hdc, &rect, descr->focus_item, ODA_FOCUS, FALSE );
1113b3fb8555SGiannis Adamopoulos         rect.top = rect.bottom;
1114b3fb8555SGiannis Adamopoulos     }
1115b3fb8555SGiannis Adamopoulos 
1116b3fb8555SGiannis Adamopoulos     /* Paint all the item, regarding the selection
1117b3fb8555SGiannis Adamopoulos        Focus state will be painted after  */
1118b3fb8555SGiannis Adamopoulos 
1119b3fb8555SGiannis Adamopoulos     for (i = descr->top_item; i < descr->nb_items; i++)
1120b3fb8555SGiannis Adamopoulos     {
1121b3fb8555SGiannis Adamopoulos         if (!(descr->style & LBS_OWNERDRAWVARIABLE))
1122b3fb8555SGiannis Adamopoulos             rect.bottom = rect.top + descr->item_height;
1123b3fb8555SGiannis Adamopoulos         else
1124*0707475fSJustin Miller             rect.bottom = rect.top + get_item_height(descr, i);
1125b3fb8555SGiannis Adamopoulos 
1126b3fb8555SGiannis Adamopoulos         /* keep the focus rect, to paint the focus item after */
1127b3fb8555SGiannis Adamopoulos         if (i == descr->focus_item)
1128b3fb8555SGiannis Adamopoulos             focusRect = rect;
1129b3fb8555SGiannis Adamopoulos 
1130b3fb8555SGiannis Adamopoulos         LISTBOX_PaintItem( descr, hdc, &rect, i, ODA_DRAWENTIRE, TRUE );
1131b3fb8555SGiannis Adamopoulos         rect.top = rect.bottom;
1132b3fb8555SGiannis Adamopoulos 
1133b3fb8555SGiannis Adamopoulos         if ((descr->style & LBS_MULTICOLUMN) && !col_pos)
1134b3fb8555SGiannis Adamopoulos         {
1135b3fb8555SGiannis Adamopoulos             if (!IS_OWNERDRAW(descr))
1136b3fb8555SGiannis Adamopoulos             {
1137b3fb8555SGiannis Adamopoulos                 /* Clear the bottom of the column */
1138b3fb8555SGiannis Adamopoulos                 if (rect.top < descr->height)
1139b3fb8555SGiannis Adamopoulos                 {
1140b3fb8555SGiannis Adamopoulos                     rect.bottom = descr->height;
1141b3fb8555SGiannis Adamopoulos                     ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
1142b3fb8555SGiannis Adamopoulos                                    &rect, NULL, 0, NULL );
1143b3fb8555SGiannis Adamopoulos                 }
1144b3fb8555SGiannis Adamopoulos             }
1145b3fb8555SGiannis Adamopoulos 
1146b3fb8555SGiannis Adamopoulos             /* Go to the next column */
1147b3fb8555SGiannis Adamopoulos             rect.left += descr->column_width;
1148b3fb8555SGiannis Adamopoulos             rect.right += descr->column_width;
1149b3fb8555SGiannis Adamopoulos             rect.top = 0;
1150b3fb8555SGiannis Adamopoulos             col_pos = descr->page_size - 1;
1151*0707475fSJustin Miller             if (rect.left >= descr->width) break;
1152b3fb8555SGiannis Adamopoulos         }
1153b3fb8555SGiannis Adamopoulos         else
1154b3fb8555SGiannis Adamopoulos         {
1155b3fb8555SGiannis Adamopoulos             col_pos--;
1156b3fb8555SGiannis Adamopoulos             if (rect.top >= descr->height) break;
1157b3fb8555SGiannis Adamopoulos         }
1158b3fb8555SGiannis Adamopoulos     }
1159b3fb8555SGiannis Adamopoulos 
1160b3fb8555SGiannis Adamopoulos     /* Paint the focus item now */
1161b3fb8555SGiannis Adamopoulos     if (focusRect.top != focusRect.bottom &&
1162b3fb8555SGiannis Adamopoulos         descr->caret_on && descr->in_focus)
1163b3fb8555SGiannis Adamopoulos         LISTBOX_PaintItem( descr, hdc, &focusRect, descr->focus_item, ODA_FOCUS, FALSE );
1164b3fb8555SGiannis Adamopoulos 
1165b3fb8555SGiannis Adamopoulos     if (!IS_OWNERDRAW(descr))
1166b3fb8555SGiannis Adamopoulos     {
1167b3fb8555SGiannis Adamopoulos         /* Clear the remainder of the client area */
1168b3fb8555SGiannis Adamopoulos         if (rect.top < descr->height)
1169b3fb8555SGiannis Adamopoulos         {
1170b3fb8555SGiannis Adamopoulos             rect.bottom = descr->height;
1171b3fb8555SGiannis Adamopoulos             ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
1172b3fb8555SGiannis Adamopoulos                            &rect, NULL, 0, NULL );
1173b3fb8555SGiannis Adamopoulos         }
1174b3fb8555SGiannis Adamopoulos         if (rect.right < descr->width)
1175b3fb8555SGiannis Adamopoulos         {
1176b3fb8555SGiannis Adamopoulos             rect.left   = rect.right;
1177b3fb8555SGiannis Adamopoulos             rect.right  = descr->width;
1178b3fb8555SGiannis Adamopoulos             rect.top    = 0;
1179b3fb8555SGiannis Adamopoulos             rect.bottom = descr->height;
1180b3fb8555SGiannis Adamopoulos             ExtTextOutW( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
1181b3fb8555SGiannis Adamopoulos                            &rect, NULL, 0, NULL );
1182b3fb8555SGiannis Adamopoulos         }
1183b3fb8555SGiannis Adamopoulos     }
1184b3fb8555SGiannis Adamopoulos     if (oldFont) SelectObject( hdc, oldFont );
1185b3fb8555SGiannis Adamopoulos     if (oldBrush) SelectObject( hdc, oldBrush );
1186b3fb8555SGiannis Adamopoulos     return 0;
1187b3fb8555SGiannis Adamopoulos }
1188b3fb8555SGiannis Adamopoulos 
LISTBOX_NCPaint(LB_DESCR * descr,HRGN region)1189b3fb8555SGiannis Adamopoulos static void LISTBOX_NCPaint( LB_DESCR *descr, HRGN region )
1190b3fb8555SGiannis Adamopoulos {
1191b3fb8555SGiannis Adamopoulos     DWORD exstyle = GetWindowLongW( descr->self, GWL_EXSTYLE);
1192b3fb8555SGiannis Adamopoulos     HTHEME theme = GetWindowTheme( descr->self );
1193b3fb8555SGiannis Adamopoulos     HRGN cliprgn = region;
1194b3fb8555SGiannis Adamopoulos     int cxEdge, cyEdge;
1195b3fb8555SGiannis Adamopoulos     HDC hdc;
1196b3fb8555SGiannis Adamopoulos     RECT r;
1197b3fb8555SGiannis Adamopoulos 
1198b3fb8555SGiannis Adamopoulos     if (!theme || !(exstyle & WS_EX_CLIENTEDGE))
1199b3fb8555SGiannis Adamopoulos         return;
1200b3fb8555SGiannis Adamopoulos 
1201*0707475fSJustin Miller     cxEdge = GetSystemMetrics(SM_CXEDGE);
1202b3fb8555SGiannis Adamopoulos     cyEdge = GetSystemMetrics(SM_CYEDGE);
1203b3fb8555SGiannis Adamopoulos 
1204b3fb8555SGiannis Adamopoulos     GetWindowRect(descr->self, &r);
1205b3fb8555SGiannis Adamopoulos 
1206b3fb8555SGiannis Adamopoulos     /* New clipping region passed to default proc to exclude border */
1207b3fb8555SGiannis Adamopoulos     cliprgn = CreateRectRgn(r.left + cxEdge, r.top + cyEdge,
1208b3fb8555SGiannis Adamopoulos         r.right - cxEdge, r.bottom - cyEdge);
1209b3fb8555SGiannis Adamopoulos     if (region != (HRGN)1)
1210b3fb8555SGiannis Adamopoulos         CombineRgn(cliprgn, cliprgn, region, RGN_AND);
1211b3fb8555SGiannis Adamopoulos     OffsetRect(&r, -r.left, -r.top);
1212b3fb8555SGiannis Adamopoulos 
1213b3fb8555SGiannis Adamopoulos #ifdef __REACTOS__ /* r73789 */
1214b3fb8555SGiannis Adamopoulos     hdc = GetWindowDC(descr->self);
1215b3fb8555SGiannis Adamopoulos     /* Exclude client part */
1216b3fb8555SGiannis Adamopoulos     ExcludeClipRect(hdc,
1217b3fb8555SGiannis Adamopoulos                     r.left + cxEdge,
1218b3fb8555SGiannis Adamopoulos                     r.top + cyEdge,
1219b3fb8555SGiannis Adamopoulos                     r.right - cxEdge,
1220b3fb8555SGiannis Adamopoulos                     r.bottom -cyEdge);
1221b3fb8555SGiannis Adamopoulos #else
1222b3fb8555SGiannis Adamopoulos     hdc = GetDCEx(descr->self, region, DCX_WINDOW|DCX_INTERSECTRGN);
1223b3fb8555SGiannis Adamopoulos     OffsetRect(&r, -r.left, -r.top);
1224b3fb8555SGiannis Adamopoulos #endif
1225b3fb8555SGiannis Adamopoulos 
1226b3fb8555SGiannis Adamopoulos     if (IsThemeBackgroundPartiallyTransparent (theme, 0, 0))
1227b3fb8555SGiannis Adamopoulos         DrawThemeParentBackground(descr->self, hdc, &r);
1228b3fb8555SGiannis Adamopoulos     DrawThemeBackground (theme, hdc, 0, 0, &r, 0);
1229b3fb8555SGiannis Adamopoulos     ReleaseDC(descr->self, hdc);
1230b3fb8555SGiannis Adamopoulos }
1231b3fb8555SGiannis Adamopoulos 
1232b3fb8555SGiannis Adamopoulos /***********************************************************************
1233b3fb8555SGiannis Adamopoulos  *           LISTBOX_InvalidateItems
1234b3fb8555SGiannis Adamopoulos  *
1235b3fb8555SGiannis Adamopoulos  * Invalidate all items from a given item. If the specified item is not
1236b3fb8555SGiannis Adamopoulos  * visible, nothing happens.
1237b3fb8555SGiannis Adamopoulos  */
LISTBOX_InvalidateItems(LB_DESCR * descr,INT index)1238b3fb8555SGiannis Adamopoulos static void LISTBOX_InvalidateItems( LB_DESCR *descr, INT index )
1239b3fb8555SGiannis Adamopoulos {
1240b3fb8555SGiannis Adamopoulos     RECT rect;
1241b3fb8555SGiannis Adamopoulos 
1242b3fb8555SGiannis Adamopoulos     if (LISTBOX_GetItemRect( descr, index, &rect ) == 1)
1243b3fb8555SGiannis Adamopoulos     {
1244b3fb8555SGiannis Adamopoulos         if (descr->style & LBS_NOREDRAW)
1245b3fb8555SGiannis Adamopoulos         {
1246b3fb8555SGiannis Adamopoulos             descr->style |= LBS_DISPLAYCHANGED;
1247b3fb8555SGiannis Adamopoulos             return;
1248b3fb8555SGiannis Adamopoulos         }
1249b3fb8555SGiannis Adamopoulos         rect.bottom = descr->height;
1250b3fb8555SGiannis Adamopoulos         InvalidateRect( descr->self, &rect, TRUE );
1251b3fb8555SGiannis Adamopoulos         if (descr->style & LBS_MULTICOLUMN)
1252b3fb8555SGiannis Adamopoulos         {
1253b3fb8555SGiannis Adamopoulos             /* Repaint the other columns */
1254b3fb8555SGiannis Adamopoulos             rect.left  = rect.right;
1255b3fb8555SGiannis Adamopoulos             rect.right = descr->width;
1256b3fb8555SGiannis Adamopoulos             rect.top   = 0;
1257b3fb8555SGiannis Adamopoulos             InvalidateRect( descr->self, &rect, TRUE );
1258b3fb8555SGiannis Adamopoulos         }
1259b3fb8555SGiannis Adamopoulos     }
1260b3fb8555SGiannis Adamopoulos }
1261b3fb8555SGiannis Adamopoulos 
LISTBOX_InvalidateItemRect(LB_DESCR * descr,INT index)1262b3fb8555SGiannis Adamopoulos static void LISTBOX_InvalidateItemRect( LB_DESCR *descr, INT index )
1263b3fb8555SGiannis Adamopoulos {
1264b3fb8555SGiannis Adamopoulos     RECT rect;
1265b3fb8555SGiannis Adamopoulos 
1266b3fb8555SGiannis Adamopoulos     if (LISTBOX_GetItemRect( descr, index, &rect ) == 1)
1267b3fb8555SGiannis Adamopoulos         InvalidateRect( descr->self, &rect, TRUE );
1268b3fb8555SGiannis Adamopoulos }
1269b3fb8555SGiannis Adamopoulos 
1270b3fb8555SGiannis Adamopoulos /***********************************************************************
1271b3fb8555SGiannis Adamopoulos  *           LISTBOX_GetItemHeight
1272b3fb8555SGiannis Adamopoulos  */
LISTBOX_GetItemHeight(const LB_DESCR * descr,INT index)1273b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_GetItemHeight( const LB_DESCR *descr, INT index )
1274b3fb8555SGiannis Adamopoulos {
1275b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_OWNERDRAWVARIABLE && descr->nb_items > 0)
1276b3fb8555SGiannis Adamopoulos     {
1277b3fb8555SGiannis Adamopoulos         if ((index < 0) || (index >= descr->nb_items))
1278b3fb8555SGiannis Adamopoulos         {
1279b3fb8555SGiannis Adamopoulos             SetLastError(ERROR_INVALID_INDEX);
1280b3fb8555SGiannis Adamopoulos             return LB_ERR;
1281b3fb8555SGiannis Adamopoulos         }
1282*0707475fSJustin Miller         return get_item_height(descr, index);
1283b3fb8555SGiannis Adamopoulos     }
1284b3fb8555SGiannis Adamopoulos     else return descr->item_height;
1285b3fb8555SGiannis Adamopoulos }
1286b3fb8555SGiannis Adamopoulos 
1287b3fb8555SGiannis Adamopoulos 
1288b3fb8555SGiannis Adamopoulos /***********************************************************************
1289b3fb8555SGiannis Adamopoulos  *           LISTBOX_SetItemHeight
1290b3fb8555SGiannis Adamopoulos  */
LISTBOX_SetItemHeight(LB_DESCR * descr,INT index,INT height,BOOL repaint)1291b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_SetItemHeight( LB_DESCR *descr, INT index, INT height, BOOL repaint )
1292b3fb8555SGiannis Adamopoulos {
1293*0707475fSJustin Miller     if (height > MAXWORD)
1294b3fb8555SGiannis Adamopoulos         return -1;
1295b3fb8555SGiannis Adamopoulos 
1296b3fb8555SGiannis Adamopoulos     if (!height) height = 1;
1297b3fb8555SGiannis Adamopoulos 
1298b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_OWNERDRAWVARIABLE)
1299b3fb8555SGiannis Adamopoulos     {
1300b3fb8555SGiannis Adamopoulos         if ((index < 0) || (index >= descr->nb_items))
1301b3fb8555SGiannis Adamopoulos         {
1302b3fb8555SGiannis Adamopoulos             SetLastError(ERROR_INVALID_INDEX);
1303b3fb8555SGiannis Adamopoulos             return LB_ERR;
1304b3fb8555SGiannis Adamopoulos         }
1305b3fb8555SGiannis Adamopoulos         TRACE("[%p]: item %d height = %d\n", descr->self, index, height );
1306*0707475fSJustin Miller         set_item_height(descr, index, height);
1307b3fb8555SGiannis Adamopoulos         LISTBOX_UpdateScroll( descr );
1308b3fb8555SGiannis Adamopoulos 	if (repaint)
1309b3fb8555SGiannis Adamopoulos 	    LISTBOX_InvalidateItems( descr, index );
1310b3fb8555SGiannis Adamopoulos     }
1311b3fb8555SGiannis Adamopoulos     else if (height != descr->item_height)
1312b3fb8555SGiannis Adamopoulos     {
1313b3fb8555SGiannis Adamopoulos         TRACE("[%p]: new height = %d\n", descr->self, height );
1314b3fb8555SGiannis Adamopoulos         descr->item_height = height;
1315b3fb8555SGiannis Adamopoulos         LISTBOX_UpdatePage( descr );
1316b3fb8555SGiannis Adamopoulos         LISTBOX_UpdateScroll( descr );
1317b3fb8555SGiannis Adamopoulos 	if (repaint)
1318b3fb8555SGiannis Adamopoulos 	    InvalidateRect( descr->self, 0, TRUE );
1319b3fb8555SGiannis Adamopoulos     }
1320b3fb8555SGiannis Adamopoulos     return LB_OKAY;
1321b3fb8555SGiannis Adamopoulos }
1322b3fb8555SGiannis Adamopoulos 
1323b3fb8555SGiannis Adamopoulos 
1324b3fb8555SGiannis Adamopoulos /***********************************************************************
1325b3fb8555SGiannis Adamopoulos  *           LISTBOX_SetHorizontalPos
1326b3fb8555SGiannis Adamopoulos  */
LISTBOX_SetHorizontalPos(LB_DESCR * descr,INT pos)1327b3fb8555SGiannis Adamopoulos static void LISTBOX_SetHorizontalPos( LB_DESCR *descr, INT pos )
1328b3fb8555SGiannis Adamopoulos {
1329b3fb8555SGiannis Adamopoulos     INT diff;
1330b3fb8555SGiannis Adamopoulos 
1331b3fb8555SGiannis Adamopoulos     if (pos > descr->horz_extent - descr->width)
1332b3fb8555SGiannis Adamopoulos         pos = descr->horz_extent - descr->width;
1333b3fb8555SGiannis Adamopoulos     if (pos < 0) pos = 0;
1334b3fb8555SGiannis Adamopoulos     if (!(diff = descr->horz_pos - pos)) return;
1335b3fb8555SGiannis Adamopoulos     TRACE("[%p]: new horz pos = %d\n", descr->self, pos );
1336b3fb8555SGiannis Adamopoulos     descr->horz_pos = pos;
1337b3fb8555SGiannis Adamopoulos     LISTBOX_UpdateScroll( descr );
1338b3fb8555SGiannis Adamopoulos     if (abs(diff) < descr->width)
1339b3fb8555SGiannis Adamopoulos     {
1340b3fb8555SGiannis Adamopoulos         RECT rect;
1341b3fb8555SGiannis Adamopoulos         /* Invalidate the focused item so it will be repainted correctly */
1342b3fb8555SGiannis Adamopoulos         if (LISTBOX_GetItemRect( descr, descr->focus_item, &rect ) == 1)
1343b3fb8555SGiannis Adamopoulos             InvalidateRect( descr->self, &rect, TRUE );
1344b3fb8555SGiannis Adamopoulos         ScrollWindowEx( descr->self, diff, 0, NULL, NULL, 0, NULL,
1345b3fb8555SGiannis Adamopoulos                           SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
1346b3fb8555SGiannis Adamopoulos     }
1347b3fb8555SGiannis Adamopoulos     else
1348b3fb8555SGiannis Adamopoulos         InvalidateRect( descr->self, NULL, TRUE );
1349b3fb8555SGiannis Adamopoulos }
1350b3fb8555SGiannis Adamopoulos 
1351b3fb8555SGiannis Adamopoulos 
1352b3fb8555SGiannis Adamopoulos /***********************************************************************
1353b3fb8555SGiannis Adamopoulos  *           LISTBOX_SetHorizontalExtent
1354b3fb8555SGiannis Adamopoulos  */
LISTBOX_SetHorizontalExtent(LB_DESCR * descr,INT extent)1355b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_SetHorizontalExtent( LB_DESCR *descr, INT extent )
1356b3fb8555SGiannis Adamopoulos {
1357b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_MULTICOLUMN)
1358b3fb8555SGiannis Adamopoulos         return LB_OKAY;
1359b3fb8555SGiannis Adamopoulos     if (extent == descr->horz_extent) return LB_OKAY;
1360b3fb8555SGiannis Adamopoulos     TRACE("[%p]: new horz extent = %d\n", descr->self, extent );
1361b3fb8555SGiannis Adamopoulos     descr->horz_extent = extent;
1362b3fb8555SGiannis Adamopoulos     if (descr->style & WS_HSCROLL) {
1363b3fb8555SGiannis Adamopoulos         SCROLLINFO info;
1364b3fb8555SGiannis Adamopoulos         info.cbSize = sizeof(info);
1365b3fb8555SGiannis Adamopoulos         info.nMin  = 0;
1366b3fb8555SGiannis Adamopoulos         info.nMax = descr->horz_extent ? descr->horz_extent - 1 : 0;
1367b3fb8555SGiannis Adamopoulos         info.fMask = SIF_RANGE;
1368b3fb8555SGiannis Adamopoulos         if (descr->style & LBS_DISABLENOSCROLL)
1369b3fb8555SGiannis Adamopoulos             info.fMask |= SIF_DISABLENOSCROLL;
1370b3fb8555SGiannis Adamopoulos         SetScrollInfo( descr->self, SB_HORZ, &info, TRUE );
1371b3fb8555SGiannis Adamopoulos     }
1372b3fb8555SGiannis Adamopoulos     if (descr->horz_pos > extent - descr->width)
1373b3fb8555SGiannis Adamopoulos         LISTBOX_SetHorizontalPos( descr, extent - descr->width );
1374b3fb8555SGiannis Adamopoulos     return LB_OKAY;
1375b3fb8555SGiannis Adamopoulos }
1376b3fb8555SGiannis Adamopoulos 
1377b3fb8555SGiannis Adamopoulos 
1378b3fb8555SGiannis Adamopoulos /***********************************************************************
1379b3fb8555SGiannis Adamopoulos  *           LISTBOX_SetColumnWidth
1380b3fb8555SGiannis Adamopoulos  */
LISTBOX_SetColumnWidth(LB_DESCR * descr,INT column_width)1381*0707475fSJustin Miller static LRESULT LISTBOX_SetColumnWidth( LB_DESCR *descr, INT column_width)
1382b3fb8555SGiannis Adamopoulos {
1383*0707475fSJustin Miller     RECT rect;
1384*0707475fSJustin Miller 
1385*0707475fSJustin Miller     TRACE("[%p]: new column width = %d\n", descr->self, column_width);
1386*0707475fSJustin Miller 
1387*0707475fSJustin Miller     GetClientRect(descr->self, &rect);
1388*0707475fSJustin Miller     descr->width = rect.right - rect.left;
1389*0707475fSJustin Miller     descr->height = rect.bottom - rect.top;
1390*0707475fSJustin Miller     descr->column_width = column_width;
1391*0707475fSJustin Miller 
1392b3fb8555SGiannis Adamopoulos     LISTBOX_UpdatePage(descr);
1393*0707475fSJustin Miller     LISTBOX_UpdateScroll(descr);
1394b3fb8555SGiannis Adamopoulos     return LB_OKAY;
1395b3fb8555SGiannis Adamopoulos }
1396b3fb8555SGiannis Adamopoulos 
1397b3fb8555SGiannis Adamopoulos 
1398b3fb8555SGiannis Adamopoulos /***********************************************************************
1399b3fb8555SGiannis Adamopoulos  *           LISTBOX_SetFont
1400b3fb8555SGiannis Adamopoulos  *
1401b3fb8555SGiannis Adamopoulos  * Returns the item height.
1402b3fb8555SGiannis Adamopoulos  */
LISTBOX_SetFont(LB_DESCR * descr,HFONT font)1403b3fb8555SGiannis Adamopoulos static INT LISTBOX_SetFont( LB_DESCR *descr, HFONT font )
1404b3fb8555SGiannis Adamopoulos {
1405b3fb8555SGiannis Adamopoulos     HDC hdc;
1406b3fb8555SGiannis Adamopoulos     HFONT oldFont = 0;
1407b3fb8555SGiannis Adamopoulos     const char *alphabet = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ";
1408b3fb8555SGiannis Adamopoulos     SIZE sz;
1409b3fb8555SGiannis Adamopoulos 
1410b3fb8555SGiannis Adamopoulos     descr->font = font;
1411b3fb8555SGiannis Adamopoulos 
1412b3fb8555SGiannis Adamopoulos     if (!(hdc = GetDCEx( descr->self, 0, DCX_CACHE )))
1413b3fb8555SGiannis Adamopoulos     {
1414b3fb8555SGiannis Adamopoulos         ERR("unable to get DC.\n" );
1415b3fb8555SGiannis Adamopoulos         return 16;
1416b3fb8555SGiannis Adamopoulos     }
1417b3fb8555SGiannis Adamopoulos     if (font) oldFont = SelectObject( hdc, font );
1418b3fb8555SGiannis Adamopoulos     GetTextExtentPointA( hdc, alphabet, 52, &sz);
1419b3fb8555SGiannis Adamopoulos     if (oldFont) SelectObject( hdc, oldFont );
1420b3fb8555SGiannis Adamopoulos     ReleaseDC( descr->self, hdc );
1421b3fb8555SGiannis Adamopoulos 
1422b3fb8555SGiannis Adamopoulos     descr->avg_char_width = (sz.cx / 26 + 1) / 2;
1423b3fb8555SGiannis Adamopoulos     if (!IS_OWNERDRAW(descr))
1424b3fb8555SGiannis Adamopoulos         LISTBOX_SetItemHeight( descr, 0, sz.cy, FALSE );
1425b3fb8555SGiannis Adamopoulos     return sz.cy;
1426b3fb8555SGiannis Adamopoulos }
1427b3fb8555SGiannis Adamopoulos 
1428b3fb8555SGiannis Adamopoulos 
1429b3fb8555SGiannis Adamopoulos /***********************************************************************
1430b3fb8555SGiannis Adamopoulos  *           LISTBOX_MakeItemVisible
1431b3fb8555SGiannis Adamopoulos  *
1432b3fb8555SGiannis Adamopoulos  * Make sure that a given item is partially or fully visible.
1433b3fb8555SGiannis Adamopoulos  */
LISTBOX_MakeItemVisible(LB_DESCR * descr,INT index,BOOL fully)1434b3fb8555SGiannis Adamopoulos static void LISTBOX_MakeItemVisible( LB_DESCR *descr, INT index, BOOL fully )
1435b3fb8555SGiannis Adamopoulos {
1436b3fb8555SGiannis Adamopoulos     INT top;
1437b3fb8555SGiannis Adamopoulos 
1438b3fb8555SGiannis Adamopoulos     TRACE("current top item %d, index %d, fully %d\n", descr->top_item, index, fully);
1439b3fb8555SGiannis Adamopoulos 
1440b3fb8555SGiannis Adamopoulos     if (index <= descr->top_item) top = index;
1441b3fb8555SGiannis Adamopoulos     else if (descr->style & LBS_MULTICOLUMN)
1442b3fb8555SGiannis Adamopoulos     {
1443b3fb8555SGiannis Adamopoulos         INT cols = descr->width;
1444b3fb8555SGiannis Adamopoulos         if (!fully) cols += descr->column_width - 1;
1445b3fb8555SGiannis Adamopoulos         if (cols >= descr->column_width) cols /= descr->column_width;
1446b3fb8555SGiannis Adamopoulos         else cols = 1;
1447b3fb8555SGiannis Adamopoulos         if (index < descr->top_item + (descr->page_size * cols)) return;
1448b3fb8555SGiannis Adamopoulos         top = index - descr->page_size * (cols - 1);
1449b3fb8555SGiannis Adamopoulos     }
1450b3fb8555SGiannis Adamopoulos     else if (descr->style & LBS_OWNERDRAWVARIABLE)
1451b3fb8555SGiannis Adamopoulos     {
1452*0707475fSJustin Miller         INT height = fully ? get_item_height(descr, index) : 1;
1453b3fb8555SGiannis Adamopoulos         for (top = index; top > descr->top_item; top--)
1454*0707475fSJustin Miller             if ((height += get_item_height(descr, top - 1)) > descr->height) break;
1455b3fb8555SGiannis Adamopoulos     }
1456b3fb8555SGiannis Adamopoulos     else
1457b3fb8555SGiannis Adamopoulos     {
1458b3fb8555SGiannis Adamopoulos         if (index < descr->top_item + descr->page_size) return;
1459b3fb8555SGiannis Adamopoulos         if (!fully && (index == descr->top_item + descr->page_size) &&
1460b3fb8555SGiannis Adamopoulos             (descr->height > (descr->page_size * descr->item_height))) return;
1461b3fb8555SGiannis Adamopoulos         top = index - descr->page_size + 1;
1462b3fb8555SGiannis Adamopoulos     }
1463b3fb8555SGiannis Adamopoulos     LISTBOX_SetTopItem( descr, top, TRUE );
1464b3fb8555SGiannis Adamopoulos }
1465b3fb8555SGiannis Adamopoulos 
1466b3fb8555SGiannis Adamopoulos /***********************************************************************
1467b3fb8555SGiannis Adamopoulos  *           LISTBOX_SetCaretIndex
1468b3fb8555SGiannis Adamopoulos  *
1469b3fb8555SGiannis Adamopoulos  * NOTES
1470b3fb8555SGiannis Adamopoulos  *   index must be between 0 and descr->nb_items-1, or LB_ERR is returned.
1471b3fb8555SGiannis Adamopoulos  *
1472b3fb8555SGiannis Adamopoulos  */
LISTBOX_SetCaretIndex(LB_DESCR * descr,INT index,BOOL fully_visible)1473b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_SetCaretIndex( LB_DESCR *descr, INT index, BOOL fully_visible )
1474b3fb8555SGiannis Adamopoulos {
1475*0707475fSJustin Miller     BOOL focus_changed = descr->focus_item != index;
1476b3fb8555SGiannis Adamopoulos 
1477*0707475fSJustin Miller     TRACE("old focus %d, index %d\n", descr->focus_item, index);
1478b3fb8555SGiannis Adamopoulos 
1479b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_NOSEL) return LB_ERR;
1480b3fb8555SGiannis Adamopoulos     if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
1481b3fb8555SGiannis Adamopoulos 
1482*0707475fSJustin Miller     if (focus_changed)
1483*0707475fSJustin Miller     {
1484b3fb8555SGiannis Adamopoulos         LISTBOX_DrawFocusRect( descr, FALSE );
1485b3fb8555SGiannis Adamopoulos         descr->focus_item = index;
1486*0707475fSJustin Miller     }
1487b3fb8555SGiannis Adamopoulos 
1488b3fb8555SGiannis Adamopoulos     LISTBOX_MakeItemVisible( descr, index, fully_visible );
1489*0707475fSJustin Miller 
1490*0707475fSJustin Miller     if (focus_changed)
1491b3fb8555SGiannis Adamopoulos         LISTBOX_DrawFocusRect( descr, TRUE );
1492b3fb8555SGiannis Adamopoulos 
1493b3fb8555SGiannis Adamopoulos     return LB_OKAY;
1494b3fb8555SGiannis Adamopoulos }
1495b3fb8555SGiannis Adamopoulos 
1496b3fb8555SGiannis Adamopoulos 
1497b3fb8555SGiannis Adamopoulos /***********************************************************************
1498b3fb8555SGiannis Adamopoulos  *           LISTBOX_SelectItemRange
1499b3fb8555SGiannis Adamopoulos  *
1500b3fb8555SGiannis Adamopoulos  * Select a range of items. Should only be used on a MULTIPLESEL listbox.
1501b3fb8555SGiannis Adamopoulos  */
LISTBOX_SelectItemRange(LB_DESCR * descr,INT first,INT last,BOOL on)1502b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_SelectItemRange( LB_DESCR *descr, INT first,
1503b3fb8555SGiannis Adamopoulos                                         INT last, BOOL on )
1504b3fb8555SGiannis Adamopoulos {
1505b3fb8555SGiannis Adamopoulos     INT i;
1506b3fb8555SGiannis Adamopoulos 
1507b3fb8555SGiannis Adamopoulos     /* A few sanity checks */
1508b3fb8555SGiannis Adamopoulos 
1509b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_NOSEL) return LB_ERR;
1510b3fb8555SGiannis Adamopoulos     if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
1511b3fb8555SGiannis Adamopoulos 
1512b3fb8555SGiannis Adamopoulos     if (!descr->nb_items) return LB_OKAY;
1513b3fb8555SGiannis Adamopoulos 
1514b3fb8555SGiannis Adamopoulos     if (last == -1 || last >= descr->nb_items) last = descr->nb_items - 1;
1515b3fb8555SGiannis Adamopoulos     if (first < 0) first = 0;
1516b3fb8555SGiannis Adamopoulos     if (last < first) return LB_OKAY;
1517b3fb8555SGiannis Adamopoulos 
1518b3fb8555SGiannis Adamopoulos     if (on)  /* Turn selection on */
1519b3fb8555SGiannis Adamopoulos     {
1520b3fb8555SGiannis Adamopoulos         for (i = first; i <= last; i++)
1521b3fb8555SGiannis Adamopoulos         {
1522*0707475fSJustin Miller             if (is_item_selected(descr, i)) continue;
1523*0707475fSJustin Miller             set_item_selected_state(descr, i, TRUE);
1524b3fb8555SGiannis Adamopoulos             LISTBOX_InvalidateItemRect(descr, i);
1525b3fb8555SGiannis Adamopoulos         }
1526b3fb8555SGiannis Adamopoulos     }
1527b3fb8555SGiannis Adamopoulos     else  /* Turn selection off */
1528b3fb8555SGiannis Adamopoulos     {
1529b3fb8555SGiannis Adamopoulos         for (i = first; i <= last; i++)
1530b3fb8555SGiannis Adamopoulos         {
1531*0707475fSJustin Miller             if (!is_item_selected(descr, i)) continue;
1532*0707475fSJustin Miller             set_item_selected_state(descr, i, FALSE);
1533b3fb8555SGiannis Adamopoulos             LISTBOX_InvalidateItemRect(descr, i);
1534b3fb8555SGiannis Adamopoulos         }
1535b3fb8555SGiannis Adamopoulos     }
1536b3fb8555SGiannis Adamopoulos     return LB_OKAY;
1537b3fb8555SGiannis Adamopoulos }
1538b3fb8555SGiannis Adamopoulos 
1539b3fb8555SGiannis Adamopoulos /***********************************************************************
1540b3fb8555SGiannis Adamopoulos  *           LISTBOX_SetSelection
1541b3fb8555SGiannis Adamopoulos  */
LISTBOX_SetSelection(LB_DESCR * descr,INT index,BOOL on,BOOL send_notify)1542b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_SetSelection( LB_DESCR *descr, INT index,
1543b3fb8555SGiannis Adamopoulos                                      BOOL on, BOOL send_notify )
1544b3fb8555SGiannis Adamopoulos {
1545b3fb8555SGiannis Adamopoulos     TRACE( "cur_sel=%d index=%d notify=%s\n",
1546b3fb8555SGiannis Adamopoulos            descr->selected_item, index, send_notify ? "YES" : "NO" );
1547b3fb8555SGiannis Adamopoulos 
1548b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_NOSEL)
1549b3fb8555SGiannis Adamopoulos     {
1550b3fb8555SGiannis Adamopoulos         descr->selected_item = index;
1551b3fb8555SGiannis Adamopoulos         return LB_ERR;
1552b3fb8555SGiannis Adamopoulos     }
1553b3fb8555SGiannis Adamopoulos     if ((index < -1) || (index >= descr->nb_items)) return LB_ERR;
1554b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_MULTIPLESEL)
1555b3fb8555SGiannis Adamopoulos     {
1556b3fb8555SGiannis Adamopoulos         if (index == -1)  /* Select all items */
1557b3fb8555SGiannis Adamopoulos             return LISTBOX_SelectItemRange( descr, 0, descr->nb_items, on );
1558b3fb8555SGiannis Adamopoulos         else  /* Only one item */
1559b3fb8555SGiannis Adamopoulos             return LISTBOX_SelectItemRange( descr, index, index, on );
1560b3fb8555SGiannis Adamopoulos     }
1561b3fb8555SGiannis Adamopoulos     else
1562b3fb8555SGiannis Adamopoulos     {
1563b3fb8555SGiannis Adamopoulos         INT oldsel = descr->selected_item;
1564b3fb8555SGiannis Adamopoulos         if (index == oldsel) return LB_OKAY;
1565*0707475fSJustin Miller         if (oldsel != -1) set_item_selected_state(descr, oldsel, FALSE);
1566*0707475fSJustin Miller         if (index != -1) set_item_selected_state(descr, index, TRUE);
1567b3fb8555SGiannis Adamopoulos         descr->selected_item = index;
1568*0707475fSJustin Miller         if (oldsel != -1) LISTBOX_RepaintItem( descr, oldsel, ODA_SELECT );
1569b3fb8555SGiannis Adamopoulos         if (index != -1) LISTBOX_RepaintItem( descr, index, ODA_SELECT );
1570b3fb8555SGiannis Adamopoulos         if (send_notify && descr->nb_items) SEND_NOTIFICATION( descr,
1571b3fb8555SGiannis Adamopoulos                                (index != -1) ? LBN_SELCHANGE : LBN_SELCANCEL );
1572b3fb8555SGiannis Adamopoulos 	else
1573b3fb8555SGiannis Adamopoulos 	    if( descr->lphc ) /* set selection change flag for parent combo */
1574b3fb8555SGiannis Adamopoulos 		descr->lphc->wState |= CBF_SELCHANGE;
1575b3fb8555SGiannis Adamopoulos     }
1576b3fb8555SGiannis Adamopoulos     return LB_OKAY;
1577b3fb8555SGiannis Adamopoulos }
1578b3fb8555SGiannis Adamopoulos 
1579b3fb8555SGiannis Adamopoulos 
1580b3fb8555SGiannis Adamopoulos /***********************************************************************
1581b3fb8555SGiannis Adamopoulos  *           LISTBOX_MoveCaret
1582b3fb8555SGiannis Adamopoulos  *
1583b3fb8555SGiannis Adamopoulos  * Change the caret position and extend the selection to the new caret.
1584b3fb8555SGiannis Adamopoulos  */
LISTBOX_MoveCaret(LB_DESCR * descr,INT index,BOOL fully_visible)1585b3fb8555SGiannis Adamopoulos static void LISTBOX_MoveCaret( LB_DESCR *descr, INT index, BOOL fully_visible )
1586b3fb8555SGiannis Adamopoulos {
1587b3fb8555SGiannis Adamopoulos     TRACE("old focus %d, index %d\n", descr->focus_item, index);
1588b3fb8555SGiannis Adamopoulos 
1589b3fb8555SGiannis Adamopoulos     if ((index <  0) || (index >= descr->nb_items))
1590b3fb8555SGiannis Adamopoulos         return;
1591b3fb8555SGiannis Adamopoulos 
1592b3fb8555SGiannis Adamopoulos     /* Important, repaint needs to be done in this order if
1593b3fb8555SGiannis Adamopoulos        you want to mimic Windows behavior:
1594b3fb8555SGiannis Adamopoulos        1. Remove the focus and paint the item
1595b3fb8555SGiannis Adamopoulos        2. Remove the selection and paint the item(s)
1596b3fb8555SGiannis Adamopoulos        3. Set the selection and repaint the item(s)
1597b3fb8555SGiannis Adamopoulos        4. Set the focus to 'index' and repaint the item */
1598b3fb8555SGiannis Adamopoulos 
1599b3fb8555SGiannis Adamopoulos     /* 1. remove the focus and repaint the item */
1600b3fb8555SGiannis Adamopoulos     LISTBOX_DrawFocusRect( descr, FALSE );
1601b3fb8555SGiannis Adamopoulos 
1602b3fb8555SGiannis Adamopoulos     /* 2. then turn off the previous selection */
1603b3fb8555SGiannis Adamopoulos     /* 3. repaint the new selected item */
1604b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_EXTENDEDSEL)
1605b3fb8555SGiannis Adamopoulos     {
1606b3fb8555SGiannis Adamopoulos         if (descr->anchor_item != -1)
1607b3fb8555SGiannis Adamopoulos         {
1608b3fb8555SGiannis Adamopoulos             INT first = min( index, descr->anchor_item );
1609b3fb8555SGiannis Adamopoulos             INT last  = max( index, descr->anchor_item );
1610b3fb8555SGiannis Adamopoulos             if (first > 0)
1611b3fb8555SGiannis Adamopoulos                 LISTBOX_SelectItemRange( descr, 0, first - 1, FALSE );
1612b3fb8555SGiannis Adamopoulos             LISTBOX_SelectItemRange( descr, last + 1, -1, FALSE );
1613b3fb8555SGiannis Adamopoulos             LISTBOX_SelectItemRange( descr, first, last, TRUE );
1614b3fb8555SGiannis Adamopoulos         }
1615b3fb8555SGiannis Adamopoulos     }
1616b3fb8555SGiannis Adamopoulos     else if (!(descr->style & LBS_MULTIPLESEL))
1617b3fb8555SGiannis Adamopoulos     {
1618b3fb8555SGiannis Adamopoulos         /* Set selection to new caret item */
1619b3fb8555SGiannis Adamopoulos         LISTBOX_SetSelection( descr, index, TRUE, FALSE );
1620b3fb8555SGiannis Adamopoulos     }
1621b3fb8555SGiannis Adamopoulos 
1622b3fb8555SGiannis Adamopoulos     /* 4. repaint the new item with the focus */
1623b3fb8555SGiannis Adamopoulos     descr->focus_item = index;
1624b3fb8555SGiannis Adamopoulos     LISTBOX_MakeItemVisible( descr, index, fully_visible );
1625b3fb8555SGiannis Adamopoulos     LISTBOX_DrawFocusRect( descr, TRUE );
1626b3fb8555SGiannis Adamopoulos }
1627b3fb8555SGiannis Adamopoulos 
1628b3fb8555SGiannis Adamopoulos 
1629b3fb8555SGiannis Adamopoulos /***********************************************************************
1630b3fb8555SGiannis Adamopoulos  *           LISTBOX_InsertItem
1631b3fb8555SGiannis Adamopoulos  */
LISTBOX_InsertItem(LB_DESCR * descr,INT index,LPWSTR str,ULONG_PTR data)1632b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_InsertItem( LB_DESCR *descr, INT index,
1633b3fb8555SGiannis Adamopoulos                                    LPWSTR str, ULONG_PTR data )
1634b3fb8555SGiannis Adamopoulos {
1635b3fb8555SGiannis Adamopoulos     INT oldfocus = descr->focus_item;
1636b3fb8555SGiannis Adamopoulos 
1637b3fb8555SGiannis Adamopoulos     if (index == -1) index = descr->nb_items;
1638b3fb8555SGiannis Adamopoulos     else if ((index < 0) || (index > descr->nb_items)) return LB_ERR;
1639*0707475fSJustin Miller     if (!resize_storage(descr, descr->nb_items + 1)) return LB_ERR;
1640b3fb8555SGiannis Adamopoulos 
1641*0707475fSJustin Miller     insert_item_data(descr, index);
1642b3fb8555SGiannis Adamopoulos     descr->nb_items++;
1643*0707475fSJustin Miller     set_item_string(descr, index, str);
1644*0707475fSJustin Miller     set_item_data(descr, index, HAS_STRINGS(descr) ? 0 : data);
1645*0707475fSJustin Miller     set_item_height(descr, index, 0);
1646*0707475fSJustin Miller     set_item_selected_state(descr, index, FALSE);
1647b3fb8555SGiannis Adamopoulos 
1648b3fb8555SGiannis Adamopoulos     /* Get item height */
1649b3fb8555SGiannis Adamopoulos 
1650b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_OWNERDRAWVARIABLE)
1651b3fb8555SGiannis Adamopoulos     {
1652b3fb8555SGiannis Adamopoulos         MEASUREITEMSTRUCT mis;
1653b3fb8555SGiannis Adamopoulos         UINT id = (UINT)GetWindowLongPtrW( descr->self, GWLP_ID );
1654b3fb8555SGiannis Adamopoulos 
1655b3fb8555SGiannis Adamopoulos         mis.CtlType    = ODT_LISTBOX;
1656b3fb8555SGiannis Adamopoulos         mis.CtlID      = id;
1657b3fb8555SGiannis Adamopoulos         mis.itemID     = index;
1658b3fb8555SGiannis Adamopoulos         mis.itemData   = data;
1659b3fb8555SGiannis Adamopoulos         mis.itemHeight = descr->item_height;
1660b3fb8555SGiannis Adamopoulos         SendMessageW( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
1661*0707475fSJustin Miller         set_item_height(descr, index, mis.itemHeight ? mis.itemHeight : 1);
1662b3fb8555SGiannis Adamopoulos         TRACE("[%p]: measure item %d (%s) = %d\n",
1663*0707475fSJustin Miller               descr->self, index, str ? debugstr_w(str) : "", get_item_height(descr, index));
1664b3fb8555SGiannis Adamopoulos     }
1665b3fb8555SGiannis Adamopoulos 
1666b3fb8555SGiannis Adamopoulos     /* Repaint the items */
1667b3fb8555SGiannis Adamopoulos 
1668b3fb8555SGiannis Adamopoulos     LISTBOX_UpdateScroll( descr );
1669b3fb8555SGiannis Adamopoulos     LISTBOX_InvalidateItems( descr, index );
1670b3fb8555SGiannis Adamopoulos 
1671b3fb8555SGiannis Adamopoulos     /* Move selection and focused item */
1672b3fb8555SGiannis Adamopoulos     /* If listbox was empty, set focus to the first item */
1673b3fb8555SGiannis Adamopoulos     if (descr->nb_items == 1)
1674b3fb8555SGiannis Adamopoulos          LISTBOX_SetCaretIndex( descr, 0, FALSE );
1675b3fb8555SGiannis Adamopoulos     /* single select don't change selection index in win31 */
1676b3fb8555SGiannis Adamopoulos     else if ((ISWIN31) && !(IS_MULTISELECT(descr)))
1677b3fb8555SGiannis Adamopoulos     {
1678b3fb8555SGiannis Adamopoulos         descr->selected_item++;
1679b3fb8555SGiannis Adamopoulos         LISTBOX_SetSelection( descr, descr->selected_item-1, TRUE, FALSE );
1680b3fb8555SGiannis Adamopoulos     }
1681b3fb8555SGiannis Adamopoulos     else
1682b3fb8555SGiannis Adamopoulos     {
1683b3fb8555SGiannis Adamopoulos         if (index <= descr->selected_item)
1684b3fb8555SGiannis Adamopoulos         {
1685b3fb8555SGiannis Adamopoulos             descr->selected_item++;
1686b3fb8555SGiannis Adamopoulos             descr->focus_item = oldfocus; /* focus not changed */
1687b3fb8555SGiannis Adamopoulos         }
1688b3fb8555SGiannis Adamopoulos     }
1689b3fb8555SGiannis Adamopoulos     return LB_OKAY;
1690b3fb8555SGiannis Adamopoulos }
1691b3fb8555SGiannis Adamopoulos 
1692b3fb8555SGiannis Adamopoulos 
1693b3fb8555SGiannis Adamopoulos /***********************************************************************
1694b3fb8555SGiannis Adamopoulos  *           LISTBOX_InsertString
1695b3fb8555SGiannis Adamopoulos  */
LISTBOX_InsertString(LB_DESCR * descr,INT index,LPCWSTR str)1696b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_InsertString( LB_DESCR *descr, INT index, LPCWSTR str )
1697b3fb8555SGiannis Adamopoulos {
1698b3fb8555SGiannis Adamopoulos     LPWSTR new_str = NULL;
1699b3fb8555SGiannis Adamopoulos     LRESULT ret;
1700b3fb8555SGiannis Adamopoulos 
1701b3fb8555SGiannis Adamopoulos     if (HAS_STRINGS(descr))
1702b3fb8555SGiannis Adamopoulos     {
1703b3fb8555SGiannis Adamopoulos         static const WCHAR empty_stringW[] = { 0 };
1704b3fb8555SGiannis Adamopoulos         if (!str) str = empty_stringW;
1705*0707475fSJustin Miller         if (!(new_str = HeapAlloc( GetProcessHeap(), 0, (lstrlenW(str) + 1) * sizeof(WCHAR) )))
1706b3fb8555SGiannis Adamopoulos         {
1707b3fb8555SGiannis Adamopoulos             SEND_NOTIFICATION( descr, LBN_ERRSPACE );
1708b3fb8555SGiannis Adamopoulos             return LB_ERRSPACE;
1709b3fb8555SGiannis Adamopoulos         }
1710*0707475fSJustin Miller         lstrcpyW(new_str, str);
1711b3fb8555SGiannis Adamopoulos     }
1712b3fb8555SGiannis Adamopoulos 
1713b3fb8555SGiannis Adamopoulos     if (index == -1) index = descr->nb_items;
1714b3fb8555SGiannis Adamopoulos     if ((ret = LISTBOX_InsertItem( descr, index, new_str, (ULONG_PTR)str )) != 0)
1715b3fb8555SGiannis Adamopoulos     {
1716b3fb8555SGiannis Adamopoulos         HeapFree( GetProcessHeap(), 0, new_str );
1717b3fb8555SGiannis Adamopoulos         return ret;
1718b3fb8555SGiannis Adamopoulos     }
1719b3fb8555SGiannis Adamopoulos 
1720b3fb8555SGiannis Adamopoulos     TRACE("[%p]: added item %d %s\n",
1721b3fb8555SGiannis Adamopoulos           descr->self, index, HAS_STRINGS(descr) ? debugstr_w(new_str) : "" );
1722b3fb8555SGiannis Adamopoulos     return index;
1723b3fb8555SGiannis Adamopoulos }
1724b3fb8555SGiannis Adamopoulos 
1725b3fb8555SGiannis Adamopoulos 
1726b3fb8555SGiannis Adamopoulos /***********************************************************************
1727b3fb8555SGiannis Adamopoulos  *           LISTBOX_DeleteItem
1728b3fb8555SGiannis Adamopoulos  *
1729b3fb8555SGiannis Adamopoulos  * Delete the content of an item. 'index' must be a valid index.
1730b3fb8555SGiannis Adamopoulos  */
LISTBOX_DeleteItem(LB_DESCR * descr,INT index)1731b3fb8555SGiannis Adamopoulos static void LISTBOX_DeleteItem( LB_DESCR *descr, INT index )
1732b3fb8555SGiannis Adamopoulos {
1733b3fb8555SGiannis Adamopoulos     /* Note: Win 3.1 only sends DELETEITEM on owner-draw items,
1734b3fb8555SGiannis Adamopoulos      *       while Win95 sends it for all items with user data.
1735b3fb8555SGiannis Adamopoulos      *       It's probably better to send it too often than not
1736b3fb8555SGiannis Adamopoulos      *       often enough, so this is what we do here.
1737b3fb8555SGiannis Adamopoulos      */
1738*0707475fSJustin Miller     if (IS_OWNERDRAW(descr) || get_item_data(descr, index))
1739b3fb8555SGiannis Adamopoulos     {
1740b3fb8555SGiannis Adamopoulos         DELETEITEMSTRUCT dis;
1741b3fb8555SGiannis Adamopoulos         UINT id = (UINT)GetWindowLongPtrW( descr->self, GWLP_ID );
1742b3fb8555SGiannis Adamopoulos 
1743b3fb8555SGiannis Adamopoulos         dis.CtlType  = ODT_LISTBOX;
1744b3fb8555SGiannis Adamopoulos         dis.CtlID    = id;
1745b3fb8555SGiannis Adamopoulos         dis.itemID   = index;
1746b3fb8555SGiannis Adamopoulos         dis.hwndItem = descr->self;
1747*0707475fSJustin Miller         dis.itemData = get_item_data(descr, index);
1748b3fb8555SGiannis Adamopoulos         SendMessageW( descr->owner, WM_DELETEITEM, id, (LPARAM)&dis );
1749b3fb8555SGiannis Adamopoulos     }
1750*0707475fSJustin Miller     HeapFree( GetProcessHeap(), 0, get_item_string(descr, index) );
1751b3fb8555SGiannis Adamopoulos }
1752b3fb8555SGiannis Adamopoulos 
1753b3fb8555SGiannis Adamopoulos 
1754b3fb8555SGiannis Adamopoulos /***********************************************************************
1755b3fb8555SGiannis Adamopoulos  *           LISTBOX_RemoveItem
1756b3fb8555SGiannis Adamopoulos  *
1757b3fb8555SGiannis Adamopoulos  * Remove an item from the listbox and delete its content.
1758b3fb8555SGiannis Adamopoulos  */
LISTBOX_RemoveItem(LB_DESCR * descr,INT index)1759b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_RemoveItem( LB_DESCR *descr, INT index )
1760b3fb8555SGiannis Adamopoulos {
1761b3fb8555SGiannis Adamopoulos     if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
1762b3fb8555SGiannis Adamopoulos 
1763b3fb8555SGiannis Adamopoulos     /* We need to invalidate the original rect instead of the updated one. */
1764b3fb8555SGiannis Adamopoulos     LISTBOX_InvalidateItems( descr, index );
1765b3fb8555SGiannis Adamopoulos 
1766*0707475fSJustin Miller     if (descr->nb_items == 1)
1767*0707475fSJustin Miller     {
1768*0707475fSJustin Miller         SendMessageW(descr->self, LB_RESETCONTENT, 0, 0);
1769*0707475fSJustin Miller         return LB_OKAY;
1770*0707475fSJustin Miller     }
1771b3fb8555SGiannis Adamopoulos     descr->nb_items--;
1772b3fb8555SGiannis Adamopoulos     LISTBOX_DeleteItem( descr, index );
1773*0707475fSJustin Miller     remove_item_data(descr, index);
1774b3fb8555SGiannis Adamopoulos 
1775b3fb8555SGiannis Adamopoulos     if (descr->anchor_item == descr->nb_items) descr->anchor_item--;
1776*0707475fSJustin Miller     resize_storage(descr, descr->nb_items);
1777b3fb8555SGiannis Adamopoulos 
1778b3fb8555SGiannis Adamopoulos     /* Repaint the items */
1779b3fb8555SGiannis Adamopoulos 
1780b3fb8555SGiannis Adamopoulos     LISTBOX_UpdateScroll( descr );
1781b3fb8555SGiannis Adamopoulos     /* if we removed the scrollbar, reset the top of the list
1782b3fb8555SGiannis Adamopoulos       (correct for owner-drawn ???) */
1783b3fb8555SGiannis Adamopoulos     if (descr->nb_items == descr->page_size)
1784b3fb8555SGiannis Adamopoulos         LISTBOX_SetTopItem( descr, 0, TRUE );
1785b3fb8555SGiannis Adamopoulos 
1786b3fb8555SGiannis Adamopoulos     /* Move selection and focused item */
1787b3fb8555SGiannis Adamopoulos     if (!IS_MULTISELECT(descr))
1788b3fb8555SGiannis Adamopoulos     {
1789b3fb8555SGiannis Adamopoulos         if (index == descr->selected_item)
1790b3fb8555SGiannis Adamopoulos             descr->selected_item = -1;
1791b3fb8555SGiannis Adamopoulos         else if (index < descr->selected_item)
1792b3fb8555SGiannis Adamopoulos         {
1793b3fb8555SGiannis Adamopoulos             descr->selected_item--;
1794b3fb8555SGiannis Adamopoulos             if (ISWIN31) /* win 31 do not change the selected item number */
1795b3fb8555SGiannis Adamopoulos                LISTBOX_SetSelection( descr, descr->selected_item + 1, TRUE, FALSE);
1796b3fb8555SGiannis Adamopoulos         }
1797b3fb8555SGiannis Adamopoulos     }
1798b3fb8555SGiannis Adamopoulos 
1799b3fb8555SGiannis Adamopoulos     if (descr->focus_item >= descr->nb_items)
1800b3fb8555SGiannis Adamopoulos     {
1801b3fb8555SGiannis Adamopoulos           descr->focus_item = descr->nb_items - 1;
1802b3fb8555SGiannis Adamopoulos           if (descr->focus_item < 0) descr->focus_item = 0;
1803b3fb8555SGiannis Adamopoulos     }
1804b3fb8555SGiannis Adamopoulos     return LB_OKAY;
1805b3fb8555SGiannis Adamopoulos }
1806b3fb8555SGiannis Adamopoulos 
1807b3fb8555SGiannis Adamopoulos 
1808b3fb8555SGiannis Adamopoulos /***********************************************************************
1809b3fb8555SGiannis Adamopoulos  *           LISTBOX_ResetContent
1810b3fb8555SGiannis Adamopoulos  */
LISTBOX_ResetContent(LB_DESCR * descr)1811b3fb8555SGiannis Adamopoulos static void LISTBOX_ResetContent( LB_DESCR *descr )
1812b3fb8555SGiannis Adamopoulos {
1813b3fb8555SGiannis Adamopoulos     INT i;
1814b3fb8555SGiannis Adamopoulos 
1815*0707475fSJustin Miller     if (!(descr->style & LBS_NODATA))
1816b3fb8555SGiannis Adamopoulos         for (i = descr->nb_items - 1; i >= 0; i--) LISTBOX_DeleteItem(descr, i);
1817*0707475fSJustin Miller     HeapFree( GetProcessHeap(), 0, descr->u.items );
1818b3fb8555SGiannis Adamopoulos     descr->nb_items      = 0;
1819b3fb8555SGiannis Adamopoulos     descr->top_item      = 0;
1820b3fb8555SGiannis Adamopoulos     descr->selected_item = -1;
1821b3fb8555SGiannis Adamopoulos     descr->focus_item    = 0;
1822b3fb8555SGiannis Adamopoulos     descr->anchor_item   = -1;
1823*0707475fSJustin Miller     descr->items_size    = 0;
1824*0707475fSJustin Miller     descr->u.items       = NULL;
1825b3fb8555SGiannis Adamopoulos }
1826b3fb8555SGiannis Adamopoulos 
1827b3fb8555SGiannis Adamopoulos 
1828b3fb8555SGiannis Adamopoulos /***********************************************************************
1829b3fb8555SGiannis Adamopoulos  *           LISTBOX_SetCount
1830b3fb8555SGiannis Adamopoulos  */
LISTBOX_SetCount(LB_DESCR * descr,UINT count)1831*0707475fSJustin Miller static LRESULT LISTBOX_SetCount( LB_DESCR *descr, UINT count )
1832b3fb8555SGiannis Adamopoulos {
1833*0707475fSJustin Miller     UINT orig_num = descr->nb_items;
1834b3fb8555SGiannis Adamopoulos 
1835*0707475fSJustin Miller     if (!(descr->style & LBS_NODATA)) return LB_ERR;
1836*0707475fSJustin Miller 
1837*0707475fSJustin Miller     if (!resize_storage(descr, count))
1838*0707475fSJustin Miller         return LB_ERRSPACE;
1839*0707475fSJustin Miller     descr->nb_items = count;
1840*0707475fSJustin Miller 
1841*0707475fSJustin Miller     if (count)
1842b3fb8555SGiannis Adamopoulos     {
1843*0707475fSJustin Miller         LISTBOX_UpdateScroll(descr);
1844*0707475fSJustin Miller         if (count < orig_num)
1845*0707475fSJustin Miller         {
1846*0707475fSJustin Miller             descr->anchor_item = min(descr->anchor_item, count - 1);
1847*0707475fSJustin Miller             if (descr->selected_item >= count)
1848*0707475fSJustin Miller                 descr->selected_item = -1;
1849*0707475fSJustin Miller 
1850*0707475fSJustin Miller             /* If we removed the scrollbar, reset the top of the list */
1851*0707475fSJustin Miller             if (count <= descr->page_size && orig_num > descr->page_size)
1852*0707475fSJustin Miller                 LISTBOX_SetTopItem(descr, 0, TRUE);
1853*0707475fSJustin Miller 
1854*0707475fSJustin Miller             descr->focus_item = min(descr->focus_item, count - 1);
1855b3fb8555SGiannis Adamopoulos         }
1856b3fb8555SGiannis Adamopoulos 
1857*0707475fSJustin Miller         /* If it was empty before growing, set focus to the first item */
1858*0707475fSJustin Miller         else if (orig_num == 0) LISTBOX_SetCaretIndex(descr, 0, FALSE);
1859b3fb8555SGiannis Adamopoulos     }
1860*0707475fSJustin Miller     else SendMessageW(descr->self, LB_RESETCONTENT, 0, 0);
1861b3fb8555SGiannis Adamopoulos 
1862b3fb8555SGiannis Adamopoulos     InvalidateRect( descr->self, NULL, TRUE );
1863b3fb8555SGiannis Adamopoulos     return LB_OKAY;
1864b3fb8555SGiannis Adamopoulos }
1865b3fb8555SGiannis Adamopoulos 
1866b3fb8555SGiannis Adamopoulos 
1867b3fb8555SGiannis Adamopoulos /***********************************************************************
1868b3fb8555SGiannis Adamopoulos  *           LISTBOX_Directory
1869b3fb8555SGiannis Adamopoulos  */
LISTBOX_Directory(LB_DESCR * descr,UINT attrib,LPCWSTR filespec,BOOL long_names)1870b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_Directory( LB_DESCR *descr, UINT attrib,
1871b3fb8555SGiannis Adamopoulos                                   LPCWSTR filespec, BOOL long_names )
1872b3fb8555SGiannis Adamopoulos {
1873b3fb8555SGiannis Adamopoulos     HANDLE handle;
1874b3fb8555SGiannis Adamopoulos     LRESULT ret = LB_OKAY;
1875b3fb8555SGiannis Adamopoulos     WIN32_FIND_DATAW entry;
1876b3fb8555SGiannis Adamopoulos     int pos;
1877b3fb8555SGiannis Adamopoulos     LRESULT maxinsert = LB_ERR;
1878b3fb8555SGiannis Adamopoulos 
1879b3fb8555SGiannis Adamopoulos     /* don't scan directory if we just want drives exclusively */
1880b3fb8555SGiannis Adamopoulos     if (attrib != (DDL_DRIVES | DDL_EXCLUSIVE)) {
1881b3fb8555SGiannis Adamopoulos         /* scan directory */
1882b3fb8555SGiannis Adamopoulos         if ((handle = FindFirstFileW(filespec, &entry)) == INVALID_HANDLE_VALUE)
1883b3fb8555SGiannis Adamopoulos         {
1884b3fb8555SGiannis Adamopoulos 	     int le = GetLastError();
1885b3fb8555SGiannis Adamopoulos             if ((le != ERROR_NO_MORE_FILES) && (le != ERROR_FILE_NOT_FOUND)) return LB_ERR;
1886b3fb8555SGiannis Adamopoulos         }
1887b3fb8555SGiannis Adamopoulos         else
1888b3fb8555SGiannis Adamopoulos         {
1889b3fb8555SGiannis Adamopoulos             do
1890b3fb8555SGiannis Adamopoulos             {
1891b3fb8555SGiannis Adamopoulos                 WCHAR buffer[270];
1892b3fb8555SGiannis Adamopoulos                 if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
1893b3fb8555SGiannis Adamopoulos                 {
1894b3fb8555SGiannis Adamopoulos                     static const WCHAR bracketW[]  = { ']',0 };
1895b3fb8555SGiannis Adamopoulos                     static const WCHAR dotW[] = { '.',0 };
1896b3fb8555SGiannis Adamopoulos                     if (!(attrib & DDL_DIRECTORY) ||
1897*0707475fSJustin Miller                         !lstrcmpW( entry.cFileName, dotW )) continue;
1898b3fb8555SGiannis Adamopoulos                     buffer[0] = '[';
1899b3fb8555SGiannis Adamopoulos                     if (!long_names && entry.cAlternateFileName[0])
1900*0707475fSJustin Miller                         lstrcpyW( buffer + 1, entry.cAlternateFileName );
1901b3fb8555SGiannis Adamopoulos                     else
1902*0707475fSJustin Miller                         lstrcpyW( buffer + 1, entry.cFileName );
1903*0707475fSJustin Miller                     lstrcatW(buffer, bracketW);
1904b3fb8555SGiannis Adamopoulos                 }
1905b3fb8555SGiannis Adamopoulos                 else  /* not a directory */
1906b3fb8555SGiannis Adamopoulos                 {
1907b3fb8555SGiannis Adamopoulos #define ATTRIBS (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
1908b3fb8555SGiannis Adamopoulos                  FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE)
1909b3fb8555SGiannis Adamopoulos 
1910b3fb8555SGiannis Adamopoulos                     if ((attrib & DDL_EXCLUSIVE) &&
1911b3fb8555SGiannis Adamopoulos                         ((attrib & ATTRIBS) != (entry.dwFileAttributes & ATTRIBS)))
1912b3fb8555SGiannis Adamopoulos                         continue;
1913b3fb8555SGiannis Adamopoulos #undef ATTRIBS
1914b3fb8555SGiannis Adamopoulos                     if (!long_names && entry.cAlternateFileName[0])
1915*0707475fSJustin Miller                         lstrcpyW( buffer, entry.cAlternateFileName );
1916b3fb8555SGiannis Adamopoulos                     else
1917*0707475fSJustin Miller                         lstrcpyW( buffer, entry.cFileName );
1918b3fb8555SGiannis Adamopoulos                 }
1919b3fb8555SGiannis Adamopoulos                 if (!long_names) CharLowerW( buffer );
1920b3fb8555SGiannis Adamopoulos                 pos = LISTBOX_FindFileStrPos( descr, buffer );
1921b3fb8555SGiannis Adamopoulos                 if ((ret = LISTBOX_InsertString( descr, pos, buffer )) < 0)
1922b3fb8555SGiannis Adamopoulos                     break;
1923b3fb8555SGiannis Adamopoulos                 if (ret <= maxinsert) maxinsert++; else maxinsert = ret;
1924b3fb8555SGiannis Adamopoulos             } while (FindNextFileW( handle, &entry ));
1925b3fb8555SGiannis Adamopoulos             FindClose( handle );
1926b3fb8555SGiannis Adamopoulos         }
1927b3fb8555SGiannis Adamopoulos     }
1928b3fb8555SGiannis Adamopoulos     if (ret >= 0)
1929b3fb8555SGiannis Adamopoulos     {
1930b3fb8555SGiannis Adamopoulos         ret = maxinsert;
1931b3fb8555SGiannis Adamopoulos 
1932b3fb8555SGiannis Adamopoulos         /* scan drives */
1933b3fb8555SGiannis Adamopoulos         if (attrib & DDL_DRIVES)
1934b3fb8555SGiannis Adamopoulos         {
1935b3fb8555SGiannis Adamopoulos             WCHAR buffer[] = {'[','-','a','-',']',0};
1936b3fb8555SGiannis Adamopoulos             WCHAR root[] = {'A',':','\\',0};
1937b3fb8555SGiannis Adamopoulos             int drive;
1938b3fb8555SGiannis Adamopoulos             for (drive = 0; drive < 26; drive++, buffer[2]++, root[0]++)
1939b3fb8555SGiannis Adamopoulos             {
1940b3fb8555SGiannis Adamopoulos                 if (GetDriveTypeW(root) <= DRIVE_NO_ROOT_DIR) continue;
1941b3fb8555SGiannis Adamopoulos                 if ((ret = LISTBOX_InsertString( descr, -1, buffer )) < 0)
1942b3fb8555SGiannis Adamopoulos                     break;
1943b3fb8555SGiannis Adamopoulos             }
1944b3fb8555SGiannis Adamopoulos         }
1945b3fb8555SGiannis Adamopoulos     }
1946b3fb8555SGiannis Adamopoulos     return ret;
1947b3fb8555SGiannis Adamopoulos }
1948b3fb8555SGiannis Adamopoulos 
1949b3fb8555SGiannis Adamopoulos 
1950b3fb8555SGiannis Adamopoulos /***********************************************************************
1951b3fb8555SGiannis Adamopoulos  *           LISTBOX_HandleVScroll
1952b3fb8555SGiannis Adamopoulos  */
LISTBOX_HandleVScroll(LB_DESCR * descr,WORD scrollReq,WORD pos)1953b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_HandleVScroll( LB_DESCR *descr, WORD scrollReq, WORD pos )
1954b3fb8555SGiannis Adamopoulos {
1955b3fb8555SGiannis Adamopoulos     SCROLLINFO info;
1956b3fb8555SGiannis Adamopoulos 
1957b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_MULTICOLUMN) return 0;
1958b3fb8555SGiannis Adamopoulos     switch(scrollReq)
1959b3fb8555SGiannis Adamopoulos     {
1960b3fb8555SGiannis Adamopoulos     case SB_LINEUP:
1961b3fb8555SGiannis Adamopoulos         LISTBOX_SetTopItem( descr, descr->top_item - 1, TRUE );
1962b3fb8555SGiannis Adamopoulos         break;
1963b3fb8555SGiannis Adamopoulos     case SB_LINEDOWN:
1964b3fb8555SGiannis Adamopoulos         LISTBOX_SetTopItem( descr, descr->top_item + 1, TRUE );
1965b3fb8555SGiannis Adamopoulos         break;
1966b3fb8555SGiannis Adamopoulos     case SB_PAGEUP:
1967b3fb8555SGiannis Adamopoulos         LISTBOX_SetTopItem( descr, descr->top_item -
1968b3fb8555SGiannis Adamopoulos                             LISTBOX_GetCurrentPageSize( descr ), TRUE );
1969b3fb8555SGiannis Adamopoulos         break;
1970b3fb8555SGiannis Adamopoulos     case SB_PAGEDOWN:
1971b3fb8555SGiannis Adamopoulos         LISTBOX_SetTopItem( descr, descr->top_item +
1972b3fb8555SGiannis Adamopoulos                             LISTBOX_GetCurrentPageSize( descr ), TRUE );
1973b3fb8555SGiannis Adamopoulos         break;
1974b3fb8555SGiannis Adamopoulos     case SB_THUMBPOSITION:
1975b3fb8555SGiannis Adamopoulos         LISTBOX_SetTopItem( descr, pos, TRUE );
1976b3fb8555SGiannis Adamopoulos         break;
1977b3fb8555SGiannis Adamopoulos     case SB_THUMBTRACK:
1978b3fb8555SGiannis Adamopoulos         info.cbSize = sizeof(info);
1979b3fb8555SGiannis Adamopoulos         info.fMask = SIF_TRACKPOS;
1980b3fb8555SGiannis Adamopoulos         GetScrollInfo( descr->self, SB_VERT, &info );
1981b3fb8555SGiannis Adamopoulos         LISTBOX_SetTopItem( descr, info.nTrackPos, TRUE );
1982b3fb8555SGiannis Adamopoulos         break;
1983b3fb8555SGiannis Adamopoulos     case SB_TOP:
1984b3fb8555SGiannis Adamopoulos         LISTBOX_SetTopItem( descr, 0, TRUE );
1985b3fb8555SGiannis Adamopoulos         break;
1986b3fb8555SGiannis Adamopoulos     case SB_BOTTOM:
1987b3fb8555SGiannis Adamopoulos         LISTBOX_SetTopItem( descr, descr->nb_items, TRUE );
1988b3fb8555SGiannis Adamopoulos         break;
1989b3fb8555SGiannis Adamopoulos     }
1990b3fb8555SGiannis Adamopoulos     return 0;
1991b3fb8555SGiannis Adamopoulos }
1992b3fb8555SGiannis Adamopoulos 
1993b3fb8555SGiannis Adamopoulos 
1994b3fb8555SGiannis Adamopoulos /***********************************************************************
1995b3fb8555SGiannis Adamopoulos  *           LISTBOX_HandleHScroll
1996b3fb8555SGiannis Adamopoulos  */
LISTBOX_HandleHScroll(LB_DESCR * descr,WORD scrollReq,WORD pos)1997b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_HandleHScroll( LB_DESCR *descr, WORD scrollReq, WORD pos )
1998b3fb8555SGiannis Adamopoulos {
1999b3fb8555SGiannis Adamopoulos     SCROLLINFO info;
2000b3fb8555SGiannis Adamopoulos     INT page;
2001b3fb8555SGiannis Adamopoulos 
2002b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_MULTICOLUMN)
2003b3fb8555SGiannis Adamopoulos     {
2004b3fb8555SGiannis Adamopoulos         switch(scrollReq)
2005b3fb8555SGiannis Adamopoulos         {
2006b3fb8555SGiannis Adamopoulos         case SB_LINELEFT:
2007b3fb8555SGiannis Adamopoulos             LISTBOX_SetTopItem( descr, descr->top_item-descr->page_size,
2008b3fb8555SGiannis Adamopoulos                                 TRUE );
2009b3fb8555SGiannis Adamopoulos             break;
2010b3fb8555SGiannis Adamopoulos         case SB_LINERIGHT:
2011b3fb8555SGiannis Adamopoulos             LISTBOX_SetTopItem( descr, descr->top_item+descr->page_size,
2012b3fb8555SGiannis Adamopoulos                                 TRUE );
2013b3fb8555SGiannis Adamopoulos             break;
2014b3fb8555SGiannis Adamopoulos         case SB_PAGELEFT:
2015b3fb8555SGiannis Adamopoulos             page = descr->width / descr->column_width;
2016b3fb8555SGiannis Adamopoulos             if (page < 1) page = 1;
2017b3fb8555SGiannis Adamopoulos             LISTBOX_SetTopItem( descr,
2018b3fb8555SGiannis Adamopoulos                              descr->top_item - page * descr->page_size, TRUE );
2019b3fb8555SGiannis Adamopoulos             break;
2020b3fb8555SGiannis Adamopoulos         case SB_PAGERIGHT:
2021b3fb8555SGiannis Adamopoulos             page = descr->width / descr->column_width;
2022b3fb8555SGiannis Adamopoulos             if (page < 1) page = 1;
2023b3fb8555SGiannis Adamopoulos             LISTBOX_SetTopItem( descr,
2024b3fb8555SGiannis Adamopoulos                              descr->top_item + page * descr->page_size, TRUE );
2025b3fb8555SGiannis Adamopoulos             break;
2026b3fb8555SGiannis Adamopoulos         case SB_THUMBPOSITION:
2027b3fb8555SGiannis Adamopoulos             LISTBOX_SetTopItem( descr, pos*descr->page_size, TRUE );
2028b3fb8555SGiannis Adamopoulos             break;
2029b3fb8555SGiannis Adamopoulos         case SB_THUMBTRACK:
2030b3fb8555SGiannis Adamopoulos             info.cbSize = sizeof(info);
2031b3fb8555SGiannis Adamopoulos             info.fMask  = SIF_TRACKPOS;
2032b3fb8555SGiannis Adamopoulos             GetScrollInfo( descr->self, SB_VERT, &info );
2033b3fb8555SGiannis Adamopoulos             LISTBOX_SetTopItem( descr, info.nTrackPos*descr->page_size,
2034b3fb8555SGiannis Adamopoulos                                 TRUE );
2035b3fb8555SGiannis Adamopoulos             break;
2036b3fb8555SGiannis Adamopoulos         case SB_LEFT:
2037b3fb8555SGiannis Adamopoulos             LISTBOX_SetTopItem( descr, 0, TRUE );
2038b3fb8555SGiannis Adamopoulos             break;
2039b3fb8555SGiannis Adamopoulos         case SB_RIGHT:
2040b3fb8555SGiannis Adamopoulos             LISTBOX_SetTopItem( descr, descr->nb_items, TRUE );
2041b3fb8555SGiannis Adamopoulos             break;
2042b3fb8555SGiannis Adamopoulos         }
2043b3fb8555SGiannis Adamopoulos     }
2044b3fb8555SGiannis Adamopoulos     else if (descr->horz_extent)
2045b3fb8555SGiannis Adamopoulos     {
2046b3fb8555SGiannis Adamopoulos         switch(scrollReq)
2047b3fb8555SGiannis Adamopoulos         {
2048b3fb8555SGiannis Adamopoulos         case SB_LINELEFT:
2049b3fb8555SGiannis Adamopoulos             LISTBOX_SetHorizontalPos( descr, descr->horz_pos - 1 );
2050b3fb8555SGiannis Adamopoulos             break;
2051b3fb8555SGiannis Adamopoulos         case SB_LINERIGHT:
2052b3fb8555SGiannis Adamopoulos             LISTBOX_SetHorizontalPos( descr, descr->horz_pos + 1 );
2053b3fb8555SGiannis Adamopoulos             break;
2054b3fb8555SGiannis Adamopoulos         case SB_PAGELEFT:
2055b3fb8555SGiannis Adamopoulos             LISTBOX_SetHorizontalPos( descr,
2056b3fb8555SGiannis Adamopoulos                                       descr->horz_pos - descr->width );
2057b3fb8555SGiannis Adamopoulos             break;
2058b3fb8555SGiannis Adamopoulos         case SB_PAGERIGHT:
2059b3fb8555SGiannis Adamopoulos             LISTBOX_SetHorizontalPos( descr,
2060b3fb8555SGiannis Adamopoulos                                       descr->horz_pos + descr->width );
2061b3fb8555SGiannis Adamopoulos             break;
2062b3fb8555SGiannis Adamopoulos         case SB_THUMBPOSITION:
2063b3fb8555SGiannis Adamopoulos             LISTBOX_SetHorizontalPos( descr, pos );
2064b3fb8555SGiannis Adamopoulos             break;
2065b3fb8555SGiannis Adamopoulos         case SB_THUMBTRACK:
2066b3fb8555SGiannis Adamopoulos             info.cbSize = sizeof(info);
2067b3fb8555SGiannis Adamopoulos             info.fMask = SIF_TRACKPOS;
2068b3fb8555SGiannis Adamopoulos             GetScrollInfo( descr->self, SB_HORZ, &info );
2069b3fb8555SGiannis Adamopoulos             LISTBOX_SetHorizontalPos( descr, info.nTrackPos );
2070b3fb8555SGiannis Adamopoulos             break;
2071b3fb8555SGiannis Adamopoulos         case SB_LEFT:
2072b3fb8555SGiannis Adamopoulos             LISTBOX_SetHorizontalPos( descr, 0 );
2073b3fb8555SGiannis Adamopoulos             break;
2074b3fb8555SGiannis Adamopoulos         case SB_RIGHT:
2075b3fb8555SGiannis Adamopoulos             LISTBOX_SetHorizontalPos( descr,
2076b3fb8555SGiannis Adamopoulos                                       descr->horz_extent - descr->width );
2077b3fb8555SGiannis Adamopoulos             break;
2078b3fb8555SGiannis Adamopoulos         }
2079b3fb8555SGiannis Adamopoulos     }
2080b3fb8555SGiannis Adamopoulos     return 0;
2081b3fb8555SGiannis Adamopoulos }
2082b3fb8555SGiannis Adamopoulos 
LISTBOX_HandleMouseWheel(LB_DESCR * descr,SHORT delta)2083b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_HandleMouseWheel(LB_DESCR *descr, SHORT delta )
2084b3fb8555SGiannis Adamopoulos {
2085*0707475fSJustin Miller     INT pulScrollLines = 3;
2086b3fb8555SGiannis Adamopoulos 
2087b3fb8555SGiannis Adamopoulos     SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
2088b3fb8555SGiannis Adamopoulos 
2089b3fb8555SGiannis Adamopoulos     /* if scrolling changes direction, ignore left overs */
2090b3fb8555SGiannis Adamopoulos     if ((delta < 0 && descr->wheel_remain < 0) ||
2091b3fb8555SGiannis Adamopoulos         (delta > 0 && descr->wheel_remain > 0))
2092b3fb8555SGiannis Adamopoulos         descr->wheel_remain += delta;
2093b3fb8555SGiannis Adamopoulos     else
2094b3fb8555SGiannis Adamopoulos         descr->wheel_remain = delta;
2095b3fb8555SGiannis Adamopoulos 
2096b3fb8555SGiannis Adamopoulos     if (descr->wheel_remain && pulScrollLines)
2097b3fb8555SGiannis Adamopoulos     {
2098b3fb8555SGiannis Adamopoulos         int cLineScroll;
2099*0707475fSJustin Miller         if (descr->style & LBS_MULTICOLUMN)
2100*0707475fSJustin Miller         {
2101*0707475fSJustin Miller             pulScrollLines = min(descr->width / descr->column_width, pulScrollLines);
2102*0707475fSJustin Miller             pulScrollLines = max(1, pulScrollLines);
2103*0707475fSJustin Miller             cLineScroll = pulScrollLines * descr->wheel_remain / WHEEL_DELTA;
2104*0707475fSJustin Miller             descr->wheel_remain -= WHEEL_DELTA * cLineScroll / pulScrollLines;
2105*0707475fSJustin Miller             cLineScroll *= descr->page_size;
2106*0707475fSJustin Miller         }
2107*0707475fSJustin Miller         else
2108*0707475fSJustin Miller         {
2109*0707475fSJustin Miller             pulScrollLines = min(descr->page_size, pulScrollLines);
2110*0707475fSJustin Miller             cLineScroll = pulScrollLines * descr->wheel_remain / WHEEL_DELTA;
2111*0707475fSJustin Miller             descr->wheel_remain -= WHEEL_DELTA * cLineScroll / pulScrollLines;
2112*0707475fSJustin Miller         }
2113b3fb8555SGiannis Adamopoulos         LISTBOX_SetTopItem( descr, descr->top_item - cLineScroll, TRUE );
2114b3fb8555SGiannis Adamopoulos     }
2115b3fb8555SGiannis Adamopoulos     return 0;
2116b3fb8555SGiannis Adamopoulos }
2117b3fb8555SGiannis Adamopoulos 
2118b3fb8555SGiannis Adamopoulos /***********************************************************************
2119b3fb8555SGiannis Adamopoulos  *           LISTBOX_HandleLButtonDown
2120b3fb8555SGiannis Adamopoulos  */
LISTBOX_HandleLButtonDown(LB_DESCR * descr,DWORD keys,INT x,INT y)2121b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_HandleLButtonDown( LB_DESCR *descr, DWORD keys, INT x, INT y )
2122b3fb8555SGiannis Adamopoulos {
2123b3fb8555SGiannis Adamopoulos     INT index = LISTBOX_GetItemFromPoint( descr, x, y );
2124b3fb8555SGiannis Adamopoulos 
2125b3fb8555SGiannis Adamopoulos     TRACE("[%p]: lbuttondown %d,%d item %d, focus item %d\n",
2126b3fb8555SGiannis Adamopoulos           descr->self, x, y, index, descr->focus_item);
2127b3fb8555SGiannis Adamopoulos 
2128b3fb8555SGiannis Adamopoulos     if (!descr->caret_on && (descr->in_focus)) return 0;
2129b3fb8555SGiannis Adamopoulos 
2130b3fb8555SGiannis Adamopoulos     if (!descr->in_focus)
2131b3fb8555SGiannis Adamopoulos     {
2132b3fb8555SGiannis Adamopoulos         if( !descr->lphc ) SetFocus( descr->self );
2133b3fb8555SGiannis Adamopoulos         else SetFocus( (descr->lphc->hWndEdit) ? descr->lphc->hWndEdit : descr->lphc->self );
2134b3fb8555SGiannis Adamopoulos     }
2135b3fb8555SGiannis Adamopoulos 
2136b3fb8555SGiannis Adamopoulos     if (index == -1) return 0;
2137b3fb8555SGiannis Adamopoulos 
2138b3fb8555SGiannis Adamopoulos     if (!descr->lphc)
2139b3fb8555SGiannis Adamopoulos     {
2140b3fb8555SGiannis Adamopoulos         if (descr->style & LBS_NOTIFY )
2141b3fb8555SGiannis Adamopoulos             SendMessageW( descr->owner, WM_LBTRACKPOINT, index,
2142b3fb8555SGiannis Adamopoulos                             MAKELPARAM( x, y ) );
2143b3fb8555SGiannis Adamopoulos     }
2144b3fb8555SGiannis Adamopoulos 
2145b3fb8555SGiannis Adamopoulos     descr->captured = TRUE;
2146b3fb8555SGiannis Adamopoulos     SetCapture( descr->self );
2147b3fb8555SGiannis Adamopoulos 
2148b3fb8555SGiannis Adamopoulos     if (descr->style & (LBS_EXTENDEDSEL | LBS_MULTIPLESEL))
2149b3fb8555SGiannis Adamopoulos     {
2150b3fb8555SGiannis Adamopoulos         /* we should perhaps make sure that all items are deselected
2151b3fb8555SGiannis Adamopoulos            FIXME: needed for !LBS_EXTENDEDSEL, too ?
2152b3fb8555SGiannis Adamopoulos            if (!(keys & (MK_SHIFT|MK_CONTROL)))
2153b3fb8555SGiannis Adamopoulos            LISTBOX_SetSelection( descr, -1, FALSE, FALSE);
2154b3fb8555SGiannis Adamopoulos         */
2155b3fb8555SGiannis Adamopoulos 
2156b3fb8555SGiannis Adamopoulos         if (!(keys & MK_SHIFT)) descr->anchor_item = index;
2157b3fb8555SGiannis Adamopoulos         if (keys & MK_CONTROL)
2158b3fb8555SGiannis Adamopoulos         {
2159b3fb8555SGiannis Adamopoulos             LISTBOX_SetCaretIndex( descr, index, FALSE );
2160b3fb8555SGiannis Adamopoulos             LISTBOX_SetSelection( descr, index,
2161*0707475fSJustin Miller                                   !is_item_selected(descr, index),
2162b3fb8555SGiannis Adamopoulos                                   (descr->style & LBS_NOTIFY) != 0);
2163b3fb8555SGiannis Adamopoulos         }
2164b3fb8555SGiannis Adamopoulos         else
2165b3fb8555SGiannis Adamopoulos         {
2166b3fb8555SGiannis Adamopoulos             LISTBOX_MoveCaret( descr, index, FALSE );
2167b3fb8555SGiannis Adamopoulos 
2168b3fb8555SGiannis Adamopoulos             if (descr->style & LBS_EXTENDEDSEL)
2169b3fb8555SGiannis Adamopoulos             {
2170b3fb8555SGiannis Adamopoulos                 LISTBOX_SetSelection( descr, index,
2171*0707475fSJustin Miller                                is_item_selected(descr, index),
2172b3fb8555SGiannis Adamopoulos                               (descr->style & LBS_NOTIFY) != 0 );
2173b3fb8555SGiannis Adamopoulos             }
2174b3fb8555SGiannis Adamopoulos             else
2175b3fb8555SGiannis Adamopoulos             {
2176b3fb8555SGiannis Adamopoulos                 LISTBOX_SetSelection( descr, index,
2177*0707475fSJustin Miller                                !is_item_selected(descr, index),
2178b3fb8555SGiannis Adamopoulos                               (descr->style & LBS_NOTIFY) != 0 );
2179b3fb8555SGiannis Adamopoulos             }
2180b3fb8555SGiannis Adamopoulos         }
2181b3fb8555SGiannis Adamopoulos     }
2182b3fb8555SGiannis Adamopoulos     else
2183b3fb8555SGiannis Adamopoulos     {
2184b3fb8555SGiannis Adamopoulos         descr->anchor_item = index;
2185b3fb8555SGiannis Adamopoulos         LISTBOX_MoveCaret( descr, index, FALSE );
2186b3fb8555SGiannis Adamopoulos         LISTBOX_SetSelection( descr, index,
2187b3fb8555SGiannis Adamopoulos                               TRUE, (descr->style & LBS_NOTIFY) != 0 );
2188b3fb8555SGiannis Adamopoulos     }
2189b3fb8555SGiannis Adamopoulos 
2190b3fb8555SGiannis Adamopoulos     if (!descr->lphc)
2191b3fb8555SGiannis Adamopoulos     {
2192b3fb8555SGiannis Adamopoulos         if (GetWindowLongW( descr->self, GWL_EXSTYLE ) & WS_EX_DRAGDETECT)
2193b3fb8555SGiannis Adamopoulos         {
2194b3fb8555SGiannis Adamopoulos             POINT pt;
2195b3fb8555SGiannis Adamopoulos 
2196b3fb8555SGiannis Adamopoulos 	    pt.x = x;
2197b3fb8555SGiannis Adamopoulos 	    pt.y = y;
2198b3fb8555SGiannis Adamopoulos 
2199b3fb8555SGiannis Adamopoulos             if (DragDetect( descr->self, pt ))
2200b3fb8555SGiannis Adamopoulos                 SendMessageW( descr->owner, WM_BEGINDRAG, 0, 0 );
2201b3fb8555SGiannis Adamopoulos         }
2202b3fb8555SGiannis Adamopoulos     }
2203b3fb8555SGiannis Adamopoulos     return 0;
2204b3fb8555SGiannis Adamopoulos }
2205b3fb8555SGiannis Adamopoulos 
2206b3fb8555SGiannis Adamopoulos 
2207b3fb8555SGiannis Adamopoulos /*************************************************************************
2208b3fb8555SGiannis Adamopoulos  * LISTBOX_HandleLButtonDownCombo [Internal]
2209b3fb8555SGiannis Adamopoulos  *
2210b3fb8555SGiannis Adamopoulos  * Process LButtonDown message for the ComboListBox
2211b3fb8555SGiannis Adamopoulos  *
2212b3fb8555SGiannis Adamopoulos  * PARAMS
2213b3fb8555SGiannis Adamopoulos  *     pWnd       [I] The windows internal structure
2214b3fb8555SGiannis Adamopoulos  *     pDescr     [I] The ListBox internal structure
2215b3fb8555SGiannis Adamopoulos  *     keys       [I] Key Flag (WM_LBUTTONDOWN doc for more info)
2216b3fb8555SGiannis Adamopoulos  *     x          [I] X Mouse Coordinate
2217b3fb8555SGiannis Adamopoulos  *     y          [I] Y Mouse Coordinate
2218b3fb8555SGiannis Adamopoulos  *
2219b3fb8555SGiannis Adamopoulos  * RETURNS
2220b3fb8555SGiannis Adamopoulos  *     0 since we are processing the WM_LBUTTONDOWN Message
2221b3fb8555SGiannis Adamopoulos  *
2222b3fb8555SGiannis Adamopoulos  * NOTES
2223b3fb8555SGiannis Adamopoulos  *  This function is only to be used when a ListBox is a ComboListBox
2224b3fb8555SGiannis Adamopoulos  */
2225b3fb8555SGiannis Adamopoulos 
LISTBOX_HandleLButtonDownCombo(LB_DESCR * descr,UINT msg,DWORD keys,INT x,INT y)2226b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_HandleLButtonDownCombo( LB_DESCR *descr, UINT msg, DWORD keys, INT x, INT y)
2227b3fb8555SGiannis Adamopoulos {
2228b3fb8555SGiannis Adamopoulos     RECT clientRect, screenRect;
2229b3fb8555SGiannis Adamopoulos     POINT mousePos;
2230b3fb8555SGiannis Adamopoulos 
2231b3fb8555SGiannis Adamopoulos     mousePos.x = x;
2232b3fb8555SGiannis Adamopoulos     mousePos.y = y;
2233b3fb8555SGiannis Adamopoulos 
2234b3fb8555SGiannis Adamopoulos     GetClientRect(descr->self, &clientRect);
2235b3fb8555SGiannis Adamopoulos 
2236b3fb8555SGiannis Adamopoulos     if(PtInRect(&clientRect, mousePos))
2237b3fb8555SGiannis Adamopoulos     {
2238b3fb8555SGiannis Adamopoulos        /* MousePos is in client, resume normal processing */
2239b3fb8555SGiannis Adamopoulos         if (msg == WM_LBUTTONDOWN)
2240b3fb8555SGiannis Adamopoulos         {
2241b3fb8555SGiannis Adamopoulos            descr->lphc->droppedIndex = descr->nb_items ? descr->selected_item : -1;
2242b3fb8555SGiannis Adamopoulos            return LISTBOX_HandleLButtonDown( descr, keys, x, y);
2243b3fb8555SGiannis Adamopoulos         }
2244b3fb8555SGiannis Adamopoulos         else if (descr->style & LBS_NOTIFY)
2245b3fb8555SGiannis Adamopoulos             SEND_NOTIFICATION( descr, LBN_DBLCLK );
2246b3fb8555SGiannis Adamopoulos     }
2247b3fb8555SGiannis Adamopoulos     else
2248b3fb8555SGiannis Adamopoulos     {
2249b3fb8555SGiannis Adamopoulos         POINT screenMousePos;
2250b3fb8555SGiannis Adamopoulos         HWND hWndOldCapture;
2251b3fb8555SGiannis Adamopoulos 
2252b3fb8555SGiannis Adamopoulos         /* Check the Non-Client Area */
2253b3fb8555SGiannis Adamopoulos         screenMousePos = mousePos;
2254b3fb8555SGiannis Adamopoulos         hWndOldCapture = GetCapture();
2255b3fb8555SGiannis Adamopoulos         ReleaseCapture();
2256b3fb8555SGiannis Adamopoulos         GetWindowRect(descr->self, &screenRect);
2257b3fb8555SGiannis Adamopoulos         ClientToScreen(descr->self, &screenMousePos);
2258b3fb8555SGiannis Adamopoulos 
2259b3fb8555SGiannis Adamopoulos         if(!PtInRect(&screenRect, screenMousePos))
2260b3fb8555SGiannis Adamopoulos         {
2261b3fb8555SGiannis Adamopoulos             LISTBOX_SetCaretIndex( descr, descr->lphc->droppedIndex, FALSE );
2262b3fb8555SGiannis Adamopoulos             LISTBOX_SetSelection( descr, descr->lphc->droppedIndex, FALSE, FALSE );
2263b3fb8555SGiannis Adamopoulos             COMBO_FlipListbox( descr->lphc, FALSE, FALSE );
2264b3fb8555SGiannis Adamopoulos         }
2265b3fb8555SGiannis Adamopoulos         else
2266b3fb8555SGiannis Adamopoulos         {
2267b3fb8555SGiannis Adamopoulos             /* Check to see the NC is a scrollbar */
2268b3fb8555SGiannis Adamopoulos             INT nHitTestType=0;
2269b3fb8555SGiannis Adamopoulos             LONG style = GetWindowLongW( descr->self, GWL_STYLE );
2270b3fb8555SGiannis Adamopoulos             /* Check Vertical scroll bar */
2271b3fb8555SGiannis Adamopoulos             if (style & WS_VSCROLL)
2272b3fb8555SGiannis Adamopoulos             {
2273b3fb8555SGiannis Adamopoulos                 clientRect.right += GetSystemMetrics(SM_CXVSCROLL);
2274b3fb8555SGiannis Adamopoulos                 if (PtInRect( &clientRect, mousePos ))
2275b3fb8555SGiannis Adamopoulos                     nHitTestType = HTVSCROLL;
2276b3fb8555SGiannis Adamopoulos             }
2277b3fb8555SGiannis Adamopoulos               /* Check horizontal scroll bar */
2278b3fb8555SGiannis Adamopoulos             if (style & WS_HSCROLL)
2279b3fb8555SGiannis Adamopoulos             {
2280b3fb8555SGiannis Adamopoulos                 clientRect.bottom += GetSystemMetrics(SM_CYHSCROLL);
2281b3fb8555SGiannis Adamopoulos                 if (PtInRect( &clientRect, mousePos ))
2282b3fb8555SGiannis Adamopoulos                     nHitTestType = HTHSCROLL;
2283b3fb8555SGiannis Adamopoulos             }
2284b3fb8555SGiannis Adamopoulos             /* Windows sends this message when a scrollbar is clicked
2285b3fb8555SGiannis Adamopoulos              */
2286b3fb8555SGiannis Adamopoulos 
2287b3fb8555SGiannis Adamopoulos             if(nHitTestType != 0)
2288b3fb8555SGiannis Adamopoulos             {
2289b3fb8555SGiannis Adamopoulos                 SendMessageW(descr->self, WM_NCLBUTTONDOWN, nHitTestType,
2290b3fb8555SGiannis Adamopoulos                              MAKELONG(screenMousePos.x, screenMousePos.y));
2291b3fb8555SGiannis Adamopoulos             }
2292b3fb8555SGiannis Adamopoulos             /* Resume the Capture after scrolling is complete
2293b3fb8555SGiannis Adamopoulos              */
2294b3fb8555SGiannis Adamopoulos             if(hWndOldCapture != 0)
2295b3fb8555SGiannis Adamopoulos                 SetCapture(hWndOldCapture);
2296b3fb8555SGiannis Adamopoulos         }
2297b3fb8555SGiannis Adamopoulos     }
2298b3fb8555SGiannis Adamopoulos     return 0;
2299b3fb8555SGiannis Adamopoulos }
2300b3fb8555SGiannis Adamopoulos 
2301b3fb8555SGiannis Adamopoulos /***********************************************************************
2302b3fb8555SGiannis Adamopoulos  *           LISTBOX_HandleLButtonUp
2303b3fb8555SGiannis Adamopoulos  */
LISTBOX_HandleLButtonUp(LB_DESCR * descr)2304b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_HandleLButtonUp( LB_DESCR *descr )
2305b3fb8555SGiannis Adamopoulos {
2306b3fb8555SGiannis Adamopoulos     if (LISTBOX_Timer != LB_TIMER_NONE)
2307b3fb8555SGiannis Adamopoulos         KillSystemTimer( descr->self, LB_TIMER_ID );
2308b3fb8555SGiannis Adamopoulos     LISTBOX_Timer = LB_TIMER_NONE;
2309b3fb8555SGiannis Adamopoulos     if (descr->captured)
2310b3fb8555SGiannis Adamopoulos     {
2311b3fb8555SGiannis Adamopoulos         descr->captured = FALSE;
2312b3fb8555SGiannis Adamopoulos         if (GetCapture() == descr->self) ReleaseCapture();
2313b3fb8555SGiannis Adamopoulos         if ((descr->style & LBS_NOTIFY) && descr->nb_items)
2314b3fb8555SGiannis Adamopoulos             SEND_NOTIFICATION( descr, LBN_SELCHANGE );
2315b3fb8555SGiannis Adamopoulos     }
2316b3fb8555SGiannis Adamopoulos     return 0;
2317b3fb8555SGiannis Adamopoulos }
2318b3fb8555SGiannis Adamopoulos 
2319b3fb8555SGiannis Adamopoulos 
2320b3fb8555SGiannis Adamopoulos /***********************************************************************
2321b3fb8555SGiannis Adamopoulos  *           LISTBOX_HandleTimer
2322b3fb8555SGiannis Adamopoulos  *
2323b3fb8555SGiannis Adamopoulos  * Handle scrolling upon a timer event.
2324b3fb8555SGiannis Adamopoulos  * Return TRUE if scrolling should continue.
2325b3fb8555SGiannis Adamopoulos  */
LISTBOX_HandleTimer(LB_DESCR * descr,INT index,TIMER_DIRECTION dir)2326b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_HandleTimer( LB_DESCR *descr, INT index, TIMER_DIRECTION dir )
2327b3fb8555SGiannis Adamopoulos {
2328b3fb8555SGiannis Adamopoulos     switch(dir)
2329b3fb8555SGiannis Adamopoulos     {
2330b3fb8555SGiannis Adamopoulos     case LB_TIMER_UP:
2331b3fb8555SGiannis Adamopoulos         if (descr->top_item) index = descr->top_item - 1;
2332b3fb8555SGiannis Adamopoulos         else index = 0;
2333b3fb8555SGiannis Adamopoulos         break;
2334b3fb8555SGiannis Adamopoulos     case LB_TIMER_LEFT:
2335b3fb8555SGiannis Adamopoulos         if (descr->top_item) index -= descr->page_size;
2336b3fb8555SGiannis Adamopoulos         break;
2337b3fb8555SGiannis Adamopoulos     case LB_TIMER_DOWN:
2338b3fb8555SGiannis Adamopoulos         index = descr->top_item + LISTBOX_GetCurrentPageSize( descr );
2339b3fb8555SGiannis Adamopoulos         if (index == descr->focus_item) index++;
2340b3fb8555SGiannis Adamopoulos         if (index >= descr->nb_items) index = descr->nb_items - 1;
2341b3fb8555SGiannis Adamopoulos         break;
2342b3fb8555SGiannis Adamopoulos     case LB_TIMER_RIGHT:
2343b3fb8555SGiannis Adamopoulos         if (index + descr->page_size < descr->nb_items)
2344b3fb8555SGiannis Adamopoulos             index += descr->page_size;
2345b3fb8555SGiannis Adamopoulos         break;
2346b3fb8555SGiannis Adamopoulos     case LB_TIMER_NONE:
2347b3fb8555SGiannis Adamopoulos         break;
2348b3fb8555SGiannis Adamopoulos     }
2349b3fb8555SGiannis Adamopoulos     if (index == descr->focus_item) return FALSE;
2350b3fb8555SGiannis Adamopoulos     LISTBOX_MoveCaret( descr, index, FALSE );
2351b3fb8555SGiannis Adamopoulos     return TRUE;
2352b3fb8555SGiannis Adamopoulos }
2353b3fb8555SGiannis Adamopoulos 
2354b3fb8555SGiannis Adamopoulos 
2355b3fb8555SGiannis Adamopoulos /***********************************************************************
2356b3fb8555SGiannis Adamopoulos  *           LISTBOX_HandleSystemTimer
2357b3fb8555SGiannis Adamopoulos  *
2358b3fb8555SGiannis Adamopoulos  * WM_SYSTIMER handler.
2359b3fb8555SGiannis Adamopoulos  */
LISTBOX_HandleSystemTimer(LB_DESCR * descr)2360b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_HandleSystemTimer( LB_DESCR *descr )
2361b3fb8555SGiannis Adamopoulos {
2362b3fb8555SGiannis Adamopoulos     if (!LISTBOX_HandleTimer( descr, descr->focus_item, LISTBOX_Timer ))
2363b3fb8555SGiannis Adamopoulos     {
2364b3fb8555SGiannis Adamopoulos         KillSystemTimer( descr->self, LB_TIMER_ID );
2365b3fb8555SGiannis Adamopoulos         LISTBOX_Timer = LB_TIMER_NONE;
2366b3fb8555SGiannis Adamopoulos     }
2367b3fb8555SGiannis Adamopoulos     return 0;
2368b3fb8555SGiannis Adamopoulos }
2369b3fb8555SGiannis Adamopoulos 
2370b3fb8555SGiannis Adamopoulos 
2371b3fb8555SGiannis Adamopoulos /***********************************************************************
2372b3fb8555SGiannis Adamopoulos  *           LISTBOX_HandleMouseMove
2373b3fb8555SGiannis Adamopoulos  *
2374b3fb8555SGiannis Adamopoulos  * WM_MOUSEMOVE handler.
2375b3fb8555SGiannis Adamopoulos  */
LISTBOX_HandleMouseMove(LB_DESCR * descr,INT x,INT y)2376b3fb8555SGiannis Adamopoulos static void LISTBOX_HandleMouseMove( LB_DESCR *descr,
2377b3fb8555SGiannis Adamopoulos                                      INT x, INT y )
2378b3fb8555SGiannis Adamopoulos {
2379b3fb8555SGiannis Adamopoulos     INT index;
2380b3fb8555SGiannis Adamopoulos     TIMER_DIRECTION dir = LB_TIMER_NONE;
2381b3fb8555SGiannis Adamopoulos 
2382b3fb8555SGiannis Adamopoulos     if (!descr->captured) return;
2383b3fb8555SGiannis Adamopoulos 
2384b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_MULTICOLUMN)
2385b3fb8555SGiannis Adamopoulos     {
2386b3fb8555SGiannis Adamopoulos         if (y < 0) y = 0;
2387b3fb8555SGiannis Adamopoulos         else if (y >= descr->item_height * descr->page_size)
2388b3fb8555SGiannis Adamopoulos             y = descr->item_height * descr->page_size - 1;
2389b3fb8555SGiannis Adamopoulos 
2390b3fb8555SGiannis Adamopoulos         if (x < 0)
2391b3fb8555SGiannis Adamopoulos         {
2392b3fb8555SGiannis Adamopoulos             dir = LB_TIMER_LEFT;
2393b3fb8555SGiannis Adamopoulos             x = 0;
2394b3fb8555SGiannis Adamopoulos         }
2395b3fb8555SGiannis Adamopoulos         else if (x >= descr->width)
2396b3fb8555SGiannis Adamopoulos         {
2397b3fb8555SGiannis Adamopoulos             dir = LB_TIMER_RIGHT;
2398b3fb8555SGiannis Adamopoulos             x = descr->width - 1;
2399b3fb8555SGiannis Adamopoulos         }
2400b3fb8555SGiannis Adamopoulos     }
2401b3fb8555SGiannis Adamopoulos     else
2402b3fb8555SGiannis Adamopoulos     {
2403b3fb8555SGiannis Adamopoulos         if (y < 0) dir = LB_TIMER_UP;  /* above */
2404b3fb8555SGiannis Adamopoulos         else if (y >= descr->height) dir = LB_TIMER_DOWN;  /* below */
2405b3fb8555SGiannis Adamopoulos     }
2406b3fb8555SGiannis Adamopoulos 
2407b3fb8555SGiannis Adamopoulos     index = LISTBOX_GetItemFromPoint( descr, x, y );
2408b3fb8555SGiannis Adamopoulos     if (index == -1) index = descr->focus_item;
2409b3fb8555SGiannis Adamopoulos     if (!LISTBOX_HandleTimer( descr, index, dir )) dir = LB_TIMER_NONE;
2410b3fb8555SGiannis Adamopoulos 
2411b3fb8555SGiannis Adamopoulos     /* Start/stop the system timer */
2412b3fb8555SGiannis Adamopoulos 
2413b3fb8555SGiannis Adamopoulos     if (dir != LB_TIMER_NONE)
2414b3fb8555SGiannis Adamopoulos         SetSystemTimer( descr->self, LB_TIMER_ID, LB_SCROLL_TIMEOUT, NULL);
2415b3fb8555SGiannis Adamopoulos     else if (LISTBOX_Timer != LB_TIMER_NONE)
2416b3fb8555SGiannis Adamopoulos         KillSystemTimer( descr->self, LB_TIMER_ID );
2417b3fb8555SGiannis Adamopoulos     LISTBOX_Timer = dir;
2418b3fb8555SGiannis Adamopoulos }
2419b3fb8555SGiannis Adamopoulos 
2420b3fb8555SGiannis Adamopoulos 
2421b3fb8555SGiannis Adamopoulos /***********************************************************************
2422b3fb8555SGiannis Adamopoulos  *           LISTBOX_HandleKeyDown
2423b3fb8555SGiannis Adamopoulos  */
LISTBOX_HandleKeyDown(LB_DESCR * descr,DWORD key)2424b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_HandleKeyDown( LB_DESCR *descr, DWORD key )
2425b3fb8555SGiannis Adamopoulos {
2426b3fb8555SGiannis Adamopoulos     INT caret = -1;
2427b3fb8555SGiannis Adamopoulos     BOOL bForceSelection = TRUE; /* select item pointed to by focus_item */
2428b3fb8555SGiannis Adamopoulos     if ((IS_MULTISELECT(descr)) || (descr->selected_item == descr->focus_item))
2429b3fb8555SGiannis Adamopoulos         bForceSelection = FALSE; /* only for single select list */
2430b3fb8555SGiannis Adamopoulos 
2431b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_WANTKEYBOARDINPUT)
2432b3fb8555SGiannis Adamopoulos     {
2433b3fb8555SGiannis Adamopoulos         caret = SendMessageW( descr->owner, WM_VKEYTOITEM,
2434b3fb8555SGiannis Adamopoulos                                 MAKEWPARAM(LOWORD(key), descr->focus_item),
2435b3fb8555SGiannis Adamopoulos                                 (LPARAM)descr->self );
2436b3fb8555SGiannis Adamopoulos         if (caret == -2) return 0;
2437b3fb8555SGiannis Adamopoulos     }
2438b3fb8555SGiannis Adamopoulos     if (caret == -1) switch(key)
2439b3fb8555SGiannis Adamopoulos     {
2440b3fb8555SGiannis Adamopoulos     case VK_LEFT:
2441b3fb8555SGiannis Adamopoulos         if (descr->style & LBS_MULTICOLUMN)
2442b3fb8555SGiannis Adamopoulos         {
2443b3fb8555SGiannis Adamopoulos             bForceSelection = FALSE;
2444b3fb8555SGiannis Adamopoulos             if (descr->focus_item >= descr->page_size)
2445b3fb8555SGiannis Adamopoulos                 caret = descr->focus_item - descr->page_size;
2446b3fb8555SGiannis Adamopoulos             break;
2447b3fb8555SGiannis Adamopoulos         }
2448b3fb8555SGiannis Adamopoulos         /* fall through */
2449b3fb8555SGiannis Adamopoulos     case VK_UP:
2450b3fb8555SGiannis Adamopoulos         caret = descr->focus_item - 1;
2451b3fb8555SGiannis Adamopoulos         if (caret < 0) caret = 0;
2452b3fb8555SGiannis Adamopoulos         break;
2453b3fb8555SGiannis Adamopoulos     case VK_RIGHT:
2454b3fb8555SGiannis Adamopoulos         if (descr->style & LBS_MULTICOLUMN)
2455b3fb8555SGiannis Adamopoulos         {
2456b3fb8555SGiannis Adamopoulos             bForceSelection = FALSE;
2457*0707475fSJustin Miller             caret = min(descr->focus_item + descr->page_size, descr->nb_items - 1);
2458b3fb8555SGiannis Adamopoulos             break;
2459b3fb8555SGiannis Adamopoulos         }
2460b3fb8555SGiannis Adamopoulos         /* fall through */
2461b3fb8555SGiannis Adamopoulos     case VK_DOWN:
2462b3fb8555SGiannis Adamopoulos         caret = descr->focus_item + 1;
2463b3fb8555SGiannis Adamopoulos         if (caret >= descr->nb_items) caret = descr->nb_items - 1;
2464b3fb8555SGiannis Adamopoulos         break;
2465b3fb8555SGiannis Adamopoulos 
2466b3fb8555SGiannis Adamopoulos     case VK_PRIOR:
2467b3fb8555SGiannis Adamopoulos         if (descr->style & LBS_MULTICOLUMN)
2468b3fb8555SGiannis Adamopoulos         {
2469b3fb8555SGiannis Adamopoulos             INT page = descr->width / descr->column_width;
2470b3fb8555SGiannis Adamopoulos             if (page < 1) page = 1;
2471b3fb8555SGiannis Adamopoulos             caret = descr->focus_item - (page * descr->page_size) + 1;
2472b3fb8555SGiannis Adamopoulos         }
2473b3fb8555SGiannis Adamopoulos         else caret = descr->focus_item-LISTBOX_GetCurrentPageSize(descr) + 1;
2474b3fb8555SGiannis Adamopoulos         if (caret < 0) caret = 0;
2475b3fb8555SGiannis Adamopoulos         break;
2476b3fb8555SGiannis Adamopoulos     case VK_NEXT:
2477b3fb8555SGiannis Adamopoulos         if (descr->style & LBS_MULTICOLUMN)
2478b3fb8555SGiannis Adamopoulos         {
2479b3fb8555SGiannis Adamopoulos             INT page = descr->width / descr->column_width;
2480b3fb8555SGiannis Adamopoulos             if (page < 1) page = 1;
2481b3fb8555SGiannis Adamopoulos             caret = descr->focus_item + (page * descr->page_size) - 1;
2482b3fb8555SGiannis Adamopoulos         }
2483b3fb8555SGiannis Adamopoulos         else caret = descr->focus_item + LISTBOX_GetCurrentPageSize(descr) - 1;
2484b3fb8555SGiannis Adamopoulos         if (caret >= descr->nb_items) caret = descr->nb_items - 1;
2485b3fb8555SGiannis Adamopoulos         break;
2486b3fb8555SGiannis Adamopoulos     case VK_HOME:
2487b3fb8555SGiannis Adamopoulos         caret = 0;
2488b3fb8555SGiannis Adamopoulos         break;
2489b3fb8555SGiannis Adamopoulos     case VK_END:
2490b3fb8555SGiannis Adamopoulos         caret = descr->nb_items - 1;
2491b3fb8555SGiannis Adamopoulos         break;
2492b3fb8555SGiannis Adamopoulos     case VK_SPACE:
2493b3fb8555SGiannis Adamopoulos         if (descr->style & LBS_EXTENDEDSEL) caret = descr->focus_item;
2494b3fb8555SGiannis Adamopoulos         else if (descr->style & LBS_MULTIPLESEL)
2495b3fb8555SGiannis Adamopoulos         {
2496b3fb8555SGiannis Adamopoulos             LISTBOX_SetSelection( descr, descr->focus_item,
2497*0707475fSJustin Miller                                   !is_item_selected(descr, descr->focus_item),
2498b3fb8555SGiannis Adamopoulos                                   (descr->style & LBS_NOTIFY) != 0 );
2499b3fb8555SGiannis Adamopoulos         }
2500b3fb8555SGiannis Adamopoulos         break;
2501b3fb8555SGiannis Adamopoulos     default:
2502b3fb8555SGiannis Adamopoulos         bForceSelection = FALSE;
2503b3fb8555SGiannis Adamopoulos     }
2504b3fb8555SGiannis Adamopoulos     if (bForceSelection) /* focused item is used instead of key */
2505b3fb8555SGiannis Adamopoulos         caret = descr->focus_item;
2506b3fb8555SGiannis Adamopoulos     if (caret >= 0)
2507b3fb8555SGiannis Adamopoulos     {
2508b3fb8555SGiannis Adamopoulos         if (((descr->style & LBS_EXTENDEDSEL) &&
2509b3fb8555SGiannis Adamopoulos             !(GetKeyState( VK_SHIFT ) & 0x8000)) ||
2510b3fb8555SGiannis Adamopoulos             !IS_MULTISELECT(descr))
2511b3fb8555SGiannis Adamopoulos             descr->anchor_item = caret;
2512b3fb8555SGiannis Adamopoulos         LISTBOX_MoveCaret( descr, caret, TRUE );
2513b3fb8555SGiannis Adamopoulos 
2514b3fb8555SGiannis Adamopoulos         if (descr->style & LBS_MULTIPLESEL)
2515b3fb8555SGiannis Adamopoulos             descr->selected_item = caret;
2516b3fb8555SGiannis Adamopoulos         else
2517b3fb8555SGiannis Adamopoulos             LISTBOX_SetSelection( descr, caret, TRUE, FALSE);
2518b3fb8555SGiannis Adamopoulos         if (descr->style & LBS_NOTIFY)
2519b3fb8555SGiannis Adamopoulos         {
2520b3fb8555SGiannis Adamopoulos             if (descr->lphc && IsWindowVisible( descr->self ))
2521b3fb8555SGiannis Adamopoulos             {
2522b3fb8555SGiannis Adamopoulos                 /* make sure that combo parent doesn't hide us */
2523b3fb8555SGiannis Adamopoulos                 descr->lphc->wState |= CBF_NOROLLUP;
2524b3fb8555SGiannis Adamopoulos             }
2525b3fb8555SGiannis Adamopoulos             if (descr->nb_items) SEND_NOTIFICATION( descr, LBN_SELCHANGE );
2526b3fb8555SGiannis Adamopoulos         }
2527b3fb8555SGiannis Adamopoulos     }
2528b3fb8555SGiannis Adamopoulos     return 0;
2529b3fb8555SGiannis Adamopoulos }
2530b3fb8555SGiannis Adamopoulos 
2531b3fb8555SGiannis Adamopoulos 
2532b3fb8555SGiannis Adamopoulos /***********************************************************************
2533b3fb8555SGiannis Adamopoulos  *           LISTBOX_HandleChar
2534b3fb8555SGiannis Adamopoulos  */
LISTBOX_HandleChar(LB_DESCR * descr,WCHAR charW)2535b3fb8555SGiannis Adamopoulos static LRESULT LISTBOX_HandleChar( LB_DESCR *descr, WCHAR charW )
2536b3fb8555SGiannis Adamopoulos {
2537b3fb8555SGiannis Adamopoulos     INT caret = -1;
2538b3fb8555SGiannis Adamopoulos     WCHAR str[2];
2539b3fb8555SGiannis Adamopoulos 
2540b3fb8555SGiannis Adamopoulos     str[0] = charW;
2541b3fb8555SGiannis Adamopoulos     str[1] = '\0';
2542b3fb8555SGiannis Adamopoulos 
2543b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_WANTKEYBOARDINPUT)
2544b3fb8555SGiannis Adamopoulos     {
2545b3fb8555SGiannis Adamopoulos         caret = SendMessageW( descr->owner, WM_CHARTOITEM,
2546b3fb8555SGiannis Adamopoulos                                 MAKEWPARAM(charW, descr->focus_item),
2547b3fb8555SGiannis Adamopoulos                                 (LPARAM)descr->self );
2548b3fb8555SGiannis Adamopoulos         if (caret == -2) return 0;
2549b3fb8555SGiannis Adamopoulos     }
2550b3fb8555SGiannis Adamopoulos     if (caret == -1)
2551b3fb8555SGiannis Adamopoulos         caret = LISTBOX_FindString( descr, descr->focus_item, str, FALSE);
2552b3fb8555SGiannis Adamopoulos     if (caret != -1)
2553b3fb8555SGiannis Adamopoulos     {
2554b3fb8555SGiannis Adamopoulos         if ((!IS_MULTISELECT(descr)) && descr->selected_item == -1)
2555b3fb8555SGiannis Adamopoulos            LISTBOX_SetSelection( descr, caret, TRUE, FALSE);
2556b3fb8555SGiannis Adamopoulos         LISTBOX_MoveCaret( descr, caret, TRUE );
2557b3fb8555SGiannis Adamopoulos         if ((descr->style & LBS_NOTIFY) && descr->nb_items)
2558b3fb8555SGiannis Adamopoulos             SEND_NOTIFICATION( descr, LBN_SELCHANGE );
2559b3fb8555SGiannis Adamopoulos     }
2560b3fb8555SGiannis Adamopoulos     return 0;
2561b3fb8555SGiannis Adamopoulos }
2562b3fb8555SGiannis Adamopoulos 
2563b3fb8555SGiannis Adamopoulos 
2564b3fb8555SGiannis Adamopoulos /***********************************************************************
2565b3fb8555SGiannis Adamopoulos  *           LISTBOX_Create
2566b3fb8555SGiannis Adamopoulos  */
LISTBOX_Create(HWND hwnd,LPHEADCOMBO lphc)2567b3fb8555SGiannis Adamopoulos static BOOL LISTBOX_Create( HWND hwnd, LPHEADCOMBO lphc )
2568b3fb8555SGiannis Adamopoulos {
2569b3fb8555SGiannis Adamopoulos     LB_DESCR *descr;
2570b3fb8555SGiannis Adamopoulos     MEASUREITEMSTRUCT mis;
2571b3fb8555SGiannis Adamopoulos     RECT rect;
2572b3fb8555SGiannis Adamopoulos 
2573b3fb8555SGiannis Adamopoulos     if (!(descr = HeapAlloc( GetProcessHeap(), 0, sizeof(*descr) )))
2574b3fb8555SGiannis Adamopoulos         return FALSE;
2575b3fb8555SGiannis Adamopoulos 
2576b3fb8555SGiannis Adamopoulos     GetClientRect( hwnd, &rect );
2577b3fb8555SGiannis Adamopoulos     descr->self          = hwnd;
2578b3fb8555SGiannis Adamopoulos     descr->owner         = GetParent( descr->self );
2579b3fb8555SGiannis Adamopoulos     descr->style         = GetWindowLongW( descr->self, GWL_STYLE );
2580b3fb8555SGiannis Adamopoulos     descr->width         = rect.right - rect.left;
2581b3fb8555SGiannis Adamopoulos     descr->height        = rect.bottom - rect.top;
2582*0707475fSJustin Miller     descr->u.items       = NULL;
2583*0707475fSJustin Miller     descr->items_size    = 0;
2584b3fb8555SGiannis Adamopoulos     descr->nb_items      = 0;
2585b3fb8555SGiannis Adamopoulos     descr->top_item      = 0;
2586b3fb8555SGiannis Adamopoulos     descr->selected_item = -1;
2587b3fb8555SGiannis Adamopoulos     descr->focus_item    = 0;
2588b3fb8555SGiannis Adamopoulos     descr->anchor_item   = -1;
2589b3fb8555SGiannis Adamopoulos     descr->item_height   = 1;
2590b3fb8555SGiannis Adamopoulos     descr->page_size     = 1;
2591b3fb8555SGiannis Adamopoulos     descr->column_width  = 150;
2592b3fb8555SGiannis Adamopoulos     descr->horz_extent   = 0;
2593b3fb8555SGiannis Adamopoulos     descr->horz_pos      = 0;
2594b3fb8555SGiannis Adamopoulos     descr->nb_tabs       = 0;
2595b3fb8555SGiannis Adamopoulos     descr->tabs          = NULL;
2596b3fb8555SGiannis Adamopoulos     descr->wheel_remain  = 0;
2597b3fb8555SGiannis Adamopoulos     descr->caret_on      = !lphc;
2598b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_NOSEL) descr->caret_on = FALSE;
2599b3fb8555SGiannis Adamopoulos     descr->in_focus 	 = FALSE;
2600b3fb8555SGiannis Adamopoulos     descr->captured      = FALSE;
2601b3fb8555SGiannis Adamopoulos     descr->font          = 0;
2602b3fb8555SGiannis Adamopoulos     descr->locale        = GetUserDefaultLCID();
2603b3fb8555SGiannis Adamopoulos     descr->lphc		 = lphc;
2604b3fb8555SGiannis Adamopoulos 
2605b3fb8555SGiannis Adamopoulos     if( lphc )
2606b3fb8555SGiannis Adamopoulos     {
2607b3fb8555SGiannis Adamopoulos         TRACE("[%p]: resetting owner %p -> %p\n", descr->self, descr->owner, lphc->self );
2608b3fb8555SGiannis Adamopoulos         descr->owner = lphc->self;
2609b3fb8555SGiannis Adamopoulos     }
2610b3fb8555SGiannis Adamopoulos 
2611b3fb8555SGiannis Adamopoulos     SetWindowLongPtrW( descr->self, 0, (LONG_PTR)descr );
2612b3fb8555SGiannis Adamopoulos 
2613b3fb8555SGiannis Adamopoulos /*    if (wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) descr->style &= ~LBS_NOTIFY;
2614b3fb8555SGiannis Adamopoulos  */
2615b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_EXTENDEDSEL) descr->style |= LBS_MULTIPLESEL;
2616b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_MULTICOLUMN) descr->style &= ~LBS_OWNERDRAWVARIABLE;
2617b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_OWNERDRAWVARIABLE) descr->style |= LBS_NOINTEGRALHEIGHT;
2618*0707475fSJustin Miller     if ((descr->style & (LBS_OWNERDRAWFIXED | LBS_HASSTRINGS | LBS_SORT)) != LBS_OWNERDRAWFIXED)
2619*0707475fSJustin Miller         descr->style &= ~LBS_NODATA;
2620b3fb8555SGiannis Adamopoulos     descr->item_height = LISTBOX_SetFont( descr, 0 );
2621b3fb8555SGiannis Adamopoulos 
2622b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_OWNERDRAWFIXED)
2623b3fb8555SGiannis Adamopoulos     {
2624*0707475fSJustin Miller         descr->style &= ~LBS_OWNERDRAWVARIABLE;
2625*0707475fSJustin Miller 
2626b3fb8555SGiannis Adamopoulos 	if( descr->lphc && (descr->lphc->dwStyle & CBS_DROPDOWN))
2627b3fb8555SGiannis Adamopoulos 	{
2628b3fb8555SGiannis Adamopoulos 	    /* WinWord gets VERY unhappy if we send WM_MEASUREITEM from here */
2629b3fb8555SGiannis Adamopoulos 	  descr->item_height = lphc->fixedOwnerDrawHeight;
2630b3fb8555SGiannis Adamopoulos 	}
2631b3fb8555SGiannis Adamopoulos 	else
2632b3fb8555SGiannis Adamopoulos 	{
2633b3fb8555SGiannis Adamopoulos             UINT id = (UINT)GetWindowLongPtrW( descr->self, GWLP_ID );
2634b3fb8555SGiannis Adamopoulos             mis.CtlType    = ODT_LISTBOX;
2635b3fb8555SGiannis Adamopoulos             mis.CtlID      = id;
2636b3fb8555SGiannis Adamopoulos             mis.itemID     = -1;
2637b3fb8555SGiannis Adamopoulos             mis.itemWidth  =  0;
2638b3fb8555SGiannis Adamopoulos             mis.itemData   =  0;
2639b3fb8555SGiannis Adamopoulos             mis.itemHeight = descr->item_height;
2640b3fb8555SGiannis Adamopoulos             SendMessageW( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
2641b3fb8555SGiannis Adamopoulos             descr->item_height = mis.itemHeight ? mis.itemHeight : 1;
2642b3fb8555SGiannis Adamopoulos 	}
2643b3fb8555SGiannis Adamopoulos     }
2644b3fb8555SGiannis Adamopoulos 
2645b3fb8555SGiannis Adamopoulos     OpenThemeData( descr->self, WC_LISTBOXW );
2646b3fb8555SGiannis Adamopoulos 
2647b3fb8555SGiannis Adamopoulos     TRACE("owner: %p, style: %08x, width: %d, height: %d\n", descr->owner, descr->style, descr->width, descr->height);
2648b3fb8555SGiannis Adamopoulos     return TRUE;
2649b3fb8555SGiannis Adamopoulos }
2650b3fb8555SGiannis Adamopoulos 
2651b3fb8555SGiannis Adamopoulos 
2652b3fb8555SGiannis Adamopoulos /***********************************************************************
2653b3fb8555SGiannis Adamopoulos  *           LISTBOX_Destroy
2654b3fb8555SGiannis Adamopoulos  */
LISTBOX_Destroy(LB_DESCR * descr)2655b3fb8555SGiannis Adamopoulos static BOOL LISTBOX_Destroy( LB_DESCR *descr )
2656b3fb8555SGiannis Adamopoulos {
2657b3fb8555SGiannis Adamopoulos     HTHEME theme = GetWindowTheme( descr->self );
2658b3fb8555SGiannis Adamopoulos     CloseThemeData( theme );
2659b3fb8555SGiannis Adamopoulos     LISTBOX_ResetContent( descr );
2660b3fb8555SGiannis Adamopoulos     SetWindowLongPtrW( descr->self, 0, 0 );
2661b3fb8555SGiannis Adamopoulos     HeapFree( GetProcessHeap(), 0, descr );
2662b3fb8555SGiannis Adamopoulos     return TRUE;
2663b3fb8555SGiannis Adamopoulos }
2664b3fb8555SGiannis Adamopoulos 
2665b3fb8555SGiannis Adamopoulos 
2666b3fb8555SGiannis Adamopoulos /***********************************************************************
2667b3fb8555SGiannis Adamopoulos  *           ListBoxWndProc_common
2668b3fb8555SGiannis Adamopoulos  */
LISTBOX_WindowProc(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)2669b3fb8555SGiannis Adamopoulos static LRESULT CALLBACK LISTBOX_WindowProc( HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam )
2670b3fb8555SGiannis Adamopoulos {
2671b3fb8555SGiannis Adamopoulos     LB_DESCR *descr = (LB_DESCR *)GetWindowLongPtrW( hwnd, 0 );
2672b3fb8555SGiannis Adamopoulos     HEADCOMBO *lphc = NULL;
2673b3fb8555SGiannis Adamopoulos     HTHEME theme;
2674b3fb8555SGiannis Adamopoulos     LRESULT ret;
2675b3fb8555SGiannis Adamopoulos 
2676b3fb8555SGiannis Adamopoulos     if (!descr)
2677b3fb8555SGiannis Adamopoulos     {
2678b3fb8555SGiannis Adamopoulos         if (!IsWindow(hwnd)) return 0;
2679b3fb8555SGiannis Adamopoulos 
2680b3fb8555SGiannis Adamopoulos         if (msg == WM_CREATE)
2681b3fb8555SGiannis Adamopoulos         {
2682b3fb8555SGiannis Adamopoulos 	    CREATESTRUCTW *lpcs = (CREATESTRUCTW *)lParam;
2683b3fb8555SGiannis Adamopoulos             if (lpcs->style & LBS_COMBOBOX) lphc = lpcs->lpCreateParams;
2684b3fb8555SGiannis Adamopoulos             if (!LISTBOX_Create( hwnd, lphc )) return -1;
2685b3fb8555SGiannis Adamopoulos             TRACE("creating hwnd %p descr %p\n", hwnd, (void *)GetWindowLongPtrW( hwnd, 0 ) );
2686b3fb8555SGiannis Adamopoulos             return 0;
2687b3fb8555SGiannis Adamopoulos         }
2688b3fb8555SGiannis Adamopoulos         /* Ignore all other messages before we get a WM_CREATE */
2689b3fb8555SGiannis Adamopoulos         return DefWindowProcW( hwnd, msg, wParam, lParam );
2690b3fb8555SGiannis Adamopoulos     }
2691b3fb8555SGiannis Adamopoulos     if (descr->style & LBS_COMBOBOX) lphc = descr->lphc;
2692b3fb8555SGiannis Adamopoulos 
2693b3fb8555SGiannis Adamopoulos     TRACE("[%p]: msg %#x wp %08lx lp %08lx\n", descr->self, msg, wParam, lParam );
2694b3fb8555SGiannis Adamopoulos 
2695b3fb8555SGiannis Adamopoulos     switch(msg)
2696b3fb8555SGiannis Adamopoulos     {
2697b3fb8555SGiannis Adamopoulos     case LB_RESETCONTENT:
2698b3fb8555SGiannis Adamopoulos         LISTBOX_ResetContent( descr );
2699b3fb8555SGiannis Adamopoulos         LISTBOX_UpdateScroll( descr );
2700b3fb8555SGiannis Adamopoulos         InvalidateRect( descr->self, NULL, TRUE );
2701b3fb8555SGiannis Adamopoulos         return 0;
2702b3fb8555SGiannis Adamopoulos 
2703b3fb8555SGiannis Adamopoulos     case LB_ADDSTRING:
2704b3fb8555SGiannis Adamopoulos     {
2705b3fb8555SGiannis Adamopoulos         const WCHAR *textW = (const WCHAR *)lParam;
2706b3fb8555SGiannis Adamopoulos         INT index = LISTBOX_FindStringPos( descr, textW, FALSE );
2707b3fb8555SGiannis Adamopoulos         return LISTBOX_InsertString( descr, index, textW );
2708b3fb8555SGiannis Adamopoulos     }
2709b3fb8555SGiannis Adamopoulos 
2710b3fb8555SGiannis Adamopoulos     case LB_INSERTSTRING:
2711b3fb8555SGiannis Adamopoulos         return LISTBOX_InsertString( descr, wParam, (const WCHAR *)lParam );
2712b3fb8555SGiannis Adamopoulos 
2713b3fb8555SGiannis Adamopoulos     case LB_ADDFILE:
2714b3fb8555SGiannis Adamopoulos     {
2715b3fb8555SGiannis Adamopoulos         const WCHAR *textW = (const WCHAR *)lParam;
2716b3fb8555SGiannis Adamopoulos         INT index = LISTBOX_FindFileStrPos( descr, textW );
2717b3fb8555SGiannis Adamopoulos         return LISTBOX_InsertString( descr, index, textW );
2718b3fb8555SGiannis Adamopoulos     }
2719b3fb8555SGiannis Adamopoulos 
2720b3fb8555SGiannis Adamopoulos     case LB_DELETESTRING:
2721b3fb8555SGiannis Adamopoulos         if (LISTBOX_RemoveItem( descr, wParam) != LB_ERR)
2722b3fb8555SGiannis Adamopoulos             return descr->nb_items;
2723b3fb8555SGiannis Adamopoulos         else
2724b3fb8555SGiannis Adamopoulos         {
2725b3fb8555SGiannis Adamopoulos             SetLastError(ERROR_INVALID_INDEX);
2726b3fb8555SGiannis Adamopoulos             return LB_ERR;
2727b3fb8555SGiannis Adamopoulos         }
2728b3fb8555SGiannis Adamopoulos 
2729b3fb8555SGiannis Adamopoulos     case LB_GETITEMDATA:
2730b3fb8555SGiannis Adamopoulos         if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
2731b3fb8555SGiannis Adamopoulos         {
2732b3fb8555SGiannis Adamopoulos             SetLastError(ERROR_INVALID_INDEX);
2733b3fb8555SGiannis Adamopoulos             return LB_ERR;
2734b3fb8555SGiannis Adamopoulos         }
2735*0707475fSJustin Miller         return get_item_data(descr, wParam);
2736b3fb8555SGiannis Adamopoulos 
2737b3fb8555SGiannis Adamopoulos     case LB_SETITEMDATA:
2738b3fb8555SGiannis Adamopoulos         if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
2739b3fb8555SGiannis Adamopoulos         {
2740b3fb8555SGiannis Adamopoulos             SetLastError(ERROR_INVALID_INDEX);
2741b3fb8555SGiannis Adamopoulos             return LB_ERR;
2742b3fb8555SGiannis Adamopoulos         }
2743*0707475fSJustin Miller         set_item_data(descr, wParam, lParam);
2744b3fb8555SGiannis Adamopoulos         /* undocumented: returns TRUE, not LB_OKAY (0) */
2745b3fb8555SGiannis Adamopoulos         return TRUE;
2746b3fb8555SGiannis Adamopoulos 
2747b3fb8555SGiannis Adamopoulos     case LB_GETCOUNT:
2748b3fb8555SGiannis Adamopoulos         return descr->nb_items;
2749b3fb8555SGiannis Adamopoulos 
2750b3fb8555SGiannis Adamopoulos     case LB_GETTEXT:
2751b3fb8555SGiannis Adamopoulos         return LISTBOX_GetText( descr, wParam, (LPWSTR)lParam, TRUE );
2752b3fb8555SGiannis Adamopoulos 
2753b3fb8555SGiannis Adamopoulos     case LB_GETTEXTLEN:
2754b3fb8555SGiannis Adamopoulos         if ((INT)wParam >= descr->nb_items || (INT)wParam < 0)
2755b3fb8555SGiannis Adamopoulos         {
2756b3fb8555SGiannis Adamopoulos             SetLastError(ERROR_INVALID_INDEX);
2757b3fb8555SGiannis Adamopoulos             return LB_ERR;
2758b3fb8555SGiannis Adamopoulos         }
2759*0707475fSJustin Miller         if (!HAS_STRINGS(descr)) return sizeof(ULONG_PTR);
2760*0707475fSJustin Miller         return lstrlenW(get_item_string(descr, wParam));
2761b3fb8555SGiannis Adamopoulos 
2762b3fb8555SGiannis Adamopoulos     case LB_GETCURSEL:
2763b3fb8555SGiannis Adamopoulos         if (descr->nb_items == 0)
2764b3fb8555SGiannis Adamopoulos             return LB_ERR;
2765b3fb8555SGiannis Adamopoulos         if (!IS_MULTISELECT(descr))
2766b3fb8555SGiannis Adamopoulos             return descr->selected_item;
2767b3fb8555SGiannis Adamopoulos         if (descr->selected_item != -1)
2768b3fb8555SGiannis Adamopoulos             return descr->selected_item;
2769b3fb8555SGiannis Adamopoulos         return descr->focus_item;
2770b3fb8555SGiannis Adamopoulos         /* otherwise, if the user tries to move the selection with the    */
2771b3fb8555SGiannis Adamopoulos         /* arrow keys, we will give the application something to choke on */
2772b3fb8555SGiannis Adamopoulos     case LB_GETTOPINDEX:
2773b3fb8555SGiannis Adamopoulos         return descr->top_item;
2774b3fb8555SGiannis Adamopoulos 
2775b3fb8555SGiannis Adamopoulos     case LB_GETITEMHEIGHT:
2776b3fb8555SGiannis Adamopoulos         return LISTBOX_GetItemHeight( descr, wParam );
2777b3fb8555SGiannis Adamopoulos 
2778b3fb8555SGiannis Adamopoulos     case LB_SETITEMHEIGHT:
2779b3fb8555SGiannis Adamopoulos         return LISTBOX_SetItemHeight( descr, wParam, lParam, TRUE );
2780b3fb8555SGiannis Adamopoulos 
2781b3fb8555SGiannis Adamopoulos     case LB_ITEMFROMPOINT:
2782b3fb8555SGiannis Adamopoulos         {
2783b3fb8555SGiannis Adamopoulos             POINT pt;
2784b3fb8555SGiannis Adamopoulos             RECT rect;
2785b3fb8555SGiannis Adamopoulos             int index;
2786b3fb8555SGiannis Adamopoulos             BOOL hit = TRUE;
2787b3fb8555SGiannis Adamopoulos 
2788b3fb8555SGiannis Adamopoulos             /* The hiword of the return value is not a client area
2789b3fb8555SGiannis Adamopoulos                hittest as suggested by MSDN, but rather a hittest on
2790b3fb8555SGiannis Adamopoulos                the returned listbox item. */
2791b3fb8555SGiannis Adamopoulos 
2792b3fb8555SGiannis Adamopoulos             if(descr->nb_items == 0)
2793b3fb8555SGiannis Adamopoulos                 return 0x1ffff;      /* win9x returns 0x10000, we copy winnt */
2794b3fb8555SGiannis Adamopoulos 
2795b3fb8555SGiannis Adamopoulos             pt.x = (short)LOWORD(lParam);
2796b3fb8555SGiannis Adamopoulos             pt.y = (short)HIWORD(lParam);
2797b3fb8555SGiannis Adamopoulos 
2798b3fb8555SGiannis Adamopoulos             SetRect(&rect, 0, 0, descr->width, descr->height);
2799b3fb8555SGiannis Adamopoulos 
2800b3fb8555SGiannis Adamopoulos             if(!PtInRect(&rect, pt))
2801b3fb8555SGiannis Adamopoulos             {
2802b3fb8555SGiannis Adamopoulos                 pt.x = min(pt.x, rect.right - 1);
2803b3fb8555SGiannis Adamopoulos                 pt.x = max(pt.x, 0);
2804b3fb8555SGiannis Adamopoulos                 pt.y = min(pt.y, rect.bottom - 1);
2805b3fb8555SGiannis Adamopoulos                 pt.y = max(pt.y, 0);
2806b3fb8555SGiannis Adamopoulos                 hit = FALSE;
2807b3fb8555SGiannis Adamopoulos             }
2808b3fb8555SGiannis Adamopoulos 
2809b3fb8555SGiannis Adamopoulos             index = LISTBOX_GetItemFromPoint(descr, pt.x, pt.y);
2810b3fb8555SGiannis Adamopoulos 
2811b3fb8555SGiannis Adamopoulos             if(index == -1)
2812b3fb8555SGiannis Adamopoulos             {
2813b3fb8555SGiannis Adamopoulos                 index = descr->nb_items - 1;
2814b3fb8555SGiannis Adamopoulos                 hit = FALSE;
2815b3fb8555SGiannis Adamopoulos             }
2816b3fb8555SGiannis Adamopoulos             return MAKELONG(index, hit ? 0 : 1);
2817b3fb8555SGiannis Adamopoulos         }
2818b3fb8555SGiannis Adamopoulos 
2819b3fb8555SGiannis Adamopoulos     case LB_SETCARETINDEX:
2820b3fb8555SGiannis Adamopoulos         if ((!IS_MULTISELECT(descr)) && (descr->selected_item != -1)) return LB_ERR;
2821b3fb8555SGiannis Adamopoulos         if (LISTBOX_SetCaretIndex( descr, wParam, !lParam ) == LB_ERR)
2822b3fb8555SGiannis Adamopoulos             return LB_ERR;
2823b3fb8555SGiannis Adamopoulos         else if (ISWIN31)
2824b3fb8555SGiannis Adamopoulos              return wParam;
2825b3fb8555SGiannis Adamopoulos         else
2826b3fb8555SGiannis Adamopoulos              return LB_OKAY;
2827b3fb8555SGiannis Adamopoulos 
2828b3fb8555SGiannis Adamopoulos     case LB_GETCARETINDEX:
2829b3fb8555SGiannis Adamopoulos         return descr->focus_item;
2830b3fb8555SGiannis Adamopoulos 
2831b3fb8555SGiannis Adamopoulos     case LB_SETTOPINDEX:
2832b3fb8555SGiannis Adamopoulos         return LISTBOX_SetTopItem( descr, wParam, TRUE );
2833b3fb8555SGiannis Adamopoulos 
2834b3fb8555SGiannis Adamopoulos     case LB_SETCOLUMNWIDTH:
2835b3fb8555SGiannis Adamopoulos         return LISTBOX_SetColumnWidth( descr, wParam );
2836b3fb8555SGiannis Adamopoulos 
2837b3fb8555SGiannis Adamopoulos     case LB_GETITEMRECT:
2838b3fb8555SGiannis Adamopoulos         return LISTBOX_GetItemRect( descr, wParam, (RECT *)lParam );
2839b3fb8555SGiannis Adamopoulos 
2840b3fb8555SGiannis Adamopoulos     case LB_FINDSTRING:
2841b3fb8555SGiannis Adamopoulos         return LISTBOX_FindString( descr, wParam, (const WCHAR *)lParam, FALSE );
2842b3fb8555SGiannis Adamopoulos 
2843b3fb8555SGiannis Adamopoulos     case LB_FINDSTRINGEXACT:
2844b3fb8555SGiannis Adamopoulos         return LISTBOX_FindString( descr, wParam, (const WCHAR *)lParam, TRUE );
2845b3fb8555SGiannis Adamopoulos 
2846b3fb8555SGiannis Adamopoulos     case LB_SELECTSTRING:
2847b3fb8555SGiannis Adamopoulos     {
2848b3fb8555SGiannis Adamopoulos         const WCHAR *textW = (const WCHAR *)lParam;
2849b3fb8555SGiannis Adamopoulos         INT index;
2850b3fb8555SGiannis Adamopoulos 
2851b3fb8555SGiannis Adamopoulos         if (HAS_STRINGS(descr))
2852b3fb8555SGiannis Adamopoulos             TRACE("LB_SELECTSTRING: %s\n", debugstr_w(textW));
2853b3fb8555SGiannis Adamopoulos 
2854b3fb8555SGiannis Adamopoulos         index = LISTBOX_FindString( descr, wParam, textW, FALSE );
2855b3fb8555SGiannis Adamopoulos         if (index != LB_ERR)
2856b3fb8555SGiannis Adamopoulos         {
2857b3fb8555SGiannis Adamopoulos             LISTBOX_MoveCaret( descr, index, TRUE );
2858b3fb8555SGiannis Adamopoulos             LISTBOX_SetSelection( descr, index, TRUE, FALSE );
2859b3fb8555SGiannis Adamopoulos         }
2860b3fb8555SGiannis Adamopoulos         return index;
2861b3fb8555SGiannis Adamopoulos     }
2862b3fb8555SGiannis Adamopoulos 
2863b3fb8555SGiannis Adamopoulos     case LB_GETSEL:
2864b3fb8555SGiannis Adamopoulos         if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
2865b3fb8555SGiannis Adamopoulos             return LB_ERR;
2866*0707475fSJustin Miller         return is_item_selected(descr, wParam);
2867b3fb8555SGiannis Adamopoulos 
2868b3fb8555SGiannis Adamopoulos     case LB_SETSEL:
2869*0707475fSJustin Miller         ret = LISTBOX_SetSelection( descr, lParam, wParam, FALSE );
2870*0707475fSJustin Miller         if (ret != LB_ERR && wParam)
2871*0707475fSJustin Miller         {
2872*0707475fSJustin Miller             descr->anchor_item = lParam;
2873*0707475fSJustin Miller             if (lParam != -1)
2874*0707475fSJustin Miller                 LISTBOX_SetCaretIndex( descr, lParam, TRUE );
2875*0707475fSJustin Miller         }
2876*0707475fSJustin Miller         return ret;
2877b3fb8555SGiannis Adamopoulos 
2878b3fb8555SGiannis Adamopoulos     case LB_SETCURSEL:
2879b3fb8555SGiannis Adamopoulos         if (IS_MULTISELECT(descr)) return LB_ERR;
2880b3fb8555SGiannis Adamopoulos         LISTBOX_SetCaretIndex( descr, wParam, TRUE );
2881b3fb8555SGiannis Adamopoulos         ret = LISTBOX_SetSelection( descr, wParam, TRUE, FALSE );
2882b3fb8555SGiannis Adamopoulos 	if (ret != LB_ERR) ret = descr->selected_item;
2883b3fb8555SGiannis Adamopoulos 	return ret;
2884b3fb8555SGiannis Adamopoulos 
2885b3fb8555SGiannis Adamopoulos     case LB_GETSELCOUNT:
2886b3fb8555SGiannis Adamopoulos         return LISTBOX_GetSelCount( descr );
2887b3fb8555SGiannis Adamopoulos 
2888b3fb8555SGiannis Adamopoulos     case LB_GETSELITEMS:
2889b3fb8555SGiannis Adamopoulos         return LISTBOX_GetSelItems( descr, wParam, (LPINT)lParam );
2890b3fb8555SGiannis Adamopoulos 
2891b3fb8555SGiannis Adamopoulos     case LB_SELITEMRANGE:
2892b3fb8555SGiannis Adamopoulos         if (LOWORD(lParam) <= HIWORD(lParam))
2893b3fb8555SGiannis Adamopoulos             return LISTBOX_SelectItemRange( descr, LOWORD(lParam),
2894b3fb8555SGiannis Adamopoulos                                             HIWORD(lParam), wParam );
2895b3fb8555SGiannis Adamopoulos         else
2896b3fb8555SGiannis Adamopoulos             return LISTBOX_SelectItemRange( descr, HIWORD(lParam),
2897b3fb8555SGiannis Adamopoulos                                             LOWORD(lParam), wParam );
2898b3fb8555SGiannis Adamopoulos 
2899b3fb8555SGiannis Adamopoulos     case LB_SELITEMRANGEEX:
2900b3fb8555SGiannis Adamopoulos         if ((INT)lParam >= (INT)wParam)
2901b3fb8555SGiannis Adamopoulos             return LISTBOX_SelectItemRange( descr, wParam, lParam, TRUE );
2902b3fb8555SGiannis Adamopoulos         else
2903b3fb8555SGiannis Adamopoulos             return LISTBOX_SelectItemRange( descr, lParam, wParam, FALSE);
2904b3fb8555SGiannis Adamopoulos 
2905b3fb8555SGiannis Adamopoulos     case LB_GETHORIZONTALEXTENT:
2906b3fb8555SGiannis Adamopoulos         return descr->horz_extent;
2907b3fb8555SGiannis Adamopoulos 
2908b3fb8555SGiannis Adamopoulos     case LB_SETHORIZONTALEXTENT:
2909b3fb8555SGiannis Adamopoulos         return LISTBOX_SetHorizontalExtent( descr, wParam );
2910b3fb8555SGiannis Adamopoulos 
2911b3fb8555SGiannis Adamopoulos     case LB_GETANCHORINDEX:
2912b3fb8555SGiannis Adamopoulos         return descr->anchor_item;
2913b3fb8555SGiannis Adamopoulos 
2914b3fb8555SGiannis Adamopoulos     case LB_SETANCHORINDEX:
2915b3fb8555SGiannis Adamopoulos         if (((INT)wParam < -1) || ((INT)wParam >= descr->nb_items))
2916b3fb8555SGiannis Adamopoulos         {
2917b3fb8555SGiannis Adamopoulos             SetLastError(ERROR_INVALID_INDEX);
2918b3fb8555SGiannis Adamopoulos             return LB_ERR;
2919b3fb8555SGiannis Adamopoulos         }
2920b3fb8555SGiannis Adamopoulos         descr->anchor_item = (INT)wParam;
2921b3fb8555SGiannis Adamopoulos         return LB_OKAY;
2922b3fb8555SGiannis Adamopoulos 
2923b3fb8555SGiannis Adamopoulos     case LB_DIR:
2924b3fb8555SGiannis Adamopoulos         return LISTBOX_Directory( descr, wParam, (const WCHAR *)lParam, msg == LB_DIR );
2925b3fb8555SGiannis Adamopoulos 
2926b3fb8555SGiannis Adamopoulos     case LB_GETLOCALE:
2927b3fb8555SGiannis Adamopoulos         return descr->locale;
2928b3fb8555SGiannis Adamopoulos 
2929b3fb8555SGiannis Adamopoulos     case LB_SETLOCALE:
2930b3fb8555SGiannis Adamopoulos     {
2931b3fb8555SGiannis Adamopoulos         LCID ret;
2932b3fb8555SGiannis Adamopoulos         if (!IsValidLocale((LCID)wParam, LCID_INSTALLED))
2933b3fb8555SGiannis Adamopoulos             return LB_ERR;
2934b3fb8555SGiannis Adamopoulos         ret = descr->locale;
2935b3fb8555SGiannis Adamopoulos         descr->locale = (LCID)wParam;
2936b3fb8555SGiannis Adamopoulos         return ret;
2937b3fb8555SGiannis Adamopoulos     }
2938b3fb8555SGiannis Adamopoulos 
2939b3fb8555SGiannis Adamopoulos     case LB_INITSTORAGE:
2940b3fb8555SGiannis Adamopoulos         return LISTBOX_InitStorage( descr, wParam );
2941b3fb8555SGiannis Adamopoulos 
2942b3fb8555SGiannis Adamopoulos     case LB_SETCOUNT:
2943b3fb8555SGiannis Adamopoulos         return LISTBOX_SetCount( descr, (INT)wParam );
2944b3fb8555SGiannis Adamopoulos 
2945b3fb8555SGiannis Adamopoulos     case LB_SETTABSTOPS:
2946b3fb8555SGiannis Adamopoulos         return LISTBOX_SetTabStops( descr, wParam, (LPINT)lParam );
2947b3fb8555SGiannis Adamopoulos 
2948b3fb8555SGiannis Adamopoulos     case LB_CARETON:
2949b3fb8555SGiannis Adamopoulos         if (descr->caret_on)
2950b3fb8555SGiannis Adamopoulos             return LB_OKAY;
2951b3fb8555SGiannis Adamopoulos         descr->caret_on = TRUE;
2952b3fb8555SGiannis Adamopoulos         if ((descr->focus_item != -1) && (descr->in_focus))
2953b3fb8555SGiannis Adamopoulos             LISTBOX_RepaintItem( descr, descr->focus_item, ODA_FOCUS );
2954b3fb8555SGiannis Adamopoulos         return LB_OKAY;
2955b3fb8555SGiannis Adamopoulos 
2956b3fb8555SGiannis Adamopoulos     case LB_CARETOFF:
2957b3fb8555SGiannis Adamopoulos         if (!descr->caret_on)
2958b3fb8555SGiannis Adamopoulos             return LB_OKAY;
2959b3fb8555SGiannis Adamopoulos         descr->caret_on = FALSE;
2960b3fb8555SGiannis Adamopoulos         if ((descr->focus_item != -1) && (descr->in_focus))
2961b3fb8555SGiannis Adamopoulos             LISTBOX_RepaintItem( descr, descr->focus_item, ODA_FOCUS );
2962b3fb8555SGiannis Adamopoulos         return LB_OKAY;
2963b3fb8555SGiannis Adamopoulos 
2964b3fb8555SGiannis Adamopoulos     case LB_GETLISTBOXINFO:
2965b3fb8555SGiannis Adamopoulos         return descr->page_size;
2966b3fb8555SGiannis Adamopoulos 
2967b3fb8555SGiannis Adamopoulos     case WM_DESTROY:
2968b3fb8555SGiannis Adamopoulos         return LISTBOX_Destroy( descr );
2969b3fb8555SGiannis Adamopoulos 
2970b3fb8555SGiannis Adamopoulos     case WM_ENABLE:
2971b3fb8555SGiannis Adamopoulos         InvalidateRect( descr->self, NULL, TRUE );
2972b3fb8555SGiannis Adamopoulos         return 0;
2973b3fb8555SGiannis Adamopoulos 
2974b3fb8555SGiannis Adamopoulos     case WM_SETREDRAW:
2975b3fb8555SGiannis Adamopoulos         LISTBOX_SetRedraw( descr, wParam != 0 );
2976b3fb8555SGiannis Adamopoulos         return 0;
2977b3fb8555SGiannis Adamopoulos 
2978b3fb8555SGiannis Adamopoulos     case WM_GETDLGCODE:
2979b3fb8555SGiannis Adamopoulos         return DLGC_WANTARROWS | DLGC_WANTCHARS;
2980b3fb8555SGiannis Adamopoulos 
2981b3fb8555SGiannis Adamopoulos     case WM_PRINTCLIENT:
2982b3fb8555SGiannis Adamopoulos     case WM_PAINT:
2983b3fb8555SGiannis Adamopoulos         {
2984b3fb8555SGiannis Adamopoulos             PAINTSTRUCT ps;
2985b3fb8555SGiannis Adamopoulos             HDC hdc = ( wParam ) ? ((HDC)wParam) :  BeginPaint( descr->self, &ps );
2986b3fb8555SGiannis Adamopoulos             ret = LISTBOX_Paint( descr, hdc );
2987b3fb8555SGiannis Adamopoulos             if( !wParam ) EndPaint( descr->self, &ps );
2988b3fb8555SGiannis Adamopoulos         }
2989b3fb8555SGiannis Adamopoulos         return ret;
2990b3fb8555SGiannis Adamopoulos 
2991b3fb8555SGiannis Adamopoulos     case WM_NCPAINT:
2992b3fb8555SGiannis Adamopoulos         LISTBOX_NCPaint( descr, (HRGN)wParam );
2993b3fb8555SGiannis Adamopoulos         break;
2994b3fb8555SGiannis Adamopoulos 
2995b3fb8555SGiannis Adamopoulos     case WM_SIZE:
2996b3fb8555SGiannis Adamopoulos         LISTBOX_UpdateSize( descr );
2997b3fb8555SGiannis Adamopoulos         return 0;
2998b3fb8555SGiannis Adamopoulos     case WM_GETFONT:
2999b3fb8555SGiannis Adamopoulos         return (LRESULT)descr->font;
3000b3fb8555SGiannis Adamopoulos     case WM_SETFONT:
3001b3fb8555SGiannis Adamopoulos         LISTBOX_SetFont( descr, (HFONT)wParam );
3002b3fb8555SGiannis Adamopoulos         if (lParam) InvalidateRect( descr->self, 0, TRUE );
3003b3fb8555SGiannis Adamopoulos         return 0;
3004b3fb8555SGiannis Adamopoulos     case WM_SETFOCUS:
3005b3fb8555SGiannis Adamopoulos         descr->in_focus = TRUE;
3006b3fb8555SGiannis Adamopoulos         descr->caret_on = TRUE;
3007b3fb8555SGiannis Adamopoulos         if (descr->focus_item != -1)
3008b3fb8555SGiannis Adamopoulos             LISTBOX_DrawFocusRect( descr, TRUE );
3009b3fb8555SGiannis Adamopoulos         SEND_NOTIFICATION( descr, LBN_SETFOCUS );
3010b3fb8555SGiannis Adamopoulos         return 0;
3011b3fb8555SGiannis Adamopoulos     case WM_KILLFOCUS:
3012b3fb8555SGiannis Adamopoulos         LISTBOX_HandleLButtonUp( descr ); /* Release capture if we have it */
3013b3fb8555SGiannis Adamopoulos         descr->in_focus = FALSE;
3014b3fb8555SGiannis Adamopoulos         descr->wheel_remain = 0;
3015b3fb8555SGiannis Adamopoulos         if ((descr->focus_item != -1) && descr->caret_on)
3016b3fb8555SGiannis Adamopoulos             LISTBOX_RepaintItem( descr, descr->focus_item, ODA_FOCUS );
3017b3fb8555SGiannis Adamopoulos         SEND_NOTIFICATION( descr, LBN_KILLFOCUS );
3018b3fb8555SGiannis Adamopoulos         return 0;
3019b3fb8555SGiannis Adamopoulos     case WM_HSCROLL:
3020b3fb8555SGiannis Adamopoulos         return LISTBOX_HandleHScroll( descr, LOWORD(wParam), HIWORD(wParam) );
3021b3fb8555SGiannis Adamopoulos     case WM_VSCROLL:
3022b3fb8555SGiannis Adamopoulos         return LISTBOX_HandleVScroll( descr, LOWORD(wParam), HIWORD(wParam) );
3023b3fb8555SGiannis Adamopoulos     case WM_MOUSEWHEEL:
3024b3fb8555SGiannis Adamopoulos         if (wParam & (MK_SHIFT | MK_CONTROL))
3025b3fb8555SGiannis Adamopoulos             return DefWindowProcW( descr->self, msg, wParam, lParam );
3026b3fb8555SGiannis Adamopoulos         return LISTBOX_HandleMouseWheel( descr, (SHORT)HIWORD(wParam) );
3027b3fb8555SGiannis Adamopoulos     case WM_LBUTTONDOWN:
3028b3fb8555SGiannis Adamopoulos 	if (lphc)
3029b3fb8555SGiannis Adamopoulos             return LISTBOX_HandleLButtonDownCombo(descr, msg, wParam,
3030b3fb8555SGiannis Adamopoulos                                                   (INT16)LOWORD(lParam),
3031b3fb8555SGiannis Adamopoulos                                                   (INT16)HIWORD(lParam) );
3032b3fb8555SGiannis Adamopoulos         return LISTBOX_HandleLButtonDown( descr, wParam,
3033b3fb8555SGiannis Adamopoulos                                           (INT16)LOWORD(lParam),
3034b3fb8555SGiannis Adamopoulos                                           (INT16)HIWORD(lParam) );
3035b3fb8555SGiannis Adamopoulos     case WM_LBUTTONDBLCLK:
3036b3fb8555SGiannis Adamopoulos 	if (lphc)
3037b3fb8555SGiannis Adamopoulos             return LISTBOX_HandleLButtonDownCombo(descr, msg, wParam,
3038b3fb8555SGiannis Adamopoulos                                                   (INT16)LOWORD(lParam),
3039b3fb8555SGiannis Adamopoulos                                                   (INT16)HIWORD(lParam) );
3040b3fb8555SGiannis Adamopoulos         if (descr->style & LBS_NOTIFY)
3041b3fb8555SGiannis Adamopoulos             SEND_NOTIFICATION( descr, LBN_DBLCLK );
3042b3fb8555SGiannis Adamopoulos         return 0;
3043b3fb8555SGiannis Adamopoulos     case WM_MOUSEMOVE:
3044b3fb8555SGiannis Adamopoulos         if ( lphc && ((lphc->dwStyle & CBS_DROPDOWNLIST) != CBS_SIMPLE) )
3045b3fb8555SGiannis Adamopoulos         {
3046b3fb8555SGiannis Adamopoulos             BOOL    captured = descr->captured;
3047b3fb8555SGiannis Adamopoulos             POINT   mousePos;
3048b3fb8555SGiannis Adamopoulos             RECT    clientRect;
3049b3fb8555SGiannis Adamopoulos 
3050b3fb8555SGiannis Adamopoulos             mousePos.x = (INT16)LOWORD(lParam);
3051b3fb8555SGiannis Adamopoulos             mousePos.y = (INT16)HIWORD(lParam);
3052b3fb8555SGiannis Adamopoulos 
3053b3fb8555SGiannis Adamopoulos             /*
3054b3fb8555SGiannis Adamopoulos              * If we are in a dropdown combobox, we simulate that
3055b3fb8555SGiannis Adamopoulos              * the mouse is captured to show the tracking of the item.
3056b3fb8555SGiannis Adamopoulos              */
3057b3fb8555SGiannis Adamopoulos             if (GetClientRect(descr->self, &clientRect) && PtInRect( &clientRect, mousePos ))
3058b3fb8555SGiannis Adamopoulos                 descr->captured = TRUE;
3059b3fb8555SGiannis Adamopoulos 
3060b3fb8555SGiannis Adamopoulos             LISTBOX_HandleMouseMove( descr, mousePos.x, mousePos.y);
3061b3fb8555SGiannis Adamopoulos 
3062b3fb8555SGiannis Adamopoulos             descr->captured = captured;
3063b3fb8555SGiannis Adamopoulos         }
3064b3fb8555SGiannis Adamopoulos         else if (GetCapture() == descr->self)
3065b3fb8555SGiannis Adamopoulos         {
3066b3fb8555SGiannis Adamopoulos             LISTBOX_HandleMouseMove( descr, (INT16)LOWORD(lParam),
3067b3fb8555SGiannis Adamopoulos                                      (INT16)HIWORD(lParam) );
3068b3fb8555SGiannis Adamopoulos         }
3069b3fb8555SGiannis Adamopoulos         return 0;
3070b3fb8555SGiannis Adamopoulos     case WM_LBUTTONUP:
3071b3fb8555SGiannis Adamopoulos 	if (lphc)
3072b3fb8555SGiannis Adamopoulos 	{
3073b3fb8555SGiannis Adamopoulos             POINT mousePos;
3074b3fb8555SGiannis Adamopoulos             RECT  clientRect;
3075b3fb8555SGiannis Adamopoulos 
3076b3fb8555SGiannis Adamopoulos             /*
3077b3fb8555SGiannis Adamopoulos              * If the mouse button "up" is not in the listbox,
3078b3fb8555SGiannis Adamopoulos              * we make sure there is no selection by re-selecting the
3079b3fb8555SGiannis Adamopoulos              * item that was selected when the listbox was made visible.
3080b3fb8555SGiannis Adamopoulos              */
3081b3fb8555SGiannis Adamopoulos             mousePos.x = (INT16)LOWORD(lParam);
3082b3fb8555SGiannis Adamopoulos             mousePos.y = (INT16)HIWORD(lParam);
3083b3fb8555SGiannis Adamopoulos 
3084b3fb8555SGiannis Adamopoulos             GetClientRect(descr->self, &clientRect);
3085b3fb8555SGiannis Adamopoulos 
3086b3fb8555SGiannis Adamopoulos             /*
3087b3fb8555SGiannis Adamopoulos              * When the user clicks outside the combobox and the focus
3088b3fb8555SGiannis Adamopoulos              * is lost, the owning combobox will send a fake buttonup with
3089b3fb8555SGiannis Adamopoulos              * 0xFFFFFFF as the mouse location, we must also revert the
3090b3fb8555SGiannis Adamopoulos              * selection to the original selection.
3091b3fb8555SGiannis Adamopoulos              */
3092b3fb8555SGiannis Adamopoulos             if ( (lParam == (LPARAM)-1) || (!PtInRect( &clientRect, mousePos )) )
3093b3fb8555SGiannis Adamopoulos                 LISTBOX_MoveCaret( descr, lphc->droppedIndex, FALSE );
3094b3fb8555SGiannis Adamopoulos         }
3095b3fb8555SGiannis Adamopoulos         return LISTBOX_HandleLButtonUp( descr );
3096b3fb8555SGiannis Adamopoulos     case WM_KEYDOWN:
3097b3fb8555SGiannis Adamopoulos         if( lphc && (lphc->dwStyle & CBS_DROPDOWNLIST) != CBS_SIMPLE )
3098b3fb8555SGiannis Adamopoulos         {
3099b3fb8555SGiannis Adamopoulos             /* for some reason Windows makes it possible to
3100b3fb8555SGiannis Adamopoulos              * show/hide ComboLBox by sending it WM_KEYDOWNs */
3101b3fb8555SGiannis Adamopoulos 
3102b3fb8555SGiannis Adamopoulos             if( (!(lphc->wState & CBF_EUI) && wParam == VK_F4) ||
3103b3fb8555SGiannis Adamopoulos                 ( (lphc->wState & CBF_EUI) && !(lphc->wState & CBF_DROPPED)
3104b3fb8555SGiannis Adamopoulos                   && (wParam == VK_DOWN || wParam == VK_UP)) )
3105b3fb8555SGiannis Adamopoulos             {
3106b3fb8555SGiannis Adamopoulos                 COMBO_FlipListbox( lphc, FALSE, FALSE );
3107b3fb8555SGiannis Adamopoulos                 return 0;
3108b3fb8555SGiannis Adamopoulos             }
3109b3fb8555SGiannis Adamopoulos         }
3110b3fb8555SGiannis Adamopoulos         return LISTBOX_HandleKeyDown( descr, wParam );
3111b3fb8555SGiannis Adamopoulos     case WM_CHAR:
3112b3fb8555SGiannis Adamopoulos         return LISTBOX_HandleChar( descr, wParam );
3113b3fb8555SGiannis Adamopoulos 
3114b3fb8555SGiannis Adamopoulos     case WM_SYSTIMER:
3115b3fb8555SGiannis Adamopoulos         return LISTBOX_HandleSystemTimer( descr );
3116b3fb8555SGiannis Adamopoulos     case WM_ERASEBKGND:
3117b3fb8555SGiannis Adamopoulos         if ((IS_OWNERDRAW(descr)) && !(descr->style & LBS_DISPLAYCHANGED))
3118b3fb8555SGiannis Adamopoulos         {
3119b3fb8555SGiannis Adamopoulos             RECT rect;
3120b3fb8555SGiannis Adamopoulos             HBRUSH hbrush = (HBRUSH)SendMessageW( descr->owner, WM_CTLCOLORLISTBOX,
3121b3fb8555SGiannis Adamopoulos                                               wParam, (LPARAM)descr->self );
3122b3fb8555SGiannis Adamopoulos 	    TRACE("hbrush = %p\n", hbrush);
3123b3fb8555SGiannis Adamopoulos 	    if(!hbrush)
3124b3fb8555SGiannis Adamopoulos 		hbrush = GetSysColorBrush(COLOR_WINDOW);
3125b3fb8555SGiannis Adamopoulos 	    if(hbrush)
3126b3fb8555SGiannis Adamopoulos 	    {
3127b3fb8555SGiannis Adamopoulos 		GetClientRect(descr->self, &rect);
3128b3fb8555SGiannis Adamopoulos 		FillRect((HDC)wParam, &rect, hbrush);
3129b3fb8555SGiannis Adamopoulos 	    }
3130b3fb8555SGiannis Adamopoulos         }
3131b3fb8555SGiannis Adamopoulos         return 1;
3132b3fb8555SGiannis Adamopoulos     case WM_DROPFILES:
3133b3fb8555SGiannis Adamopoulos         if( lphc ) return 0;
3134b3fb8555SGiannis Adamopoulos         return SendMessageW( descr->owner, msg, wParam, lParam );
3135b3fb8555SGiannis Adamopoulos 
3136b3fb8555SGiannis Adamopoulos     case WM_NCDESTROY:
3137b3fb8555SGiannis Adamopoulos         if( lphc && (lphc->dwStyle & CBS_DROPDOWNLIST) != CBS_SIMPLE )
3138b3fb8555SGiannis Adamopoulos             lphc->hWndLBox = 0;
3139b3fb8555SGiannis Adamopoulos         break;
3140b3fb8555SGiannis Adamopoulos 
3141b3fb8555SGiannis Adamopoulos     case WM_NCACTIVATE:
3142b3fb8555SGiannis Adamopoulos         if (lphc) return 0;
3143b3fb8555SGiannis Adamopoulos 	break;
3144b3fb8555SGiannis Adamopoulos 
3145b3fb8555SGiannis Adamopoulos     case WM_THEMECHANGED:
3146b3fb8555SGiannis Adamopoulos         theme = GetWindowTheme( hwnd );
3147b3fb8555SGiannis Adamopoulos         CloseThemeData( theme );
3148b3fb8555SGiannis Adamopoulos         OpenThemeData( hwnd, WC_LISTBOXW );
3149b3fb8555SGiannis Adamopoulos         break;
3150b3fb8555SGiannis Adamopoulos 
3151b3fb8555SGiannis Adamopoulos     default:
3152b3fb8555SGiannis Adamopoulos         if ((msg >= WM_USER) && (msg < 0xc000))
3153b3fb8555SGiannis Adamopoulos             WARN("[%p]: unknown msg %04x wp %08lx lp %08lx\n",
3154b3fb8555SGiannis Adamopoulos                  hwnd, msg, wParam, lParam );
3155b3fb8555SGiannis Adamopoulos     }
3156b3fb8555SGiannis Adamopoulos 
3157b3fb8555SGiannis Adamopoulos     return DefWindowProcW( hwnd, msg, wParam, lParam );
3158b3fb8555SGiannis Adamopoulos }
3159b3fb8555SGiannis Adamopoulos 
LISTBOX_Register(void)3160b3fb8555SGiannis Adamopoulos void LISTBOX_Register(void)
3161b3fb8555SGiannis Adamopoulos {
3162b3fb8555SGiannis Adamopoulos     WNDCLASSW wndClass;
3163b3fb8555SGiannis Adamopoulos 
3164b3fb8555SGiannis Adamopoulos     memset(&wndClass, 0, sizeof(wndClass));
3165b3fb8555SGiannis Adamopoulos     wndClass.style = CS_PARENTDC | CS_DBLCLKS | CS_GLOBALCLASS;
3166b3fb8555SGiannis Adamopoulos     wndClass.lpfnWndProc = LISTBOX_WindowProc;
3167b3fb8555SGiannis Adamopoulos     wndClass.cbClsExtra = 0;
3168b3fb8555SGiannis Adamopoulos     wndClass.cbWndExtra = sizeof(LB_DESCR *);
3169b3fb8555SGiannis Adamopoulos     wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
3170b3fb8555SGiannis Adamopoulos     wndClass.hbrBackground = NULL;
3171b3fb8555SGiannis Adamopoulos     wndClass.lpszClassName = WC_LISTBOXW;
3172b3fb8555SGiannis Adamopoulos     RegisterClassW(&wndClass);
3173b3fb8555SGiannis Adamopoulos }
3174b3fb8555SGiannis Adamopoulos 
COMBOLBOX_Register(void)3175b3fb8555SGiannis Adamopoulos void COMBOLBOX_Register(void)
3176b3fb8555SGiannis Adamopoulos {
3177b3fb8555SGiannis Adamopoulos     static const WCHAR combolboxW[] = {'C','o','m','b','o','L','B','o','x',0};
3178b3fb8555SGiannis Adamopoulos     WNDCLASSW wndClass;
3179b3fb8555SGiannis Adamopoulos 
3180b3fb8555SGiannis Adamopoulos     memset(&wndClass, 0, sizeof(wndClass));
3181b3fb8555SGiannis Adamopoulos     wndClass.style = CS_SAVEBITS | CS_DBLCLKS | CS_DROPSHADOW | CS_GLOBALCLASS;
3182b3fb8555SGiannis Adamopoulos     wndClass.lpfnWndProc = LISTBOX_WindowProc;
3183b3fb8555SGiannis Adamopoulos     wndClass.cbClsExtra = 0;
3184b3fb8555SGiannis Adamopoulos     wndClass.cbWndExtra = sizeof(LB_DESCR *);
3185b3fb8555SGiannis Adamopoulos     wndClass.hCursor = LoadCursorW(0, (LPWSTR)IDC_ARROW);
3186b3fb8555SGiannis Adamopoulos     wndClass.hbrBackground = NULL;
3187b3fb8555SGiannis Adamopoulos     wndClass.lpszClassName = combolboxW;
3188b3fb8555SGiannis Adamopoulos     RegisterClassW(&wndClass);
3189b3fb8555SGiannis Adamopoulos }
3190ffae49deSMark Jansen 
3191ffae49deSMark Jansen #ifdef __REACTOS__
LISTBOX_Unregister(void)3192ffae49deSMark Jansen void LISTBOX_Unregister(void)
3193ffae49deSMark Jansen {
3194ffae49deSMark Jansen     UnregisterClassW(WC_LISTBOXW, NULL);
3195ffae49deSMark Jansen }
3196ffae49deSMark Jansen 
COMBOLBOX_Unregister(void)3197ffae49deSMark Jansen void COMBOLBOX_Unregister(void)
3198ffae49deSMark Jansen {
3199ffae49deSMark Jansen     static const WCHAR combolboxW[] = {'C','o','m','b','o','L','B','o','x',0};
3200ffae49deSMark Jansen     UnregisterClassW(combolboxW, NULL);
3201ffae49deSMark Jansen }
3202ffae49deSMark Jansen #endif
3203