home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / xwphescr.zip / XWPH0208.ZIP / src / helpers / cctl_combo.c < prev    next >
C/C++ Source or Header  |  2002-06-02  |  24KB  |  725 lines

  1.  
  2. /*
  3.  *@@sourcefile cctl_combo.c:
  4.  *      super combo box control, which is, essentially, a
  5.  *      subclassed entry field with a list box attached to
  6.  *      it.
  7.  *
  8.  *      Compared to the standard PM combo box, this one has a
  9.  *      number of advantages:
  10.  *
  11.  *      --  It doesn't require the parent window to have the
  12.  *          WS_CLIPCHILDREN style bit cleared.
  13.  *
  14.  *      --  It has proper window positioning; the size of the
  15.  *          enhanced combo is the size of the entry field, while
  16.  *          the PM combo wants to have the size of the expanded
  17.  *          list box too, which isn't easy to handle.
  18.  *
  19.  *      See ctlComboFromEntryField for details.
  20.  *
  21.  *      Note: Version numbering in this file relates to XWorkplace version
  22.  *            numbering.
  23.  *
  24.  *@@header "helpers\comctl.h"
  25.  *@@added V0.9.16 (2002-01-01) [umoeller]
  26.  */
  27.  
  28. /*
  29.  *      Copyright (C) 2001-2002 Ulrich Möller.
  30.  *      This file is part of the "XWorkplace helpers" source package.
  31.  *      This is free software; you can redistribute it and/or modify
  32.  *      it under the terms of the GNU General Public License as published
  33.  *      by the Free Software Foundation, in version 2 as it comes in the
  34.  *      "COPYING" file of the XWorkplace main distribution.
  35.  *      This program is distributed in the hope that it will be useful,
  36.  *      but WITHOUT ANY WARRANTY; without even the implied warranty of
  37.  *      MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  38.  *      GNU General Public License for more details.
  39.  */
  40.  
  41. #define OS2EMX_PLAIN_CHAR
  42.     // this is needed for "os2emx.h"; if this is defined,
  43.     // emx will define PSZ as _signed_ char, otherwise
  44.     // as unsigned char
  45.  
  46. #define INCL_DOSEXCEPTIONS
  47. #define INCL_DOSPROCESS
  48. #define INCL_DOSSEMAPHORES
  49. #define INCL_DOSERRORS
  50.  
  51. #define INCL_WINWINDOWMGR
  52. #define INCL_WINFRAMEMGR
  53. #define INCL_WININPUT
  54. #define INCL_WINPOINTERS
  55.  
  56. #define INCL_WINBUTTONS
  57. #define INCL_WINENTRYFIELDS
  58. #define INCL_WINLISTBOXES
  59.  
  60. #define INCL_GPILOGCOLORTABLE
  61. #define INCL_GPIBITMAPS
  62. #include <os2.h>
  63.  
  64. #include <stdlib.h>
  65. #include <stdio.h>
  66. #include <string.h>
  67. #include <setjmp.h>             // needed for except.h
  68. #include <assert.h>             // needed for except.h
  69.  
  70. #include "setup.h"                      // code generation and debugging options
  71.  
  72. #include "helpers\except.h"             // exception handling
  73. #include "helpers\winh.h"
  74.  
  75. #include "helpers\comctl.h"
  76.  
  77. #pragma hdrstop
  78.  
  79. /*
  80.  *@@category: Helpers\PM helpers\Window classes\Super combo box
  81.  *      See cctl_combo.c.
  82.  */
  83.  
  84. /* ******************************************************************
  85.  *
  86.  *   Super Combination Box control
  87.  *
  88.  ********************************************************************/
  89.  
  90. #define COMBO_BUTTON_WIDTH      20
  91.  
  92. #define ID_COMBO_BUTTON         1001
  93. #define ID_COMBO_LISTBOX        1002
  94.  
  95. /*
  96.  *@@ COMBODATA:
  97.  *
  98.  *@@added V0.9.9 (2001-03-17) [umoeller]
  99.  */
  100.  
  101. typedef struct _COMBODATA
  102. {
  103.     PFNWP       pfnwpOrigEntryField,
  104.                 pfnwpOrigButton;
  105.     ULONG       flStyle;
  106.  
  107.     // position of entire combo
  108.     LONG        x,
  109.                 y,
  110.                 cx,
  111.                 cy;
  112.  
  113.     HWND        hwndButton,
  114.                 hwndListbox;
  115.  
  116.     HBITMAP     hbmButton;
  117.     SIZEL       szlButton;          // bitmap dimensions
  118.  
  119. } COMBODATA, *PCOMBODATA;
  120.  
  121. /*
  122.  *@@ PaintButtonBitmap:
  123.  *
  124.  *@@added V0.9.9 (2001-03-17) [umoeller]
  125.  */
  126.  
  127. static VOID PaintButtonBitmap(HWND hwnd,
  128.                               PCOMBODATA pcd)
  129. {
  130.     HPS hps;
  131.     RECTL rcl;
  132.     POINTL ptlDest;
  133.  
  134.     hps = WinGetPS(hwnd);
  135.     WinQueryWindowRect(hwnd, &rcl);
  136.  
  137.     ptlDest.x = (rcl.xRight - pcd->szlButton.cx) / 2;
  138.     ptlDest.y = (rcl.yTop - pcd->szlButton.cy) / 2;
  139.     WinDrawBitmap(hps,
  140.                   pcd->hbmButton,
  141.                   NULL,
  142.                   &ptlDest,
  143.                   0, 0,
  144.                   DBM_NORMAL);
  145.  
  146.     WinReleasePS(hps);
  147. }
  148.  
  149. /*
  150.  *@@ fnwpSubclassedComboButton:
  151.  *      window proc the combobox's button is subclassed with.
  152.  *      This is only for WM_PAINT because BN_PAINT is really
  153.  *      not that great for painting a button that looks like
  154.  *      a standard button.
  155.  *
  156.  *@@added V0.9.9 (2001-03-17) [umoeller]
  157.  */
  158.  
  159. static MRESULT EXPENTRY fnwpSubclassedComboButton(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  160. {
  161.     MRESULT mrc = 0;
  162.     PCOMBODATA pcd;
  163.  
  164.     switch (msg)
  165.     {
  166.         case WM_PAINT:
  167.             if (pcd = (PCOMBODATA)WinQueryWindowPtr(hwnd, QWL_USER))
  168.             {
  169.                 mrc = pcd->pfnwpOrigButton(hwnd, msg, mp1, mp2);
  170.  
  171.                 PaintButtonBitmap(hwnd, pcd);
  172.             }
  173.         break;
  174.  
  175.         /*
  176.          * default:
  177.          *
  178.          */
  179.  
  180.         default:
  181.             if (pcd = (PCOMBODATA)WinQueryWindowPtr(hwnd, QWL_USER))
  182.                 mrc = pcd->pfnwpOrigButton(hwnd, msg, mp1, mp2);
  183.         break;
  184.     }
  185.  
  186.     return mrc;
  187. }
  188.  
  189. /*
  190.  *@@ ShowListbox:
  191.  *
  192.  *@@added V0.9.9 (2001-03-17) [umoeller]
  193.  */
  194.  
  195. static VOID ShowListbox(HWND hwnd,      // in: subclassed entry field
  196.                         PCOMBODATA pcd,
  197.                         BOOL fShow)    // in: TRUE == show, FALSE == hide
  198. {
  199.     BOOL fHilite = FALSE;
  200.  
  201.     if (fShow)
  202.     {
  203.         // list box is invisible:
  204.         SWP swp;
  205.         POINTL ptl;
  206.         WinQueryWindowPos(hwnd, &swp);
  207.  
  208.         _Pmpf(("showing lb"));
  209.  
  210.         // convert to desktop
  211.         ptl.x = swp.x;
  212.         ptl.y = swp.y;
  213.         WinMapWindowPoints(WinQueryWindow(hwnd, QW_PARENT), // from
  214.                            HWND_DESKTOP,    // to
  215.                            &ptl,
  216.                                 // SWP.y comes before SWP.x
  217.                            1);
  218.  
  219.         WinSetWindowPos(pcd->hwndListbox,
  220.                         HWND_TOP,
  221.                         ptl.x + COMBO_BUTTON_WIDTH,
  222.                         ptl.y - 100,
  223.                         swp.cx,
  224.                         100,
  225.                         SWP_MOVE | SWP_SIZE | SWP_ZORDER | SWP_NOREDRAW);
  226.         WinSetParent(pcd->hwndListbox,
  227.                      HWND_DESKTOP,
  228.                      TRUE);        // redraw
  229.  
  230.         // set focus to subclassed entry field in any case;
  231.         // we never let the listbox get the focus
  232.         WinSetFocus(HWND_DESKTOP, hwnd);
  233.  
  234.         fHilite = TRUE;
  235.     }
  236.     else
  237.     {
  238.         // list box is showing:
  239.         HWND hwndFocus = WinQueryFocus(HWND_DESKTOP);
  240.         _Pmpf(("hiding listbox"));
  241.  
  242.         WinSetParent(pcd->hwndListbox,
  243.                      HWND_OBJECT,
  244.                      TRUE);         // redraw now
  245.         // give focus back to entry field
  246.         if (hwndFocus == pcd->hwndListbox)
  247.             WinSetFocus(HWND_DESKTOP, hwnd);
  248.     }
  249.  
  250.     WinSendMsg(pcd->hwndButton,
  251.                BM_SETHILITE,
  252.                (MPARAM)fHilite,
  253.                0);
  254.     PaintButtonBitmap(pcd->hwndButton, pcd);
  255. }
  256.  
  257. /*
  258.  *@@ fnwpComboSubclass:
  259.  *
  260.  *@@added V0.9.9 (2001-03-17) [umoeller]
  261.  */
  262.  
  263. static MRESULT EXPENTRY fnwpComboSubclass(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2)
  264. {
  265.     MRESULT     mrc = 0;
  266.     PCOMBODATA  pcd;
  267.  
  268.     switch (msg)
  269.     {
  270.         /*
  271.          * WM_ADJUSTWINDOWPOS:
  272.          *
  273.          */
  274.  
  275.         case WM_ADJUSTWINDOWPOS:
  276.             if (pcd = (PCOMBODATA)WinQueryWindowPtr(hwnd, QWL_USER))
  277.             {
  278.                 PSWP pswp = (PSWP)mp1;
  279.  
  280.                 if (pswp->fl & SWP_SIZE)
  281.                     // if we're being sized, make us smaller so that
  282.                     // there's room for the button
  283.                     pswp->cx -= COMBO_BUTTON_WIDTH;
  284.  
  285.                 mrc = pcd->pfnwpOrigEntryField(hwnd, msg, mp1, mp2);
  286.             }
  287.         break;
  288.  
  289.         /*
  290.          * WM_WINDOWPOSCHANGED:
  291.          *
  292.          */
  293.  
  294.         case WM_WINDOWPOSCHANGED:
  295.             if (pcd = (PCOMBODATA)WinQueryWindowPtr(hwnd, QWL_USER))
  296.             {
  297.                 PSWP pswpNew = (PSWP)mp1;
  298.  
  299.                 if (pswpNew->fl & (SWP_SIZE | SWP_MOVE))
  300.                 {
  301.                     // moved or sized:
  302.                     SWP swp;
  303.                     WinQueryWindowPos(hwnd, &swp);
  304.                     WinSetWindowPos(pcd->hwndButton,
  305.                                     0,
  306.                                     pswpNew->x + pswpNew->cx, // has already been truncated!
  307.                                     pswpNew->y,
  308.                                     COMBO_BUTTON_WIDTH,
  309.                                     pswpNew->cy,
  310.                                     SWP_MOVE | SWP_SIZE);
  311.                 }
  312.  
  313.                 mrc = pcd->pfnwpOrigEntryField(hwnd, msg, mp1, mp2);
  314.             }
  315.         break;
  316.  
  317.         /*
  318.          * WM_SETFOCUS:
  319.          *      hide listbox if focus is going away from us
  320.          */
  321.  
  322.         case WM_SETFOCUS:
  323.             if (pcd = (PCOMBODATA)WinQueryWindowPtr(hwnd, QWL_USER))
  324.             {
  325.                 if (!mp2)
  326.                     // we're losing focus:
  327.                     // is listbox currently showing?
  328.                     ShowListbox(hwnd,
  329.                                 pcd,
  330.                                 FALSE);
  331.  
  332.                 mrc = pcd->pfnwpOrigEntryField(hwnd, msg, mp1, mp2);
  333.             }
  334.         break;
  335.  
  336.         /*
  337.          * WM_COMMAND:
  338.          *      show/hide listbox if the button gets pressed.
  339.          */
  340.  
  341.         case WM_COMMAND:
  342.             if (pcd = (PCOMBODATA)WinQueryWindowPtr(hwnd, QWL_USER))
  343.             {
  344.                 if (SHORT1FROMMP(mp1) == ID_COMBO_BUTTON)
  345.                 {
  346.                     // button clicked:
  347.                     ShowListbox(hwnd,
  348.                                 pcd,
  349.                                 // check state of list box
  350.                                 (WinQueryWindow(pcd->hwndListbox, QW_PARENT)
  351.                                  == WinQueryObjectWindow(HWND_DESKTOP)));
  352.  
  353.                     // do not call parent
  354.                     break;
  355.  
  356.                 } // end if ((SHORT)mp1 == ID_COMBO_BUTTON)
  357.  
  358.                 mrc = pcd->pfnwpOrigEntryField(hwnd, msg, mp1, mp2);
  359.             }
  360.         break;
  361.  
  362.         /*
  363.          * WM_CONTROL:
  364.          *      handle notifications from listbox.
  365.          */
  366.  
  367.         case WM_CONTROL:
  368.             if (pcd = (PCOMBODATA)WinQueryWindowPtr(hwnd, QWL_USER))
  369.             {
  370.                 USHORT usid = SHORT1FROMMP(mp1),
  371.                        uscode = SHORT2FROMMP(mp1);
  372.                 if (usid == ID_COMBO_LISTBOX)
  373.                 {
  374.                     switch (uscode)
  375.                     {
  376.                         case LN_ENTER:
  377.                         break;
  378.  
  379.                         case LN_SELECT:
  380.                         {
  381.                             SHORT sSelected = winhQueryLboxSelectedItem(pcd->hwndListbox,
  382.                                                                         LIT_FIRST);
  383.                             PSZ psz = NULL;
  384.                             if (sSelected != LIT_NONE)
  385.                             {
  386.                                 psz = winhQueryLboxItemText(pcd->hwndListbox,
  387.                                                             sSelected);
  388.                             }
  389.                             WinSetWindowText(hwnd, psz);
  390.                             if (psz)
  391.                             {
  392.                                 WinPostMsg(hwnd,
  393.                                            EM_SETSEL,
  394.                                            MPFROM2SHORT(0, strlen(psz)),
  395.                                            0);
  396.                                 free(psz);
  397.                             }
  398.                         break; }
  399.  
  400.                         case LN_SETFOCUS:
  401.                             // when the list box gets the focus, always
  402.                             // set focus to ourselves
  403.                             WinSetFocus(HWND_DESKTOP, hwnd);
  404.                         break;
  405.                     }
  406.  
  407.                     // forward list box notifications to
  408.                     // our own owner, but replace the id
  409.                     // with the combo box id
  410.                     WinPostMsg(WinQueryWindow(hwnd, QW_OWNER),
  411.                                WM_CONTROL,
  412.                                MPFROM2SHORT(WinQueryWindowUShort(hwnd, QWS_ID),
  413.                                             uscode),
  414.                                mp2);
  415.  
  416.                     // do not call parent
  417.                     break;
  418.  
  419.                 } // end if (usid == ID_COMBO_LISTBOX)
  420.  
  421.                 mrc = pcd->pfnwpOrigEntryField(hwnd, msg, mp1, mp2);
  422.             }
  423.         break;
  424.  
  425.         /*
  426.          * WM_CHAR:
  427.          *
  428.          */
  429.  
  430.         case WM_CHAR:
  431.             if (pcd = (PCOMBODATA)WinQueryWindowPtr(hwnd, QWL_USER))
  432.             {
  433.                 USHORT usFlags    = SHORT1FROMMP(mp1);
  434.                 // USHORT usch       = SHORT1FROMMP(mp2);
  435.                 USHORT usvk       = SHORT2FROMMP(mp2);
  436.  
  437.                 if ((usFlags & KC_KEYUP) == 0)
  438.                 {
  439.                     if (usFlags & KC_VIRTUALKEY)
  440.                     {
  441.                         switch (usvk)
  442.                         {
  443.                             case VK_DOWN:
  444.                             case VK_UP:
  445.                                 // if alt is pressed with these, show/hide listbox
  446.                                 if (usFlags & KC_ALT)
  447.                                     WinPostMsg(hwnd,
  448.                                                CBM_SHOWLIST,
  449.                                                (MPARAM)(WinQueryWindow(pcd->hwndListbox, QW_PARENT)
  450.                                                         == WinQueryObjectWindow(HWND_DESKTOP)),
  451.                                                0);
  452.                                 else
  453.                                 {
  454.                                     // just up or down, no alt:
  455.                                     // select next or previous item in list box
  456.                                     SHORT sSelected = winhQueryLboxSelectedItem(pcd->hwndListbox,
  457.                                                                                 LIT_FIRST),
  458.                                           sNew = 0;
  459.  
  460.                                     if (usvk == VK_DOWN)
  461.                                     {
  462.                                         if (sSelected != LIT_NONE)
  463.                                         {
  464.                                             if (sSelected < WinQueryLboxCount(pcd->hwndListbox))
  465.                                                 sNew = sSelected + 1;
  466.                                         }
  467.                                         // else: sNew still 0
  468.                                     }
  469.                                     else
  470.                                     {
  471.                                         // up:
  472.                                         if (    (sSelected != LIT_NONE)
  473.                                              && (sSelected > 0)
  474.                                            )
  475.                                             sNew = sSelected - 1;
  476.                                     }
  477.  
  478.                                     winhSetLboxSelectedItem(pcd->hwndListbox,
  479.                                                             sNew,
  480.                                                             TRUE);
  481.                                 }
  482.                             break;
  483.                         }
  484.                     }
  485.                 }
  486.  
  487.                 // call parent only if this is not a drop-down list
  488.                 if ((pcd->flStyle & CBS_DROPDOWNLIST) == 0)
  489.                     mrc = pcd->pfnwpOrigEntryField(hwnd, msg, mp1, mp2);
  490.                 else
  491.                     // forward to owner
  492.                     WinSendMsg(WinQueryWindow(hwnd, QW_OWNER),
  493.                                msg,
  494.                                mp1,
  495.                                mp2);
  496.             }
  497.         break;
  498.  
  499.         /*
  500.          * CBM_ISLISTSHOWING:
  501.          *      implementation of the original combobox msg.
  502.          */
  503.  
  504.         case CBM_ISLISTSHOWING:
  505.             if (pcd = (PCOMBODATA)WinQueryWindowPtr(hwnd, QWL_USER))
  506.             {
  507.                 mrc = (MPARAM)(WinQueryWindow(pcd->hwndListbox, QW_PARENT)
  508.                                      == WinQueryObjectWindow(HWND_DESKTOP));
  509.             }
  510.         break;
  511.  
  512.         /*
  513.          * CBM_SHOWLIST:
  514.          *      implementation of the original combobox msg.
  515.          */
  516.  
  517.         case CBM_SHOWLIST:
  518.             if (pcd = (PCOMBODATA)WinQueryWindowPtr(hwnd, QWL_USER))
  519.             {
  520.                 ShowListbox(hwnd,
  521.                             pcd,
  522.                             (BOOL)mp1);
  523.             }
  524.         break;
  525.  
  526.         /*
  527.          * list box messages:
  528.          *      forward all these to the listbox and
  529.          *      return the listbox return value.
  530.          */
  531.  
  532.         case LM_INSERTITEM:
  533.         case LM_SETTOPINDEX:
  534.         case LM_QUERYTOPINDEX:
  535.         case LM_DELETEITEM:
  536.         case LM_SELECTITEM:
  537.         case LM_QUERYSELECTION:
  538.         case LM_SETITEMTEXT:
  539.         case LM_QUERYITEMTEXT:
  540.         case LM_SEARCHSTRING:
  541.         case LM_DELETEALL:
  542.             if (pcd = (PCOMBODATA)WinQueryWindowPtr(hwnd, QWL_USER))
  543.                 mrc = WinSendMsg(pcd->hwndListbox, msg, mp1, mp2);
  544.         break;
  545.  
  546.         /*
  547.          * WM_DESTROY:
  548.          *
  549.          */
  550.  
  551.         case WM_DESTROY:
  552.             if (pcd = (PCOMBODATA)WinQueryWindowPtr(hwnd, QWL_USER))
  553.             {
  554.                 WinDestroyWindow(pcd->hwndButton);
  555.                 WinDestroyWindow(pcd->hwndListbox);
  556.  
  557.                 mrc = pcd->pfnwpOrigEntryField(hwnd, msg, mp1, mp2);
  558.  
  559.                 free(pcd);
  560.             }
  561.         break;
  562.  
  563.         /*
  564.          * default:
  565.          *
  566.          */
  567.  
  568.         default:
  569.             if (pcd = (PCOMBODATA)WinQueryWindowPtr(hwnd, QWL_USER))
  570.                 mrc = pcd->pfnwpOrigEntryField(hwnd, msg, mp1, mp2);
  571.         break;
  572.     }
  573.  
  574.     return mrc;
  575. }
  576.  
  577. /*
  578.  *@@ ctlComboFromEntryField:
  579.  *      turns a standard entry field control into an
  580.  *      XComboBox.
  581.  *
  582.  *      The XComboBox is intended to work like a standard
  583.  *      combobox, but it doesn't have the silly limitation
  584.  *      that the size of the combobox is assumed to be
  585.  *      the size of the dropped-down combobox. This limitation
  586.  *      makes it impossible to use standard comboboxes in
  587.  *      windows which have the WS_CLIPCHILDREN style because
  588.  *      the entire combo area will always be clipped out.
  589.  *
  590.  *      This is not a full reimplementation. Only drop-down
  591.  *      and drop-down list comboboxes are supported. Besides,
  592.  *      the XComboBox is essentially a subclassed entryfield,
  593.  *      so there might be limitations.
  594.  *
  595.  *      On input to this function, with flStyle, specify
  596.  *      either CBS_DROPDOWN or CBS_DROPDOWNLIST. CBS_SIMPLE
  597.  *      is not supported.
  598.  *
  599.  *      Supported messages to the XComboBox after this funcion
  600.  *      has been called:
  601.  *
  602.  *      -- CBM_ISLISTSHOWING
  603.  *
  604.  *      -- CBM_SHOWLIST
  605.  *
  606.  *      -- LM_QUERYITEMCOUNT
  607.  *
  608.  *      -- LM_INSERTITEM
  609.  *
  610.  *      -- LM_SETTOPINDEX
  611.  *
  612.  *      -- LM_QUERYTOPINDEX
  613.  *
  614.  *      -- LM_DELETEITEM
  615.  *
  616.  *      -- LM_SELECTITEM
  617.  *
  618.  *      -- LM_QUERYSELECTION
  619.  *
  620.  *      -- LM_SETITEMTEXT
  621.  *
  622.  *      -- LM_QUERYITEMTEXT
  623.  *
  624.  *      -- LM_SEARCHSTRING
  625.  *
  626.  *      -- LM_DELETEALL
  627.  *
  628.  *      NOTE: This occupies QWL_USER of the entryfield.
  629.  *
  630.  *@@added V0.9.9 (2001-03-17) [umoeller]
  631.  */
  632.  
  633. BOOL ctlComboFromEntryField(HWND hwnd,          // in: entry field to be converted
  634.                             ULONG flStyle)      // in: combo box styles
  635. {
  636.     BOOL brc = FALSE;
  637.     PFNWP pfnwpOrig;
  638.     if (pfnwpOrig = WinSubclassWindow(hwnd,
  639.                                       fnwpComboSubclass))
  640.     {
  641.         PCOMBODATA pcd;
  642.         if (pcd = (PCOMBODATA)malloc(sizeof(*pcd)))
  643.         {
  644.             SWP swp;
  645.             BITMAPINFOHEADER2 bmih2;
  646.  
  647.             memset(pcd, 0, sizeof(*pcd));
  648.             pcd->pfnwpOrigEntryField = pfnwpOrig;
  649.             pcd->flStyle = flStyle;
  650.  
  651.             WinSetWindowPtr(hwnd, QWL_USER, pcd);
  652.  
  653.             WinQueryWindowPos(hwnd, &swp);
  654.             pcd->x = swp.x;
  655.             pcd->y = swp.y;
  656.             pcd->cx = swp.cx;
  657.             pcd->cy = swp.cy;
  658.  
  659.             swp.cx -= COMBO_BUTTON_WIDTH;
  660.             WinSetWindowPos(hwnd,
  661.                             0,
  662.                             0, 0,
  663.                             swp.cx, swp.cy,
  664.                             SWP_SIZE | SWP_NOADJUST);       // circumvent subclassing
  665.  
  666.             pcd->hbmButton = WinGetSysBitmap(HWND_DESKTOP,
  667.                                              SBMP_COMBODOWN);
  668.             bmih2.cbFix = sizeof(bmih2);
  669.             GpiQueryBitmapInfoHeader(pcd->hbmButton,
  670.                                      &bmih2);
  671.             pcd->szlButton.cx = bmih2.cx;
  672.             pcd->szlButton.cy = bmih2.cy;
  673.  
  674.             pcd->hwndButton = WinCreateWindow(WinQueryWindow(hwnd, QW_PARENT),
  675.                                               WC_BUTTON,
  676.                                               "",
  677.                                               WS_VISIBLE
  678.                                                 | BS_PUSHBUTTON | BS_NOPOINTERFOCUS,
  679.                                               swp.x + swp.cx - COMBO_BUTTON_WIDTH,
  680.                                               swp.y,
  681.                                               COMBO_BUTTON_WIDTH,
  682.                                               swp.cy,
  683.                                               hwnd,     // owner == entry field!
  684.                                               hwnd,     // insert behind entry field
  685.                                               ID_COMBO_BUTTON,
  686.                                               NULL,
  687.                                               NULL);
  688.             WinSetWindowPtr(pcd->hwndButton, QWL_USER, pcd);
  689.             pcd->pfnwpOrigButton = WinSubclassWindow(pcd->hwndButton,
  690.                                                      fnwpSubclassedComboButton);
  691.  
  692.             pcd->hwndListbox = WinCreateWindow(HWND_OBJECT,      // parent, for now
  693.                                                WC_LISTBOX,
  694.                                                "?",
  695.                                                WS_VISIBLE | WS_SAVEBITS | WS_CLIPSIBLINGS
  696.                                                  | LS_NOADJUSTPOS,
  697.                                                0,
  698.                                                0,
  699.                                                0,
  700.                                                0,
  701.                                                hwnd,     // owner == entry field!
  702.                                                HWND_TOP,     // insert behind entry field
  703.                                                ID_COMBO_LISTBOX,
  704.                                                NULL,
  705.                                                NULL);
  706.  
  707.             // finally, set style of entry field... we force
  708.             // these flags no matter what the original style
  709.             // was
  710.             /* WinSetWindowBits(hwnd,
  711.                              QWL_STYLE,
  712.                              // bits to set:
  713.                             (flStyle & CBS_DROPDOWNLIST)
  714.                                 ? ES_READONLY
  715.                                 : 0,
  716.                              // mask:
  717.                              ES_READONLY); */
  718.         }
  719.     }
  720.  
  721.     return brc;
  722. }
  723.  
  724.  
  725.