home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk11 / petzold / chap16 / sqbtnlib.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-02-20  |  12.1 KB  |  360 lines

  1. /*---------------------------------------------------------------------
  2.    SQBTNLIB.C -- Dynamic link library version of square 3D push button
  3.   ---------------------------------------------------------------------*/
  4.  
  5. #define INCL_WIN
  6. #define INCL_GPI
  7. #include <os2.h>
  8. #include <malloc.h>
  9. #include <string.h>
  10. #include "sqbtnlib.h"
  11.  
  12. #define LCID_ITALIC 1L
  13.  
  14.                /*--------------------------------------------------
  15.                   Structure for storing data unique to each window
  16.          --------------------------------------------------*/
  17. typedef struct
  18.      {
  19.      PSZ  pszText ;
  20.      BOOL fHaveCapture ;
  21.      BOOL fHaveFocus ;
  22.      BOOL fInsideRect ;
  23.      BOOL fSpaceDown ;
  24.      }
  25.      SQBTN ;
  26.  
  27. typedef SQBTN *PSQBTN ;
  28.  
  29. MRESULT EXPENTRY SqBtnWndProc (HWND, USHORT, MPARAM, MPARAM) ;
  30. VOID             DrawButton   (HWND, HPS, PSQBTN) ;
  31.  
  32. HAB  hab ;
  33.  
  34.           /*--------------------------------------------------------
  35.              RegisterSqBtnClass function available to other modules
  36.             --------------------------------------------------------*/
  37.  
  38. BOOL APIENTRY RegisterSqBtnClass (HAB habIn)
  39.      {
  40.      hab = habIn ;
  41.  
  42.      return WinRegisterClass (hab, "SqBtn", SqBtnWndProc,
  43.                               CS_SIZEREDRAW, sizeof (PSQBTN)) ;
  44.      }
  45.  
  46.           /*-------------------------------
  47.              SqBtnWndProc window procedure
  48.             -------------------------------*/
  49.  
  50. MRESULT EXPENTRY SqBtnWndProc (HWND hwnd, USHORT msg, MPARAM mp1, MPARAM mp2)
  51.      {
  52.      BOOL          fTestInsideRect ;
  53.      HPS           hps ;
  54.      PCREATESTRUCT pcrst ;
  55.      POINTL        ptl ;
  56.      PSQBTN        pSqBtn ;
  57.      PWNDPARAMS    pwprm ;
  58.      RECTL         rcl ;
  59.  
  60.      pSqBtn = WinQueryWindowPtr (hwnd, 0) ;
  61.  
  62.      switch (msg)
  63.           {
  64.           case WM_CREATE:
  65.                pSqBtn = malloc (sizeof (SQBTN)) ;
  66.  
  67.                          // Initialize structure
  68.  
  69.                pSqBtn->fHaveCapture = FALSE ;
  70.                pSqBtn->fHaveFocus   = FALSE ;
  71.                pSqBtn->fInsideRect  = FALSE ;
  72.                pSqBtn->fSpaceDown   = FALSE ;
  73.  
  74.                          // Get window text from creation structure
  75.  
  76.                pcrst = (PCREATESTRUCT) PVOIDFROMMP (mp2) ;
  77.  
  78.                pSqBtn->pszText = malloc (1 + strlen (pcrst->pszText)) ;
  79.                strcpy (pSqBtn->pszText, pcrst->pszText) ;
  80.  
  81.                WinSetWindowPtr (hwnd, 0, pSqBtn) ;
  82.                return 0 ;
  83.  
  84.           case WM_SETWINDOWPARAMS:
  85.                pwprm = (PWNDPARAMS) PVOIDFROMMP (mp1) ;
  86.  
  87.                          // Get window text from window parameter structure
  88.  
  89.                if (pwprm->fsStatus & WPM_TEXT)
  90.                     {
  91.                     free (pSqBtn->pszText) ;
  92.                     pSqBtn->pszText = malloc (1 + pwprm->cchText) ;
  93.                     strcpy (pSqBtn->pszText, pwprm->pszText) ;
  94.                     }
  95.                return 1 ;
  96.  
  97.           case WM_QUERYWINDOWPARAMS:
  98.                pwprm == (PWNDPARAMS) PVOIDFROMMP (mp1) ;
  99.  
  100.                          // Set window parameter structure fields
  101.  
  102.                if (pwprm->fsStatus & WPM_CCHTEXT)
  103.                     pwprm->cchText = strlen (pSqBtn->pszText) ;
  104.  
  105.                if (pwprm->fsStatus & WPM_TEXT)
  106.                     strcpy (pwprm->pszText, pSqBtn->pszText) ;
  107.  
  108.                if (pwprm->fsStatus & WPM_CBPRESPARAMS)
  109.                     pwprm->cbPresParams = 0 ;
  110.  
  111.                if (pwprm->fsStatus & WPM_PRESPARAMS)
  112.                     pwprm->pPresParams = NULL ;
  113.  
  114.                if (pwprm->fsStatus & WPM_CBCTLDATA)
  115.                     pwprm->cbCtlData = 0 ;
  116.  
  117.                if (pwprm->fsStatus & WPM_CTLDATA)
  118.                     pwprm->pCtlData = NULL ;
  119.  
  120.                return 1 ;
  121.  
  122.           case WM_BUTTON1DOWN:
  123.                WinSetFocus (HWND_DESKTOP, hwnd) ;
  124.                WinSetCapture (HWND_DESKTOP, hwnd) ;
  125.                pSqBtn->fHaveCapture = TRUE ;
  126.                pSqBtn->fInsideRect  = TRUE ;
  127.                WinInvalidateRect (hwnd, NULL, FALSE) ;
  128.                return 0 ;
  129.  
  130.           case WM_MOUSEMOVE:
  131.                if (!pSqBtn->fHaveCapture)
  132.                     break ;
  133.  
  134.                WinQueryWindowRect (hwnd, &rcl) ;
  135.                ptl.x = MOUSEMSG(&msg)->x ;
  136.                ptl.y = MOUSEMSG(&msg)->y ;
  137.  
  138.                          // Test if mouse pointer is still in window
  139.  
  140.                fTestInsideRect = WinPtInRect (hab, &rcl, &ptl) ;
  141.  
  142.                if (pSqBtn->fInsideRect != fTestInsideRect)
  143.                     {
  144.                     pSqBtn->fInsideRect = fTestInsideRect ;
  145.                     WinInvalidateRect (hwnd, NULL, FALSE) ;
  146.                     }
  147.                break ;
  148.  
  149.           case WM_BUTTON1UP:
  150.                if (!pSqBtn->fHaveCapture)
  151.                     break ;
  152.  
  153.                WinSetCapture (HWND_DESKTOP, NULL) ;
  154.                pSqBtn->fHaveCapture = FALSE ;
  155.                pSqBtn->fInsideRect  = FALSE ;
  156.  
  157.                WinQueryWindowRect (hwnd, &rcl) ;
  158.                ptl.x = MOUSEMSG(&msg)->x ;
  159.                ptl.y = MOUSEMSG(&msg)->y ;
  160.  
  161.                          // Post WM_COMMAND if mouse pointer is in window
  162.  
  163.                if (WinPtInRect (hab, &rcl, &ptl))
  164.                     WinPostMsg (WinQueryWindow (hwnd, QW_OWNER, FALSE),
  165.                          WM_COMMAND,
  166.                          MPFROMSHORT (WinQueryWindowUShort (hwnd, QWS_ID)),
  167.                          MPFROM2SHORT (CMDSRC_OTHER, TRUE)) ;
  168.  
  169.                WinInvalidateRect (hwnd, NULL, FALSE) ;
  170.                return 0 ;
  171.  
  172.           case WM_ENABLE:
  173.                WinInvalidateRect (hwnd, NULL, FALSE) ;
  174.                return 0 ;
  175.  
  176.           case WM_SETFOCUS:
  177.                pSqBtn->fHaveFocus = SHORT1FROMMP (mp2) ;
  178.                WinInvalidateRect (hwnd, NULL, FALSE) ;
  179.                return 0 ;
  180.  
  181.           case WM_CHAR:
  182.                if (!(CHARMSG(&msg)->fs & KC_VIRTUALKEY) ||
  183.                      CHARMSG(&msg)->vkey != VK_SPACE    ||
  184.                      CHARMSG(&msg)->fs & KC_PREVDOWN)
  185.                     break ;
  186.  
  187.                          // Post WM_COMMAND when space bar is released
  188.  
  189.                if (!(CHARMSG(&msg)->fs & KC_KEYUP))
  190.                     pSqBtn->fSpaceDown = TRUE ;
  191.                else
  192.                     {
  193.                     pSqBtn->fSpaceDown = FALSE ;
  194.                     WinPostMsg (WinQueryWindow (hwnd, QW_OWNER, FALSE),
  195.                          WM_COMMAND,
  196.                          MPFROMSHORT (WinQueryWindowUShort (hwnd, QWS_ID)),
  197.                          MPFROM2SHORT (CMDSRC_OTHER, FALSE)) ;
  198.                     }
  199.                WinInvalidateRect (hwnd, NULL, FALSE) ;
  200.                return 0 ;
  201.  
  202.           case WM_PAINT:
  203.                hps = WinBeginPaint (hwnd, NULL, NULL) ;
  204.                DrawButton (hwnd, hps, pSqBtn) ;
  205.                WinEndPaint (hps) ;
  206.                return 0 ;
  207.  
  208.           case WM_DESTROY:
  209.                free (pSqBtn->pszText) ;
  210.                free (pSqBtn) ;
  211.                return 0 ;
  212.           }
  213.      return WinDefWindowProc (hwnd, msg, mp1, mp2) ;
  214.      }
  215.  
  216.           /*--------------------------------------------------------
  217.              Draws filled and outlined polygon (used by DrawButton)
  218.             --------------------------------------------------------*/
  219.  
  220. VOID Polygon (HPS hps, LONG lPoints, POINTL aptl[], LONG lColor)
  221.      {
  222.                // Draw interior in specified color
  223.  
  224.      GpiSavePS (hps) ;
  225.      GpiSetColor (hps, lColor) ;
  226.  
  227.      GpiBeginArea (hps, BA_NOBOUNDARY | BA_ALTERNATE) ;
  228.      GpiMove (hps, aptl) ;
  229.      GpiPolyLine (hps, lPoints - 1, aptl + 1) ;
  230.      GpiEndArea (hps) ;
  231.  
  232.      GpiRestorePS (hps, -1L) ;
  233.  
  234.                // Draw boundary in default color
  235.  
  236.      GpiMove (hps, aptl + lPoints - 1) ;
  237.      GpiPolyLine (hps, lPoints, aptl) ;
  238.      }
  239.  
  240.           /*---------------------
  241.              Draws Square Button
  242.             ---------------------*/
  243.  
  244. VOID DrawButton (HWND hwnd, HPS hps, PSQBTN pSqBtn)
  245.      {
  246.      FATTRS      fat ;
  247.      FONTMETRICS fm ;
  248.      HDC         hdc ;
  249.      LONG        lColor, lHorzRes, lVertRes, cxEdge, cyEdge ;
  250.      POINTL      aptl[10], aptlTextBox[TXTBOX_COUNT], ptlShadow, ptlText ;
  251.      RECTL       rcl ;
  252.  
  253.                // Find 2 millimeter edge width in pixels
  254.  
  255.      hdc = GpiQueryDevice (hps) ;
  256.      DevQueryCaps (hdc, CAPS_HORIZONTAL_RESOLUTION, 1L, &lHorzRes) ;
  257.      DevQueryCaps (hdc, CAPS_VERTICAL_RESOLUTION,   1L, &lVertRes) ;
  258.  
  259.      cxEdge = lHorzRes / 500 ;
  260.      cyEdge = lVertRes / 500 ;
  261.  
  262.                // Set up coordinates for drawing the button
  263.  
  264.      WinQueryWindowRect (hwnd, &rcl) ;
  265.  
  266.      aptl[0].x = 0 ;                    aptl[0].y = 0 ;
  267.      aptl[1].x = cxEdge ;               aptl[1].y = cyEdge ;
  268.      aptl[2].x = rcl.xRight - cxEdge ;  aptl[2].y = cyEdge ;
  269.      aptl[3].x = rcl.xRight - 1 ;       aptl[3].y = 0 ;
  270.      aptl[4].x = rcl.xRight - 1 ;       aptl[4].y = rcl.yTop - 1 ;
  271.      aptl[5].x = rcl.xRight - cxEdge ;  aptl[5].y = rcl.yTop - cyEdge ;
  272.      aptl[6].x = cxEdge ;               aptl[6].y = rcl.yTop - cyEdge ;
  273.      aptl[7].x = 0 ;                    aptl[7].y = rcl.yTop - 1 ;
  274.      aptl[8].x = 0 ;                    aptl[8].y = 0 ;
  275.      aptl[9].x = cxEdge ;               aptl[9].y = cyEdge ;
  276.  
  277.                // Paint edges at bottom and right side
  278.  
  279.      GpiSetColor (hps, CLR_BLACK) ;
  280.      lColor = (pSqBtn->fInsideRect || pSqBtn->fSpaceDown) ?
  281.                               CLR_PALEGRAY : CLR_DARKGRAY ;
  282.      Polygon (hps, 4L, aptl + 0, lColor) ;
  283.      Polygon (hps, 4L, aptl + 2, lColor) ;
  284.  
  285.                // Paint edges at top and left side
  286.  
  287.      lColor = (pSqBtn->fInsideRect || pSqBtn->fSpaceDown) ?
  288.                               CLR_DARKGRAY : CLR_WHITE ;
  289.      Polygon (hps, 4L, aptl + 4, lColor) ;
  290.      Polygon (hps, 4L, aptl + 6, lColor) ;
  291.  
  292.                // Paint interior area
  293.  
  294.      GpiSavePS (hps) ;
  295.      GpiSetColor (hps, (pSqBtn->fInsideRect || pSqBtn->fSpaceDown) ?
  296.                               CLR_DARKGRAY : CLR_PALEGRAY) ;
  297.      GpiMove (hps, aptl + 1) ;
  298.      GpiBox (hps, DRO_FILL, aptl + 5, 0L, 0L) ;
  299.      GpiRestorePS (hps, -1L) ;
  300.      GpiBox (hps, DRO_OUTLINE, aptl + 5, 0L, 0L) ;
  301.  
  302.                // If button has focus, use italic font
  303.  
  304.      GpiQueryFontMetrics (hps, (LONG) sizeof fm, &fm) ;
  305.  
  306.      if (pSqBtn->fHaveFocus)
  307.           {
  308.           fat.usRecordLength  = sizeof fat ;
  309.           fat.fsSelection     = FATTR_SEL_ITALIC ;
  310.           fat.lMatch          = 0 ;
  311.           fat.idRegistry      = fm.idRegistry ;
  312.           fat.usCodePage      = fm.usCodePage ;
  313.           fat.lMaxBaselineExt = fm.lMaxBaselineExt ;
  314.           fat.lAveCharWidth   = fm.lAveCharWidth ;
  315.           fat.fsType          = 0 ;
  316.           fat.fsFontUse       = 0 ;
  317.           strcpy (fat.szFacename, fm.szFacename) ;
  318.  
  319.           GpiCreateLogFont (hps, NULL, LCID_ITALIC, &fat) ;
  320.           GpiSetCharSet (hps, LCID_ITALIC) ;
  321.           }
  322.                // Calculate text position
  323.  
  324.      GpiQueryTextBox (hps, (LONG) strlen (pSqBtn->pszText), pSqBtn->pszText,
  325.                            TXTBOX_COUNT, aptlTextBox) ;
  326.  
  327.      ptlText.x = (rcl.xRight - aptlTextBox[TXTBOX_CONCAT].x) / 2 ;
  328.      ptlText.y = (rcl.yTop   - aptlTextBox[TXTBOX_TOPLEFT].y -
  329.                                aptlTextBox[TXTBOX_BOTTOMLEFT].y) / 2 ;
  330.  
  331.      ptlShadow.x = ptlText.x + fm.lAveCharWidth   / 3 ;
  332.      ptlShadow.y = ptlText.y - fm.lMaxBaselineExt / 8 ;
  333.  
  334.                // Display text shadow in black, and text in white
  335.  
  336.      GpiSetColor (hps, CLR_BLACK) ;
  337.      GpiCharStringAt (hps, &ptlShadow, (LONG) strlen (pSqBtn->pszText),
  338.                                        pSqBtn->pszText) ;
  339.      GpiSetColor (hps, CLR_WHITE) ;
  340.      GpiCharStringAt (hps, &ptlText, (LONG) strlen (pSqBtn->pszText),
  341.                                      pSqBtn->pszText) ;
  342.  
  343.                // X out button if the window is not enabled
  344.  
  345.      if (!WinIsWindowEnabled (hwnd))
  346.           {
  347.           GpiMove (hps, aptl + 1) ;
  348.           GpiLine (hps, aptl + 5) ;
  349.           GpiMove (hps, aptl + 2) ;
  350.           GpiLine (hps, aptl + 6) ;
  351.           }
  352.                // Clean up
  353.  
  354.      if (pSqBtn->fHaveFocus)
  355.           {
  356.           GpiSetCharSet (hps, LCID_DEFAULT) ;
  357.           GpiDeleteSetId (hps, LCID_ITALIC) ;
  358.           }
  359.      }
  360.