4 * Copyright 1996 Alexandre Julliard
7 #define NO_TRANSITION_TYPES /* This file is Win32-clean */
28 /* Items array granularity */
29 #define LB_ARRAY_GRANULARITY 16
31 /* Scrolling timeout in ms */
32 #define LB_SCROLL_TIMEOUT 50
34 /* Listbox system timer id */
40 LPSTR str
; /* Item text */
41 BOOL32 selected
; /* Is item selected? */
42 UINT32 height
; /* Item height (only for OWNERDRAWVARIABLE) */
43 DWORD data
; /* User data */
46 /* Listbox structure */
49 HANDLE32 heap
; /* Heap for this listbox */
50 HWND32 owner
; /* Owner window */
51 UINT32 style
; /* Window style */
52 INT32 width
; /* Window width */
53 INT32 height
; /* Window height */
54 LB_ITEMDATA
*items
; /* Array of items */
55 INT32 nb_items
; /* Number of items */
56 INT32 top_item
; /* Top visible item */
57 INT32 selected_item
; /* Selected item */
58 INT32 focus_item
; /* Item that has the focus */
59 INT32 anchor_item
; /* Anchor item for extended selection */
60 INT32 item_height
; /* Default item height */
61 INT32 page_size
; /* Items per listbox page */
62 INT32 column_width
; /* Column width for multi-column listboxes */
63 INT32 horz_extent
; /* Horizontal extent (0 if no hscroll) */
64 INT32 horz_pos
; /* Horizontal position */
65 INT32 nb_tabs
; /* Number of tabs in array */
66 INT32
*tabs
; /* Array of tabs */
67 BOOL32 caret_on
; /* Is caret on? */
68 HFONT32 font
; /* Current font */
69 LCID locale
; /* Current locale for string comparisons */
73 #define IS_OWNERDRAW(descr) \
74 ((descr)->style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE))
76 #define HAS_STRINGS(descr) \
77 (!IS_OWNERDRAW(descr) || ((descr)->style & LBS_HASSTRINGS))
79 #define SEND_NOTIFICATION(wnd,descr,code) \
80 (SendMessage32A( (descr)->owner, WM_COMMAND, \
81 MAKEWPARAM( (wnd)->wIDmenu, (code) ), (wnd)->hwndSelf ))
83 /* Current timer status */
93 static TIMER_DIRECTION LISTBOX_Timer
= LB_TIMER_NONE
;
96 /***********************************************************************
99 void LISTBOX_Dump( WND
*wnd
)
103 LB_DESCR
*descr
= *(LB_DESCR
**)wnd
->wExtra
;
105 printf( "Listbox:\n" );
106 printf( "hwnd=%04x descr=%08x heap=%08x items=%d top=%d\n",
107 wnd
->hwndSelf
, (UINT32
)descr
, descr
->heap
, descr
->nb_items
,
109 for (i
= 0, item
= descr
->items
; i
< descr
->nb_items
; i
++, item
++)
111 printf( "%4d: %-40s %d %08lx %3d\n",
112 i
, item
->str
, item
->selected
, item
->data
, item
->height
);
117 /***********************************************************************
118 * LISTBOX_GetCurrentPageSize
120 * Return the current page size
122 static INT32
LISTBOX_GetCurrentPageSize( WND
*wnd
, LB_DESCR
*descr
)
125 if (!(descr
->style
& LBS_OWNERDRAWVARIABLE
)) return descr
->page_size
;
126 for (i
= descr
->top_item
, height
= 0; i
< descr
->nb_items
; i
++)
128 if ((height
+= descr
->items
[i
].height
) > descr
->height
) break;
130 if (i
== descr
->top_item
) return 1;
131 else return i
- descr
->top_item
;
135 /***********************************************************************
136 * LISTBOX_GetMaxTopIndex
138 * Return the maximum possible index for the top of the listbox.
140 static INT32
LISTBOX_GetMaxTopIndex( WND
*wnd
, LB_DESCR
*descr
)
144 if (descr
->style
& LBS_OWNERDRAWVARIABLE
)
146 page
= descr
->height
;
147 for (max
= descr
->nb_items
- 1; max
>= 0; max
--)
148 if ((page
-= descr
->items
[max
].height
) < 0) break;
149 if (max
< descr
->nb_items
- 1) max
++;
151 else if (descr
->style
& LBS_MULTICOLUMN
)
153 if ((page
= descr
->width
/ descr
->column_width
) < 1) page
= 1;
154 max
= (descr
->nb_items
+ descr
->page_size
- 1) / descr
->page_size
;
155 max
= (max
- page
) * descr
->page_size
;
159 max
= descr
->nb_items
- descr
->page_size
;
161 if (max
< 0) max
= 0;
166 /***********************************************************************
167 * LISTBOX_UpdateScroll
169 * Update the scrollbars. Should be called whenever the content
170 * of the listbox changes.
172 static void LISTBOX_UpdateScroll( WND
*wnd
, LB_DESCR
*descr
)
176 if (descr
->style
& LBS_NOREDRAW
) return;
177 info
.cbSize
= sizeof(info
);
179 if (descr
->style
& LBS_MULTICOLUMN
)
182 info
.nMax
= (descr
->nb_items
- 1) / descr
->page_size
;
183 info
.nPos
= descr
->top_item
/ descr
->page_size
;
184 info
.nPage
= descr
->width
/ descr
->column_width
;
185 if (info
.nPage
< 1) info
.nPage
= 1;
186 info
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
187 if (descr
->style
& LBS_DISABLENOSCROLL
)
188 info
.fMask
|= SIF_DISABLENOSCROLL
;
189 SetScrollInfo32( wnd
->hwndSelf
, SB_HORZ
, &info
, TRUE
);
191 info
.fMask
= SIF_RANGE
;
192 SetScrollInfo32( wnd
->hwndSelf
, SB_VERT
, &info
, TRUE
);
197 info
.nMax
= descr
->nb_items
- 1;
198 info
.nPos
= descr
->top_item
;
199 info
.nPage
= LISTBOX_GetCurrentPageSize( wnd
, descr
);
200 info
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
201 if (descr
->style
& LBS_DISABLENOSCROLL
)
202 info
.fMask
|= SIF_DISABLENOSCROLL
;
203 SetScrollInfo32( wnd
->hwndSelf
, SB_VERT
, &info
, TRUE
);
205 if (descr
->horz_extent
)
208 info
.nMax
= descr
->horz_extent
- 1;
209 info
.nPos
= descr
->horz_pos
;
210 info
.nPage
= descr
->width
;
211 info
.fMask
= SIF_RANGE
| SIF_POS
| SIF_PAGE
;
212 if (descr
->style
& LBS_DISABLENOSCROLL
)
213 info
.fMask
|= SIF_DISABLENOSCROLL
;
214 SetScrollInfo32( wnd
->hwndSelf
, SB_HORZ
, &info
, TRUE
);
220 /***********************************************************************
223 * Set the top item of the listbox, scrolling up or down if necessary.
225 static LRESULT
LISTBOX_SetTopItem( WND
*wnd
, LB_DESCR
*descr
, INT32 index
,
228 INT32 max
= LISTBOX_GetMaxTopIndex( wnd
, descr
);
229 if (index
> max
) index
= max
;
230 if (index
< 0) index
= 0;
231 if (descr
->style
& LBS_MULTICOLUMN
) index
-= index
% descr
->page_size
;
232 if (descr
->top_item
== index
) return LB_OKAY
;
233 if (descr
->style
& LBS_MULTICOLUMN
)
235 INT32 diff
= (descr
->top_item
- index
) / descr
->page_size
* descr
->column_width
;
236 if (scroll
&& (abs(diff
) < descr
->width
))
237 ScrollWindow32( wnd
->hwndSelf
, diff
, 0, NULL
, NULL
);
244 if (descr
->style
& LBS_OWNERDRAWVARIABLE
)
248 if (index
> descr
->top_item
)
250 for (i
= index
- 1; i
>= descr
->top_item
; i
--)
251 diff
-= descr
->items
[i
].height
;
255 for (i
= index
; i
< descr
->top_item
; i
++)
256 diff
+= descr
->items
[i
].height
;
260 diff
= (descr
->top_item
- index
) * descr
->item_height
;
262 if (abs(diff
) < descr
->height
)
263 ScrollWindow32( wnd
->hwndSelf
, 0, diff
, NULL
, NULL
);
267 if (!scroll
) InvalidateRect32( wnd
->hwndSelf
, NULL
, TRUE
);
268 descr
->top_item
= index
;
269 LISTBOX_UpdateScroll( wnd
, descr
);
274 /***********************************************************************
277 * Update the page size. Should be called when the size of
278 * the client area or the item height changes.
280 static void LISTBOX_UpdatePage( WND
*wnd
, LB_DESCR
*descr
)
284 if ((page_size
= descr
->height
/ descr
->item_height
) < 1) page_size
= 1;
285 if (page_size
== descr
->page_size
) return;
286 descr
->page_size
= page_size
;
287 if (descr
->style
& LBS_MULTICOLUMN
)
288 InvalidateRect32( wnd
->hwndSelf
, NULL
, TRUE
);
289 LISTBOX_SetTopItem( wnd
, descr
, descr
->top_item
, FALSE
);
293 /***********************************************************************
296 * Update the size of the listbox. Should be called when the size of
297 * the client area changes.
299 static void LISTBOX_UpdateSize( WND
*wnd
, LB_DESCR
*descr
)
303 GetClientRect32( wnd
->hwndSelf
, &rect
);
304 descr
->width
= rect
.right
- rect
.left
;
305 descr
->height
= rect
.bottom
- rect
.top
;
306 if (!(descr
->style
& LBS_NOINTEGRALHEIGHT
))
308 if ((descr
->height
> descr
->item_height
) &&
309 (descr
->height
% descr
->item_height
))
311 dprintf_listbox(stddeb
, "Listbox %04x: changing height %d -> %d\n",
312 wnd
->hwndSelf
, descr
->height
,
313 descr
->height
- descr
->height
%descr
->item_height
);
314 SetWindowPos( wnd
->hwndSelf
, 0, 0, 0,
315 wnd
->rectWindow
.right
- wnd
->rectWindow
.left
,
316 wnd
->rectWindow
.bottom
- wnd
->rectWindow
.top
-
317 (descr
->height
% descr
->item_height
),
318 SWP_NOZORDER
| SWP_NOACTIVATE
| SWP_NOMOVE
);
322 dprintf_listbox( stddeb
, "Listbox %04x: new size = %d,%d\n",
323 wnd
->hwndSelf
, descr
->width
, descr
->height
);
324 LISTBOX_UpdatePage( wnd
, descr
);
325 LISTBOX_UpdateScroll( wnd
, descr
);
329 /***********************************************************************
330 * LISTBOX_GetItemRect
332 * Get the rectangle enclosing an item, in listbox client coordinates.
333 * Return 1 if the rectangle is (partially) visible, 0 if hidden, -1 on error.
335 static LRESULT
LISTBOX_GetItemRect( WND
*wnd
, LB_DESCR
*descr
, INT32 index
,
338 /* Index <= 0 is legal even on empty listboxes */
339 if (index
&& (index
>= descr
->nb_items
)) return -1;
340 SetRect32( rect
, 0, 0, descr
->width
, descr
->height
);
341 if (descr
->style
& LBS_MULTICOLUMN
)
343 INT32 col
= (index
/ descr
->page_size
) -
344 (descr
->top_item
/ descr
->page_size
);
345 rect
->left
+= col
* descr
->column_width
;
346 rect
->right
= rect
->left
+ descr
->column_width
;
347 rect
->top
+= (index
% descr
->page_size
) * descr
->item_height
;
348 rect
->bottom
= rect
->top
+ descr
->item_height
;
350 else if (descr
->style
& LBS_OWNERDRAWVARIABLE
)
353 if (index
< descr
->top_item
)
355 for (i
= descr
->top_item
-1; i
>= index
; i
--)
356 rect
->top
-= descr
->items
[i
].height
;
360 for (i
= descr
->top_item
; i
< index
; i
++)
361 rect
->top
+= descr
->items
[i
].height
;
363 rect
->bottom
= rect
->top
+ descr
->items
[index
].height
;
364 rect
->right
+= descr
->horz_pos
;
368 rect
->top
+= (index
- descr
->top_item
) * descr
->item_height
;
369 rect
->bottom
= rect
->top
+ descr
->item_height
;
370 rect
->right
+= descr
->horz_pos
;
373 return ((rect
->left
< descr
->width
) && (rect
->right
> 0) &&
374 (rect
->top
< descr
->height
) && (rect
->bottom
> 0));
378 /***********************************************************************
379 * LISTBOX_GetItemFromPoint
381 * Return the item nearest from point (x,y) (in client coordinates).
383 static INT32
LISTBOX_GetItemFromPoint( WND
*wnd
, LB_DESCR
*descr
,
386 INT32 index
= descr
->top_item
;
388 if (!descr
->nb_items
) return -1; /* No items */
389 if (descr
->style
& LBS_OWNERDRAWVARIABLE
)
394 while (index
< descr
->nb_items
)
396 if ((pos
+= descr
->items
[index
].height
) > y
) break;
405 if ((pos
-= descr
->items
[index
].height
) <= y
) break;
409 else if (descr
->style
& LBS_MULTICOLUMN
)
411 if (y
>= descr
->item_height
* descr
->page_size
) return -1;
412 if (y
>= 0) index
+= y
/ descr
->item_height
;
413 if (x
>= 0) index
+= (x
/ descr
->column_width
) * descr
->page_size
;
414 else index
-= (((x
+ 1) / descr
->column_width
) - 1) * descr
->page_size
;
418 index
+= (y
/ descr
->item_height
);
420 if (index
< 0) return 0;
421 if (index
>= descr
->nb_items
) return -1;
426 /***********************************************************************
431 static void LISTBOX_PaintItem( WND
*wnd
, LB_DESCR
*descr
, HDC32 hdc
,
432 const RECT32
*rect
, INT32 index
, UINT32 action
)
434 LB_ITEMDATA
*item
= NULL
;
435 if (index
< descr
->nb_items
) item
= &descr
->items
[index
];
437 if (IS_OWNERDRAW(descr
))
439 DRAWITEMSTRUCT32 dis
;
440 dis
.CtlType
= ODT_LISTBOX
;
441 dis
.CtlID
= wnd
->wIDmenu
;
442 dis
.hwndItem
= wnd
->hwndSelf
;
443 dis
.itemAction
= action
;
447 if (item
&& item
->selected
) dis
.itemState
|= ODS_SELECTED
;
448 if ((descr
->focus_item
== index
) &&
450 (GetFocus32() == wnd
->hwndSelf
)) dis
.itemState
|= ODS_FOCUS
;
451 if (wnd
->dwStyle
& WS_DISABLED
) dis
.itemState
|= ODS_DISABLED
;
452 dis
.itemData
= item
? item
->data
: 0;
454 dprintf_listbox( stddeb
, "Listbox %04x: drawitem %d (%s) action=%02x "
455 "state=%02x rect=%d,%d-%d,%d\n",
456 wnd
->hwndSelf
, index
, item
? item
->str
: "", action
,
457 dis
.itemState
, rect
->left
, rect
->top
,
458 rect
->right
, rect
->bottom
);
459 SendMessage32A(descr
->owner
, WM_DRAWITEM
, wnd
->wIDmenu
, (LPARAM
)&dis
);
463 if (action
== ODA_FOCUS
)
465 DrawFocusRect32( hdc
, rect
);
468 if (item
&& item
->selected
)
470 SetBkColor( hdc
, GetSysColor( COLOR_HIGHLIGHT
) );
471 SetTextColor( hdc
, GetSysColor( COLOR_HIGHLIGHTTEXT
) );
475 SetBkColor( hdc
, GetSysColor( COLOR_WINDOW
) );
476 if (wnd
->dwStyle
& WS_DISABLED
)
477 SetTextColor( hdc
, GetSysColor( COLOR_GRAYTEXT
) );
479 SetTextColor( hdc
, GetSysColor( COLOR_WINDOWTEXT
) );
481 dprintf_listbox( stddeb
, "Listbox %04x: painting %d (%s) action=%02x"
482 "rect=%d,%d-%d,%d\n",
483 wnd
->hwndSelf
, index
, item
? item
->str
: "", action
,
484 rect
->left
, rect
->top
, rect
->right
, rect
->bottom
);
485 /* FIXME: check LBS_USETABSTOPS style */
487 ExtTextOut32A( hdc
, rect
->left
+ 1, rect
->top
+ 1,
488 ETO_OPAQUE
| ETO_CLIPPED
, rect
, item
->str
,
489 strlen(item
->str
), NULL
);
491 ExtTextOut32A( hdc
, rect
->left
+ 1, rect
->top
+ 1,
492 ETO_OPAQUE
| ETO_CLIPPED
, rect
, NULL
, 0, NULL
);
493 if ((descr
->focus_item
== index
) &&
495 (GetFocus32() == wnd
->hwndSelf
)) DrawFocusRect32( hdc
, rect
);
500 /***********************************************************************
503 * Change the redraw flag.
505 static void LISTBOX_SetRedraw( WND
*wnd
, LB_DESCR
*descr
, BOOL32 on
)
509 if (!(descr
->style
& LBS_NOREDRAW
)) return;
510 descr
->style
&= ~LBS_NOREDRAW
;
511 LISTBOX_UpdateScroll( wnd
, descr
);
513 else descr
->style
|= LBS_NOREDRAW
;
517 /***********************************************************************
518 * LISTBOX_RepaintItem
520 * Repaint a single item synchronously.
522 static void LISTBOX_RepaintItem( WND
*wnd
, LB_DESCR
*descr
, INT32 index
,
528 if (descr
->style
& LBS_NOREDRAW
) return;
529 if (LISTBOX_GetItemRect( wnd
, descr
, index
, &rect
) != 1) return;
530 if ((hdc
= GetDCEx32( wnd
->hwndSelf
, 0, DCX_CACHE
)))
533 if (descr
->font
) oldFont
= SelectObject32( hdc
, descr
->font
);
534 SetWindowOrgEx32( hdc
, descr
->horz_pos
, 0, NULL
);
535 LISTBOX_PaintItem( wnd
, descr
, hdc
, &rect
, index
, action
);
536 if (oldFont
) SelectObject32( hdc
, oldFont
);
537 ReleaseDC32( wnd
->hwndSelf
, hdc
);
542 /***********************************************************************
543 * LISTBOX_InitStorage
545 static LRESULT
LISTBOX_InitStorage( WND
*wnd
, LB_DESCR
*descr
, INT32 nb_items
,
550 nb_items
+= LB_ARRAY_GRANULARITY
- 1;
551 nb_items
-= (nb_items
% LB_ARRAY_GRANULARITY
);
553 nb_items
+= HeapSize( descr
->heap
, 0, descr
->items
) / sizeof(*item
);
554 if (!(item
= HeapReAlloc( descr
->heap
, 0, descr
->items
,
555 nb_items
* sizeof(LB_ITEMDATA
) )))
557 SEND_NOTIFICATION( wnd
, descr
, LBN_ERRSPACE
);
565 /***********************************************************************
566 * LISTBOX_SetTabStops
568 static BOOL32
LISTBOX_SetTabStops( WND
*wnd
, LB_DESCR
*descr
, INT32 count
,
569 LPINT32 tabs
, BOOL32 short_ints
)
571 if (!(descr
->style
& LBS_USETABSTOPS
)) return TRUE
;
572 if (descr
->tabs
) HeapFree( descr
->heap
, 0, descr
->tabs
);
573 if (!(descr
->nb_tabs
= count
))
578 /* FIXME: count = 1 */
579 if (!(descr
->tabs
= (INT32
*)HeapAlloc( descr
->heap
, 0,
580 descr
->nb_tabs
* sizeof(INT32
) )))
585 LPINT16 p
= (LPINT16
)tabs
;
586 for (i
= 0; i
< descr
->nb_tabs
; i
++) descr
->tabs
[i
] = *p
++;
588 else memcpy( descr
->tabs
, tabs
, descr
->nb_tabs
* sizeof(INT32
) );
589 /* FIXME: repaint the window? */
594 /***********************************************************************
597 static LRESULT
LISTBOX_GetText( WND
*wnd
, LB_DESCR
*descr
, INT32 index
,
600 if ((index
< 0) || (index
>= descr
->nb_items
)) return LB_ERR
;
601 if (HAS_STRINGS(descr
))
603 lstrcpy32A( buffer
, descr
->items
[index
].str
);
604 return strlen(buffer
);
608 memcpy( buffer
, &descr
->items
[index
].data
, sizeof(DWORD
) );
609 return sizeof(DWORD
);
614 /***********************************************************************
615 * LISTBOX_FindStringPos
617 * Find the nearest string located before a given string in sort order.
618 * If 'exact' is TRUE, return an error if we don't get an exact match.
620 static INT32
LISTBOX_FindStringPos( WND
*wnd
, LB_DESCR
*descr
, LPCSTR str
,
623 INT32 index
, min
, max
, res
= -1;
625 if (!(descr
->style
& LBS_SORT
)) return -1; /* Add it at the end */
627 max
= descr
->nb_items
;
630 index
= (min
+ max
) / 2;
631 if (HAS_STRINGS(descr
))
632 res
= lstrcmpi32A( descr
->items
[index
].str
, str
);
635 COMPAREITEMSTRUCT32 cis
;
636 cis
.CtlType
= ODT_LISTBOX
;
637 cis
.CtlID
= wnd
->wIDmenu
;
638 cis
.hwndItem
= wnd
->hwndSelf
;
640 cis
.itemData1
= descr
->items
[index
].data
;
642 cis
.itemData2
= (DWORD
)str
;
643 cis
.dwLocaleId
= descr
->locale
;
644 res
= SendMessage32A( descr
->owner
, WM_COMPAREITEM
,
645 wnd
->wIDmenu
, (LPARAM
)&cis
);
647 if (!res
) return index
;
648 if (res
> 0) max
= index
;
649 else min
= index
+ 1;
651 return exact
? -1 : max
;
655 /***********************************************************************
656 * LISTBOX_FindFileStrPos
658 * Find the nearest string located before a given string in directory
659 * sort order (i.e. first files, then directories, then drives).
661 static INT32
LISTBOX_FindFileStrPos( WND
*wnd
, LB_DESCR
*descr
, LPCSTR str
)
663 INT32 min
, max
, res
= -1;
665 if (!HAS_STRINGS(descr
))
666 return LISTBOX_FindStringPos( wnd
, descr
, str
, FALSE
);
668 max
= descr
->nb_items
;
671 INT32 index
= (min
+ max
) / 2;
672 const char *p
= descr
->items
[index
].str
;
673 if (*p
== '[') /* drive or directory */
675 if (*str
!= '[') res
= -1;
676 else if (p
[1] == '-') /* drive */
678 if (str
[1] == '-') res
= str
[2] - p
[2];
683 if (str
[1] == '-') res
= 1;
684 else res
= lstrcmpi32A( str
, p
);
689 if (*str
== '[') res
= 1;
690 else res
= lstrcmpi32A( str
, p
);
692 if (!res
) return index
;
693 if (res
< 0) max
= index
;
694 else min
= index
+ 1;
700 /***********************************************************************
703 * Find the item beginning with a given string.
705 static INT32
LISTBOX_FindString( WND
*wnd
, LB_DESCR
*descr
, INT32 start
,
706 LPCSTR str
, BOOL32 exact
)
711 if (start
>= descr
->nb_items
) start
= -1;
712 item
= descr
->items
+ start
+ 1;
713 if (HAS_STRINGS(descr
))
717 for (i
= start
+ 1; i
< descr
->nb_items
; i
++, item
++)
718 if (!lstrcmpi32A( str
, item
->str
)) return i
;
719 for (i
= 0, item
= descr
->items
; i
<= start
; i
++, item
++)
720 if (!lstrcmpi32A( str
, item
->str
)) return i
;
724 /* Special case for drives and directories: ignore prefix */
725 #define CHECK_DRIVE(item) \
726 if ((item)->str[0] == '[') \
728 if (!lstrncmpi32A( str, (item)->str+1, len )) return i; \
729 if (((item)->str[1] == '-') && !lstrncmpi32A(str,(item)->str+2,len)) \
733 INT32 len
= strlen(str
);
734 for (i
= start
+ 1; i
< descr
->nb_items
; i
++, item
++)
736 if (!lstrncmpi32A( str
, item
->str
, len
)) return i
;
739 for (i
= 0, item
= descr
->items
; i
<= start
; i
++, item
++)
741 if (!lstrncmpi32A( str
, item
->str
, len
)) return i
;
749 if (exact
&& (descr
->style
& LBS_SORT
))
750 /* If sorted, use a WM_COMPAREITEM binary search */
751 return LISTBOX_FindStringPos( wnd
, descr
, str
, TRUE
);
753 /* Otherwise use a linear search */
754 for (i
= start
+ 1; i
< descr
->nb_items
; i
++, item
++)
755 if (item
->data
== (DWORD
)str
) return i
;
756 for (i
= 0, item
= descr
->items
; i
<= start
; i
++, item
++)
757 if (item
->data
== (DWORD
)str
) return i
;
763 /***********************************************************************
764 * LISTBOX_GetSelCount
766 static LRESULT
LISTBOX_GetSelCount( WND
*wnd
, LB_DESCR
*descr
)
769 LB_ITEMDATA
*item
= descr
->items
;
771 if (!(descr
->style
& LBS_MULTIPLESEL
)) return LB_ERR
;
772 for (i
= count
= 0; i
< descr
->nb_items
; i
++, item
++)
773 if (item
->selected
) count
++;
778 /***********************************************************************
779 * LISTBOX_GetSelItems16
781 static LRESULT
LISTBOX_GetSelItems16( WND
*wnd
, LB_DESCR
*descr
, INT16 max
,
785 LB_ITEMDATA
*item
= descr
->items
;
787 if (!(descr
->style
& LBS_MULTIPLESEL
)) return LB_ERR
;
788 for (i
= count
= 0; (i
< descr
->nb_items
) && (count
< max
); i
++, item
++)
789 if (item
->selected
) array
[count
++] = (INT16
)i
;
794 /***********************************************************************
795 * LISTBOX_GetSelItems32
797 static LRESULT
LISTBOX_GetSelItems32( WND
*wnd
, LB_DESCR
*descr
, INT32 max
,
801 LB_ITEMDATA
*item
= descr
->items
;
803 if (!(descr
->style
& LBS_MULTIPLESEL
)) return LB_ERR
;
804 for (i
= count
= 0; (i
< descr
->nb_items
) && (count
< max
); i
++, item
++)
805 if (item
->selected
) array
[count
++] = i
;
810 /***********************************************************************
813 static LRESULT
LISTBOX_Paint( WND
*wnd
, LB_DESCR
*descr
, HDC32 hdc
)
815 INT32 i
, col_pos
= descr
->page_size
- 1;
819 SetRect32( &rect
, 0, 0, descr
->width
, descr
->height
);
820 if (descr
->style
& LBS_NOREDRAW
) return 0;
821 if (descr
->style
& LBS_MULTICOLUMN
)
822 rect
.right
= rect
.left
+ descr
->column_width
;
823 else if (descr
->horz_pos
)
825 SetWindowOrgEx32( hdc
, descr
->horz_pos
, 0, NULL
);
826 rect
.right
+= descr
->horz_pos
;
829 if (descr
->font
) oldFont
= SelectObject32( hdc
, descr
->font
);
831 if (!descr
->nb_items
&& (descr
->focus_item
!= -1) && descr
->caret_on
&&
832 (GetFocus32() == wnd
->hwndSelf
))
834 /* Special case for empty listbox: paint focus rect */
835 rect
.bottom
= rect
.top
+ descr
->item_height
;
836 LISTBOX_PaintItem( wnd
, descr
, hdc
, &rect
, descr
->focus_item
,
838 rect
.top
= rect
.bottom
;
841 for (i
= descr
->top_item
; i
< descr
->nb_items
; i
++)
843 if (!(descr
->style
& LBS_OWNERDRAWVARIABLE
))
844 rect
.bottom
= rect
.top
+ descr
->item_height
;
846 rect
.bottom
= rect
.top
+ descr
->items
[i
].height
;
848 LISTBOX_PaintItem( wnd
, descr
, hdc
, &rect
, i
, ODA_DRAWENTIRE
);
849 rect
.top
= rect
.bottom
;
851 if ((descr
->style
& LBS_MULTICOLUMN
) && !col_pos
)
853 if (!IS_OWNERDRAW(descr
))
855 /* Clear the bottom of the column */
856 SetBkColor( hdc
, GetSysColor( COLOR_WINDOW
) );
857 if (rect
.top
< descr
->height
)
859 rect
.bottom
= descr
->height
;
860 ExtTextOut32A( hdc
, 0, 0, ETO_OPAQUE
| ETO_CLIPPED
,
861 &rect
, NULL
, 0, NULL
);
865 /* Go to the next column */
866 rect
.left
+= descr
->column_width
;
867 rect
.right
+= descr
->column_width
;
869 col_pos
= descr
->page_size
- 1;
874 if (rect
.top
>= descr
->height
) break;
878 if (!IS_OWNERDRAW(descr
))
880 /* Clear the remainder of the client area */
881 SetBkColor( hdc
, GetSysColor( COLOR_WINDOW
) );
882 if (rect
.top
< descr
->height
)
884 rect
.bottom
= descr
->height
;
885 ExtTextOut32A( hdc
, 0, 0, ETO_OPAQUE
| ETO_CLIPPED
,
886 &rect
, NULL
, 0, NULL
);
888 if (rect
.right
< descr
->width
)
890 rect
.left
= rect
.right
;
891 rect
.right
= descr
->width
;
893 rect
.bottom
= descr
->height
;
894 ExtTextOut32A( hdc
, 0, 0, ETO_OPAQUE
| ETO_CLIPPED
,
895 &rect
, NULL
, 0, NULL
);
898 if (oldFont
) SelectObject32( hdc
, oldFont
);
903 /***********************************************************************
904 * LISTBOX_InvalidateItems
906 * Invalidate all items from a given item. If the specified item is not
907 * visible, nothing happens.
909 static void LISTBOX_InvalidateItems( WND
*wnd
, LB_DESCR
*descr
, INT32 index
)
913 if (LISTBOX_GetItemRect( wnd
, descr
, index
, &rect
) == 1)
915 rect
.bottom
= descr
->height
;
916 InvalidateRect32( wnd
->hwndSelf
, &rect
, TRUE
);
917 if (descr
->style
& LBS_MULTICOLUMN
)
919 /* Repaint the other columns */
920 rect
.left
= rect
.right
;
921 rect
.right
= descr
->width
;
923 InvalidateRect32( wnd
->hwndSelf
, &rect
, TRUE
);
929 /***********************************************************************
930 * LISTBOX_GetItemHeight
932 static LRESULT
LISTBOX_GetItemHeight( WND
*wnd
, LB_DESCR
*descr
, INT32 index
)
934 if (descr
->style
& LBS_OWNERDRAWVARIABLE
)
936 if ((index
< 0) || (index
>= descr
->nb_items
)) return LB_ERR
;
937 return descr
->items
[index
].height
;
939 else return descr
->item_height
;
943 /***********************************************************************
944 * LISTBOX_SetItemHeight
946 static LRESULT
LISTBOX_SetItemHeight( WND
*wnd
, LB_DESCR
*descr
, INT32 index
,
949 if (!height
) height
= 1;
951 if (descr
->style
& LBS_OWNERDRAWVARIABLE
)
953 if ((index
< 0) || (index
>= descr
->nb_items
)) return LB_ERR
;
954 dprintf_listbox( stddeb
, "Listbox %04x: item %d height = %d\n",
955 wnd
->hwndSelf
, index
, height
);
956 descr
->items
[index
].height
= height
;
957 LISTBOX_UpdateScroll( wnd
, descr
);
958 LISTBOX_InvalidateItems( wnd
, descr
, index
);
960 else if (height
!= descr
->item_height
)
962 dprintf_listbox( stddeb
, "Listbox %04x: new height = %d\n",
963 wnd
->hwndSelf
, height
);
964 descr
->item_height
= height
;
965 LISTBOX_UpdatePage( wnd
, descr
);
966 LISTBOX_UpdateScroll( wnd
, descr
);
967 InvalidateRect32( wnd
->hwndSelf
, 0, TRUE
);
973 /***********************************************************************
974 * LISTBOX_SetHorizontalPos
976 static void LISTBOX_SetHorizontalPos( WND
*wnd
, LB_DESCR
*descr
, INT32 pos
)
980 if (pos
> descr
->horz_extent
- descr
->width
)
981 pos
= descr
->horz_extent
- descr
->width
;
982 if (pos
< 0) pos
= 0;
983 if (!(diff
= descr
->horz_pos
- pos
)) return;
984 dprintf_listbox( stddeb
, "Listbox %04x: new horz pos = %d\n",
985 wnd
->hwndSelf
, pos
);
986 descr
->horz_pos
= pos
;
987 LISTBOX_UpdateScroll( wnd
, descr
);
988 if (abs(diff
) < descr
->width
)
989 ScrollWindow32( wnd
->hwndSelf
, diff
, 0, NULL
, NULL
);
991 InvalidateRect32( wnd
->hwndSelf
, NULL
, TRUE
);
995 /***********************************************************************
996 * LISTBOX_SetHorizontalExtent
998 static LRESULT
LISTBOX_SetHorizontalExtent( WND
*wnd
, LB_DESCR
*descr
,
1001 if (!descr
->horz_extent
|| (descr
->style
& LBS_MULTICOLUMN
))
1003 if (extent
<= 0) extent
= 1;
1004 if (extent
== descr
->horz_extent
) return LB_OKAY
;
1005 dprintf_listbox( stddeb
, "Listbox %04x: new horz extent = %d\n",
1006 wnd
->hwndSelf
, extent
);
1007 descr
->horz_extent
= extent
;
1008 if (descr
->horz_pos
> extent
- descr
->width
)
1009 LISTBOX_SetHorizontalPos( wnd
, descr
, extent
- descr
->width
);
1011 LISTBOX_UpdateScroll( wnd
, descr
);
1016 /***********************************************************************
1017 * LISTBOX_SetColumnWidth
1019 static LRESULT
LISTBOX_SetColumnWidth( WND
*wnd
, LB_DESCR
*descr
, UINT32 width
)
1021 width
+= 2; /* For left and right margin */
1022 if (width
== descr
->column_width
) return LB_OKAY
;
1023 dprintf_listbox( stddeb
, "Listbox %04x: new column width = %d\n",
1024 wnd
->hwndSelf
, width
);
1025 descr
->column_width
= width
;
1026 LISTBOX_UpdatePage( wnd
, descr
);
1031 /***********************************************************************
1034 * Returns the item height.
1036 static INT32
LISTBOX_SetFont( WND
*wnd
, LB_DESCR
*descr
, HFONT32 font
)
1039 HFONT32 oldFont
= 0;
1044 if (!(hdc
= GetDCEx32( wnd
->hwndSelf
, 0, DCX_CACHE
)))
1046 fprintf( stderr
, "LISTBOX_SetFont: unable to get DC\n" );
1049 if (font
) oldFont
= SelectObject32( hdc
, font
);
1050 GetTextMetrics32A( hdc
, &tm
);
1051 if (oldFont
) SelectObject32( hdc
, oldFont
);
1052 ReleaseDC32( wnd
->hwndSelf
, hdc
);
1053 if (!IS_OWNERDRAW(descr
))
1054 LISTBOX_SetItemHeight( wnd
, descr
, 0, tm
.tmHeight
+ 2 );
1055 return tm
.tmHeight
+ 2;
1059 /***********************************************************************
1060 * LISTBOX_MakeItemVisible
1062 * Make sure that a given item is partially or fully visible.
1064 static void LISTBOX_MakeItemVisible( WND
*wnd
, LB_DESCR
*descr
, INT32 index
,
1069 if (index
<= descr
->top_item
) top
= index
;
1070 else if (descr
->style
& LBS_MULTICOLUMN
)
1072 INT32 cols
= descr
->width
;
1073 if (!fully
) cols
+= descr
->column_width
- 1;
1074 if (cols
>= descr
->column_width
) cols
/= descr
->column_width
;
1076 if (index
< descr
->top_item
+ (descr
->page_size
* cols
)) return;
1077 top
= index
- descr
->page_size
* (cols
- 1);
1079 else if (descr
->style
& LBS_OWNERDRAWVARIABLE
)
1081 INT32 height
= fully
? descr
->items
[index
].height
: 1;
1082 for (top
= index
; top
> descr
->top_item
; top
--)
1083 if ((height
+= descr
->items
[top
-1].height
) > descr
->height
) break;
1087 if (index
< descr
->top_item
+ descr
->page_size
) return;
1088 if (!fully
&& (index
== descr
->top_item
+ descr
->page_size
) &&
1089 (descr
->height
> (descr
->page_size
* descr
->item_height
))) return;
1090 top
= index
- descr
->page_size
+ 1;
1092 LISTBOX_SetTopItem( wnd
, descr
, top
, TRUE
);
1096 /***********************************************************************
1097 * LISTBOX_SelectItemRange
1099 * Select a range of items. Should only be used on a MULTIPLESEL listbox.
1101 static LRESULT
LISTBOX_SelectItemRange( WND
*wnd
, LB_DESCR
*descr
, INT32 first
,
1102 INT32 last
, BOOL32 on
)
1106 /* A few sanity checks */
1108 if (!(descr
->style
& LBS_MULTIPLESEL
)) return LB_ERR
;
1109 if (last
== -1) last
= descr
->nb_items
- 1;
1110 if ((first
< 0) || (first
>= descr
->nb_items
)) return LB_ERR
;
1111 if ((last
< 0) || (last
>= descr
->nb_items
)) return LB_ERR
;
1112 /* selected_item reflects last selected/unselected item on multiple sel */
1113 descr
->selected_item
= last
;
1115 if (on
) /* Turn selection on */
1117 for (i
= first
; i
<= last
; i
++)
1119 if (descr
->items
[i
].selected
) continue;
1120 descr
->items
[i
].selected
= TRUE
;
1121 LISTBOX_RepaintItem( wnd
, descr
, i
, ODA_SELECT
);
1124 else /* Turn selection off */
1126 for (i
= first
; i
<= last
; i
++)
1128 if (!descr
->items
[i
].selected
) continue;
1129 descr
->items
[i
].selected
= FALSE
;
1130 LISTBOX_RepaintItem( wnd
, descr
, i
, ODA_SELECT
);
1137 /***********************************************************************
1138 * LISTBOX_SetCaretIndex
1140 static LRESULT
LISTBOX_SetCaretIndex( WND
*wnd
, LB_DESCR
*descr
, INT32 index
,
1141 BOOL32 fully_visible
)
1143 INT32 oldfocus
= descr
->focus_item
;
1145 if ((index
< -1) || (index
>= descr
->nb_items
)) return LB_ERR
;
1146 if (index
== oldfocus
) return LB_OKAY
;
1147 descr
->focus_item
= index
;
1148 if ((oldfocus
!= -1) && descr
->caret_on
&& (GetFocus32() == wnd
->hwndSelf
))
1149 LISTBOX_RepaintItem( wnd
, descr
, oldfocus
, ODA_FOCUS
);
1152 LISTBOX_MakeItemVisible( wnd
, descr
, index
, fully_visible
);
1153 if (descr
->caret_on
&& (GetFocus32() == wnd
->hwndSelf
))
1154 LISTBOX_RepaintItem( wnd
, descr
, index
, ODA_FOCUS
);
1160 /***********************************************************************
1161 * LISTBOX_SetSelection
1163 static LRESULT
LISTBOX_SetSelection( WND
*wnd
, LB_DESCR
*descr
, INT32 index
,
1164 BOOL32 on
, BOOL32 send_notify
)
1166 if ((index
< -1) || (index
>= descr
->nb_items
)) return LB_ERR
;
1167 if (descr
->style
& LBS_MULTIPLESEL
)
1169 if (index
== -1) /* Select all items */
1170 return LISTBOX_SelectItemRange( wnd
, descr
, 0, -1, on
);
1171 else /* Only one item */
1172 return LISTBOX_SelectItemRange( wnd
, descr
, index
, index
, on
);
1176 INT32 oldsel
= descr
->selected_item
;
1177 if (index
== oldsel
) return LB_OKAY
;
1178 if (oldsel
!= -1) descr
->items
[oldsel
].selected
= FALSE
;
1179 if (index
!= -1) descr
->items
[index
].selected
= TRUE
;
1180 descr
->selected_item
= index
;
1181 if (oldsel
!= -1) LISTBOX_RepaintItem( wnd
, descr
, oldsel
, ODA_SELECT
);
1182 if (index
!= -1) LISTBOX_RepaintItem( wnd
, descr
, index
, ODA_SELECT
);
1183 if (send_notify
) SEND_NOTIFICATION( wnd
, descr
,
1184 (index
!= -1) ? LBN_SELCHANGE
: LBN_SELCANCEL
);
1190 /***********************************************************************
1193 * Change the caret position and extend the selection to the new caret.
1195 static void LISTBOX_MoveCaret( WND
*wnd
, LB_DESCR
*descr
, INT32 index
,
1196 BOOL32 fully_visible
)
1198 LISTBOX_SetCaretIndex( wnd
, descr
, index
, fully_visible
);
1199 if (descr
->style
& LBS_EXTENDEDSEL
)
1201 if (descr
->anchor_item
!= -1)
1203 INT32 first
= MIN( descr
->focus_item
, descr
->anchor_item
);
1204 INT32 last
= MAX( descr
->focus_item
, descr
->anchor_item
);
1206 LISTBOX_SelectItemRange( wnd
, descr
, 0, first
- 1, FALSE
);
1207 LISTBOX_SelectItemRange( wnd
, descr
, last
+ 1, -1, FALSE
);
1208 LISTBOX_SelectItemRange( wnd
, descr
, first
, last
, TRUE
);
1211 else if (!(descr
->style
& LBS_MULTIPLESEL
) && (descr
->selected_item
!= -1))
1213 /* Set selection to new caret item */
1214 LISTBOX_SetSelection( wnd
, descr
, index
, TRUE
, FALSE
);
1219 /***********************************************************************
1220 * LISTBOX_InsertItem
1222 static LRESULT
LISTBOX_InsertItem( WND
*wnd
, LB_DESCR
*descr
, INT32 index
,
1223 LPSTR str
, DWORD data
)
1228 if (index
== -1) index
= descr
->nb_items
;
1229 else if ((index
< 0) || (index
> descr
->nb_items
)) return LB_ERR
;
1230 if (!descr
->items
) max_items
= 0;
1231 else max_items
= HeapSize( descr
->heap
, 0, descr
->items
) / sizeof(*item
);
1232 if (descr
->nb_items
== max_items
)
1234 /* We need to grow the array */
1235 max_items
+= LB_ARRAY_GRANULARITY
;
1236 if (!(item
= HeapReAlloc( descr
->heap
, 0, descr
->items
,
1237 max_items
* sizeof(LB_ITEMDATA
) )))
1239 SEND_NOTIFICATION( wnd
, descr
, LBN_ERRSPACE
);
1242 descr
->items
= item
;
1245 /* Insert the item structure */
1247 item
= &descr
->items
[index
];
1248 if (index
< descr
->nb_items
)
1249 RtlMoveMemory( item
+ 1, item
,
1250 (descr
->nb_items
- index
) * sizeof(LB_ITEMDATA
) );
1254 item
->selected
= FALSE
;
1257 /* Get item height */
1259 if (descr
->style
& LBS_OWNERDRAWVARIABLE
)
1261 MEASUREITEMSTRUCT32 mis
;
1262 mis
.CtlType
= ODT_LISTBOX
;
1263 mis
.CtlID
= wnd
->wIDmenu
;
1265 mis
.itemData
= descr
->items
[index
].data
;
1266 mis
.itemHeight
= descr
->item_height
;
1267 SendMessage32A( descr
->owner
, WM_MEASUREITEM
, wnd
->wIDmenu
,
1269 item
->height
= mis
.itemHeight
? mis
.itemHeight
: 1;
1270 dprintf_listbox( stddeb
, "Listbox %04x: measure item %d (%s) = %d\n",
1271 wnd
->hwndSelf
, index
, str
? str
: "", item
->height
);
1274 /* Repaint the items */
1276 LISTBOX_UpdateScroll( wnd
, descr
);
1277 LISTBOX_InvalidateItems( wnd
, descr
, index
);
1279 /* Move selection and focused item */
1281 if (index
<= descr
->selected_item
) descr
->selected_item
++;
1282 if (index
<= descr
->focus_item
)
1284 descr
->focus_item
++;
1285 LISTBOX_MoveCaret( wnd
, descr
, descr
->focus_item
- 1, FALSE
);
1288 /* If listbox was empty, set focus to the first item */
1290 if (descr
->nb_items
== 1) LISTBOX_SetCaretIndex( wnd
, descr
, 0, FALSE
);
1295 /***********************************************************************
1296 * LISTBOX_InsertString
1298 static LRESULT
LISTBOX_InsertString( WND
*wnd
, LB_DESCR
*descr
, INT32 index
,
1301 LPSTR new_str
= NULL
;
1305 if (HAS_STRINGS(descr
))
1307 if (!(new_str
= HEAP_strdupA( descr
->heap
, 0, str
)))
1309 SEND_NOTIFICATION( wnd
, descr
, LBN_ERRSPACE
);
1313 else data
= (DWORD
)str
;
1315 if (index
== -1) index
= descr
->nb_items
;
1316 if ((ret
= LISTBOX_InsertItem( wnd
, descr
, index
, new_str
, data
)) != 0)
1318 if (new_str
) HeapFree( descr
->heap
, 0, new_str
);
1322 dprintf_listbox( stddeb
, "Listbox %04x: added item %d '%s'\n",
1323 wnd
->hwndSelf
, index
, HAS_STRINGS(descr
) ? new_str
: "" );
1328 /***********************************************************************
1329 * LISTBOX_DeleteItem
1331 * Delete the content of an item. 'index' must be a valid index.
1333 static void LISTBOX_DeleteItem( WND
*wnd
, LB_DESCR
*descr
, INT32 index
)
1335 /* Note: Win 3.1 only sends DELETEITEM on owner-draw items,
1336 * while Win95 sends it for all items with user data.
1337 * It's probably better to send it too often than not
1338 * often enough, so this is what we do here.
1340 if (IS_OWNERDRAW(descr
) || descr
->items
[index
].data
)
1342 DELETEITEMSTRUCT32 dis
;
1343 dis
.CtlType
= ODT_LISTBOX
;
1344 dis
.CtlID
= wnd
->wIDmenu
;
1346 dis
.hwndItem
= wnd
->hwndSelf
;
1347 dis
.itemData
= descr
->items
[index
].data
;
1348 SendMessage32A( wnd
->hwndSelf
, WM_DELETEITEM
, wnd
->wIDmenu
,
1351 if (HAS_STRINGS(descr
) && descr
->items
[index
].str
)
1352 HeapFree( descr
->heap
, 0, descr
->items
[index
].str
);
1356 /***********************************************************************
1357 * LISTBOX_RemoveItem
1359 * Remove an item from the listbox and delete its content.
1361 static LRESULT
LISTBOX_RemoveItem( WND
*wnd
, LB_DESCR
*descr
, INT32 index
)
1366 if (index
== -1) index
= descr
->nb_items
- 1;
1367 else if ((index
< 0) || (index
>= descr
->nb_items
)) return LB_ERR
;
1368 LISTBOX_DeleteItem( wnd
, descr
, index
);
1370 /* Remove the item */
1372 item
= &descr
->items
[index
];
1373 if (index
< descr
->nb_items
-1)
1374 RtlMoveMemory( item
, item
+ 1,
1375 (descr
->nb_items
- index
- 1) * sizeof(LB_ITEMDATA
) );
1377 if (descr
->anchor_item
== descr
->nb_items
) descr
->anchor_item
--;
1379 /* Shrink the item array if possible */
1381 max_items
= HeapSize( descr
->heap
, 0, descr
->items
) / sizeof(LB_ITEMDATA
);
1382 if (descr
->nb_items
< max_items
- 2*LB_ARRAY_GRANULARITY
)
1384 max_items
-= LB_ARRAY_GRANULARITY
;
1385 item
= HeapReAlloc( descr
->heap
, 0, descr
->items
,
1386 max_items
* sizeof(LB_ITEMDATA
) );
1387 if (item
) descr
->items
= item
;
1390 /* Repaint the items */
1392 LISTBOX_UpdateScroll( wnd
, descr
);
1393 LISTBOX_InvalidateItems( wnd
, descr
, index
);
1395 /* Move selection and focused item */
1397 if (index
<= descr
->selected_item
) descr
->selected_item
--;
1398 if (index
<= descr
->focus_item
)
1400 descr
->focus_item
--;
1401 LISTBOX_MoveCaret( wnd
, descr
, descr
->focus_item
+ 1, FALSE
);
1407 /***********************************************************************
1408 * LISTBOX_ResetContent
1410 static void LISTBOX_ResetContent( WND
*wnd
, LB_DESCR
*descr
)
1414 for (i
= 0; i
< descr
->nb_items
; i
++) LISTBOX_DeleteItem( wnd
, descr
, i
);
1415 if (descr
->items
) HeapFree( descr
->heap
, 0, descr
->items
);
1416 descr
->nb_items
= 0;
1417 descr
->top_item
= 0;
1418 descr
->selected_item
= -1;
1419 descr
->focus_item
= 0;
1420 descr
->anchor_item
= -1;
1421 descr
->items
= NULL
;
1422 LISTBOX_UpdateScroll( wnd
, descr
);
1423 InvalidateRect32( wnd
->hwndSelf
, NULL
, TRUE
);
1427 /***********************************************************************
1430 static LRESULT
LISTBOX_SetCount( WND
*wnd
, LB_DESCR
*descr
, INT32 count
)
1434 if (HAS_STRINGS(descr
)) return LB_ERR
;
1435 /* FIXME: this is far from optimal... */
1436 if (count
> descr
->nb_items
)
1438 while (count
> descr
->nb_items
)
1439 if ((ret
= LISTBOX_InsertString( wnd
, descr
, -1, 0 )) < 0)
1442 else if (count
< descr
->nb_items
)
1444 while (count
< descr
->nb_items
)
1445 if ((ret
= LISTBOX_RemoveItem( wnd
, descr
, -1 )) < 0)
1452 /***********************************************************************
1455 LRESULT
LISTBOX_Directory( WND
*wnd
, LB_DESCR
*descr
, UINT32 attrib
,
1456 LPCSTR filespec
, BOOL32 long_names
)
1461 int count
, skip
, pos
;
1465 /* FIXME: should use FindFirstFile/FindNextFile */
1467 if (!filespec
) return LB_ERR
;
1468 if (!(ptr
= DOSFS_GetUnixFileName( filespec
, FALSE
))) return LB_ERR
;
1469 path
= HEAP_strdupA( SystemHeap
, 0, ptr
);
1470 p
= strrchr( path
, '/' );
1472 if (!(ptr
= DOSFS_ToDosFCBFormat( p
)))
1474 HeapFree( SystemHeap
, 0, path
);
1477 strcpy( mask
, ptr
);
1481 attrib
&= ~FA_LABEL
;
1482 while ((count
= DOSFS_FindNext( path
, mask
, NULL
, 0,
1483 attrib
, skip
, &entry
)) > 0)
1487 if (entry
.attr
& FA_DIRECTORY
)
1489 if (!(attrib
& DDL_DIRECTORY
) || !strcmp(entry
.name
,". "))
1491 if (long_names
) sprintf( buffer
, "[%s]", entry
.unixname
);
1492 else sprintf( buffer
, "[%s]", DOSFS_ToDosDTAFormat( entry
.name
) );
1494 else /* not a directory */
1496 if ((attrib
& DDL_EXCLUSIVE
) &&
1497 ((attrib
& (FA_RDONLY
|FA_HIDDEN
|FA_SYSTEM
|FA_ARCHIVE
)) !=
1498 (entry
.attr
& (FA_RDONLY
|FA_HIDDEN
|FA_SYSTEM
|FA_ARCHIVE
))))
1500 if (long_names
) strcpy( buffer
, entry
.unixname
);
1501 else strcpy( buffer
, DOSFS_ToDosDTAFormat( entry
.name
) );
1503 if (!long_names
) AnsiLower( buffer
);
1504 pos
= LISTBOX_FindFileStrPos( wnd
, descr
, buffer
);
1505 if ((ret
= LISTBOX_InsertString( wnd
, descr
, pos
, buffer
)) < 0)
1509 if ((ret
== LB_OKAY
) && (attrib
& DDL_DRIVES
))
1511 char buffer
[] = "[-a-]";
1513 for (drive
= 0; drive
< MAX_DOS_DRIVES
; drive
++, buffer
[2]++)
1515 if (!DRIVE_IsValid(drive
)) continue;
1516 if ((ret
= LISTBOX_InsertString( wnd
, descr
, -1, buffer
)) < 0)
1521 HeapFree( SystemHeap
, 0, path
);
1526 /***********************************************************************
1527 * LISTBOX_HandleVScroll
1529 static LRESULT
LISTBOX_HandleVScroll( WND
*wnd
, LB_DESCR
*descr
,
1530 WPARAM32 wParam
, LPARAM lParam
)
1534 if (descr
->style
& LBS_MULTICOLUMN
) return 0;
1535 switch(LOWORD(wParam
))
1538 LISTBOX_SetTopItem( wnd
, descr
, descr
->top_item
- 1, TRUE
);
1541 LISTBOX_SetTopItem( wnd
, descr
, descr
->top_item
+ 1, TRUE
);
1544 LISTBOX_SetTopItem( wnd
, descr
, descr
->top_item
-
1545 LISTBOX_GetCurrentPageSize( wnd
, descr
), TRUE
);
1548 LISTBOX_SetTopItem( wnd
, descr
, descr
->top_item
+
1549 LISTBOX_GetCurrentPageSize( wnd
, descr
), TRUE
);
1551 case SB_THUMBPOSITION
:
1552 LISTBOX_SetTopItem( wnd
, descr
, HIWORD(wParam
), TRUE
);
1555 info
.cbSize
= sizeof(info
);
1556 info
.fMask
= SIF_TRACKPOS
;
1557 GetScrollInfo32( wnd
->hwndSelf
, SB_VERT
, &info
);
1558 LISTBOX_SetTopItem( wnd
, descr
, info
.nTrackPos
, TRUE
);
1561 LISTBOX_SetTopItem( wnd
, descr
, 0, TRUE
);
1564 LISTBOX_SetTopItem( wnd
, descr
, descr
->nb_items
, TRUE
);
1571 /***********************************************************************
1572 * LISTBOX_HandleHScroll
1574 static LRESULT
LISTBOX_HandleHScroll( WND
*wnd
, LB_DESCR
*descr
,
1575 WPARAM32 wParam
, LPARAM lParam
)
1580 if (descr
->style
& LBS_MULTICOLUMN
)
1582 switch(LOWORD(wParam
))
1585 LISTBOX_SetTopItem( wnd
, descr
, descr
->top_item
-descr
->page_size
,
1589 LISTBOX_SetTopItem( wnd
, descr
, descr
->top_item
+descr
->page_size
,
1593 page
= descr
->width
/ descr
->column_width
;
1594 if (page
< 1) page
= 1;
1595 LISTBOX_SetTopItem( wnd
, descr
,
1596 descr
->top_item
- page
* descr
->page_size
, TRUE
);
1599 page
= descr
->width
/ descr
->column_width
;
1600 if (page
< 1) page
= 1;
1601 LISTBOX_SetTopItem( wnd
, descr
,
1602 descr
->top_item
+ page
* descr
->page_size
, TRUE
);
1604 case SB_THUMBPOSITION
:
1605 LISTBOX_SetTopItem( wnd
, descr
, HIWORD(wParam
)*descr
->page_size
,
1609 info
.cbSize
= sizeof(info
);
1610 info
.fMask
= SIF_TRACKPOS
;
1611 GetScrollInfo32( wnd
->hwndSelf
, SB_VERT
, &info
);
1612 LISTBOX_SetTopItem( wnd
, descr
, info
.nTrackPos
*descr
->page_size
,
1616 LISTBOX_SetTopItem( wnd
, descr
, 0, TRUE
);
1619 LISTBOX_SetTopItem( wnd
, descr
, descr
->nb_items
, TRUE
);
1623 else if (descr
->horz_extent
)
1625 switch(LOWORD(wParam
))
1628 LISTBOX_SetHorizontalPos( wnd
, descr
, descr
->horz_pos
- 1 );
1631 LISTBOX_SetHorizontalPos( wnd
, descr
, descr
->horz_pos
+ 1 );
1634 LISTBOX_SetHorizontalPos( wnd
, descr
,
1635 descr
->horz_pos
- descr
->width
);
1638 LISTBOX_SetHorizontalPos( wnd
, descr
,
1639 descr
->horz_pos
+ descr
->width
);
1641 case SB_THUMBPOSITION
:
1642 LISTBOX_SetHorizontalPos( wnd
, descr
, HIWORD(wParam
) );
1645 info
.cbSize
= sizeof(info
);
1646 info
.fMask
= SIF_TRACKPOS
;
1647 GetScrollInfo32( wnd
->hwndSelf
, SB_HORZ
, &info
);
1648 LISTBOX_SetHorizontalPos( wnd
, descr
, info
.nTrackPos
);
1651 LISTBOX_SetHorizontalPos( wnd
, descr
, 0 );
1654 LISTBOX_SetHorizontalPos( wnd
, descr
,
1655 descr
->horz_extent
- descr
->width
);
1663 /***********************************************************************
1664 * LISTBOX_HandleLButtonDown
1666 static LRESULT
LISTBOX_HandleLButtonDown( WND
*wnd
, LB_DESCR
*descr
,
1667 WPARAM32 wParam
, INT32 x
, INT32 y
)
1669 INT32 index
= LISTBOX_GetItemFromPoint( wnd
, descr
, x
, y
);
1670 dprintf_listbox( stddeb
, "Listbox %04x: lbuttondown %d,%d item %d\n",
1671 wnd
->hwndSelf
, x
, y
, index
);
1672 if (!descr
->caret_on
&& (GetFocus32() == wnd
->hwndSelf
)) return 0;
1675 if (descr
->style
& LBS_EXTENDEDSEL
)
1677 if (!(wParam
& MK_SHIFT
)) descr
->anchor_item
= index
;
1678 if (wParam
& MK_CONTROL
)
1680 LISTBOX_SetCaretIndex( wnd
, descr
, index
, FALSE
);
1681 LISTBOX_SetSelection( wnd
, descr
, index
,
1682 !descr
->items
[index
].selected
, FALSE
);
1684 else LISTBOX_MoveCaret( wnd
, descr
, index
, FALSE
);
1688 LISTBOX_MoveCaret( wnd
, descr
, index
, FALSE
);
1689 LISTBOX_SetSelection( wnd
, descr
, index
,
1690 (!(descr
->style
& LBS_MULTIPLESEL
) ||
1691 !descr
->items
[index
].selected
), FALSE
);
1694 SetFocus32( wnd
->hwndSelf
);
1695 SetCapture32( wnd
->hwndSelf
);
1698 if (descr
->style
& LBS_NOTIFY
)
1699 SendMessage32A( descr
->owner
, WM_LBTRACKPOINT
, index
,
1700 MAKELPARAM( x
, y
) );
1701 if (wnd
->dwExStyle
& WS_EX_DRAGDETECT
)
1703 POINT16 pt
= { x
, y
};
1704 if (DragDetect( wnd
->hwndSelf
, pt
))
1705 SendMessage32A( descr
->owner
, WM_BEGINDRAG
, 0, 0 );
1712 /***********************************************************************
1713 * LISTBOX_HandleLButtonUp
1715 static LRESULT
LISTBOX_HandleLButtonUp( WND
*wnd
, LB_DESCR
*descr
)
1717 if (LISTBOX_Timer
!= LB_TIMER_NONE
)
1718 KillSystemTimer32( wnd
->hwndSelf
, LB_TIMER_ID
);
1719 LISTBOX_Timer
= LB_TIMER_NONE
;
1720 if (GetCapture32() == wnd
->hwndSelf
) ReleaseCapture();
1721 if (descr
->style
& LBS_NOTIFY
)
1722 SEND_NOTIFICATION( wnd
, descr
, LBN_SELCHANGE
);
1727 /***********************************************************************
1728 * LISTBOX_HandleTimer
1730 * Handle scrolling upon a timer event.
1731 * Return TRUE if scrolling should continue.
1733 static LRESULT
LISTBOX_HandleTimer( WND
*wnd
, LB_DESCR
*descr
,
1734 INT32 index
, TIMER_DIRECTION dir
)
1739 if (descr
->top_item
) index
= descr
->top_item
- 1;
1743 if (descr
->top_item
) index
-= descr
->page_size
;
1746 index
= descr
->top_item
+ LISTBOX_GetCurrentPageSize( wnd
, descr
);
1747 if (index
>= descr
->nb_items
) index
= descr
->nb_items
- 1;
1749 case LB_TIMER_RIGHT
:
1750 if (index
+ descr
->page_size
< descr
->nb_items
)
1751 index
+= descr
->page_size
;
1756 if (index
== descr
->focus_item
) return FALSE
;
1757 LISTBOX_MoveCaret( wnd
, descr
, index
, FALSE
);
1762 /***********************************************************************
1763 * LISTBOX_HandleSystemTimer
1765 * WM_SYSTIMER handler.
1767 static LRESULT
LISTBOX_HandleSystemTimer( WND
*wnd
, LB_DESCR
*descr
)
1769 if (!LISTBOX_HandleTimer( wnd
, descr
, descr
->focus_item
, LISTBOX_Timer
))
1771 KillSystemTimer32( wnd
->hwndSelf
, LB_TIMER_ID
);
1772 LISTBOX_Timer
= LB_TIMER_NONE
;
1778 /***********************************************************************
1779 * LISTBOX_HandleMouseMove
1781 * WM_MOUSEMOVE handler.
1783 static void LISTBOX_HandleMouseMove( WND
*wnd
, LB_DESCR
*descr
,
1787 TIMER_DIRECTION dir
;
1789 if (descr
->style
& LBS_MULTICOLUMN
)
1792 else if (y
>= descr
->item_height
* descr
->page_size
)
1793 y
= descr
->item_height
* descr
->page_size
- 1;
1797 dir
= LB_TIMER_LEFT
;
1800 else if (x
>= descr
->width
)
1802 dir
= LB_TIMER_RIGHT
;
1803 x
= descr
->width
- 1;
1805 else dir
= LB_TIMER_NONE
; /* inside */
1809 if (y
< 0) dir
= LB_TIMER_UP
; /* above */
1810 else if (y
>= descr
->height
) dir
= LB_TIMER_DOWN
; /* below */
1811 else dir
= LB_TIMER_NONE
; /* inside */
1814 index
= LISTBOX_GetItemFromPoint( wnd
, descr
, x
, y
);
1815 if (index
== -1) index
= descr
->focus_item
;
1816 if (!LISTBOX_HandleTimer( wnd
, descr
, index
, dir
)) dir
= LB_TIMER_NONE
;
1818 /* Start/stop the system timer */
1820 if (dir
!= LB_TIMER_NONE
)
1821 SetSystemTimer32( wnd
->hwndSelf
, LB_TIMER_ID
, LB_SCROLL_TIMEOUT
, NULL
);
1822 else if (LISTBOX_Timer
!= LB_TIMER_NONE
)
1823 KillSystemTimer32( wnd
->hwndSelf
, LB_TIMER_ID
);
1824 LISTBOX_Timer
= dir
;
1828 /***********************************************************************
1829 * LISTBOX_HandleKeyDown
1831 static LRESULT
LISTBOX_HandleKeyDown( WND
*wnd
, LB_DESCR
*descr
,
1835 if (descr
->style
& LBS_WANTKEYBOARDINPUT
)
1837 caret
= SendMessage32A( descr
->owner
, WM_VKEYTOITEM
,
1838 MAKEWPARAM(LOWORD(wParam
), descr
->focus_item
),
1840 if (caret
== -2) return 0;
1842 if (caret
== -1) switch(wParam
)
1845 if (descr
->style
& LBS_MULTICOLUMN
)
1847 if (descr
->focus_item
>= descr
->page_size
)
1848 caret
= descr
->focus_item
- descr
->page_size
;
1853 caret
= descr
->focus_item
- 1;
1854 if (caret
< 0) caret
= 0;
1857 if (descr
->style
& LBS_MULTICOLUMN
)
1859 if (descr
->focus_item
+ descr
->page_size
< descr
->nb_items
)
1860 caret
= descr
->focus_item
+ descr
->page_size
;
1865 caret
= descr
->focus_item
+ 1;
1866 if (caret
>= descr
->nb_items
) caret
= descr
->nb_items
- 1;
1869 if (descr
->style
& LBS_MULTICOLUMN
)
1871 INT32 page
= descr
->width
/ descr
->column_width
;
1872 if (page
< 1) page
= 1;
1873 caret
= descr
->focus_item
- (page
* descr
->page_size
) + 1;
1875 else caret
= descr
->focus_item
-LISTBOX_GetCurrentPageSize(wnd
,descr
)+1;
1876 if (caret
< 0) caret
= 0;
1879 if (descr
->style
& LBS_MULTICOLUMN
)
1881 INT32 page
= descr
->width
/ descr
->column_width
;
1882 if (page
< 1) page
= 1;
1883 caret
= descr
->focus_item
+ (page
* descr
->page_size
) - 1;
1885 else caret
= descr
->focus_item
+LISTBOX_GetCurrentPageSize(wnd
,descr
)-1;
1886 if (caret
>= descr
->nb_items
) caret
= descr
->nb_items
- 1;
1892 caret
= descr
->nb_items
- 1;
1895 if (descr
->style
& LBS_EXTENDEDSEL
) caret
= descr
->focus_item
;
1896 else if (descr
->style
& LBS_MULTIPLESEL
)
1898 LISTBOX_SetSelection( wnd
, descr
, descr
->focus_item
,
1899 !descr
->items
[descr
->focus_item
].selected
,
1900 (descr
->style
& LBS_NOTIFY
) != 0 );
1906 if ((descr
->style
& LBS_EXTENDEDSEL
) &&
1907 !(GetKeyState( VK_SHIFT
) & 0x8000))
1908 descr
->anchor_item
= caret
;
1909 LISTBOX_MoveCaret( wnd
, descr
, caret
, TRUE
);
1910 if (descr
->style
& LBS_NOTIFY
)
1911 SEND_NOTIFICATION( wnd
, descr
, LBN_SELCHANGE
);
1917 /***********************************************************************
1918 * LISTBOX_HandleChar
1920 static LRESULT
LISTBOX_HandleChar( WND
*wnd
, LB_DESCR
*descr
,
1924 char str
[2] = { wParam
& 0xff, '\0' };
1926 if (descr
->style
& LBS_WANTKEYBOARDINPUT
)
1928 caret
= SendMessage32A( descr
->owner
, WM_CHARTOITEM
,
1929 MAKEWPARAM(LOWORD(wParam
), descr
->focus_item
),
1931 if (caret
== -2) return 0;
1934 caret
= LISTBOX_FindString( wnd
, descr
, descr
->focus_item
, str
, FALSE
);
1937 LISTBOX_MoveCaret( wnd
, descr
, caret
, TRUE
);
1938 if (descr
->style
& LBS_NOTIFY
)
1939 SEND_NOTIFICATION( wnd
, descr
, LBN_SELCHANGE
);
1945 /***********************************************************************
1948 static BOOL32
LISTBOX_Create( WND
*wnd
)
1951 MEASUREITEMSTRUCT32 mis
;
1954 if (!(descr
= HeapAlloc( GetProcessHeap(), 0, sizeof(*descr
) )))
1956 if (!(descr
->heap
= HeapCreate( 0, 0x10000, 0 )))
1958 HeapFree( GetProcessHeap(), 0, descr
);
1961 GetClientRect32( wnd
->hwndSelf
, &rect
);
1962 descr
->owner
= GetParent32( wnd
->hwndSelf
);
1963 descr
->style
= wnd
->dwStyle
;
1964 descr
->width
= rect
.right
- rect
.left
;
1965 descr
->height
= rect
.bottom
- rect
.top
;
1966 descr
->items
= NULL
;
1967 descr
->nb_items
= 0;
1968 descr
->top_item
= 0;
1969 descr
->selected_item
= -1;
1970 descr
->focus_item
= 0;
1971 descr
->anchor_item
= -1;
1972 descr
->item_height
= 1;
1973 descr
->page_size
= 1;
1974 descr
->column_width
= 150;
1975 descr
->horz_extent
= (wnd
->dwStyle
& WS_HSCROLL
) ? 1 : 0;
1976 descr
->horz_pos
= 0;
1979 descr
->caret_on
= TRUE
;
1981 descr
->locale
= 0; /* FIXME */
1983 *(LB_DESCR
**)wnd
->wExtra
= descr
;
1985 if (descr
->style
& LBS_EXTENDEDSEL
) descr
->style
|= LBS_MULTIPLESEL
;
1986 if (descr
->style
& LBS_MULTICOLUMN
) descr
->style
&= ~LBS_OWNERDRAWVARIABLE
;
1987 if (descr
->style
& LBS_OWNERDRAWVARIABLE
) descr
->style
|= LBS_NOINTEGRALHEIGHT
;
1988 descr
->item_height
= LISTBOX_SetFont( wnd
, descr
, 0 );
1990 if (descr
->style
& LBS_OWNERDRAWFIXED
)
1992 mis
.CtlType
= ODT_LISTBOX
;
1993 mis
.CtlID
= wnd
->wIDmenu
;
1997 mis
.itemHeight
= descr
->item_height
;
1998 SendMessage32A( descr
->owner
, WM_MEASUREITEM
, wnd
->wIDmenu
,
2000 descr
->item_height
= mis
.itemHeight
? mis
.itemHeight
: 1;
2007 /***********************************************************************
2010 static BOOL32
LISTBOX_Destroy( WND
*wnd
, LB_DESCR
*descr
)
2012 LISTBOX_ResetContent( wnd
, descr
);
2013 HeapDestroy( descr
->heap
);
2014 HeapFree( GetProcessHeap(), 0, descr
);
2015 *(LB_DESCR
**)wnd
->wExtra
= NULL
;
2020 /***********************************************************************
2023 LRESULT
ListBoxWndProc(HWND32 hwnd
, UINT32 msg
, WPARAM32 wParam
, LPARAM lParam
)
2027 WND
*wnd
= WIN_FindWndPtr( hwnd
);
2030 if (!(descr
= *(LB_DESCR
**)wnd
->wExtra
))
2032 if (msg
== WM_CREATE
)
2034 if (!LISTBOX_Create( wnd
)) return -1;
2035 dprintf_listbox( stddeb
, "Listbox: creating wnd=%04x descr=%p\n",
2036 hwnd
, *(LB_DESCR
**)wnd
->wExtra
);
2039 /* Ignore all other messages before we get a WM_CREATE */
2040 return DefWindowProc32A( hwnd
, msg
, wParam
, lParam
);
2043 dprintf_listbox( stddeb
, "Listbox %04x: msg %s wp %08x lp %08lx\n",
2044 wnd
->hwndSelf
, SPY_GetMsgName(msg
), wParam
, lParam
);
2047 case LB_RESETCONTENT16
:
2048 case LB_RESETCONTENT32
:
2049 LISTBOX_ResetContent( wnd
, descr
);
2052 case LB_ADDSTRING16
:
2053 if (HAS_STRINGS(descr
)) lParam
= (LPARAM
)PTR_SEG_TO_LIN(lParam
);
2055 case LB_ADDSTRING32
:
2056 wParam
= LISTBOX_FindStringPos( wnd
, descr
, (LPCSTR
)lParam
, FALSE
);
2057 return LISTBOX_InsertString( wnd
, descr
, wParam
, (LPCSTR
)lParam
);
2059 case LB_INSERTSTRING16
:
2060 if (HAS_STRINGS(descr
)) lParam
= (LPARAM
)PTR_SEG_TO_LIN(lParam
);
2061 wParam
= (INT32
)(INT16
)wParam
;
2063 case LB_INSERTSTRING32
:
2064 return LISTBOX_InsertString( wnd
, descr
, wParam
, (LPCSTR
)lParam
);
2067 if (HAS_STRINGS(descr
)) lParam
= (LPARAM
)PTR_SEG_TO_LIN(lParam
);
2070 wParam
= LISTBOX_FindFileStrPos( wnd
, descr
, (LPCSTR
)lParam
);
2071 return LISTBOX_InsertString( wnd
, descr
, wParam
, (LPCSTR
)lParam
);
2073 case LB_DELETESTRING16
:
2074 case LB_DELETESTRING32
:
2075 return LISTBOX_RemoveItem( wnd
, descr
, wParam
);
2077 case LB_GETITEMDATA16
:
2078 case LB_GETITEMDATA32
:
2079 if (((INT32
)wParam
< 0) || ((INT32
)wParam
>= descr
->nb_items
))
2081 return descr
->items
[wParam
].data
;
2083 case LB_SETITEMDATA16
:
2084 case LB_SETITEMDATA32
:
2085 if (((INT32
)wParam
< 0) || ((INT32
)wParam
>= descr
->nb_items
))
2087 descr
->items
[wParam
].data
= (DWORD
)lParam
;
2092 return descr
->nb_items
;
2095 lParam
= (LPARAM
)PTR_SEG_TO_LIN(lParam
);
2098 return LISTBOX_GetText( wnd
, descr
, wParam
, (LPSTR
)lParam
);
2100 case LB_GETTEXTLEN16
:
2102 case LB_GETTEXTLEN32
:
2103 if (wParam
>= descr
->nb_items
) return LB_ERR
;
2104 return (HAS_STRINGS(descr
) ? strlen(descr
->items
[wParam
].str
)
2107 case LB_GETCURSEL16
:
2108 case LB_GETCURSEL32
:
2109 return descr
->selected_item
;
2111 case LB_GETTOPINDEX16
:
2112 case LB_GETTOPINDEX32
:
2113 return descr
->top_item
;
2115 case LB_GETITEMHEIGHT16
:
2116 case LB_GETITEMHEIGHT32
:
2117 return LISTBOX_GetItemHeight( wnd
, descr
, wParam
);
2119 case LB_SETITEMHEIGHT16
:
2120 lParam
= LOWORD(lParam
);
2122 case LB_SETITEMHEIGHT32
:
2123 return LISTBOX_SetItemHeight( wnd
, descr
, wParam
, lParam
);
2125 case LB_ITEMFROMPOINT32
:
2127 POINT32 pt
= { LOWORD(lParam
), HIWORD(lParam
) };
2128 RECT32 rect
= { 0, 0, descr
->width
, descr
->height
};
2129 return MAKELONG( LISTBOX_GetItemFromPoint(wnd
, descr
, pt
.x
, pt
.y
),
2130 PtInRect32( &rect
, pt
) );
2133 case LB_SETCARETINDEX16
:
2134 case LB_SETCARETINDEX32
:
2135 return LISTBOX_SetCaretIndex( wnd
, descr
, wParam
, !lParam
);
2137 case LB_GETCARETINDEX16
:
2138 case LB_GETCARETINDEX32
:
2139 return descr
->focus_item
;
2141 case LB_SETTOPINDEX16
:
2142 case LB_SETTOPINDEX32
:
2143 return LISTBOX_SetTopItem( wnd
, descr
, wParam
, TRUE
);
2145 case LB_SETCOLUMNWIDTH16
:
2146 case LB_SETCOLUMNWIDTH32
:
2147 return LISTBOX_SetColumnWidth( wnd
, descr
, wParam
);
2149 case LB_GETITEMRECT16
:
2152 ret
= LISTBOX_GetItemRect( wnd
, descr
, (INT16
)wParam
, &rect
);
2153 CONV_RECT32TO16( &rect
, (RECT16
*)PTR_SEG_TO_LIN(lParam
) );
2157 case LB_GETITEMRECT32
:
2158 return LISTBOX_GetItemRect( wnd
, descr
, wParam
, (RECT32
*)lParam
);
2160 case LB_FINDSTRING16
:
2161 wParam
= (INT32
)(INT16
)wParam
;
2162 if (HAS_STRINGS(descr
)) lParam
= (LPARAM
)PTR_SEG_TO_LIN(lParam
);
2164 case LB_FINDSTRING32
:
2165 return LISTBOX_FindString( wnd
, descr
, wParam
, (LPCSTR
)lParam
, FALSE
);
2167 case LB_FINDSTRINGEXACT16
:
2168 wParam
= (INT32
)(INT16
)wParam
;
2169 if (HAS_STRINGS(descr
)) lParam
= (LPARAM
)PTR_SEG_TO_LIN(lParam
);
2171 case LB_FINDSTRINGEXACT32
:
2172 return LISTBOX_FindString( wnd
, descr
, wParam
, (LPCSTR
)lParam
, TRUE
);
2174 case LB_SELECTSTRING16
:
2175 wParam
= (INT32
)(INT16
)wParam
;
2176 if (HAS_STRINGS(descr
)) lParam
= (LPARAM
)PTR_SEG_TO_LIN(lParam
);
2178 case LB_SELECTSTRING32
:
2180 INT32 index
= LISTBOX_FindString( wnd
, descr
, wParam
,
2181 (LPCSTR
)lParam
, FALSE
);
2182 if (index
== LB_ERR
) return LB_ERR
;
2183 LISTBOX_SetSelection( wnd
, descr
, index
, TRUE
, FALSE
);
2188 wParam
= (INT32
)(INT16
)wParam
;
2191 if (((INT32
)wParam
< 0) || ((INT32
)wParam
>= descr
->nb_items
))
2193 return descr
->items
[wParam
].selected
;
2196 lParam
= (INT32
)(INT16
)lParam
;
2199 return LISTBOX_SetSelection( wnd
, descr
, lParam
, wParam
, FALSE
);
2201 case LB_SETCURSEL16
:
2202 wParam
= (INT32
)(INT16
)wParam
;
2204 case LB_SETCURSEL32
:
2205 if (wParam
!= -1) LISTBOX_MakeItemVisible( wnd
, descr
, wParam
, TRUE
);
2206 return LISTBOX_SetSelection( wnd
, descr
, wParam
, TRUE
, FALSE
);
2208 case LB_GETSELCOUNT16
:
2209 case LB_GETSELCOUNT32
:
2210 return LISTBOX_GetSelCount( wnd
, descr
);
2212 case LB_GETSELITEMS16
:
2213 return LISTBOX_GetSelItems16( wnd
, descr
, wParam
,
2214 (LPINT16
)PTR_SEG_TO_LIN(lParam
) );
2216 case LB_GETSELITEMS32
:
2217 return LISTBOX_GetSelItems32( wnd
, descr
, wParam
, (LPINT32
)lParam
);
2219 case LB_SELITEMRANGE16
:
2220 case LB_SELITEMRANGE32
:
2221 return LISTBOX_SelectItemRange( wnd
, descr
, LOWORD(lParam
),
2222 HIWORD(lParam
), wParam
);
2224 case LB_SELITEMRANGEEX16
:
2225 case LB_SELITEMRANGEEX32
:
2226 if ((INT32
)lParam
>= (INT32
)wParam
)
2227 return LISTBOX_SelectItemRange( wnd
, descr
, wParam
, lParam
, TRUE
);
2229 return LISTBOX_SelectItemRange( wnd
, descr
, lParam
, wParam
, FALSE
);
2231 case LB_GETHORIZONTALEXTENT16
:
2232 case LB_GETHORIZONTALEXTENT32
:
2233 return descr
->horz_extent
;
2235 case LB_SETHORIZONTALEXTENT16
:
2236 case LB_SETHORIZONTALEXTENT32
:
2237 return LISTBOX_SetHorizontalExtent( wnd
, descr
, wParam
);
2239 case LB_GETANCHORINDEX16
:
2240 case LB_GETANCHORINDEX32
:
2241 return descr
->anchor_item
;
2243 case LB_SETANCHORINDEX16
:
2244 wParam
= (INT32
)(INT16
)wParam
;
2246 case LB_SETANCHORINDEX32
:
2247 if (((INT32
)wParam
< -1) || ((INT32
)wParam
>= descr
->nb_items
))
2249 descr
->anchor_item
= (INT32
)wParam
;
2253 return LISTBOX_Directory( wnd
, descr
, wParam
,
2254 (LPCSTR
)PTR_SEG_TO_LIN(lParam
), FALSE
);
2257 return LISTBOX_Directory( wnd
, descr
, wParam
, (LPCSTR
)lParam
, TRUE
);
2259 case LB_GETLOCALE32
:
2260 return descr
->locale
;
2262 case LB_SETLOCALE32
:
2263 descr
->locale
= (LCID
)wParam
; /* FIXME: should check for valid lcid */
2266 case LB_INITSTORAGE32
:
2267 return LISTBOX_InitStorage( wnd
, descr
, wParam
, (DWORD
)lParam
);
2270 return LISTBOX_SetCount( wnd
, descr
, (INT32
)wParam
);
2272 case LB_SETTABSTOPS16
:
2273 return LISTBOX_SetTabStops( wnd
, descr
, (INT32
)(INT16
)wParam
,
2274 (LPINT32
)PTR_SEG_TO_LIN(lParam
), TRUE
);
2276 case LB_SETTABSTOPS32
:
2277 return LISTBOX_SetTabStops( wnd
, descr
, wParam
,
2278 (LPINT32
)lParam
, FALSE
);
2282 if (descr
->caret_on
) return LB_OKAY
;
2283 descr
->caret_on
= TRUE
;
2284 if ((descr
->focus_item
!= -1) && (GetFocus32() == wnd
->hwndSelf
))
2285 LISTBOX_RepaintItem( wnd
, descr
, descr
->focus_item
, ODA_FOCUS
);
2290 if (!descr
->caret_on
) return LB_OKAY
;
2291 descr
->caret_on
= FALSE
;
2292 if ((descr
->focus_item
!= -1) && (GetFocus32() == wnd
->hwndSelf
))
2293 LISTBOX_RepaintItem( wnd
, descr
, descr
->focus_item
, ODA_FOCUS
);
2297 return LISTBOX_Destroy( wnd
, descr
);
2300 InvalidateRect32( hwnd
, NULL
, TRUE
);
2304 LISTBOX_SetRedraw( wnd
, descr
, wParam
!= 0 );
2308 return DLGC_WANTARROWS
| DLGC_WANTCHARS
;
2313 HDC32 hdc
= BeginPaint32( hwnd
, &ps
);
2314 ret
= LISTBOX_Paint( wnd
, descr
, hdc
);
2315 EndPaint32( hwnd
, &ps
);
2320 LISTBOX_UpdateSize( wnd
, descr
);
2327 LISTBOX_SetFont( wnd
, descr
, (HFONT32
)wParam
);
2328 if (lParam
) InvalidateRect32( wnd
->hwndSelf
, 0, TRUE
);
2332 descr
->caret_on
= TRUE
;
2333 if (descr
->focus_item
!= -1)
2334 LISTBOX_RepaintItem( wnd
, descr
, descr
->focus_item
, ODA_FOCUS
);
2335 SEND_NOTIFICATION( wnd
, descr
, LBN_SETFOCUS
);
2339 if ((descr
->focus_item
!= -1) && descr
->caret_on
)
2340 LISTBOX_RepaintItem( wnd
, descr
, descr
->focus_item
, ODA_FOCUS
);
2341 SEND_NOTIFICATION( wnd
, descr
, LBN_KILLFOCUS
);
2345 return LISTBOX_HandleHScroll( wnd
, descr
, wParam
, lParam
);
2348 return LISTBOX_HandleVScroll( wnd
, descr
, wParam
, lParam
);
2350 case WM_LBUTTONDOWN
:
2351 return LISTBOX_HandleLButtonDown( wnd
, descr
, wParam
,
2352 (INT16
)LOWORD(lParam
),
2353 (INT16
)HIWORD(lParam
) );
2355 case WM_LBUTTONDBLCLK
:
2356 if (descr
->style
& LBS_NOTIFY
)
2357 SEND_NOTIFICATION( wnd
, descr
, LBN_DBLCLK
);
2361 if (GetCapture32() == hwnd
)
2362 LISTBOX_HandleMouseMove( wnd
, descr
, (INT16
)LOWORD(lParam
),
2363 (INT16
)HIWORD(lParam
) );
2367 return LISTBOX_HandleLButtonUp( wnd
, descr
);
2370 return LISTBOX_HandleKeyDown( wnd
, descr
, wParam
);
2373 return LISTBOX_HandleChar( wnd
, descr
, wParam
);
2376 return LISTBOX_HandleSystemTimer( wnd
, descr
);
2379 if (IS_OWNERDRAW(descr
))
2381 RECT32 rect
= { 0, 0, descr
->width
, descr
->height
};
2382 HBRUSH32 hbrush
= SendMessage32A( descr
->owner
, WM_CTLCOLORLISTBOX
,
2383 wParam
, (LPARAM
)wnd
->hwndSelf
);
2384 if (hbrush
) FillRect32( (HDC32
)wParam
, &rect
, hbrush
);
2389 return SendMessage32A( descr
->owner
, msg
, wParam
, lParam
);
2392 case WM_QUERYDROPOBJECT
:
2396 LPDRAGINFO dragInfo
= (LPDRAGINFO
)PTR_SEG_TO_LIN( (SEGPTR
)lParam
);
2397 dragInfo
->l
= LISTBOX_GetItemFromPoint( wnd
, descr
, dragInfo
->pt
.x
,
2399 return SendMessage32A( descr
->owner
, msg
, wParam
, lParam
);
2403 if ((msg
>= WM_USER
) && (msg
< 0xc000))
2404 fprintf(stderr
,"Listbox %04x: unknown msg %04x wp %08x lp %08lx\n",
2405 hwnd
, msg
, wParam
, lParam
);
2406 return DefWindowProc32A( hwnd
, msg
, wParam
, lParam
);