4 * Copyright 1996 Alexandre Julliard
12 #include "wine/winuser16.h"
13 #include "wine/winbase16.h"
21 #include "debugtools.h"
24 DEFAULT_DEBUG_CHANNEL(listbox
);
25 DECLARE_DEBUG_CHANNEL(combo
);
34 /* Items array granularity */
35 #define LB_ARRAY_GRANULARITY 16
37 /* Scrolling timeout in ms */
38 #define LB_SCROLL_TIMEOUT 50
40 /* Listbox system timer id */
46 LPSTR str
; /* Item text */
47 BOOL selected
; /* Is item selected? */
48 UINT height
; /* Item height (only for OWNERDRAWVARIABLE) */
49 DWORD data
; /* User data */
52 /* Listbox structure */
55 HANDLE heap
; /* Heap for this listbox */
56 HWND owner
; /* Owner window to send notifications to */
57 UINT style
; /* Window style */
58 INT width
; /* Window width */
59 INT height
; /* Window height */
60 LB_ITEMDATA
*items
; /* Array of items */
61 INT nb_items
; /* Number of items */
62 INT top_item
; /* Top visible item */
63 INT selected_item
; /* Selected item */
64 INT focus_item
; /* Item that has the focus */
65 INT anchor_item
; /* Anchor item for extended selection */
66 INT item_height
; /* Default item height */
67 INT page_size
; /* Items per listbox page */
68 INT column_width
; /* Column width for multi-column listboxes */
69 INT horz_extent
; /* Horizontal extent (0 if no hscroll) */
70 INT horz_pos
; /* Horizontal position */
71 INT nb_tabs
; /* Number of tabs in array */
72 INT
*tabs
; /* Array of tabs */
73 BOOL caret_on
; /* Is caret on? */
74 BOOL captured
; /* Is mouse captured? */
75 HFONT font
; /* Current font */
76 LCID locale
; /* Current locale for string comparisons */
77 LPHEADCOMBO lphc
; /* ComboLBox */
81 #define IS_OWNERDRAW(descr) \
82 ((descr)->style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE))
84 #define HAS_STRINGS(descr) \
85 (!IS_OWNERDRAW(descr) || ((descr)->style & LBS_HASSTRINGS))
88 #define IS_MULTISELECT(descr) \
89 ((descr)->style & LBS_MULTIPLESEL || ((descr)->style & LBS_EXTENDEDSEL))
91 #define SEND_NOTIFICATION(wnd,descr,code) \
92 (SendMessageA( (descr)->owner, WM_COMMAND, \
93 MAKEWPARAM((((descr)->lphc)?ID_CB_LISTBOX:(wnd)->wIDmenu), (code) ), (wnd)->hwndSelf ))
95 #define ISWIN31 (LOWORD(GetVersion()) == 0x0a03)
97 /* Current timer status */
107 static TIMER_DIRECTION LISTBOX_Timer
= LB_TIMER_NONE
;
110 /***********************************************************************
113 void LISTBOX_Dump( WND
*wnd
)
117 LB_DESCR
*descr
= *(LB_DESCR
**)wnd
->wExtra
;
119 TRACE( "Listbox:\n" );
120 TRACE( "hwnd=%04x descr=%08x heap=%08x items=%d top=%d\n",
121 wnd
->hwndSelf
, (UINT
)descr
, descr
->heap
, descr
->nb_items
,
123 for (i
= 0, item
= descr
->items
; i
< descr
->nb_items
; i
++, item
++)
125 TRACE( "%4d: %-40s %d %08lx %3d\n",
126 i
, item
->str
, item
->selected
, item
->data
, item
->height
);
131 /***********************************************************************
132 * LISTBOX_GetCurrentPageSize
134 * Return the current page size
136 static INT
LISTBOX_GetCurrentPageSize( WND
*wnd
, LB_DESCR
*descr
)
139 if (!(descr
->style
& LBS_OWNERDRAWVARIABLE
)) return descr
->page_size
;
140 for (i
= descr
->top_item
, height
= 0; i
< descr
->nb_items
; i
++)
142 if ((height
+= descr
->items
[i
].height
) > descr
->height
) break;
144 if (i
== descr
->top_item
) return 1;
145 else return i
- descr
->top_item
;
149 /***********************************************************************
150 * LISTBOX_GetMaxTopIndex
152 * Return the maximum possible index for the top of the listbox.
154 static INT
LISTBOX_GetMaxTopIndex( WND
*wnd
, LB_DESCR
*descr
)
158 if (descr
->style
& LBS_OWNERDRAWVARIABLE
)
160 page
= descr
->height
;
161 for (max
= descr
->nb_items
- 1; max
>= 0; max
--)
162 if ((page
-= descr
->items
[max
].height
) < 0) break;
163 if (max
< descr
->nb_items
- 1) max
++;
165 else if (descr
->style
& LBS_MULTICOLUMN
)
167 if ((page
= descr
->width
/ descr
->column_width
) < 1) page
= 1;
168 max
= (descr
->nb_items
+ descr
->page_size
- 1) / descr
->page_size
;
169 max
= (max
- page
) * descr
->page_size
;
173 max
= descr
->nb_items
- descr
->page_size
;
175 if (max
< 0) max
= 0;
180 /***********************************************************************
181 * LISTBOX_UpdateScroll
183 * Update the scrollbars. Should be called whenever the content
184 * of the listbox changes.
186 static void LISTBOX_UpdateScroll( WND
*wnd
, LB_DESCR
*descr
)
190 if (!(descr
->style
& WS_VSCROLL
)) return;
191 /* It is important that we check descr->style, and not wnd->dwStyle,
192 for WS_VSCROLL, as the former is exactly the one passed in
193 argument to CreateWindow.
194 In Windows (and from now on in Wine :) a listbox created
195 with such a style (no WS_SCROLL) does not update
196 the scrollbar with listbox-related data, thus letting
197 the programmer use it for his/her own purposes. */
199 if (descr
->style
& LBS_NOREDRAW
) return;
200 info
.cbSize
= sizeof(info
);
202 if (descr
->style
& LBS_MULTICOLUMN
)
205 info
.nMax
= (descr
->nb_items
- 1) / descr
->page_size
;
206 info
.nPos
= descr
->top_item
/ descr
->page_size
;
207 info
.nPage
= descr
->width
/ descr
->column_width
;
208 if (info
.nPage
< 1) info
.nPage
= 1;
209 info
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
210 if (descr
->style
& LBS_DISABLENOSCROLL
)
211 info
.fMask
|= SIF_DISABLENOSCROLL
;
212 SetScrollInfo( wnd
->hwndSelf
, SB_HORZ
, &info
, TRUE
);
214 info
.fMask
= SIF_RANGE
;
215 SetScrollInfo( wnd
->hwndSelf
, SB_VERT
, &info
, TRUE
);
220 info
.nMax
= descr
->nb_items
- 1;
221 info
.nPos
= descr
->top_item
;
222 info
.nPage
= LISTBOX_GetCurrentPageSize( wnd
, descr
);
223 info
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
224 if (descr
->style
& LBS_DISABLENOSCROLL
)
225 info
.fMask
|= SIF_DISABLENOSCROLL
;
226 SetScrollInfo( wnd
->hwndSelf
, SB_VERT
, &info
, TRUE
);
228 if (descr
->horz_extent
)
231 info
.nMax
= descr
->horz_extent
- 1;
232 info
.nPos
= descr
->horz_pos
;
233 info
.nPage
= descr
->width
;
234 info
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
235 if (descr
->style
& LBS_DISABLENOSCROLL
)
236 info
.fMask
|= SIF_DISABLENOSCROLL
;
237 SetScrollInfo( wnd
->hwndSelf
, SB_HORZ
, &info
, TRUE
);
243 /***********************************************************************
246 * Set the top item of the listbox, scrolling up or down if necessary.
248 static LRESULT
LISTBOX_SetTopItem( WND
*wnd
, LB_DESCR
*descr
, INT index
,
251 INT max
= LISTBOX_GetMaxTopIndex( wnd
, descr
);
252 if (index
> max
) index
= max
;
253 if (index
< 0) index
= 0;
254 if (descr
->style
& LBS_MULTICOLUMN
) index
-= index
% descr
->page_size
;
255 if (descr
->top_item
== index
) return LB_OKAY
;
256 if (descr
->style
& LBS_MULTICOLUMN
)
258 INT diff
= (descr
->top_item
- index
) / descr
->page_size
* descr
->column_width
;
259 if (scroll
&& (abs(diff
) < descr
->width
))
260 ScrollWindowEx( wnd
->hwndSelf
, diff
, 0, NULL
, NULL
, 0, NULL
,
261 SW_INVALIDATE
| SW_ERASE
| SW_SCROLLCHILDREN
);
269 if (descr
->style
& LBS_OWNERDRAWVARIABLE
)
273 if (index
> descr
->top_item
)
275 for (i
= index
- 1; i
>= descr
->top_item
; i
--)
276 diff
-= descr
->items
[i
].height
;
280 for (i
= index
; i
< descr
->top_item
; i
++)
281 diff
+= descr
->items
[i
].height
;
285 diff
= (descr
->top_item
- index
) * descr
->item_height
;
287 if (abs(diff
) < descr
->height
)
288 ScrollWindowEx( wnd
->hwndSelf
, 0, diff
, NULL
, NULL
, 0, NULL
,
289 SW_INVALIDATE
| SW_ERASE
| SW_SCROLLCHILDREN
);
293 if (!scroll
) InvalidateRect( wnd
->hwndSelf
, NULL
, TRUE
);
294 descr
->top_item
= index
;
295 LISTBOX_UpdateScroll( wnd
, descr
);
300 /***********************************************************************
303 * Update the page size. Should be called when the size of
304 * the client area or the item height changes.
306 static void LISTBOX_UpdatePage( WND
*wnd
, LB_DESCR
*descr
)
310 if ((descr
->item_height
== 0) || (page_size
= descr
->height
/ descr
->item_height
) < 1)
312 if (page_size
== descr
->page_size
) return;
313 descr
->page_size
= page_size
;
314 if (descr
->style
& LBS_MULTICOLUMN
)
315 InvalidateRect( wnd
->hwndSelf
, NULL
, TRUE
);
316 LISTBOX_SetTopItem( wnd
, descr
, descr
->top_item
, FALSE
);
320 /***********************************************************************
323 * Update the size of the listbox. Should be called when the size of
324 * the client area changes.
326 static void LISTBOX_UpdateSize( WND
*wnd
, LB_DESCR
*descr
)
330 GetClientRect( wnd
->hwndSelf
, &rect
);
331 descr
->width
= rect
.right
- rect
.left
;
332 descr
->height
= rect
.bottom
- rect
.top
;
333 if (!(descr
->style
& LBS_NOINTEGRALHEIGHT
) && !IS_OWNERDRAW(descr
))
335 if ((descr
->height
> descr
->item_height
) &&
336 (descr
->height
% descr
->item_height
))
338 TRACE("[%04x]: changing height %d -> %d\n",
339 wnd
->hwndSelf
, descr
->height
,
340 descr
->height
- descr
->height
%descr
->item_height
);
341 SetWindowPos( wnd
->hwndSelf
, 0, 0, 0,
342 wnd
->rectWindow
.right
- wnd
->rectWindow
.left
,
343 wnd
->rectWindow
.bottom
- wnd
->rectWindow
.top
-
344 (descr
->height
% descr
->item_height
),
345 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOMOVE
);
349 TRACE("[%04x]: new size = %d,%d\n",
350 wnd
->hwndSelf
, descr
->width
, descr
->height
);
351 LISTBOX_UpdatePage( wnd
, descr
);
352 LISTBOX_UpdateScroll( wnd
, descr
);
356 /***********************************************************************
357 * LISTBOX_GetItemRect
359 * Get the rectangle enclosing an item, in listbox client coordinates.
360 * Return 1 if the rectangle is (partially) visible, 0 if hidden, -1 on error.
362 static LRESULT
LISTBOX_GetItemRect( WND
*wnd
, LB_DESCR
*descr
, INT index
,
365 /* Index <= 0 is legal even on empty listboxes */
366 if (index
&& (index
>= descr
->nb_items
)) return -1;
367 SetRect( rect
, 0, 0, descr
->width
, descr
->height
);
368 if (descr
->style
& LBS_MULTICOLUMN
)
370 INT col
= (index
/ descr
->page_size
) -
371 (descr
->top_item
/ descr
->page_size
);
372 rect
->left
+= col
* descr
->column_width
;
373 rect
->right
= rect
->left
+ descr
->column_width
;
374 rect
->top
+= (index
% descr
->page_size
) * descr
->item_height
;
375 rect
->bottom
= rect
->top
+ descr
->item_height
;
377 else if (descr
->style
& LBS_OWNERDRAWVARIABLE
)
380 rect
->right
+= descr
->horz_pos
;
381 if ((index
>= 0) && (index
< descr
->nb_items
))
383 if (index
< descr
->top_item
)
385 for (i
= descr
->top_item
-1; i
>= index
; i
--)
386 rect
->top
-= descr
->items
[i
].height
;
390 for (i
= descr
->top_item
; i
< index
; i
++)
391 rect
->top
+= descr
->items
[i
].height
;
393 rect
->bottom
= rect
->top
+ descr
->items
[index
].height
;
399 rect
->top
+= (index
- descr
->top_item
) * descr
->item_height
;
400 rect
->bottom
= rect
->top
+ descr
->item_height
;
401 rect
->right
+= descr
->horz_pos
;
404 return ((rect
->left
< descr
->width
) && (rect
->right
> 0) &&
405 (rect
->top
< descr
->height
) && (rect
->bottom
> 0));
409 /***********************************************************************
410 * LISTBOX_GetItemFromPoint
412 * Return the item nearest from point (x,y) (in client coordinates).
414 static INT
LISTBOX_GetItemFromPoint( WND
*wnd
, LB_DESCR
*descr
,
417 INT index
= descr
->top_item
;
419 if (!descr
->nb_items
) return -1; /* No items */
420 if (descr
->style
& LBS_OWNERDRAWVARIABLE
)
425 while (index
< descr
->nb_items
)
427 if ((pos
+= descr
->items
[index
].height
) > y
) break;
436 if ((pos
-= descr
->items
[index
].height
) <= y
) break;
440 else if (descr
->style
& LBS_MULTICOLUMN
)
442 if (y
>= descr
->item_height
* descr
->page_size
) return -1;
443 if (y
>= 0) index
+= y
/ descr
->item_height
;
444 if (x
>= 0) index
+= (x
/ descr
->column_width
) * descr
->page_size
;
445 else index
-= (((x
+ 1) / descr
->column_width
) - 1) * descr
->page_size
;
449 index
+= (y
/ descr
->item_height
);
451 if (index
< 0) return 0;
452 if (index
>= descr
->nb_items
) return -1;
457 /***********************************************************************
462 static void LISTBOX_PaintItem( WND
*wnd
, LB_DESCR
*descr
, HDC hdc
,
463 const RECT
*rect
, INT index
, UINT action
)
465 LB_ITEMDATA
*item
= NULL
;
466 if (index
< descr
->nb_items
) item
= &descr
->items
[index
];
468 if (IS_OWNERDRAW(descr
))
471 UINT id
= (descr
->lphc
) ? ID_CB_LISTBOX
: wnd
->wIDmenu
;
475 if (action
== ODA_FOCUS
)
476 DrawFocusRect( hdc
, rect
);
478 FIXME("called with an out of bounds index %d(%d) in owner draw, Not good.\n",index
,descr
->nb_items
);
481 dis
.CtlType
= ODT_LISTBOX
;
483 dis
.hwndItem
= wnd
->hwndSelf
;
484 dis
.itemAction
= action
;
488 if (item
&& item
->selected
) dis
.itemState
|= ODS_SELECTED
;
489 if ((descr
->focus_item
== index
) &&
491 (GetFocus() == wnd
->hwndSelf
)) dis
.itemState
|= ODS_FOCUS
;
492 if (wnd
->dwStyle
& WS_DISABLED
) dis
.itemState
|= ODS_DISABLED
;
493 dis
.itemData
= item
? item
->data
: 0;
495 TRACE("[%04x]: drawitem %d (%s) action=%02x "
496 "state=%02x rect=%d,%d-%d,%d\n",
497 wnd
->hwndSelf
, index
, item
? item
->str
: "", action
,
498 dis
.itemState
, rect
->left
, rect
->top
,
499 rect
->right
, rect
->bottom
);
500 SendMessageA(descr
->owner
, WM_DRAWITEM
, id
, (LPARAM
)&dis
);
504 COLORREF oldText
= 0, oldBk
= 0;
506 if (action
== ODA_FOCUS
)
508 DrawFocusRect( hdc
, rect
);
511 if (item
&& item
->selected
)
513 oldBk
= SetBkColor( hdc
, GetSysColor( COLOR_HIGHLIGHT
) );
514 oldText
= SetTextColor( hdc
, GetSysColor(COLOR_HIGHLIGHTTEXT
));
517 TRACE("[%04x]: painting %d (%s) action=%02x "
518 "rect=%d,%d-%d,%d\n",
519 wnd
->hwndSelf
, index
, item
? item
->str
: "", action
,
520 rect
->left
, rect
->top
, rect
->right
, rect
->bottom
);
522 ExtTextOutA( hdc
, rect
->left
+ 1, rect
->top
,
523 ETO_OPAQUE
| ETO_CLIPPED
, rect
, NULL
, 0, NULL
);
524 else if (!(descr
->style
& LBS_USETABSTOPS
))
525 ExtTextOutA( hdc
, rect
->left
+ 1, rect
->top
,
526 ETO_OPAQUE
| ETO_CLIPPED
, rect
, item
->str
,
527 strlen(item
->str
), NULL
);
530 /* Output empty string to paint background in the full width. */
531 ExtTextOutA( hdc
, rect
->left
+ 1, rect
->top
,
532 ETO_OPAQUE
| ETO_CLIPPED
, rect
, NULL
, 0, NULL
);
533 TabbedTextOutA( hdc
, rect
->left
+ 1 , rect
->top
,
534 item
->str
, strlen(item
->str
),
535 descr
->nb_tabs
, descr
->tabs
, 0);
537 if (item
&& item
->selected
)
539 SetBkColor( hdc
, oldBk
);
540 SetTextColor( hdc
, oldText
);
542 if ((descr
->focus_item
== index
) &&
544 (GetFocus() == wnd
->hwndSelf
)) DrawFocusRect( hdc
, rect
);
549 /***********************************************************************
552 * Change the redraw flag.
554 static void LISTBOX_SetRedraw( WND
*wnd
, LB_DESCR
*descr
, BOOL on
)
558 if (!(descr
->style
& LBS_NOREDRAW
)) return;
559 descr
->style
&= ~LBS_NOREDRAW
;
560 LISTBOX_UpdateScroll( wnd
, descr
);
562 else descr
->style
|= LBS_NOREDRAW
;
566 /***********************************************************************
567 * LISTBOX_RepaintItem
569 * Repaint a single item synchronously.
571 static void LISTBOX_RepaintItem( WND
*wnd
, LB_DESCR
*descr
, INT index
,
577 HBRUSH hbrush
, oldBrush
= 0;
579 /* Do not repaint the item if the item is not visible */
580 if ((descr
->style
& LBS_NOREDRAW
) || !IsWindowVisible(wnd
->hwndSelf
)) return;
582 if (LISTBOX_GetItemRect( wnd
, descr
, index
, &rect
) != 1) return;
583 if (!(hdc
= GetDCEx( wnd
->hwndSelf
, 0, DCX_CACHE
))) return;
584 if (descr
->font
) oldFont
= SelectObject( hdc
, descr
->font
);
585 hbrush
= SendMessageA( descr
->owner
, WM_CTLCOLORLISTBOX
,
586 hdc
, (LPARAM
)wnd
->hwndSelf
);
587 if (hbrush
) oldBrush
= SelectObject( hdc
, hbrush
);
588 if (wnd
->dwStyle
& WS_DISABLED
)
589 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
590 SetWindowOrgEx( hdc
, descr
->horz_pos
, 0, NULL
);
591 LISTBOX_PaintItem( wnd
, descr
, hdc
, &rect
, index
, action
);
592 if (oldFont
) SelectObject( hdc
, oldFont
);
593 if (oldBrush
) SelectObject( hdc
, oldBrush
);
594 ReleaseDC( wnd
->hwndSelf
, hdc
);
598 /***********************************************************************
599 * LISTBOX_InitStorage
601 static LRESULT
LISTBOX_InitStorage( WND
*wnd
, LB_DESCR
*descr
, INT nb_items
,
606 nb_items
+= LB_ARRAY_GRANULARITY
- 1;
607 nb_items
-= (nb_items
% LB_ARRAY_GRANULARITY
);
609 nb_items
+= HeapSize( descr
->heap
, 0, descr
->items
) / sizeof(*item
);
610 if (!(item
= HeapReAlloc( descr
->heap
, 0, descr
->items
,
611 nb_items
* sizeof(LB_ITEMDATA
) )))
613 SEND_NOTIFICATION( wnd
, descr
, LBN_ERRSPACE
);
621 /***********************************************************************
622 * LISTBOX_SetTabStops
624 static BOOL
LISTBOX_SetTabStops( WND
*wnd
, LB_DESCR
*descr
, INT count
,
625 LPINT tabs
, BOOL short_ints
)
627 if (!(descr
->style
& LBS_USETABSTOPS
)) return TRUE
;
628 if (descr
->tabs
) HeapFree( descr
->heap
, 0, descr
->tabs
);
629 if (!(descr
->nb_tabs
= count
))
634 /* FIXME: count = 1 */
635 if (!(descr
->tabs
= (INT
*)HeapAlloc( descr
->heap
, 0,
636 descr
->nb_tabs
* sizeof(INT
) )))
641 LPINT16 p
= (LPINT16
)tabs
;
643 TRACE("[%04x]: settabstops ", wnd
->hwndSelf
);
644 for (i
= 0; i
< descr
->nb_tabs
; i
++) {
645 descr
->tabs
[i
] = *p
++<<1; /* FIXME */
646 if (TRACE_ON(listbox
)) DPRINTF("%hd ", descr
->tabs
[i
]);
648 if (TRACE_ON(listbox
)) DPRINTF("\n");
650 else memcpy( descr
->tabs
, tabs
, descr
->nb_tabs
* sizeof(INT
) );
651 /* FIXME: repaint the window? */
656 /***********************************************************************
659 static LRESULT
LISTBOX_GetText( WND
*wnd
, LB_DESCR
*descr
, INT index
,
662 if ((index
< 0) || (index
>= descr
->nb_items
)) return LB_ERR
;
663 if (HAS_STRINGS(descr
))
666 return strlen(descr
->items
[index
].str
);
667 lstrcpyA( buffer
, descr
->items
[index
].str
);
668 return strlen(buffer
);
671 *((LPDWORD
)buffer
)=*(LPDWORD
)(&descr
->items
[index
].data
);
672 return sizeof(DWORD
);
677 /***********************************************************************
678 * LISTBOX_FindStringPos
680 * Find the nearest string located before a given string in sort order.
681 * If 'exact' is TRUE, return an error if we don't get an exact match.
683 static INT
LISTBOX_FindStringPos( WND
*wnd
, LB_DESCR
*descr
, LPCSTR str
,
686 INT index
, min
, max
, res
= -1;
688 if (!(descr
->style
& LBS_SORT
)) return -1; /* Add it at the end */
690 max
= descr
->nb_items
;
693 index
= (min
+ max
) / 2;
694 if (HAS_STRINGS(descr
))
695 res
= lstrcmpiA( descr
->items
[index
].str
, str
);
698 COMPAREITEMSTRUCT cis
;
699 UINT id
= (descr
->lphc
) ? ID_CB_LISTBOX
: wnd
->wIDmenu
;
701 cis
.CtlType
= ODT_LISTBOX
;
703 cis
.hwndItem
= wnd
->hwndSelf
;
705 cis
.itemData1
= descr
->items
[index
].data
;
707 cis
.itemData2
= (DWORD
)str
;
708 cis
.dwLocaleId
= descr
->locale
;
709 res
= SendMessageA( descr
->owner
, WM_COMPAREITEM
,
712 if (!res
) return index
;
713 if (res
> 0) max
= index
;
714 else min
= index
+ 1;
716 return exact
? -1 : max
;
720 /***********************************************************************
721 * LISTBOX_FindFileStrPos
723 * Find the nearest string located before a given string in directory
724 * sort order (i.e. first files, then directories, then drives).
726 static INT
LISTBOX_FindFileStrPos( WND
*wnd
, LB_DESCR
*descr
, LPCSTR str
)
728 INT min
, max
, res
= -1;
730 if (!HAS_STRINGS(descr
))
731 return LISTBOX_FindStringPos( wnd
, descr
, str
, FALSE
);
733 max
= descr
->nb_items
;
736 INT index
= (min
+ max
) / 2;
737 const char *p
= descr
->items
[index
].str
;
738 if (*p
== '[') /* drive or directory */
740 if (*str
!= '[') res
= -1;
741 else if (p
[1] == '-') /* drive */
743 if (str
[1] == '-') res
= str
[2] - p
[2];
748 if (str
[1] == '-') res
= 1;
749 else res
= lstrcmpiA( str
, p
);
754 if (*str
== '[') res
= 1;
755 else res
= lstrcmpiA( str
, p
);
757 if (!res
) return index
;
758 if (res
< 0) max
= index
;
759 else min
= index
+ 1;
765 /***********************************************************************
768 * Find the item beginning with a given string.
770 static INT
LISTBOX_FindString( WND
*wnd
, LB_DESCR
*descr
, INT start
,
771 LPCSTR str
, BOOL exact
)
776 if (start
>= descr
->nb_items
) start
= -1;
777 item
= descr
->items
+ start
+ 1;
778 if (HAS_STRINGS(descr
))
780 if (!str
|| ! str
[0] ) return LB_ERR
;
783 for (i
= start
+ 1; i
< descr
->nb_items
; i
++, item
++)
784 if (!lstrcmpiA( str
, item
->str
)) return i
;
785 for (i
= 0, item
= descr
->items
; i
<= start
; i
++, item
++)
786 if (!lstrcmpiA( str
, item
->str
)) return i
;
790 /* Special case for drives and directories: ignore prefix */
791 #define CHECK_DRIVE(item) \
792 if ((item)->str[0] == '[') \
794 if (!lstrncmpiA( str, (item)->str+1, len )) return i; \
795 if (((item)->str[1] == '-') && !lstrncmpiA(str,(item)->str+2,len)) \
799 INT len
= strlen(str
);
800 for (i
= start
+ 1; i
< descr
->nb_items
; i
++, item
++)
802 if (!lstrncmpiA( str
, item
->str
, len
)) return i
;
805 for (i
= 0, item
= descr
->items
; i
<= start
; i
++, item
++)
807 if (!lstrncmpiA( str
, item
->str
, len
)) return i
;
815 if (exact
&& (descr
->style
& LBS_SORT
))
816 /* If sorted, use a WM_COMPAREITEM binary search */
817 return LISTBOX_FindStringPos( wnd
, descr
, str
, TRUE
);
819 /* Otherwise use a linear search */
820 for (i
= start
+ 1; i
< descr
->nb_items
; i
++, item
++)
821 if (item
->data
== (DWORD
)str
) return i
;
822 for (i
= 0, item
= descr
->items
; i
<= start
; i
++, item
++)
823 if (item
->data
== (DWORD
)str
) return i
;
829 /***********************************************************************
830 * LISTBOX_GetSelCount
832 static LRESULT
LISTBOX_GetSelCount( WND
*wnd
, LB_DESCR
*descr
)
835 LB_ITEMDATA
*item
= descr
->items
;
837 if (!(descr
->style
& LBS_MULTIPLESEL
)) return LB_ERR
;
838 for (i
= count
= 0; i
< descr
->nb_items
; i
++, item
++)
839 if (item
->selected
) count
++;
844 /***********************************************************************
845 * LISTBOX_GetSelItems16
847 static LRESULT
LISTBOX_GetSelItems16( WND
*wnd
, LB_DESCR
*descr
, INT16 max
,
851 LB_ITEMDATA
*item
= descr
->items
;
853 if (!(descr
->style
& LBS_MULTIPLESEL
)) return LB_ERR
;
854 for (i
= count
= 0; (i
< descr
->nb_items
) && (count
< max
); i
++, item
++)
855 if (item
->selected
) array
[count
++] = (INT16
)i
;
860 /***********************************************************************
861 * LISTBOX_GetSelItems32
863 static LRESULT
LISTBOX_GetSelItems( WND
*wnd
, LB_DESCR
*descr
, INT max
,
867 LB_ITEMDATA
*item
= descr
->items
;
869 if (!(descr
->style
& LBS_MULTIPLESEL
)) return LB_ERR
;
870 for (i
= count
= 0; (i
< descr
->nb_items
) && (count
< max
); i
++, item
++)
871 if (item
->selected
) array
[count
++] = i
;
876 /***********************************************************************
879 static LRESULT
LISTBOX_Paint( WND
*wnd
, LB_DESCR
*descr
, HDC hdc
)
881 INT i
, col_pos
= descr
->page_size
- 1;
884 HBRUSH hbrush
, oldBrush
= 0;
886 SetRect( &rect
, 0, 0, descr
->width
, descr
->height
);
887 if (descr
->style
& LBS_NOREDRAW
) return 0;
888 if (descr
->style
& LBS_MULTICOLUMN
)
889 rect
.right
= rect
.left
+ descr
->column_width
;
890 else if (descr
->horz_pos
)
892 SetWindowOrgEx( hdc
, descr
->horz_pos
, 0, NULL
);
893 rect
.right
+= descr
->horz_pos
;
896 if (descr
->font
) oldFont
= SelectObject( hdc
, descr
->font
);
897 hbrush
= SendMessageA( descr
->owner
, WM_CTLCOLORLISTBOX
,
898 hdc
, (LPARAM
)wnd
->hwndSelf
);
899 if (hbrush
) oldBrush
= SelectObject( hdc
, hbrush
);
900 if (wnd
->dwStyle
& WS_DISABLED
)
901 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
903 if (!descr
->nb_items
&& (descr
->focus_item
!= -1) && descr
->caret_on
&&
904 (GetFocus() == wnd
->hwndSelf
))
906 /* Special case for empty listbox: paint focus rect */
907 rect
.bottom
= rect
.top
+ descr
->item_height
;
908 LISTBOX_PaintItem( wnd
, descr
, hdc
, &rect
, descr
->focus_item
,
910 rect
.top
= rect
.bottom
;
913 for (i
= descr
->top_item
; i
< descr
->nb_items
; i
++)
915 if (!(descr
->style
& LBS_OWNERDRAWVARIABLE
))
916 rect
.bottom
= rect
.top
+ descr
->item_height
;
918 rect
.bottom
= rect
.top
+ descr
->items
[i
].height
;
920 LISTBOX_PaintItem( wnd
, descr
, hdc
, &rect
, i
, ODA_DRAWENTIRE
);
921 rect
.top
= rect
.bottom
;
923 if ((descr
->style
& LBS_MULTICOLUMN
) && !col_pos
)
925 if (!IS_OWNERDRAW(descr
))
927 /* Clear the bottom of the column */
928 SetBkColor( hdc
, GetSysColor( COLOR_WINDOW
) );
929 if (rect
.top
< descr
->height
)
931 rect
.bottom
= descr
->height
;
932 ExtTextOutA( hdc
, 0, 0, ETO_OPAQUE
| ETO_CLIPPED
,
933 &rect
, NULL
, 0, NULL
);
937 /* Go to the next column */
938 rect
.left
+= descr
->column_width
;
939 rect
.right
+= descr
->column_width
;
941 col_pos
= descr
->page_size
- 1;
946 if (rect
.top
>= descr
->height
) break;
950 if (!IS_OWNERDRAW(descr
))
952 /* Clear the remainder of the client area */
953 SetBkColor( hdc
, GetSysColor( COLOR_WINDOW
) );
954 if (rect
.top
< descr
->height
)
956 rect
.bottom
= descr
->height
;
957 ExtTextOutA( hdc
, 0, 0, ETO_OPAQUE
| ETO_CLIPPED
,
958 &rect
, NULL
, 0, NULL
);
960 if (rect
.right
< descr
->width
)
962 rect
.left
= rect
.right
;
963 rect
.right
= descr
->width
;
965 rect
.bottom
= descr
->height
;
966 ExtTextOutA( hdc
, 0, 0, ETO_OPAQUE
| ETO_CLIPPED
,
967 &rect
, NULL
, 0, NULL
);
970 if (oldFont
) SelectObject( hdc
, oldFont
);
971 if (oldBrush
) SelectObject( hdc
, oldBrush
);
976 /***********************************************************************
977 * LISTBOX_InvalidateItems
979 * Invalidate all items from a given item. If the specified item is not
980 * visible, nothing happens.
982 static void LISTBOX_InvalidateItems( WND
*wnd
, LB_DESCR
*descr
, INT index
)
986 if (LISTBOX_GetItemRect( wnd
, descr
, index
, &rect
) == 1)
988 rect
.bottom
= descr
->height
;
989 InvalidateRect( wnd
->hwndSelf
, &rect
, TRUE
);
990 if (descr
->style
& LBS_MULTICOLUMN
)
992 /* Repaint the other columns */
993 rect
.left
= rect
.right
;
994 rect
.right
= descr
->width
;
996 InvalidateRect( wnd
->hwndSelf
, &rect
, TRUE
);
1002 /***********************************************************************
1003 * LISTBOX_GetItemHeight
1005 static LRESULT
LISTBOX_GetItemHeight( WND
*wnd
, LB_DESCR
*descr
, INT index
)
1007 if (descr
->style
& LBS_OWNERDRAWVARIABLE
)
1009 if ((index
< 0) || (index
>= descr
->nb_items
)) return LB_ERR
;
1010 return descr
->items
[index
].height
;
1012 else return descr
->item_height
;
1016 /***********************************************************************
1017 * LISTBOX_SetItemHeight
1019 static LRESULT
LISTBOX_SetItemHeight( WND
*wnd
, LB_DESCR
*descr
, INT index
,
1022 if (!height
) height
= 1;
1024 if (descr
->style
& LBS_OWNERDRAWVARIABLE
)
1026 if ((index
< 0) || (index
>= descr
->nb_items
)) return LB_ERR
;
1027 TRACE("[%04x]: item %d height = %d\n",
1028 wnd
->hwndSelf
, index
, height
);
1029 descr
->items
[index
].height
= height
;
1030 LISTBOX_UpdateScroll( wnd
, descr
);
1031 LISTBOX_InvalidateItems( wnd
, descr
, index
);
1033 else if (height
!= descr
->item_height
)
1035 TRACE("[%04x]: new height = %d\n",
1036 wnd
->hwndSelf
, height
);
1037 descr
->item_height
= height
;
1038 LISTBOX_UpdatePage( wnd
, descr
);
1039 LISTBOX_UpdateScroll( wnd
, descr
);
1040 InvalidateRect( wnd
->hwndSelf
, 0, TRUE
);
1046 /***********************************************************************
1047 * LISTBOX_SetHorizontalPos
1049 static void LISTBOX_SetHorizontalPos( WND
*wnd
, LB_DESCR
*descr
, INT pos
)
1053 if (pos
> descr
->horz_extent
- descr
->width
)
1054 pos
= descr
->horz_extent
- descr
->width
;
1055 if (pos
< 0) pos
= 0;
1056 if (!(diff
= descr
->horz_pos
- pos
)) return;
1057 TRACE("[%04x]: new horz pos = %d\n",
1058 wnd
->hwndSelf
, pos
);
1059 descr
->horz_pos
= pos
;
1060 LISTBOX_UpdateScroll( wnd
, descr
);
1061 if (abs(diff
) < descr
->width
)
1062 ScrollWindowEx( wnd
->hwndSelf
, diff
, 0, NULL
, NULL
, 0, NULL
,
1063 SW_INVALIDATE
| SW_ERASE
| SW_SCROLLCHILDREN
);
1065 InvalidateRect( wnd
->hwndSelf
, NULL
, TRUE
);
1069 /***********************************************************************
1070 * LISTBOX_SetHorizontalExtent
1072 static LRESULT
LISTBOX_SetHorizontalExtent( WND
*wnd
, LB_DESCR
*descr
,
1075 if (!descr
->horz_extent
|| (descr
->style
& LBS_MULTICOLUMN
))
1077 if (extent
<= 0) extent
= 1;
1078 if (extent
== descr
->horz_extent
) return LB_OKAY
;
1079 TRACE("[%04x]: new horz extent = %d\n",
1080 wnd
->hwndSelf
, extent
);
1081 descr
->horz_extent
= extent
;
1082 if (descr
->horz_pos
> extent
- descr
->width
)
1083 LISTBOX_SetHorizontalPos( wnd
, descr
, extent
- descr
->width
);
1085 LISTBOX_UpdateScroll( wnd
, descr
);
1090 /***********************************************************************
1091 * LISTBOX_SetColumnWidth
1093 static LRESULT
LISTBOX_SetColumnWidth( WND
*wnd
, LB_DESCR
*descr
, UINT width
)
1095 width
+= 2; /* For left and right margin */
1096 if (width
== descr
->column_width
) return LB_OKAY
;
1097 TRACE("[%04x]: new column width = %d\n",
1098 wnd
->hwndSelf
, width
);
1099 descr
->column_width
= width
;
1100 LISTBOX_UpdatePage( wnd
, descr
);
1105 /***********************************************************************
1108 * Returns the item height.
1110 static INT
LISTBOX_SetFont( WND
*wnd
, LB_DESCR
*descr
, HFONT font
)
1118 if (!(hdc
= GetDCEx( wnd
->hwndSelf
, 0, DCX_CACHE
)))
1120 ERR("unable to get DC.\n" );
1123 if (font
) oldFont
= SelectObject( hdc
, font
);
1124 GetTextMetricsA( hdc
, &tm
);
1125 if (oldFont
) SelectObject( hdc
, oldFont
);
1126 ReleaseDC( wnd
->hwndSelf
, hdc
);
1127 if (!IS_OWNERDRAW(descr
))
1128 LISTBOX_SetItemHeight( wnd
, descr
, 0, tm
.tmHeight
);
1129 return tm
.tmHeight
;
1133 /***********************************************************************
1134 * LISTBOX_MakeItemVisible
1136 * Make sure that a given item is partially or fully visible.
1138 static void LISTBOX_MakeItemVisible( WND
*wnd
, LB_DESCR
*descr
, INT index
,
1143 if (index
<= descr
->top_item
) top
= index
;
1144 else if (descr
->style
& LBS_MULTICOLUMN
)
1146 INT cols
= descr
->width
;
1147 if (!fully
) cols
+= descr
->column_width
- 1;
1148 if (cols
>= descr
->column_width
) cols
/= descr
->column_width
;
1150 if (index
< descr
->top_item
+ (descr
->page_size
* cols
)) return;
1151 top
= index
- descr
->page_size
* (cols
- 1);
1153 else if (descr
->style
& LBS_OWNERDRAWVARIABLE
)
1155 INT height
= fully
? descr
->items
[index
].height
: 1;
1156 for (top
= index
; top
> descr
->top_item
; top
--)
1157 if ((height
+= descr
->items
[top
-1].height
) > descr
->height
) break;
1161 if (index
< descr
->top_item
+ descr
->page_size
) return;
1162 if (!fully
&& (index
== descr
->top_item
+ descr
->page_size
) &&
1163 (descr
->height
> (descr
->page_size
* descr
->item_height
))) return;
1164 top
= index
- descr
->page_size
+ 1;
1166 LISTBOX_SetTopItem( wnd
, descr
, top
, TRUE
);
1170 /***********************************************************************
1171 * LISTBOX_SelectItemRange
1173 * Select a range of items. Should only be used on a MULTIPLESEL listbox.
1175 static LRESULT
LISTBOX_SelectItemRange( WND
*wnd
, LB_DESCR
*descr
, INT first
,
1180 /* A few sanity checks */
1182 if ((last
== -1) && (descr
->nb_items
== 0)) return LB_OKAY
;
1183 if (!(descr
->style
& LBS_MULTIPLESEL
)) return LB_ERR
;
1184 if (last
== -1) last
= descr
->nb_items
- 1;
1185 if ((first
< 0) || (first
>= descr
->nb_items
)) return LB_ERR
;
1186 if ((last
< 0) || (last
>= descr
->nb_items
)) return LB_ERR
;
1187 /* selected_item reflects last selected/unselected item on multiple sel */
1188 descr
->selected_item
= last
;
1190 if (on
) /* Turn selection on */
1192 for (i
= first
; i
<= last
; i
++)
1194 if (descr
->items
[i
].selected
) continue;
1195 descr
->items
[i
].selected
= TRUE
;
1196 LISTBOX_RepaintItem( wnd
, descr
, i
, ODA_SELECT
);
1199 else /* Turn selection off */
1201 for (i
= first
; i
<= last
; i
++)
1203 if (!descr
->items
[i
].selected
) continue;
1204 descr
->items
[i
].selected
= FALSE
;
1205 LISTBOX_RepaintItem( wnd
, descr
, i
, ODA_SELECT
);
1212 /***********************************************************************
1213 * LISTBOX_SetCaretIndex
1216 * index must be between 0 and descr->nb_items-1, or LB_ERR is returned.
1219 static LRESULT
LISTBOX_SetCaretIndex( WND
*wnd
, LB_DESCR
*descr
, INT index
,
1220 BOOL fully_visible
)
1222 INT oldfocus
= descr
->focus_item
;
1224 if ((index
< 0) || (index
>= descr
->nb_items
)) return LB_ERR
;
1225 if (index
== oldfocus
) return LB_OKAY
;
1226 descr
->focus_item
= index
;
1227 if ((oldfocus
!= -1) && descr
->caret_on
&& (GetFocus() == wnd
->hwndSelf
))
1228 LISTBOX_RepaintItem( wnd
, descr
, oldfocus
, ODA_FOCUS
);
1230 LISTBOX_MakeItemVisible( wnd
, descr
, index
, fully_visible
);
1231 if (descr
->caret_on
&& (GetFocus() == wnd
->hwndSelf
))
1232 LISTBOX_RepaintItem( wnd
, descr
, index
, ODA_FOCUS
);
1238 /***********************************************************************
1239 * LISTBOX_SetSelection
1241 static LRESULT
LISTBOX_SetSelection( WND
*wnd
, LB_DESCR
*descr
, INT index
,
1242 BOOL on
, BOOL send_notify
)
1244 TRACE( "index=%d notify=%s\n", index
, send_notify
? "YES" : "NO" );
1246 if ((index
< -1) || (index
>= descr
->nb_items
)) return LB_ERR
;
1247 if (descr
->style
& LBS_MULTIPLESEL
)
1249 if (index
== -1) /* Select all items */
1250 return LISTBOX_SelectItemRange( wnd
, descr
, 0, -1, on
);
1251 else /* Only one item */
1252 return LISTBOX_SelectItemRange( wnd
, descr
, index
, index
, on
);
1256 INT oldsel
= descr
->selected_item
;
1257 if (index
== oldsel
) return LB_OKAY
;
1258 if (oldsel
!= -1) descr
->items
[oldsel
].selected
= FALSE
;
1259 if (index
!= -1) descr
->items
[index
].selected
= TRUE
;
1260 descr
->selected_item
= index
;
1261 if (oldsel
!= -1) LISTBOX_RepaintItem( wnd
, descr
, oldsel
, 0 );
1262 if (index
!= -1) LISTBOX_RepaintItem( wnd
, descr
, index
, ODA_SELECT
);
1263 if (send_notify
&& descr
->nb_items
) SEND_NOTIFICATION( wnd
, descr
,
1264 (index
!= -1) ? LBN_SELCHANGE
: LBN_SELCANCEL
);
1266 if( descr
->lphc
) /* set selection change flag for parent combo */
1267 descr
->lphc
->wState
|= CBF_SELCHANGE
;
1273 /***********************************************************************
1276 * Change the caret position and extend the selection to the new caret.
1278 static void LISTBOX_MoveCaret( WND
*wnd
, LB_DESCR
*descr
, INT index
,
1279 BOOL fully_visible
)
1281 LISTBOX_SetCaretIndex( wnd
, descr
, index
, fully_visible
);
1282 if (descr
->style
& LBS_EXTENDEDSEL
)
1284 if (descr
->anchor_item
!= -1)
1286 INT first
= MIN( descr
->focus_item
, descr
->anchor_item
);
1287 INT last
= MAX( descr
->focus_item
, descr
->anchor_item
);
1289 LISTBOX_SelectItemRange( wnd
, descr
, 0, first
- 1, FALSE
);
1290 LISTBOX_SelectItemRange( wnd
, descr
, last
+ 1, -1, FALSE
);
1291 LISTBOX_SelectItemRange( wnd
, descr
, first
, last
, TRUE
);
1294 else if (!(descr
->style
& LBS_MULTIPLESEL
))
1296 /* Set selection to new caret item */
1297 LISTBOX_SetSelection( wnd
, descr
, index
, TRUE
, FALSE
);
1302 /***********************************************************************
1303 * LISTBOX_InsertItem
1305 static LRESULT
LISTBOX_InsertItem( WND
*wnd
, LB_DESCR
*descr
, INT index
,
1306 LPSTR str
, DWORD data
)
1310 INT oldfocus
= descr
->focus_item
;
1312 if (index
== -1) index
= descr
->nb_items
;
1313 else if ((index
< 0) || (index
> descr
->nb_items
)) return LB_ERR
;
1314 if (!descr
->items
) max_items
= 0;
1315 else max_items
= HeapSize( descr
->heap
, 0, descr
->items
) / sizeof(*item
);
1316 if (descr
->nb_items
== max_items
)
1318 /* We need to grow the array */
1319 max_items
+= LB_ARRAY_GRANULARITY
;
1320 if (!(item
= HeapReAlloc( descr
->heap
, 0, descr
->items
,
1321 max_items
* sizeof(LB_ITEMDATA
) )))
1323 SEND_NOTIFICATION( wnd
, descr
, LBN_ERRSPACE
);
1326 descr
->items
= item
;
1329 /* Insert the item structure */
1331 item
= &descr
->items
[index
];
1332 if (index
< descr
->nb_items
)
1333 RtlMoveMemory( item
+ 1, item
,
1334 (descr
->nb_items
- index
) * sizeof(LB_ITEMDATA
) );
1338 item
->selected
= FALSE
;
1341 /* Get item height */
1343 if (descr
->style
& LBS_OWNERDRAWVARIABLE
)
1345 MEASUREITEMSTRUCT mis
;
1346 UINT id
= (descr
->lphc
) ? ID_CB_LISTBOX
: wnd
->wIDmenu
;
1348 mis
.CtlType
= ODT_LISTBOX
;
1351 mis
.itemData
= descr
->items
[index
].data
;
1352 mis
.itemHeight
= descr
->item_height
;
1353 SendMessageA( descr
->owner
, WM_MEASUREITEM
, id
, (LPARAM
)&mis
);
1354 item
->height
= mis
.itemHeight
? mis
.itemHeight
: 1;
1355 TRACE("[%04x]: measure item %d (%s) = %d\n",
1356 wnd
->hwndSelf
, index
, str
? str
: "", item
->height
);
1359 /* Repaint the items */
1361 LISTBOX_UpdateScroll( wnd
, descr
);
1362 LISTBOX_InvalidateItems( wnd
, descr
, index
);
1364 /* Move selection and focused item */
1365 /* If listbox was empty, set focus to the first item */
1366 if (descr
->nb_items
== 1)
1367 LISTBOX_SetCaretIndex( wnd
, descr
, 0, FALSE
);
1368 /* single select don't change selection index in win31 */
1369 else if ((ISWIN31
) && !(IS_MULTISELECT(descr
)))
1371 descr
->selected_item
++;
1372 LISTBOX_SetSelection( wnd
, descr
, descr
->selected_item
-1, TRUE
, FALSE
);
1376 if (index
<= descr
->selected_item
)
1378 descr
->selected_item
++;
1379 descr
->focus_item
= oldfocus
; /* focus not changed */
1386 /***********************************************************************
1387 * LISTBOX_InsertString
1389 static LRESULT
LISTBOX_InsertString( WND
*wnd
, LB_DESCR
*descr
, INT index
,
1392 LPSTR new_str
= NULL
;
1396 if (HAS_STRINGS(descr
))
1399 if (!(new_str
= HEAP_strdupA( descr
->heap
, 0, str
)))
1401 SEND_NOTIFICATION( wnd
, descr
, LBN_ERRSPACE
);
1405 else data
= (DWORD
)str
;
1407 if (index
== -1) index
= descr
->nb_items
;
1408 if ((ret
= LISTBOX_InsertItem( wnd
, descr
, index
, new_str
, data
)) != 0)
1410 if (new_str
) HeapFree( descr
->heap
, 0, new_str
);
1414 TRACE("[%04x]: added item %d '%s'\n",
1415 wnd
->hwndSelf
, index
, HAS_STRINGS(descr
) ? new_str
: "" );
1420 /***********************************************************************
1421 * LISTBOX_DeleteItem
1423 * Delete the content of an item. 'index' must be a valid index.
1425 static void LISTBOX_DeleteItem( WND
*wnd
, LB_DESCR
*descr
, INT index
)
1427 /* Note: Win 3.1 only sends DELETEITEM on owner-draw items,
1428 * while Win95 sends it for all items with user data.
1429 * It's probably better to send it too often than not
1430 * often enough, so this is what we do here.
1432 if (IS_OWNERDRAW(descr
) || descr
->items
[index
].data
)
1434 DELETEITEMSTRUCT dis
;
1435 UINT id
= (descr
->lphc
) ? ID_CB_LISTBOX
: wnd
->wIDmenu
;
1437 dis
.CtlType
= ODT_LISTBOX
;
1440 dis
.hwndItem
= wnd
->hwndSelf
;
1441 dis
.itemData
= descr
->items
[index
].data
;
1442 SendMessageA( descr
->owner
, WM_DELETEITEM
, id
, (LPARAM
)&dis
);
1444 if (HAS_STRINGS(descr
) && descr
->items
[index
].str
)
1445 HeapFree( descr
->heap
, 0, descr
->items
[index
].str
);
1449 /***********************************************************************
1450 * LISTBOX_RemoveItem
1452 * Remove an item from the listbox and delete its content.
1454 static LRESULT
LISTBOX_RemoveItem( WND
*wnd
, LB_DESCR
*descr
, INT index
)
1459 if (index
== -1) index
= descr
->nb_items
- 1;
1460 else if ((index
< 0) || (index
>= descr
->nb_items
)) return LB_ERR
;
1461 LISTBOX_DeleteItem( wnd
, descr
, index
);
1463 /* Remove the item */
1465 item
= &descr
->items
[index
];
1466 if (index
< descr
->nb_items
-1)
1467 RtlMoveMemory( item
, item
+ 1,
1468 (descr
->nb_items
- index
- 1) * sizeof(LB_ITEMDATA
) );
1470 if (descr
->anchor_item
== descr
->nb_items
) descr
->anchor_item
--;
1472 /* Shrink the item array if possible */
1474 max_items
= HeapSize( descr
->heap
, 0, descr
->items
) / sizeof(LB_ITEMDATA
);
1475 if (descr
->nb_items
< max_items
- 2*LB_ARRAY_GRANULARITY
)
1477 max_items
-= LB_ARRAY_GRANULARITY
;
1478 item
= HeapReAlloc( descr
->heap
, 0, descr
->items
,
1479 max_items
* sizeof(LB_ITEMDATA
) );
1480 if (item
) descr
->items
= item
;
1482 /* Repaint the items */
1484 LISTBOX_UpdateScroll( wnd
, descr
);
1485 /* if we removed the scrollbar, reset the top of the list
1486 (correct for owner-drawn ???) */
1487 if (descr
->nb_items
== descr
->page_size
)
1488 LISTBOX_SetTopItem( wnd
, descr
, 0, TRUE
);
1490 /* Move selection and focused item */
1491 if (!IS_MULTISELECT(descr
))
1493 if (index
== descr
->selected_item
)
1494 descr
->selected_item
= -1;
1495 else if (index
< descr
->selected_item
)
1497 descr
->selected_item
--;
1498 if (ISWIN31
) /* win 31 do not change the selected item number */
1499 LISTBOX_SetSelection( wnd
, descr
, descr
->selected_item
+ 1, TRUE
, FALSE
);
1502 LISTBOX_InvalidateItems( wnd
, descr
, index
);
1503 if (descr
->focus_item
>= descr
->nb_items
)
1505 descr
->focus_item
= descr
->nb_items
- 1;
1506 if (descr
->focus_item
< 0) descr
->focus_item
= 0;
1512 /***********************************************************************
1513 * LISTBOX_ResetContent
1515 static void LISTBOX_ResetContent( WND
*wnd
, LB_DESCR
*descr
)
1519 for (i
= 0; i
< descr
->nb_items
; i
++) LISTBOX_DeleteItem( wnd
, descr
, i
);
1520 if (descr
->items
) HeapFree( descr
->heap
, 0, descr
->items
);
1521 descr
->nb_items
= 0;
1522 descr
->top_item
= 0;
1523 descr
->selected_item
= -1;
1524 descr
->focus_item
= 0;
1525 descr
->anchor_item
= -1;
1526 descr
->items
= NULL
;
1527 LISTBOX_UpdateScroll( wnd
, descr
);
1528 InvalidateRect( wnd
->hwndSelf
, NULL
, TRUE
);
1532 /***********************************************************************
1535 static LRESULT
LISTBOX_SetCount( WND
*wnd
, LB_DESCR
*descr
, INT count
)
1539 if (HAS_STRINGS(descr
)) return LB_ERR
;
1540 /* FIXME: this is far from optimal... */
1541 if (count
> descr
->nb_items
)
1543 while (count
> descr
->nb_items
)
1544 if ((ret
= LISTBOX_InsertString( wnd
, descr
, -1, 0 )) < 0)
1547 else if (count
< descr
->nb_items
)
1549 while (count
< descr
->nb_items
)
1550 if ((ret
= LISTBOX_RemoveItem( wnd
, descr
, -1 )) < 0)
1557 /***********************************************************************
1560 static LRESULT
LISTBOX_Directory( WND
*wnd
, LB_DESCR
*descr
, UINT attrib
,
1561 LPCSTR filespec
, BOOL long_names
)
1564 LRESULT ret
= LB_OKAY
;
1565 WIN32_FIND_DATAA entry
;
1568 if ((handle
= FindFirstFileA(filespec
,&entry
)) == INVALID_HANDLE_VALUE
)
1570 if (GetLastError() != ERROR_NO_MORE_FILES
) return LB_ERR
;
1577 if (entry
.dwFileAttributes
& FILE_ATTRIBUTE_DIRECTORY
)
1579 if (!(attrib
& DDL_DIRECTORY
) ||
1580 !strcmp( entry
.cAlternateFileName
, "." )) continue;
1581 if (long_names
) sprintf( buffer
, "[%s]", entry
.cFileName
);
1582 else sprintf( buffer
, "[%s]", entry
.cAlternateFileName
);
1584 else /* not a directory */
1586 #define ATTRIBS (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
1587 FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE)
1589 if ((attrib
& DDL_EXCLUSIVE
) &&
1590 ((attrib
& ATTRIBS
) != (entry
.dwFileAttributes
& ATTRIBS
)))
1593 if (long_names
) strcpy( buffer
, entry
.cFileName
);
1594 else strcpy( buffer
, entry
.cAlternateFileName
);
1596 if (!long_names
) CharLowerA( buffer
);
1597 pos
= LISTBOX_FindFileStrPos( wnd
, descr
, buffer
);
1598 if ((ret
= LISTBOX_InsertString( wnd
, descr
, pos
, buffer
)) < 0)
1600 } while (FindNextFileA( handle
, &entry
));
1601 FindClose( handle
);
1604 if ((ret
>= 0) && (attrib
& DDL_DRIVES
))
1606 char buffer
[] = "[-a-]";
1608 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++, buffer
[2]++)
1610 if (!DRIVE_IsValid(drive
)) continue;
1611 if ((ret
= LISTBOX_InsertString( wnd
, descr
, -1, buffer
)) < 0)
1619 /***********************************************************************
1620 * LISTBOX_HandleVScroll
1622 static LRESULT
LISTBOX_HandleVScroll( WND
*wnd
, LB_DESCR
*descr
,
1623 WPARAM wParam
, LPARAM lParam
)
1627 if (descr
->style
& LBS_MULTICOLUMN
) return 0;
1628 switch(LOWORD(wParam
))
1631 LISTBOX_SetTopItem( wnd
, descr
, descr
->top_item
- 1, TRUE
);
1634 LISTBOX_SetTopItem( wnd
, descr
, descr
->top_item
+ 1, TRUE
);
1637 LISTBOX_SetTopItem( wnd
, descr
, descr
->top_item
-
1638 LISTBOX_GetCurrentPageSize( wnd
, descr
), TRUE
);
1641 LISTBOX_SetTopItem( wnd
, descr
, descr
->top_item
+
1642 LISTBOX_GetCurrentPageSize( wnd
, descr
), TRUE
);
1644 case SB_THUMBPOSITION
:
1645 LISTBOX_SetTopItem( wnd
, descr
, HIWORD(wParam
), TRUE
);
1648 info
.cbSize
= sizeof(info
);
1649 info
.fMask
= SIF_TRACKPOS
;
1650 GetScrollInfo( wnd
->hwndSelf
, SB_VERT
, &info
);
1651 LISTBOX_SetTopItem( wnd
, descr
, info
.nTrackPos
, TRUE
);
1654 LISTBOX_SetTopItem( wnd
, descr
, 0, TRUE
);
1657 LISTBOX_SetTopItem( wnd
, descr
, descr
->nb_items
, TRUE
);
1664 /***********************************************************************
1665 * LISTBOX_HandleHScroll
1667 static LRESULT
LISTBOX_HandleHScroll( WND
*wnd
, LB_DESCR
*descr
,
1668 WPARAM wParam
, LPARAM lParam
)
1673 if (descr
->style
& LBS_MULTICOLUMN
)
1675 switch(LOWORD(wParam
))
1678 LISTBOX_SetTopItem( wnd
, descr
, descr
->top_item
-descr
->page_size
,
1682 LISTBOX_SetTopItem( wnd
, descr
, descr
->top_item
+descr
->page_size
,
1686 page
= descr
->width
/ descr
->column_width
;
1687 if (page
< 1) page
= 1;
1688 LISTBOX_SetTopItem( wnd
, descr
,
1689 descr
->top_item
- page
* descr
->page_size
, TRUE
);
1692 page
= descr
->width
/ descr
->column_width
;
1693 if (page
< 1) page
= 1;
1694 LISTBOX_SetTopItem( wnd
, descr
,
1695 descr
->top_item
+ page
* descr
->page_size
, TRUE
);
1697 case SB_THUMBPOSITION
:
1698 LISTBOX_SetTopItem( wnd
, descr
, HIWORD(wParam
)*descr
->page_size
,
1702 info
.cbSize
= sizeof(info
);
1703 info
.fMask
= SIF_TRACKPOS
;
1704 GetScrollInfo( wnd
->hwndSelf
, SB_VERT
, &info
);
1705 LISTBOX_SetTopItem( wnd
, descr
, info
.nTrackPos
*descr
->page_size
,
1709 LISTBOX_SetTopItem( wnd
, descr
, 0, TRUE
);
1712 LISTBOX_SetTopItem( wnd
, descr
, descr
->nb_items
, TRUE
);
1716 else if (descr
->horz_extent
)
1718 switch(LOWORD(wParam
))
1721 LISTBOX_SetHorizontalPos( wnd
, descr
, descr
->horz_pos
- 1 );
1724 LISTBOX_SetHorizontalPos( wnd
, descr
, descr
->horz_pos
+ 1 );
1727 LISTBOX_SetHorizontalPos( wnd
, descr
,
1728 descr
->horz_pos
- descr
->width
);
1731 LISTBOX_SetHorizontalPos( wnd
, descr
,
1732 descr
->horz_pos
+ descr
->width
);
1734 case SB_THUMBPOSITION
:
1735 LISTBOX_SetHorizontalPos( wnd
, descr
, HIWORD(wParam
) );
1738 info
.cbSize
= sizeof(info
);
1739 info
.fMask
= SIF_TRACKPOS
;
1740 GetScrollInfo( wnd
->hwndSelf
, SB_HORZ
, &info
);
1741 LISTBOX_SetHorizontalPos( wnd
, descr
, info
.nTrackPos
);
1744 LISTBOX_SetHorizontalPos( wnd
, descr
, 0 );
1747 LISTBOX_SetHorizontalPos( wnd
, descr
,
1748 descr
->horz_extent
- descr
->width
);
1756 /***********************************************************************
1757 * LISTBOX_HandleLButtonDown
1759 static LRESULT
LISTBOX_HandleLButtonDown( WND
*wnd
, LB_DESCR
*descr
,
1760 WPARAM wParam
, INT x
, INT y
)
1762 INT index
= LISTBOX_GetItemFromPoint( wnd
, descr
, x
, y
);
1763 TRACE("[%04x]: lbuttondown %d,%d item %d\n",
1764 wnd
->hwndSelf
, x
, y
, index
);
1765 if (!descr
->caret_on
&& (GetFocus() == wnd
->hwndSelf
)) return 0;
1768 if (descr
->style
& LBS_EXTENDEDSEL
)
1770 if (!(wParam
& MK_SHIFT
)) descr
->anchor_item
= index
;
1771 if (wParam
& MK_CONTROL
)
1773 LISTBOX_SetCaretIndex( wnd
, descr
, index
, FALSE
);
1774 LISTBOX_SetSelection( wnd
, descr
, index
,
1775 !descr
->items
[index
].selected
,
1776 (descr
->style
& LBS_NOTIFY
) != 0);
1778 else LISTBOX_MoveCaret( wnd
, descr
, index
, FALSE
);
1782 LISTBOX_MoveCaret( wnd
, descr
, index
, FALSE
);
1783 LISTBOX_SetSelection( wnd
, descr
, index
,
1784 (!(descr
->style
& LBS_MULTIPLESEL
) ||
1785 !descr
->items
[index
].selected
),
1786 (descr
->style
& LBS_NOTIFY
) != 0 );
1790 if( !descr
->lphc
) SetFocus( wnd
->hwndSelf
);
1791 else SetFocus( (descr
->lphc
->hWndEdit
) ? descr
->lphc
->hWndEdit
1792 : descr
->lphc
->self
->hwndSelf
) ;
1794 descr
->captured
= TRUE
;
1795 SetCapture( wnd
->hwndSelf
);
1796 if (index
!= -1 && !descr
->lphc
)
1798 if (descr
->style
& LBS_NOTIFY
)
1799 SendMessageA( descr
->owner
, WM_LBTRACKPOINT
, index
,
1800 MAKELPARAM( x
, y
) );
1801 if (wnd
->dwExStyle
& WS_EX_DRAGDETECT
)
1808 if (DragDetect( wnd
->hwndSelf
, pt
))
1809 SendMessageA( descr
->owner
, WM_BEGINDRAG
, 0, 0 );
1816 /*************************************************************************
1817 * LISTBOX_HandleLButtonDownCombo [Internal]
1819 * Process LButtonDown message for the ComboListBox
1822 * pWnd [I] The windows internal structure
1823 * pDescr [I] The ListBox internal structure
1824 * wParam [I] Key Flag (WM_LBUTTONDOWN doc for more info)
1825 * x [I] X Mouse Coordinate
1826 * y [I] Y Mouse Coordinate
1829 * 0 since we are processing the WM_LBUTTONDOWN Message
1832 * This function is only to be used when a ListBox is a ComboListBox
1835 static LRESULT
LISTBOX_HandleLButtonDownCombo( WND
*pWnd
, LB_DESCR
*pDescr
,
1836 WPARAM wParam
, INT x
, INT y
)
1838 RECT clientRect
, screenRect
;
1844 GetClientRect(pWnd
->hwndSelf
, &clientRect
);
1846 if(PtInRect(&clientRect
, mousePos
))
1848 /* MousePos is in client, resume normal processing */
1849 return LISTBOX_HandleLButtonDown( pWnd
, pDescr
, wParam
, x
, y
);
1853 POINT screenMousePos
;
1854 HWND hWndOldCapture
;
1856 /* Check the Non-Client Area */
1857 screenMousePos
= mousePos
;
1858 hWndOldCapture
= GetCapture();
1860 GetWindowRect(pWnd
->hwndSelf
, &screenRect
);
1861 ClientToScreen(pWnd
->hwndSelf
, &screenMousePos
);
1863 if(!PtInRect(&screenRect
, screenMousePos
))
1865 /* Close The Drop Down */
1866 SEND_NOTIFICATION( pWnd
, pDescr
, LBN_SELCANCEL
);
1871 /* Check to see the NC is a scrollbar */
1873 /* Check Vertical scroll bar */
1874 if (pWnd
->dwStyle
& WS_VSCROLL
)
1876 clientRect
.right
+= GetSystemMetrics(SM_CXVSCROLL
);
1877 if (PtInRect( &clientRect
, mousePos
))
1879 nHitTestType
= HTVSCROLL
;
1882 /* Check horizontal scroll bar */
1883 if (pWnd
->dwStyle
& WS_HSCROLL
)
1885 clientRect
.bottom
+= GetSystemMetrics(SM_CYHSCROLL
);
1886 if (PtInRect( &clientRect
, mousePos
))
1888 nHitTestType
= HTHSCROLL
;
1891 /* Windows sends this message when a scrollbar is clicked
1894 if(nHitTestType
!= 0)
1896 SendMessageA(pWnd
->hwndSelf
, WM_NCLBUTTONDOWN
, nHitTestType
,
1897 MAKELONG(screenMousePos
.x
, screenMousePos
.y
));
1899 /* Resume the Capture after scrolling is complete
1901 if(hWndOldCapture
!= 0)
1903 SetCapture(hWndOldCapture
);
1910 /***********************************************************************
1911 * LISTBOX_HandleLButtonUp
1913 static LRESULT
LISTBOX_HandleLButtonUp( WND
*wnd
, LB_DESCR
*descr
)
1915 if (LISTBOX_Timer
!= LB_TIMER_NONE
)
1916 KillSystemTimer( wnd
->hwndSelf
, LB_TIMER_ID
);
1917 LISTBOX_Timer
= LB_TIMER_NONE
;
1918 if (descr
->captured
)
1920 descr
->captured
= FALSE
;
1921 if (GetCapture() == wnd
->hwndSelf
) ReleaseCapture();
1922 if ((descr
->style
& LBS_NOTIFY
) && descr
->nb_items
)
1923 SEND_NOTIFICATION( wnd
, descr
, LBN_SELCHANGE
);
1929 /***********************************************************************
1930 * LISTBOX_HandleTimer
1932 * Handle scrolling upon a timer event.
1933 * Return TRUE if scrolling should continue.
1935 static LRESULT
LISTBOX_HandleTimer( WND
*wnd
, LB_DESCR
*descr
,
1936 INT index
, TIMER_DIRECTION dir
)
1941 if (descr
->top_item
) index
= descr
->top_item
- 1;
1945 if (descr
->top_item
) index
-= descr
->page_size
;
1948 index
= descr
->top_item
+ LISTBOX_GetCurrentPageSize( wnd
, descr
);
1949 if (index
== descr
->focus_item
) index
++;
1950 if (index
>= descr
->nb_items
) index
= descr
->nb_items
- 1;
1952 case LB_TIMER_RIGHT
:
1953 if (index
+ descr
->page_size
< descr
->nb_items
)
1954 index
+= descr
->page_size
;
1959 if (index
== descr
->focus_item
) return FALSE
;
1960 LISTBOX_MoveCaret( wnd
, descr
, index
, FALSE
);
1965 /***********************************************************************
1966 * LISTBOX_HandleSystemTimer
1968 * WM_SYSTIMER handler.
1970 static LRESULT
LISTBOX_HandleSystemTimer( WND
*wnd
, LB_DESCR
*descr
)
1972 if (!LISTBOX_HandleTimer( wnd
, descr
, descr
->focus_item
, LISTBOX_Timer
))
1974 KillSystemTimer( wnd
->hwndSelf
, LB_TIMER_ID
);
1975 LISTBOX_Timer
= LB_TIMER_NONE
;
1981 /***********************************************************************
1982 * LISTBOX_HandleMouseMove
1984 * WM_MOUSEMOVE handler.
1986 static void LISTBOX_HandleMouseMove( WND
*wnd
, LB_DESCR
*descr
,
1990 TIMER_DIRECTION dir
;
1992 if (!descr
->captured
) return;
1994 if (descr
->style
& LBS_MULTICOLUMN
)
1997 else if (y
>= descr
->item_height
* descr
->page_size
)
1998 y
= descr
->item_height
* descr
->page_size
- 1;
2002 dir
= LB_TIMER_LEFT
;
2005 else if (x
>= descr
->width
)
2007 dir
= LB_TIMER_RIGHT
;
2008 x
= descr
->width
- 1;
2010 else dir
= LB_TIMER_NONE
; /* inside */
2014 if (y
< 0) dir
= LB_TIMER_UP
; /* above */
2015 else if (y
>= descr
->height
) dir
= LB_TIMER_DOWN
; /* below */
2016 else dir
= LB_TIMER_NONE
; /* inside */
2019 index
= LISTBOX_GetItemFromPoint( wnd
, descr
, x
, y
);
2020 if (index
== -1) index
= descr
->focus_item
;
2021 if (!LISTBOX_HandleTimer( wnd
, descr
, index
, dir
)) dir
= LB_TIMER_NONE
;
2023 /* Start/stop the system timer */
2025 if (dir
!= LB_TIMER_NONE
)
2026 SetSystemTimer( wnd
->hwndSelf
, LB_TIMER_ID
, LB_SCROLL_TIMEOUT
, NULL
);
2027 else if (LISTBOX_Timer
!= LB_TIMER_NONE
)
2028 KillSystemTimer( wnd
->hwndSelf
, LB_TIMER_ID
);
2029 LISTBOX_Timer
= dir
;
2033 /***********************************************************************
2034 * LISTBOX_HandleKeyDown
2036 static LRESULT
LISTBOX_HandleKeyDown( WND
*wnd
, LB_DESCR
*descr
, WPARAM wParam
)
2039 BOOL bForceSelection
= TRUE
; /* select item pointed to by focus_item */
2040 if ((IS_MULTISELECT(descr
)) || (descr
->selected_item
== descr
->focus_item
))
2041 bForceSelection
= FALSE
; /* only for single select list */
2043 if (descr
->style
& LBS_WANTKEYBOARDINPUT
)
2045 caret
= SendMessageA( descr
->owner
, WM_VKEYTOITEM
,
2046 MAKEWPARAM(LOWORD(wParam
), descr
->focus_item
),
2048 if (caret
== -2) return 0;
2050 if (caret
== -1) switch(wParam
)
2053 if (descr
->style
& LBS_MULTICOLUMN
)
2055 bForceSelection
= FALSE
;
2056 if (descr
->focus_item
>= descr
->page_size
)
2057 caret
= descr
->focus_item
- descr
->page_size
;
2062 caret
= descr
->focus_item
- 1;
2063 if (caret
< 0) caret
= 0;
2066 if (descr
->style
& LBS_MULTICOLUMN
)
2068 bForceSelection
= FALSE
;
2069 if (descr
->focus_item
+ descr
->page_size
< descr
->nb_items
)
2070 caret
= descr
->focus_item
+ descr
->page_size
;
2075 caret
= descr
->focus_item
+ 1;
2076 if (caret
>= descr
->nb_items
) caret
= descr
->nb_items
- 1;
2080 if (descr
->style
& LBS_MULTICOLUMN
)
2082 INT page
= descr
->width
/ descr
->column_width
;
2083 if (page
< 1) page
= 1;
2084 caret
= descr
->focus_item
- (page
* descr
->page_size
) + 1;
2086 else caret
= descr
->focus_item
-LISTBOX_GetCurrentPageSize(wnd
,descr
)+1;
2087 if (caret
< 0) caret
= 0;
2090 if (descr
->style
& LBS_MULTICOLUMN
)
2092 INT page
= descr
->width
/ descr
->column_width
;
2093 if (page
< 1) page
= 1;
2094 caret
= descr
->focus_item
+ (page
* descr
->page_size
) - 1;
2096 else caret
= descr
->focus_item
+LISTBOX_GetCurrentPageSize(wnd
,descr
)-1;
2097 if (caret
>= descr
->nb_items
) caret
= descr
->nb_items
- 1;
2103 caret
= descr
->nb_items
- 1;
2106 if (descr
->style
& LBS_EXTENDEDSEL
) caret
= descr
->focus_item
;
2107 else if (descr
->style
& LBS_MULTIPLESEL
)
2109 LISTBOX_SetSelection( wnd
, descr
, descr
->focus_item
,
2110 !descr
->items
[descr
->focus_item
].selected
,
2111 (descr
->style
& LBS_NOTIFY
) != 0 );
2115 bForceSelection
= FALSE
;
2117 if (bForceSelection
) /* focused item is used instead of key */
2118 caret
= descr
->focus_item
;
2121 if ((descr
->style
& LBS_EXTENDEDSEL
) &&
2122 !(GetKeyState( VK_SHIFT
) & 0x8000))
2123 descr
->anchor_item
= caret
;
2124 LISTBOX_MoveCaret( wnd
, descr
, caret
, TRUE
);
2125 LISTBOX_SetSelection( wnd
, descr
, caret
, TRUE
, FALSE
);
2126 if (descr
->style
& LBS_NOTIFY
)
2128 if( descr
->lphc
&& CB_GETTYPE(descr
->lphc
) != CBS_SIMPLE
)
2130 /* make sure that combo parent doesn't hide us */
2131 descr
->lphc
->wState
|= CBF_NOROLLUP
;
2133 if (descr
->nb_items
) SEND_NOTIFICATION( wnd
, descr
, LBN_SELCHANGE
);
2140 /***********************************************************************
2141 * LISTBOX_HandleChar
2143 static LRESULT
LISTBOX_HandleChar( WND
*wnd
, LB_DESCR
*descr
,
2149 str
[0] = wParam
& 0xff;
2152 if (descr
->style
& LBS_WANTKEYBOARDINPUT
)
2154 caret
= SendMessageA( descr
->owner
, WM_CHARTOITEM
,
2155 MAKEWPARAM(LOWORD(wParam
), descr
->focus_item
),
2157 if (caret
== -2) return 0;
2160 caret
= LISTBOX_FindString( wnd
, descr
, descr
->focus_item
, str
, FALSE
);
2163 if ((!IS_MULTISELECT(descr
)) && descr
->selected_item
== -1)
2164 LISTBOX_SetSelection( wnd
, descr
, caret
, TRUE
, FALSE
);
2165 LISTBOX_MoveCaret( wnd
, descr
, caret
, TRUE
);
2166 if ((descr
->style
& LBS_NOTIFY
) && descr
->nb_items
)
2167 SEND_NOTIFICATION( wnd
, descr
, LBN_SELCHANGE
);
2173 /***********************************************************************
2176 static BOOL
LISTBOX_Create( WND
*wnd
, LPHEADCOMBO lphc
)
2179 MEASUREITEMSTRUCT mis
;
2182 if (!(descr
= HeapAlloc( GetProcessHeap(), 0, sizeof(*descr
) )))
2184 if (!(descr
->heap
= HeapCreate( 0, 0x10000, 0 )))
2186 HeapFree( GetProcessHeap(), 0, descr
);
2189 GetClientRect( wnd
->hwndSelf
, &rect
);
2190 descr
->owner
= GetParent( wnd
->hwndSelf
);
2191 descr
->style
= wnd
->dwStyle
;
2192 descr
->width
= rect
.right
- rect
.left
;
2193 descr
->height
= rect
.bottom
- rect
.top
;
2194 descr
->items
= NULL
;
2195 descr
->nb_items
= 0;
2196 descr
->top_item
= 0;
2197 descr
->selected_item
= -1;
2198 descr
->focus_item
= 0;
2199 descr
->anchor_item
= -1;
2200 descr
->item_height
= 1;
2201 descr
->page_size
= 1;
2202 descr
->column_width
= 150;
2203 descr
->horz_extent
= (wnd
->dwStyle
& WS_HSCROLL
) ? 1 : 0;
2204 descr
->horz_pos
= 0;
2207 descr
->caret_on
= TRUE
;
2208 descr
->captured
= FALSE
;
2210 descr
->locale
= 0; /* FIXME */
2213 if( ( GetExpWinVer16( wnd
->hInstance
) & 0xFF00 ) == 0x0300
2214 && ( descr
->style
& ( WS_VSCROLL
| WS_HSCROLL
) ) )
2216 /* Win95 document "List Box Differences" from MSDN:
2217 If a list box in a version 3.x application has either the
2218 WS_HSCROLL or WS_VSCROLL style, the list box receives both
2219 horizontal and vertical scroll bars.
2221 descr
->style
|= WS_VSCROLL
| WS_HSCROLL
;
2226 TRACE_(combo
)("[%04x]: resetting owner %04x -> %04x\n",
2227 wnd
->hwndSelf
, descr
->owner
, lphc
->self
->hwndSelf
);
2228 descr
->owner
= lphc
->self
->hwndSelf
;
2231 *(LB_DESCR
**)wnd
->wExtra
= descr
;
2233 /* if (wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) descr->style &= ~LBS_NOTIFY;
2235 if (descr
->style
& LBS_EXTENDEDSEL
) descr
->style
|= LBS_MULTIPLESEL
;
2236 if (descr
->style
& LBS_MULTICOLUMN
) descr
->style
&= ~LBS_OWNERDRAWVARIABLE
;
2237 if (descr
->style
& LBS_OWNERDRAWVARIABLE
) descr
->style
|= LBS_NOINTEGRALHEIGHT
;
2238 descr
->item_height
= LISTBOX_SetFont( wnd
, descr
, 0 );
2240 if (descr
->style
& LBS_OWNERDRAWFIXED
)
2242 if( descr
->lphc
&& (descr
->lphc
->dwStyle
& CBS_DROPDOWN
))
2244 /* WinWord gets VERY unhappy if we send WM_MEASUREITEM from here */
2245 descr
->item_height
= lphc
->fixedOwnerDrawHeight
;
2249 UINT id
= (descr
->lphc
) ? ID_CB_LISTBOX
: wnd
->wIDmenu
;
2251 mis
.CtlType
= ODT_LISTBOX
;
2256 mis
.itemHeight
= descr
->item_height
;
2257 SendMessageA( descr
->owner
, WM_MEASUREITEM
, id
, (LPARAM
)&mis
);
2258 descr
->item_height
= mis
.itemHeight
? mis
.itemHeight
: 1;
2266 /***********************************************************************
2269 static BOOL
LISTBOX_Destroy( WND
*wnd
, LB_DESCR
*descr
)
2271 LISTBOX_ResetContent( wnd
, descr
);
2272 HeapDestroy( descr
->heap
);
2273 HeapFree( GetProcessHeap(), 0, descr
);
2279 /***********************************************************************
2282 static inline LRESULT WINAPI
ListBoxWndProc_locked( WND
* wnd
, UINT msg
,
2283 WPARAM wParam
, LPARAM lParam
)
2287 HWND hwnd
= wnd
->hwndSelf
;
2290 if (!(descr
= *(LB_DESCR
**)wnd
->wExtra
))
2296 if (!LISTBOX_Create( wnd
, NULL
))
2298 TRACE("creating wnd=%04x descr=%p\n",
2299 hwnd
, *(LB_DESCR
**)wnd
->wExtra
);
2305 * When a listbox is not in a combobox and the look
2306 * is win95, the WS_BORDER style is replaced with
2307 * the WS_EX_CLIENTEDGE style.
2309 if ( (TWEAK_WineLook
> WIN31_LOOK
) &&
2310 (wnd
->dwStyle
& WS_BORDER
) )
2312 wnd
->dwExStyle
|= WS_EX_CLIENTEDGE
;
2313 wnd
->dwStyle
&= ~ WS_BORDER
;
2318 /* Ignore all other messages before we get a WM_CREATE */
2319 return DefWindowProcA( hwnd
, msg
, wParam
, lParam
);
2322 TRACE("[%04x]: msg %s wp %08x lp %08lx\n",
2323 wnd
->hwndSelf
, SPY_GetMsgName(msg
), wParam
, lParam
);
2326 case LB_RESETCONTENT16
:
2327 case LB_RESETCONTENT
:
2328 LISTBOX_ResetContent( wnd
, descr
);
2331 case LB_ADDSTRING16
:
2332 if (HAS_STRINGS(descr
)) lParam
= (LPARAM
)PTR_SEG_TO_LIN(lParam
);
2335 wParam
= LISTBOX_FindStringPos( wnd
, descr
, (LPCSTR
)lParam
, FALSE
);
2336 return LISTBOX_InsertString( wnd
, descr
, wParam
, (LPCSTR
)lParam
);
2338 case LB_INSERTSTRING16
:
2339 if (HAS_STRINGS(descr
)) lParam
= (LPARAM
)PTR_SEG_TO_LIN(lParam
);
2340 wParam
= (INT
)(INT16
)wParam
;
2342 case LB_INSERTSTRING
:
2343 return LISTBOX_InsertString( wnd
, descr
, wParam
, (LPCSTR
)lParam
);
2346 if (HAS_STRINGS(descr
)) lParam
= (LPARAM
)PTR_SEG_TO_LIN(lParam
);
2349 wParam
= LISTBOX_FindFileStrPos( wnd
, descr
, (LPCSTR
)lParam
);
2350 return LISTBOX_InsertString( wnd
, descr
, wParam
, (LPCSTR
)lParam
);
2352 case LB_DELETESTRING16
:
2353 case LB_DELETESTRING
:
2354 if (LISTBOX_RemoveItem( wnd
, descr
, wParam
) != LB_ERR
)
2355 return descr
->nb_items
;
2359 case LB_GETITEMDATA16
:
2360 case LB_GETITEMDATA
:
2361 if (((INT
)wParam
< 0) || ((INT
)wParam
>= descr
->nb_items
))
2363 return descr
->items
[wParam
].data
;
2365 case LB_SETITEMDATA16
:
2366 case LB_SETITEMDATA
:
2367 if (((INT
)wParam
< 0) || ((INT
)wParam
>= descr
->nb_items
))
2369 descr
->items
[wParam
].data
= (DWORD
)lParam
;
2374 return descr
->nb_items
;
2377 lParam
= (LPARAM
)PTR_SEG_TO_LIN(lParam
);
2380 return LISTBOX_GetText( wnd
, descr
, wParam
, (LPSTR
)lParam
);
2382 case LB_GETTEXTLEN16
:
2385 if (wParam
>= descr
->nb_items
)
2387 return (HAS_STRINGS(descr
) ? strlen(descr
->items
[wParam
].str
)
2390 case LB_GETCURSEL16
:
2392 if (descr
->nb_items
==0)
2394 if (!IS_MULTISELECT(descr
))
2395 return descr
->selected_item
;
2397 if (descr
->selected_item
!=-1)
2398 return descr
->selected_item
;
2400 return descr
->focus_item
;
2401 /* otherwise, if the user tries to move the selection with the */
2402 /* arrow keys, we will give the application something to choke on */
2403 case LB_GETTOPINDEX16
:
2404 case LB_GETTOPINDEX
:
2405 return descr
->top_item
;
2407 case LB_GETITEMHEIGHT16
:
2408 case LB_GETITEMHEIGHT
:
2409 return LISTBOX_GetItemHeight( wnd
, descr
, wParam
);
2411 case LB_SETITEMHEIGHT16
:
2412 lParam
= LOWORD(lParam
);
2414 case LB_SETITEMHEIGHT
:
2415 return LISTBOX_SetItemHeight( wnd
, descr
, wParam
, lParam
);
2417 case LB_ITEMFROMPOINT
:
2422 pt
.x
= LOWORD(lParam
);
2423 pt
.y
= HIWORD(lParam
);
2426 rect
.right
= descr
->width
;
2427 rect
.bottom
= descr
->height
;
2429 return MAKELONG( LISTBOX_GetItemFromPoint(wnd
, descr
, pt
.x
, pt
.y
),
2430 !PtInRect( &rect
, pt
) );
2433 case LB_SETCARETINDEX16
:
2434 case LB_SETCARETINDEX
:
2435 if ((!IS_MULTISELECT(descr
)) && (descr
->selected_item
!= -1)) return LB_ERR
;
2436 if (LISTBOX_SetCaretIndex( wnd
, descr
, wParam
, !lParam
) == LB_ERR
)
2443 case LB_GETCARETINDEX16
:
2444 case LB_GETCARETINDEX
:
2445 return descr
->focus_item
;
2447 case LB_SETTOPINDEX16
:
2448 case LB_SETTOPINDEX
:
2449 return LISTBOX_SetTopItem( wnd
, descr
, wParam
, TRUE
);
2451 case LB_SETCOLUMNWIDTH16
:
2452 case LB_SETCOLUMNWIDTH
:
2453 return LISTBOX_SetColumnWidth( wnd
, descr
, wParam
);
2455 case LB_GETITEMRECT16
:
2458 ret
= LISTBOX_GetItemRect( wnd
, descr
, (INT16
)wParam
, &rect
);
2459 CONV_RECT32TO16( &rect
, (RECT16
*)PTR_SEG_TO_LIN(lParam
) );
2463 case LB_GETITEMRECT
:
2464 return LISTBOX_GetItemRect( wnd
, descr
, wParam
, (RECT
*)lParam
);
2466 case LB_FINDSTRING16
:
2467 wParam
= (INT
)(INT16
)wParam
;
2468 if (HAS_STRINGS(descr
)) lParam
= (LPARAM
)PTR_SEG_TO_LIN(lParam
);
2471 return LISTBOX_FindString( wnd
, descr
, wParam
, (LPCSTR
)lParam
, FALSE
);
2473 case LB_FINDSTRINGEXACT16
:
2474 wParam
= (INT
)(INT16
)wParam
;
2475 if (HAS_STRINGS(descr
)) lParam
= (LPARAM
)PTR_SEG_TO_LIN(lParam
);
2477 case LB_FINDSTRINGEXACT
:
2478 return LISTBOX_FindString( wnd
, descr
, wParam
, (LPCSTR
)lParam
, TRUE
);
2480 case LB_SELECTSTRING16
:
2481 wParam
= (INT
)(INT16
)wParam
;
2482 if (HAS_STRINGS(descr
)) lParam
= (LPARAM
)PTR_SEG_TO_LIN(lParam
);
2484 case LB_SELECTSTRING
:
2486 INT index
= LISTBOX_FindString( wnd
, descr
, wParam
,
2487 (LPCSTR
)lParam
, FALSE
);
2488 if (index
== LB_ERR
)
2490 LISTBOX_SetSelection( wnd
, descr
, index
, TRUE
, FALSE
);
2495 wParam
= (INT
)(INT16
)wParam
;
2498 if (((INT
)wParam
< 0) || ((INT
)wParam
>= descr
->nb_items
))
2500 return descr
->items
[wParam
].selected
;
2503 lParam
= (INT
)(INT16
)lParam
;
2506 return LISTBOX_SetSelection( wnd
, descr
, lParam
, wParam
, FALSE
);
2508 case LB_SETCURSEL16
:
2509 wParam
= (INT
)(INT16
)wParam
;
2512 if (IS_MULTISELECT(descr
)) return LB_ERR
;
2513 LISTBOX_SetCaretIndex( wnd
, descr
, wParam
, TRUE
);
2514 return LISTBOX_SetSelection( wnd
, descr
, wParam
, TRUE
, FALSE
);
2516 case LB_GETSELCOUNT16
:
2517 case LB_GETSELCOUNT
:
2518 return LISTBOX_GetSelCount( wnd
, descr
);
2520 case LB_GETSELITEMS16
:
2521 return LISTBOX_GetSelItems16( wnd
, descr
, wParam
,
2522 (LPINT16
)PTR_SEG_TO_LIN(lParam
) );
2524 case LB_GETSELITEMS
:
2525 return LISTBOX_GetSelItems( wnd
, descr
, wParam
, (LPINT
)lParam
);
2527 case LB_SELITEMRANGE16
:
2528 case LB_SELITEMRANGE
:
2529 if (LOWORD(lParam
) <= HIWORD(lParam
))
2530 return LISTBOX_SelectItemRange( wnd
, descr
, LOWORD(lParam
),
2531 HIWORD(lParam
), wParam
);
2533 return LISTBOX_SelectItemRange( wnd
, descr
, HIWORD(lParam
),
2534 LOWORD(lParam
), wParam
);
2536 case LB_SELITEMRANGEEX16
:
2537 case LB_SELITEMRANGEEX
:
2538 if ((INT
)lParam
>= (INT
)wParam
)
2539 return LISTBOX_SelectItemRange( wnd
, descr
, wParam
, lParam
, TRUE
);
2541 return LISTBOX_SelectItemRange( wnd
, descr
, lParam
, wParam
, FALSE
);
2543 case LB_GETHORIZONTALEXTENT16
:
2544 case LB_GETHORIZONTALEXTENT
:
2545 return descr
->horz_extent
;
2547 case LB_SETHORIZONTALEXTENT16
:
2548 case LB_SETHORIZONTALEXTENT
:
2549 return LISTBOX_SetHorizontalExtent( wnd
, descr
, wParam
);
2551 case LB_GETANCHORINDEX16
:
2552 case LB_GETANCHORINDEX
:
2553 return descr
->anchor_item
;
2555 case LB_SETANCHORINDEX16
:
2556 wParam
= (INT
)(INT16
)wParam
;
2558 case LB_SETANCHORINDEX
:
2559 if (((INT
)wParam
< -1) || ((INT
)wParam
>= descr
->nb_items
))
2561 descr
->anchor_item
= (INT
)wParam
;
2565 return LISTBOX_Directory( wnd
, descr
, wParam
,
2566 (LPCSTR
)PTR_SEG_TO_LIN(lParam
), FALSE
);
2569 return LISTBOX_Directory( wnd
, descr
, wParam
, (LPCSTR
)lParam
, TRUE
);
2572 return descr
->locale
;
2575 descr
->locale
= (LCID
)wParam
; /* FIXME: should check for valid lcid */
2578 case LB_INITSTORAGE
:
2579 return LISTBOX_InitStorage( wnd
, descr
, wParam
, (DWORD
)lParam
);
2582 return LISTBOX_SetCount( wnd
, descr
, (INT
)wParam
);
2584 case LB_SETTABSTOPS16
:
2585 return LISTBOX_SetTabStops( wnd
, descr
, (INT
)(INT16
)wParam
,
2586 (LPINT
)PTR_SEG_TO_LIN(lParam
), TRUE
);
2588 case LB_SETTABSTOPS
:
2589 return LISTBOX_SetTabStops( wnd
, descr
, wParam
, (LPINT
)lParam
, FALSE
);
2593 if (descr
->caret_on
)
2595 descr
->caret_on
= TRUE
;
2596 if ((descr
->focus_item
!= -1) && (GetFocus() == wnd
->hwndSelf
))
2597 LISTBOX_RepaintItem( wnd
, descr
, descr
->focus_item
, ODA_FOCUS
);
2602 if (!descr
->caret_on
)
2604 descr
->caret_on
= FALSE
;
2605 if ((descr
->focus_item
!= -1) && (GetFocus() == wnd
->hwndSelf
))
2606 LISTBOX_RepaintItem( wnd
, descr
, descr
->focus_item
, ODA_FOCUS
);
2610 return LISTBOX_Destroy( wnd
, descr
);
2613 InvalidateRect( hwnd
, NULL
, TRUE
);
2617 LISTBOX_SetRedraw( wnd
, descr
, wParam
!= 0 );
2621 return DLGC_WANTARROWS
| DLGC_WANTCHARS
;
2626 HDC hdc
= ( wParam
) ? ((HDC
)wParam
)
2627 : BeginPaint( hwnd
, &ps
);
2628 ret
= LISTBOX_Paint( wnd
, descr
, hdc
);
2629 if( !wParam
) EndPaint( hwnd
, &ps
);
2633 LISTBOX_UpdateSize( wnd
, descr
);
2638 LISTBOX_SetFont( wnd
, descr
, (HFONT
)wParam
);
2639 if (lParam
) InvalidateRect( wnd
->hwndSelf
, 0, TRUE
);
2642 descr
->caret_on
= TRUE
;
2643 if (descr
->focus_item
!= -1)
2644 LISTBOX_RepaintItem( wnd
, descr
, descr
->focus_item
, ODA_FOCUS
);
2645 SEND_NOTIFICATION( wnd
, descr
, LBN_SETFOCUS
);
2648 if ((descr
->focus_item
!= -1) && descr
->caret_on
)
2649 LISTBOX_RepaintItem( wnd
, descr
, descr
->focus_item
, ODA_FOCUS
);
2650 SEND_NOTIFICATION( wnd
, descr
, LBN_KILLFOCUS
);
2653 return LISTBOX_HandleHScroll( wnd
, descr
, wParam
, lParam
);
2655 return LISTBOX_HandleVScroll( wnd
, descr
, wParam
, lParam
);
2656 case WM_LBUTTONDOWN
:
2657 return LISTBOX_HandleLButtonDown( wnd
, descr
, wParam
,
2658 (INT16
)LOWORD(lParam
),
2659 (INT16
)HIWORD(lParam
) );
2660 case WM_LBUTTONDBLCLK
:
2661 if (descr
->style
& LBS_NOTIFY
)
2662 SEND_NOTIFICATION( wnd
, descr
, LBN_DBLCLK
);
2665 if (GetCapture() == hwnd
)
2666 LISTBOX_HandleMouseMove( wnd
, descr
, (INT16
)LOWORD(lParam
),
2667 (INT16
)HIWORD(lParam
) );
2670 return LISTBOX_HandleLButtonUp( wnd
, descr
);
2672 return LISTBOX_HandleKeyDown( wnd
, descr
, wParam
);
2674 return LISTBOX_HandleChar( wnd
, descr
, wParam
);
2676 return LISTBOX_HandleSystemTimer( wnd
, descr
);
2678 if (IS_OWNERDRAW(descr
))
2681 HBRUSH hbrush
= SendMessageA( descr
->owner
, WM_CTLCOLORLISTBOX
,
2682 wParam
, (LPARAM
)wnd
->hwndSelf
);
2683 GetClientRect(hwnd
, &rect
);
2684 if (hbrush
) FillRect( (HDC
)wParam
, &rect
, hbrush
);
2689 return SendMessageA( descr
->owner
, msg
, wParam
, lParam
);
2693 case WM_QUERYDROPOBJECT
:
2698 LPDRAGINFO dragInfo
= (LPDRAGINFO
)PTR_SEG_TO_LIN( (SEGPTR
)lParam
);
2699 dragInfo
->l
= LISTBOX_GetItemFromPoint( wnd
, descr
, dragInfo
->pt
.x
,
2701 return SendMessageA( descr
->owner
, msg
, wParam
, lParam
);
2706 if ((msg
>= WM_USER
) && (msg
< 0xc000))
2707 WARN("[%04x]: unknown msg %04x wp %08x lp %08lx\n",
2708 hwnd
, msg
, wParam
, lParam
);
2709 return DefWindowProcA( hwnd
, msg
, wParam
, lParam
);
2714 /***********************************************************************
2717 * This is just a wrapper for the real wndproc, it only does window locking
2720 LRESULT WINAPI
ListBoxWndProc( HWND hwnd
, UINT msg
,
2721 WPARAM wParam
, LPARAM lParam
)
2723 WND
* wndPtr
= WIN_FindWndPtr( hwnd
);
2724 LRESULT res
= ListBoxWndProc_locked(wndPtr
,msg
,wParam
,lParam
);
2726 WIN_ReleaseWndPtr(wndPtr
);
2730 /***********************************************************************
2733 LRESULT
COMBO_Directory( LPHEADCOMBO lphc
, UINT attrib
, LPSTR dir
, BOOL bLong
)
2735 WND
*wnd
= WIN_FindWndPtr( lphc
->hWndLBox
);
2739 LB_DESCR
*descr
= *(LB_DESCR
**)wnd
->wExtra
;
2742 LRESULT lRet
= LISTBOX_Directory( wnd
, descr
, attrib
, dir
, bLong
);
2744 RedrawWindow( lphc
->self
->hwndSelf
, NULL
, 0,
2745 RDW_INVALIDATE
| RDW_ERASE
| RDW_UPDATENOW
);
2746 WIN_ReleaseWndPtr(wnd
);
2749 WIN_ReleaseWndPtr(wnd
);
2754 /***********************************************************************
2755 * ComboLBWndProc_locked
2757 * The real combo listbox wndproc, but called with locked WND struct.
2759 static inline LRESULT WINAPI
ComboLBWndProc_locked( WND
* wnd
, UINT msg
,
2760 WPARAM wParam
, LPARAM lParam
)
2763 HWND hwnd
= wnd
->hwndSelf
;
2767 LB_DESCR
*descr
= *(LB_DESCR
**)wnd
->wExtra
;
2769 TRACE_(combo
)("[%04x]: msg %s wp %08x lp %08lx\n",
2770 wnd
->hwndSelf
, SPY_GetMsgName(msg
), wParam
, lParam
);
2772 if( descr
|| msg
== WM_CREATE
)
2774 LPHEADCOMBO lphc
= (descr
) ? descr
->lphc
: NULL
;
2779 #define lpcs ((LPCREATESTRUCTA)lParam)
2780 TRACE_(combo
)("\tpassed parent handle = 0x%08x\n",
2781 (UINT
)lpcs
->lpCreateParams
);
2783 lphc
= (LPHEADCOMBO
)(lpcs
->lpCreateParams
);
2785 return LISTBOX_Create( wnd
, lphc
);
2787 if ( (TWEAK_WineLook
> WIN31_LOOK
) &&
2788 (CB_GETTYPE(lphc
) != CBS_SIMPLE
) )
2794 mousePos
.x
= (INT16
)LOWORD(lParam
);
2795 mousePos
.y
= (INT16
)HIWORD(lParam
);
2798 * If we are in a dropdown combobox, we simulate that
2799 * the mouse is captured to show the tracking of the item.
2801 GetClientRect(hwnd
, &clientRect
);
2803 if (PtInRect( &clientRect
, mousePos
))
2805 captured
= descr
->captured
;
2806 descr
->captured
= TRUE
;
2808 LISTBOX_HandleMouseMove( wnd
, descr
,
2809 mousePos
.x
, mousePos
.y
);
2811 descr
->captured
= captured
;
2816 LISTBOX_HandleMouseMove( wnd
, descr
,
2817 mousePos
.x
, mousePos
.y
);
2826 * If we are in Win3.1 look, go with the default behavior.
2828 return ListBoxWndProc( hwnd
, msg
, wParam
, lParam
);
2831 if (TWEAK_WineLook
> WIN31_LOOK
)
2837 * If the mouse button "up" is not in the listbox,
2838 * we make sure there is no selection by re-selecting the
2839 * item that was selected when the listbox was made visible.
2841 mousePos
.x
= (INT16
)LOWORD(lParam
);
2842 mousePos
.y
= (INT16
)HIWORD(lParam
);
2844 GetClientRect(hwnd
, &clientRect
);
2847 * When the user clicks outside the combobox and the focus
2848 * is lost, the owning combobox will send a fake buttonup with
2849 * 0xFFFFFFF as the mouse location, we must also revert the
2850 * selection to the original selection.
2852 if ( (lParam
== 0xFFFFFFFF) ||
2853 (!PtInRect( &clientRect
, mousePos
)) )
2855 LISTBOX_MoveCaret( wnd
,
2861 return LISTBOX_HandleLButtonUp( wnd
, descr
);
2862 case WM_LBUTTONDOWN
:
2863 return LISTBOX_HandleLButtonDownCombo(wnd
, descr
, wParam
,
2864 (INT16
)LOWORD(lParam
),
2865 (INT16
)HIWORD(lParam
) );
2866 case WM_MOUSEACTIVATE
:
2867 return MA_NOACTIVATE
;
2871 if( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
2873 /* for some reason(?) Windows makes it possible to
2874 * show/hide ComboLBox by sending it WM_KEYDOWNs */
2876 if( (!(lphc
->wState
& CBF_EUI
) && wParam
== VK_F4
) ||
2877 ( (lphc
->wState
& CBF_EUI
) && !(lphc
->wState
& CBF_DROPPED
)
2878 && (wParam
== VK_DOWN
|| wParam
== VK_UP
)) )
2880 COMBO_FlipListbox( lphc
, FALSE
);
2884 return LISTBOX_HandleKeyDown( wnd
, descr
, wParam
);
2886 case LB_SETCURSEL16
:
2888 lRet
= ListBoxWndProc( hwnd
, msg
, wParam
, lParam
);
2889 lRet
=(lRet
== LB_ERR
) ? lRet
: descr
->selected_item
;
2892 if( CB_GETTYPE(lphc
) != CBS_SIMPLE
)
2897 return ListBoxWndProc( hwnd
, msg
, wParam
, lParam
);
2900 lRet
= DefWindowProcA( hwnd
, msg
, wParam
, lParam
);
2902 TRACE_(combo
)("\t default on msg [%04x]\n", (UINT16
)msg
);
2907 /***********************************************************************
2910 * NOTE: in Windows, winproc address of the ComboLBox is the same
2911 * as that of the Listbox.
2913 * This is just a wrapper for the real wndproc, it only does window locking
2916 LRESULT WINAPI
ComboLBWndProc( HWND hwnd
, UINT msg
,
2917 WPARAM wParam
, LPARAM lParam
)
2919 WND
*wnd
= WIN_FindWndPtr( hwnd
);
2920 LRESULT res
= ComboLBWndProc_locked(wnd
,msg
,wParam
,lParam
);
2922 WIN_ReleaseWndPtr(wnd
);