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

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