home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD1.mdf / pascal / wksinst / rwcdemo.pak / BITBTN.C < prev    next >
C/C++ Source or Header  |  1991-09-09  |  22KB  |  809 lines

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