home *** CD-ROM | disk | FTP | other *** search
/ Liren Large Software Subsidy 7 / 07.iso / c / c082_122 / 5.ddi / RWCDEMO.ZIP / BITBTN.C < prev    next >
Encoding:
C/C++ Source or Header  |  1992-06-10  |  22.6 KB  |  813 lines

  1. // (C) Copyright 1991, 1992 by Borland International
  2.  
  3. #define STRICT
  4.  
  5. #include <windows.h>
  6. #include <custcntl.h>
  7. #include "bitbtnco.h"
  8.  
  9. // "local" variable offsets into the window structure
  10. #define OF_RESERVED        0        // Used by the dialog manager
  11. #define OF_STATE        2
  12. #define OF_DOWNBITS        4
  13. #define OF_UPBITS        6
  14. #define OF_FOCUPBITS            8
  15. #define OF_SIZE            10
  16.  
  17. // Width of the line bordering the bitmap of the button
  18. #define BD_BORDERWIDTH    1
  19.  
  20. // State masks for the state of the button
  21. #define BS_DISABLED        0x0001
  22. #define BS_FOCUS        0x0002
  23. #define BS_KEYDOWN        0x0004
  24. #define BS_MOUSEDOWN    0x0008
  25. #define BS_MOUSEUPDOWN    0x0010
  26. #define BS_DEFAULT        0x0020
  27.  
  28. // Color definitions
  29. #define CO_GRAY            0x00C0C0C0L
  30.  
  31. static HINSTANCE hInstance;
  32.  
  33. /* GetAppInstance ----------------------------------------------- *
  34.  *     Returns a handle to the current client application.      *
  35.  * -------------------------------------------------------------- */
  36. HINSTANCE GetAppInstance(void)
  37. {
  38.   return (HINSTANCE) GlobalHandle(_SS);
  39. }
  40.  
  41. /* IsWorkshopWindow --------------------------------------------- *
  42.  *    Returns true if the window belongs to Resource Workshop.      *
  43.  *    Used to determine if the control is being edited; allowing    *
  44.  *    the LoadResRW function to be called.                          *
  45.  * -------------------------------------------------------------- */
  46. static BOOL IsWorkshopWindow(HWND hWnd)
  47. {
  48.     HWND    hParent;
  49.     char    szClassName[81];
  50.  
  51.     hParent = hWnd;
  52.     do
  53.     {
  54.         hWnd = hParent;
  55.         hParent = GetParent(hWnd);
  56.     }
  57.     while ( hParent );
  58.     GetClassName(hWnd, szClassName, sizeof(szClassName));
  59.     return ( lstrcmpi(szClassName, "rwswnd") == 0);
  60. }
  61.  
  62. /* LoadResRW ---------------------------------------------------- *
  63.  *   Load a resource from Resource Workshop. Initialized by       *
  64.  *   ListClasses below.                                           *
  65.  * -------------------------------------------------------------- */
  66. static LPFNLOADRES LoadResRW;
  67.  
  68. /* GetDInColors ------------------------------------------------- *
  69.  *   Return the number of colors in the given number of bits.      *
  70.  * -------------------------------------------------------------- */
  71. static int GetDInColors(int BitCount)
  72. {
  73.     switch( BitCount )
  74.     {
  75.         case 1:
  76.         case 3:
  77.         case 4:
  78.         case 8:
  79.             return    1 << BitCount;
  80.         default:
  81.             return     0;
  82.     }
  83. }
  84.  
  85. /* LoadBitmapRW ------------------------------------------------- *
  86.  *   Load a bitmap from Resource Workshop.  *MUST* be called from *
  87.  *   inside resource workshop (IsWorkshopWindow must be true).    *
  88.  * -------------------------------------------------------------- */
  89. static HBITMAP LoadBitmapRW(LPSTR szTitle)
  90. {
  91.     HBITMAP hRet = NULL;
  92.         HGLOBAL  hRes = LoadResRW((LPCSTR)RT_BITMAP, (LPCSTR)szTitle);
  93.  
  94.     if ( hRes )
  95.     {
  96.         LPBITMAPINFOHEADER pBits = (LPBITMAPINFOHEADER) GlobalLock(hRes);
  97.  
  98.                 // only Windows format bitmaps
  99.  
  100.         if ( pBits->biSize == sizeof(BITMAPINFOHEADER) )
  101.         {
  102.             int nColors = GetDInColors(pBits->biBitCount);
  103.             HDC hDC = GetDC(NULL);
  104.  
  105.                         // number of colors can be less than returned above
  106.  
  107.                         if ( pBits->biClrUsed)
  108.                           nColors = (int)pBits->biClrUsed;
  109.  
  110.             if ( hDC )
  111.             {
  112.                 hRet = CreateDIBitmap(hDC, pBits, CBM_INIT,
  113.                     ((LPSTR) (pBits + 1)) + (nColors * sizeof(RGBQUAD)),
  114.                     (LPBITMAPINFO) pBits, DIB_RGB_COLORS);
  115.                 ReleaseDC(NULL, hDC);
  116.             }
  117.             GlobalUnlock(hRes);
  118.             GlobalFree(hRes);
  119.         }
  120.     }
  121.  
  122.     return hRet;
  123. }
  124.  
  125. /* Get, SetWord, State, DownBits, UpBits, FocBits, GetState ----- *
  126.  *   Utility macros to implement pseudo button local variables.      *
  127.  * -------------------------------------------------------------- */
  128. #define Get(Ofs)                GetWindowWord(hWnd, Ofs)
  129. #define SetWord(Ofs, Val)        SetWindowWord(hWnd, Ofs, Val)
  130. #define State                    Get(OF_STATE)
  131. #define DownBits                Get(OF_DOWNBITS)
  132. #define UpBits                    Get(OF_UPBITS)
  133. #define FocUpBits                Get(OF_FOCUPBITS)
  134. #define GetState(AState)        ((State & (AState)) == (AState))
  135.  
  136. /* Paint -------------------------------------------------------- *
  137.  *    Paint the button.  Called in response to a WM_PAINT message   *
  138.  *    and whenever the button changes state (called by Repaint).    *
  139.  * -------------------------------------------------------------- */
  140. static void Paint(HWND hWnd, HDC hDC)
  141. {
  142.     HBITMAP hBits;
  143.  
  144.     // Get the appropriate bitmap for the button state
  145.     if ( (State & (BS_MOUSEDOWN | BS_KEYDOWN)) && !GetState(BS_MOUSEUPDOWN) )
  146.                 hBits = (HBITMAP)DownBits;
  147.     else
  148.         if ( GetState(BS_FOCUS) )
  149.                         hBits = (HBITMAP)FocUpBits;
  150.         else
  151.                         hBits = (HBITMAP)UpBits;
  152.  
  153.     // Draw the button border
  154.     {
  155.         RECT    Frame;
  156.         int        Height, Width;
  157.         HBRUSH    hBorderBrush, hOldBrush;
  158.  
  159.         // Get window extent
  160.         GetClientRect(hWnd, &Frame);
  161.         Height = Frame.bottom - Frame.top;
  162.         Width = Frame.right - Frame.left;
  163.  
  164.         // Select brush
  165.         if ( GetState(BS_DEFAULT) )
  166.             hBorderBrush = GetStockObject(BLACK_BRUSH);
  167.         else
  168.             hBorderBrush = GetStockObject(WHITE_BRUSH);
  169.         hOldBrush = SelectObject(hDC, hBorderBrush);
  170.  
  171.         // Blt the brush
  172.         PatBlt(hDC, Frame.left, Frame.top, Width, BD_BORDERWIDTH, PATCOPY);
  173.         PatBlt(hDC, Frame.left, Frame.top, BD_BORDERWIDTH, Height, PATCOPY);
  174.         PatBlt(hDC, Frame.left, Frame.bottom - BD_BORDERWIDTH, Width,
  175.             BD_BORDERWIDTH, PATCOPY);
  176.         PatBlt(hDC, Frame.right - BD_BORDERWIDTH, Frame.top, BD_BORDERWIDTH,
  177.             Height, PATCOPY);
  178.  
  179.         // Clean up scope
  180.         SelectObject(hDC, hOldBrush);
  181.     }
  182.  
  183.     // Draw the bitmap
  184.     {
  185.                 HDC     hMemDC          =       CreateCompatibleDC(hDC);
  186.         HBITMAP    hOldBitmap    =    SelectObject(hMemDC, hBits);
  187.         BITMAP    Bitmap;
  188.  
  189.         // Blt the image
  190.         GetObject(hBits, sizeof(Bitmap), (LPSTR) &Bitmap);
  191.         if ( GetState(BS_DISABLED) )
  192.         {
  193.             // Blt disabled
  194.             HBITMAP hOldBrush = SelectObject(hDC, CreateSolidBrush(CO_GRAY));
  195.             LOGBRUSH lbLogBrush;
  196.  
  197.             PatBlt(hDC, BD_BORDERWIDTH, BD_BORDERWIDTH, Bitmap.bmWidth,
  198.                 Bitmap.bmHeight, PATCOPY);
  199.             DeleteObject(SelectObject(hDC, hOldBrush));
  200.  
  201.             lbLogBrush.lbStyle = BS_PATTERN;
  202.                         lbLogBrush.lbHatch = (int)LoadBitmap(hInstance,
  203.                 MAKEINTRESOURCE(BT_DISABLEBITS));;
  204.             hOldBrush = SelectObject(hDC, CreateBrushIndirect(&lbLogBrush));
  205.  
  206.             BitBlt(hDC, BD_BORDERWIDTH, BD_BORDERWIDTH, Bitmap.bmWidth,
  207.               Bitmap.bmHeight, hMemDC, 0, 0, 0x00A803A9UL); // DPSoa
  208.             DeleteObject(SelectObject(hDC, hOldBrush));
  209.                         DeleteObject((HGDIOBJ)lbLogBrush.lbHatch);
  210.         }
  211.         else
  212.             // Blt enabled
  213.             BitBlt(hDC, BD_BORDERWIDTH, BD_BORDERWIDTH, Bitmap.bmWidth,
  214.                 Bitmap.bmHeight, hMemDC, 0, 0, SRCCOPY);
  215.  
  216.         // Clean up
  217.         SelectObject(hDC, hOldBitmap);
  218.         DeleteDC(hMemDC);
  219.     }
  220. }
  221.  
  222. /* Repaint ------------------------------------------------------ *
  223.  *   Repaint the button. Called whenever the button changes       *
  224.  *   state.                                                       *
  225.  * -------------------------------------------------------------- */
  226. static void Repaint(HWND hWnd)
  227. {
  228.     HDC        hDC        =     GetDC(hWnd);
  229.  
  230.     Paint(hWnd, hDC);
  231.     ReleaseDC(hWnd, hDC);
  232. }
  233.  
  234. /* SetState ----------------------------------------------------- *
  235.  *   Sets the value of a state bit.  If the word changes value    *
  236.  *   the button is repainted.                                     *
  237.  * -------------------------------------------------------------- */
  238. // Make it look like GetState
  239. #define SetState(AState, Enable) Set_State(hWnd, AState, Enable)
  240.  
  241. static void Set_State(HWND hWnd, int AState, BOOL Enable)
  242. {
  243.     WORD    OldState    =     State;
  244.     WORD    NewState    =    Enable ? OldState | AState : OldState & ~AState;
  245.  
  246.     if (NewState != OldState)
  247.     {
  248.         SetWord(OF_STATE, NewState);
  249.         Repaint(hWnd);
  250.     }
  251. }
  252.  
  253. /* InMe --------------------------------------------------------- *
  254.  *    Returns true if the given point is within the border of       *
  255.  *    the button.                                                   *
  256.  * -------------------------------------------------------------- */
  257. static BOOL InMe(HWND hWnd, POINT Point)
  258. {
  259.     RECT    R;
  260.  
  261.     GetClientRect(hWnd, &R);
  262.     InflateRect(&R, -BD_BORDERWIDTH, -BD_BORDERWIDTH);
  263.     return PtInRect(&R, Point);
  264. }
  265.  
  266. /* ButtonPressed ------------------------------------------------ *
  267.  *    Called when the button is pressed by either the keyboard or   *
  268.  *    by the mouse.                                                 *
  269.  * -------------------------------------------------------------- */
  270. static void ButtonPressed(HWND hWnd)
  271. {
  272.     SetState(BS_MOUSEDOWN | BS_MOUSEUPDOWN | BS_KEYDOWN, FALSE);
  273.     SendMessage(GetParent(hWnd), WM_COMMAND, (WPARAM) GetDlgCtrlID(hWnd),
  274.       (LPARAM) MAKELONG(hWnd, BN_CLICKED));
  275. }
  276.  
  277. /* LoadBits ----------------------------------------------------- *
  278.  *     Load the bitmap for the button or the "NO BITMAP" version    *
  279.  *     if it does not exist.                                        *
  280.  * -------------------------------------------------------------- */
  281. static void LoadBits(HWND hWnd, WORD Wrd, WORD MapNumber)
  282. {
  283.     HBITMAP    hMapBits = LoadBitmap(hInstance, MAKEINTRESOURCE(MapNumber));
  284.  
  285.     if ( !hMapBits )
  286.         if ( IsWorkshopWindow(hWnd) )
  287.                         hMapBits = LoadBitmapRW((LPSTR)MAKEINTRESOURCE(MapNumber));
  288.         else
  289.                         hMapBits = LoadBitmap(GetAppInstance(), MAKEINTRESOURCE(MapNumber));
  290.  
  291.     if ( !hMapBits )
  292.         hMapBits = LoadBitmap(hInstance, MAKEINTRESOURCE(MapNumber -
  293.           Get(GWW_ID)));
  294.  
  295.         SetWord((int)Wrd, (WORD)hMapBits);
  296. }
  297.  
  298. /* BitButtonWinFn ----------------------------------------------- *
  299.  *     Button window procedure.                                     *
  300.  * -------------------------------------------------------------- */
  301. LRESULT CALLBACK BitButtonWinFn(HWND hWnd, UINT wMessage,
  302.         WPARAM wParam, LPARAM lParam)
  303. {
  304.     DWORD    result = 0;
  305.  
  306.     switch( wMessage )
  307.     {
  308.         case WM_CREATE:
  309.         {
  310.             HDC     hDC         = GetDC(NULL);
  311.             int        BitsNumber;
  312.             BITMAP    Bitmap;
  313.             RECT    Rect;
  314.             POINT    Pt;
  315.             DWORD    style;
  316.  
  317.             // Detect EGA vs. VGA monitor
  318.             if ( GetSystemMetrics(SM_CYSCREEN) < 480 ||
  319.                     GetDeviceCaps(hDC, NUMCOLORS) < 16 )
  320.                 BitsNumber = 2000 + Get(GWW_ID);
  321.             else
  322.                 BitsNumber = 1000 + Get(GWW_ID);
  323.             ReleaseDC(NULL, hDC);
  324.  
  325.             // Load bitmaps from resource
  326.             LoadBits(hWnd, OF_UPBITS, BitsNumber);
  327.             LoadBits(hWnd, OF_DOWNBITS, BitsNumber + 2000);
  328.             LoadBits(hWnd, OF_FOCUPBITS, BitsNumber + 4000);
  329.  
  330.             // Adjust size of buttons to size of bitmap
  331.                         GetObject((HBITMAP)DownBits, sizeof(Bitmap), (LPSTR) &Bitmap);
  332.             GetWindowRect(hWnd, &Rect);
  333.             Pt.x = Rect.left;
  334.             Pt.y = Rect.top;
  335.             ScreenToClient(((LPCREATESTRUCT) lParam)->hwndParent, &Pt);
  336.             MoveWindow(hWnd, Pt.x, Pt.y, Bitmap.bmWidth + BD_BORDERWIDTH * 2,
  337.               Bitmap.bmHeight + BD_BORDERWIDTH * 2, FALSE);
  338.  
  339.             // Initialize button state flags
  340.             style = ((LPCREATESTRUCT) lParam)->style;
  341.             if ( (style & 0x1F) == BS_DEFPUSHBUTTON )
  342.                 SetState(BS_DEFAULT, TRUE);
  343.             if ( style & WS_DISABLED )
  344.                 SetState(BS_DISABLED, TRUE);
  345.  
  346.             break;
  347.         }
  348.  
  349.         case WM_NCDESTROY:
  350.         {
  351.             // Destroy all saved bitmaps before the button is destroyed.
  352.  
  353.             result = DefWindowProc(hWnd, wMessage, wParam, lParam);
  354.                         DeleteObject((HGDIOBJ)UpBits);
  355.                         DeleteObject((HGDIOBJ)DownBits);
  356.                         DeleteObject((HGDIOBJ)FocUpBits);
  357.  
  358.             break;
  359.         }
  360.  
  361.         case WM_PAINT:
  362.         {
  363.             PAINTSTRUCT PS;
  364.  
  365.             BeginPaint(hWnd, &PS);
  366.             Paint(hWnd, PS.hdc);
  367.             EndPaint(hWnd, &PS);
  368.  
  369.             break;
  370.         }
  371.  
  372.         case WM_ERASEBKGND:
  373.         {
  374.             // Squelch the painting of the background to eliminate flicker
  375.             break;
  376.         }
  377.  
  378.         case WM_ENABLE:
  379.         {
  380.             SetState(BS_DISABLED, wParam == 0);
  381.  
  382.             break;
  383.         }
  384.  
  385.         case WM_SETFOCUS:
  386.         {
  387.             SetState(BS_FOCUS, TRUE);
  388.  
  389.             break;
  390.         }
  391.  
  392.         case WM_KILLFOCUS:
  393.         {
  394.             SetState(BS_FOCUS, FALSE);
  395.  
  396.             break;
  397.         }
  398.  
  399.         case WM_KEYDOWN:
  400.         {
  401.             if ( wParam == ' '  && ! GetState(BS_MOUSEDOWN) &&
  402.                     !GetState(BS_KEYDOWN) )
  403.                 SetState(BS_KEYDOWN, TRUE);
  404.  
  405.             break;
  406.         }
  407.  
  408.         case WM_KEYUP:
  409.         {
  410.             if ( wParam == ' ' && GetState(BS_KEYDOWN) )
  411.                 ButtonPressed(hWnd);
  412.  
  413.             break;
  414.         }
  415.  
  416.         case WM_LBUTTONDBLCLK:
  417.         case WM_LBUTTONDOWN:
  418.         {
  419.             if ( InMe(hWnd, *((LPPOINT) &lParam)) && !GetState(BS_KEYDOWN) )
  420.             {
  421.                 if ( GetFocus() != hWnd )
  422.                     SetFocus(hWnd);
  423.                 SetState(BS_MOUSEDOWN, TRUE);
  424.                 SetCapture(hWnd);
  425.             }
  426.  
  427.             break;
  428.         }
  429.  
  430.         case WM_MOUSEMOVE:
  431.         {
  432.             if ( GetState(BS_MOUSEDOWN) )
  433.                 SetState(BS_MOUSEUPDOWN, !InMe(hWnd, *((LPPOINT) &lParam)));
  434.  
  435.             break;
  436.         }
  437.  
  438.         case WM_LBUTTONUP:
  439.         {
  440.             if ( GetState(BS_MOUSEDOWN) )
  441.             {
  442.                 ReleaseCapture();
  443.                 if ( !GetState(BS_MOUSEUPDOWN) )
  444.                     ButtonPressed(hWnd);
  445.                 else
  446.                     SetState(BS_MOUSEDOWN | BS_MOUSEUPDOWN, FALSE);
  447.             }
  448.  
  449.             break;
  450.         }
  451.  
  452.         /**** Handling the next four messages is what, at least for the dialog
  453.           manager, makes a push button a push button. ****/
  454.         case WM_GETDLGCODE:
  455.         {
  456.             /* Sent by the dialog manager to determine the control kind of
  457.             a child window.  Returning DLGC_DEFPUSHBUTTON or
  458.             DLGC_UNDEFPUSHBUTTON causes the dialog manager to treat the
  459.             control like a button, sending the BM_SETSTYLE message to
  460.             move the default button style to the currently focused button.
  461.  
  462.             The DLGC_BUTTON constant is not documented by Microsoft
  463.             (however, it is documented for OS/2 PM, and appears to work
  464.             the same). If this constant is or'd in, the Windows dialog
  465.             manager will take care of all accelerator key processing,
  466.             sending BM_GETSTATE and BM_SETSTATE messages when an
  467.             accelerator key is pressed. There is a side effect to using
  468.             the message, however, the dialog manager messes with the word
  469.             at offset 0 from the user window words. */
  470.  
  471.             result = GetState(BS_DEFAULT) ?
  472.                 DLGC_DEFPUSHBUTTON | DLGC_BUTTON:
  473.                 DLGC_UNDEFPUSHBUTTON | DLGC_BUTTON;
  474.  
  475.             break;
  476.         }
  477.  
  478.         case BM_GETSTATE:
  479.         {
  480.             result = GetState(BS_KEYDOWN);
  481.  
  482.             break;
  483.         }
  484.  
  485.         case BM_SETSTATE:
  486.         {
  487.             SetState(BS_KEYDOWN, wParam);
  488.  
  489.             break;
  490.         }
  491.  
  492.         case BM_SETSTYLE:
  493.         {
  494.             SetState(BS_DEFAULT, wParam == BS_DEFPUSHBUTTON);
  495.  
  496.             break;
  497.         }
  498.  
  499.         default:
  500.         {
  501.             result = DefWindowProc(hWnd, wMessage, wParam, lParam);
  502.  
  503.             break;
  504.         }
  505.     }
  506.  
  507.     return result;
  508. }
  509.  
  510. /* ============================================================== *
  511.  * Custom control interface routines.                              *
  512.  * ============================================================== */
  513.  
  514. /* BitBtnInfo --------------------------------------------------- *
  515.  *     Return the information about the capabilities of the         *
  516.  *     bit button class.                                            *
  517.  * -------------------------------------------------------------- */
  518. HGLOBAL CALLBACK BitBtnInfo(void)
  519. {
  520.     HGLOBAL hInfo =        GlobalAlloc(GHND,
  521.         sizeof(RWCTLINFO));
  522.  
  523.     if ( hInfo )
  524.     {
  525.         LPRWCTLINFO    Info =    (LPRWCTLINFO) GlobalLock(hInfo);
  526.  
  527.         Info->wVersion    =    0x0100;        // Version 1.00
  528.         Info->wCtlTypes =     2;            // 2 types
  529.         lstrcpy(Info->szClass, "BitButton");
  530.         lstrcpy(Info->szTitle, "Button");
  531.  
  532.         // Normal (un-default) push button type
  533.         Info->Type[0].wWidth  = 63 | 0x8000;
  534.         Info->Type[0].wHeight = 39 | 0x8000;
  535.         lstrcpy(Info->Type[0].szDescr, "Push Button");
  536.         Info->Type[0].dwStyle = BS_PUSHBUTTON | WS_TABSTOP;
  537.         Info->Type[0].hToolBit = LoadBitmap(hInstance,
  538.             MAKEINTRESOURCE(BT_UNDEFBITS));
  539.         Info->Type[0].hDropCurs = LoadCursor(hInstance,
  540.             MAKEINTRESOURCE(CR_UNDEFCURS));
  541.  
  542.         // Default push button type
  543.         Info->Type[1].wWidth  = 63 | 0x8000;
  544.         Info->Type[1].wHeight = 39 | 0x8000;
  545.         lstrcpy(Info->Type[1].szDescr, "Default Push Button");
  546.         Info->Type[1].dwStyle = BS_DEFPUSHBUTTON | WS_TABSTOP;
  547.         Info->Type[1].hToolBit = LoadBitmap(hInstance,
  548.             MAKEINTRESOURCE(BT_DEFBITS));
  549.         Info->Type[1].hDropCurs = LoadCursor(hInstance,
  550.             MAKEINTRESOURCE(CR_DEFCURS));
  551.  
  552.  
  553.         GlobalUnlock(hInfo);
  554.     }
  555.  
  556.     return hInfo;
  557. }
  558.  
  559. typedef struct
  560. {
  561.            HGLOBAL     CtlStyle;
  562.     LPFNSTRTOID     StrToId;
  563.     LPFNIDTOSTR    IdToStr;
  564. } PARAMREC, FAR * LPPARAMREC;
  565.  
  566. /* BitBtnStyleDlg ----------------------------------------------- *
  567.  *     Style dialog's dialog hook.  Used by the dialog and called   *
  568.  *     when the control is double-clicked inside the dialog         *
  569.  *     editor.                                                      *
  570.  * -------------------------------------------------------------- */
  571. BOOL FAR PASCAL BitBtnStyleDlg(HWND hWnd, UINT wMessage,
  572.     WPARAM wParam, LPARAM lParam)
  573. {
  574.     BOOL result = TRUE;
  575.  
  576.     switch( wMessage )
  577.     {
  578.         case WM_INITDIALOG:
  579.         {
  580.                         HGLOBAL         hRec    =       (HGLOBAL)LOWORD(lParam);
  581.             LPPARAMREC  Rec        =    (LPPARAMREC) GlobalLock(hRec);
  582.             LPCTLSTYLE    Style    =    (LPCTLSTYLE) GlobalLock(Rec->CtlStyle);
  583.             char        S[81];
  584.  
  585.             // Save hRec for future use in other messages.
  586.             SetProp(hWnd, "Prop", hRec);
  587.  
  588.             // SetCaption
  589.             SetDlgItemText(hWnd, ID_CAPTION, Style->szTitle);
  590.  
  591.             // Set control id
  592.             (*Rec->IdToStr)(Style->wId, S, sizeof(S));
  593.             SetDlgItemText(hWnd, ID_CONTROLID, S);
  594.  
  595.             // Set type radio buttons
  596.             CheckRadioButton(hWnd, ID_DEFAULTBUTTON, ID_PUSHBUTTON,
  597.               (Style->dwStyle & 0xF) == BS_DEFPUSHBUTTON ? ID_DEFAULTBUTTON :
  598.               ID_PUSHBUTTON);
  599.  
  600.             // Initialize Tab Stop check box
  601.             CheckDlgButton(hWnd, ID_TABSTOP,
  602.                 (Style->dwStyle & WS_TABSTOP) != 0);
  603.  
  604.             // Initialize Disabled check box
  605.             CheckDlgButton(hWnd, ID_DISABLED,
  606.                 (Style->dwStyle & WS_DISABLED) != 0);
  607.  
  608.             // Initialize Group check box
  609.             CheckDlgButton(hWnd, ID_GROUP,
  610.                 (Style->dwStyle & WS_GROUP) != 0);
  611.  
  612.             // Clean-up scope
  613.             GlobalUnlock(Rec->CtlStyle);
  614.             GlobalUnlock(hRec);
  615.  
  616.             break;
  617.         }
  618.  
  619.         case WM_COMMAND:
  620.         {
  621.             switch( wParam )
  622.             {
  623.                 case IDCANCEL:
  624.                 {
  625.                     EndDialog(hWnd, FALSE);
  626.  
  627.                     break;
  628.                 }
  629.  
  630.                 case IDOK:
  631.                 {
  632.                     HGLOBAL        hRec    =    GetProp(hWnd, "Prop");
  633.                     LPPARAMREC      Rec        =    (LPPARAMREC) GlobalLock(hRec);
  634.                     LPCTLSTYLE    Style    =    (LPCTLSTYLE) GlobalLock(Rec->CtlStyle);
  635.                     char        S[81];
  636.  
  637.                     // Get caption
  638.                     GetDlgItemText(hWnd, ID_CAPTION, Style->szTitle,
  639.                         sizeof(Style->szTitle));
  640.  
  641.                     // Get control id
  642.                     GetDlgItemText(hWnd, ID_CONTROLID, S, sizeof(S));
  643.                     Style->wId = HIWORD( (*Rec->StrToId)(S));
  644.  
  645.                     // Get button type
  646.                     Style->dwStyle = IsDlgButtonChecked(hWnd,
  647.                         ID_DEFAULTBUTTON) ? BS_DEFPUSHBUTTON : BS_PUSHBUTTON;
  648.  
  649.                     // Get tab stop
  650.                     if ( IsDlgButtonChecked(hWnd, ID_TABSTOP) )
  651.                         Style->dwStyle |= WS_TABSTOP;
  652.  
  653.                     // Get disabled
  654.                     if ( IsDlgButtonChecked(hWnd, ID_DISABLED) )
  655.                         Style->dwStyle |= WS_DISABLED;
  656.  
  657.                     // Get group
  658.                     if ( IsDlgButtonChecked(hWnd, ID_GROUP) )
  659.                         Style->dwStyle |= WS_GROUP;
  660.  
  661.                     // Clean-up scope
  662.                     GlobalUnlock(Rec->CtlStyle);
  663.                     GlobalUnlock(hRec);
  664.                     EndDialog(hWnd, TRUE);
  665.  
  666.                     break;
  667.                 }
  668.  
  669.                 default:
  670.                 {
  671.                     result = 0;
  672.  
  673.                     break;
  674.                 }
  675.             }
  676.  
  677.             break;
  678.         }
  679.  
  680.         case WM_DESTROY:
  681.         {
  682.             RemoveProp(hWnd, "Prop");
  683.  
  684.             break;
  685.         }
  686.  
  687.         default:
  688.         {
  689.             result = 0;
  690.  
  691.             break;
  692.         }
  693.     }
  694.  
  695.     return result;
  696. }
  697.  
  698. /* BitBtnStyle -------------------------------------------------- *
  699.  *     The function will bring up a dialog box to modify the style  *
  700.  *     of the button.  Called when the button is double-clicked in  *
  701.  *     the dialog editor.                                           *
  702.  * -------------------------------------------------------------- */
  703. BOOL CALLBACK BitBtnStyle(HWND hWnd, HGLOBAL hCtlStyle,
  704.     LPFNSTRTOID StrToId, LPFNIDTOSTR IdToStr)
  705. {
  706.     BOOL    result     =     FALSE;
  707.     HGLOBAL    hRec    =       GlobalAlloc(GHND, sizeof(PARAMREC));
  708.  
  709.     if ( hRec )
  710.     {
  711.         LPPARAMREC    Rec     = (LPPARAMREC) GlobalLock(hRec);
  712.         HWND        hFocus  = GetFocus();
  713.  
  714.         // Setup the parameter record
  715.         Rec->IdToStr = IdToStr;
  716.         Rec->StrToId = StrToId;
  717.         Rec->CtlStyle = hCtlStyle;
  718.         GlobalUnlock(hRec);
  719.  
  720.         // Invoke the dialog box
  721.         result = DialogBoxParam(hInstance, MAKEINTRESOURCE(ID_BUTTONSTYLE),
  722.                         hWnd, (DLGPROC) BitBtnStyleDlg, (DWORD) hRec);
  723.  
  724.         // Restore focused window since Windows does not do it
  725.         if ( hFocus )
  726.             SetFocus(hFocus);
  727.  
  728.         GlobalFree(hRec);
  729.     }
  730.  
  731.     return result;
  732. }
  733.  
  734. /* BitBtnFlags -------------------------------------------------- *
  735.  *     Called to decompose the style double word into the .RC       *
  736.  *     script expression that it represents.  This only needs to    *
  737.  *     decompose the style bits added to the style double word,     *
  738.  *     it need not decompose, for example, the ws_XXX bits.         *
  739.  *     The expression returned must be a valid .RC expression       *
  740.  *     (i.e. C syntax, case sensitive).                             *
  741.  * -------------------------------------------------------------- */
  742. #pragma warn -par
  743. UINT CALLBACK BitBtnFlag(DWORD Style, LPSTR Buff,
  744.     UINT BuffLength)
  745. {
  746.     lstrcpy(Buff, (Style & 0xF) == BS_DEFPUSHBUTTON ? "BS_DEFPUSHBUTTON" :
  747.         "BS_PUSHBUTTON");
  748.  
  749.     return 0;
  750. }
  751. #pragma warn .par
  752.  
  753. /* ListClasses ------------------------------------------------------ *
  754.  *     Called by Resource Workshop to retrieve the information      *
  755.  *     necessary to edit the custom controls contained in this DLL. *
  756.  *     This is an alternative to the Microsoft xxxStyle convention. *
  757.  * ------------------------------------------------------------------ */
  758. #pragma argsused       // szAppName, wVersion, and fnEdit intentionally unused
  759. HGLOBAL CALLBACK ListClasses(LPSTR szAppName,
  760.     UINT wVersion, LPFNLOADRES fnLoad, LPFNEDITRES fnEdit)
  761. {
  762.     HGLOBAL hClasses = GlobalAlloc(GHND,
  763.         sizeof(int) + sizeof(RWCTLCLASS));
  764.  
  765.     LoadResRW = fnLoad;
  766.  
  767.     if ( hClasses )
  768.     {
  769.         LPCTLCLASSLIST    Classes    = (LPCTLCLASSLIST) GlobalLock(hClasses);
  770.  
  771.         Classes->nClasses = 1;
  772.         Classes->Classes[0].fnRWInfo  = BitBtnInfo;
  773.         Classes->Classes[0].fnRWStyle = BitBtnStyle;
  774.         Classes->Classes[0].fnFlags   = BitBtnFlag;
  775.         lstrcpy(Classes->Classes[0].szClass, "BitButton");
  776.         GlobalUnlock(hClasses);
  777.     }
  778.  
  779.     return hClasses;
  780. }
  781.  
  782.  
  783. /* LibMain --------------------------------------------------------*
  784.  *    Called by Windows when the library is loaded.  Registers the *
  785.  *      Custom control class.                       *                      *
  786.  * ----------------------------------------------------------------*/
  787.  
  788. static WNDCLASS Class = {
  789. /* Style */            CS_HREDRAW | CS_VREDRAW | CS_DBLCLKS | CS_GLOBALCLASS,
  790. /* lpfnWndProc */       BitButtonWinFn,
  791. /* cbClsExtra */    0,
  792. /* cbWndExtra */    OF_SIZE,
  793. /* hInstance */        0,                 // Initialized in LibMain
  794. /* hIcon */            NULL,            // No icon
  795. /* hCursor */        NULL,            // No cursor
  796. /* hbrBackground */    NULL,            // Default background brush
  797. /* lpszMenuName */    NULL,            // No menu
  798. /* lpszClassName */    "BitButton"
  799. };
  800.  
  801. #pragma argsused // wDataSeg, cbHeapSize, lpszCmdLine not used
  802. int FAR PASCAL LibMain(HINSTANCE hInst, WORD wDataSeg, WORD cbHeapSize,
  803.                         LPSTR lpszCmdLine)
  804. {
  805.     hInstance = hInst;
  806.  
  807.     // Register the "BitButton" class
  808.     Class.hInstance = hInstance;
  809.     RegisterClass(&Class);
  810.  
  811.     return 1;
  812. }
  813.