home *** CD-ROM | disk | FTP | other *** search
/ Microsoft Programmer's Library 1.3 / Microsoft-Programers-Library-v1.3.iso / sampcode / os2sdk / os2sdk11 / tk3 / calc / calc.c next >
Encoding:
C/C++ Source or Header  |  1989-02-20  |  20.8 KB  |  782 lines

  1. /****************************** Module Header *********************************/
  2. /*                                          */
  3. /* Module Name:  calc.c - Calc application                      */
  4. /*                                          */
  5. /* OS/2 Presentation Manager version of Calc, ported from Windows version     */
  6. /*                                          */
  7. /* Created by Microsoft Corporation, 1987                      */
  8. /*                                          */
  9. /******************************************************************************/
  10.  
  11. #define INCL_WININPUT
  12. #define INCL_WINPOINTERS
  13. #define INCL_WINMENUS
  14. #define INCL_WINSYS
  15. #define INCL_WINCLIPBOARD
  16. #define INCL_GPIPRIMITIVES
  17. #define INCL_GPIBITMAPS
  18. #define INCL_GPILCIDS
  19. #define INCL_DEV
  20. #define INCL_ERRORS
  21. #define INCL_DOSPROCESS
  22. #define INCL_DOSSEMAPHORES
  23. #define INCL_DOSNLS
  24. #include <os2.h>
  25. #include <string.h>
  26. #include <stdlib.h>
  27. #include <stdio.h>
  28. #include "calc.h"
  29.  
  30. /******************************************************************************/
  31. /*                                          */
  32. /*  GLOBAL VARIABLES                                  */
  33. /*                                          */
  34. /******************************************************************************/
  35.  
  36. CHAR  chLastKey, chCurrKey;
  37. CHAR  szreg1[20], szreg2[20], szmem[20], szregx[20];
  38. CHAR  szTitle[30], szErrorString[20], szPlusMinus[2];
  39. SHORT sCharWidth, sCharHeight;
  40. extern BOOL fError;
  41. BOOL  fValueInMemory = FALSE;
  42. BOOL  fMDown = FALSE;               /* TRUE iff 'm' key depressed  */
  43. UCHAR uchMScan = 0;               /* scan code for 'm' key       */
  44.  
  45. #define TOLOWER(x)   ( (((x) >= 'A') && ((x) <= 'Z')) ? (x)|0x20 : (x))
  46. #define WIDTHCONST  28
  47. #define CXCHARS     37
  48. #define CYCHARS     13
  49.  
  50. HAB hab;
  51. HDC hdcLocal;                /* Local used for button bitmap */
  52. HPS hpsLocal;
  53. HDC hdcSqr;                /* Sqr used for square-root bitmap */
  54. HPS hpsSqr;
  55. HBITMAP hbmLocal, hbmSqr;
  56. HMQ  hmqCalc;
  57. HWND hwndCalc, hwndMenu;
  58. HWND hwndCalcFrame;
  59. HPS  hpsCalc;
  60. HDC  hdcCalc;
  61. HPOINTER hptrFinger;
  62.  
  63. DEVOPENSTRUC dop =            /* used by DevOpenDC */
  64. {
  65.     NULL, "DISPLAY", NULL, NULL, NULL, NULL, NULL, NULL, NULL
  66. };
  67.  
  68. static char achKeys[25] =           /* keyboard keys */
  69. {
  70.     '\271', '0', '.', '\261', '+', '=',
  71.     '\272', '1', '2', '3', '-', 'c',
  72.     '\273', '4', '5', '6', '*', '%',
  73.     '\274', '7', '8', '9', '/', 'q',
  74.     NULL
  75. };
  76.  
  77. static CHAR achDKeys[25] =    /* 4th key is plusminus */
  78. {
  79.     ' ', '0', '.', '+', '+', '=',
  80.     ' ', '1', '2', '3', '-', 'C',
  81.     ' ', '4', '5', '6', '*', '%',
  82.     ' ', '7', '8', '9', '/', ' ',
  83.     NULL
  84. };
  85.  
  86. /******************************************************************************/
  87. /*                                          */
  88. /*  PROCEDURE DECLARATIONS                              */
  89. /*                                          */
  90. /******************************************************************************/
  91.  
  92. VOID FarStrcpy( PSZ, PSZ);
  93. MPARAM CALLBACK AboutDlgProc( HWND, USHORT, MPARAM, MPARAM);
  94. BOOL CalcInit(VOID);
  95. VOID CalcPaint( HWND, HPS);
  96. VOID CalcTextOut( HPS, INT, INT, PCH, INT);
  97. MRESULT CALLBACK CalcWndProc( HWND, USHORT, MPARAM, MPARAM);
  98. VOID cdecl main(VOID);
  99. VOID DataXCopy( VOID);
  100. VOID DataXPaste( VOID);
  101. VOID DrawNumbers( HPS);
  102. VOID Evaluate(BYTE);
  103. BOOL FlashSqr( HPS, PWPOINT);
  104. VOID FlipKey( HPS, INT, INT);
  105. VOID FrameKey( HPS, INT, INT);
  106. VOID InitCalc( VOID);
  107. BOOL InterpretChar( CHAR);
  108. VOID ProcessKey( PWPOINT);
  109. BOOL PSInit( VOID);
  110. CHAR Translate( PWPOINT);
  111. VOID UpdateDisplay( VOID);
  112.  
  113.  
  114. /******************************************************************************/
  115. /******************************************************************************/
  116. VOID CalcTextOut( hps, iX, iY, pch, iCount)
  117.  
  118. HPS hps;
  119. INT iX, iY;
  120. PCH pch;
  121. INT iCount;
  122. {
  123.     POINTL ptl;
  124.  
  125.     ptl.x = iX;
  126.     ptl.y = iY;
  127.  
  128.     GpiSetColor( hps, CLR_BLACK);
  129.     GpiCharStringAt( hps, (PPOINTL)&ptl, (LONG)iCount, (PSZ)pch);
  130. }
  131.  
  132.  
  133. /******************************************************************************/
  134. /* Write the appropriate number or error string to the display area          */
  135. /* and mark memory-in-use if appropriate.                      */
  136. /******************************************************************************/
  137. VOID
  138. UpdateDisplay()
  139. {
  140.     RECTL rcl;
  141.  
  142.     rcl.xLeft = (6 * sCharWidth);
  143.     rcl.yBottom = 1050 * sCharHeight / 100;
  144.     rcl.xRight = rcl.xLeft + (12 * sCharWidth);
  145.     rcl.yTop = rcl.yBottom + (3 * sCharHeight) / 2;
  146.  
  147.     WinFillRect( hpsCalc, &rcl, CLR_WHITE);     /* paint display area white */
  148.     if( fError)
  149.     WinDrawText( hpsCalc
  150.            , -1
  151.            , szErrorString
  152.            , &rcl
  153.            , CLR_BLACK
  154.            , CLR_WHITE
  155.            , DT_RIGHT | DT_VCENTER );
  156.     else
  157.     WinDrawText( hpsCalc
  158.            , -1
  159.            , szreg1
  160.            , &rcl
  161.            , CLR_BLACK
  162.            , CLR_WHITE
  163.            , DT_RIGHT | DT_VCENTER );
  164.  
  165.     if (fValueInMemory)         /* little black square shows mem use */
  166.     {
  167.     rcl.xLeft = (6 * sCharWidth);
  168.     rcl.yBottom = 1050 * sCharHeight / 100;
  169.     rcl.xRight = rcl.xLeft + (sCharWidth / 2);
  170.     rcl.yTop = rcl.yBottom + (sCharHeight / 2);
  171.     WinFillRect( hpsCalc, &rcl, CLR_BLACK);
  172.     }
  173. }
  174.  
  175.  
  176. /******************************************************************************/
  177. /*  Display helpful info                              */
  178. /******************************************************************************/
  179. MPARAM CALLBACK
  180. AboutDlgProc( hwnd, msg, mp1, mp2)
  181.  
  182. HWND   hwnd;
  183. USHORT msg;
  184. MPARAM mp1;
  185. MPARAM mp2;
  186. {
  187.     if (msg == WM_COMMAND)
  188.     {
  189.         WinDismissDlg(hwnd, TRUE);
  190.     return(MPFROMSHORT(TRUE));
  191.     }
  192.     else return(WinDefDlgProc( hwnd, msg, mp1, mp2));
  193. }
  194.  
  195.  
  196. /******************************************************************************/
  197. /*  General initialization                              */
  198. /******************************************************************************/
  199. BOOL
  200. CalcInit()
  201. {
  202.     hab = WinInitialize( NULL);
  203.  
  204.     hmqCalc = WinCreateMsgQueue( hab, 0);
  205.     if( !hmqCalc)
  206.         return(FALSE);
  207.  
  208.     WinLoadString( NULL, NULL, 1, 30, (PSZ)szTitle);
  209.     WinLoadString( NULL, NULL, 2, 20, (PSZ)szErrorString);
  210.     WinLoadString( NULL, NULL, 3, 2, (PSZ)szPlusMinus);
  211.  
  212.     if (!WinRegisterClass( hab, szTitle, CalcWndProc, CS_SIZEREDRAW, 0))
  213.         return(FALSE);
  214.  
  215.     hptrFinger = WinLoadPointer( HWND_DESKTOP, (HMODULE)NULL, IDP_FINGER);
  216.  
  217.     InitCalc();             /* arithmetic initialization */
  218.  
  219.     return(TRUE);
  220. }
  221.  
  222. /******************************************************************************/
  223. /*  main procedure                                  */
  224. /******************************************************************************/
  225. VOID cdecl
  226. main()
  227. {
  228.     QMSG  qmsg;
  229.     ULONG ulFCF;
  230.  
  231.     if (!CalcInit()) {                /* general initialization */
  232.     WinAlarm(HWND_DESKTOP, WA_ERROR);
  233.         goto exit;
  234.     }
  235.  
  236.     if (!PSInit()) {                /* presentation spaces & bitmaps */
  237.     WinAlarm(HWND_DESKTOP, WA_ERROR);
  238.         goto exit;
  239.     }
  240.  
  241.     ulFCF = FCF_STANDARD & ~(LONG)(FCF_SIZEBORDER | FCF_MAXBUTTON);
  242.     hwndCalcFrame = WinCreateStdWindow( HWND_DESKTOP
  243.                       , WS_VISIBLE | FS_BORDER
  244.                       , &ulFCF
  245.                       , szTitle
  246.                       , NULL
  247.                       , 0L
  248.                       , NULL
  249.                       , IDR_CALC
  250.                       , &hwndCalc);
  251.  
  252.     WinSetWindowPos( hwndCalcFrame
  253.            , (HWND)NULL
  254.            , 2
  255.            , 2
  256.            , CXCHARS * sCharWidth
  257.            , CYCHARS * sCharHeight
  258.                  + (SHORT)WinQuerySysValue( HWND_DESKTOP
  259.                               , SV_CYTITLEBAR )
  260.                  + (SHORT)WinQuerySysValue( HWND_DESKTOP
  261.                               , SV_CYMENU )
  262.            , SWP_MOVE | SWP_SIZE );
  263.  
  264.     while (WinGetMsg( hab, &qmsg, NULL, 0, 0))
  265.     WinDispatchMsg( hab, &qmsg);
  266.  
  267. exit:                        /* clean up */
  268.     if (hdcSqr)                 /* square-root bitmap */
  269.     {
  270.     GpiDestroyPS( hpsSqr);
  271.     if (hbmSqr)
  272.         GpiDeleteBitmap( hbmSqr);
  273.     }
  274.  
  275.     if (hdcLocal)                /* keypad button */
  276.     {
  277.     GpiDestroyPS( hpsLocal);
  278.     if (hbmLocal)
  279.         GpiDeleteBitmap( hbmLocal);
  280.     }
  281.  
  282.     WinDestroyWindow(hwndCalcFrame);
  283.  
  284.     WinDestroyMsgQueue(hmqCalc);
  285.     WinTerminate(hab);
  286.  
  287.     DosExit(EXIT_PROCESS, 0);            /* exit without error */
  288. }
  289.  
  290.  
  291. /******************************************************************************/
  292. /* Calc Window Procedure                              */
  293. /******************************************************************************/
  294. MRESULT CALLBACK
  295. CalcWndProc(hwnd, msg, mp1, mp2)
  296.  
  297. HWND    hwnd;
  298. USHORT    msg;
  299. MPARAM    mp1;
  300. MPARAM    mp2;
  301. {
  302.     HPS     hps;
  303.     RECTL   rclPaint;
  304.     WPOINT  wpt;
  305.     BOOL    fClip;
  306.     USHORT  usFmtInfo;
  307.     RECTL   rcl;
  308.     SIZEL   sizl;
  309.  
  310.     switch (msg)
  311.     {
  312.     case WM_CREATE:
  313.     hdcCalc = WinOpenWindowDC( hwnd);
  314.     WinQueryWindowRect( hwnd, &rcl);
  315.     sizl.cx = rcl.xRight - rcl.xLeft;
  316.     sizl.cy = rcl.yTop - rcl.yBottom;
  317.     hpsCalc = GpiCreatePS( hab
  318.                  , hdcCalc
  319.                  , &sizl
  320.                  , GPIA_ASSOC | PU_PELS );
  321.         break;
  322.  
  323.     case WM_DESTROY:
  324.         WinDestroyPointer(hptrFinger);
  325.     GpiDestroyPS( hpsSqr);
  326.     GpiDeleteBitmap( hbmSqr);
  327.     GpiDestroyPS( hpsLocal);
  328.     GpiDeleteBitmap( hbmLocal);
  329.         break;
  330.  
  331.     case WM_INITMENU:
  332.         fClip = FALSE;
  333.     if (WinOpenClipbrd( hab))
  334.         {
  335.         fClip = WinQueryClipbrdFmtInfo( hab, CF_TEXT, &usFmtInfo);
  336.         WinCloseClipbrd( hab);
  337.         }
  338.     WinSendMsg((HWND)mp2, MM_SETITEMATTR,
  339.            (MPARAM) MAKELONG(CMD_PASTE, TRUE),
  340.            (MPARAM) MAKELONG(MIA_DISABLED, fClip ? 0 : MIA_DISABLED));
  341.         break;
  342.  
  343.     case WM_PAINT:
  344.     hps = WinBeginPaint(hwnd, NULL, &rclPaint);
  345.     CalcPaint( hwnd, hps);                /* re-draw calculator */
  346.         WinEndPaint(hps);
  347.         break;
  348.  
  349.     case WM_COMMAND:
  350.     if (fError)
  351.             break;
  352.         switch(LOUSHORT(mp1))
  353.         {
  354.         case CMD_COPY:
  355.         DataXCopy();            /* copy to clipboard */
  356.             break;
  357.         case CMD_PASTE:
  358.         DataXPaste();            /* paste from clipboard */
  359.             break;
  360.         case CMD_EXIT:
  361.         WinPostMsg( hwndCalcFrame, WM_QUIT, 0L, 0L);
  362.             break;
  363.         case CMD_ABOUT:
  364.         WinDlgBox( HWND_DESKTOP
  365.              , hwndCalcFrame
  366.              , (PFNWP)AboutDlgProc
  367.              , NULL
  368.              , 1
  369.              , (PSZ)NULL );
  370.             break;
  371.         }
  372.         break;
  373.  
  374.     case WM_MOUSEMOVE:
  375.     WinSetPointer( HWND_DESKTOP, hptrFinger);
  376.         break;
  377.  
  378.     case WM_BUTTON1DOWN:
  379.     wpt.x = LOUSHORT(mp1);
  380.     wpt.y = HIUSHORT(mp1);
  381.     ProcessKey( &wpt);
  382.         goto dwp;
  383.         break;
  384.  
  385.     case WM_CHAR:
  386.     if (SHORT1FROMMP(mp1) & KC_KEYUP)
  387.     {
  388.         if (CHAR4FROMMP(mp1) == uchMScan)
  389.         fMDown = FALSE;         /* 'm' key went up */
  390.     }
  391.     else if (SHORT1FROMMP(mp1) & KC_CHAR)
  392.         {
  393.         if (InterpretChar(CHAR1FROMMP(mp2)))
  394.         UpdateDisplay();
  395.         else if ((CHAR1FROMMP(mp2)=='m') || (CHAR1FROMMP(mp2)=='M'))
  396.         {
  397.         uchMScan = CHAR4FROMMP(mp1);       /* save 'm' key scan code  */
  398.         fMDown = TRUE;               /* 'm' key went down       */
  399.         }
  400.         }
  401.         break;
  402.  
  403.     case WM_ACTIVATE:
  404.         if (HIUSHORT(mp1))
  405.         WinSetFocus( HWND_DESKTOP, hwndCalc);
  406.     break;
  407.  
  408.     case WM_SETFOCUS:
  409.     if ((HWNDFROMMP(mp1)==hwndCalc) && !mp2);
  410.         fMDown = FALSE;            /* since we are losing focus */
  411.     break;
  412.  
  413. dwp:
  414.     default:
  415.         return(WinDefWindowProc(hwnd, msg, mp1, mp2));
  416.         break;
  417.     }
  418.     return(0L);
  419. }
  420.  
  421.  
  422. /******************************************************************************/
  423. /*  translate & interpret keys (ie. locate in logical keyboard)           */
  424. /******************************************************************************/
  425. BOOL
  426. InterpretChar( ch)
  427.  
  428. CHAR ch;
  429. {
  430.     BOOL fDone;
  431.     NPCH pchStep;
  432.     INT  i;
  433.  
  434.     fDone = FALSE;
  435.     pchStep = achKeys;
  436.     switch (ch)
  437.     {
  438.     case 'n':
  439.     ch = szPlusMinus[0];
  440.         break;
  441.     case 27:                        /* xlate Escape into 'c' */
  442.         ch = 'c';
  443.         break;
  444.     case '\r':                      /* xlate Enter into '=' */
  445.         ch = '=';
  446.         break;
  447.     }
  448.  
  449.     if (fMDown)             /* Do memory keys */
  450.     {
  451.         switch (ch)
  452.         {
  453.         case 'c':
  454.         case 'C':
  455.             ch = '\274';
  456.             break;
  457.         case 'r':
  458.         case 'R':
  459.             ch = '\273';
  460.             break;
  461.         case '+':
  462.             ch = '\272';
  463.             break;
  464.         case '-':
  465.             ch = '\271';
  466.             break;
  467.         }
  468.     }
  469.  
  470.     while (!fDone && *pchStep)
  471.     {
  472.     if (*pchStep++ == ch)
  473.         fDone = TRUE;        /* char found in logical keyboard */
  474.     }
  475.     if (fDone)
  476.     {
  477.     chLastKey = chCurrKey;
  478.     i = pchStep - achKeys - 1;
  479.     FlipKey( hpsCalc, i/6, i%6);
  480.     Evaluate( achKeys[i]);
  481.     }
  482.     return (fDone);
  483. }
  484.  
  485.  
  486. /******************************************************************************/
  487. /*  briefly reverse the shading on one of the keys                  */
  488. /******************************************************************************/
  489. VOID
  490. FlipKey( hps, iRow, iCol)
  491.  
  492. HPS hps;
  493. INT iRow, iCol;
  494. {
  495.     RECTL rcl;
  496.  
  497.     rcl.xLeft = (iCol * 6 * sCharWidth) + (14 * sCharWidth / 10);
  498.     rcl.yBottom = (165 * sCharHeight / 100) + (2 * iRow * sCharHeight);
  499.     rcl.xRight = rcl.xLeft + (11 * sCharWidth / 3);
  500.     rcl.yTop = rcl.yBottom + (7 * sCharHeight / 4);
  501.     WinInvertRect( hps, &rcl);
  502.     DosSleep( 50L);
  503.     WinInvertRect( hps, &rcl);
  504. }
  505.  
  506.  
  507. /******************************************************************************/
  508. /*  compute whether a point is over a button and flash the button if so       */
  509. /******************************************************************************/
  510. BOOL
  511. FlashSqr( hps, pwpt)
  512.  
  513. HPS     hps;
  514. PWPOINT  pwpt;
  515. {
  516.     INT  iRow, iCol;
  517.     BOOL fDone;
  518.  
  519.     /* find x range */
  520.     fDone = FALSE;
  521.     iCol = 0;
  522.     iRow = 3;
  523.     while (!fDone && iCol<6)
  524.     {
  525.     if (pwpt->x <    (iCol * 6 * sCharWidth)
  526.                + (14 * sCharWidth / 10)
  527.                + (11*sCharWidth/3)     )
  528.         {
  529.         if (pwpt->x > (iCol * 6 * sCharWidth) + (14 * sCharWidth / 10))
  530.                 fDone = TRUE;
  531.             else
  532.                 return FALSE;
  533.         }
  534.         else
  535.         iCol++;
  536.     }
  537.     if (!fDone)
  538.         return FALSE;
  539.     fDone = FALSE;
  540.     while (!fDone && iRow >= 0)
  541.     {
  542.     if (pwpt->y > ((165 * sCharHeight / 100) + (2 * iRow * sCharHeight)))
  543.         {
  544.         if (pwpt->y <   (165 * sCharHeight / 100)
  545.                + (2 * iRow * sCharHeight)
  546.                + (7 * sCharHeight / 4)     )
  547.                 fDone = TRUE;
  548.             else
  549.                 return FALSE;
  550.         }
  551.         else
  552.         iRow--;
  553.     }
  554.     if (!fDone)
  555.         return FALSE;
  556.     pwpt->x = iCol;
  557.     pwpt->y = iRow;
  558.     FlipKey( hps, iRow, iCol);
  559.     return TRUE;
  560. }
  561.  
  562.  
  563. /******************************************************************************/
  564. /*  which key is point on?                              */
  565. /******************************************************************************/
  566. CHAR
  567. Translate( pwpt)
  568.  
  569. PWPOINT pwpt;
  570. {
  571.     return( achKeys[ pwpt->y * 6 + pwpt->x]);
  572. }
  573.  
  574.  
  575. /******************************************************************************/
  576. /*  invoke flashing, point-to-key translation, and result-display update      */
  577. /******************************************************************************/
  578. VOID
  579. ProcessKey( pwpt)
  580.  
  581. PWPOINT pwpt;
  582. {
  583.     BOOL fFlashed;
  584.  
  585.     chLastKey = chCurrKey;
  586.     fFlashed = FlashSqr( hpsCalc, pwpt);
  587.  
  588.     if (fFlashed)
  589.     Evaluate( (BYTE)Translate( pwpt));
  590.     UpdateDisplay();
  591. }
  592.  
  593.  
  594. /******************************************************************************/
  595. /*  draw a blank key                                  */
  596. /******************************************************************************/
  597. VOID
  598. FrameKey(hps, iRow, iCol)
  599.  
  600. HPS hps;
  601. INT iRow, iCol;
  602. {
  603.     POINTL aptl[3];
  604.  
  605.     aptl[0].x = (iCol * 6 * sCharWidth) + (14 * sCharWidth / 10);
  606.     aptl[0].y = (165 * sCharHeight / 100) + (2 * iRow * sCharHeight);
  607.     aptl[1].x = (11 * sCharWidth / 3) + (aptl[0].x);
  608.     aptl[1].y = (7 * sCharHeight / 4) + (aptl[0].y);
  609.     aptl[2].x = 0;
  610.     aptl[2].y = 0;
  611.     GpiBitBlt( hps, hpsLocal, 3L, aptl, ROP_SRCCOPY, BBO_IGNORE);
  612. }
  613.  
  614.  
  615. /******************************************************************************/
  616. /*  draw the keys and fill in numbers                          */
  617. /******************************************************************************/
  618. VOID
  619. DrawNumbers(hps)
  620.  
  621. HPS hps;
  622. {
  623.     INT iRow, iCol;
  624.  
  625.     /* Draw the keys and fill in the numbers we can */
  626.     for (iRow = 0; iRow < 4; iRow++)
  627.     {
  628.     for (iCol = 0; iCol < 6; iCol++)
  629.         {
  630.         FrameKey( hps, iRow, iCol);
  631.         CalcTextOut( hps
  632.                ,   (iCol * 6 * sCharWidth)
  633.              + (WIDTHCONST * sCharWidth / 10)
  634.                , (iRow + 1) * 2 * sCharHeight
  635.                , (PSZ)(achDKeys + (iRow * 6) + iCol)
  636.                , 1 );
  637.         }
  638.     }
  639. }
  640.  
  641.  
  642. /******************************************************************************/
  643. /*  redraw the whole calculator                           */
  644. /******************************************************************************/
  645. VOID
  646. CalcPaint( hwnd, hps)
  647.  
  648. HWND hwnd;
  649. HPS  hps;
  650. {
  651.     RECTL      rclDst;
  652.     CHARBUNDLE cbnd;
  653.     INT        iX, iY;
  654.  
  655.     WinQueryWindowRect( hwnd, &rclDst);
  656.     WinFillRect( hps, &rclDst, CLR_GREEN);
  657.  
  658.     DrawNumbers(hps);
  659.     CalcTextOut(hps, iX = (11 * sCharWidth / 5) + 1, iY = 2 * sCharHeight,
  660.                (PSZ)"M-", 2);
  661.     CalcTextOut(hps, iX, iY + 2 * sCharHeight, (PSZ)"M+", 2);
  662.     CalcTextOut(hps, iX, iY + 4 * sCharHeight, (PSZ)"MR", 2);
  663.     CalcTextOut(hps, iX, iY + 6 * sCharHeight, (PSZ)"MC", 2);
  664.  
  665.     /* Draw the minus of the plus/minus button */
  666.     cbnd.usBackMixMode = FM_LEAVEALONE;
  667.     GpiSetAttrs( hps, PRIM_CHAR, CBB_BACK_MIX_MODE, 0L, &cbnd);
  668.     iX =  (3 * 6 * sCharWidth) + (WIDTHCONST * sCharWidth / 10);
  669.     CalcTextOut( hps, iX, iY + sCharHeight / 4, (PSZ)"_", 1);
  670.  
  671.     /* Draw the square root bitmap */
  672.     rclDst.xLeft = 160 * sCharWidth / 5;
  673.     rclDst.yBottom = 31 * sCharHeight / 4;
  674.     rclDst.xRight = rclDst.xLeft + 2 * sCharWidth;
  675.     rclDst.yTop = rclDst.yBottom + (3 * sCharHeight / 2);
  676.     WinDrawBitmap( hps
  677.          , hbmSqr
  678.          , NULL
  679.          , (PPOINTL)&rclDst
  680.          , CLR_WHITE
  681.          , CLR_BLACK
  682.          , DBM_STRETCH );
  683.  
  684.     UpdateDisplay();
  685. }
  686.  
  687.  
  688. /******************************************************************************/
  689. /*  initialize the bitmaps for a blank key and for the square-root sign       */
  690. /******************************************************************************/
  691. BOOL
  692. PSInit()
  693. {
  694.     HPS          hps;
  695.     FONTMETRICS      fm;
  696.     POINTL         ptl;
  697.     SIZEL         sizl;
  698.     BITMAPINFOHEADER bmp;
  699.     POINTL         aptl[4];
  700.     LONG         alCaps[2];
  701.  
  702.     /**************************************************************************/
  703.     /*    compute the units of horizontal and vertical distance based on font   */
  704.     /**************************************************************************/
  705.     hps = WinGetPS( HWND_DESKTOP);
  706.     GpiQueryFontMetrics( hps, (LONG)sizeof(FONTMETRICS), &fm);
  707.     sCharHeight = (SHORT)(fm.lEmHeight); /* avg height of uppercase character */
  708.     sCharWidth    = (SHORT)(fm.lEmInc);     /* usually 'M' increment          */
  709.     WinReleasePS( hps);
  710.  
  711.     /**************************************************************************/
  712.     /*    prepare the square root bitmap                          */
  713.     /**************************************************************************/
  714.     hdcSqr = DevOpenDC( hab, OD_MEMORY, "*", 3L, (PDEVOPENDATA)&dop, NULL);
  715.     if( !hdcSqr)
  716.     return(FALSE);
  717.  
  718.     sizl.cx = sizl.cy = 0L;
  719.     hpsSqr = GpiCreatePS( hab
  720.             , hdcSqr
  721.             , &sizl
  722.             , PU_PELS | GPIT_MICRO | GPIA_ASSOC );
  723.     hbmSqr = GpiLoadBitmap( hpsSqr, NULL, IDB_SQR, 0L, 0L);
  724.  
  725.     /**************************************************************************/
  726.     /*    prepare the bitmap of a blank key                      */
  727.     /**************************************************************************/
  728.     hdcLocal = DevOpenDC( hab, OD_MEMORY, "*", 3L, (PDEVOPENDATA)&dop, NULL);
  729.     if( !hdcLocal)
  730.     return(FALSE);
  731.  
  732.     sizl.cx = sizl.cy = 0L;
  733.     hpsLocal = GpiCreatePS( hab
  734.               , hdcLocal
  735.               , &sizl
  736.               , PU_PELS | GPIT_MICRO | GPIA_ASSOC );
  737.     bmp.cbFix = 12;
  738.     bmp.cx = 11 * sCharWidth / 3;
  739.     bmp.cy = sCharHeight * 2;
  740.     DevQueryCaps( hdcLocal, CAPS_COLOR_PLANES, 2L, alCaps);
  741.     bmp.cPlanes = (USHORT)alCaps[0];
  742.     bmp.cBitCount = (USHORT)alCaps[1];
  743.     hbmLocal = GpiCreateBitmap( hpsLocal, &bmp, 0L, NULL, NULL);
  744.     if( !hbmLocal )
  745.     return(FALSE);
  746.     GpiSetBitmap( hpsLocal, hbmLocal);
  747.  
  748.     aptl[0].x = aptl[0].y = 0;
  749.     aptl[1].x = 11 * sCharWidth / 3;
  750.     aptl[1].y = 7 * sCharHeight / 4;
  751.     aptl[2].x = aptl[2].y = 0;
  752.     aptl[3].x = aptl[1].x;
  753.     aptl[3].y = aptl[1].y;
  754.     GpiSetColor( hpsLocal, CLR_GREEN);        /* match the background to client */
  755.     GpiBitBlt( hpsLocal, NULL, 2L, aptl, ROP_PATCOPY, BBO_IGNORE);
  756.  
  757.     /* Draw the rounded rect */
  758.     ptl.x = 0;
  759.     ptl.y = 0;
  760.     GpiSetCurrentPosition( hpsLocal, &ptl);
  761.     ptl.x = (11 * sCharWidth / 3) - 1;
  762.     ptl.y = (7 * sCharHeight / 4) - 1;
  763.     GpiSetColor( hpsLocal, CLR_WHITE);        /* white interior              */
  764.     GpiBox( hpsLocal
  765.       , DRO_FILL
  766.       , &ptl
  767.       , (LONG)sCharWidth
  768.       , (LONG)(sCharHeight / 2) );
  769.     ptl.x = 0;
  770.     ptl.y = 0;
  771.     GpiSetCurrentPosition( hpsLocal, &ptl);
  772.     ptl.x = (11 * sCharWidth / 3) - 1;
  773.     ptl.y = (7 * sCharHeight / 4) - 1;
  774.     GpiSetColor( hpsLocal, CLR_BLACK);        /* black border              */
  775.     GpiBox( hpsLocal
  776.       , DRO_OUTLINE
  777.       , &ptl
  778.       , (LONG)sCharWidth
  779.       , (LONG)(sCharHeight / 2) );
  780.     return( TRUE);
  781. }
  782.