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