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