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