home *** CD-ROM | disk | FTP | other *** search
/ PC World Komputer 1998 April A / Pcwk4a98.iso / PROGRAM / DELPHI16 / Calc / CALC.PAS
Pascal/Delphi Source File  |  1995-06-01  |  9KB  |  416 lines

  1. unit Calc;
  2.  
  3. {$F+,O+,S-}
  4.  
  5. {     Calculator object.
  6.     Modified from the Borland Demo by Sanford Aranoff. }
  7.  
  8. interface
  9.  
  10. uses Drivers, Objects, Views, Dialogs, general;
  11.  
  12.  
  13. type
  14.  
  15.   TCalcState = (csFirst, csValid, csError);
  16.  
  17.   PCalcDisplay = ^TCalcDisplay;
  18.   TCalcDisplay = object(TView)
  19.     Status    : TCalcState;
  20.     Num1,
  21.     Num2,
  22.     Number    : string[79];
  23.     Sign        : Char;
  24.     Operator: Char;
  25.     PriorOp,
  26.     Operand    : Double;
  27.     constructor Init (var Bounds: TRect);
  28.     constructor Load (var S: TStream);
  29.     procedure CalcKey (Key: Char);
  30.     procedure Clear;
  31.     procedure Draw; virtual;
  32.     function GetPalette: PPalette; virtual;
  33.     procedure HandleEvent (var Event: TEvent); virtual;
  34.     procedure Store (var S: TStream);
  35.   end;
  36.  
  37.   PCalculator = ^TCalculator;
  38.   TCalculator = object(TDialog)
  39.     constructor Init;
  40.   end;
  41.  
  42. const
  43.   RCalcDisplay: TStreamRec = (
  44.      ObjType: 10040;
  45.      VmtLink: Ofs (TypeOf (TCalcDisplay)^);
  46.      Load:    @TCalcDisplay.Load;
  47.      Store:   @TCalcDisplay.Store
  48.   );
  49.   RCalculator: TStreamRec = (
  50.      ObjType: 10041;
  51.      VmtLink: Ofs (TypeOf (TCalculator)^);
  52.      Load:    @TCalculator.Load;
  53.      Store:   @TCalculator.Store
  54.   );
  55.  
  56. PROCEDURE NuAdd(VAR s : String; const source : String);
  57. PROCEDURE NuAdd1(VAR s : String; const let: char);
  58. PROCEDURE NuAdd2(VAR s : String; const source : String;
  59.  
  60. procedure RegisterCalc;
  61.  
  62. implementation
  63.  
  64. const
  65.     plus                = '+';
  66.    minus             = '-';
  67.    equals         = '=';
  68.       cmCalcButton     = 100;
  69.    equals13       = [equals, #13];
  70.  
  71. var
  72.     R1,R2        : double;
  73.     n            : integer;
  74.    lin_calc,
  75.    Ln            : string[80];
  76.  
  77.  
  78.  
  79. constructor TCalcDisplay.Init (var Bounds: TRect);
  80. begin
  81.    inherited Init (Bounds);
  82.    Options:= Options or ofSelectable;
  83.    EventMask:= evKeyDown + evBroadcast;
  84.    Clear;
  85. end;
  86.  
  87. constructor TCalcDisplay.Load (var S: TStream);
  88. begin
  89.    inherited Load (S);
  90.    S.Read (Status, SizeOf (Status) + SizeOf (Number) + SizeOf (Sign) +
  91.       SizeOf (Operator) + SizeOf (Operand));
  92. end;
  93.  
  94. procedure NuAdd;
  95. var
  96.     i,j    : word;
  97. begin
  98.     i:= byte(source[0]);
  99.    j:= byte(s[0]);
  100.    if i+j >= $FF then
  101.        exit;
  102.    move(source[1],s[succ(j)],i);
  103.    inc(s[0],i)
  104.    {Move(source[1], s[succ(length(s))], length(source));
  105.    Inc(s[0], length(source))}
  106. END;
  107.  
  108. procedure nuadd1;
  109. begin
  110.     {s + let}
  111.    inc(s[0]);
  112.     s[byte(s[0])]:= let
  113. end;
  114.  
  115. procedure NuAdd2;
  116. begin
  117.     {s + source + let}
  118.     if byte(source[0]) + byte(s[0]) >= $ff then
  119.        exit;
  120.    inc(s[0]);
  121.    Move(source[1], s[byte(s[0])], byte(source[0]));
  122.    Inc(s[0], byte(source[0]));
  123.     s[byte(s[0])]:= let
  124. END;
  125.  
  126. procedure TCalcDisplay.CalcKey (Key: Char);
  127. var
  128.       R        : Double;
  129.    E,
  130.      i,j,k    : integer;
  131.  
  132. procedure Error;
  133. begin
  134.    Status:= csError;
  135.    Num1:= '0';
  136.    Num2:= '0';
  137.    Number:= 'Error';
  138.    R1:= 0;
  139.    R2:= 0;
  140.    Sign:= blank
  141. end;
  142.  
  143. procedure SetDisplay (R: Double);
  144. var
  145.   S: string[63];
  146. begin
  147.    Str (R:0:10, S);
  148.    if  S[1] <> minus  then
  149.         Sign:= blank
  150.    else begin
  151.       Delete (S, 1, 1);
  152.       Sign:= minus
  153.    end;
  154.    if  byte(S[0]) > 79  then
  155.       Error
  156.       {15 + 1 + 10 then Error}
  157.    else begin
  158.       while  S[byte(S[0])] = '0'  do
  159.             Dec (S[0]);
  160.       if  S[byte(S[0])] = period  then
  161.             Dec (S[0]);
  162.       Number:= S
  163.    end
  164. end;
  165.  
  166. procedure GetDisplay (var R: Double);
  167. begin
  168.    Val (Sign + Number, R, E)
  169. end;
  170.  
  171. procedure GetPriorDisplay (var R: Double);
  172. begin
  173.    Val (Num1, R, E)
  174. end;
  175.  
  176. procedure CheckFirst;
  177. begin
  178.    if  Status = csFirst  then
  179.    begin
  180.       Status:= csValid;
  181.        Num1:= '0';
  182.       Num2:= '0';
  183.       Number:= '0';
  184.       Sign:= blank
  185.    end
  186. end;
  187.  
  188. begin
  189.    Key:= UpCase (Key);
  190.    if  (Status = csError) and not (Key in ['C',esc]) then
  191.         Key:= blank;
  192.    case  Key  of
  193.       '0'..'9':
  194.       begin
  195.          CheckFirst;
  196.          if  Number = '0'  then
  197.                 Number:= '';
  198.          nuadd1(number,key);
  199.          if  Num2 = '0'  then
  200.                 Num2:= '';
  201.          nuadd1(Num2,key);
  202.  
  203.          if byte(lin_calc[0]) >= 72 then
  204.              Nudelete(lin_calc,1,1);
  205.          nuadd1(lin_calc,key)
  206.       end;
  207.       period:
  208.       begin
  209.          CheckFirst;
  210.          if  Pos (period, Number) = 0  then
  211.          begin
  212.              nuadd1(number,period);
  213.             nuadd1(num2,period);
  214.             if byte(lin_calc[0]) >= 72 then
  215.                 delete(lin_calc,1,1);
  216.             nuadd1(lin_calc,period)
  217.          end
  218.       end;
  219.       #8:
  220.       begin
  221.          CheckFirst;
  222.          dec(lin_calc[0]);
  223.          if  byte(Number[0]) = 1  then
  224.                 Number:= '0'
  225.          else
  226.                 Dec (Number[0])
  227.       end;
  228.       '_', #241: begin  {+-}
  229.          if  Sign = blank  then
  230.                 Sign:= minus
  231.          else
  232.                 Sign:= blank;
  233.          if byte(lin_calc[0]) >= 72 then
  234.              delete(lin_calc,1,1);
  235.          i:= 0;
  236.          k:= byte(lin_calc[0]);
  237.          if k > 0 then
  238.          for j:= 1 to k do
  239.              if lin_calc[j] = blank then
  240.                 i:= j;
  241.          NuInsert(sign,lin_calc,succ(i))
  242.       end;
  243.       plus, minus, star, slash, equals, '%', #13:
  244.       begin
  245.           if (key in [star,slash]) and not (Operator in [star,slash]) then
  246.          begin
  247.                 Num1:= Sign + Num2;
  248.              val(Num1,R1,E);
  249.              if operator = minus then
  250.                  R1:= -R1
  251.          end;
  252.          if byte(lin_calc[0]) >= 72 then
  253.              delete(lin_calc,1,1);
  254.          if not (key in equals13) then
  255.              nuadd1(lin_calc,key);
  256.          if  Status = csValid  then
  257.          begin
  258.             Status:= csFirst;
  259.             GetDisplay (R);
  260.             if Operator in [star,slash] then
  261.                val(Num2,R2,E);
  262.             if  Key = '%'  then
  263.             begin
  264.                case  Operator  of
  265.                   plus, minus: R:= Operand * R / 100;
  266.                   star, slash: R:= R / 100
  267.                end;
  268.                R2:= R2/100
  269.             end;
  270.             if Operator in [plus,minus] then
  271.                 PriorOp:= Operand;
  272.             case  Operator  of
  273.                plus    : SetDisplay (Operand + R);
  274.                minus    : SetDisplay (Operand - R);
  275.                star    : begin
  276.                    R1:= R1*R2;
  277.                         SetDisplay (PriorOp + R1)
  278.                         {(Operand * R);}
  279.                end;
  280.                slash    :
  281.                   if  R2 = 0  then
  282.                             Error
  283.                   else begin
  284.                       R1:= R1/R2;
  285.                             SetDisplay(PriorOp + R1)
  286.                   end
  287.                                 {(Operand / R);}
  288.             end
  289.          end;
  290.          if key in equals13 then
  291.          begin
  292.              PriorOp:= 0;
  293.              ln:= equals;
  294.                 if sign = minus then
  295.                     nuadd1(ln,minus);
  296.                 nuadd2(ln,number,blank);
  297.             n:= byte(ln[0]);
  298.             if byte(lin_calc[0]) + n >= 72 then
  299.                 delete(lin_calc,1, (byte(lin_calc[0])+n-80));
  300.             nuadd(lin_calc,ln)
  301.          end;
  302.          Operator:= Key;
  303.          GetDisplay (Operand)
  304.       end;
  305.       'C', esc: Clear;
  306.       else begin
  307.          if byte(lin_calc[0]) >= 72 then
  308.              delete(lin_calc,1,1);
  309.          nuadd1(lin_calc,blank);
  310.          PriorOp:= 0;
  311.          number:= '0'
  312.       end
  313.    end;
  314.    DrawView
  315. end;
  316.  
  317. procedure TCalcDisplay.Clear;
  318. begin
  319.    Status:= csFirst;
  320.    Num1:= '0';
  321.    Num2:= '0';
  322.    Number:= '0';
  323.    R1:= 0;
  324.    R2:= 0;
  325.    lin_calc:= '';
  326.    PriorOp:= 0;
  327.    Sign:= blank;
  328.    Operator:= equals
  329. end;
  330.  
  331. procedure TCalcDisplay.Draw;
  332. var
  333.   Color: Byte;
  334.   I: Integer;
  335.   B: TDrawBuffer;
  336. begin
  337.      i:= byte(lin_calc[0]);
  338.    if i >= 72 then
  339.        delete(lin_calc,1,i-72);
  340.    Color:= GetColor (1);
  341.    I:= Size.X - byte(lin_calc[0]) - 2;
  342.    MoveChar (B, blank, Color, Size.X);
  343.    {MoveChar (B[I], Sign, Color, 1);}
  344.    MoveStr (B[I + 1], lin_calc, Color);
  345.    WriteBuf (0, 0, Size.X, 1, B);
  346. end;
  347.  
  348. function TCalcDisplay.GetPalette: PPalette;
  349. const
  350.   P: string[1] = #19;
  351. begin
  352.    GetPalette:= @P
  353. end;
  354.  
  355. procedure TCalcDisplay.HandleEvent (var Event: TEvent);
  356. begin
  357.    inherited HandleEvent (Event);
  358.    case  Event.What  of
  359.       evKeyDown:
  360.       begin
  361.          CalcKey (Event.CharCode);
  362.          ClearEvent (Event)
  363.       end;
  364.       evBroadcast:
  365.          if  Event.Command = cmCalcButton  then
  366.          begin
  367.             CalcKey (PButton (Event.InfoPtr)^.Title^[1]);
  368.             ClearEvent (Event);
  369.          end;
  370.    end;
  371. end;
  372.  
  373. procedure TCalcDisplay.Store (var S: TStream);
  374. begin
  375.    TView.Store (S);
  376.    S.Write (Status, SizeOf (Status) + SizeOf (Number) + SizeOf (Sign) +
  377.       SizeOf (Operator) + SizeOf (Operand));
  378. end;
  379.  
  380. { TCalculator }
  381.  
  382. constructor TCalculator.Init;
  383. const
  384.   KeyChar: array[0..19] of Char = 'C'#27'%'#241'789/456*123-0.=+';
  385. var
  386.   I: Integer;
  387.   P: PView;
  388.   R: TRect;
  389. begin
  390.    lin_calc:= blank;
  391.    R.Assign (0, 3, 79, 18);
  392.    inherited Init (R, 'Calculator');
  393.    Options:= Options or ofFirstClick;
  394.    for  I:= 0 to 19  do
  395.    begin
  396.       R.A.X:= (I mod 4) * 5 + 2;
  397.       R.A.Y:= (I div 4) * 2 + 4;
  398.       R.B.X:= R.A.X + 5;
  399.       R.B.Y:= R.A.Y + 2;
  400.       P:= New (PButton, Init (R, KeyChar[I], cmCalcButton,
  401.          bfNormal + bfBroadcast));
  402.       P^.Options:= P^.Options and not ofSelectable;
  403.       Insert (P);
  404.    end;
  405.    R.Assign (1, 2, 78, 3);
  406.    Insert (New (PCalcDisplay, Init (R)));
  407. end;
  408.  
  409. procedure RegisterCalc;
  410. begin
  411.    RegisterType (RCalcDisplay);
  412.    RegisterType (RCalculator)
  413. end;
  414.  
  415. end.
  416.