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