Main Page   Class Hierarchy   Alphabetical List   Compound List   File List   Compound Members   File Members  

listbox.cpp

Go to the documentation of this file.
00001 /* $Id: listbox.cpp,v 1.27 2001/07/09 18:10:44 sandervl Exp $ */
00002 /*
00003  * Listbox controls
00004  *
00005  * Copyright 1996 Alexandre Julliard
00006  * Copyright 1999 Christoph Bratschi (ported from WINE)
00007  *
00008  * Corel version: 20000513
00009  * (WINE version: 991212)
00010  *
00011  * Status: ???
00012  * Version: ???
00013  */
00014 
00015 #include <string.h>
00016 #include <stdlib.h>
00017 #include <stdio.h>
00018 #include <os2win.h>
00019 #include "controls.h"
00020 #include "winerror.h"
00021 #include "combo.h"
00022 #include <misc.h>
00023 #include "heapstring.h"
00024 
00025 #define DBG_LOCALLOG    DBG_listbox
00026 #include "dbglocal.h"
00027 
00028 /* bugs:
00029  - LBS_NOSEL
00030  - LBS_USETABSTOPS
00031  - Locale handling
00032  - OS/2 default font bug: Odin about dialog -> LISTBOX_UpdateSize
00033  - WS_EX_NOPARENTNOTIFY
00034  - VK_LINEDOWN -> bottom most item not always visible
00035  - performance not optimized
00036  - first item selection mark not redrawn on new selection
00037  - LISTBOX_HandleLButtonDownCombo fails, bug in GetWindowRect or ClientToScreen!
00038    I clicked on the vertical scrollbar, this happens:
00039     t1: SendInternalMessageA WM_LBUTTONDOWN for 68000009 1 1d00c6
00040     t1: GetClientRect of 68000009 returned (0,0) (191,110)
00041     t1: USER32: GetCapture returned 68000009
00042     t1: GetWindowRect 68000009 (450,130) (657,242)
00043     t1: ClientToScreen 68000009 (198,29) -> (424,108)
00044    mouse position is ok, but screen point is outside window rect!!!
00045    the new point is left-top and not on the right!!!
00046  */
00047 
00048 //CB: drive funtions (… la wine drive.c)
00049 
00050 #define MAX_DOS_DRIVES  26 //a..z
00051 
00052 BOOL DRIVE_IsValid( int drive )
00053 {
00054   if ((drive < 0) || (drive >= MAX_DOS_DRIVES)) return 0;
00055 
00056   return (GetLogicalDrives() & (1 << drive));
00057 }
00058 
00059 /* Items array granularity */
00060 #define LB_ARRAY_GRANULARITY 16
00061 
00062 /* Scrolling timeout in ms */
00063 #define LB_SCROLL_TIMEOUT 50
00064 
00065 /* Listbox system timer id */
00066 #define LB_TIMER_ID  2
00067 
00068 /* Item structure */
00069 typedef struct
00070 {
00071     LPSTR   str;       /* Item text */
00072     BOOL    selected;  /* Is item selected? */
00073     UINT    height;    /* Item height (only for OWNERDRAWVARIABLE) */
00074     DWORD   data;      /* User data */
00075 } LB_ITEMDATA;
00076 
00077 /* Listbox structure */
00078 typedef struct
00079 {
00080     HANDLE      heap;           /* Heap for this listbox */
00081     HWND        owner;          /* Owner window to send notifications to */
00082     UINT        style;          /* Window style */
00083     INT         width;          /* Window width */
00084     INT         height;         /* Window height */
00085     LB_ITEMDATA  *items;          /* Array of items */
00086     INT         nb_items;       /* Number of items */
00087     INT         top_item;       /* Top visible item */
00088     INT         selected_item;  /* Selected item */
00089     INT         focus_item;     /* Item that has the focus */
00090     INT         anchor_item;    /* Anchor item for extended selection */
00091     INT         item_height;    /* Default item height */
00092     INT         page_size;      /* Items per listbox page */
00093     INT         column_width;   /* Column width for multi-column listboxes */
00094     INT         horz_extent;    /* Horizontal extent (0 if no hscroll) */
00095     INT         horz_pos;       /* Horizontal position */
00096     INT         nb_tabs;        /* Number of tabs in array */
00097     INT        *tabs;           /* Array of tabs */
00098     BOOL        caret_on;       /* Is caret on? */
00099     BOOL        captured;       /* Is mouse captured? */
00100     BOOL        in_focus;
00101     HFONT       font;           /* Current font */
00102     LCID        locale;         /* Current locale for string comparisons */
00103     LPHEADCOMBO lphc;           /* ComboLBox */
00104 } LB_DESCR;
00105 
00106 
00107 #define IS_OWNERDRAW(descr) \
00108     ((descr)->style & (LBS_OWNERDRAWFIXED | LBS_OWNERDRAWVARIABLE))
00109 
00110 #define HAS_STRINGS(descr) \
00111     (!IS_OWNERDRAW(descr) || ((descr)->style & LBS_HASSTRINGS))
00112 
00113 #define HAS_NODATA(descr) \
00114     ((descr)->style & LBS_NODATA)
00115 
00116 #define IS_MULTISELECT(descr) \
00117     ((descr)->style & LBS_MULTIPLESEL || ((descr)->style & LBS_EXTENDEDSEL))
00118 
00119 #define SEND_NOTIFICATION(hwnd,descr,code) \
00120     (SendMessageA( (descr)->owner, WM_COMMAND, \
00121      MAKEWPARAM(GetWindowLongA(hwnd,GWL_ID), (code)), hwnd ))
00122 
00123 /* Current timer status */
00124 typedef enum
00125 {
00126     LB_TIMER_NONE,
00127     LB_TIMER_UP,
00128     LB_TIMER_LEFT,
00129     LB_TIMER_DOWN,
00130     LB_TIMER_RIGHT
00131 } TIMER_DIRECTION;
00132 
00133 static TIMER_DIRECTION LISTBOX_Timer = LB_TIMER_NONE;
00134 
00135 
00136 /***********************************************************************
00137  *           LISTBOX_GetCurrentPageSize
00138  *
00139  * Return the current page size
00140  */
00141 static INT LISTBOX_GetCurrentPageSize( HWND hwnd, LB_DESCR *descr )
00142 {
00143     INT i, height;
00144     if (!(descr->style & LBS_OWNERDRAWVARIABLE)) return descr->page_size;
00145     for (i = descr->top_item, height = 0; i < descr->nb_items; i++)
00146     {
00147         if ((height += descr->items[i].height) > descr->height) break;
00148     }
00149     if (i == descr->top_item) return 1;
00150     else return i - descr->top_item;
00151 }
00152 
00153 
00154 /***********************************************************************
00155  *           LISTBOX_GetMaxTopIndex
00156  *
00157  * Return the maximum possible index for the top of the listbox.
00158  */
00159 static INT LISTBOX_GetMaxTopIndex( HWND hwnd, LB_DESCR *descr )
00160 {
00161     INT max, page;
00162 
00163     if (descr->style & LBS_OWNERDRAWVARIABLE)
00164     {
00165         page = descr->height;
00166         for (max = descr->nb_items - 1; max >= 0; max--)
00167             if ((page -= descr->items[max].height) < 0) break;
00168         if (max < descr->nb_items - 1) max++;
00169     }
00170     else if (descr->style & LBS_MULTICOLUMN)
00171     {
00172         if ((page = descr->width / descr->column_width) < 1) page = 1;
00173         max = (descr->nb_items + descr->page_size - 1) / descr->page_size;
00174         max = (max - page) * descr->page_size;
00175     }
00176     else
00177     {
00178         max = descr->nb_items - descr->page_size;
00179     }
00180     if (max < 0) max = 0;
00181     return max;
00182 }
00183 
00184 
00185 /***********************************************************************
00186  *           LISTBOX_UpdateScroll
00187  *
00188  * Update the scrollbars. Should be called whenever the content
00189  * of the listbox changes.
00190  */
00191 static void LISTBOX_UpdateScroll( HWND hwnd, LB_DESCR *descr )
00192 {
00193     SCROLLINFO info;
00194 
00195     /* Check the listbox scroll bar flags individually before we call
00196        SetScrollInfo otherwise when the listbox style is WS_HSCROLL and
00197        no WS_VSCROLL, we end up with an uninitialized, visible horizontal
00198        scroll bar when we do not need one.
00199               if (!(descr->style & WS_VSCROLL)) return;
00200           */
00201 
00202     /*   It is important that we check descr->style, and not wnd->dwStyle,
00203        for WS_VSCROLL, as the former is exactly the one passed in
00204        argument to CreateWindow.
00205          In Windows (and from now on in Wine :) a listbox created
00206        with such a style (no WS_SCROLL) does not update
00207        the scrollbar with listbox-related data, thus letting
00208        the programmer use it for his/her own purposes. */
00209 
00210     if (descr->style & LBS_NOREDRAW) return;
00211     info.cbSize = sizeof(info);
00212 
00213     if (descr->style & LBS_MULTICOLUMN)
00214     {
00215         info.nMin  = 0;
00216         info.nMax = (descr->nb_items - 1) / descr->page_size;
00217         info.nPos  = descr->top_item / descr->page_size;
00218         info.nPage = descr->width / descr->column_width;
00219         if (info.nPage < 1) info.nPage = 1;
00220         info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
00221         if (descr->style & LBS_DISABLENOSCROLL)
00222             info.fMask |= SIF_DISABLENOSCROLL;
00223         if (descr->style & WS_HSCROLL)
00224           SetScrollInfo( hwnd, SB_HORZ, &info, TRUE );
00225         info.nMax = 0;
00226         info.fMask = SIF_RANGE;
00227         if (descr->style & WS_VSCROLL)
00228           SetScrollInfo( hwnd, SB_VERT, &info, TRUE );
00229     }
00230     else
00231     {
00232         info.nMin  = 0;
00233         info.nMax  = descr->nb_items - 1;
00234         info.nPos  = descr->top_item;
00235         info.nPage = LISTBOX_GetCurrentPageSize( hwnd, descr );
00236         info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
00237         if (descr->style & LBS_DISABLENOSCROLL)
00238             info.fMask |= SIF_DISABLENOSCROLL;
00239         if (descr->style & WS_VSCROLL)
00240           SetScrollInfo( hwnd, SB_VERT, &info, TRUE );
00241 
00242         if (descr->horz_extent)
00243         {
00244             info.nMin  = 0;
00245             info.nMax  = descr->horz_extent - 1;
00246             info.nPos  = descr->horz_pos;
00247             info.nPage = descr->width;
00248             info.fMask = SIF_RANGE | SIF_POS | SIF_PAGE;
00249             if (descr->style & LBS_DISABLENOSCROLL)
00250                 info.fMask |= SIF_DISABLENOSCROLL;
00251             if (descr->style & WS_HSCROLL)
00252               SetScrollInfo( hwnd, SB_HORZ, &info, TRUE );
00253         }
00254     }
00255 }
00256 
00257 
00258 /***********************************************************************
00259  *           LISTBOX_SetTopItem
00260  *
00261  * Set the top item of the listbox, scrolling up or down if necessary.
00262  */
00263 static LRESULT LISTBOX_SetTopItem( HWND hwnd, LB_DESCR *descr, INT index,
00264                                    BOOL scroll )
00265 {
00266     INT max = LISTBOX_GetMaxTopIndex( hwnd, descr );
00267     if (index > max) index = max;
00268     if (index < 0) index = 0;
00269     if (descr->style & LBS_MULTICOLUMN) index -= index % descr->page_size;
00270     if (descr->top_item == index) return LB_OKAY;
00271     if (descr->style & LBS_MULTICOLUMN)
00272     {
00273         INT diff = (descr->top_item - index) / descr->page_size * descr->column_width;
00274         if (scroll && (abs(diff) < descr->width))
00275             ScrollWindowEx( hwnd, diff, 0, NULL, NULL, 0, NULL,
00276                               SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
00277 
00278         else
00279             scroll = FALSE;
00280     }
00281     else if (scroll)
00282     {
00283         INT diff;
00284         if (descr->style & LBS_OWNERDRAWVARIABLE)
00285         {
00286             INT i;
00287             diff = 0;
00288             if (index > descr->top_item)
00289             {
00290                 for (i = index - 1; i >= descr->top_item; i--)
00291                     diff -= descr->items[i].height;
00292             }
00293             else
00294             {
00295                 for (i = index; i < descr->top_item; i++)
00296                     diff += descr->items[i].height;
00297             }
00298         }
00299         else
00300             diff = (descr->top_item - index) * descr->item_height;
00301 
00302         if (abs(diff) < descr->height)
00303             ScrollWindowEx( hwnd, 0, diff, NULL, NULL, 0, NULL,
00304                               SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
00305         else
00306             scroll = FALSE;
00307     }
00308     if (!scroll) InvalidateRect( hwnd, NULL, TRUE );
00309     descr->top_item = index;
00310     LISTBOX_UpdateScroll( hwnd, descr );
00311     return LB_OKAY;
00312 }
00313 
00314 
00315 /***********************************************************************
00316  *           LISTBOX_UpdatePage
00317  *
00318  * Update the page size. Should be called when the size of
00319  * the client area or the item height changes.
00320  */
00321 static void LISTBOX_UpdatePage( HWND hwnd, LB_DESCR *descr )
00322 {
00323     INT page_size;
00324 
00325     if ((descr->item_height == 0) || (page_size = descr->height / descr->item_height) < 1)
00326                        page_size = 1;
00327     if (page_size == descr->page_size) return;
00328     descr->page_size = page_size;
00329     if (descr->style & LBS_MULTICOLUMN)
00330         InvalidateRect( hwnd, NULL, TRUE );
00331     LISTBOX_SetTopItem( hwnd, descr, descr->top_item, FALSE );
00332 }
00333 
00334 
00335 /***********************************************************************
00336  *           LISTBOX_UpdateSize
00337  *
00338  * Update the size of the listbox. Should be called when the size of
00339  * the client area changes.
00340  */
00341 static void LISTBOX_UpdateSize( HWND hwnd, LB_DESCR *descr )
00342 {
00343     RECT rect, rectWindow;
00344 
00345     GetWindowRect( hwnd, &rectWindow );
00346     GetClientRect( hwnd, &rect );
00347 
00348     //CB: todo: doesn't works in ShellAbout dialog
00349     descr->width  = rect.right - rect.left;
00350     descr->height = rect.bottom - rect.top;
00351     if (!(descr->style & LBS_NOINTEGRALHEIGHT) && !(descr->style & LBS_OWNERDRAWVARIABLE))
00352     {
00353         if ((descr->height > descr->item_height) &&
00354             (descr->height % descr->item_height))
00355         {
00356             dprintf(("LISTBOX: [%04x]: changing height %d -> %d\n",
00357                     hwnd, descr->height,
00358                     descr->height - descr->height%descr->item_height));
00359             SetWindowPos( hwnd, 0, 0, 0,
00360                             rectWindow.right - rectWindow.left,
00361                             rectWindow.bottom - rectWindow.top -
00362                                 (descr->height % descr->item_height),
00363                             SWP_NOZORDER | SWP_NOACTIVATE | SWP_NOMOVE );
00364             return;
00365         }
00366     }
00367     //TRACE("[%04x]: new size = %d,%d\n",
00368     //             wnd->hwndSelf, descr->width, descr->height );
00369     LISTBOX_UpdatePage( hwnd, descr );
00370     LISTBOX_UpdateScroll( hwnd, descr );
00371 }
00372 
00373 
00374 /***********************************************************************
00375  *           LISTBOX_GetItemRect
00376  *
00377  * Get the rectangle enclosing an item, in listbox client coordinates.
00378  * Return 1 if the rectangle is (partially) visible, 0 if hidden, -1 on error.
00379  */
00380 static LRESULT LISTBOX_GetItemRect( HWND hwnd, LB_DESCR *descr, INT index,
00381                                     RECT *rect )
00382 {
00383     /* Index <= 0 is legal even on empty listboxes */
00384     if (index && (index >= descr->nb_items)) return -1;
00385     SetRect( rect, 0, 0, descr->width, descr->height );
00386     if (descr->style & LBS_MULTICOLUMN)
00387     {
00388         INT col = (index / descr->page_size) -
00389                         (descr->top_item / descr->page_size);
00390         rect->left += col * descr->column_width;
00391         rect->right = rect->left + descr->column_width;
00392         rect->top += (index % descr->page_size) * descr->item_height;
00393         rect->bottom = rect->top + descr->item_height;
00394     }
00395     else if (descr->style & LBS_OWNERDRAWVARIABLE)
00396     {
00397         INT i;
00398         rect->right += descr->horz_pos;
00399         if ((index >= 0) && (index < descr->nb_items))
00400         {
00401             if (index < descr->top_item)
00402             {
00403                 for (i = descr->top_item-1; i >= index; i--)
00404                     rect->top -= descr->items[i].height;
00405             }
00406             else
00407             {
00408                 for (i = descr->top_item; i < index; i++)
00409                     rect->top += descr->items[i].height;
00410             }
00411             rect->bottom = rect->top + descr->items[index].height;
00412 
00413         }
00414     }
00415     else
00416     {
00417         rect->top += (index - descr->top_item) * descr->item_height;
00418         rect->bottom = rect->top + descr->item_height;
00419         rect->right += descr->horz_pos;
00420     }
00421 
00422     return ((rect->left < descr->width) && (rect->right > 0) &&
00423             (rect->top < descr->height) && (rect->bottom > 0));
00424 }
00425 
00426 
00427 /***********************************************************************
00428  *           LISTBOX_GetItemFromPoint
00429  *
00430  * Return the item nearest from point (x,y) (in client coordinates).
00431  */
00432 static INT LISTBOX_GetItemFromPoint( HWND hwnd, LB_DESCR *descr,
00433                                        INT x, INT y )
00434 {
00435     INT index = descr->top_item;
00436 
00437     if (!descr->nb_items) return -1;  /* No items */
00438     if (descr->style & LBS_OWNERDRAWVARIABLE)
00439     {
00440         INT pos = 0;
00441         if (y >= 0)
00442         {
00443             while (index < descr->nb_items)
00444             {
00445                 if ((pos += descr->items[index].height) > y) break;
00446                 index++;
00447             }
00448         }
00449         else
00450         {
00451             while (index > 0)
00452             {
00453                 index--;
00454                 if ((pos -= descr->items[index].height) <= y) break;
00455             }
00456         }
00457     }
00458     else if (descr->style & LBS_MULTICOLUMN)
00459     {
00460         if (y >= descr->item_height * descr->page_size) return -1;
00461         if (y >= 0) index += y / descr->item_height;
00462         if (x >= 0) index += (x / descr->column_width) * descr->page_size;
00463         else index -= (((x + 1) / descr->column_width) - 1) * descr->page_size;
00464     }
00465     else
00466     {
00467         index += (y / descr->item_height);
00468     }
00469     if (index < 0) return 0;
00470     if (index >= descr->nb_items) return -1;
00471     return index;
00472 }
00473 
00474 
00475 /***********************************************************************
00476  *           LISTBOX_DrawItem
00477  *
00478  * Draw an item.
00479  */
00480 static void LISTBOX_DrawItem( HWND hwnd, LB_DESCR *descr, HDC hdc,
00481                                const RECT *rect, INT index, UINT action )
00482 {
00483     LB_ITEMDATA *item = NULL;
00484     DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
00485 
00486     if (index < descr->nb_items) item = &descr->items[index];
00487 
00488     if (IS_OWNERDRAW(descr))
00489     {
00490         DRAWITEMSTRUCT dis;
00491         UINT           id = GetWindowLongA(hwnd,GWL_ID);
00492 
00493         if (!item)
00494         {
00495             if (action == ODA_FOCUS)
00496                 DrawFocusRect( hdc, rect );
00497             //else
00498             //    FIXME("called with an out of bounds index %d(%d) in owner draw, Not good.\n",index,descr->nb_items);
00499             return;
00500         }
00501         dis.CtlType      = ODT_LISTBOX;
00502         dis.CtlID        = id;
00503         dis.hwndItem     = hwnd;
00504         dis.itemAction   = action;
00505         dis.hDC          = hdc;
00506         dis.itemID       = index;
00507         dis.itemState    = 0;
00508         if (item && item->selected) dis.itemState |= ODS_SELECTED;
00509         if ((descr->focus_item == index) &&
00510             (descr->caret_on) &&
00511             (descr->in_focus)) dis.itemState |= ODS_FOCUS;
00512         if (dwStyle & WS_DISABLED) dis.itemState |= ODS_DISABLED;
00513         dis.itemData     = item ? item->data : 0;
00514         dis.rcItem       = *rect;
00515         dprintf2(("[%04x]: drawitem %d (%s) action=%02x "
00516                      "state=%02x rect=%d,%d-%d,%d\n",
00517                      hwnd, index, item ? item->str : "", action,
00518                      dis.itemState, rect->left, rect->top,
00519                      rect->right, rect->bottom ));
00520         SendMessageA(descr->owner, WM_DRAWITEM, id, (LPARAM)&dis);
00521     }
00522     else
00523     {
00524         COLORREF oldText = 0, oldBk = 0;
00525 
00526         if (action == ODA_FOCUS)
00527         {
00528             DrawFocusRect( hdc, rect );
00529             return;
00530         }
00531         if (item && item->selected)
00532         {
00533             oldBk = SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
00534             oldText = SetTextColor( hdc, GetSysColor(COLOR_HIGHLIGHTTEXT));
00535         }
00536 
00537         //TRACE("[%04x]: painting %d (%s) action=%02x "
00538         //             "rect=%d,%d-%d,%d\n",
00539         //             wnd->hwndSelf, index, item ? item->str : "", action,
00540         //             rect->left, rect->top, rect->right, rect->bottom );
00541         if (!item)
00542             ExtTextOutA( hdc, rect->left + 1, rect->top,
00543                            ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
00544         else if (!(descr->style & LBS_USETABSTOPS))
00545             ExtTextOutA( hdc, rect->left + 1, rect->top,
00546                            ETO_OPAQUE | ETO_CLIPPED, rect, item->str,
00547                            strlen(item->str), NULL );
00548         else
00549         {
00550             /* Output empty string to paint background in the full width. */
00551             ExtTextOutA( hdc, rect->left + 1, rect->top,
00552                            ETO_OPAQUE | ETO_CLIPPED, rect, NULL, 0, NULL );
00553             TabbedTextOutA( hdc, rect->left + 1 , rect->top,
00554                               item->str, strlen(item->str),
00555                               descr->nb_tabs, descr->tabs, 0);
00556         }
00557         if (item && item->selected)
00558         {
00559             SetBkColor( hdc, oldBk );
00560             SetTextColor( hdc, oldText );
00561         }
00562         if ((descr->focus_item == index) &&
00563             (descr->caret_on) &&
00564             (descr->in_focus)) DrawFocusRect( hdc, rect );
00565     }
00566 }
00567 
00568 
00569 /***********************************************************************
00570  *           LISTBOX_SetRedraw
00571  *
00572  * Change the redraw flag.
00573  */
00574 static LRESULT LISTBOX_SetRedraw( HWND hwnd, LB_DESCR *descr, BOOL on )
00575 {
00576     if (on)
00577     {
00578         if (!(descr->style & LBS_NOREDRAW)) return 0;
00579         descr->style &= ~LBS_NOREDRAW;
00580         LISTBOX_UpdateScroll( hwnd, descr );
00581     }
00582     else descr->style |= LBS_NOREDRAW;
00583 
00584     return 0;
00585 }
00586 
00587 
00588 /***********************************************************************
00589  *           LISTBOX_RepaintItem
00590  *
00591  * Repaint a single item synchronously.
00592  */
00593 static void LISTBOX_RepaintItem( HWND hwnd, LB_DESCR *descr, INT index,
00594                                  UINT action )
00595 {
00596     HDC hdc;
00597     RECT rect;
00598     HFONT oldFont = 0;
00599     HBRUSH hbrush, oldBrush = 0;
00600     DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
00601 
00602     /* Do not repaint the item if the item is not visible */
00603     if ((descr->style & LBS_NOREDRAW) || !IsWindowVisible(hwnd)) return;
00604 
00605     if (LISTBOX_GetItemRect( hwnd, descr, index, &rect ) != 1) return;
00606     if (!(hdc = GetDCEx( hwnd, 0, DCX_CACHE ))) return;
00607     if (descr->font) oldFont = SelectObject( hdc, descr->font );
00608     hbrush = SendMessageA( descr->owner, WM_CTLCOLORLISTBOX,
00609                              hdc, (LPARAM)hwnd );
00610     if (hbrush) oldBrush = SelectObject( hdc, hbrush );
00611     if (dwStyle & WS_DISABLED)
00612         SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
00613     SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
00614     LISTBOX_DrawItem( hwnd, descr, hdc, &rect, index, action );
00615     if (oldFont) SelectObject( hdc, oldFont );
00616     if (oldBrush) SelectObject( hdc, oldBrush );
00617     ReleaseDC( hwnd, hdc );
00618 }
00619 
00620 
00621 /***********************************************************************
00622  *           LISTBOX_InitStorage
00623  */
00624 static LRESULT LISTBOX_InitStorage( HWND hwnd, LB_DESCR *descr, INT nb_items,
00625                                     DWORD bytes )
00626 {
00627     LB_ITEMDATA *item;
00628 
00629     nb_items += LB_ARRAY_GRANULARITY - 1;
00630     nb_items -= (nb_items % LB_ARRAY_GRANULARITY);
00631     if (descr->items)
00632         nb_items += HeapSize( descr->heap, 0, descr->items ) / sizeof(*item);
00633     if (!(item = (LB_ITEMDATA*)HeapReAlloc( descr->heap, 0, descr->items,
00634                                  nb_items * sizeof(LB_ITEMDATA) )))
00635     {
00636         SEND_NOTIFICATION( hwnd, descr, LBN_ERRSPACE );
00637         return LB_ERRSPACE;
00638     }
00639     descr->items = item;
00640     return LB_OKAY;
00641 }
00642 
00643 
00644 /***********************************************************************
00645  *           LISTBOX_SetTabStops
00646  */
00647 static BOOL LISTBOX_SetTabStops( HWND hwnd, LB_DESCR *descr, INT count,
00648                                    LPINT tabs, BOOL short_ints )
00649 {
00650     if (!(descr->style & LBS_USETABSTOPS)) return TRUE;
00651     if (descr->tabs) HeapFree( descr->heap, 0, descr->tabs );
00652     if (!(descr->nb_tabs = count))
00653     {
00654         descr->tabs = NULL;
00655         return TRUE;
00656     }
00657     /* FIXME: count = 1 */
00658     if (!(descr->tabs = (INT *)HeapAlloc( descr->heap, 0,
00659                                             descr->nb_tabs * sizeof(INT) )))
00660         return FALSE;
00661     if (short_ints)
00662     {
00663         INT i;
00664         LPINT16 p = (LPINT16)tabs;
00665 
00666         for (i = 0; i < descr->nb_tabs; i++) {
00667             descr->tabs[i] = *p++<<1; /* FIXME */
00668             //if(TRACE_ON(listbox))
00669             //  dsprintf(listbox, "%hd ", descr->tabs[i]);
00670         }
00671         //TRACE("[%04x]: settabstops %s\n",
00672         //             wnd->hwndSelf, dbg_str(listbox));
00673     }
00674     else memcpy( descr->tabs, tabs, descr->nb_tabs * sizeof(INT) );
00675     /* FIXME: repaint the window? */
00676     return TRUE;
00677 }
00678 
00679 
00680 /***********************************************************************
00681  *           LISTBOX_GetText
00682  */
00683 static LRESULT LISTBOX_GetText( HWND hwnd, LB_DESCR *descr, INT index,
00684                                 LPSTR buffer )
00685 {
00686     if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
00687     if (HAS_STRINGS(descr))
00688     {
00689         if (!buffer)
00690                 return strlen(descr->items[index].str);
00691         lstrcpyA( buffer, descr->items[index].str );
00692         return strlen(buffer);
00693     } else {
00694         if (buffer)
00695                 *((LPDWORD)buffer)=*(LPDWORD)(&descr->items[index].data);
00696         return sizeof(DWORD);
00697     }
00698 }
00699 
00700 
00701 /***********************************************************************
00702  *           LISTBOX_FindStringPos
00703  *
00704  * Find the nearest string located before a given string in sort order.
00705  * If 'exact' is TRUE, return an error if we don't get an exact match.
00706  */
00707 static INT LISTBOX_FindStringPos( HWND hwnd, LB_DESCR *descr, LPCSTR str,
00708                                     BOOL exact )
00709 {
00710     INT index, min, max, res = -1;
00711 
00712     if (!(descr->style & LBS_SORT)) return -1;  /* Add it at the end */
00713     min = 0;
00714     max = descr->nb_items;
00715     while (min != max)
00716     {
00717         index = (min + max) / 2;
00718         if (HAS_STRINGS(descr))
00719             res = lstrcmpiA( descr->items[index].str, str );
00720         else
00721         {
00722             COMPAREITEMSTRUCT cis;
00723             UINT                id = GetWindowLongA(hwnd,GWL_ID);
00724 
00725             cis.CtlType    = ODT_LISTBOX;
00726             cis.CtlID      = id;
00727             cis.hwndItem   = hwnd;
00728             cis.itemID1    = index;
00729             cis.itemData1  = descr->items[index].data;
00730             cis.itemID2    = -1;
00731             cis.itemData2  = (DWORD)str;
00732             cis.dwLocaleId = descr->locale;
00733             res = SendMessageA( descr->owner, WM_COMPAREITEM,
00734                                   id, (LPARAM)&cis );
00735         }
00736         if (!res) return index;
00737         if (res > 0) max = index;
00738         else min = index + 1;
00739     }
00740     return exact ? -1 : max;
00741 }
00742 
00743 
00744 /***********************************************************************
00745  *           LISTBOX_FindFileStrPos
00746  *
00747  * Find the nearest string located before a given string in directory
00748  * sort order (i.e. first files, then directories, then drives).
00749  */
00750 static INT LISTBOX_FindFileStrPos( HWND hwnd, LB_DESCR *descr, LPCSTR str )
00751 {
00752     INT min, max, res = -1;
00753 
00754     if (!HAS_STRINGS(descr))
00755         return LISTBOX_FindStringPos( hwnd, descr, str, FALSE );
00756     min = 0;
00757     max = descr->nb_items;
00758     while (min != max)
00759     {
00760         INT index = (min + max) / 2;
00761         const char *p = descr->items[index].str;
00762         if (*p == '[')  /* drive or directory */
00763         {
00764             if (*str != '[') res = -1;
00765             else if (p[1] == '-')  /* drive */
00766             {
00767                 if (str[1] == '-') res = str[2] - p[2];
00768                 else res = -1;
00769             }
00770             else  /* directory */
00771             {
00772                 if (str[1] == '-') res = 1;
00773                 else res = lstrcmpiA( str, p );
00774             }
00775         }
00776         else  /* filename */
00777         {
00778             if (*str == '[') res = 1;
00779             else res = lstrcmpiA( str, p );
00780         }
00781         if (!res) return index;
00782         if (res < 0) max = index;
00783         else min = index + 1;
00784     }
00785     return max;
00786 }
00787 
00788 
00789 /***********************************************************************
00790  *           LISTBOX_FindString
00791  *
00792  * Find the item beginning with a given string.
00793  */
00794 static INT LISTBOX_FindString( HWND hwnd, LB_DESCR *descr, INT start,
00795                                  LPCSTR str, BOOL exact )
00796 {
00797     INT i;
00798     LB_ITEMDATA *item;
00799 
00800     if (start >= descr->nb_items) start = -1;
00801     item = descr->items + start + 1;
00802     if (HAS_STRINGS(descr))
00803     {
00804         if (!str || !str[0]) return LB_ERR;
00805         if (exact)
00806         {
00807             for (i = start + 1; i < descr->nb_items; i++, item++)
00808                 if (!lstrcmpiA( str, item->str )) return i;
00809             for (i = 0, item = descr->items; i <= start; i++, item++)
00810                 if (!lstrcmpiA( str, item->str )) return i;
00811         }
00812         else
00813         {
00814  /* Special case for drives and directories: ignore prefix */
00815 #define CHECK_DRIVE(item) \
00816     if ((item)->str[0] == '[') \
00817     { \
00818         if (!lstrcmpiA( str, (item)->str+1)) return i; \
00819         if (((item)->str[1] == '-') && !lstrcmpiA(str,(item)->str+2)) \
00820         return i; \
00821     }
00822 
00823             for (i = start + 1; i < descr->nb_items; i++, item++)
00824             {
00825                if (!lstrcmpiA( str, item->str)) return i;
00826                CHECK_DRIVE(item);
00827             }
00828             for (i = 0, item = descr->items; i <= start; i++, item++)
00829             {
00830                if (!lstrcmpiA( str, item->str)) return i;
00831                CHECK_DRIVE(item);
00832             }
00833 #undef CHECK_DRIVE
00834         }
00835     }
00836     else
00837     {
00838         if (exact && (descr->style & LBS_SORT))
00839             /* If sorted, use a WM_COMPAREITEM binary search */
00840             return LISTBOX_FindStringPos( hwnd, descr, str, TRUE );
00841 
00842         /* Otherwise use a linear search */
00843         for (i = start + 1; i < descr->nb_items; i++, item++)
00844             if (item->data == (DWORD)str) return i;
00845         for (i = 0, item = descr->items; i <= start; i++, item++)
00846             if (item->data == (DWORD)str) return i;
00847     }
00848     return LB_ERR;
00849 }
00850 
00851 
00852 /***********************************************************************
00853  *           LISTBOX_GetSelCount
00854  */
00855 static LRESULT LISTBOX_GetSelCount( HWND hwnd, LB_DESCR *descr )
00856 {
00857     INT i, count;
00858     LB_ITEMDATA *item = descr->items;
00859 
00860     if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
00861     for (i = count = 0; i < descr->nb_items; i++, item++)
00862         if (item->selected) count++;
00863     return count;
00864 }
00865 
00866 
00867 /***********************************************************************
00868  *           LISTBOX_GetSelItems32
00869  */
00870 static LRESULT LISTBOX_GetSelItems( HWND hwnd, LB_DESCR *descr, INT max,
00871                                       LPINT array )
00872 {
00873     INT i, count;
00874     LB_ITEMDATA *item = descr->items;
00875 
00876     if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
00877     for (i = count = 0; (i < descr->nb_items) && (count < max); i++, item++)
00878         if (item->selected) array[count++] = i;
00879     return count;
00880 }
00881 
00882 
00883 /***********************************************************************
00884  *           LISTBOX_Draw
00885  */
00886 static LRESULT LISTBOX_Draw( HWND hwnd, LB_DESCR *descr, HDC hdc )
00887 {
00888     INT i, col_pos = descr->page_size - 1;
00889     RECT rect;
00890     RECT focusRect = {-1, -1, -1, -1};
00891     HFONT oldFont = 0;
00892     HBRUSH hbrush, oldBrush = 0;
00893     DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
00894     INT focusItem;
00895 
00896     if (descr->style & LBS_NOREDRAW) return 0;
00897 
00898     SetRect( &rect, 0, 0, descr->width, descr->height );
00899     if (descr->style & LBS_MULTICOLUMN)
00900         rect.right = rect.left + descr->column_width;
00901     else if (descr->horz_pos)
00902     {
00903         SetWindowOrgEx( hdc, descr->horz_pos, 0, NULL );
00904         rect.right += descr->horz_pos;
00905     }
00906 
00907     if (descr->font) oldFont = SelectObject( hdc, descr->font );
00908     hbrush = SendMessageA( descr->owner, WM_CTLCOLORLISTBOX,
00909                              hdc, (LPARAM)hwnd );
00910     if (hbrush) oldBrush = SelectObject( hdc, hbrush );
00911     if (dwStyle & WS_DISABLED)
00912         SetTextColor( hdc, GetSysColor( COLOR_GRAYTEXT ) );
00913 
00914     if (!descr->nb_items && (descr->focus_item != -1) && descr->caret_on &&
00915         (descr->in_focus))
00916     {
00917         /* Special case for empty listbox: paint focus rect */
00918         rect.bottom = rect.top + descr->item_height;
00919         LISTBOX_DrawItem( hwnd, descr, hdc, &rect, descr->focus_item,
00920                            ODA_FOCUS );
00921         rect.top = rect.bottom;
00922     }
00923 
00924     /* Paint all the item, regarding the selection
00925        Focus state will be painted after  */
00926     focusItem = descr->focus_item;
00927     descr->focus_item = -1;
00928 
00929     for (i = descr->top_item; i < descr->nb_items; i++)
00930     {
00931         if (!(descr->style & LBS_OWNERDRAWVARIABLE))
00932             rect.bottom = rect.top + descr->item_height;
00933         else
00934             rect.bottom = rect.top + descr->items[i].height;
00935 
00936         if (i == focusItem)
00937         {
00938             /* keep the focus rect, to paint the focus item after */
00939             focusRect.left = rect.left;
00940             focusRect.right = rect.right;
00941             focusRect.top = rect.top;
00942             focusRect.bottom = rect.bottom;
00943         }
00944         LISTBOX_DrawItem( hwnd, descr, hdc, &rect, i, ODA_DRAWENTIRE );
00945         rect.top = rect.bottom;
00946 
00947         if ((descr->style & LBS_MULTICOLUMN) && !col_pos)
00948         {
00949             if (!IS_OWNERDRAW(descr))
00950             {
00951                 /* Clear the bottom of the column */
00952                 SetBkColor( hdc, GetSysColor( COLOR_WINDOW ) );
00953                 if (rect.top < descr->height)
00954                 {
00955                     rect.bottom = descr->height;
00956                     ExtTextOutA( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
00957                                    &rect, NULL, 0, NULL );
00958                 }
00959             }
00960 
00961             /* Go to the next column */
00962             rect.left += descr->column_width;
00963             rect.right += descr->column_width;
00964             rect.top = 0;
00965             col_pos = descr->page_size - 1;
00966         }
00967         else
00968         {
00969             col_pos--;
00970             if (rect.top >= descr->height) break;
00971         }
00972     }
00973 
00974     /* Paint the focus item now */
00975     descr->focus_item = focusItem;
00976     if (focusRect.top != focusRect.bottom && descr->caret_on)
00977         LISTBOX_DrawItem( hwnd, descr, hdc, &focusRect, descr->focus_item, ODA_FOCUS );
00978 
00979     if (!IS_OWNERDRAW(descr))
00980     {
00981         /* Clear the remainder of the client area */
00982         SetBkColor( hdc, GetSysColor( COLOR_WINDOW ) );
00983         if (rect.top < descr->height)
00984         {
00985             rect.bottom = descr->height;
00986             ExtTextOutA( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
00987                            &rect, NULL, 0, NULL );
00988         }
00989         if (rect.right < descr->width)
00990         {
00991             rect.left   = rect.right;
00992             rect.right  = descr->width;
00993             rect.top    = 0;
00994             rect.bottom = descr->height;
00995             ExtTextOutA( hdc, 0, 0, ETO_OPAQUE | ETO_CLIPPED,
00996                            &rect, NULL, 0, NULL );
00997         }
00998     }
00999     if (oldFont) SelectObject( hdc, oldFont );
01000     if (oldBrush) SelectObject( hdc, oldBrush );
01001     return 0;
01002 }
01003 
01004 
01005 /***********************************************************************
01006  *           LISTBOX_InvalidateItems
01007  *
01008  * Invalidate all items from a given item. If the specified item is not
01009  * visible, nothing happens.
01010  */
01011 static void LISTBOX_InvalidateItems( HWND hwnd, LB_DESCR *descr, INT index )
01012 {
01013     RECT rect;
01014 
01015     if (descr->style & LBS_NOREDRAW) return;
01016 
01017     if (LISTBOX_GetItemRect( hwnd, descr, index, &rect ) == 1)
01018     {
01019         rect.bottom = descr->height;
01020         InvalidateRect( hwnd, &rect, TRUE );
01021         if (descr->style & LBS_MULTICOLUMN)
01022         {
01023             /* Repaint the other columns */
01024             rect.left  = rect.right;
01025             rect.right = descr->width;
01026             rect.top   = 0;
01027             InvalidateRect( hwnd, &rect, TRUE );
01028         }
01029     }
01030 }
01031 
01032 
01033 /***********************************************************************
01034  *           LISTBOX_GetItemHeight
01035  */
01036 static LRESULT LISTBOX_GetItemHeight( HWND hwnd, LB_DESCR *descr, INT index )
01037 {
01038     if (descr->style & LBS_OWNERDRAWVARIABLE)
01039     {
01040         if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
01041         return descr->items[index].height;
01042     }
01043     else return descr->item_height;
01044 }
01045 
01046 
01047 /***********************************************************************
01048  *           LISTBOX_SetItemHeight
01049  */
01050 static LRESULT LISTBOX_SetItemHeight( HWND hwnd, LB_DESCR *descr, INT index,
01051                                       UINT height )
01052 {
01053     if (!height) height = 1;
01054 
01055     if (descr->style & LBS_OWNERDRAWVARIABLE)
01056     {
01057         if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
01058         //TRACE("[%04x]: item %d height = %d\n",
01059         //             wnd->hwndSelf, index, height );
01060         descr->items[index].height = height;
01061         LISTBOX_UpdateScroll( hwnd, descr );
01062         LISTBOX_InvalidateItems( hwnd, descr, index );
01063     }
01064     else if (height != descr->item_height)
01065     {
01066         //TRACE("[%04x]: new height = %d\n",
01067         //             wnd->hwndSelf, height );
01068         descr->item_height = height;
01069         LISTBOX_UpdatePage( hwnd, descr );
01070         LISTBOX_UpdateScroll( hwnd, descr );
01071         InvalidateRect( hwnd, 0, TRUE );
01072     }
01073     return LB_OKAY;
01074 }
01075 
01076 
01077 /***********************************************************************
01078  *           LISTBOX_SetHorizontalPos
01079  */
01080 static void LISTBOX_SetHorizontalPos( HWND hwnd, LB_DESCR *descr, INT pos )
01081 {
01082     INT diff;
01083 
01084     if (pos > descr->horz_extent - descr->width)
01085         pos = descr->horz_extent - descr->width;
01086     if (pos < 0) pos = 0;
01087     if (!(diff = descr->horz_pos - pos)) return;
01088     //TRACE("[%04x]: new horz pos = %d\n",
01089     //             wnd->hwndSelf, pos );
01090     descr->horz_pos = pos;
01091     LISTBOX_UpdateScroll( hwnd, descr );
01092     if (abs(diff) < descr->width)
01093         ScrollWindowEx( hwnd, diff, 0, NULL, NULL, 0, NULL,
01094                           SW_INVALIDATE | SW_ERASE | SW_SCROLLCHILDREN );
01095     else
01096         InvalidateRect( hwnd, NULL, TRUE );
01097 }
01098 
01099 
01100 /***********************************************************************
01101  *           LISTBOX_SetHorizontalExtent
01102  */
01103 static LRESULT LISTBOX_SetHorizontalExtent( HWND hwnd, LB_DESCR *descr,
01104                                             UINT extent )
01105 {
01106     if (!descr->horz_extent || (descr->style & LBS_MULTICOLUMN))
01107         return LB_OKAY;
01108     if (extent <= 0) extent = 1;
01109     if (extent == descr->horz_extent) return LB_OKAY;
01110     //TRACE("[%04x]: new horz extent = %d\n",
01111     //             wnd->hwndSelf, extent );
01112     descr->horz_extent = extent;
01113     if (descr->horz_pos > extent - descr->width)
01114         LISTBOX_SetHorizontalPos( hwnd, descr, extent - descr->width );
01115     else
01116         LISTBOX_UpdateScroll( hwnd, descr );
01117     return LB_OKAY;
01118 }
01119 
01120 
01121 /***********************************************************************
01122  *           LISTBOX_SetColumnWidth
01123  */
01124 static LRESULT LISTBOX_SetColumnWidth( HWND hwnd, LB_DESCR *descr, UINT width)
01125 {
01126     if (width == descr->column_width) return LB_OKAY;
01127     //TRACE("[%04x]: new column width = %d\n",
01128     //             wnd->hwndSelf, width );
01129     descr->column_width = width;
01130     LISTBOX_UpdatePage( hwnd, descr );
01131     return LB_OKAY;
01132 }
01133 
01134 
01135 /***********************************************************************
01136  *           LISTBOX_SetFont
01137  *
01138  * Returns the item height.
01139  */
01140 static LRESULT LISTBOX_SetFont(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
01141 {
01142     HDC hdc;
01143     HFONT oldFont = 0;
01144     TEXTMETRICA tm;
01145 
01146     descr->font = (HFONT)wParam;
01147 
01148     if (!(hdc = GetDCEx( hwnd, 0, DCX_CACHE )))
01149     {
01150       //ERR("unable to get DC.\n" );
01151       descr->item_height =  16;
01152       return 0;
01153     }
01154     if (descr->font) oldFont = SelectObject(hdc,descr->font);
01155     GetTextMetricsA( hdc, &tm );
01156     if (oldFont) SelectObject( hdc, oldFont );
01157     ReleaseDC( hwnd, hdc );
01158     if (!IS_OWNERDRAW(descr))
01159         LISTBOX_SetItemHeight( hwnd, descr, 0, tm.tmHeight );
01160 
01161     descr->item_height =  tm.tmHeight;
01162 
01163     if (lParam) InvalidateRect( hwnd, 0, TRUE );
01164 
01165     return 0;
01166 }
01167 
01168 
01169 /***********************************************************************
01170  *           LISTBOX_MakeItemVisible
01171  *
01172  * Make sure that a given item is partially or fully visible.
01173  */
01174 static void LISTBOX_MakeItemVisible( HWND hwnd, LB_DESCR *descr, INT index,
01175                                      BOOL fully )
01176 {
01177     INT top;
01178 
01179     if (index <= descr->top_item) top = index;
01180     else if (descr->style & LBS_MULTICOLUMN)
01181     {
01182         INT cols = descr->width;
01183         if (!fully) cols += descr->column_width - 1;
01184         if (cols >= descr->column_width) cols /= descr->column_width;
01185         else cols = 1;
01186         if (index < descr->top_item + (descr->page_size * cols)) return;
01187         top = index - descr->page_size * (cols - 1);
01188     }
01189     else if (descr->style & LBS_OWNERDRAWVARIABLE)
01190     {
01191         INT height = fully ? descr->items[index].height : 1;
01192         for (top = index; top > descr->top_item; top--)
01193             if ((height += descr->items[top-1].height) > descr->height) break;
01194     }
01195     else
01196     {
01197         if (index < descr->top_item + descr->page_size) return;
01198         if (!fully && (index == descr->top_item + descr->page_size) &&
01199             (descr->height > (descr->page_size * descr->item_height))) return;
01200         top = index - descr->page_size + 1;
01201     }
01202     LISTBOX_SetTopItem( hwnd, descr, top, TRUE );
01203 }
01204 
01205 
01206 /***********************************************************************
01207  *           LISTBOX_SelectItemRange
01208  *
01209  * Select a range of items. Should only be used on a MULTIPLESEL listbox.
01210  */
01211 static LRESULT LISTBOX_SelectItemRange( HWND hwnd, LB_DESCR *descr, INT first,
01212                                         INT last, BOOL on )
01213 {
01214     INT i;
01215 
01216     /* A few sanity checks */
01217 
01218     if ((last == -1) && (descr->nb_items == 0)) return LB_OKAY;
01219     if (!(descr->style & LBS_MULTIPLESEL)) return LB_ERR;
01220     if (last == -1) last = descr->nb_items - 1;
01221     if ((first < 0) || (first >= descr->nb_items)) return LB_ERR;
01222     if ((last < 0) || (last >= descr->nb_items)) return LB_ERR;
01223     /* selected_item reflects last selected/unselected item on multiple sel */
01224     descr->selected_item = last;
01225 
01226     if (on)  /* Turn selection on */
01227     {
01228         for (i = first; i <= last; i++)
01229         {
01230             if (descr->items[i].selected) continue;
01231             descr->items[i].selected = TRUE;
01232             LISTBOX_RepaintItem( hwnd, descr, i, ODA_SELECT );
01233         }
01234     }
01235     else  /* Turn selection off */
01236     {
01237         for (i = first; i <= last; i++)
01238         {
01239             if (!descr->items[i].selected) continue;
01240             descr->items[i].selected = FALSE;
01241             LISTBOX_RepaintItem( hwnd, descr, i, ODA_SELECT );
01242         }
01243     }
01244     return LB_OKAY;
01245 }
01246 
01247 
01248 /***********************************************************************
01249  *           LISTBOX_SetCaretIndex
01250  *
01251  * NOTES
01252  *   index must be between 0 and descr->nb_items-1, or LB_ERR is returned.
01253  *
01254  */
01255 static LRESULT LISTBOX_SetCaretIndex( HWND hwnd, LB_DESCR *descr, INT index,
01256                                       BOOL fully_visible )
01257 {
01258     INT oldfocus = descr->focus_item;
01259 
01260     if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
01261     if (index == oldfocus) return LB_OKAY;
01262     descr->focus_item = index;
01263     if ((oldfocus != -1) && descr->caret_on && (descr->in_focus))
01264         LISTBOX_RepaintItem( hwnd, descr, oldfocus, ODA_FOCUS );
01265 
01266     LISTBOX_MakeItemVisible( hwnd, descr, index, fully_visible );
01267     if (descr->caret_on && (descr->in_focus))
01268         LISTBOX_RepaintItem( hwnd, descr, index, ODA_FOCUS );
01269 
01270     return LB_OKAY;
01271 }
01272 
01273 
01274 /***********************************************************************
01275  *           LISTBOX_SetSelection
01276  */
01277 static LRESULT LISTBOX_SetSelection( HWND hwnd, LB_DESCR *descr, INT index,
01278                                      BOOL on, BOOL send_notify )
01279 {
01280     if ((index < -1) || (index >= descr->nb_items)) return LB_ERR;
01281     if (descr->style & LBS_MULTIPLESEL)
01282     {
01283         if (index == -1)  /* Select all items */
01284             return LISTBOX_SelectItemRange( hwnd, descr, 0, -1, on );
01285         else  /* Only one item */
01286             return LISTBOX_SelectItemRange( hwnd, descr, index, index, on );
01287     }
01288     else
01289     {
01290         INT oldsel = descr->selected_item;
01291 
01292         if (index != oldsel)
01293         {
01294           if (oldsel != -1) descr->items[oldsel].selected = FALSE;
01295           if (index != -1) descr->items[index].selected = TRUE;
01296 
01297           descr->selected_item = index;
01298 
01299           if (oldsel != -1)
01300             LISTBOX_RepaintItem( hwnd, descr, oldsel, ODA_SELECT);
01301           if (index != -1)
01302             LISTBOX_RepaintItem( hwnd, descr, index, ODA_SELECT );
01303 
01304           if (send_notify && descr->nb_items)
01305             SEND_NOTIFICATION( hwnd, descr, (index != -1)
01306                                ? LBN_SELCHANGE : LBN_SELCANCEL );
01307           else
01308             if( descr->lphc )
01309               /* set selection change flag for parent combo */
01310               descr->lphc->wState |= CBF_SELCHANGE;
01311         }
01312     }
01313 
01314     /* "If the index parameter is -1, the return value is LB_ERR even though
01315      * no error occurred." (At least for single selection boxes.) */
01316     return (index == -1) ? LB_ERR : LB_OKAY;
01317 }
01318 
01319 
01320 /***********************************************************************
01321  *           LISTBOX_MoveCaret
01322  *
01323  * Change the caret position and extend the selection to the new caret.
01324  */
01325 static void LISTBOX_MoveCaret( HWND hwnd, LB_DESCR *descr, INT index,
01326                                BOOL fully_visible )
01327 {
01328     INT oldfocus = descr->focus_item;
01329 
01330     if ((index <  0) || (index >= descr->nb_items) || (oldfocus == index))
01331         return;
01332 
01333     /* Important, repaint need ot be done in this order if
01334        you want to mimic Windows behavior:
01335        1. Remove the focus and paint the item
01336        2. Remove the selection and paint the item(s)
01337        3. Set the selection and repaint the item(s)
01338        4. Set the focus to 'index' and repaint the item */
01339 
01340     /* 1. remove the focus and repaint the item */
01341     descr->focus_item = -1;
01342     if ((oldfocus != -1) && descr->caret_on && (descr->in_focus))
01343         LISTBOX_RepaintItem( hwnd, descr, oldfocus, ODA_FOCUS );
01344 
01345     /* 2. then turn off the previous selection */
01346     /* 3. repaint the new selected item */
01347     if (descr->style & LBS_EXTENDEDSEL)
01348     {
01349         if (descr->anchor_item != -1)
01350         {
01351             INT first = MIN( index, descr->anchor_item );
01352             INT last  = MAX( index, descr->anchor_item );
01353             if (first > 0)
01354                 LISTBOX_SelectItemRange( hwnd, descr, 0, first - 1, FALSE );
01355             LISTBOX_SelectItemRange( hwnd, descr, last + 1, -1, FALSE );
01356             LISTBOX_SelectItemRange( hwnd, descr, first, last, TRUE );
01357         }
01358     }
01359     else if (!(descr->style & LBS_MULTIPLESEL))
01360     {
01361         /* Set selection to new caret item */
01362         LISTBOX_SetSelection( hwnd, descr, index, TRUE, FALSE );
01363     }
01364 
01365     /* 4. repaint the new item with the focus */
01366     descr->focus_item = index;
01367     LISTBOX_MakeItemVisible( hwnd, descr, index, fully_visible );
01368     if (descr->caret_on && (descr->in_focus))
01369         LISTBOX_RepaintItem( hwnd, descr, index, ODA_FOCUS );
01370 }
01371 
01372 
01373 /***********************************************************************
01374  *           LISTBOX_InsertItem
01375  */
01376 static LRESULT LISTBOX_InsertItem( HWND hwnd, LB_DESCR *descr, INT index,
01377                                    LPSTR str, DWORD data )
01378 {
01379     LB_ITEMDATA *item;
01380     INT max_items;
01381     INT oldfocus = descr->focus_item;
01382 
01383     if (index == -1) index = descr->nb_items;
01384     else if ((index < 0) || (index > descr->nb_items)) return LB_ERR;
01385     if (!descr->items) max_items = 0;
01386     else max_items = HeapSize( descr->heap, 0, descr->items ) / sizeof(*item);
01387     if (descr->nb_items == max_items)
01388     {
01389         /* We need to grow the array */
01390         max_items += LB_ARRAY_GRANULARITY;
01391         if (!(item = (LB_ITEMDATA*)HeapReAlloc( descr->heap, 0, descr->items,
01392                                      max_items * sizeof(LB_ITEMDATA) )))
01393         {
01394             SEND_NOTIFICATION( hwnd, descr, LBN_ERRSPACE );
01395             return LB_ERRSPACE;
01396         }
01397         descr->items = item;
01398     }
01399 
01400     /* Insert the item structure */
01401 
01402     item = &descr->items[index];
01403     if (index < descr->nb_items)
01404         RtlMoveMemory( item + 1, item,
01405                        (descr->nb_items - index) * sizeof(LB_ITEMDATA) );
01406     item->str      = str;
01407     item->data     = data;
01408     item->height   = 0;
01409     item->selected = FALSE;
01410     descr->nb_items++;
01411 
01412     /* Get item height */
01413 
01414     if (descr->style & LBS_OWNERDRAWVARIABLE)
01415     {
01416         MEASUREITEMSTRUCT mis;
01417         UINT              id = GetWindowLongA(hwnd,GWL_ID);
01418 
01419         mis.CtlType    = ODT_LISTBOX;
01420         mis.CtlID      = id;
01421         mis.itemID     = index;
01422         mis.itemData   = descr->items[index].data;
01423         mis.itemHeight = descr->item_height;
01424         SendMessageA( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
01425         item->height = mis.itemHeight ? mis.itemHeight : 1;
01426         //TRACE("[%04x]: measure item %d (%s) = %d\n",
01427         //             wnd->hwndSelf, index, str ? str : "", item->height );
01428     }
01429 
01430     /* Repaint the items */
01431 
01432     LISTBOX_UpdateScroll( hwnd, descr );
01433     LISTBOX_InvalidateItems( hwnd, descr, index );
01434 
01435     /* Move selection and focused item */
01436     /* If listbox was empty, set focus to the first item */
01437     if (descr->nb_items == 1)
01438          LISTBOX_SetCaretIndex( hwnd, descr, 0, FALSE );
01439     /* single select don't change selection index in win31 */
01440     else
01441     {
01442         if (index <= descr->selected_item)
01443         {
01444            descr->selected_item++;
01445            descr->focus_item = oldfocus; /* focus not changed */
01446         }
01447     }
01448     return LB_OKAY;
01449 }
01450 
01451 /***********************************************************************
01452  *           LISTBOX_InsertString
01453  */
01454 static LRESULT LISTBOX_InsertString( HWND hwnd, LB_DESCR *descr, INT index,
01455                                      LPCSTR str )
01456 {
01457     LPSTR new_str = NULL;
01458     DWORD data = 0;
01459     LRESULT ret;
01460 
01461     if (HAS_STRINGS(descr))
01462     {
01463         if (!str) str="";
01464         if (!(new_str = HEAP_strdupA( descr->heap, 0, str )))
01465         {
01466             SEND_NOTIFICATION( hwnd, descr, LBN_ERRSPACE );
01467             return LB_ERRSPACE;
01468         }
01469     }
01470     else data = (DWORD)str;
01471 
01472     if (index == -1) index = descr->nb_items;
01473     if ((ret = LISTBOX_InsertItem( hwnd, descr, index, new_str, data )) != 0)
01474     {
01475         if (new_str) HeapFree( descr->heap, 0, new_str );
01476         return ret;
01477     }
01478 
01479     //TRACE("[%04x]: added item %d '%s'\n",
01480     //             wnd->hwndSelf, index, HAS_STRINGS(descr) ? new_str : "" );
01481     return index;
01482 }
01483 
01484 static LRESULT LISTBOX_AddString(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
01485 {
01486   wParam = LISTBOX_FindStringPos( hwnd, descr, (LPCSTR)lParam, FALSE );
01487   return LISTBOX_InsertString( hwnd, descr, wParam, (LPCSTR)lParam );
01488 }
01489 
01490 static LRESULT LISTBOX_AddFile(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
01491 {
01492   wParam = LISTBOX_FindFileStrPos( hwnd, descr, (LPCSTR)lParam );
01493   return LISTBOX_InsertString( hwnd, descr, wParam, (LPCSTR)lParam );
01494 }
01495 
01496 /***********************************************************************
01497  *           LISTBOX_DeleteItem
01498  *
01499  * Delete the content of an item. 'index' must be a valid index.
01500  */
01501 static void LISTBOX_DeleteItem( HWND hwnd, LB_DESCR *descr, INT index )
01502 {
01503     /* Note: Win 3.1 only sends DELETEITEM on owner-draw items,
01504      *       while Win95 sends it for all items with user data.
01505      *       It's probably better to send it too often than not
01506      *       often enough, so this is what we do here.
01507      */
01508     if (IS_OWNERDRAW(descr) || descr->items[index].data)
01509     {
01510         DELETEITEMSTRUCT dis;
01511         UINT             id = GetWindowLongA(hwnd,GWL_ID);
01512 
01513         dis.CtlType  = ODT_LISTBOX;
01514         dis.CtlID    = id;
01515         dis.itemID   = index;
01516         dis.hwndItem = hwnd;
01517         dis.itemData = descr->items[index].data;
01518         SendMessageA( descr->owner, WM_DELETEITEM, id, (LPARAM)&dis );
01519     }
01520     if (HAS_STRINGS(descr) && descr->items[index].str)
01521         HeapFree( descr->heap, 0, descr->items[index].str );
01522 }
01523 
01524 
01525 /***********************************************************************
01526  *           LISTBOX_RemoveItem
01527  *
01528  * Remove an item from the listbox and delete its content.
01529  */
01530 static LRESULT LISTBOX_RemoveItem( HWND hwnd, LB_DESCR *descr, INT index )
01531 {
01532     LB_ITEMDATA *item;
01533     INT max_items;
01534 
01535     if (index == -1) index = descr->nb_items - 1;
01536     else if ((index < 0) || (index >= descr->nb_items)) return LB_ERR;
01537 
01538     /* We need to Invalidate the original rect intead of the updated one. */
01539     LISTBOX_InvalidateItems( hwnd, descr, index );
01540 
01541     LISTBOX_DeleteItem( hwnd, descr, index );
01542 
01543     /* Remove the item */
01544 
01545     item = &descr->items[index];
01546     if (index < descr->nb_items-1)
01547         RtlMoveMemory( item, item + 1,
01548                        (descr->nb_items - index - 1) * sizeof(LB_ITEMDATA) );
01549     descr->nb_items--;
01550     if (descr->anchor_item == descr->nb_items) descr->anchor_item--;
01551 
01552     /* Shrink the item array if possible */
01553 
01554     max_items = HeapSize( descr->heap, 0, descr->items ) / sizeof(LB_ITEMDATA);
01555     if (descr->nb_items < max_items - 2*LB_ARRAY_GRANULARITY)
01556     {
01557         max_items -= LB_ARRAY_GRANULARITY;
01558         item = (LB_ITEMDATA*)HeapReAlloc( descr->heap, 0, descr->items,
01559                                max_items * sizeof(LB_ITEMDATA) );
01560         if (item) descr->items = item;
01561     }
01562 
01563     /* Repaint the items */
01564 
01565     LISTBOX_UpdateScroll( hwnd, descr );
01566     /* if we removed the scrollbar, reset the top of the list
01567       (correct for owner-drawn ???) */
01568     if (descr->nb_items == descr->page_size)
01569         LISTBOX_SetTopItem( hwnd, descr, 0, TRUE );
01570 
01571     /* Move selection and focused item */
01572     if (!IS_MULTISELECT(descr))
01573     {
01574         if (index == descr->selected_item)
01575             descr->selected_item = -1;
01576         else if (index < descr->selected_item)
01577       {
01578             descr->selected_item--;
01579       }
01580     }
01581 
01582     if (descr->focus_item >= descr->nb_items)
01583     {
01584           descr->focus_item = descr->nb_items - 1;
01585           if (descr->focus_item < 0) descr->focus_item = 0;
01586     }
01587     return LB_OKAY;
01588 }
01589 
01590 static LRESULT LISTBOX_DeleteString(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
01591 {
01592   if (LISTBOX_RemoveItem( hwnd, descr, wParam) != LB_ERR)
01593     return descr->nb_items;
01594   else
01595     return LB_ERR;
01596 }
01597 
01598 /***********************************************************************
01599  *           LISTBOX_ResetContent
01600  */
01601 static LRESULT LISTBOX_ResetContent( HWND hwnd, LB_DESCR *descr,BOOL refresh)
01602 {
01603     INT i;
01604 
01605     for (i = 0; i < descr->nb_items; i++) LISTBOX_DeleteItem( hwnd, descr, i );
01606     if (descr->items) HeapFree( descr->heap, 0, descr->items );
01607     descr->nb_items      = 0;
01608     descr->top_item      = 0;
01609     descr->selected_item = -1;
01610     descr->focus_item    = 0;
01611     descr->anchor_item   = -1;
01612     descr->items         = NULL;
01613     if (refresh)
01614     {
01615       LISTBOX_UpdateScroll( hwnd, descr );
01616       InvalidateRect( hwnd, NULL, TRUE );
01617     }
01618 
01619     return 0;
01620 }
01621 
01622 
01623 /***********************************************************************
01624  *           LISTBOX_SetCount
01625  */
01626 static LRESULT LISTBOX_SetCount( HWND hwnd, LB_DESCR *descr, INT count )
01627 {
01628     LRESULT ret;
01629     INT oldcount = descr->nb_items;
01630 
01631     if (HAS_STRINGS(descr) || !HAS_NODATA(descr)) return LB_ERR;
01632 
01633     if (count > descr->nb_items)
01634     {
01635       LB_ITEMDATA *item;
01636       INT max_items,index;
01637       UINT id = (descr->lphc) ? ID_CB_LISTBOX:GetWindowLongA(hwnd,GWL_ID);
01638 
01639       max_items = count+LB_ARRAY_GRANULARITY-(count % LB_ARRAY_GRANULARITY);
01640       if (!(item = (LB_ITEMDATA*)HeapReAlloc(descr->heap,0,descr->items,max_items*sizeof(LB_ITEMDATA))))
01641       {
01642         SEND_NOTIFICATION( hwnd, descr, LBN_ERRSPACE );
01643         return LB_ERRSPACE;
01644       }
01645       descr->items = item;
01646 
01647       /* Insert the item structure */
01648 
01649       index = descr->nb_items-1;
01650       while (count > descr->nb_items)
01651       {
01652         index++;
01653         item = &descr->items[index];
01654 
01655         item->str      = "";
01656         item->data     = 0;
01657         item->height   = 0;
01658         item->selected = FALSE;
01659         descr->nb_items++;
01660 
01661         /* Get item height */
01662 
01663         if (descr->style & LBS_OWNERDRAWVARIABLE)
01664         {
01665           MEASUREITEMSTRUCT mis;
01666 
01667           mis.CtlType    = ODT_LISTBOX;
01668           mis.CtlID      = id;
01669           mis.itemID     = index;
01670           mis.itemData   = descr->items[index].data;
01671           mis.itemHeight = descr->item_height;
01672           SendMessageA( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
01673           item->height = mis.itemHeight ? mis.itemHeight : 1;
01674         }
01675       }
01676     } else if (count < descr->nb_items)
01677     {
01678       descr->nb_items = count;
01679       if (descr->selected_item >= count) descr->selected_item = count-1;
01680       if (descr->focus_item >= count) descr-> focus_item = count-1;
01681     }
01682     /* Repaint the items */
01683 
01684     LISTBOX_UpdateScroll( hwnd, descr );
01685     InvalidateRect(hwnd,NULL,TRUE);
01686 
01687     /* Move selection and focused item */
01688     /* If listbox was empty, set focus to the first item */
01689     if (oldcount == 0)
01690       LISTBOX_SetCaretIndex( hwnd, descr, 0, FALSE );
01691 
01692     return LB_OKAY;
01693 }
01694 
01695 
01696 /***********************************************************************
01697  *           LISTBOX_Directory
01698  */
01699 static LRESULT LISTBOX_Directory( HWND hwnd, LB_DESCR *descr, UINT attrib,
01700                                   LPCSTR filespec, BOOL long_names )
01701 {
01702     HANDLE handle;
01703     LRESULT ret = LB_OKAY;
01704     WIN32_FIND_DATAA entry;
01705     int pos;
01706 
01707     if ((handle = FindFirstFileA(filespec,&entry)) == INVALID_HANDLE_VALUE)
01708     {
01709         if (GetLastError() != ERROR_NO_MORE_FILES) return LB_ERR;
01710     }
01711     else
01712     {
01713         do
01714         {
01715             char buffer[270];
01716             if (entry.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY)
01717             {
01718                 if (!(attrib & DDL_DIRECTORY) ||
01719                     !strcmp( entry.cAlternateFileName, "." )) continue;
01720                 if (long_names) sprintf( buffer, "[%s]", entry.cFileName );
01721                 else sprintf( buffer, "[%s]", entry.cAlternateFileName );
01722             }
01723             else  /* not a directory */
01724             {
01725 #ifdef __WIN32OS2__
01726 #define ATTRIBS (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
01727                  FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE | FILE_ATTRIBUTE_NORMAL)
01728 #else
01729 #define ATTRIBS (FILE_ATTRIBUTE_READONLY | FILE_ATTRIBUTE_HIDDEN | \
01730                  FILE_ATTRIBUTE_SYSTEM | FILE_ATTRIBUTE_ARCHIVE )
01731 #endif
01732 
01733                 if ((attrib & DDL_EXCLUSIVE) &&
01734                     ((attrib & ATTRIBS) != (entry.dwFileAttributes & ATTRIBS)))
01735                     continue;
01736 #undef ATTRIBS
01737                 if (long_names) strcpy( buffer, entry.cFileName );
01738                 else strcpy( buffer, entry.cAlternateFileName );
01739             }
01740             if (!long_names) CharLowerA( buffer );
01741             pos = LISTBOX_FindFileStrPos( hwnd, descr, buffer );
01742             if ((ret = LISTBOX_InsertString( hwnd, descr, pos, buffer )) < 0)
01743                 break;
01744         } while (FindNextFileA( handle, &entry ));
01745         FindClose( handle );
01746     }
01747 
01748     if ((ret >= 0) && (attrib & DDL_DRIVES))
01749     {
01750         char buffer[] = "[-a-]";
01751         int drive;
01752         for (drive = 0; drive < MAX_DOS_DRIVES; drive++, buffer[2]++)
01753         {
01754             if (!DRIVE_IsValid(drive)) continue;
01755             if ((ret = LISTBOX_InsertString( hwnd, descr, -1, buffer )) < 0)
01756                 break;
01757         }
01758     }
01759     return ret;
01760 }
01761 
01762 
01763 /***********************************************************************
01764  *           LISTBOX_HandleVScroll
01765  */
01766 static LRESULT LISTBOX_HandleVScroll( HWND hwnd, LB_DESCR *descr,
01767                                       WPARAM wParam, LPARAM lParam )
01768 {
01769     SCROLLINFO info;
01770 
01771     if (descr->style & LBS_MULTICOLUMN) return 0;
01772     switch(LOWORD(wParam))
01773     {
01774     case SB_LINEUP:
01775         LISTBOX_SetTopItem( hwnd, descr, descr->top_item - 1, TRUE );
01776         break;
01777     case SB_LINEDOWN:
01778         LISTBOX_SetTopItem( hwnd, descr, descr->top_item + 1, TRUE );
01779         break;
01780     case SB_PAGEUP:
01781         LISTBOX_SetTopItem( hwnd, descr, descr->top_item -
01782                             LISTBOX_GetCurrentPageSize( hwnd, descr ), TRUE );
01783         break;
01784     case SB_PAGEDOWN:
01785         LISTBOX_SetTopItem( hwnd, descr, descr->top_item +
01786                             LISTBOX_GetCurrentPageSize( hwnd, descr ), TRUE );
01787         break;
01788     case SB_THUMBPOSITION:
01789         LISTBOX_SetTopItem( hwnd, descr, HIWORD(wParam), TRUE );
01790         break;
01791     case SB_THUMBTRACK:
01792         info.cbSize = sizeof(info);
01793         info.fMask = SIF_TRACKPOS;
01794         GetScrollInfo( hwnd, SB_VERT, &info );
01795         LISTBOX_SetTopItem( hwnd, descr, info.nTrackPos, TRUE );
01796         break;
01797     case SB_TOP:
01798         LISTBOX_SetTopItem( hwnd, descr, 0, TRUE );
01799         break;
01800     case SB_BOTTOM:
01801         LISTBOX_SetTopItem( hwnd, descr, descr->nb_items, TRUE );
01802         break;
01803     }
01804     return 0;
01805 }
01806 
01807 
01808 /***********************************************************************
01809  *           LISTBOX_HandleHScroll
01810  */
01811 static LRESULT LISTBOX_HandleHScroll( HWND hwnd, LB_DESCR *descr,
01812                                       WPARAM wParam, LPARAM lParam )
01813 {
01814     SCROLLINFO info;
01815     INT page;
01816 
01817     if (descr->style & LBS_MULTICOLUMN)
01818     {
01819         switch(LOWORD(wParam))
01820         {
01821         case SB_LINELEFT:
01822             LISTBOX_SetTopItem( hwnd, descr, descr->top_item-descr->page_size,
01823                                 TRUE );
01824             break;
01825         case SB_LINERIGHT:
01826             LISTBOX_SetTopItem( hwnd, descr, descr->top_item+descr->page_size,
01827                                 TRUE );
01828             break;
01829         case SB_PAGELEFT:
01830             page = descr->width / descr->column_width;
01831             if (page < 1) page = 1;
01832             LISTBOX_SetTopItem( hwnd, descr,
01833                              descr->top_item - page * descr->page_size, TRUE );
01834             break;
01835         case SB_PAGERIGHT:
01836             page = descr->width / descr->column_width;
01837             if (page < 1) page = 1;
01838             LISTBOX_SetTopItem( hwnd, descr,
01839                              descr->top_item + page * descr->page_size, TRUE );
01840             break;
01841         case SB_THUMBPOSITION:
01842             LISTBOX_SetTopItem( hwnd, descr, HIWORD(wParam)*descr->page_size,
01843                                 TRUE );
01844             break;
01845         case SB_THUMBTRACK:
01846             info.cbSize = sizeof(info);
01847             info.fMask  = SIF_TRACKPOS;
01848             GetScrollInfo( hwnd, SB_VERT, &info );
01849             LISTBOX_SetTopItem( hwnd, descr, info.nTrackPos*descr->page_size,
01850                                 TRUE );
01851             break;
01852         case SB_LEFT:
01853             LISTBOX_SetTopItem( hwnd, descr, 0, TRUE );
01854             break;
01855         case SB_RIGHT:
01856             LISTBOX_SetTopItem( hwnd, descr, descr->nb_items, TRUE );
01857             break;
01858         }
01859     }
01860     else if (descr->horz_extent)
01861     {
01862         switch(LOWORD(wParam))
01863         {
01864         case SB_LINELEFT:
01865             LISTBOX_SetHorizontalPos( hwnd, descr, descr->horz_pos - 1 );
01866             break;
01867         case SB_LINERIGHT:
01868             LISTBOX_SetHorizontalPos( hwnd, descr, descr->horz_pos + 1 );
01869             break;
01870         case SB_PAGELEFT:
01871             LISTBOX_SetHorizontalPos( hwnd, descr,
01872                                       descr->horz_pos - descr->width );
01873             break;
01874         case SB_PAGERIGHT:
01875             LISTBOX_SetHorizontalPos( hwnd, descr,
01876                                       descr->horz_pos + descr->width );
01877             break;
01878         case SB_THUMBPOSITION:
01879             LISTBOX_SetHorizontalPos( hwnd, descr, HIWORD(wParam) );
01880             break;
01881         case SB_THUMBTRACK:
01882             info.cbSize = sizeof(info);
01883             info.fMask = SIF_TRACKPOS;
01884             GetScrollInfo( hwnd, SB_HORZ, &info );
01885             LISTBOX_SetHorizontalPos( hwnd, descr, info.nTrackPos );
01886             break;
01887         case SB_LEFT:
01888             LISTBOX_SetHorizontalPos( hwnd, descr, 0 );
01889             break;
01890         case SB_RIGHT:
01891             LISTBOX_SetHorizontalPos( hwnd, descr,
01892                                       descr->horz_extent - descr->width );
01893             break;
01894         }
01895     }
01896     return 0;
01897 }
01898 
01899 static LRESULT LISTBOX_HandleMouseWheel(HWND hwnd, LB_DESCR *descr,WPARAM wParam, LPARAM lParam )
01900 {
01901     short gcWheelDelta = 0;
01902     UINT pulScrollLines = 3;
01903 
01904     if (wParam & (MK_SHIFT | MK_CONTROL))
01905       return DefWindowProcA(hwnd,WM_MOUSEWHEEL,wParam,lParam);
01906 
01907     SystemParametersInfoW(SPI_GETWHEELSCROLLLINES,0, &pulScrollLines, 0);
01908 
01909     gcWheelDelta -= (short) HIWORD(wParam);
01910 
01911     if (abs(gcWheelDelta) >= WHEEL_DELTA && pulScrollLines)
01912     {
01913         int cLineScroll = (int) min((UINT) descr->page_size, pulScrollLines);
01914         cLineScroll *= (gcWheelDelta / WHEEL_DELTA);
01915         LISTBOX_SetTopItem( hwnd, descr, descr->top_item + cLineScroll, TRUE );
01916     }
01917     return 0;
01918 }
01919 
01920 /***********************************************************************
01921  *           LISTBOX_HandleLButtonDown
01922  */
01923 static LRESULT LISTBOX_HandleLButtonDown( HWND hwnd, LB_DESCR *descr,
01924                                           WPARAM wParam, INT x, INT y )
01925 {
01926     INT index = LISTBOX_GetItemFromPoint( hwnd, descr, x, y );
01927     //TRACE("[%04x]: lbuttondown %d,%d item %d\n",
01928     //             wnd->hwndSelf, x, y, index );
01929     if (!descr->caret_on && (descr->in_focus)) return 0;
01930     if (index != -1)
01931     {
01932         if (descr->style & LBS_EXTENDEDSEL)
01933         {
01934             if (!(wParam & MK_SHIFT)) descr->anchor_item = index;
01935             if (wParam & MK_CONTROL)
01936             {
01937                 LISTBOX_SetCaretIndex( hwnd, descr, index, FALSE );
01938                 LISTBOX_SetSelection( hwnd, descr, index,
01939                                       !descr->items[index].selected,
01940                                       (descr->style & LBS_NOTIFY) != 0 );
01941             }
01942             else LISTBOX_MoveCaret( hwnd, descr, index, FALSE );
01943         }
01944         else
01945         {
01946             LISTBOX_MoveCaret( hwnd, descr, index, FALSE );
01947             LISTBOX_SetSelection( hwnd, descr, index,
01948                                   (!(descr->style & LBS_MULTIPLESEL) ||
01949                                    !descr->items[index].selected),
01950                                    (descr->style & LBS_NOTIFY) != 0 );
01951         }
01952     }
01953 
01954     if (!descr->in_focus)
01955     {
01956       if( !descr->lphc ) SetFocus( hwnd );
01957       else SetFocus( (descr->lphc->hWndEdit) ? descr->lphc->hWndEdit
01958                                              : descr->lphc->hwndself ) ;
01959     }
01960 
01961     descr->captured = TRUE;
01962     SetCapture( hwnd );
01963     if (index != -1 && !descr->lphc)
01964     {
01965         if (descr->style & LBS_NOTIFY )
01966             SendMessageA( descr->owner, WM_LBTRACKPOINT, index,
01967                             MAKELPARAM( x, y ) );
01968         if (GetWindowLongA(hwnd,GWL_EXSTYLE) & WS_EX_DRAGDETECT)
01969         {
01970             POINT pt;
01971 
01972             pt.x = x;
01973             pt.y = y;
01974 
01975             if (DragDetect( hwnd, pt ))
01976                 SendMessageA( descr->owner, WM_BEGINDRAG, 0, 0 );
01977         }
01978     }
01979     return 0;
01980 }
01981 
01982 
01983 /*************************************************************************
01984  * LISTBOX_HandleLButtonDownCombo [Internal]
01985  *
01986  * Process LButtonDown message for the ComboListBox
01987  *
01988  * PARAMS
01989  *     pWnd       [I] The windows internal structure
01990  *     pDescr     [I] The ListBox internal structure
01991  *     wParam     [I] Key Flag (WM_LBUTTONDOWN doc for more info)
01992  *     x          [I] X Mouse Coordinate
01993  *     y          [I] Y Mouse Coordinate
01994  *
01995  * RETURNS
01996  *     0 since we are processing the WM_LBUTTONDOWN Message
01997  *
01998  * NOTES
01999  *  This function is only to be used when a ListBox is a ComboListBox
02000  */
02001 
02002 static LRESULT LISTBOX_HandleLButtonDownCombo( HWND hwnd, LB_DESCR *pDescr,
02003                                                UINT msg,WPARAM wParam, INT x, INT y)
02004 {
02005     RECT clientRect, screenRect;
02006     POINT mousePos;
02007 
02008     mousePos.x = x;
02009     mousePos.y = y;
02010 
02011     GetClientRect(hwnd, &clientRect);
02012 
02013     if(PtInRect(&clientRect, mousePos))
02014     {
02015       /* MousePos is in client, resume normal processing */
02016       if (msg == WM_LBUTTONDOWN)
02017       {
02018          pDescr->lphc->droppedIndex = pDescr->nb_items ? pDescr->selected_item : -1;
02019          return LISTBOX_HandleLButtonDown( hwnd, pDescr, wParam, x, y);
02020       }
02021       else if (pDescr->style & LBS_NOTIFY)
02022         SEND_NOTIFICATION( hwnd, pDescr, LBN_DBLCLK );
02023       return 0;
02024     }
02025     else
02026     {
02027       POINT screenMousePos;
02028       RECT screenRect;
02029       HWND hWndOldCapture;
02030 //CB: read buglist
02031       /* Check the Non-Client Area */
02032       screenMousePos = mousePos;
02033       hWndOldCapture = GetCapture();
02034       GetWindowRect(hwnd,&screenRect);
02035       ClientToScreen(hwnd,&screenMousePos);
02036 
02037       if (!PtInRect(&screenRect,screenMousePos))
02038       {
02039         ReleaseCapture();
02040         LISTBOX_SetSelection( hwnd, pDescr, pDescr->lphc->droppedIndex, FALSE, FALSE );
02041         COMBO_FlipListbox( pDescr->lphc, FALSE, FALSE );
02042 
02043         return 0;
02044       } else
02045       {
02046         /* Check to see the NC is a scrollbar */
02047         INT nHitTestType = SendMessageA(hwnd,WM_NCHITTEST,0,MAKELONG(screenMousePos.x,screenMousePos.y));
02048 
02049         /* Windows sends this message when a scrollbar is clicked
02050          */
02051         if (nHitTestType != HTCLIENT)
02052         {
02053           SendMessageA(hwnd,(msg == WM_LBUTTONDOWN) ? WM_NCLBUTTONDOWN:WM_NCLBUTTONDBLCLK,nHitTestType,MAKELONG(screenMousePos.x,screenMousePos.y));
02054         }
02055 
02056         /* Resume the Capture after scrolling is complete
02057          */
02058         if (hWndOldCapture)
02059         {
02060           SetCapture(hWndOldCapture);
02061         }
02062       }
02063     }
02064     return 0;
02065 }
02066 
02067 
02068 /***********************************************************************
02069  *           LISTBOX_HandleLButtonUp
02070  */
02071 static LRESULT LISTBOX_HandleLButtonUp( HWND hwnd, LB_DESCR *descr )
02072 {
02073     if (LISTBOX_Timer != LB_TIMER_NONE)
02074         KillSystemTimer( hwnd, LB_TIMER_ID );
02075 
02076     LISTBOX_Timer = LB_TIMER_NONE;
02077     if (descr->captured)
02078     {
02079         descr->captured = FALSE;
02080         if (GetCapture() == hwnd) ReleaseCapture();
02081         if ((descr->style & LBS_NOTIFY) && descr->nb_items)
02082             SEND_NOTIFICATION( hwnd, descr, LBN_SELCHANGE );
02083     }
02084     return 0;
02085 }
02086 
02087 
02088 /***********************************************************************
02089  *           LISTBOX_HandleTimer
02090  *
02091  * Handle scrolling upon a timer event.
02092  * Return TRUE if scrolling should continue.
02093  */
02094 static LRESULT LISTBOX_HandleTimer( HWND hwnd, LB_DESCR *descr,
02095                                     INT index, TIMER_DIRECTION dir )
02096 {
02097     switch(dir)
02098     {
02099     case LB_TIMER_UP:
02100         if (descr->top_item) index = descr->top_item - 1;
02101         else index = 0;
02102         break;
02103     case LB_TIMER_LEFT:
02104         if (descr->top_item) index -= descr->page_size;
02105         break;
02106     case LB_TIMER_DOWN:
02107         index = descr->top_item + LISTBOX_GetCurrentPageSize( hwnd, descr );
02108         if (index == descr->focus_item) index++;
02109         if (index >= descr->nb_items) index = descr->nb_items - 1;
02110         break;
02111     case LB_TIMER_RIGHT:
02112         if (index + descr->page_size < descr->nb_items)
02113             index += descr->page_size;
02114         break;
02115     case LB_TIMER_NONE:
02116         break;
02117     }
02118     if (index == descr->focus_item) return FALSE;
02119     LISTBOX_MoveCaret( hwnd, descr, index, FALSE );
02120     return TRUE;
02121 }
02122 
02123 
02124 /***********************************************************************
02125  *           LISTBOX_HandleSystemTimer
02126  *
02127  * WM_SYSTIMER handler.
02128  */
02129 static LRESULT LISTBOX_HandleSystemTimer( HWND hwnd, LB_DESCR *descr )
02130 {
02131     if (!LISTBOX_HandleTimer( hwnd, descr, descr->focus_item, LISTBOX_Timer ))
02132     {
02133         KillSystemTimer( hwnd, LB_TIMER_ID );
02134 
02135         LISTBOX_Timer = LB_TIMER_NONE;
02136     }
02137     return 0;
02138 }
02139 
02140 
02141 /***********************************************************************
02142  *           LISTBOX_HandleMouseMove
02143  *
02144  * WM_MOUSEMOVE handler.
02145  */
02146 static LRESULT LISTBOX_HandleMouseMove( HWND hwnd, LB_DESCR *descr,
02147                                      INT x, INT y )
02148 {
02149     INT index;
02150     TIMER_DIRECTION dir = LB_TIMER_NONE;
02151 
02152     if (GetCapture() != hwnd) return 0;
02153     if (!descr->captured) return 0;
02154 
02155     if (descr->style & LBS_MULTICOLUMN)
02156     {
02157         if (y < 0) y = 0;
02158         else if (y >= descr->item_height * descr->page_size)
02159             y = descr->item_height * descr->page_size - 1;
02160 
02161         if (x < 0)
02162         {
02163             dir = LB_TIMER_LEFT;
02164             x = 0;
02165         }
02166         else if (x >= descr->width)
02167         {
02168             dir = LB_TIMER_RIGHT;
02169             x = descr->width - 1;
02170         }
02171     }
02172     else
02173     {
02174         if (y < 0) dir = LB_TIMER_UP;  /* above */
02175         else if (y >= descr->height) dir = LB_TIMER_DOWN;  /* below */
02176     }
02177 
02178     index = LISTBOX_GetItemFromPoint( hwnd, descr, x, y );
02179     if (index == -1) index = descr->focus_item;
02180     if (!LISTBOX_HandleTimer( hwnd, descr, index, dir )) dir = LB_TIMER_NONE;
02181 
02182     /* Start/stop the system timer */
02183 
02184     if (dir != LB_TIMER_NONE)
02185         SetSystemTimer( hwnd, LB_TIMER_ID, LB_SCROLL_TIMEOUT, NULL);
02186     else if (LISTBOX_Timer != LB_TIMER_NONE)
02187         KillSystemTimer( hwnd, LB_TIMER_ID );
02188 
02189     LISTBOX_Timer = dir;
02190 
02191     return 0;
02192 }
02193 
02194 
02195 /***********************************************************************
02196  *           LISTBOX_HandleKeyDown
02197  */
02198 static LRESULT LISTBOX_HandleKeyDown( HWND hwnd, LB_DESCR *descr, WPARAM wParam )
02199 {
02200     INT caret = -1;
02201     BOOL bForceSelection = TRUE; /* select item pointed to by focus_item */
02202 
02203     if ((IS_MULTISELECT(descr)) || (descr->selected_item == descr->focus_item))
02204        bForceSelection = FALSE; /* only for single select list */
02205 
02206     if (descr->style & LBS_WANTKEYBOARDINPUT)
02207     {
02208         caret = SendMessageA( descr->owner, WM_VKEYTOITEM,
02209                                 MAKEWPARAM(LOWORD(wParam), descr->focus_item),
02210                                 hwnd );
02211         if (caret == -2) return 0;
02212     }
02213     if (caret == -1) switch(wParam)
02214     {
02215     case VK_LEFT:
02216         if (descr->style & LBS_MULTICOLUMN)
02217         {
02218             bForceSelection = FALSE;
02219             if (descr->focus_item >= descr->page_size)
02220                 caret = descr->focus_item - descr->page_size;
02221             break;
02222         }
02223         /* fall through */
02224     case VK_UP:
02225         caret = descr->focus_item - 1;
02226         if (caret < 0) caret = 0;
02227         break;
02228     case VK_RIGHT:
02229         if (descr->style & LBS_MULTICOLUMN)
02230         {
02231             bForceSelection = FALSE;
02232             if (descr->focus_item + descr->page_size < descr->nb_items)
02233                 caret = descr->focus_item + descr->page_size;
02234             break;
02235         }
02236         /* fall through */
02237     case VK_DOWN:
02238         caret = descr->focus_item + 1;
02239         if (caret >= descr->nb_items) caret = descr->nb_items - 1;
02240         break;
02241     case VK_PRIOR:
02242         if (descr->style & LBS_MULTICOLUMN)
02243         {
02244             INT page = descr->width / descr->column_width;
02245             if (page < 1) page = 1;
02246             caret = descr->focus_item - (page * descr->page_size) + 1;
02247         }
02248         else caret = descr->focus_item-LISTBOX_GetCurrentPageSize(hwnd,descr)+1;
02249         if (caret < 0) caret = 0;
02250         break;
02251     case VK_NEXT:
02252         if (descr->style & LBS_MULTICOLUMN)
02253         {
02254             INT page = descr->width / descr->column_width;
02255             if (page < 1) page = 1;
02256             caret = descr->focus_item + (page * descr->page_size) - 1;
02257         }
02258         else caret = descr->focus_item+LISTBOX_GetCurrentPageSize(hwnd,descr)-1;
02259         if (caret >= descr->nb_items) caret = descr->nb_items - 1;
02260         break;
02261     case VK_HOME:
02262         caret = 0;
02263         break;
02264     case VK_END:
02265         caret = descr->nb_items - 1;
02266         break;
02267     case VK_SPACE:
02268         if (descr->style & LBS_EXTENDEDSEL) caret = descr->focus_item;
02269         else if (descr->style & LBS_MULTIPLESEL)
02270         {
02271             LISTBOX_SetSelection( hwnd, descr, descr->focus_item,
02272                                   !descr->items[descr->focus_item].selected,
02273                                   (descr->style & LBS_NOTIFY) != 0 );
02274         }
02275         break;
02276     default:
02277         bForceSelection = FALSE;
02278     }
02279     if (bForceSelection) /* focused item is used instead of key */
02280         caret = descr->focus_item;
02281     if (caret >= 0)
02282     {
02283         if ((descr->style & LBS_EXTENDEDSEL) &&
02284             !(GetKeyState( VK_SHIFT ) & 0x8000))
02285             descr->anchor_item = caret;
02286         LISTBOX_MoveCaret( hwnd, descr, caret, TRUE );
02287         LISTBOX_SetSelection( hwnd, descr, caret, TRUE, FALSE);
02288         if (descr->style & LBS_NOTIFY)
02289         {
02290             if( descr->lphc && CB_GETTYPE(descr->lphc) != CBS_SIMPLE )
02291             {
02292                 /* make sure that combo parent doesn't hide us */
02293                 descr->lphc->wState |= CBF_NOROLLUP;
02294             }
02295             if (descr->nb_items) SEND_NOTIFICATION( hwnd, descr, LBN_SELCHANGE );
02296         }
02297     }
02298     return 0;
02299 }
02300 
02301 
02302 /***********************************************************************
02303  *           LISTBOX_HandleChar
02304  */
02305 static LRESULT LISTBOX_HandleChar( HWND hwnd, LB_DESCR *descr,
02306                                    WPARAM wParam )
02307 {
02308     INT caret = -1;
02309     char str[2];
02310 
02311     str[0] = wParam & 0xff;
02312     str[1] = '\0';
02313 
02314     if (descr->style & LBS_WANTKEYBOARDINPUT)
02315     {
02316         caret = SendMessageA( descr->owner, WM_CHARTOITEM,
02317                                 MAKEWPARAM(LOWORD(wParam), descr->focus_item),
02318                                 hwnd );
02319         if (caret == -2) return 0;
02320     }
02321     if (caret == -1)
02322         caret = LISTBOX_FindString( hwnd, descr, descr->focus_item, str, FALSE);
02323     if (caret != -1)
02324     {
02325         if ((!IS_MULTISELECT(descr)) && descr->selected_item == -1)
02326            LISTBOX_SetSelection( hwnd, descr, caret, TRUE, FALSE);
02327         LISTBOX_MoveCaret( hwnd, descr, caret, TRUE );
02328         if ((descr->style & LBS_NOTIFY) && descr->nb_items)
02329             SEND_NOTIFICATION( hwnd, descr, LBN_SELCHANGE );
02330     }
02331     return 0;
02332 }
02333 
02334 
02335 /***********************************************************************
02336  *           LISTBOX_Create
02337  */
02338 static LRESULT LISTBOX_Create( HWND hwnd, LPHEADCOMBO lphc )
02339 {
02340     LB_DESCR *descr;
02341     MEASUREITEMSTRUCT mis;
02342     RECT rect;
02343 
02344     if (!(descr = (LB_DESCR*)HeapAlloc( GetProcessHeap(), 0, sizeof(*descr) )))
02345         return -1;
02346     if (!(descr->heap = HeapCreate( 0, 0x10000, 0 )))
02347     {
02348         HeapFree( GetProcessHeap(), 0, descr );
02349         return -1;
02350     }
02351     GetClientRect( hwnd, &rect );
02352     descr->owner         = GetParent( hwnd );
02353     descr->style         = GetWindowLongA(hwnd,GWL_STYLE);
02354     descr->width         = rect.right - rect.left;
02355     descr->height        = rect.bottom - rect.top;
02356     descr->items         = NULL;
02357     descr->nb_items      = 0;
02358     descr->top_item      = 0;
02359     descr->selected_item = -1;
02360     descr->focus_item    = 0;
02361     descr->anchor_item   = -1;
02362     descr->item_height   = 1;
02363     descr->page_size     = 1;
02364     descr->column_width  = 150;
02365     descr->horz_extent   = (descr->style & WS_HSCROLL) ? 1 : 0;
02366     descr->horz_pos      = 0;
02367     descr->nb_tabs       = 0;
02368     descr->tabs          = NULL;
02369     descr->caret_on      = lphc ? FALSE:TRUE;
02370     descr->in_focus      = FALSE;
02371     descr->captured      = FALSE;
02372     descr->font          = 0;
02373     descr->locale        = 0;  /* FIXME */
02374     descr->lphc          = lphc;
02375 
02376     if( lphc )
02377     {
02378         //TRACE_(combo)("[%04x]: resetting owner %04x -> %04x\n",
02379         //             wnd->hwndSelf, descr->owner, lphc->self->hwndSelf );
02380         descr->owner = lphc->hwndself;
02381     }
02382 
02383     SetInfoPtr(hwnd,(DWORD)descr);
02384 
02385 /*    if (wnd->dwExStyle & WS_EX_NOPARENTNOTIFY) descr->style &= ~LBS_NOTIFY;
02386  */
02387     if (descr->style & LBS_EXTENDEDSEL) descr->style |= LBS_MULTIPLESEL;
02388     if (descr->style & LBS_MULTICOLUMN) descr->style &= ~LBS_OWNERDRAWVARIABLE;
02389     if (descr->style & LBS_OWNERDRAWVARIABLE) descr->style |= LBS_NOINTEGRALHEIGHT;
02390     LISTBOX_SetFont(hwnd,descr,0,(LPARAM)FALSE);
02391 
02392     if (descr->style & LBS_OWNERDRAWFIXED)
02393     {
02394         if( descr->lphc && (descr->lphc->dwStyle & CBS_DROPDOWN))
02395         {
02396             /* WinWord gets VERY unhappy if we send WM_MEASUREITEM from here */
02397           descr->item_height = lphc->fixedOwnerDrawHeight;
02398         }
02399         else
02400         {
02401             UINT        id = GetWindowLongA(hwnd,GWL_ID);
02402 
02403             mis.CtlType    = ODT_LISTBOX;
02404             mis.CtlID      = id;
02405             mis.itemID     = -1;
02406             mis.itemWidth  =  0;
02407             mis.itemData   =  0;
02408             mis.itemHeight = descr->item_height;
02409             SendMessageA( descr->owner, WM_MEASUREITEM, id, (LPARAM)&mis );
02410             descr->item_height = mis.itemHeight ? mis.itemHeight : 1;
02411         }
02412     }
02413 
02414     return 0;
02415 }
02416 
02417 static LRESULT LISTBOX_NCCreate(HWND hwnd,WPARAM wParam,LPARAM lParam)
02418 {
02419   DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
02420 
02421   /*
02422    * When a listbox is not in a combobox and the look
02423    * is win95,  the WS_BORDER style is replaced with
02424    * the WS_EX_CLIENTEDGE style.
02425    */
02426   if (dwStyle & WS_BORDER)
02427   {
02428     SetWindowLongA(hwnd,GWL_EXSTYLE,GetWindowLongA(hwnd,GWL_EXSTYLE) | WS_EX_CLIENTEDGE);
02429     SetWindowLongA(hwnd,GWL_STYLE,GetWindowLongA(hwnd,GWL_STYLE)  & ~ WS_BORDER);
02430   }
02431 
02432   return DefWindowProcA(hwnd,WM_NCCREATE,wParam,lParam);
02433 }
02434 
02435 /***********************************************************************
02436  *           LISTBOX_Destroy
02437  */
02438 static BOOL LISTBOX_Destroy( HWND hwnd, LB_DESCR *descr )
02439 {
02440     LISTBOX_ResetContent(hwnd,descr,FALSE);
02441     HeapDestroy( descr->heap );
02442     HeapFree( GetProcessHeap(), 0, descr );
02443     SetInfoPtr(hwnd,0);
02444     return TRUE;
02445 }
02446 
02447 static LRESULT LISTBOX_GetItemData(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02448 {
02449   if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
02450     return LB_ERR;
02451   return descr->items[wParam].data;
02452 }
02453 
02454 static LRESULT LISTBOX_SetItemData(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02455 {
02456   if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
02457     return LB_ERR;
02458   descr->items[wParam].data = (DWORD)lParam;
02459   return LB_OKAY;
02460 }
02461 
02462 static LRESULT LISTBOX_GetCount(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02463 {
02464   return descr->nb_items;
02465 }
02466 
02467 static LRESULT LISTBOX_GetTextLen(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02468 {
02469   if (wParam >= descr->nb_items)
02470     return LB_ERR;
02471   return (HAS_STRINGS(descr) ? strlen(descr->items[wParam].str)
02472                                : sizeof(DWORD));
02473 }
02474 
02475 static LRESULT LISTBOX_GetCurSel(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02476 {
02477   if (descr->nb_items==0)
02478     return LB_ERR;
02479   if (!IS_MULTISELECT(descr))
02480     return descr->selected_item;
02481   /* else */
02482   if (descr->selected_item!=-1)
02483     return descr->selected_item;
02484   /* else */
02485   return descr->focus_item;
02486   /* otherwise, if the user tries to move the selection with the    */
02487   /* arrow keys, we will give the application something to choke on */
02488 }
02489 
02490 static LRESULT LISTBOX_GetTopIndex(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02491 {
02492   return descr->top_item;
02493 }
02494 
02495 static LRESULT LISTBOX_ItemFromPoint(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02496 {
02497   POINT pt;
02498   RECT rect;
02499 
02500   pt.x = LOWORD(lParam);
02501   pt.y = HIWORD(lParam);
02502   rect.left = 0;
02503   rect.top = 0;
02504   rect.right = descr->width;
02505   rect.bottom = descr->height;
02506 
02507   return MAKELONG( LISTBOX_GetItemFromPoint(hwnd, descr, pt.x, pt.y),
02508                    !PtInRect( &rect, pt ) );
02509 }
02510 
02511 static LRESULT LISTBOX_HandleSetCaretIndex(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02512 {
02513   if ((!IS_MULTISELECT(descr)) && (descr->selected_item != -1)) return LB_ERR;
02514   if (LISTBOX_SetCaretIndex( hwnd, descr, wParam, !lParam ) == LB_ERR)
02515     return LB_ERR;
02516   else
02517     return LB_OKAY;
02518 }
02519 
02520 static LRESULT LISTBOX_GetCaretIndex(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02521 {
02522   return descr->focus_item;
02523 }
02524 
02525 static LRESULT LISTBOX_SelectString(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02526 {
02527   INT index = LISTBOX_FindString( hwnd, descr, wParam,
02528                                  (LPCSTR)lParam, FALSE );
02529   if (index == LB_ERR)
02530     return LB_ERR;
02531   LISTBOX_SetSelection( hwnd, descr, index, TRUE, FALSE );
02532   return index;
02533 }
02534 
02535 static LRESULT LISTBOX_GetSel(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02536 {
02537   if (((INT)wParam < 0) || ((INT)wParam >= descr->nb_items))
02538     return LB_ERR;
02539   return descr->items[wParam].selected;
02540 }
02541 
02542 static LRESULT LISTBOX_SetCurSel(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02543 {
02544   if (IS_MULTISELECT(descr)) return LB_ERR;
02545   LISTBOX_SetCaretIndex( hwnd, descr, wParam, TRUE );
02546   return LISTBOX_SetSelection( hwnd, descr, wParam, TRUE, FALSE );
02547 }
02548 
02549 static LRESULT LISTBOX_SelItemRange(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02550 {
02551   if (LOWORD(lParam) <= HIWORD(lParam))
02552     return LISTBOX_SelectItemRange( hwnd, descr, LOWORD(lParam),
02553                                     HIWORD(lParam), wParam );
02554   else
02555     return LISTBOX_SelectItemRange( hwnd, descr, HIWORD(lParam),
02556                                     LOWORD(lParam), wParam );
02557 }
02558 
02559 static LRESULT LISTBOX_SelItemRangeEx(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02560 {
02561   if ((INT)lParam >= (INT)wParam)
02562     return LISTBOX_SelectItemRange( hwnd, descr, wParam, lParam, TRUE );
02563   else
02564     return LISTBOX_SelectItemRange( hwnd, descr, lParam, wParam, FALSE);
02565 }
02566 
02567 static LRESULT LISTBOX_GetHorizontalExtent(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02568 {
02569   return descr->horz_extent;
02570 }
02571 
02572 static LRESULT LISTBOX_GetAnchorIndex(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02573 {
02574   return descr->anchor_item;
02575 }
02576 
02577 static LRESULT LISTBOX_SetAnchorIndex(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02578 {
02579   if (((INT)wParam < -1) || ((INT)wParam >= descr->nb_items))
02580     return LB_ERR;
02581   descr->anchor_item = (INT)wParam;
02582   return LB_OKAY;
02583 }
02584 
02585 static LRESULT LISTBOX_GetLocale(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02586 {
02587   return descr->locale;
02588 }
02589 
02590 static LRESULT LISTBOX_SetLocale(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02591 {
02592   descr->locale = (LCID)wParam;  /* FIXME: should check for valid lcid */
02593   return LB_OKAY;
02594 }
02595 
02596 static LRESULT LISTBOX_CaretOn(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02597 {
02598   if (descr->caret_on)
02599     return LB_OKAY;
02600   descr->caret_on = TRUE;
02601   if ((descr->focus_item != -1) && (descr->in_focus))
02602     LISTBOX_RepaintItem( hwnd, descr, descr->focus_item, ODA_FOCUS );
02603   return LB_OKAY;
02604 }
02605 
02606 static LRESULT LISTBOX_CaretOff(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02607 {
02608   if (!descr->caret_on)
02609     return LB_OKAY;
02610   descr->caret_on = FALSE;
02611   if ((descr->focus_item != -1) && (descr->in_focus))
02612     LISTBOX_RepaintItem( hwnd, descr, descr->focus_item, ODA_FOCUS );
02613   return LB_OKAY;
02614 }
02615 
02616 static LRESULT LISTBOX_Enable(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02617 {
02618   InvalidateRect( hwnd, NULL, TRUE );
02619   return 0;
02620 }
02621 
02622 static LRESULT LISTBOX_GetDlgCode(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02623 {
02624   return DLGC_WANTARROWS | DLGC_WANTCHARS;
02625 }
02626 
02627 static LRESULT LISTBOX_Paint(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02628 {
02629   PAINTSTRUCT ps;
02630   HDC hdc = ( wParam ) ? ((HDC)wParam) :  BeginPaint( hwnd, &ps );
02631   LRESULT ret;
02632 
02633   ret = LISTBOX_Draw( hwnd, descr, hdc );
02634   if( !wParam ) EndPaint( hwnd, &ps );
02635 
02636   return ret;
02637 }
02638 
02639 static LRESULT LISTBOX_Size(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02640 {
02641   LISTBOX_UpdateSize( hwnd, descr );
02642   return 0;
02643 }
02644 
02645 static LRESULT LISTBOX_GetFont(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02646 {
02647   return descr->font;
02648 }
02649 
02650 static LRESULT LISTBOX_SetFocus(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02651 {
02652   descr->in_focus = TRUE;
02653   descr->caret_on = TRUE;
02654   if (descr->focus_item != -1)
02655     LISTBOX_RepaintItem( hwnd, descr, descr->focus_item, ODA_FOCUS );
02656   SEND_NOTIFICATION( hwnd, descr, LBN_SETFOCUS );
02657   return 0;
02658 }
02659 
02660 static LRESULT LISTBOX_KillFocus(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02661 {
02662   descr->in_focus = FALSE;
02663   if ((descr->focus_item != -1) && descr->caret_on)
02664     LISTBOX_RepaintItem( hwnd, descr, descr->focus_item, ODA_FOCUS );
02665   SEND_NOTIFICATION( hwnd, descr, LBN_KILLFOCUS );
02666   return 0;
02667 }
02668 
02669 static LRESULT LISTBOX_MouseActivate(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02670 {
02671   return MA_NOACTIVATE;
02672 }
02673 
02674 static LRESULT LISTBOX_LButtonDblClk(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02675 {
02676   if (descr->style & LBS_NOTIFY)
02677     SEND_NOTIFICATION( hwnd, descr, LBN_DBLCLK );
02678   return 0;
02679 }
02680 
02681 static LRESULT LISTBOX_EraseBackground(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02682 {
02683   if (IS_OWNERDRAW(descr))
02684   {
02685     RECT rect;
02686     HBRUSH hbrush = SendMessageA( descr->owner, WM_CTLCOLORLISTBOX, wParam, (LPARAM)hwnd );
02687 
02688     GetClientRect(hwnd, &rect);
02689     if (hbrush) FillRect( (HDC)wParam, &rect, hbrush );
02690   }
02691 
02692   return 1;
02693 }
02694 
02695 static LRESULT LISTBOX_DropFiles(HWND hwnd,LB_DESCR *descr,WPARAM wParam,LPARAM lParam)
02696 {
02697   if ( !descr->lphc )
02698     return SendMessageA( descr->owner, WM_DROPFILES, wParam, lParam );
02699 
02700   return 0;
02701 }
02702 
02703 static LRESULT LISTBOX_HandleDragDrop(HWND hwnd,LB_DESCR *descr,UINT msg,WPARAM wParam,LPARAM lParam)
02704 {
02705   if( !descr->lphc )
02706   {
02707     LPDRAGINFO dragInfo = (LPDRAGINFO)lParam;
02708 
02709     dragInfo->l = LISTBOX_GetItemFromPoint( hwnd, descr, dragInfo->pt.x,
02710                                                 dragInfo->pt.y );
02711     return SendMessageA( descr->owner, msg, wParam, lParam );
02712   }
02713 
02714   return 0;
02715 }
02716 
02717 /***********************************************************************
02718  *           ListBoxWndProc
02719  */
02720 LRESULT WINAPI ListBoxWndProc( HWND hwnd, UINT msg,
02721                                       WPARAM wParam, LPARAM lParam )
02722 {
02723     LB_DESCR *descr;
02724 
02725     if (!(descr = (LB_DESCR*)GetInfoPtr(hwnd)))
02726     {
02727       switch (msg)
02728       {
02729         case WM_CREATE:
02730           return LISTBOX_Create(hwnd,NULL);
02731 
02732         case WM_NCCREATE:
02733           return LISTBOX_NCCreate(hwnd,wParam,lParam);
02734       }
02735       /* Ignore all other messages before we get a WM_CREATE */
02736       return DefWindowProcA( hwnd, msg, wParam, lParam );
02737     }
02738 
02739     switch(msg)
02740     {
02741       case LB_RESETCONTENT:
02742         return LISTBOX_ResetContent(hwnd,descr,TRUE);
02743 
02744       case LB_ADDSTRING:
02745         return LISTBOX_AddString(hwnd,descr,wParam,lParam);
02746 
02747       case LB_INSERTSTRING:
02748         return LISTBOX_InsertString( hwnd, descr, wParam, (LPCSTR)lParam );
02749 
02750       case LB_ADDFILE:
02751         return LISTBOX_AddFile(hwnd,descr,wParam,lParam);
02752 
02753       case LB_DELETESTRING:
02754         return LISTBOX_DeleteString(hwnd,descr,wParam,lParam);
02755 
02756       case LB_GETITEMDATA:
02757         return LISTBOX_GetItemData(hwnd,descr,wParam,lParam);
02758 
02759       case LB_SETITEMDATA:
02760         return LISTBOX_SetItemData(hwnd,descr,wParam,lParam);
02761 
02762       case LB_GETCOUNT:
02763         return LISTBOX_GetCount(hwnd,descr,wParam,lParam);
02764 
02765       case LB_GETTEXT:
02766         return LISTBOX_GetText( hwnd, descr, wParam, (LPSTR)lParam );
02767 
02768       case LB_GETTEXTLEN:
02769         return LISTBOX_GetTextLen(hwnd,descr,wParam,lParam);
02770 
02771       case LB_GETCURSEL:
02772         return LISTBOX_GetCurSel(hwnd,descr,wParam,lParam);
02773 
02774       case LB_GETTOPINDEX:
02775         return LISTBOX_GetTopIndex(hwnd,descr,wParam,lParam);
02776 
02777       case LB_GETITEMHEIGHT:
02778         return LISTBOX_GetItemHeight( hwnd, descr, wParam );
02779 
02780       case LB_SETITEMHEIGHT:
02781         return LISTBOX_SetItemHeight( hwnd, descr, wParam, lParam );
02782 
02783       case LB_ITEMFROMPOINT:
02784         return LISTBOX_ItemFromPoint(hwnd,descr,wParam,lParam);
02785 
02786       case LB_SETCARETINDEX:
02787         return LISTBOX_HandleSetCaretIndex(hwnd,descr,wParam,lParam);
02788 
02789       case LB_GETCARETINDEX:
02790         return LISTBOX_GetCaretIndex(hwnd,descr,wParam,lParam);
02791 
02792       case LB_SETTOPINDEX:
02793         return LISTBOX_SetTopItem( hwnd, descr, wParam, TRUE );
02794 
02795       case LB_SETCOLUMNWIDTH:
02796         return LISTBOX_SetColumnWidth( hwnd, descr, wParam );
02797 
02798       case LB_GETITEMRECT:
02799         return LISTBOX_GetItemRect( hwnd, descr, wParam, (RECT *)lParam );
02800 
02801       case LB_FINDSTRING:
02802         return LISTBOX_FindString( hwnd, descr, wParam, (LPCSTR)lParam, FALSE );
02803 
02804       case LB_FINDSTRINGEXACT:
02805         return LISTBOX_FindString( hwnd, descr, wParam, (LPCSTR)lParam, TRUE );
02806 
02807       case LB_SELECTSTRING:
02808         return LISTBOX_SelectString(hwnd,descr,wParam,lParam);
02809 
02810       case LB_GETSEL:
02811         return LISTBOX_GetSel(hwnd,descr,wParam,lParam);
02812 
02813       case LB_SETSEL:
02814         return LISTBOX_SetSelection( hwnd, descr, lParam, wParam, FALSE );
02815 
02816       case LB_SETCURSEL:
02817         return LISTBOX_SetCurSel(hwnd,descr,wParam,lParam);
02818 
02819       case LB_GETSELCOUNT:
02820         return LISTBOX_GetSelCount( hwnd, descr );
02821 
02822       case LB_GETSELITEMS:
02823         return LISTBOX_GetSelItems( hwnd, descr, wParam, (LPINT)lParam );
02824 
02825       case LB_SELITEMRANGE:
02826         return LISTBOX_SelItemRange(hwnd,descr,wParam,lParam);
02827 
02828       case LB_SELITEMRANGEEX:
02829         return LISTBOX_SelItemRangeEx(hwnd,descr,wParam,lParam);
02830 
02831       case LB_GETHORIZONTALEXTENT:
02832         return LISTBOX_GetHorizontalExtent(hwnd,descr,wParam,lParam);
02833 
02834       case LB_SETHORIZONTALEXTENT:
02835         return LISTBOX_SetHorizontalExtent( hwnd, descr, wParam );
02836 
02837       case LB_GETANCHORINDEX:
02838         return LISTBOX_GetAnchorIndex(hwnd,descr,wParam,lParam);
02839 
02840       case LB_SETANCHORINDEX:
02841         return LISTBOX_SetAnchorIndex(hwnd,descr,wParam,lParam);
02842 
02843       case LB_DIR:
02844         return LISTBOX_Directory( hwnd, descr, wParam, (LPCSTR)lParam, TRUE );
02845 
02846       case LB_GETLOCALE:
02847         return LISTBOX_GetLocale(hwnd,descr,wParam,lParam);
02848 
02849       case LB_SETLOCALE:
02850         return LISTBOX_SetLocale(hwnd,descr,wParam,lParam);
02851 
02852       case LB_INITSTORAGE:
02853         return LISTBOX_InitStorage( hwnd, descr, wParam, (DWORD)lParam );
02854 
02855       case LB_SETCOUNT:
02856         return LISTBOX_SetCount( hwnd, descr, (INT)wParam );
02857 
02858       case LB_SETTABSTOPS:
02859         return LISTBOX_SetTabStops( hwnd, descr, wParam, (LPINT)lParam, FALSE );
02860 
02861       case LB_CARETON:
02862         return LISTBOX_CaretOn(hwnd,descr,wParam,lParam);
02863 
02864       case LB_CARETOFF:
02865         return LISTBOX_CaretOff(hwnd,descr,wParam,lParam);
02866 
02867       case WM_DESTROY:
02868         return LISTBOX_Destroy( hwnd, descr );
02869 
02870       case WM_ENABLE:
02871         return LISTBOX_Enable(hwnd,descr,wParam,lParam);
02872 
02873       case WM_SETREDRAW:
02874         return LISTBOX_SetRedraw( hwnd, descr, wParam != 0 );
02875 
02876       case WM_GETDLGCODE:
02877         return LISTBOX_GetDlgCode(hwnd,descr,wParam,lParam);
02878 
02879       case WM_PAINT:
02880         return LISTBOX_Paint(hwnd,descr,wParam,lParam);
02881 
02882       case WM_SIZE:
02883         return LISTBOX_Size(hwnd,descr,wParam,lParam);
02884 
02885       case WM_GETFONT:
02886         return LISTBOX_GetFont(hwnd,descr,wParam,lParam);
02887 
02888       case WM_SETFONT:
02889         return LISTBOX_SetFont(hwnd,descr,wParam,lParam);
02890 
02891       case WM_SETFOCUS:
02892         return LISTBOX_SetFocus(hwnd,descr,wParam,lParam);
02893 
02894       case WM_KILLFOCUS:
02895         return LISTBOX_KillFocus(hwnd,descr,wParam,lParam);
02896 
02897       case WM_HSCROLL:
02898         return LISTBOX_HandleHScroll( hwnd, descr, wParam, lParam );
02899 
02900       case WM_VSCROLL:
02901         return LISTBOX_HandleVScroll( hwnd, descr, wParam, lParam );
02902 
02903       case WM_MOUSEACTIVATE:
02904         return LISTBOX_MouseActivate(hwnd,descr,wParam,lParam);
02905 
02906       case WM_MOUSEWHEEL:
02907         return LISTBOX_HandleMouseWheel( hwnd, descr, wParam, lParam );
02908 
02909       case WM_LBUTTONDOWN:
02910         return LISTBOX_HandleLButtonDown( hwnd, descr, wParam,
02911                                           (INT16)LOWORD(lParam),
02912                                           (INT16)HIWORD(lParam) );
02913       case WM_LBUTTONDBLCLK:
02914         return LISTBOX_LButtonDblClk(hwnd,descr,wParam,lParam);
02915 
02916       case WM_MOUSEMOVE:
02917         return LISTBOX_HandleMouseMove( hwnd, descr, (INT16)LOWORD(lParam),
02918                                         (INT16)HIWORD(lParam) );
02919 
02920       case WM_LBUTTONUP:
02921         return LISTBOX_HandleLButtonUp( hwnd, descr );
02922 
02923       case WM_KEYDOWN:
02924         return LISTBOX_HandleKeyDown( hwnd, descr, wParam );
02925 
02926       case WM_CHAR:
02927         return LISTBOX_HandleChar( hwnd, descr, wParam );
02928 
02929       case WM_SYSTIMER:
02930         return LISTBOX_HandleSystemTimer( hwnd, descr );
02931 
02932       case WM_ERASEBKGND:
02933         return LISTBOX_EraseBackground(hwnd,descr,wParam,lParam);
02934 
02935       case WM_DROPFILES:
02936         return LISTBOX_DropFiles(hwnd,descr,wParam,lParam);
02937 
02938       case WM_DROPOBJECT:
02939       case WM_QUERYDROPOBJECT:
02940       case WM_DRAGSELECT:
02941       case WM_DRAGMOVE:
02942         return LISTBOX_HandleDragDrop(hwnd,descr,msg,wParam,lParam);
02943 
02944     default:
02945         //if ((msg >= WM_USER) && (msg < 0xc000))
02946         //    WARN("[%04x]: unknown msg %04x wp %08x lp %08lx\n",
02947         //                 hwnd, msg, wParam, lParam );
02948         return DefWindowProcA( hwnd, msg, wParam, lParam );
02949     }
02950     return 0;
02951 }
02952 
02953 /***********************************************************************
02954  *           COMBO_Directory
02955  */
02956 LRESULT COMBO_Directory( LPHEADCOMBO lphc, UINT attrib, LPSTR dir, BOOL bLong)
02957 {
02958     LB_DESCR *descr = (LB_DESCR*)GetInfoPtr(lphc->hWndLBox);
02959 
02960     if( descr )
02961     {
02962 #ifdef __WIN32OS2__
02963         //bugfix
02964         LRESULT lRet = LISTBOX_Directory( lphc->hWndLBox, descr, attrib, dir, bLong );
02965 #else
02966         LRESULT lRet = LISTBOX_Directory( lphc->hwndself, descr, attrib, dir, bLong );
02967 #endif
02968 
02969         RedrawWindow( lphc->hwndself, NULL, 0,
02970                         RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
02971         return lRet;
02972     }
02973     return CB_ERR;
02974 }
02975 
02976 /***********************************************************************
02977  *           ComboLBWndProc
02978  *
02979  * The combo listbox wndproc
02980  */
02981 LRESULT WINAPI ComboLBWndProc( HWND hwnd, UINT msg,
02982                                WPARAM wParam, LPARAM lParam )
02983 {
02984     LRESULT lRet = 0;
02985 
02986 
02987     LB_DESCR *descr = (LB_DESCR*)GetInfoPtr(hwnd);
02988 
02989     //TRACE_(combo)("[%04x]: msg %s wp %08x lp %08lx\n",
02990     //             wnd->hwndSelf, SPY_GetMsgName(msg), wParam, lParam );
02991 
02992     if( descr || msg == WM_CREATE )
02993     {
02994         LPHEADCOMBO lphc = (descr) ? descr->lphc : NULL;
02995 
02996         switch( msg )
02997         {
02998             case WM_CREATE:
02999 #define lpcs    ((LPCREATESTRUCTA)lParam)
03000                  //TRACE_(combo)("\tpassed parent handle = 0x%08x\n",
03001                  //             (UINT)lpcs->lpCreateParams);
03002 
03003                  lphc = (LPHEADCOMBO)(lpcs->lpCreateParams);
03004 #undef  lpcs
03005                  return LISTBOX_Create( hwnd, lphc );
03006             case WM_MOUSEMOVE:
03007                  if (lphc && (CB_GETTYPE(lphc) != CBS_SIMPLE))
03008                  {
03009                    POINT   mousePos;
03010                    BOOL    captured;
03011                    RECT    clientRect;
03012 
03013                    mousePos.x = (INT16)LOWORD(lParam);
03014                    mousePos.y = (INT16)HIWORD(lParam);
03015 
03016                    /*
03017                     * If we are in a dropdown combobox, we simulate that
03018                     * the mouse is captured to show the tracking of the item.
03019                     */
03020 
03021                    GetClientRect(hwnd, &clientRect);
03022                    if (PtInRect( &clientRect, mousePos ))
03023                    {
03024                        captured = descr->captured;
03025                        descr->captured = TRUE;
03026 
03027                        LISTBOX_HandleMouseMove( hwnd, descr,
03028                                                     mousePos.x, mousePos.y);
03029                        descr->captured = captured;
03030                    }
03031                    else
03032                    {
03033                        LISTBOX_HandleMouseMove( hwnd, descr,
03034                                                     mousePos.x, mousePos.y);
03035                    }
03036 
03037 
03038                    return 0;
03039                  }
03040                  else
03041                  {
03042                    /*
03043                     * If we are in Win3.1 look, go with the default behavior.
03044                     */
03045                    return ListBoxWndProc( hwnd, msg, wParam, lParam );
03046                  }
03047             case WM_LBUTTONUP:
03048             if (lphc)
03049             {
03050                  POINT mousePos;
03051                  RECT  clientRect;
03052 
03053                  /*
03054                   * If the mouse button "up" is not in the listbox,
03055                   * we make sure there is no selection by re-selecting the
03056                   * item that was selected when the listbox was made visible.
03057                   */
03058                  mousePos.x = (INT16)LOWORD(lParam);
03059                  mousePos.y = (INT16)HIWORD(lParam);
03060 
03061                  GetClientRect(hwnd, &clientRect);
03062 
03063                  /*
03064                   * When the user clicks outside the combobox and the focus
03065                   * is lost, the owning combobox will send a fake buttonup with
03066                   * 0xFFFFFFF as the mouse location, we must also revert the
03067                   * selection to the original selection.
03068                   */
03069                  if ( (lParam == 0xFFFFFFFF) ||
03070                       (!PtInRect( &clientRect, mousePos )) )
03071                  {
03072                    LISTBOX_MoveCaret( hwnd,
03073                                       descr,
03074                                       lphc->droppedIndex,
03075                                       FALSE );
03076                  }
03077                  return LISTBOX_HandleLButtonUp( hwnd, descr );
03078             }
03079             case WM_LBUTTONDOWN:
03080             case WM_LBUTTONDBLCLK:
03081                  return LISTBOX_HandleLButtonDownCombo( hwnd, descr,msg, wParam,
03082                          (INT16)LOWORD(lParam), (INT16)HIWORD(lParam));
03083             case WM_MOUSEACTIVATE:
03084                  return MA_NOACTIVATE;
03085             case WM_NCACTIVATE:
03086                  return FALSE;
03087             case WM_KEYDOWN:
03088                  if(lphc && (CB_GETTYPE(lphc) != CBS_SIMPLE))
03089                  {
03090                      /* for some reason(?) Windows makes it possible to
03091                       * show/hide ComboLBox by sending it WM_KEYDOWNs */
03092                       if( (!(lphc->wState & CBF_EUI) && wParam == VK_F4) ||
03093                          ( (lphc->wState & CBF_EUI) && !(lphc->wState & CBF_DROPPED)
03094                            && (wParam == VK_DOWN || wParam == VK_UP)) )
03095                      {
03096                          COMBO_FlipListbox( lphc, FALSE, FALSE );
03097                          return 0;
03098                      }
03099                  }
03100                  return LISTBOX_HandleKeyDown( hwnd, descr, wParam );
03101 
03102             case LB_SETCURSEL:
03103                  lRet = ListBoxWndProc( hwnd, msg, wParam, lParam );
03104                  lRet =(lRet == LB_ERR) ? lRet : descr->selected_item;
03105                  return lRet;
03106             case WM_NCDESTROY:
03107                  if(lphc && (CB_GETTYPE(lphc) != CBS_SIMPLE))
03108                      lphc->hWndLBox = 0;
03109                  /* fall through */
03110 
03111             default:
03112                 return ListBoxWndProc( hwnd, msg, wParam, lParam );
03113         }
03114     }
03115     lRet = DefWindowProcA( hwnd, msg, wParam, lParam );
03116 
03117     //TRACE_(combo)("\t default on msg [%04x]\n", (UINT16)msg );
03118 
03119     return lRet;
03120 }
03121 
03122 BOOL LISTBOX_Register()
03123 {
03124     WNDCLASSA wndClass;
03125 
03126 //SvL: Don't check this now
03127 //    if (GlobalFindAtomA(LISTBOXCLASSNAME)) return FALSE;
03128 
03129     ZeroMemory(&wndClass,sizeof(WNDCLASSA));
03130     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS;
03131     wndClass.lpfnWndProc   = (WNDPROC)ListBoxWndProc;
03132     wndClass.cbClsExtra    = 0;
03133     wndClass.cbWndExtra    = sizeof(VOID*);
03134     wndClass.hCursor       = LoadCursorA(0,IDC_ARROWA);
03135     wndClass.hbrBackground = (HBRUSH)0;
03136     wndClass.lpszClassName = LISTBOXCLASSNAME;
03137 
03138     return RegisterClassA(&wndClass);
03139 }
03140 
03141 
03142 BOOL LISTBOX_Unregister()
03143 {
03144     if (GlobalFindAtomA(LISTBOXCLASSNAME))
03145         return UnregisterClassA(LISTBOXCLASSNAME,(HINSTANCE)NULL);
03146     else return FALSE;
03147 }
03148 
03149 BOOL COMBOLBOX_Register()
03150 {
03151     WNDCLASSA wndClass;
03152 
03153 //SvL: Don't check this now
03154 //    if (GlobalFindAtomA(COMBOLBOXCLASSNAME)) return FALSE;
03155 
03156     ZeroMemory(&wndClass,sizeof(WNDCLASSA));
03157     wndClass.style         = CS_GLOBALCLASS | CS_DBLCLKS | CS_SAVEBITS;
03158     wndClass.lpfnWndProc   = (WNDPROC)ComboLBWndProc;
03159     wndClass.cbClsExtra    = 0;
03160     wndClass.cbWndExtra    = sizeof(VOID*);
03161     wndClass.hCursor       = LoadCursorA(0,IDC_ARROWA);
03162     wndClass.hbrBackground = (HBRUSH)0;
03163     wndClass.lpszClassName = COMBOLBOXCLASSNAME;
03164 
03165     return RegisterClassA(&wndClass);
03166 }
03167 
03168 BOOL COMBOLBOX_Unregister()
03169 {
03170     if (GlobalFindAtomA(COMBOLBOXCLASSNAME))
03171         return UnregisterClassA(COMBOLBOXCLASSNAME,(HINSTANCE)NULL);
03172     else return FALSE;
03173 }

Generated on Wed Jan 23 23:17:34 2002 for ODIN-user32 by doxygen1.2.11.1 written by Dimitri van Heesch, © 1997-2001