fpcalc.pas 10 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433
  1. {
  2. $Id$
  3. This file is part of the Free Pascal Integrated Development Environment
  4. Copyright (c) 1998 by Berczi Gabor
  5. Calculator object for the IDE
  6. See the file COPYING.FPC, included in this distribution,
  7. for details about the copyright.
  8. This program is distributed in the hope that it will be useful,
  9. but WITHOUT ANY WARRANTY; without even the implied warranty of
  10. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.
  11. **********************************************************************}
  12. unit FPCalc;
  13. interface
  14. uses
  15. Drivers,Objects,Commands,Views,Dialogs,App,
  16. FPViews;
  17. const
  18. MaxDecimals = 10;
  19. MaxDigits = 30;
  20. type
  21. TCalcState = (csFirst, csValid, csError);
  22. PCalcButton = ^TCalcButton;
  23. TCalcButton = object(TButton)
  24. procedure HandleEvent(var Event: TEvent); virtual;
  25. end;
  26. PCalcDisplay = ^TCalcDisplay;
  27. TCalcDisplay = object(TView)
  28. Status: TCalcState;
  29. Number: string[MaxDigits];
  30. Sign: Char;
  31. _Operator: Char;
  32. Operand: extended;
  33. Memory: extended;
  34. DispNumber: extended;
  35. constructor Init(var Bounds: TRect);
  36. constructor Load(var S: TStream);
  37. function CalcKey(Key: string): boolean;
  38. procedure Clear;
  39. procedure Draw; virtual;
  40. function GetPalette: PPalette; virtual;
  41. procedure HandleEvent(var Event: TEvent); virtual;
  42. procedure Store(var S: TStream);
  43. private
  44. procedure GetDisplay(var R: extended);
  45. procedure SetDisplay(R: extended);
  46. procedure Error;
  47. end;
  48. PCalculator = ^TCalculator;
  49. TCalculator = object(TCenterDialog)
  50. CD : PCalcDisplay;
  51. constructor Init;
  52. procedure HandleEvent(var Event: TEvent); virtual;
  53. procedure Show; virtual;
  54. procedure Close; virtual;
  55. end;
  56. const
  57. RCalcDisplay: TStreamRec = (
  58. ObjType: 10040;
  59. VmtLink: Ofs(TypeOf(TCalcDisplay)^);
  60. Load: @TCalcDisplay.Load;
  61. Store: @TCalcDisplay.Store
  62. );
  63. RCalculator: TStreamRec = (
  64. ObjType: 10041;
  65. VmtLink: Ofs(TypeOf(TCalculator)^);
  66. Load: @TCalculator.Load;
  67. Store: @TCalculator.Store
  68. );
  69. procedure RegisterCalc;
  70. implementation
  71. uses FPUtils,FPConst;
  72. const
  73. cmCalcButton = 100;
  74. cmPressButton = 101;
  75. procedure TCalcButton.HandleEvent(var Event: TEvent);
  76. var
  77. Call : boolean;
  78. i : Sw_Word;
  79. begin
  80. Call:=true;
  81. case Event.What of
  82. evKeyDown :
  83. case Event.KeyCode of
  84. kbEnter : Call:=false;
  85. end;
  86. evBroadcast :
  87. case Event.Command of
  88. cmDefault : Call:=false;
  89. cmPressButton :
  90. begin
  91. if (PString(Event.InfoPtr)^=Title^) or
  92. ((PString(Event.InfoPtr)^='^') and (Title^='x^y')) then
  93. begin
  94. Select;
  95. DrawState(true);
  96. i:=GetDosTicks+2;
  97. repeat
  98. until GetDosTicks>i;
  99. DrawState(false);
  100. ClearEvent(Event);
  101. end;
  102. end;
  103. end;
  104. end;
  105. if Call then
  106. inherited HandleEvent(Event);
  107. end;
  108. constructor TCalcDisplay.Init(var Bounds: TRect);
  109. begin
  110. inherited Init(Bounds);
  111. Options := Options or ofSelectable;
  112. EventMask := evKeyDown + evBroadcast;
  113. Clear;
  114. HelpCtx:={hcCalculatorLine}0;
  115. end;
  116. constructor TCalcDisplay.Load(var S: TStream);
  117. begin
  118. inherited Load(S);
  119. S.Read(Status, SizeOf(Status) + SizeOf(Number) + SizeOf(Sign) +
  120. SizeOf(_Operator) + SizeOf(Operand));
  121. end;
  122. procedure TCalcDisplay.GetDisplay(var R: extended);
  123. begin
  124. { Val(Sign + Number, R, E);}
  125. R:=DispNumber;
  126. end;
  127. procedure TCalcDisplay.SetDisplay(R: extended);
  128. var
  129. S: string[MaxDigits];
  130. begin
  131. DispNumber:=R;
  132. Str(R: 0: MaxDecimals, S);
  133. if Pos('.',S)<>0 then
  134. while (length(S)>1) and (S[length(S)]='0') do Dec(S[0]);
  135. if S[1] <> '-' then Sign := ' ' else
  136. begin
  137. Delete(S, 1, 1);
  138. Sign := '-';
  139. end;
  140. if Length(S) > MaxDigits + 1 + MaxDecimals then Error
  141. else
  142. begin
  143. if S[Length(S)] = '.' then Dec(S[0]);
  144. Number := S;
  145. end;
  146. end;
  147. procedure TCalcDisplay.Error;
  148. begin
  149. Status := csError;
  150. Number := 'Error';
  151. Sign := ' ';
  152. DrawView;
  153. end;
  154. function TCalcDisplay.CalcKey(Key: string): boolean;
  155. var
  156. R,D: extended;
  157. procedure CheckFirst;
  158. begin
  159. if Status = csFirst then
  160. begin
  161. Status := csValid;
  162. { Number := '0';
  163. Sign := ' ';}
  164. SetDisplay(0);
  165. end;
  166. end;
  167. begin
  168. CalcKey:=true;
  169. Key := UpCaseStr(Key);
  170. if (Status = csError) and (Key <> 'C') then Key := ' ';
  171. if Key='X^Y' then Key:='^';
  172. if length(Key)>1 then
  173. begin
  174. { if Status = csFirst then}
  175. begin
  176. { Status := csValid;}
  177. GetDisplay(R);
  178. if Key='1/X' then begin if R=0 then Error else SetDisplay(1/R) end else
  179. if Key='SQR' then begin if R<0 then Error else SetDisplay(sqrt(R)) end else
  180. if Key='X^2' then SetDisplay(R*R) else
  181. if Key='M+' then Memory:=Memory+R else
  182. if Key='M-' then Memory:=Memory-R else
  183. if Key='M'#26 then SetDisplay(Memory) else
  184. if Key='M'#27 then Memory:=R else
  185. if Key='M'#29 then begin D:=Memory; Memory:=R; SetDisplay(D); end;
  186. end;
  187. end
  188. else
  189. case Key[1] of
  190. '0'..'9':
  191. if Length(Number)<MaxDigits then
  192. begin
  193. CheckFirst;
  194. if Number = '0' then Number := '';
  195. Number := Number + Key;
  196. SetDisplay(StrToExtended(Number)); { !!! }
  197. end;
  198. '.':
  199. begin
  200. CheckFirst;
  201. if Pos('.', Number) = 0 then Number := Number + '.';
  202. end;
  203. #8, #27:
  204. begin
  205. CheckFirst;
  206. if Length(Number) = 1 then Number := '0' else Dec(Number[0]);
  207. SetDisplay(StrToExtended(Number)); { !!! }
  208. end;
  209. '_', #241:
  210. if Sign = ' ' then Sign := '-' else Sign := ' ';
  211. '+', '-', '*', '/', '=', '%', #13, '^':
  212. begin
  213. if Status = csValid then
  214. begin
  215. Status := csFirst;
  216. GetDisplay(R);
  217. if Key = '%' then
  218. case _Operator of
  219. '+', '-': R := Operand * R / 100;
  220. '*', '/': R := R / 100;
  221. end;
  222. case _Operator of
  223. '^': SetDisplay(Power(Operand,R));
  224. '+': SetDisplay(Operand + R);
  225. '-': SetDisplay(Operand - R);
  226. '*': SetDisplay(Operand * R);
  227. '/': if R = 0 then Error else SetDisplay(Operand / R);
  228. end;
  229. end;
  230. _Operator := Key[1];
  231. GetDisplay(Operand);
  232. end;
  233. 'C':
  234. Clear;
  235. else CalcKey:=false;
  236. end;
  237. DrawView;
  238. end;
  239. procedure TCalcDisplay.Clear;
  240. begin
  241. Status := csFirst;
  242. Number := '0';
  243. Sign := ' ';
  244. _Operator := '=';
  245. end;
  246. procedure TCalcDisplay.Draw;
  247. var
  248. Color: Byte;
  249. I: Integer;
  250. B: TDrawBuffer;
  251. begin
  252. Color := GetColor(1);
  253. I := Size.X - Length(Number) - 2;
  254. MoveChar(B, ' ', Color, Size.X);
  255. MoveChar(B[I], Sign, Color, 1);
  256. MoveStr(B[I + 1], Number, Color);
  257. WriteBuf(0, 0, Size.X, 1, B);
  258. end;
  259. function TCalcDisplay.GetPalette: PPalette;
  260. const
  261. P: string[1] = #19;
  262. begin
  263. GetPalette := @P;
  264. end;
  265. procedure TCalcDisplay.HandleEvent(var Event: TEvent);
  266. var S: string[3];
  267. begin
  268. inherited HandleEvent(Event);
  269. case Event.What of
  270. evKeyDown:
  271. if Owner<>nil then
  272. if (Owner^.State and sfSelected)<>0 then
  273. begin
  274. S:=Event.CharCode;
  275. Message(Owner,evBroadcast,cmPressButton,@S);
  276. if CalcKey(Event.CharCode) then
  277. ClearEvent(Event);
  278. end;
  279. evBroadcast:
  280. if Event.Command = cmCalcButton then
  281. begin
  282. CalcKey(PButton(Event.InfoPtr)^.Title^);
  283. ClearEvent(Event);
  284. end;
  285. end;
  286. end;
  287. procedure TCalcDisplay.Store(var S: TStream);
  288. begin
  289. TView.Store(S);
  290. S.Write(Status, SizeOf(Status) + SizeOf(Number) + SizeOf(Sign) +
  291. SizeOf(_Operator) + SizeOf(Operand));
  292. end;
  293. { TCalculator }
  294. constructor TCalculator.Init;
  295. const
  296. Keys: array[0..29] of string[3] =
  297. ('M+', 'x^y','C' ,#27 ,'%' ,#241 ,
  298. 'M-', 'x^2','7' ,'8' ,'9' ,'/' ,
  299. 'M'#26,'1/x','4' ,'5' ,'6' ,'*' ,
  300. 'M'#27,'sqr','1' ,'2' ,'3' ,'-' ,
  301. 'M'#29,'log','0' ,'.' ,'=' ,'+' );
  302. var
  303. I: Integer;
  304. P: PView;
  305. R: TRect;
  306. begin
  307. R.Assign(5, 3, 43, 18);
  308. inherited Init(R, 'Calculator');
  309. Options := Options or ofFirstClick or ofTopSelect;
  310. HelpCtx:=hcCalcWindow;
  311. for I := 0 to 29 do
  312. begin
  313. R.A.X := (I mod 6) * 5 + 2;
  314. R.A.Y := (I div 6) * 2 + 4;
  315. R.B.X := R.A.X + 5;
  316. R.B.Y := R.A.Y + 2;
  317. if (I mod 6)=0 then Inc(R.B.X,1) else
  318. if (I mod 6)=1 then begin R.Move(1,0); Inc(R.B.X,2) end else
  319. R.Move(3,0);
  320. P := New(PCalcButton, Init(R, Keys[I], cmCalcButton,
  321. bfNormal + bfBroadcast+bfGrabFocus));
  322. P^.Options := P^.Options {and not ofSelectable};
  323. Insert(P);
  324. end;
  325. R.Assign(3, 2, 35, 3);
  326. New(CD, Init(R));
  327. CD^.Options:=CD^.Options or ofSelectable;
  328. Insert(CD);
  329. end;
  330. procedure TCalculator.HandleEvent(var Event: TEvent);
  331. var R: extended;
  332. Re: real;
  333. begin
  334. if (State and sfSelected)<>0 then
  335. case Event.What of
  336. evCommand :
  337. case Event.Command of
  338. cmCalculatorPaste :
  339. Message(@Self,evKeyDown,kbCtrlEnter,nil);
  340. end;
  341. evKeyDown :
  342. case Event.KeyCode of
  343. kbEnter :
  344. begin
  345. Event.KeyCode:=0;
  346. Event.CharCode:='=';
  347. end;
  348. kbCtrlEnter :
  349. begin
  350. ClearEvent(Event);
  351. CD^.GetDisplay(R); Re:=R;
  352. Close;
  353. CalcClipboard:=R;
  354. Message(Application,evBroadcast,cmCalculatorPaste,nil);
  355. end;
  356. kbEsc :
  357. begin
  358. CD^.GetDisplay(R);
  359. if R<>0 then begin
  360. CD^.SetDisplay(0);
  361. CD^.DrawView;
  362. end
  363. else Close;
  364. ClearEvent(Event);
  365. end;
  366. end;
  367. end;
  368. inherited HandleEvent(Event);
  369. if Event.What=evKeyDown then
  370. Message(CD,Event.What,Event.KeyCode,Event.InfoPtr);
  371. end;
  372. procedure TCalculator.Show;
  373. begin
  374. { if GetState(sfVisible)=false then CD^.Clear;}
  375. inherited Show;
  376. end;
  377. procedure TCalculator.Close;
  378. begin
  379. Hide;
  380. end;
  381. procedure RegisterCalc;
  382. begin
  383. RegisterType(RCalcDisplay);
  384. RegisterType(RCalculator);
  385. end;
  386. end.
  387. {
  388. $Log$
  389. Revision 1.1 1998-12-22 14:27:54 peter
  390. * moved
  391. Revision 1.2 1998/12/22 10:39:39 peter
  392. + options are now written/read
  393. + find and replace routines
  394. }