home *** CD-ROM | disk | FTP | other *** search
/ C Programming Starter Kit 2.0 / SamsPublishing-CProgrammingStarterKit-v2.0-Win31.iso / bc45 / calc.pak / CALC.CPP next >
C/C++ Source or Header  |  1997-07-23  |  8KB  |  407 lines

  1. //----------------------------------------------------------------------------
  2. // ObjectWindows - (C) Copyright 1991 by Borland International
  3. //    Simple four function calculator
  4. //----------------------------------------------------------------------------
  5. #include <owl\owlpch.h>
  6. #include <owl\applicat.h>
  7. #include <owl\dc.h>
  8. #include <owl\dialog.h>
  9. #include <owl\framewin.h>
  10. #include <cstring.h>
  11. #include <ctype.h>
  12. #include <math.h>
  13. #include <stdio.h>
  14. #include <stdlib.h>
  15.  
  16. #define min(a,b)   (((a) <(b)) ? (a) :(b))
  17.  
  18. const char AppName[] = "Calc"; // Name of app, window title & icon resource id
  19.  
  20. const int DisplayDigits = 15;  // number of digits in calculator display
  21.  
  22. const int ID_DISPLAY = 400;    // control ID of display static text
  23.  
  24. enum TCalcState {CS_FIRST, CS_VALID, CS_ERROR};  // calculator state
  25.  
  26. // Calculator dialog window object
  27. //
  28. class TCalc : public TDialog {
  29.   public:
  30.     TCalcState  CalcStatus;
  31.     char        Operator;
  32.     char        Number[DisplayDigits + 1];
  33.     BOOL        Negative;
  34.     double      Operand;
  35.     TBrush      BlueBrush;
  36.  
  37.     TCalc();
  38.  
  39.     void          FlashButton(char key);
  40.     void          Error();
  41.  
  42.     void          SetDisplay(double r);
  43.     void          GetDisplay(double& r);
  44.     virtual void  UpdateDisplay();
  45.  
  46.     void          CheckFirst();
  47.     void          InsertKey(char key);
  48.     void          CalcKey(char key);
  49.     void          Clear();
  50.  
  51.   protected:
  52.     //
  53.     // override EvCommand() defined by class TWindow
  54.     //
  55.     LRESULT       EvCommand(UINT, HWND, UINT);
  56.  
  57.     void          EvPaint();
  58.  
  59.     //
  60.     // message response functions
  61.     //
  62.     HBRUSH        EvCtlColor(HDC, HWND hWndChild, UINT ctlType);
  63.  
  64.   DECLARE_RESPONSE_TABLE(TCalc);
  65. };
  66.  
  67. DEFINE_RESPONSE_TABLE1(TCalc, TDialog)
  68.   EV_WM_PAINT,
  69.   EV_WM_CTLCOLOR,
  70. END_RESPONSE_TABLE;
  71.  
  72. //
  73. // Calculator constructor.  Create blue brush for calculator background,
  74. // and do a clear command.
  75. //
  76. TCalc::TCalc()
  77.   : TWindow((TWindow*)0),
  78.     TDialog(0, AppName),
  79.     BlueBrush(TColor(0, 0, 255))
  80. {
  81.   Clear();
  82. }
  83.  
  84. //
  85. // Colorize the calculator. Allows background to show through corners of
  86. //  buttons, uses yellow text on black background in the display, and sets
  87. //  the dialog background to blue.
  88. //
  89. HBRUSH
  90. TCalc::EvCtlColor(HDC hDC, HWND hWndChild, UINT ctlType)
  91. {
  92.   switch (ctlType) {
  93.     case CTLCOLOR_BTN:
  94.       SetBkMode(hDC, TRANSPARENT);
  95.       return (HBRUSH)GetStockObject(NULL_BRUSH);
  96.  
  97.     case CTLCOLOR_STATIC:
  98.       SetTextColor(hDC, TColor::LtYellow);
  99.       SetBkMode(hDC, TRANSPARENT);
  100.       return (HBRUSH)GetStockObject(BLACK_BRUSH);
  101.  
  102.     case CTLCOLOR_DLG:
  103.       SetBkMode(hDC, TRANSPARENT);
  104.       return (HBRUSH)BlueBrush;
  105.  
  106.     default:
  107.       return TDialog::EvCtlColor(hDC, hWndChild, ctlType);
  108.   }
  109. }
  110.  
  111. //
  112. // Even dialogs can have their backgrounds painted on.  This creates
  113. //  a red ellipse over the blue background.
  114. //
  115. void
  116. TCalc::EvPaint()
  117. {
  118.   TBrush    redBrush(TColor(255, 0, 0));
  119.   TPaintDC  dc(*this);
  120.  
  121.   dc.SelectObject(redBrush);
  122.   dc.SelectStockObject(NULL_PEN);
  123.  
  124.   TRect clientRect = GetClientRect();
  125.   clientRect.bottom = clientRect.right;
  126.   clientRect.Offset(-clientRect.right/4, -clientRect.right/4);
  127.   dc.Ellipse(clientRect);
  128. }
  129.  
  130. //
  131. // Flash a button with the value of Key.  Looks exactly like a
  132. // click of the button with the mouse.
  133. //
  134. void
  135. TCalc::FlashButton(char key)
  136. {
  137.   if (key == 0x0D)
  138.      key = '=';  // Treat Enter like '='
  139.  
  140.   HWND button = GetDlgItem(toupper(key));
  141.  
  142.   if (button) {
  143.     ::SendMessage(button, BM_SETSTATE, 1, 0);
  144.  
  145.     for (int delay = 1; delay <= 30000; ++delay)
  146.       ;
  147.  
  148.     ::SendMessage(button, BM_SETSTATE, 0, 0);
  149.   }
  150. }
  151.  
  152. //
  153. // here we handle all of the child id notifications (BN_CLICKED from the
  154. // buttons) and all accelerators at once rather than have separate response
  155. // table entries for each...
  156. //
  157. LRESULT
  158. TCalc::EvCommand(UINT id, HWND hWndCtl, UINT notifyCode)
  159. {
  160.   if (hWndCtl != 0 && notifyCode == BN_CLICKED)
  161.     CalcKey(char(id));  // button notification
  162.  
  163.   else if (hWndCtl == 0 && notifyCode == 1) {
  164.     //
  165.     // from an accelerator
  166.     //
  167.     FlashButton(char(id));
  168.     CalcKey(char(id));
  169.   }
  170.  
  171.   return TDialog::EvCommand(id, hWndCtl, notifyCode);
  172. }
  173.  
  174. //
  175. // Set Display text to the current value.
  176. //
  177. void
  178. TCalc::UpdateDisplay()
  179. {
  180.   char  str[DisplayDigits + 2];
  181.  
  182.   if (Negative)
  183.     strcpy(str, "-");
  184.  
  185.   else
  186.     str[0] = '\0';
  187.  
  188.   ::SetWindowText(GetDlgItem(ID_DISPLAY), strcat(str, Number));
  189. }
  190.  
  191. //
  192. // Clear the calculator.
  193. //
  194. void
  195. TCalc::Clear()
  196. {
  197.   CalcStatus = CS_FIRST;
  198.   strcpy(Number, "0");
  199.   Negative = FALSE;
  200.   Operator = '=';
  201. }
  202.  
  203. void
  204. TCalc::Error()
  205. {
  206.   CalcStatus = CS_ERROR;
  207.   strcpy(Number, "Error");
  208.   Negative = FALSE;
  209. }
  210.  
  211. void
  212. TCalc::SetDisplay(double r)
  213. {
  214.   char*  first;
  215.   char*  last;
  216.   int    charsToCopy;
  217.   char   str[64];
  218.  
  219.   //
  220.   // limit results of calculations to 7 digits to the right of the dec. point
  221.   //
  222.   r = (floor(r * 10000000L + .5)) / 10000000L;
  223.  
  224.   sprintf(str, "%0.10f", r);
  225.   first = str;
  226.   Negative = FALSE;
  227.  
  228.   if (str[0] == '-') {
  229.     first++;
  230.     Negative = TRUE;
  231.   }
  232.  
  233.   if (strlen(first) > DisplayDigits + 1 + 10 )
  234.     Error();
  235.  
  236.   else {
  237.     last = strchr(first, 0);
  238.  
  239.     while (last[-1] == '0')
  240.       --last;
  241.  
  242.     if (last[-1] == '.')
  243.       --last;
  244.  
  245.     charsToCopy = min(DisplayDigits + 1, int(last - first));
  246.     strncpy(Number, first, charsToCopy);
  247.     Number[charsToCopy] = 0;
  248.   }
  249. }
  250.  
  251. void
  252. TCalc::GetDisplay(double& r)
  253. {
  254.   r = atof(Number);
  255.  
  256.   if (Negative)
  257.     r = -r;
  258. }
  259.  
  260. void
  261. TCalc::CheckFirst()
  262. {
  263.   if (CalcStatus == CS_FIRST) {
  264.     CalcStatus = CS_VALID;
  265.     strcpy(Number, "0");
  266.     Negative = FALSE;
  267.   }
  268. }
  269.  
  270. void
  271. TCalc::InsertKey(char key)
  272. {
  273.   int l = strlen(Number);
  274.  
  275.   if (l < DisplayDigits) {
  276.     Number[l] = key;
  277.     Number[l + 1] = 0;
  278.   }
  279. }
  280.  
  281. //
  282. // Process calculator key.
  283. //
  284. void
  285. TCalc::CalcKey(char key)
  286. {
  287.   key = (char)toupper(key);
  288.  
  289.   if (CalcStatus == CS_ERROR && key != 'C')
  290.     key = ' ';
  291.  
  292.   if (key >= '0' && key <= '9') {
  293.     CheckFirst();
  294.  
  295.     if (strcmp(Number, "0") == 0)
  296.       Number[0] = '\0';
  297.  
  298.     InsertKey(key);
  299.  
  300.   } else if (key == '+' || key == '-' || key == '*' ||
  301.              key == '/' || key == '=' || key == '%' || key == 0x0D) {
  302.  
  303.     if (CalcStatus == CS_VALID) {
  304.       CalcStatus = CS_FIRST;
  305.       double  r;
  306.       GetDisplay(r);
  307.  
  308.       if (key == '%') {
  309.         switch(Operator) {
  310.           case '+':
  311.           case '-':
  312.             r = Operand * r / 100;
  313.             break;
  314.  
  315.           case '*':
  316.           case '/':
  317.             r /= 100;
  318.             break;
  319.         }
  320.       }
  321.  
  322.       switch(Operator) {
  323.         case '+':
  324.           SetDisplay(Operand + r);
  325.           break;
  326.  
  327.         case '-':
  328.           SetDisplay(Operand - r);
  329.           break;
  330.  
  331.         case '*':
  332.           SetDisplay(Operand * r);
  333.           break;
  334.  
  335.         case '/':
  336.           if (r == 0)
  337.             Error();
  338.  
  339.           else
  340.             SetDisplay(Operand / r);
  341.           break;
  342.       }
  343.     }
  344.  
  345.     Operator = key;
  346.     GetDisplay(Operand);
  347.  
  348.   } else
  349.     switch(key) {
  350.       case '.':
  351.         CheckFirst();
  352.         if (!strchr(Number, '.'))
  353.           InsertKey(key);
  354.         break;
  355.  
  356.       case 0x8:
  357.         CheckFirst();
  358.         if (strlen(Number) == 1)
  359.           strcpy(Number, "0");
  360.         else
  361.           Number[strlen(Number) - 1] = '\0';
  362.         break;
  363.  
  364.       case '_':
  365.         Negative = !Negative;
  366.         break;
  367.  
  368.       case 'C':
  369.         Clear();
  370.         break;
  371.     }
  372.  
  373.   UpdateDisplay();
  374. }
  375.  
  376. //----------------------------------------------------------------------------
  377.  
  378. //
  379. // Calculator application object
  380. //
  381. class TCalcApp : public TApplication {
  382.   public:
  383.     TCalcApp(const char far* name) : TApplication(name) {}
  384.  
  385.     void   InitMainWindow();
  386. };
  387.  
  388. //
  389. // Create calculator as the application's main window.
  390. //
  391. void
  392. TCalcApp::InitMainWindow()
  393. {
  394.   TWindow* calcWin = new TCalc;
  395.   calcWin->Attr.AccelTable = AppName;
  396.  
  397.   MainWindow = new TFrameWindow(0, Name, calcWin, TRUE);
  398.   MainWindow->SetIcon(this, AppName);
  399.   MainWindow->Attr.Style &= ~(WS_MAXIMIZEBOX | WS_THICKFRAME);
  400. }
  401.  
  402. int
  403. OwlMain(int /*argc*/, char* /*argv*/ [])
  404. {
  405.   return TCalcApp(AppName).Run();
  406. }
  407.