home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / pmstabar.zip / superclass.C < prev    next >
C/C++ Source or Header  |  2002-01-27  |  19KB  |  442 lines

  1. //===========================================================================
  2. // superclass.c : simple example of a static bar control implemented via
  3. //                superclassing
  4. // 10-01-2002 * by Alessandro Cantatore * v. 0.1
  5. //===========================================================================
  6.  
  7.  
  8. #include "dllmain.h"
  9. #include "superclass.h"
  10.  
  11.  
  12. // Global variables
  13. PFNWP pfnWcStatic;
  14. ULONG cbWcStatic;
  15.  
  16. // Control data (for internal use)
  17. #pragma pack(2)
  18.  
  19. typedef struct {
  20.    USHORT style;   // valid only for the BARS_VERTICAL and BARS_AUTOSIZE
  21.    USHORT thkns;   // bar control thickness
  22.    SIZES sz;       // control size
  23.    PCTRLTXT pct;   // control text data (with mnemonic)
  24. } BAR, * PBAR;
  25.  
  26. #pragma pack()
  27.  
  28. // function prototypes
  29. MRESULT EXPENTRY testDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  30. BOOL BarRegister(HAB hab);
  31. MRESULT EXPENTRY BarProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2);
  32. VOID BarPaint(HPS hps, HWND hwnd, PBAR pbar);
  33.  
  34. // macro to get the inner control data
  35. #define BarData(hwnd) \
  36.    ((PBAR)WinQueryWindowPtr((hwnd), cbWcStatic))
  37.  
  38. // colors used by the bar control:
  39. #define ICLR_BKGND         0       // light gray (caption background)
  40. #define ICLR_FGND          1       // black (caption foreground)
  41. #define ICLR_HILITE        2       // white (light border)
  42. #define ICLR_SHADE         3       // dark gray (used as dark border)
  43. #define C_ICLRS            4       // color count
  44.  
  45. // macro to get the color values
  46.  
  47. #define BarColors(hwnd, pclr)                                       \
  48. {                                                                   \
  49.    (pclr)[ICLR_BKGND] = CtrlClrGet((hwnd), PP_BACKGROUNDCOLOR,      \
  50.        PP_BACKGROUNDCOLORINDEX, SYSCLR_DIALOGBACKGROUND, TRUE);     \
  51.    (pclr)[ICLR_FGND] = CtrlClrGet((hwnd), PP_FOREGROUNDCOLOR,       \
  52.        PP_FOREGROUNDCOLORINDEX, SYSCLR_WINDOWSTATICTEXT, TRUE);     \
  53.    (pclr)[ICLR_HILITE] = CtrlClrGet((hwnd), PP_BORDERLIGHTCOLOR, 0, \
  54.        SYSCLR_BUTTONLIGHT, FALSE);                                  \
  55.    (pclr)[ICLR_SHADE] = CtrlClrGet((hwnd), PP_BORDERDARKCOLOR, 0,   \
  56.        SYSCLR_BUTTONDARK, FALSE);                                   \
  57. }    
  58.  
  59.  
  60. //===========================================================================
  61. // Test executable - main procedure
  62. // Parameters --------------------------------------------------------------
  63. // VOID
  64. // Return value ------------------------------------------------------------
  65. // VOID
  66. //===========================================================================
  67.  
  68. VOID main(VOID) {
  69.    HAB hab;
  70.    HMQ hmq;
  71.    QMSG qmsg;
  72.    HWND hwnd;
  73.    hmq = WinCreateMsgQueue((hab = WinInitialize(0)), 0);
  74.    BarRegister(hab);   
  75.    hwnd = WinLoadDlg(HWND_DESKTOP, 0, testDlgProc, 0, 100, NULL);
  76.    if (hwnd) {
  77.       while (WinGetMsg(hab, &qmsg, NULLHANDLE, 0, 0))
  78.          WinDispatchMsg(hab, &qmsg);
  79.    } /* endif */
  80.    WinDestroyWindow(hwnd);
  81.    WinDestroyMsgQueue(hmq);
  82.    WinTerminate(hab);
  83. }
  84.  
  85.  
  86. //===========================================================================
  87. // Test dialog procedure
  88. // Parameters --------------------------------------------------------------
  89. // ordinary window procedure parameters
  90. // Return value ------------------------------------------------------------
  91. // MRESULT
  92. //===========================================================================
  93.  
  94. MRESULT EXPENTRY testDlgProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) {
  95.    switch (msg) {
  96.       case WM_CLOSE:
  97.          WinPostMsg(hwnd, WM_QUIT, MPVOID, MPVOID);
  98.          break;
  99.       default:
  100.          return WinDefDlgProc(hwnd, msg, mp1, mp2);
  101.    } /* endswitch */
  102.    return MRFALSE;
  103. }
  104.  
  105.  
  106. //==========================================================================
  107. // BarRegister : register the Bar control
  108. // Parameters --------------------------------------------------------------
  109. // HAB hab : anchor block handle
  110. // Return value ------------------------------------------------------------
  111. // BOOL : TRUE (success) or FALSE (error)
  112. //==========================================================================
  113.  
  114. BOOL BarRegister(HAB hab) {
  115.    CLASSINFO ci;
  116.    if (WinQueryClassInfo(hab, WC_STATIC, &ci)) {
  117.       // store the default class procedure in the global variables
  118.       pfnWcStatic = ci.pfnWindowProc;
  119.       cbWcStatic = ci.cbWindowData;
  120.       return WinRegisterClass(hab, WC_BAR, BarProc,
  121.                               ci.flClassStyle & ~CS_PUBLIC,
  122.                               ci.cbWindowData + sizeof(PVOID));
  123.    }                           
  124.    return FALSE;
  125. }
  126.  
  127.  
  128. //===========================================================================
  129. // BarProc: Bar control window procedure implemented as WC_STATIC superclass
  130. // Parameters --------------------------------------------------------------
  131. // ordinary window procedure parameters
  132. // Return value ------------------------------------------------------------
  133. // MRESULT
  134. //===========================================================================
  135.  
  136. MRESULT EXPENTRY BarProc(HWND hwnd, ULONG msg, MPARAM mp1, MPARAM mp2) {
  137.    switch (msg) {
  138.       PBAR pbar;
  139.       
  140.       // Checks the mnemonic character -------------------------------------
  141.       // If the control is not disabled checks the input character
  142.       case WM_MATCHMNEMONIC:
  143.          if (!(WinStyle(hwnd) & WS_DISABLED) &&
  144.              (NULL != (pbar = BarData(hwnd))) && pbar->pct &&
  145.              (pbar->pct->mnemo >= 0)) {
  146.             HAB hab = WinHAB(hwnd); 
  147.             return (MRESULT)
  148.                    (WinUpperChar(hab, 0, 0, (ULONG)mp1) ==
  149.                     WinUpperChar(hab, 0, 0,
  150.                             (ULONG)pbar->pct->ach[pbar->pct->mnemo]));
  151.          } /* endif */                        
  152.          return MRFALSE;
  153.       /* end case WM_MATCHMNEMONIC */
  154.       
  155.       // control painting --------------------------------------------------
  156.       // WC_STATIC procedure is completely replaced here since we want to
  157.       // paint the control ourselves
  158.       case WM_PAINT:
  159.          if (NULL != (pbar = BarData(hwnd))) {
  160.             HPS hps;
  161.             if (NULLHANDLE != (hps = WinBeginPaint(hwnd, NULLHANDLE, NULL))) {
  162.                BarPaint(hps, hwnd, pbar);
  163.                WinEndPaint(hps);
  164.             } /* endif */
  165.          } /* endif */
  166.          return MRFALSE;
  167.       /* end case WM_PAINT */
  168.       
  169.       // Window resizing ---------------------------------------------------
  170.       // if autosize, modify the control size, otherwise store the new size
  171.       case WM_ADJUSTWINDOWPOS:
  172.          if ((((PSWP)mp1)->fl & SWP_SIZE) &&
  173.             (NULL != (pbar = BarData(hwnd)))) {
  174.             if (pbar->style & BARS_AUTOSIZE) {
  175.                if (pbar->style & BARS_VERTICAL) {
  176.                   ((PSWP)mp1)->cx = pbar->sz.cx;
  177.                } else {                                   // horizontal bar
  178.                   ((PSWP)mp1)->cy = pbar->sz.cy;
  179.                } /* endif */
  180.             } else {
  181.                pbar->sz.cx = ((PSWP)mp1)->cx;
  182.                pbar->sz.cy = ((PSWP)mp1)->cy;
  183.             } /* endif */
  184.          } /* end if */
  185.          return MRFALSE;
  186.          /* end case WM_ADJUSTWINDOWPOS */
  187.          
  188.       // Set the window text and other data --------------------------------
  189.       // This message is caused by a WinSetWindowText() call. It may also
  190.       // be sent directly if the control allow to change some data (for
  191.       // instance icon handle, bitmap handle, etc.) via the WPM_CTLDATA
  192.       // flag. As stated by the PM documentation, the only valid flags are:
  193.       // WPM_TEXT and WPM_CTLDATA.
  194.       case WM_SETWINDOWPARAMS:
  195.          if (((PWNDPARAMS)mp1)->fsStatus & WPM_TEXT) {
  196.             // updates the control text
  197.             if ((NULL != (pbar = BarData(hwnd))) &&
  198.                 !(pbar->style & BARS_VERTICAL) &&
  199.                 (NULL != (pbar->pct = CtrlTextSet(pbar->pct,
  200.                                        ((PWNDPARAMS)mp1)->pszText,
  201.                                        ((PWNDPARAMS)mp1)->cchText,
  202.                                        (WinStyle(hwnd) & BARS_MNEMONIC)))) &&
  203.                 CtrlTextSize(hwnd, pbar->pct)) {
  204.                // redraws the control
  205.                CtrlUpdate(hwnd, FALSE);
  206.                return MRTRUE;
  207.             } /* endif */
  208.          // control data to set the bar thickness
  209.          } else if (((PWNDPARAMS)mp1)->fsStatus & WPM_CTLDATA) {
  210.             if (((PWNDPARAMS)mp1)->cbCtlData && ((PWNDPARAMS)mp1)->pCtlData) {
  211.                return (MRESULT)WinBarThicknessSet(hwnd,
  212.                                      *((PUSHORT)((PWNDPARAMS)mp1)->pCtlData));
  213.             } /* endif */
  214.          } /* endif */
  215.          // invalid fsStatus flags: returns FALSE
  216.          return MRFALSE;
  217.          //break;
  218.       /* end case WM_SETWINDOWPARAMS */
  219.       
  220.       // Checks the control text or the control data -----------------------
  221.       // This message is caused by a WinQueryWindowTextLength() or by a
  222.       // WinQueryWindowText() call, or may sent directly to query the control
  223.       // data via the WPM_CTLDATA or WPM_CBCTLDATA flags.
  224.       // As stated by the PM documentation the only valid fsStatus flags
  225.       // are: WPM_TEXT, WPM_CCHTEXT, WPM_CTLDATA and WPM_CBCTLDATA.
  226.       // The flags in fsStatus must be cleared as each item is processed.
  227.       // If the call is successful, fsStatus is 0. If any item has not been 
  228.       // processed, the flag for that item is still set. 
  229.       // Note: in this implementeation the mnemonic tag character is not
  230.       //        returned
  231.       case WM_QUERYWINDOWPARAMS:
  232.          // If there are any valid flags:
  233.          if ((((PWNDPARAMS)mp1)->fsStatus & WPM_QUERYFLAGS) &&
  234.              (NULL != (pbar = BarData(hwnd)))) {
  235.             if (!(pbar->style & BARS_VERTICAL)) {
  236.                // The control text has been queried
  237.                if (((PWNDPARAMS)mp1)->fsStatus & WPM_TEXT) {
  238.                   ((PWNDPARAMS)mp1)->cchText = CtrlTextGet(pbar->pct,
  239.                                                 ((PWNDPARAMS)mp1)->pszText,
  240.                                                 ((PWNDPARAMS)mp1)->cchText, 0);
  241.                   if (((PWNDPARAMS)mp1)->cchText == WPM_TEXTERROR) {
  242.                      ((PWNDPARAMS)mp1)->cchText = 0;
  243.                   } else {
  244.                      ((PWNDPARAMS)mp1)->fsStatus &= ~(WPM_TEXT | WPM_CCHTEXT);
  245.                   } /* endif */
  246.                // The control text length has been queried
  247.                } else if (((PWNDPARAMS)mp1)->fsStatus & WPM_CCHTEXT) {
  248.                   ((PWNDPARAMS)mp1)->cchText = pbar->pct->len;
  249.                   ((PWNDPARAMS)mp1)->fsStatus &= ~WPM_CCHTEXT;
  250.                } /* endif */
  251.             } /* endif */   
  252.             // The control data have been queried 
  253.             if (((PWNDPARAMS)mp1)->fsStatus & WPM_CTLDATA) {
  254.                // set appropriately ((PWNDPARAMS)mp1)->pCtlData
  255.                // and reset the fsStatus flags if successful:
  256.                if (((PWNDPARAMS)mp1)->cbCtlData &&
  257.                    ((PWNDPARAMS)mp1)->pCtlData) {
  258.                   *((PUSHORT)((PWNDPARAMS)mp1)->pCtlData) = pbar->thkns;
  259.                   ((PWNDPARAMS)mp1)->fsStatus &=
  260.                                              ~(WPM_CTLDATA | WPM_CBCTLDATA);
  261.                } /* endif */
  262.             // The control data size has been queriedd
  263.             } else if (((PWNDPARAMS)mp1)->fsStatus & WPM_CBCTLDATA) {
  264.                ((PWNDPARAMS)mp1)->cbCtlData = 2;
  265.                ((PWNDPARAMS)mp1)->fsStatus &= ~WPM_CBCTLDATA;
  266.             } /* endif */
  267.          } /* endif */
  268.          return (MRESULT)!((PWNDPARAMS)mp1)->fsStatus;
  269.       /* end case WM_QUERYWINDOWPARAMS */
  270.       
  271.       // If the font has been changed measures the new text box ------------
  272.       case WM_PRESPARAMCHANGED:
  273.          if (((LONG)mp1 == PP_FONTNAMESIZE) &&
  274.              (NULL != (pbar = BarData(hwnd))) &&
  275.              !(pbar->style & BARS_VERTICAL) && pbar->pct) {
  276.              CtrlTextSize(hwnd, pbar->pct);
  277.              // if the BARS_AUTOSIZE flag is set resizes the control
  278.              if (pbar->style & BARS_AUTOSIZE) {
  279.                 pbar->sz.cy = pbar->pct->cy + 2;
  280.                 WinSetWindowPos(hwnd, 0, 0, 0, pbar->sz.cx, pbar->sz.cy,
  281.                                 SWP_SIZE | SWP_NOADJUST);
  282.              } /* endif */
  283.          } /* endif */
  284.          CtrlUpdate(hwnd, FALSE);
  285.          return MRFALSE;
  286.       /* end case WM_PRESPARAMCHANGED */
  287.       
  288.       // Set the bar thickness ---------------------------------------------
  289.       // this also causes the BARS_AUTOSIZE style to be set
  290.       case BARM_SETTHICKNESS:
  291.          if (!mp1 || (NULL == (pbar = BarData(hwnd)))) return MRFALSE;
  292.          pbar->style |= BARS_AUTOSIZE;
  293.          pbar->thkns = ((ULONG)mp1) & 0x7e;
  294.          if (pbar->style & BARS_VERTICAL) {
  295.             pbar->sz.cx = pbar->thkns;
  296.          } else {
  297.             pbar->sz.cy = max(pbar->thkns, (pbar->pct? pbar->pct->cy + 2: 0));
  298.          } /* endif */
  299.          WinSetWindowPos(hwnd, 0, 0, 0, pbar->sz.cx, pbar->sz.cy,
  300.                          SWP_SIZE | SWP_NOADJUST);
  301.          return MRTRUE;
  302.       /* end case BARM_SETTHICKNESS */
  303.       
  304.       // Query the bar thickness -------------------------------------------
  305.       case BARM_QUERYTHICKNESS:
  306.          if (NULL == (pbar = BarData(hwnd))) return (MRESULT)0xffff;
  307.          return (MRESULT)pbar->thkns;
  308.       /* end case BARM_QUERYTHICKNESS */
  309.       
  310.       // Window creation ---------------------------------------------------
  311.       case WM_CREATE:
  312.          // Checks if the control style is horizontal or vertical
  313.          pbar = (PBAR)memalloc(sizeof(BAR));
  314.          if (!pbar) return MRTRUE;
  315.          WinSetWindowPtr(hwnd, cbWcStatic, (PVOID)pbar);
  316.          // store the direction and BARS_AUTOSIZE styles
  317.          pbar->style = ((PCREATESTRUCT)mp2)->flStyle;
  318.          // if it is an horizontal bar stores the text
  319.          if (pbar->style & BARS_VERTICAL) {
  320.             pbar->pct = NULL;
  321.          } else {
  322.             pbar->pct = CtrlTextSet(NULL, ((PCREATESTRUCT)mp2)->pszText,
  323.                                     -1, pbar->style & BARS_MNEMONIC);
  324.             // if the control has any text, measures the text box size
  325.             if (!pbar->pct ||
  326.                 (pbar->pct->len && !CtrlTextSize(hwnd, pbar->pct))) {
  327.                memfree(pbar);
  328.                return MRTRUE;
  329.             } /* endif */
  330.          } /* endif */
  331.          // We reset the CREATESTRUCT pszText member to NULL since we don't
  332.          // want to store the text both in our procedure and in the WC_STATIC
  333.          // procedure
  334.          ((PCREATESTRUCT)mp2)->pszText = NULL;
  335.          // Set the control thickness: if a non-default thickness is defined
  336.          // automatically sets the AUTOSIZE style!!!
  337.          if (((PCREATESTRUCT)mp2)->pCtlData) {
  338.             pbar->thkns = *((PUSHORT)((PCREATESTRUCT)mp2)->pCtlData) & 0x7e;
  339.             pbar->style |= BARS_AUTOSIZE;
  340.          } else {
  341.             pbar->thkns = (pbar->style & BARS_THICK) ? 4 : 2;
  342.          } /* endif */
  343.          // if the BARS_AUTOSIZE style flag is set, resize the control
  344.          if (pbar->style & BARS_AUTOSIZE) {
  345.             if (pbar->style & BARS_VERTICAL) {
  346.                ((PCREATESTRUCT)mp2)->cx = pbar->thkns;
  347.             } else {
  348.                ((PCREATESTRUCT)mp2)->cy = max(pbar->thkns, pbar->pct->cy + 2);
  349.             } /* endif */
  350.             WinSetWindowPos(hwnd, 0, 0, 0,
  351.                           ((PCREATESTRUCT)mp2)->cx, ((PCREATESTRUCT)mp2)->cy,
  352.                           SWP_SIZE | SWP_NOADJUST);
  353.          } /* endif */
  354.          pbar->sz.cx = ((PCREATESTRUCT)mp2)->cx;
  355.          pbar->sz.cy = ((PCREATESTRUCT)mp2)->cy;
  356.          break;
  357.          /* end case WM_CREATE */
  358.       // Window destruction ------------------------------------------------
  359.       // All the allocated resources are freed:
  360.       case WM_DESTROY:
  361.          if (NULL != (pbar = BarData(hwnd))) {
  362.             if (pbar->pct) memfree(pbar->pct);
  363.             memfree(pbar);
  364.             memheapmin();
  365.          } /* endif */
  366.          break;
  367.       /* end case WM_DESTROY */
  368.        
  369.    } /* endswitch */
  370.    // all other messages go to the original WC_STATIC procedure
  371.    return pfnWcStatic(hwnd, msg, mp1, mp2);
  372. }
  373.  
  374.  
  375. //===========================================================================
  376. // BarPaint: paints the bar control
  377. // Parameters --------------------------------------------------------------
  378. // HPS hps   : control presentation space
  379. // HWND hwnd : control handle
  380. // PBAR pbar : control data
  381. // Return value ------------------------------------------------------------
  382. // VOID
  383. //===========================================================================
  384.  
  385. VOID BarPaint(HPS hps, HWND hwnd, PBAR pbar) {
  386.    RECTL r;
  387.    LONG aclr[C_ICLRS];
  388.    // get the current style flags
  389.    ULONG style = WinStyle(hwnd);
  390.    // Get the current colors
  391.    BarColors(hwnd, aclr);
  392.    // Set to RGB mode
  393.    GpiCreateLogColorTable(hps, 0, LCOLF_RGB, 0, 0, NULL);
  394.    // Erase the background if needed
  395.    if ((!(pbar->style & BARS_VERTICAL) && (pbar->sz.cy > pbar->thkns)) ||
  396.        ((pbar->style & BARS_VERTICAL) && (pbar->sz.cx > pbar->thkns))) {
  397.       RectSet(&r, 0, 0, pbar->sz.cx, pbar->sz.cy);
  398.       WinFillRect(hps, &r, aclr[ICLR_BKGND]);
  399.    } /* endif */
  400.    // Draws the bar:
  401.    if (pbar->style & BARS_VERTICAL) {
  402.       r.xLeft = ((pbar->sz.cx - pbar->thkns) >> 1) - 1,
  403.       r.xRight = r.xLeft + pbar->thkns - 1,
  404.       r.yBottom = 0,
  405.       r.yTop = pbar->sz.cy - 1;
  406.    } else {
  407.       r.xLeft = 0,
  408.       r.yBottom = ((pbar->sz.cy - pbar->thkns) >> 1) - 1,
  409.       r.xRight = pbar->sz.cx - 1,
  410.       r.yTop = r.yBottom + pbar->thkns - 1;
  411.    } /* endif */
  412.    if (style & BARS_RAISED) {
  413.       Win3DBorderDraw(hps, &r, aclr[ICLR_HILITE], aclr[ICLR_SHADE],
  414.                       pbar->thkns >> 1);
  415.    } else {
  416.       Win3DBorderDraw(hps, &r, aclr[ICLR_SHADE], aclr[ICLR_HILITE], 
  417.                       pbar->thkns >> 1);
  418.    } /* endif */
  419.    // if it is an horizontal bar and there is any text draws it
  420.    if (!(pbar->style & BARS_VERTICAL) && pbar->pct->len) {
  421.       if (style & BARS_CENTER) {
  422.          r.xLeft = max((pbar->thkns << 1) + 2,
  423.                        ((pbar->sz.cx - pbar->pct->cx) >> 1) - 2);
  424.          r.xRight = min(pbar->sz.cx - (pbar->thkns << 1) - 2,
  425.                         r.xLeft + pbar->pct->cx + 3);
  426.       } else if (style & BARS_RIGHT) {
  427.          r.xRight = pbar->sz.cx - (pbar->thkns << 1) - 2;
  428.          r.xLeft = max((pbar->thkns << 1) + 2,
  429.                        r.xRight - pbar->pct->cx - 3);
  430.       } else {
  431.          r.xLeft = (pbar->thkns << 1) + 2;
  432.          r.xRight = min(pbar->sz.cx - (pbar->thkns << 1) - 2,
  433.                         r.xLeft + pbar->pct->cx + 3);
  434.       } /* endif */
  435.       r.yBottom = 0, r.yTop = pbar->sz.cy;
  436.       pbar->pct->usflag = (style & WS_DISABLED) ?
  437.                          DT_HALFTONE | DT_CENTER | DT_VCENTER | DT_ERASERECT :
  438.                          DT_CENTER | DT_VCENTER | DT_ERASERECT;
  439.       CtrlTextDraw(hps, pbar->pct, &r, aclr[ICLR_FGND], aclr[ICLR_BKGND], 0);
  440.    } /* endif */
  441. }
  442.