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

combo.cpp

Go to the documentation of this file.
00001 /* $Id: combo.cpp,v 1.33 2001/02/17 20:16:31 sandervl Exp $ */
00002 /*
00003  * Combo controls
00004  *
00005  * Copyright 1997 Alex Korobka
00006  * Copyright 1999 Christoph Bratschi
00007  *
00008  * FIXME: roll up in Netscape 3.01.
00009  *
00010  * Corel version: 20000513
00011  * (WINE version: 991212)
00012  *
00013  * Status:  in progress
00014  * Version: ?.??
00015  */
00016 
00017 #include <string.h>
00018 #include <os2win.h>
00019 #include "controls.h"
00020 #include "combo.h"
00021 #include "initterm.h"
00022 
00023 #ifdef DEBUG
00024 char *GetMsgText(int Msg);
00025 #endif
00026 
00027 #define DBG_LOCALLOG    DBG_combo
00028 #include "dbglocal.h"
00029 
00030   /* bits in the dwKeyData */
00031 #define KEYDATA_ALT             0x2000
00032 #define KEYDATA_PREVSTATE       0x4000
00033 
00034 /*
00035  * Additional combo box definitions
00036  */
00037 
00038 #define CB_NOTIFY( lphc, code ) \
00039         (SendMessageA( (lphc)->owner, WM_COMMAND, \
00040                          MAKEWPARAM(GetWindowLongA((lphc)->hwndself,GWL_ID), (code)), (lphc)->hwndself))
00041 #define CB_GETEDITTEXTLENGTH( lphc ) \
00042         (SendMessageA( (lphc)->hWndEdit, WM_GETTEXTLENGTH, 0, 0 ))
00043 
00044 /*
00045  * Look and feel dependant "constants"
00046  */
00047 #define COMBO_YBORDERGAP         5
00048 #define COMBO_XBORDERSIZE()      ( 2 )
00049 #define COMBO_YBORDERSIZE()      ( 2 )
00050 #define COMBO_EDITBUTTONSPACE()  ( 0 )
00051 #define EDIT_CONTROL_PADDING()   ( 1 )
00052 
00053 /***********************************************************************
00054  *           COMBO_NCCreate
00055  */
00056 static LRESULT COMBO_NCCreate(HWND hwnd,WPARAM wParam,LPARAM lParam)
00057 {
00058    LPHEADCOMBO          lphc;
00059 
00060    if ( hwnd &&
00061       (lphc = (LPHEADCOMBO)HeapAlloc(GetProcessHeap(), 0, sizeof(HEADCOMBO))) )
00062    {
00063         LPCREATESTRUCTA     lpcs = (CREATESTRUCTA*)lParam;
00064         DWORD dwStyle = GetWindowLongA(hwnd,GWL_STYLE);
00065         DWORD dwExStyle = GetWindowLongA(hwnd,GWL_EXSTYLE);
00066 
00067         memset( lphc, 0, sizeof(HEADCOMBO) );
00068         SetInfoPtr(hwnd,(DWORD)lphc);
00069 
00070        /* some braindead apps do try to use scrollbar/border flags */
00071 
00072         lphc->dwStyle = (lpcs->style & ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL));
00073         dwStyle &= ~(WS_BORDER | WS_HSCROLL | WS_VSCROLL);
00074         SetWindowLongA(hwnd,GWL_STYLE,dwStyle);
00075 
00076         /*
00077          * We also have to remove the client edge style to make sure
00078          * we don't end-up with a non client area.
00079          */
00080         dwExStyle &= ~(WS_EX_CLIENTEDGE);
00081         SetWindowLongA(hwnd,GWL_EXSTYLE,dwExStyle);
00082 
00083         if( !(lpcs->style & (CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE)) )
00084               lphc->dwStyle |= CBS_HASSTRINGS;
00085         if( !(dwExStyle & WS_EX_NOPARENTNOTIFY) )
00086               lphc->wState |= CBF_NOTIFY;
00087 
00088         //TRACE("[0x%08x], style = %08x\n",
00089         //             (UINT)lphc, lphc->dwStyle );
00090 
00091         return TRUE;
00092     }
00093     return FALSE;
00094 }
00095 
00096 /***********************************************************************
00097  *           COMBO_NCDestroy
00098  */
00099 static LRESULT COMBO_NCDestroy(HWND hwnd,WPARAM wParam,LPARAM lParam)
00100 {
00101    LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
00102 
00103    if( lphc )
00104    {
00105        //TRACE("[%04x]: freeing storage\n", CB_HWND(lphc));
00106 
00107        if( (CB_GETTYPE(lphc) != CBS_SIMPLE) && lphc->hWndLBox )
00108            DestroyWindow( lphc->hWndLBox );
00109 
00110        HeapFree( GetProcessHeap(), 0, lphc );
00111        SetInfoPtr(hwnd,0);
00112    }
00113 
00114    return DefWindowProcA(hwnd,WM_NCDESTROY,wParam,lParam);
00115 }
00116 
00117 /***********************************************************************
00118  *           CBGetTextAreaHeight
00119  *
00120  * This method will calculate the height of the text area of the
00121  * combobox.
00122  * The height of the text area is set in two ways.
00123  * It can be set explicitely through a combobox message of through a
00124  * WM_MEASUREITEM callback.
00125  * If this is not the case, the height is set to 13 dialog units.
00126  * This height was determined through experimentation.
00127  */
00128 static INT CBGetTextAreaHeight(
00129   HWND        hwnd,
00130   LPHEADCOMBO lphc)
00131 {
00132   INT iTextItemHeight;
00133 
00134   if( lphc->editHeight ) /* explicitly set height */
00135   {
00136     iTextItemHeight = lphc->editHeight;
00137   }
00138   else
00139   {
00140     TEXTMETRICA tm;
00141     HDC         hDC       = GetDC(hwnd);
00142     HFONT       hPrevFont = 0;
00143     INT         baseUnitY;
00144 
00145     if (lphc->hFont)
00146       hPrevFont = SelectObject( hDC, lphc->hFont );
00147 
00148     GetTextMetricsA(hDC, &tm);
00149 
00150     baseUnitY = tm.tmHeight;
00151 
00152     if( hPrevFont )
00153       SelectObject( hDC, hPrevFont );
00154 
00155     ReleaseDC(hwnd, hDC);
00156 
00157     iTextItemHeight = ((13 * baseUnitY) / 8);
00158 
00159     /*
00160      * This "formula" calculates the height of the complete control.
00161      * To calculate the height of the text area, we have to remove the
00162      * borders.
00163      */
00164     iTextItemHeight -= 2*COMBO_YBORDERSIZE();
00165   }
00166 
00167   /*
00168    * Check the ownerdraw case if we haven't asked the parent the size
00169    * of the item yet.
00170    */
00171   if ( CB_OWNERDRAWN(lphc) &&
00172        (lphc->wState & CBF_MEASUREITEM) )
00173   {
00174     MEASUREITEMSTRUCT measureItem;
00175     RECT              clientRect;
00176     INT               originalItemHeight = iTextItemHeight;
00177 
00178     /*
00179      * We use the client rect for the width of the item.
00180      */
00181     GetClientRect(hwnd, &clientRect);
00182 
00183     lphc->wState &= ~CBF_MEASUREITEM;
00184 
00185     /*
00186      * Send a first one to measure the size of the text area
00187      */
00188     measureItem.CtlType    = ODT_COMBOBOX;
00189     measureItem.CtlID      = GetWindowLongA(lphc->hwndself,GWL_ID);
00190     measureItem.itemID     = -1;
00191     measureItem.itemWidth  = clientRect.right;
00192     measureItem.itemHeight = iTextItemHeight - 6; /* ownerdrawn cb is taller */
00193     measureItem.itemData   = 0;
00194     SendMessageA(lphc->owner, WM_MEASUREITEM,
00195                  (WPARAM)measureItem.CtlID, (LPARAM)&measureItem);
00196     iTextItemHeight = 6 + measureItem.itemHeight;
00197 
00198     /*
00199      * Send a second one in the case of a fixed ownerdraw list to calculate the
00200      * size of the list items. (we basically do this on behalf of the listbox)
00201      */
00202     if (lphc->dwStyle & CBS_OWNERDRAWFIXED)
00203     {
00204       measureItem.CtlType    = ODT_COMBOBOX;
00205       measureItem.CtlID      = GetWindowLongA(lphc->hwndself,GWL_ID);
00206       measureItem.itemID     = 0;
00207       measureItem.itemWidth  = clientRect.right;
00208       measureItem.itemHeight = originalItemHeight;
00209       measureItem.itemData   = 0;
00210       SendMessageA(lphc->owner, WM_MEASUREITEM,
00211                    (WPARAM)measureItem.CtlID, (LPARAM)&measureItem);
00212       lphc->fixedOwnerDrawHeight = measureItem.itemHeight;
00213     }
00214 
00215     /*
00216      * Keep the size for the next time
00217      */
00218     lphc->editHeight = iTextItemHeight;
00219   }
00220 
00221   return iTextItemHeight;
00222 }
00223 
00224 /***********************************************************************
00225  *           CBForceDummyResize
00226  *
00227  * The dummy resize is used for listboxes that have a popup to trigger
00228  * a re-arranging of the contents of the combobox and the recalculation
00229  * of the size of the "real" control window.
00230  */
00231 static void CBForceDummyResize(
00232   LPHEADCOMBO lphc)
00233 {
00234   RECT windowRect;
00235   int newComboHeight;
00236 
00237   newComboHeight = CBGetTextAreaHeight(CB_HWND(lphc),lphc) + 2*COMBO_YBORDERSIZE();
00238 
00239   GetWindowRect(CB_HWND(lphc), &windowRect);
00240 
00241   /*
00242    * We have to be careful, resizing a combobox also has the meaning that the
00243    * dropped rect will be resized. In this case, we want to trigger a resize
00244    * to recalculate layout but we don't want to change the dropped rectangle
00245    * So, we pass the height of text area of control as the height.
00246    * this will cancel-out in the processing of the WM_WINDOWPOSCHANGING
00247    * message.
00248    */
00249   SetWindowPos( CB_HWND(lphc),
00250                 (HWND)0,
00251                 0, 0,
00252                 windowRect.right  - windowRect.left,
00253                 newComboHeight,
00254                 SWP_NOMOVE | SWP_NOZORDER | SWP_NOACTIVATE );
00255 }
00256 
00257 /***********************************************************************
00258  *           CBCalcPlacement
00259  *
00260  * Set up component coordinates given valid lphc->RectCombo.
00261  */
00262 static void CBCalcPlacement(
00263   HWND        hwnd,
00264   LPHEADCOMBO lphc,
00265   LPRECT      lprEdit,
00266   LPRECT      lprButton,
00267   LPRECT      lprLB)
00268 {
00269 #if 1
00270   /*
00271    * Again, start with the client rectangle.
00272    */
00273   GetClientRect(hwnd, lprEdit);
00274 
00275   /*
00276    * Remove the borders
00277    */
00278   InflateRect(lprEdit, -COMBO_XBORDERSIZE(), -COMBO_YBORDERSIZE());
00279 
00280   /*
00281    * Chop off the bottom part to fit with the height of the text area.
00282    */
00283   lprEdit->bottom = lprEdit->top + CBGetTextAreaHeight(hwnd, lphc);
00284 
00285   /*
00286    * The button starts the same vertical position as the text area.
00287    */
00288   CopyRect(lprButton, lprEdit);
00289 
00290   /*
00291    * If the combobox is "simple" there is no button.
00292    */
00293   if( CB_GETTYPE(lphc) == CBS_SIMPLE ) 
00294     lprButton->left = lprButton->right = lprButton->bottom = 0;
00295   else
00296   {
00297     /*
00298      * Let's assume the combobox button is the same width as the
00299      * scrollbar button.
00300      * size the button horizontally and cut-off the text area.
00301      */
00302     lprButton->left = lprButton->right - GetSystemMetrics(SM_CXVSCROLL);
00303     lprEdit->right  = lprButton->left;
00304   }
00305   
00306   /*
00307    * In the case of a dropdown, there is an additional spacing between the
00308    * text area and the button.
00309    */
00310   if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
00311   {
00312     lprEdit->right -= COMBO_EDITBUTTONSPACE();
00313   }
00314 
00315   /*
00316    * If we have an edit control, we space it away from the borders slightly.
00317    */
00318   if (CB_GETTYPE(lphc) != CBS_DROPDOWNLIST)
00319   {
00320     InflateRect(lprEdit, -EDIT_CONTROL_PADDING(), -EDIT_CONTROL_PADDING());
00321   }
00322   
00323   /*
00324    * Adjust the size of the listbox popup.
00325    */
00326   if( CB_GETTYPE(lphc) == CBS_SIMPLE )
00327   {
00328     /*
00329      * Use the client rectangle to initialize the listbox rectangle
00330      */
00331     GetClientRect(hwnd, lprLB);
00332 
00333     /*
00334      * Then, chop-off the top part.
00335      */
00336     lprLB->top = lprEdit->bottom + COMBO_YBORDERSIZE();
00337   }
00338   else
00339   {
00340     /*
00341      * Make sure the dropped width is as large as the combobox itself.
00342      */
00343     if (lphc->droppedWidth < (lprButton->right + COMBO_XBORDERSIZE()))
00344     {
00345       lprLB->right  = lprLB->left + (lprButton->right + COMBO_XBORDERSIZE());
00346 
00347       /*
00348        * In the case of a dropdown, the popup listbox is offset to the right.
00349        * so, we want to make sure it's flush with the right side of the 
00350        * combobox
00351        */
00352       if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
00353         lprLB->right -= COMBO_EDITBUTTONSPACE();
00354     }
00355     else
00356        lprLB->right = lprLB->left + lphc->droppedWidth;
00357   }
00358 #else
00359   /*
00360    * Again, start with the client rectangle.
00361    */
00362   GetClientRect(hwnd, lprEdit);
00363 
00364   /*
00365    * Remove the borders
00366    */
00367   InflateRect(lprEdit, -COMBO_XBORDERSIZE(), -COMBO_YBORDERSIZE());
00368 
00369   /*
00370    * Chop off the bottom part to fit with the height of the text area.
00371    */
00372   lprEdit->bottom = lprEdit->top + CBGetTextAreaHeight(hwnd, lphc);
00373 
00374   /*
00375    * The button starts the same vertical position as the text area.
00376    */
00377   CopyRect(lprButton, lprEdit);
00378 
00379   /*
00380    * If the combobox is "simple" there is no button.
00381    */
00382   if( CB_GETTYPE(lphc) == CBS_SIMPLE )
00383     lprButton->left = lprButton->right = lprButton->bottom = 0;
00384   else
00385   {
00386     /*
00387      * Let's assume the combobox button is the same width as the
00388      * scrollbar button.
00389      * size the button horizontally and cut-off the text area.
00390      */
00391     lprButton->left = lprButton->right - GetSystemMetrics(SM_CXVSCROLL);
00392     lprEdit->right  = lprButton->left;
00393   }
00394 
00395   /*
00396    * In the case of a dropdown, there is an additional spacing between the
00397    * text area and the button.
00398    */
00399   if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
00400   {
00401     lprEdit->right -= COMBO_EDITBUTTONSPACE();
00402   }
00403 
00404   /*
00405    * If we have an edit control, we space it away from the borders slightly.
00406    */
00407   if (CB_GETTYPE(lphc) != CBS_DROPDOWNLIST)
00408   {
00409     InflateRect(lprEdit, -EDIT_CONTROL_PADDING(), -EDIT_CONTROL_PADDING());
00410   }
00411 
00412   /*
00413    * Adjust the size of the listbox popup.
00414    */
00415   if( CB_GETTYPE(lphc) == CBS_SIMPLE )
00416   {
00417     /*
00418      * Use the client rectangle to initialize the listbox rectangle
00419      */
00420     GetClientRect(hwnd, lprLB);
00421 
00422     /*
00423      * Then, chop-off the top part.
00424      */
00425     lprLB->top = lprEdit->bottom + COMBO_YBORDERSIZE();
00426   }
00427   else
00428   {
00429     //SvL: Listbox size might have changed!
00430     if(lphc->hWndLBox)
00431         GetWindowRect(lphc->hWndLBox, lprLB);
00432 
00433     /*
00434      * Make sure the dropped width is as large as the combobox itself.
00435      */
00436     if (lphc->droppedWidth < (lprButton->right + COMBO_XBORDERSIZE()))
00437     {
00438       lprLB->right  = lprLB->left + (lprButton->right + COMBO_XBORDERSIZE());
00439 
00440       /*
00441        * In the case of a dropdown, the popup listbox is offset to the right.
00442        * so, we want to make sure it's flush with the right side of the
00443        * combobox
00444        */
00445       if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
00446         lprLB->right -= COMBO_EDITBUTTONSPACE();
00447     }
00448     else
00449        lprLB->right = lprLB->left + lphc->droppedWidth;
00450   }
00451 #endif
00452   //TRACE("\ttext\t= (%i,%i-%i,%i)\n",
00453   //      lprEdit->left, lprEdit->top, lprEdit->right, lprEdit->bottom);
00454 
00455   //TRACE("\tbutton\t= (%i,%i-%i,%i)\n",
00456   //      lprButton->left, lprButton->top, lprButton->right, lprButton->bottom);
00457 
00458   //TRACE("\tlbox\t= (%i,%i-%i,%i)\n",
00459   //      lprLB->left, lprLB->top, lprLB->right, lprLB->bottom );
00460 }
00461 
00462 /***********************************************************************
00463  *           CBGetDroppedControlRect
00464  */
00465 static void CBGetDroppedControlRect( LPHEADCOMBO lphc, LPRECT lpRect)
00466 {
00467     /* In windows, CB_GETDROPPEDCONTROLRECT returns the upper left corner
00468      of the combo box and the lower right corner of the listbox */
00469 
00470     GetWindowRect(lphc->hwndself, lpRect);
00471 
00472     lpRect->right =  lpRect->left + lphc->droppedRect.right - lphc->droppedRect.left;
00473     lpRect->bottom = lpRect->top + lphc->droppedRect.bottom - lphc->droppedRect.top;
00474 
00475 }
00476 
00477 /***********************************************************************
00478  *           COMBO_WindowPosChanging
00479  */
00480 static LRESULT COMBO_WindowPosChanging(HWND hwnd,WPARAM wParam,LPARAM lParam)
00481 {
00482   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
00483   WINDOWPOS *posChanging = (WINDOWPOS*)lParam;
00484 
00485   dprintf(("COMBO_WindowPosChanging"));
00486 
00487   /*
00488    * We need to override the WM_WINDOWPOSCHANGING method to handle all
00489    * the non-simple comboboxes. The problem is that those controls are
00490    * always the same height. We have to make sure they are not resized
00491    * to another value.
00492    */
00493   if ( ( CB_GETTYPE(lphc) != CBS_SIMPLE ) &&
00494        ((posChanging->flags & SWP_NOSIZE) == 0) )
00495   {
00496     int newComboHeight;
00497 
00498     newComboHeight = CBGetTextAreaHeight(hwnd,lphc) +
00499                       2*COMBO_YBORDERSIZE();
00500 
00501     /*
00502      * Resizing a combobox has another side effect, it resizes the dropped
00503      * rectangle as well. However, it does it only if the new height for the
00504      * combobox is different than the height it should have. In other words,
00505      * if the application resizing the combobox only had the intention to resize
00506      * the actual control, for example, to do the layout of a dialog that is
00507      * resized, the height of the dropdown is not changed.
00508      */
00509     if (posChanging->cy != newComboHeight)
00510     {
00511       if (posChanging->cy > newComboHeight)
00512          lphc->droppedRect.bottom = lphc->droppedRect.top + posChanging->cy - newComboHeight;
00513       posChanging->cy = newComboHeight;
00514     }
00515   }
00516 
00517   return 0;
00518 }
00519 
00520 /***********************************************************************
00521  *           COMBO_Create
00522  */
00523 static LRESULT COMBO_Create(HWND hwnd,WPARAM wParam,LPARAM lParam)
00524 {
00525   static char clbName[] = "ComboLBox";
00526   static char editName[] = "Edit";
00527   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
00528 
00529   LPCREATESTRUCTA  lpcs = (CREATESTRUCTA*)lParam;
00530 
00531   if( !CB_GETTYPE(lphc) ) lphc->dwStyle |= CBS_SIMPLE;
00532   if( CB_GETTYPE(lphc) != CBS_DROPDOWNLIST ) lphc->wState |= CBF_EDIT;
00533 
00534   lphc->hwndself  = hwnd;
00535   lphc->owner = lpcs->hwndParent;
00536 
00537   /*
00538    * The item height and dropped width are not set when the control
00539    * is created.
00540    */
00541   lphc->droppedWidth = lphc->editHeight = 0;
00542 
00543   /*
00544    * The first time we go through, we want to measure the ownerdraw item
00545    */
00546   lphc->wState |= CBF_MEASUREITEM;
00547 
00548   /* M$ IE 3.01 actually creates (and rapidly destroys) an ownerless combobox */
00549 
00550   if( lphc->owner || !(lpcs->style & WS_VISIBLE) )
00551   {
00552       UINT lbeStyle   = 0;
00553       UINT lbeExStyle = 0;
00554 
00555       /*
00556        * Initialize the dropped rect to the size of the client area of the
00557        * control and then, force all the areas of the combobox to be
00558        * recalculated.
00559        */
00560       GetClientRect( hwnd, &lphc->droppedRect );
00561 
00562       CBCalcPlacement(hwnd,
00563                       lphc,
00564                       &lphc->textRect,
00565                       &lphc->buttonRect,
00566                       &lphc->droppedRect );
00567 
00568       /*
00569        * Adjust the position of the popup listbox if it's necessary
00570        */
00571       if ( CB_GETTYPE(lphc) != CBS_SIMPLE )
00572       {
00573         lphc->droppedRect.top   = lphc->textRect.bottom + COMBO_YBORDERSIZE();
00574 
00575         /*
00576          * If it's a dropdown, the listbox is offset
00577          */
00578         if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
00579           lphc->droppedRect.left += COMBO_EDITBUTTONSPACE();
00580 
00581         ClientToScreen(hwnd, (LPPOINT)&lphc->droppedRect);
00582         ClientToScreen(hwnd, (LPPOINT)&lphc->droppedRect.right);
00583       }
00584 
00585       /* create listbox popup */
00586 
00587       lbeStyle = (LBS_NOTIFY | WS_BORDER | WS_CLIPSIBLINGS | WS_CHILD) |
00588                  (lpcs->style & (WS_VSCROLL | CBS_OWNERDRAWFIXED | CBS_OWNERDRAWVARIABLE));
00589 
00590       if( lphc->dwStyle & CBS_SORT )
00591         lbeStyle |= LBS_SORT;
00592       if( lphc->dwStyle & CBS_HASSTRINGS )
00593         lbeStyle |= LBS_HASSTRINGS;
00594       if( lphc->dwStyle & CBS_NOINTEGRALHEIGHT )
00595         lbeStyle |= LBS_NOINTEGRALHEIGHT;
00596       if( lphc->dwStyle & CBS_DISABLENOSCROLL )
00597         lbeStyle |= LBS_DISABLENOSCROLL;
00598 
00599       if( CB_GETTYPE(lphc) == CBS_SIMPLE )      /* child listbox */
00600       {
00601         lbeStyle |= WS_VISIBLE;
00602 
00603         /*
00604          * In win 95 look n feel, the listbox in the simple combobox has
00605          * the WS_EXCLIENTEDGE style instead of the WS_BORDER style.
00606          */
00607         lbeStyle   &= ~WS_BORDER;
00608         lbeExStyle |= WS_EX_CLIENTEDGE;
00609       }
00610 
00611       lphc->hWndLBox = CreateWindowExA(lbeExStyle,
00612                                        clbName,
00613                                        NULL,
00614                                        lbeStyle,
00615                                        lphc->droppedRect.left,
00616                                        lphc->droppedRect.top,
00617                                        lphc->droppedRect.right - lphc->droppedRect.left,
00618                                        lphc->droppedRect.bottom - lphc->droppedRect.top,
00619                                        lphc->hwndself,
00620                                        (HMENU)ID_CB_LISTBOX,
00621                                        GetWindowLongA(lphc->hwndself,GWL_HINSTANCE),
00622                                        (LPVOID)lphc );
00623 
00624       if( lphc->hWndLBox )
00625       {
00626           BOOL  bEdit = TRUE;
00627           lbeStyle = WS_CHILD | WS_VISIBLE | ES_NOHIDESEL | ES_LEFT | ES_COMBO;
00628 
00629           /*
00630            * In Win95 look, the border fo the edit control is
00631            * provided by the combobox
00632            */
00633           if( lphc->wState & CBF_EDIT )
00634           {
00635               if( lphc->dwStyle & CBS_OEMCONVERT )
00636                   lbeStyle |= ES_OEMCONVERT;
00637               if( lphc->dwStyle & CBS_AUTOHSCROLL )
00638                   lbeStyle |= ES_AUTOHSCROLL;
00639               if( lphc->dwStyle & CBS_LOWERCASE )
00640                   lbeStyle |= ES_LOWERCASE;
00641               else if( lphc->dwStyle & CBS_UPPERCASE )
00642                   lbeStyle |= ES_UPPERCASE;
00643 
00644               lphc->hWndEdit = CreateWindowExA(0,
00645                                                editName,
00646                                                NULL,
00647                                                lbeStyle,
00648                                                lphc->textRect.left, lphc->textRect.top,
00649                                                lphc->textRect.right - lphc->textRect.left,
00650                                                lphc->textRect.bottom - lphc->textRect.top,
00651                                                lphc->hwndself,
00652                                                (HMENU)ID_CB_EDIT,
00653                                                GetWindowLongA(lphc->hwndself,GWL_HINSTANCE),
00654                                                NULL );
00655 
00656               if( !lphc->hWndEdit )
00657                 bEdit = FALSE;
00658           }
00659 
00660           if( bEdit )
00661           {
00662             if( CB_GETTYPE(lphc) != CBS_SIMPLE )
00663             {
00664               /* Now do the trick with parent */
00665               SetParent(lphc->hWndLBox, HWND_DESKTOP);
00666 
00667               /*
00668                * If the combo is a dropdown, we must resize the control to fit only
00669                * the text area and button. To do this, we send a dummy resize and the
00670                * WM_WINDOWPOSCHANGING message will take care of setting the height for
00671                * us.
00672                */
00673 
00674               CBForceDummyResize(lphc);
00675             }
00676 
00677             //TRACE("init done\n");
00678             return hwnd;
00679           }
00680           //ERR("edit control failure.\n");
00681       } //else ERR("listbox failure.\n");
00682   } //else ERR("no owner for visible combo.\n");
00683 
00684   /* CreateWindow() will send WM_NCDESTROY to cleanup */
00685 
00686   return -1;
00687 }
00688 
00689 /***********************************************************************
00690  *           CBPaintButton
00691  *
00692  * Paint combo button (normal, pressed, and disabled states).
00693  */
00694 static void CBPaintButton(
00695   LPHEADCOMBO lphc,
00696   HDC         hdc,
00697   RECT        rectButton)
00698 {
00699     if( lphc->wState & CBF_NOREDRAW )
00700       return;
00701 
00702 
00703     UINT buttonState = DFCS_SCROLLCOMBOBOX;
00704 
00705     if (lphc->wState & CBF_BUTTONDOWN)
00706     {
00707       buttonState |= DFCS_PUSHED;
00708     }
00709 
00710     if (CB_DISABLED(lphc))
00711     {
00712       buttonState |= DFCS_INACTIVE;
00713     }
00714 
00715     DrawFrameControl(hdc,&rectButton,DFC_SCROLL,buttonState);
00716 }
00717 
00718 /***********************************************************************
00719  *           CBPaintText
00720  *
00721  * Paint CBS_DROPDOWNLIST text field / update edit control contents.
00722  */
00723 static void CBPaintText(
00724   LPHEADCOMBO lphc,
00725   HDC         hdc,
00726   RECT        rectEdit)
00727 {
00728    INT  id, size = 0;
00729    LPSTR        pText = NULL;
00730 
00731    if( lphc->wState & CBF_NOREDRAW ) return;
00732 
00733    /* follow Windows combobox that sends a bunch of text
00734     * inquiries to its listbox while processing WM_PAINT. */
00735 
00736    if( (id = SendMessageA(lphc->hWndLBox, LB_GETCURSEL, 0, 0) ) != LB_ERR )
00737    {
00738         size = SendMessageA( lphc->hWndLBox, LB_GETTEXTLEN, id, 0);
00739         if( (pText = (char*)HeapAlloc( GetProcessHeap(), 0, size + 1)) != NULL )
00740         {
00741             SendMessageA( lphc->hWndLBox, LB_GETTEXT, (WPARAM)id, (LPARAM)pText );
00742             pText[size] = '\0'; /* just in case */
00743         } else return;
00744    }
00745 
00746    if( lphc->wState & CBF_EDIT )
00747    {
00748         if( CB_HASSTRINGS(lphc) ) SetWindowTextA( lphc->hWndEdit, pText ? pText : "" );
00749         if( lphc->wState & CBF_FOCUSED )
00750             SendMessageA( lphc->hWndEdit, EM_SETSEL, 0, (LPARAM)(-1));
00751    }
00752    else /* paint text field ourselves */
00753    {
00754      UINT       itemState;
00755      HFONT      hPrevFont = (lphc->hFont) ? SelectObject(hdc, lphc->hFont) : 0;
00756 
00757      /*
00758       * Give ourselves some space.
00759       */
00760      InflateRect( &rectEdit, -1, -1 );
00761 
00762      if ( (lphc->wState & CBF_FOCUSED) &&
00763           !(lphc->wState & CBF_DROPPED) )
00764      {
00765        /* highlight */
00766 
00767        FillRect( hdc, &rectEdit, GetSysColorBrush(COLOR_HIGHLIGHT) );
00768        SetBkColor( hdc, GetSysColor( COLOR_HIGHLIGHT ) );
00769        SetTextColor( hdc, GetSysColor( COLOR_HIGHLIGHTTEXT ) );
00770        itemState = ODS_SELECTED | ODS_FOCUS;
00771      }
00772      else
00773        itemState = 0;
00774 
00775      if( CB_OWNERDRAWN(lphc) )
00776      {
00777        DRAWITEMSTRUCT dis;
00778        HRGN           clipRegion;
00779        DWORD dwStyle = GetWindowLongA(lphc->hwndself,GWL_STYLE);
00780 
00781        /*
00782         * Save the current clip region.
00783         * To retrieve the clip region, we need to create one "dummy"
00784         * clip region.
00785         */
00786        clipRegion = CreateRectRgnIndirect(&rectEdit);
00787 
00788        if (GetClipRgn(hdc, clipRegion)!=1)
00789        {
00790          DeleteObject(clipRegion);
00791          clipRegion=(HRGN)NULL;
00792        }
00793 
00794        if ( dwStyle & WS_DISABLED )
00795          itemState |= ODS_DISABLED;
00796 
00797        dis.CtlType      = ODT_COMBOBOX;
00798        dis.CtlID        = GetWindowLongA(lphc->hwndself,GWL_ID);
00799        dis.hwndItem     = lphc->hwndself;
00800        dis.itemAction   = ODA_DRAWENTIRE;
00801        dis.itemID       = id;
00802        dis.itemState    = itemState | ODS_COMBOBOXEDIT;
00803        dis.hDC          = hdc;
00804        dis.rcItem       = rectEdit;
00805        dis.itemData     = SendMessageA( lphc->hWndLBox, LB_GETITEMDATA,
00806                                         (WPARAM)id, 0 );
00807 
00808        /*
00809         * Clip the DC and have the parent draw the item.
00810         */
00811        IntersectClipRect(hdc,
00812                          rectEdit.left,  rectEdit.top,
00813                          rectEdit.right, rectEdit.bottom);
00814 
00815        SendMessageA(lphc->owner, WM_DRAWITEM,
00816                     GetWindowLongA(lphc->hwndself,GWL_ID), (LPARAM)&dis );
00817 
00818        /*
00819         * Reset the clipping region.
00820         */
00821        SelectClipRgn(hdc, clipRegion);
00822      }
00823      else
00824      {
00825        ExtTextOutA( hdc,
00826                     rectEdit.left + 1,
00827                     rectEdit.top + 1,
00828                     ETO_OPAQUE | ETO_CLIPPED,
00829                     &rectEdit,
00830                     pText ? pText : "" , size, NULL );
00831 
00832        if(lphc->wState & CBF_FOCUSED && !(lphc->wState & CBF_DROPPED))
00833          DrawFocusRect( hdc, &rectEdit );
00834      }
00835 
00836      if( hPrevFont )
00837        SelectObject(hdc, hPrevFont );
00838    }
00839    if (pText)
00840         HeapFree( GetProcessHeap(), 0, pText );
00841 }
00842 
00843 /***********************************************************************
00844  *           CBPaintBorder
00845  */
00846 static void CBPaintBorder(
00847   HWND        hwnd,
00848   LPHEADCOMBO lphc,
00849   HDC         hdc)
00850 {
00851   RECT clientRect;
00852 
00853   if (CB_GETTYPE(lphc) != CBS_SIMPLE)
00854   {
00855     GetClientRect(hwnd, &clientRect);
00856   }
00857   else
00858   {
00859     CopyRect(&clientRect, &lphc->textRect);
00860 
00861     InflateRect(&clientRect, EDIT_CONTROL_PADDING(), EDIT_CONTROL_PADDING());
00862     InflateRect(&clientRect, COMBO_XBORDERSIZE(), COMBO_YBORDERSIZE());
00863   }
00864 
00865   DrawEdge(hdc, &clientRect, EDGE_SUNKEN, BF_RECT);
00866 }
00867 
00868 /***********************************************************************
00869  *           COMBO_PrepareColors
00870  *
00871  * This method will sent the appropriate WM_CTLCOLOR message to
00872  * prepare and setup the colors for the combo's DC.
00873  *
00874  * It also returns the brush to use for the background.
00875  */
00876 static HBRUSH COMBO_PrepareColors(
00877   HWND        hwnd,
00878   LPHEADCOMBO lphc,
00879   HDC         hDC)
00880 {
00881   HBRUSH  hBkgBrush;
00882 
00883   /*
00884    * Get the background brush for this control.
00885    */
00886   if (CB_DISABLED(lphc))
00887   {
00888     hBkgBrush = SendMessageA( lphc->owner, WM_CTLCOLORSTATIC,
00889                               hDC, lphc->hwndself );
00890 
00891     /*
00892      * We have to change the text color since WM_CTLCOLORSTATIC will
00893      * set it to the "enabled" color. This is the same behavior as the
00894      * edit control
00895      */
00896     SetTextColor(hDC, GetSysColor(COLOR_GRAYTEXT));
00897   }
00898   else
00899   {
00900     if (lphc->wState & CBF_EDIT)
00901     {
00902       hBkgBrush = SendMessageA( lphc->owner, WM_CTLCOLOREDIT,
00903                                 hDC, lphc->hwndself );
00904     }
00905     else
00906     {
00907       hBkgBrush = SendMessageA( lphc->owner, WM_CTLCOLORLISTBOX,
00908                                 hDC, lphc->hwndself );
00909     }
00910   }
00911 
00912   /*
00913    * Catch errors.
00914    */
00915   if( !hBkgBrush )
00916     hBkgBrush = GetSysColorBrush(COLOR_WINDOW);
00917 
00918   return hBkgBrush;
00919 }
00920 
00921 /***********************************************************************
00922  *           COMBO_EraseBackground
00923  */
00924 static LRESULT COMBO_EraseBackground(HWND hwnd,WPARAM wParam,LPARAM lParam)
00925 {
00926   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
00927   HBRUSH  hBkgBrush;
00928   RECT    clientRect;
00929   HDC     hDC;
00930 
00931   hDC = (wParam) ? (HDC)wParam:GetDC(hwnd);
00932 
00933   /*
00934    * Calculate the area that we want to erase.
00935    */
00936   if (CB_GETTYPE(lphc) != CBS_SIMPLE)
00937   {
00938     GetClientRect(hwnd, &clientRect);
00939   }
00940   else
00941   {
00942     CopyRect(&clientRect, &lphc->textRect);
00943 
00944     InflateRect(&clientRect, COMBO_XBORDERSIZE(), COMBO_YBORDERSIZE());
00945   }
00946 
00947   /*
00948    * Retrieve the background brush
00949    */
00950   hBkgBrush = COMBO_PrepareColors(hwnd, lphc, hDC);
00951 
00952   FillRect(hDC, &clientRect, hBkgBrush);
00953 
00954   if (!wParam)
00955     ReleaseDC(hwnd, hDC);
00956 
00957   return TRUE;
00958 }
00959 
00960 static LRESULT COMBO_GetDlgCode(HWND hwnd,WPARAM wParam,LPARAM lParam)
00961 {
00962   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
00963   LRESULT result = DLGC_WANTARROWS | DLGC_WANTCHARS;
00964 
00965   if (lParam && (((LPMSG)lParam)->message == WM_KEYDOWN))
00966   {
00967     int vk = (int)((LPMSG)lParam)->wParam;
00968 
00969     if ((vk == VK_RETURN || vk == VK_ESCAPE) && (lphc->wState & CBF_DROPPED))
00970       result |= DLGC_WANTMESSAGE;
00971   }
00972   return  result;
00973 }
00974 
00975 /***********************************************************************
00976  *           COMBO_Paint
00977  */
00978 static LRESULT COMBO_Paint(HWND hwnd,WPARAM wParam,LPARAM lParam)
00979 {
00980   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
00981   PAINTSTRUCT ps;
00982   HDC   hDC;
00983 
00984   hDC = (wParam) ? (HDC)wParam:BeginPaint(hwnd,&ps);
00985 
00986 
00987   if( hDC && !(lphc->wState & CBF_NOREDRAW) )
00988   {
00989       HBRUSH    hPrevBrush, hBkgBrush;
00990 
00991       /*
00992        * Retrieve the background brush and select it in the
00993        * DC.
00994        */
00995       hBkgBrush = COMBO_PrepareColors(hwnd,lphc,hDC);
00996 
00997       hPrevBrush = SelectObject( hDC, hBkgBrush );
00998 
00999       /*
01000        * In non 3.1 look, there is a sunken border on the combobox
01001        */
01002       CBPaintBorder(CB_HWND(lphc), lphc, hDC);
01003 
01004       if( !IsRectEmpty(&lphc->buttonRect) )
01005       {
01006         CBPaintButton(lphc, hDC, lphc->buttonRect);
01007       }
01008 
01009       if( !(lphc->wState & CBF_EDIT) )
01010       {
01011         /*
01012          * The text area has a border only in Win 3.1 look.
01013          */
01014 
01015         CBPaintText( lphc, hDC, lphc->textRect);
01016       }
01017 
01018       if( hPrevBrush )
01019         SelectObject( hDC, hPrevBrush );
01020   }
01021 
01022   if(!wParam) EndPaint(hwnd,&ps);
01023 
01024   return 0;
01025 }
01026 
01027 static LRESULT COMBO_PrintClient(HWND hwnd,WPARAM wParam,LPARAM lParam)
01028 {
01029   if (lParam & PRF_ERASEBKGND) COMBO_EraseBackground(hwnd,wParam,lParam);
01030 
01031   return COMBO_Paint(hwnd,wParam,lParam);
01032 }
01033 
01034 /***********************************************************************
01035  *           CBUpdateLBox
01036  *
01037  * Select listbox entry according to the contents of the edit control.
01038  */
01039 static INT CBUpdateLBox( LPHEADCOMBO lphc, BOOL bSelect )
01040 {
01041    INT  length, idx;
01042    LPSTR        pText = NULL;
01043 
01044    idx = LB_ERR;
01045    length = CB_GETEDITTEXTLENGTH( lphc );
01046 
01047    if( length > 0 )
01048        pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1);
01049 
01050    //TRACE("\t edit text length %i\n", length );
01051 
01052    if( pText )
01053    {
01054        if( length ) GetWindowTextA( lphc->hWndEdit, pText, length + 1);
01055        else pText[0] = '\0';
01056        idx = SendMessageA( lphc->hWndLBox, LB_FINDSTRING,
01057                              (WPARAM)(-1), (LPARAM)pText );
01058        HeapFree( GetProcessHeap(), 0, pText );
01059    }
01060 
01061    SendMessageA( lphc->hWndLBox, LB_SETCURSEL, (WPARAM)(bSelect ? idx : -1), 0 );
01062 
01063    /* the LB_SETCARETINDEX message should scroll the list box if required
01064       and sending LB_SETTOPINDEX can generate annoying behaviors  */
01065    /* probably superfluous but Windows sends this too */
01066    SendMessageA( lphc->hWndLBox, LB_SETCARETINDEX, (WPARAM)(idx < 0 ? 0 : idx), 0 );
01067    SendMessageA( lphc->hWndLBox, LB_SETTOPINDEX, (WPARAM)(idx < 0 ? 0 : idx), 0 );
01068 
01069    return idx;
01070 }
01071 
01072 /***********************************************************************
01073  *           CBUpdateEdit
01074  *
01075  * Copy a listbox entry to the edit control.
01076  */
01077 static void CBUpdateEdit( LPHEADCOMBO lphc , INT index )
01078 {
01079    INT  length;
01080    LPSTR        pText = NULL;
01081 
01082    //TRACE("\t %i\n", index );
01083 
01084    if( index >= 0 ) /* got an entry */
01085    {
01086        length = SendMessageA( lphc->hWndLBox, LB_GETTEXTLEN, (WPARAM)index, 0);
01087        if( length )
01088        {
01089            pText = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1);
01090            if(pText)
01091            {
01092                 SendMessageA( lphc->hWndLBox, LB_GETTEXT,
01093                                 (WPARAM)index, (LPARAM)pText );
01094            }
01095        }
01096    }
01097    lphc->wState |= CBF_NOEDITNOTIFY;
01098 
01099    SendMessageA( lphc->hWndEdit, WM_SETTEXT, 0, pText ? (LPARAM)pText : (LPARAM)"" );
01100 
01101    lphc->wState &= ~CBF_NOEDITNOTIFY;
01102 
01103    if( lphc->wState & CBF_FOCUSED )
01104      SendMessageA( lphc->hWndEdit, EM_SETSEL, 0, (LPARAM)(-1) );
01105 
01106 
01107    if( pText )
01108        HeapFree( GetProcessHeap(), 0, pText );
01109 }
01110 
01111 /***********************************************************************
01112  *           CBDropDown
01113  *
01114  * Show listbox popup.
01115  */
01116 static void CBDropDown( LPHEADCOMBO lphc )
01117 {
01118    RECT rect;
01119    int nItems = 0;
01120    int nDroppedHeight;
01121 
01122    HWND hWnd = 0;
01123    RECT DesktopRect;
01124 
01125    //TRACE("[%04x]: drop down\n", CB_HWND(lphc));
01126 
01127    CB_NOTIFY( lphc, CBN_DROPDOWN );
01128 
01129    /* set selection */
01130 
01131    lphc->wState |= CBF_DROPPED;
01132    if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
01133    {
01134        lphc->droppedIndex = CBUpdateLBox( lphc,TRUE );
01135 
01136        if( !(lphc->wState & CBF_CAPTURE) )
01137          CBUpdateEdit( lphc, lphc->droppedIndex );
01138    }
01139    else
01140    {
01141        lphc->droppedIndex = SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0 );
01142 
01143        if( lphc->droppedIndex == LB_ERR )
01144          lphc->droppedIndex = 0;
01145 
01146        SendMessageA( lphc->hWndLBox, LB_SETTOPINDEX,
01147                      (WPARAM)(lphc->droppedIndex == LB_ERR ? 0 : lphc->droppedIndex), 0 );
01148        SendMessageA( lphc->hWndLBox, LB_CARETON, 0, 0 );
01149    }
01150 
01151    /* now set popup position */
01152    GetWindowRect( lphc->hwndself, &rect );
01153 
01154    /*
01155     * If it's a dropdown, the listbox is offset
01156     */
01157    if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
01158      rect.left += COMBO_EDITBUTTONSPACE();
01159 
01160    /* if the dropped height is greater than the total height of the dropped
01161      items list, then force the drop down list height to be the total height
01162      of the items in the dropped list */
01163 
01164   /* And Remove any extra space (Best Fit) */
01165    nDroppedHeight = lphc->droppedRect.bottom - lphc->droppedRect.top;
01166    nItems = (int)SendMessageA (lphc->hWndLBox, LB_GETCOUNT, 0, 0);
01167 
01168    if (nItems > 0)
01169    {
01170       int nHeight;
01171 
01172       nHeight = (int)SendMessageA (lphc->hWndLBox, LB_GETITEMHEIGHT, 0, 0);
01173       nHeight *= nItems;
01174 
01175       if (nHeight < nDroppedHeight - COMBO_YBORDERSIZE())
01176          nDroppedHeight = nHeight + COMBO_YBORDERSIZE();
01177    }
01178 
01179    /*Now we should know screen size. */
01180    hWnd = GetDesktopWindow();
01181 
01182    if( hWnd )
01183    {
01184      GetClientRect( hWnd, &DesktopRect );
01185    }
01186 
01187 
01188    /*If height of dropped rectangle gets beyond a screen size it should go up, otherwise down.*/
01189    if((rect.bottom + nDroppedHeight) >= DesktopRect.bottom)
01190       rect.bottom = rect.top - nDroppedHeight;
01191 
01192    SetWindowPos( lphc->hWndLBox, HWND_TOP, rect.left, rect.bottom,
01193                  lphc->droppedRect.right - lphc->droppedRect.left,
01194                  nDroppedHeight,
01195                  SWP_NOACTIVATE | SWP_SHOWWINDOW);
01196 
01197 
01198    if( !(lphc->wState & CBF_NOREDRAW) )
01199      RedrawWindow( lphc->hwndself, NULL, 0, RDW_INVALIDATE |
01200                            RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
01201 
01202    EnableWindow( lphc->hWndLBox, TRUE );
01203    if (GetCapture() != lphc->hwndself)
01204       SetCapture(lphc->hWndLBox);
01205 }
01206 
01207 /***********************************************************************
01208  *           CBRollUp
01209  *
01210  * Hide listbox popup.
01211  */
01212 static void CBRollUp( LPHEADCOMBO lphc, BOOL ok, BOOL bButton )
01213 {
01214    HWND hWnd = lphc->hwndself;
01215 
01216    CB_NOTIFY( lphc, (ok) ? CBN_SELENDOK : CBN_SELENDCANCEL );
01217 
01218    if( IsWindow( hWnd ) && CB_GETTYPE(lphc) != CBS_SIMPLE )
01219    {
01220 
01221        //TRACE("[%04x]: roll up [%i]\n", CB_HWND(lphc), (INT)ok );
01222 
01223        if( lphc->wState & CBF_DROPPED )
01224        {
01225            RECT rect;
01226 
01227            lphc->wState &= ~CBF_DROPPED;
01228            /* By hiding the window, the capture by lphc->hWndLBox will be released too */
01229         
01230            ShowWindow( lphc->hWndLBox, SW_HIDE );
01231 
01232            if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
01233            {
01234                rect = lphc->buttonRect;
01235            }
01236            else
01237            {
01238                if( bButton )
01239                {
01240                  UnionRect( &rect,
01241                             &lphc->buttonRect,
01242                             &lphc->textRect);
01243                }
01244                else
01245                  rect = lphc->textRect;
01246 
01247                bButton = TRUE;
01248            }
01249 
01250            if( bButton && !(lphc->wState & CBF_NOREDRAW) )
01251                RedrawWindow( hWnd, &rect, 0, RDW_INVALIDATE |
01252                                RDW_ERASE | RDW_UPDATENOW | RDW_NOCHILDREN );
01253            CB_NOTIFY( lphc, CBN_CLOSEUP );
01254        }
01255    }
01256 }
01257 
01258 /***********************************************************************
01259  *           COMBO_FlipListbox
01260  *
01261  * Used by the ComboLBox to show/hide itself in response to VK_F4, etc...
01262  */
01263 BOOL COMBO_FlipListbox( LPHEADCOMBO lphc, BOOL ok, BOOL bRedrawButton )
01264 {
01265    if( lphc->wState & CBF_DROPPED )
01266    {
01267        CBRollUp( lphc, ok, bRedrawButton );
01268        return FALSE;
01269    }
01270 
01271    CBDropDown( lphc );
01272    return TRUE;
01273 }
01274 
01275 /***********************************************************************
01276  *           CBRepaintButton
01277  */
01278 static void CBRepaintButton( LPHEADCOMBO lphc )
01279    {
01280   InvalidateRect(CB_HWND(lphc), &lphc->buttonRect, TRUE);
01281   UpdateWindow(CB_HWND(lphc));
01282 }
01283 
01284 static VOID COMBO_EditSetFocus(LPHEADCOMBO lphc)
01285 {
01286   if(!(lphc->wState & CBF_FOCUSED))
01287   {
01288     if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
01289       SendMessageA( lphc->hWndLBox, LB_CARETON, 0, 0 );
01290 
01291     lphc->wState |= CBF_FOCUSED;
01292 
01293     if( !(lphc->wState & CBF_EDIT) )
01294       InvalidateRect(CB_HWND(lphc), &lphc->textRect, TRUE);
01295 
01296     CB_NOTIFY( lphc, CBN_SETFOCUS );
01297   }
01298 }
01299 
01300 /***********************************************************************
01301  *           COMBO_SetFocus
01302  */
01303 static LRESULT COMBO_SetFocus(HWND hwnd,WPARAM wParam,LPARAM lParam)
01304 {
01305    LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01306 
01307 //SvL: This doesn't work. Example:
01308 //     Click on combo box in Abiword (when it doesn't have the focus)
01309 //     COMBO_LButtonDown checks focus, not set -> SetFocus to combo box
01310 //     Next thing it does is check if it has the focus (CBF_FOCUSED flag).
01311 //     This check fails as SetFocus(lphc->hWndEdit) doesn't change this flag.
01312 //     Removing this check doesn't work as the listbox is not removed after it
01313 //     loses the focus.
01314 //   if(lphc->wState & CBF_EDIT)
01315 //     SetFocus(lphc->hWndEdit);
01316 //   else
01317      COMBO_EditSetFocus(lphc);
01318 
01319    return 0;
01320 }
01321 
01322 static VOID COMBO_EditKillFocus(LPHEADCOMBO lphc)
01323 {
01324   if( lphc->wState & CBF_FOCUSED )
01325   {
01326     CBRollUp( lphc, FALSE, TRUE );
01327     if( IsWindow( lphc->hwndself ) )
01328     {
01329       if( CB_GETTYPE(lphc) == CBS_DROPDOWNLIST )
01330         SendMessageA( lphc->hWndLBox, LB_CARETOFF, 0, 0 );
01331 
01332       lphc->wState &= ~CBF_FOCUSED;
01333 
01334       /* redraw text */
01335       if( !(lphc->wState & CBF_EDIT) )
01336         InvalidateRect(CB_HWND(lphc), &lphc->textRect, TRUE);
01337 
01338       CB_NOTIFY( lphc, CBN_KILLFOCUS );
01339     }
01340   }
01341 }
01342 
01343 /***********************************************************************
01344  *           COMBO_KillFocus
01345  */
01346 static LRESULT COMBO_KillFocus(HWND hwnd,WPARAM wParam,LPARAM lParam)
01347 {
01348    LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01349 
01350    if(!wParam || (wParam != lphc->hWndEdit && wParam != lphc->hWndLBox ))
01351    {
01352      COMBO_EditKillFocus(lphc);
01353    }
01354 
01355    return 0;
01356 }
01357 
01358 /***********************************************************************
01359  *           COMBO_Command
01360  */
01361 static LRESULT COMBO_Command(HWND hwnd,WPARAM wParam,LPARAM lParam)
01362 {
01363    LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01364 
01365    if ( lphc->wState & CBF_EDIT && lphc->hWndEdit == lParam )
01366    {
01367        /* ">> 8" makes gcc generate jump-table instead of cmp ladder */
01368 
01369        switch( HIWORD(wParam) >> 8 )
01370        {
01371            case (EN_SETFOCUS >> 8):
01372 
01373                 //TRACE("[%04x]: edit [%04x] got focus\n",
01374                 //             CB_HWND(lphc), lphc->hWndEdit );
01375 
01376                 COMBO_EditSetFocus(lphc);
01377                 break;
01378 
01379            case (EN_KILLFOCUS >> 8):
01380 
01381                 //TRACE("[%04x]: edit [%04x] lost focus\n",
01382                 //             CB_HWND(lphc), lphc->hWndEdit );
01383 
01384                 /* NOTE: it seems that Windows' edit control sends an
01385                  * undocumented message WM_USER + 0x1B instead of this
01386                  * notification (only when it happens to be a part of
01387                  * the combo). ?? - AK.
01388                  */
01389 
01390                 COMBO_EditKillFocus(lphc);
01391                 break;
01392 
01393 
01394            case (EN_CHANGE >> 8):
01395                /*
01396                 * In some circumstances (when the selection of the combobox
01397                 * is changed for example) we don't wans the EN_CHANGE notification
01398                 * to be forwarded to the parent of the combobox. This code
01399                 * checks a flag that is set in these occasions and ignores the
01400                 * notification.
01401                 */
01402                 if (lphc->wState & CBF_NOEDITNOTIFY)
01403                 {
01404                   lphc->wState &= ~CBF_NOEDITNOTIFY;
01405                 }
01406                 else
01407                 {
01408                   CB_NOTIFY( lphc, CBN_EDITCHANGE );
01409                 }
01410 
01411                 if (lphc->wState & CBF_NOLBSELECT)
01412                 {
01413                   lphc->wState &= ~CBF_NOLBSELECT;
01414                 }
01415                 else
01416                 {
01417                   CBUpdateLBox( lphc, lphc->wState & CBF_DROPPED );
01418                 }
01419                 break;
01420 
01421            case (EN_UPDATE >> 8):
01422                 //SvL: Don't send updates either. (Realplayer 7 infinite loops)
01423                 //CB: note: EN_UPDATE changes in Corel 20000317
01424                /*
01425                 * In some circumstances (when the selection of the combobox
01426                 * is changed for example) we don't wans the EN_CHANGE notification
01427                 * to be forwarded to the parent of the combobox. This code
01428                 * checks a flag that is set in these occasions and ignores the
01429                 * notification.
01430                 */
01431                 if (lphc->wState & CBF_NOEDITNOTIFY)
01432                 {
01433                   lphc->wState &= ~CBF_NOEDITNOTIFY;
01434                 }
01435                 else
01436                 {
01437                   CB_NOTIFY( lphc, CBN_EDITUPDATE );
01438                 }
01439                 break;
01440 
01441            case (EN_ERRSPACE >> 8):
01442                 CB_NOTIFY( lphc, CBN_ERRSPACE );
01443        }
01444    }
01445    else if( lphc->hWndLBox == lParam )
01446    {
01447        switch( HIWORD(wParam) )
01448        {
01449            case LBN_ERRSPACE:
01450                 CB_NOTIFY( lphc, CBN_ERRSPACE );
01451                 break;
01452 
01453            case LBN_DBLCLK:
01454                 CB_NOTIFY( lphc, CBN_DBLCLK );
01455                 break;
01456 
01457            case LBN_SELCHANGE:
01458            case LBN_SELCANCEL:
01459 
01460                 //TRACE("[%04x]: lbox selection change [%04x]\n",
01461                 //             CB_HWND(lphc), lphc->wState );
01462 
01463                 /* do not roll up if selection is being tracked
01464                  * by arrowkeys in the dropdown listbox */
01465 
01466                 if( (CB_GETTYPE(lphc) == CBS_SIMPLE) ||
01467                     ((lphc->wState & CBF_DROPPED) && !(lphc->wState & CBF_NOROLLUP)) )
01468                 {
01469                    CBRollUp( lphc, (HIWORD(wParam) == LBN_SELCHANGE), TRUE );
01470                 }
01471                 else lphc->wState &= ~CBF_NOROLLUP;
01472 
01473                 CB_NOTIFY( lphc, CBN_SELCHANGE );
01474 
01475                 if( HIWORD(wParam) == LBN_SELCHANGE)
01476                 {
01477                   if( lphc->wState & CBF_EDIT )
01478                   {
01479                       INT index = SendMessageA(lphc->hWndLBox, LB_GETCURSEL, 0, 0);
01480 
01481                       lphc->wState |= CBF_NOLBSELECT;
01482                       CBUpdateEdit( lphc, index );
01483                       /* select text in edit, as Windows does */
01484                       SendMessageA( lphc->hWndEdit, EM_SETSEL, 0, (LPARAM)(-1) );
01485                   }
01486                   else
01487                       InvalidateRect(CB_HWND(lphc), &lphc->textRect, TRUE);
01488                 }
01489 
01490                 /* fall through */
01491 
01492            case LBN_SETFOCUS:
01493            case LBN_KILLFOCUS:
01494                 /* nothing to do here since ComboLBox always resets the focus to its
01495                  * combo/edit counterpart */
01496                  break;
01497        }
01498    }
01499    return 0;
01500 }
01501 
01502 /***********************************************************************
01503  *           COMBO_HandleItem
01504  *
01505  * Fixup an ownerdrawn item operation and pass it up to the combobox owner.
01506  */
01507 static LRESULT COMBO_HandleItem(HWND hwnd,UINT msg,WPARAM wParam,LPARAM lParam)
01508 {
01509    LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01510 
01511    //TRACE("[%04x]: ownerdraw op %04x\n", CB_HWND(lphc), msg );
01512 
01513 #define lpIS    ((LPDELETEITEMSTRUCT)lParam)
01514 
01515    /* two first items are the same in all 4 structs */
01516    lpIS->CtlType = ODT_COMBOBOX;
01517    lpIS->CtlID   = GetWindowLongA(hwnd,GWL_ID);
01518 
01519    switch( msg )        /* patch window handle */
01520    {
01521         case WM_DELETEITEM:
01522              lpIS->hwndItem = hwnd;
01523 #undef  lpIS
01524              break;
01525         case WM_DRAWITEM:
01526 #define lpIS    ((LPDRAWITEMSTRUCT)lParam)
01527              lpIS->hwndItem = hwnd;
01528 #undef  lpIS
01529              break;
01530         case WM_COMPAREITEM:
01531 #define lpIS    ((LPCOMPAREITEMSTRUCT)lParam)
01532              lpIS->hwndItem = hwnd;
01533 #undef  lpIS
01534              break;
01535    }
01536    return SendMessageA( GetParent(hwnd), msg, GetWindowLongA(hwnd,GWL_ID), lParam );
01537 }
01538 
01539 /***********************************************************************
01540  *           COMBO_GetText
01541  */
01542 static LRESULT COMBO_GetText(HWND hwnd,WPARAM wParam,LPARAM lParam)
01543 {
01544    LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01545 
01546    if( lphc->wState & CBF_EDIT )
01547        return SendMessageA( lphc->hWndEdit, WM_GETTEXT,
01548                              wParam,lParam);
01549 
01550    /* get it from the listbox */
01551 
01552    if( lphc->hWndLBox )
01553    {
01554        INT idx = SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0 );
01555        if( idx != LB_ERR )
01556        {
01557            LPSTR        lpBuffer;
01558            INT  length = SendMessageA( lphc->hWndLBox, LB_GETTEXTLEN,
01559                                                 (WPARAM)idx, 0 );
01560 
01561            /* 'length' is without the terminating character */
01562            if( length >= (UINT)wParam )
01563                lpBuffer = (LPSTR) HeapAlloc( GetProcessHeap(), 0, length + 1 );
01564            else
01565                lpBuffer = (LPSTR)lParam;
01566 
01567            if( lpBuffer )
01568            {
01569                INT    n = SendMessageA( lphc->hWndLBox, LB_GETTEXT,
01570                                            (WPARAM)idx, (LPARAM)lpBuffer );
01571 
01572                /* truncate if buffer is too short */
01573 
01574                if( length >= (UINT)wParam )
01575                {
01576                    if ((UINT)wParam && lParam) {
01577                    if( n != LB_ERR ) memcpy( (LPSTR)lParam, lpBuffer, ((UINT)wParam>n) ? n+1 : (UINT)wParam-1 );
01578                    ((LPSTR)lParam)[(UINT)wParam - 1] = '\0';
01579                    }
01580                    HeapFree( GetProcessHeap(), 0, lpBuffer );
01581                }
01582                return (LRESULT)n;
01583            }
01584        }
01585    }
01586    return 0;
01587 }
01588 
01589 static LRESULT COMBO_GetTextLength(HWND hwnd,WPARAM wParam,LPARAM lParam)
01590 {
01591   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01592 
01593   if (!(lphc->wState & CBF_EDIT))
01594   {
01595     int idx = SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0 );
01596 
01597     if (idx == -1) return 0;
01598     return SendMessageA( lphc->hWndLBox, LB_GETTEXTLEN, idx, 0 );
01599   } else if (lphc->wState & CBF_EDIT)
01600   {
01601     /* Don't bother turning on CBF_NOEDITNOTIFY. */
01602     return SendMessageA( lphc->hWndEdit, WM_GETTEXTLENGTH, wParam, lParam );
01603   } else return CB_ERR;
01604 }
01605 
01606 static LRESULT COMBO_HandleText(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
01607 {
01608   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01609 
01610   if (lphc == NULL)
01611   {
01612     dprintf(("COMBO_HandleText Info Pointer NULL!\n"));
01613     return CB_ERR;
01614   }
01615 
01616   if (lphc->wState & CBF_EDIT)
01617   {
01618     LRESULT res;
01619 
01620     lphc->wState |= CBF_NOEDITNOTIFY;
01621     res = SendMessageA( lphc->hWndEdit, message, wParam, lParam );
01622     lphc->wState &= ~CBF_NOEDITNOTIFY;
01623     return res;
01624   } else return CB_ERR;
01625 }
01626 
01627 /***********************************************************************
01628  *           CBResetPos
01629  *
01630  * This function sets window positions according to the updated
01631  * component placement struct.
01632  */
01633 static void CBResetPos(
01634   LPHEADCOMBO lphc,
01635   LPRECT      rectEdit,
01636   LPRECT      rectLB,
01637   BOOL        bRedraw)
01638 {
01639    BOOL bDrop = (CB_GETTYPE(lphc) != CBS_SIMPLE);
01640 
01641    /* NOTE: logs sometimes have WM_LBUTTONUP before a cascade of
01642     * sizing messages */
01643 
01644    if( lphc->wState & CBF_EDIT )
01645      SetWindowPos( lphc->hWndEdit, 0,
01646                    rectEdit->left, rectEdit->top,
01647                    rectEdit->right - rectEdit->left,
01648                    rectEdit->bottom - rectEdit->top,
01649                        SWP_NOZORDER | SWP_NOACTIVATE | ((bDrop) ? SWP_NOREDRAW : 0) );
01650 
01651    SetWindowPos( lphc->hWndLBox, 0,
01652                  rectLB->left, rectLB->top,
01653                  rectLB->right - rectLB->left,
01654                  rectLB->bottom - rectLB->top,
01655                    SWP_NOACTIVATE | SWP_NOZORDER | ((bDrop) ? SWP_NOREDRAW : 0) );
01656 
01657    if( bDrop )
01658    {
01659        if( lphc->wState & CBF_DROPPED )
01660        {
01661            lphc->wState &= ~CBF_DROPPED;
01662            ShowWindow( lphc->hWndLBox, SW_HIDE );
01663        }
01664 
01665        if( bRedraw && !(lphc->wState & CBF_NOREDRAW) )
01666            RedrawWindow( lphc->hwndself, NULL, 0,
01667                            RDW_INVALIDATE | RDW_ERASE | RDW_UPDATENOW );
01668    }
01669 }
01670 
01671 
01672 /***********************************************************************
01673  *           COMBO_Size
01674  */
01675 static LRESULT COMBO_Size(HWND hwnd,WPARAM wParam,LPARAM lParam)
01676 {
01677   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01678 
01679   dprintf(("COMBO_Size"));
01680 
01681   if(lphc->hWndLBox && !(lphc->wState & CBF_NORESIZE))
01682   {
01683     CBCalcPlacement(hwnd,
01684                     lphc,
01685                     &lphc->textRect,
01686                     &lphc->buttonRect,
01687                     &lphc->droppedRect);
01688 
01689     CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
01690   }
01691 
01692   return 0;
01693 }
01694 
01695 
01696 /***********************************************************************
01697  *           COMBO_Font
01698  */
01699 static LRESULT COMBO_SetFont(HWND hwnd,WPARAM wParam,LPARAM lParam)
01700 {
01701   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01702 
01703   /*
01704    * Set the font
01705    */
01706   lphc->hFont = wParam;
01707 
01708   /*
01709    * Propagate to owned windows.
01710    */
01711   if( lphc->wState & CBF_EDIT )
01712       SendMessageA(lphc->hWndEdit,WM_SETFONT,wParam,lParam);
01713   SendMessageA(lphc->hWndLBox,WM_SETFONT,wParam,lParam);
01714 
01715   /*
01716    * Redo the layout of the control.
01717    */
01718   if ( CB_GETTYPE(lphc) == CBS_SIMPLE)
01719   {
01720     CBCalcPlacement(hwnd,
01721                     lphc,
01722                     &lphc->textRect,
01723                     &lphc->buttonRect,
01724                     &lphc->droppedRect);
01725 
01726     CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
01727   }
01728   else
01729   {
01730     CBForceDummyResize(lphc);
01731   }
01732 
01733   return 0;
01734 }
01735 
01736 static LRESULT COMBO_GetFont(HWND hwnd,WPARAM wParam,LPARAM lParam)
01737 {
01738   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01739 
01740   return lphc->hFont;
01741 }
01742 
01743 
01744 /***********************************************************************
01745  *           COMBO_LButtonDown
01746  */
01747 static LRESULT COMBO_LButtonDown(HWND hwnd,WPARAM wParam,LPARAM lParam)
01748 {
01749    LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01750    POINT     pt;
01751    BOOL      bButton;
01752 
01753    if(!(lphc->wState & CBF_FOCUSED)) SetFocus(hwnd);
01754    if(!(lphc->wState & CBF_FOCUSED)) return 0;
01755 
01756    pt.x = LOWORD(lParam);
01757    pt.y = HIWORD(lParam);
01758    bButton = PtInRect(&lphc->buttonRect, pt);
01759 
01760    if( (CB_GETTYPE(lphc) == CBS_DROPDOWNLIST) ||
01761        (bButton && (CB_GETTYPE(lphc) == CBS_DROPDOWN)) )
01762    {
01763        lphc->wState |= CBF_BUTTONDOWN;
01764        if( lphc->wState & CBF_DROPPED )
01765        {
01766            /* got a click to cancel selection */
01767 
01768            lphc->wState &= ~CBF_BUTTONDOWN;
01769            CBRollUp( lphc, TRUE, FALSE );
01770            if( !IsWindow( hwnd ) ) return 0;
01771 
01772            if( lphc->wState & CBF_CAPTURE )
01773            {
01774                lphc->wState &= ~CBF_CAPTURE;
01775                ReleaseCapture();
01776            }
01777        }
01778        else
01779        {
01780            /* drop down the listbox and start tracking */
01781 
01782            lphc->wState |= CBF_CAPTURE;
01783            SetCapture( hwnd );
01784            CBDropDown( lphc );
01785        }
01786        if( bButton ) CBRepaintButton( lphc );
01787    }
01788 
01789    return 0;
01790 }
01791 
01792 /***********************************************************************
01793  *           COMBO_LButtonUp
01794  *
01795  * Release capture and stop tracking if needed.
01796  */
01797 static LRESULT COMBO_LButtonUp(HWND hwnd,WPARAM wParam,LPARAM lParam)
01798 {
01799    LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01800 
01801    if( lphc->wState & CBF_CAPTURE )
01802    {
01803        lphc->wState &= ~CBF_CAPTURE;
01804        if( CB_GETTYPE(lphc) == CBS_DROPDOWN )
01805        {
01806            INT index = CBUpdateLBox( lphc, TRUE );
01807 
01808            lphc->wState |= CBF_NOLBSELECT;
01809            CBUpdateEdit( lphc, index );
01810            lphc->wState &= ~CBF_NOLBSELECT;
01811        }
01812        SetCapture(lphc->hWndLBox);
01813    }
01814 
01815    if( lphc->wState & CBF_BUTTONDOWN )
01816    {
01817        lphc->wState &= ~CBF_BUTTONDOWN;
01818        CBRepaintButton( lphc );
01819    }
01820 
01821    return 0;
01822 }
01823 
01824 /***********************************************************************
01825  *           COMBO_MouseMove
01826  *
01827  * Two things to do - track combo button and release capture when
01828  * pointer goes into the listbox.
01829  */
01830 static LRESULT COMBO_MouseMove(HWND hwnd,WPARAM wParam,LPARAM lParam)
01831 {
01832    LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01833    POINT  pt;
01834    RECT   lbRect;
01835 
01836    if(!(lphc->wState & CBF_CAPTURE)) return 0;
01837 
01838    pt.x = LOWORD(lParam);
01839    pt.y = HIWORD(lParam);
01840 
01841    if( lphc->wState & CBF_BUTTONDOWN )
01842    {
01843      BOOL bButton;
01844 
01845      bButton = PtInRect(&lphc->buttonRect, pt);
01846 
01847      if( !bButton )
01848      {
01849        lphc->wState &= ~CBF_BUTTONDOWN;
01850        CBRepaintButton( lphc );
01851      }
01852    }
01853 
01854    GetClientRect( lphc->hWndLBox, &lbRect );
01855    MapWindowPoints(hwnd, lphc->hWndLBox, &pt, 1 );
01856    if( PtInRect(&lbRect, pt) )
01857    {
01858        lphc->wState &= ~CBF_CAPTURE;
01859        ReleaseCapture();
01860        if( CB_GETTYPE(lphc) == CBS_DROPDOWN ) CBUpdateLBox( lphc,TRUE );
01861 
01862        /* hand over pointer tracking */
01863        SendMessageA( lphc->hWndLBox, WM_LBUTTONDOWN, wParam, lParam );
01864    }
01865 
01866    return 0;
01867 }
01868 
01869 static LRESULT COMBO_MouseWheel(HWND hwnd,WPARAM wParam,LPARAM lParam)
01870 {
01871   if (wParam & (MK_SHIFT | MK_CONTROL))
01872     return DefWindowProcA(hwnd,WM_MOUSEWHEEL,wParam,lParam);
01873 
01874   if ((short) HIWORD(wParam) > 0) return SendMessageA(hwnd,WM_KEYDOWN,VK_UP,0);
01875   if ((short) HIWORD(wParam) < 0) return SendMessageA(hwnd,WM_KEYDOWN,VK_DOWN,0);
01876 
01877   return TRUE;
01878 }
01879 
01880 static LRESULT COMBO_Enable(HWND hwnd,WPARAM wParam,LPARAM lParam)
01881 {
01882   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01883 
01884   if( lphc->wState & CBF_EDIT )
01885     EnableWindow( lphc->hWndEdit, (BOOL)wParam );
01886   EnableWindow( lphc->hWndLBox, (BOOL)wParam );
01887 
01888   /* Force the control to repaint when the enabled state changes. */
01889   InvalidateRect(CB_HWND(lphc), NULL, TRUE);
01890 
01891   return 0;
01892 }
01893 
01894 static LRESULT COMBO_SetRedraw(HWND hwnd,WPARAM wParam,LPARAM lParam)
01895 {
01896   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01897 
01898   if( wParam )
01899     lphc->wState &= ~CBF_NOREDRAW;
01900   else
01901     lphc->wState |= CBF_NOREDRAW;
01902 
01903   if( lphc->wState & CBF_EDIT )
01904     SendMessageA( lphc->hWndEdit, WM_SETREDRAW, wParam, lParam );
01905   SendMessageA( lphc->hWndLBox, WM_SETREDRAW, wParam, lParam );
01906 
01907   return 0;
01908 }
01909 
01910 static LRESULT COMBO_SysKeyDown(HWND hwnd,WPARAM wParam,LPARAM lParam)
01911 {
01912   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01913 
01914   if( KEYDATA_ALT & HIWORD(lParam) )
01915     if( wParam == VK_UP || wParam == VK_DOWN )
01916       COMBO_FlipListbox( lphc,FALSE,FALSE );
01917 
01918   return 0;
01919 }
01920 
01921 static LRESULT COMBO_HandleKey(HWND hwnd,UINT message,WPARAM wParam,LPARAM lParam)
01922 {
01923   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01924 
01925   if (((CHAR)wParam == VK_RETURN || (CHAR)wParam == VK_ESCAPE) && (lphc->wState & CBF_DROPPED))
01926   {
01927     CBRollUp( lphc, (CHAR)wParam == VK_RETURN, FALSE );
01928     return TRUE;
01929   }
01930 
01931   if( lphc->wState & CBF_EDIT )
01932     return  SendMessageA( lphc->hWndEdit, message, wParam, lParam );
01933   else
01934     return  SendMessageA( lphc->hWndLBox, message, wParam, lParam );
01935 }
01936 
01937 /* combobox messages */
01938 
01939 static LRESULT COMBO_AddString(HWND hwnd,WPARAM wParam,LPARAM lParam)
01940 {
01941   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01942 
01943   return SendMessageA(lphc->hWndLBox,LB_ADDSTRING,0,lParam);
01944 }
01945 
01946 static LRESULT COMBO_InsertString(HWND hwnd,WPARAM wParam,LPARAM lParam)
01947 {
01948   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01949 
01950   return SendMessageA(lphc->hWndLBox,LB_INSERTSTRING,wParam,lParam);
01951 }
01952 
01953 static LRESULT COMBO_DeleteString(HWND hwnd,WPARAM wParam,LPARAM lParam)
01954 {
01955   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01956 
01957   return SendMessageA(lphc->hWndLBox,LB_DELETESTRING,wParam,0);
01958 }
01959 
01960 /***********************************************************************
01961  *           COMBO_SelectString
01962  */
01963 static LRESULT COMBO_SelectString(HWND hwnd,WPARAM wParam,LPARAM lParam)
01964 {
01965   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01966   INT CurSel = SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0 );
01967   INT index = SendMessageA(lphc->hWndLBox,LB_SELECTSTRING,wParam,lParam);
01968 
01969   if( index >= 0 )
01970   {
01971     if( lphc->wState & CBF_EDIT )
01972     {
01973       if (CurSel != index)
01974         CBUpdateEdit( lphc, index );
01975     } else
01976         InvalidateRect(CB_HWND(lphc), &lphc->textRect, TRUE);
01977   }
01978 
01979   return (LRESULT)index;
01980 }
01981 
01982 static LRESULT COMBO_FindString(HWND hwnd,WPARAM wParam,LPARAM lParam)
01983 {
01984   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01985 
01986   return SendMessageA(lphc->hWndLBox,LB_FINDSTRING,wParam,lParam);
01987 }
01988 
01989 static LRESULT COMBO_FindStringExact(HWND hwnd,WPARAM wParam,LPARAM lParam)
01990 {
01991   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
01992 
01993   return SendMessageA(lphc->hWndLBox,LB_FINDSTRINGEXACT,wParam,lParam);
01994 }
01995 
01996 /***********************************************************************
01997  *           COMBO_SetItemHeight
01998  */
01999 static LRESULT COMBO_SetItemHeight(HWND hwnd,WPARAM wParam,LPARAM lParam)
02000 {
02001    LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02002    LRESULT      lRet = CB_ERR;
02003 
02004    if( wParam == -1 ) /* set text field height */
02005    {
02006        if( lParam < 32768 )
02007        {
02008            lphc->editHeight = lParam;
02009 
02010          /*
02011           * Redo the layout of the control.
02012           */
02013          if ( CB_GETTYPE(lphc) == CBS_SIMPLE)
02014          {
02015            CBCalcPlacement(hwnd,
02016                            lphc,
02017                            &lphc->textRect,
02018                            &lphc->buttonRect,
02019                            &lphc->droppedRect);
02020 
02021            CBResetPos( lphc, &lphc->textRect, &lphc->droppedRect, TRUE );
02022          }
02023          else
02024          {
02025            CBForceDummyResize(lphc);
02026          }
02027 
02028            lRet = lParam;
02029        }
02030    }
02031    else if ( CB_OWNERDRAWN(lphc) )      /* set listbox item height */
02032         lRet = SendMessageA( lphc->hWndLBox, LB_SETITEMHEIGHT,
02033                               wParam,lParam);
02034    return lRet;
02035 }
02036 
02037 static LRESULT COMBO_GetItemHeight(HWND hwnd,WPARAM wParam,LPARAM lParam)
02038 {
02039   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02040 
02041   if( (INT)wParam >= 0 )  /* listbox item */
02042     return SendMessageA( lphc->hWndLBox, LB_GETITEMHEIGHT, wParam, 0);
02043 
02044   return CBGetTextAreaHeight(hwnd, lphc);
02045 }
02046 
02047 static LRESULT COMBO_ResetContent(HWND hwnd,WPARAM wParam,LPARAM lParam)
02048 {
02049   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02050 
02051   SendMessageA( lphc->hWndLBox, LB_RESETCONTENT, 0, 0 );
02052   InvalidateRect(CB_HWND(lphc), NULL, TRUE);
02053 
02054   return  TRUE;
02055 }
02056 
02057 static LRESULT COMBO_InitStorage(HWND hwnd,WPARAM wParam,LPARAM lParam)
02058 {
02059   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02060 
02061   return SendMessageA( lphc->hWndLBox, LB_INITSTORAGE, wParam, lParam);
02062 }
02063 
02064 static LRESULT COMBO_GetHorizontalExtent(HWND hwnd,WPARAM wParam,LPARAM lParam)
02065 {
02066   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02067 
02068   return SendMessageA( lphc->hWndLBox, LB_GETHORIZONTALEXTENT, 0, 0);
02069 }
02070 
02071 static LRESULT COMBO_SetHorizontalExtent(HWND hwnd,WPARAM wParam,LPARAM lParam)
02072 {
02073   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02074 
02075   return SendMessageA( lphc->hWndLBox, LB_SETHORIZONTALEXTENT, wParam, 0);
02076 }
02077 
02078 static LRESULT COMBO_GetTopIndex(HWND hwnd,WPARAM wParam,LPARAM lParam)
02079 {
02080   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02081 
02082   return SendMessageA( lphc->hWndLBox, LB_GETTOPINDEX, 0, 0);
02083 }
02084 
02085 static LRESULT COMBO_GetLocale(HWND hwnd,WPARAM wParam,LPARAM lParam)
02086 {
02087   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02088 
02089   return SendMessageA( lphc->hWndLBox, LB_GETLOCALE, 0, 0);
02090 }
02091 
02092 static LRESULT COMBO_SetLocale(HWND hwnd,WPARAM wParam,LPARAM lParam)
02093 {
02094   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02095 
02096   return SendMessageA( lphc->hWndLBox, LB_SETLOCALE, wParam, 0);
02097 }
02098 
02099 static LRESULT COMBO_GetDroppedWidth(HWND hwnd,WPARAM wParam,LPARAM lParam)
02100 {
02101   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02102 
02103   if( lphc->droppedWidth )
02104     return  lphc->droppedWidth;
02105 
02106   return lphc->droppedRect.right - lphc->droppedRect.left;
02107 }
02108 
02109 static LRESULT COMBO_SetDroppedWidth(HWND hwnd,WPARAM wParam,LPARAM lParam)
02110 {
02111   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02112 
02113   if( (CB_GETTYPE(lphc) != CBS_SIMPLE) &&
02114       (INT)wParam < 32768 ) lphc->droppedWidth = (INT)wParam;
02115 
02116   return CB_ERR;
02117 }
02118 
02119 static LRESULT COMBO_GetDroppedControlRect(HWND hwnd,WPARAM wParam,LPARAM lParam)
02120 {
02121   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02122 
02123   if( lParam ) CBGetDroppedControlRect(lphc, (LPRECT)lParam );
02124 
02125   return CB_OKAY;
02126 }
02127 
02128 static LRESULT COMBO_GetDroppedState(HWND hwnd,WPARAM wParam,LPARAM lParam)
02129 {
02130   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02131 
02132   return (lphc->wState & CBF_DROPPED) ? TRUE : FALSE;
02133 }
02134 
02135 static LRESULT COMBO_Dir(HWND hwnd,WPARAM wParam,LPARAM lParam)
02136 {
02137   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02138 
02139   return COMBO_Directory( lphc, (UINT)wParam,
02140                           (LPSTR)lParam,TRUE);
02141 }
02142 
02143 static LRESULT COMBO_ShowDropDown(HWND hwnd,WPARAM wParam,LPARAM lParam)
02144 {
02145   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02146 
02147   if( CB_GETTYPE(lphc) != CBS_SIMPLE )
02148   {
02149     if( wParam )
02150     {
02151       if( !(lphc->wState & CBF_DROPPED) )
02152         CBDropDown( lphc );
02153     }
02154     else
02155       if( lphc->wState & CBF_DROPPED )
02156         CBRollUp( lphc, FALSE, TRUE );
02157   }
02158 
02159   return TRUE;
02160 }
02161 
02162 static LRESULT COMBO_GetCount(HWND hwnd,WPARAM wParam,LPARAM lParam)
02163 {
02164   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02165 
02166   return SendMessageA( lphc->hWndLBox, LB_GETCOUNT, 0, 0);
02167 }
02168 
02169 static LRESULT COMBO_GetCurSel(HWND hwnd,WPARAM wParam,LPARAM lParam)
02170 {
02171   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02172 
02173   return SendMessageA( lphc->hWndLBox, LB_GETCURSEL, 0, 0);
02174 }
02175 
02176 static LRESULT COMBO_SetCurSel(HWND hwnd,WPARAM wParam,LPARAM lParam)
02177 {
02178   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02179 
02180   lParam = SendMessageA( lphc->hWndLBox, LB_SETCURSEL, wParam, 0);
02181   if( lParam >= 0 )
02182     SendMessageA( lphc->hWndLBox, LB_SETTOPINDEX, wParam, 0);
02183   if( lphc->wState & CBF_SELCHANGE )
02184   {
02185     //SvL: Clear the flag here; doing it after calling CBUpdateEdit causes
02186     //     an infinite loop in RealPlayer 7
02187     lphc->wState &= ~CBF_SELCHANGE;
02188 
02189     /* no LBN_SELCHANGE in this case, update manually */
02190     if( lphc->wState & CBF_EDIT )
02191         CBUpdateEdit( lphc, (INT)wParam );
02192     else
02193         InvalidateRect(CB_HWND(lphc), &lphc->textRect, TRUE);
02194   }
02195 
02196   return lParam;
02197 }
02198 
02199 static LRESULT COMBO_GetLBText(HWND hwnd,WPARAM wParam,LPARAM lParam)
02200 {
02201   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02202 
02203   return SendMessageA( lphc->hWndLBox, LB_GETTEXT, wParam, lParam);
02204 }
02205 
02206 static LRESULT COMBO_GetLBTextLen(HWND hwnd,WPARAM wParam,LPARAM lParam)
02207 {
02208   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02209 
02210   return SendMessageA( lphc->hWndLBox, LB_GETTEXTLEN, wParam, 0);
02211 }
02212 
02213 static LRESULT COMBO_GetItemData(HWND hwnd,WPARAM wParam,LPARAM lParam)
02214 {
02215   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02216 
02217   return SendMessageA( lphc->hWndLBox, LB_GETITEMDATA, wParam, 0);
02218 }
02219 
02220 static LRESULT COMBO_SetItemData(HWND hwnd,WPARAM wParam,LPARAM lParam)
02221 {
02222   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02223 
02224   return SendMessageA( lphc->hWndLBox, LB_SETITEMDATA, wParam, lParam);
02225 }
02226 
02227 static LRESULT COMBO_GetEditSel(HWND hwnd,WPARAM wParam,LPARAM lParam)
02228 {
02229   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02230 
02231   if( lphc->wState & CBF_EDIT )
02232   {
02233     INT a, b;
02234 
02235     return  SendMessageA( lphc->hWndEdit, EM_GETSEL,
02236                           (wParam) ? wParam : (WPARAM)&a,
02237                           (lParam) ? lParam : (LPARAM)&b );
02238   }
02239 
02240   return CB_ERR;
02241 }
02242 
02243 static LRESULT COMBO_SetEditSel(HWND hwnd,WPARAM wParam,LPARAM lParam)
02244 {
02245   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02246 
02247   if( lphc->wState & CBF_EDIT )
02248     return  SendMessageA( lphc->hWndEdit, EM_SETSEL,
02249                           (INT)(INT16)LOWORD(lParam), (INT)(INT16)HIWORD(lParam) );
02250 
02251   return CB_ERR;
02252 }
02253 
02254 static LRESULT COMBO_SetExtendedUI(HWND hwnd,WPARAM wParam,LPARAM lParam)
02255 {
02256   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02257 
02258   if( CB_GETTYPE(lphc) == CBS_SIMPLE )
02259     return  CB_ERR;
02260   if( wParam )
02261     lphc->wState |= CBF_EUI;
02262   else lphc->wState &= ~CBF_EUI;
02263     return CB_OKAY;
02264 }
02265 
02266 static LRESULT COMBO_GetExtendedUI(HWND hwnd,WPARAM wParam,LPARAM lParam)
02267 {
02268   LPHEADCOMBO lphc = (LPHEADCOMBO)GetInfoPtr(hwnd);
02269 
02270   return (lphc->wState & CBF_EUI) ? TRUE : FALSE;
02271 }
02272 
02273 /***********************************************************************
02274  *           ComboWndProc
02275  *
02276  * http://www.microsoft.com/msdn/sdk/platforms/doc/sdk/win32/ctrl/src/combobox_15.htm
02277  */
02278 LRESULT WINAPI ComboWndProc( HWND hwnd, UINT message,
02279                              WPARAM wParam, LPARAM lParam )
02280 {
02281 //      dprintf(("ComboWndProc hwnd: %04x, msg %s, wp %08x lp %08lx\n",
02282 //               hwnd, GetMsgText(message), wParam, lParam));
02283 
02284       switch(message)
02285       {
02286 
02287         /* System messages */
02288 
02289         case WM_NCCREATE:
02290           return COMBO_NCCreate(hwnd,wParam,lParam);
02291 
02292         case WM_NCDESTROY:
02293           return COMBO_NCDestroy(hwnd,wParam,lParam);
02294 
02295         case WM_CREATE:
02296           return COMBO_Create(hwnd,wParam,lParam);
02297 
02298         case WM_PRINTCLIENT:
02299           return COMBO_PrintClient(hwnd,wParam,lParam);
02300 
02301         case WM_PAINT:
02302           return COMBO_Paint(hwnd,wParam,lParam);
02303 
02304         case WM_ERASEBKGND:
02305           return COMBO_EraseBackground(hwnd,wParam,lParam);
02306 
02307         case WM_GETDLGCODE:
02308           return COMBO_GetDlgCode(hwnd,wParam,lParam);
02309 
02310         case WM_WINDOWPOSCHANGING:
02311           return COMBO_WindowPosChanging(hwnd,wParam,lParam);
02312 
02313         case WM_SIZE:
02314           return COMBO_Size(hwnd,wParam,lParam);
02315 
02316         case WM_SETFONT:
02317           return COMBO_SetFont(hwnd,wParam,lParam);
02318 
02319         case WM_GETFONT:
02320           return COMBO_GetFont(hwnd,wParam,lParam);
02321 
02322         case WM_SETFOCUS:
02323           return COMBO_SetFocus(hwnd,wParam,lParam);
02324 
02325         case WM_KILLFOCUS:
02326           return COMBO_KillFocus(hwnd,wParam,lParam);
02327 
02328         case WM_COMMAND:
02329           return COMBO_Command(hwnd,wParam,lParam);
02330 
02331         case WM_GETTEXT:
02332           return COMBO_GetText(hwnd,wParam,lParam);
02333 
02334         case WM_GETTEXTLENGTH:
02335           return COMBO_GetTextLength(hwnd,wParam,lParam);
02336 
02337         case WM_SETTEXT:
02338         case WM_CLEAR:
02339         case WM_CUT:
02340         case WM_PASTE:
02341         case WM_COPY:
02342           return COMBO_HandleText(hwnd,message,wParam,lParam);
02343 
02344         case WM_DRAWITEM:
02345         case WM_DELETEITEM:
02346         case WM_COMPAREITEM:
02347         case WM_MEASUREITEM:
02348           return COMBO_HandleItem(hwnd,message,wParam,lParam);
02349 
02350         case WM_ENABLE:
02351           return COMBO_Enable(hwnd,wParam,lParam);
02352 
02353         case WM_SETREDRAW:
02354           return COMBO_SetRedraw(hwnd,wParam,lParam);
02355 
02356         case WM_SYSKEYDOWN:
02357           return COMBO_SysKeyDown(hwnd,wParam,lParam);
02358 
02359         case WM_CHAR:
02360         case WM_KEYDOWN:
02361           return COMBO_HandleKey(hwnd,message,wParam,lParam);
02362 
02363         case WM_LBUTTONDOWN:
02364           return COMBO_LButtonDown(hwnd,wParam,lParam);
02365 
02366         case WM_LBUTTONUP:
02367           return COMBO_LButtonUp(hwnd,wParam,lParam);
02368 
02369         case WM_MOUSEMOVE:
02370           return COMBO_MouseMove(hwnd,wParam,lParam);
02371 
02372         case WM_MOUSEWHEEL:
02373           return COMBO_MouseWheel(hwnd,wParam,lParam);
02374 
02375         /* Combo messages */
02376 
02377         case CB_ADDSTRING:
02378           return COMBO_AddString(hwnd,wParam,lParam);
02379 
02380         case CB_INSERTSTRING:
02381           return COMBO_InsertString(hwnd,wParam,lParam);
02382 
02383         case CB_DELETESTRING:
02384           return COMBO_DeleteString(hwnd,wParam,lParam);
02385 
02386         case CB_SELECTSTRING:
02387           return COMBO_SelectString(hwnd,wParam,lParam);
02388 
02389         case CB_FINDSTRING:
02390           return COMBO_FindString(hwnd,wParam,lParam);
02391 
02392         case CB_FINDSTRINGEXACT:
02393           return COMBO_FindStringExact(hwnd,wParam,lParam);
02394 
02395         case CB_SETITEMHEIGHT:
02396           return COMBO_SetItemHeight(hwnd,wParam,lParam);
02397 
02398         case CB_GETITEMHEIGHT:
02399           return COMBO_GetItemHeight(hwnd,wParam,lParam);
02400 
02401         case CB_RESETCONTENT:
02402           return COMBO_ResetContent(hwnd,wParam,lParam);
02403 
02404         case CB_INITSTORAGE:
02405           return COMBO_InitStorage(hwnd,wParam,lParam);
02406 
02407         case CB_GETHORIZONTALEXTENT:
02408           return COMBO_GetHorizontalExtent(hwnd,wParam,lParam);
02409 
02410         case CB_SETHORIZONTALEXTENT:
02411           return COMBO_SetHorizontalExtent(hwnd,wParam,lParam);
02412 
02413         case CB_GETTOPINDEX:
02414           return COMBO_GetTopIndex(hwnd,wParam,lParam);
02415 
02416         case CB_GETLOCALE:
02417           return COMBO_GetLocale(hwnd,wParam,lParam);
02418 
02419         case CB_SETLOCALE:
02420           return COMBO_SetLocale(hwnd,wParam,lParam);
02421 
02422         case CB_GETDROPPEDWIDTH:
02423           return COMBO_GetDroppedWidth(hwnd,wParam,lParam);
02424 
02425         case CB_SETDROPPEDWIDTH:
02426           return COMBO_SetDroppedWidth(hwnd,wParam,lParam);
02427 
02428         case CB_GETDROPPEDCONTROLRECT:
02429           return COMBO_GetDroppedControlRect(hwnd,wParam,lParam);
02430 
02431         case CB_GETDROPPEDSTATE:
02432           return COMBO_GetDroppedState(hwnd,wParam,lParam);
02433 
02434         case CB_DIR:
02435           return COMBO_Dir(hwnd,wParam,lParam);
02436 
02437         case CB_SHOWDROPDOWN:
02438           return COMBO_ShowDropDown(hwnd,wParam,lParam);
02439 
02440         case CB_GETCOUNT:
02441           return COMBO_GetCount(hwnd,wParam,lParam);
02442 
02443         case CB_GETCURSEL:
02444           return COMBO_GetCurSel(hwnd,wParam,lParam);
02445 
02446         case CB_SETCURSEL:
02447           return COMBO_SetCurSel(hwnd,wParam,lParam);
02448 
02449         case CB_GETLBTEXT:
02450           return COMBO_GetLBText(hwnd,wParam,lParam);
02451 
02452         case CB_GETLBTEXTLEN:
02453           return COMBO_GetLBTextLen(hwnd,wParam,lParam);
02454 
02455         case CB_GETITEMDATA:
02456           return COMBO_GetItemData(hwnd,wParam,lParam);
02457 
02458         case CB_SETITEMDATA:
02459           return COMBO_SetItemData(hwnd,wParam,lParam);
02460 
02461         case CB_GETEDITSEL:
02462           return COMBO_GetEditSel(hwnd,wParam,lParam);
02463 
02464         case CB_SETEDITSEL:
02465           return COMBO_SetEditSel(hwnd,wParam,lParam);
02466 
02467         case CB_SETEXTENDEDUI:
02468           return COMBO_SetExtendedUI(hwnd,wParam,lParam);
02469 
02470         case CB_GETEXTENDEDUI:
02471           return COMBO_GetExtendedUI(hwnd,wParam,lParam);
02472 
02473         //case (WM_USER + 0x1B):
02474         //        WARN("[%04x]: undocumented msg!\n", hwnd );
02475     }
02476     return DefWindowProcA(hwnd, message, wParam, lParam);
02477 }
02478 
02479 BOOL COMBOBOX_Register()
02480 {
02481     WNDCLASSA wndClass;
02482 
02483 //SvL: Don't check this now
02484 //    if (GlobalFindAtomA(COMBOBOXCLASSNAME)) return FALSE;
02485 
02486     ZeroMemory(&wndClass,sizeof(WNDCLASSA));
02487     wndClass.style         = CS_GLOBALCLASS | CS_PARENTDC;
02488     wndClass.lpfnWndProc   = (WNDPROC)ComboWndProc;
02489     wndClass.cbClsExtra    = 0;
02490     wndClass.cbWndExtra    = sizeof(VOID*);
02491     wndClass.hCursor       = LoadCursorA(0,IDC_ARROWA);
02492     wndClass.hbrBackground = (HBRUSH)0;
02493     wndClass.lpszClassName = COMBOBOXCLASSNAME;
02494 
02495     return RegisterClassA(&wndClass);
02496 }
02497 
02498 BOOL COMBOBOX_Unregister()
02499 {
02500     if (GlobalFindAtomA(COMBOBOXCLASSNAME))
02501         return UnregisterClassA(COMBOBOXCLASSNAME,(HINSTANCE)NULL);
02502     else return FALSE;
02503 }
02504 

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