fpcalc.pas 11 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465
  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. WViews,
  17. FPViews;
  18. const
  19. MaxDecimals = 10;
  20. MaxDigits = 30;
  21. type
  22. TCalcState = (csFirst, csValid, csError);
  23. PCalcButton = ^TCalcButton;
  24. TCalcButton = object(TButton)
  25. procedure HandleEvent(var Event: TEvent); virtual;
  26. end;
  27. PCalcDisplay = ^TCalcDisplay;
  28. TCalcDisplay = object(TView)
  29. Status: TCalcState;
  30. Number: string[MaxDigits];
  31. Sign: Char;
  32. _Operator: Char;
  33. Operand: extended;
  34. Memory: extended;
  35. DispNumber: extended;
  36. constructor Init(var Bounds: TRect);
  37. constructor Load(var S: TStream);
  38. function CalcKey(Key: string): boolean;
  39. procedure Clear;
  40. procedure Draw; virtual;
  41. function GetPalette: PPalette; virtual;
  42. procedure HandleEvent(var Event: TEvent); virtual;
  43. procedure Store(var S: TStream);
  44. private
  45. procedure GetDisplay(var R: extended);
  46. procedure SetDisplay(R: extended);
  47. procedure Error;
  48. end;
  49. PCalculator = ^TCalculator;
  50. TCalculator = object(TCenterDialog)
  51. CD : PCalcDisplay;
  52. constructor Init;
  53. procedure HandleEvent(var Event: TEvent); virtual;
  54. procedure Show; virtual;
  55. procedure Close; virtual;
  56. end;
  57. const
  58. RCalcButton: TStreamRec = (
  59. ObjType: 10139;
  60. VmtLink: Ofs(TypeOf(TCalcButton)^);
  61. Load: @TCalcButton.Load;
  62. Store: @TCalcButton.Store
  63. );
  64. RCalcDisplay: TStreamRec = (
  65. ObjType: 10140;
  66. VmtLink: Ofs(TypeOf(TCalcDisplay)^);
  67. Load: @TCalcDisplay.Load;
  68. Store: @TCalcDisplay.Store
  69. );
  70. RCalculator: TStreamRec = (
  71. ObjType: 10141;
  72. VmtLink: Ofs(TypeOf(TCalculator)^);
  73. Load: @TCalculator.Load;
  74. Store: @TCalculator.Store
  75. );
  76. procedure RegisterFPCalc;
  77. implementation
  78. uses FPUtils,FPConst;
  79. const
  80. cmCalcButton = 100;
  81. cmPressButton = 101;
  82. procedure TCalcButton.HandleEvent(var Event: TEvent);
  83. var
  84. Call : boolean;
  85. i : Sw_Word;
  86. begin
  87. Call:=true;
  88. case Event.What of
  89. evKeyDown :
  90. case Event.KeyCode of
  91. kbEnter : Call:=false;
  92. end;
  93. evBroadcast :
  94. case Event.Command of
  95. cmDefault : Call:=false;
  96. cmPressButton :
  97. begin
  98. if (PString(Event.InfoPtr)^=Title^) or
  99. ((PString(Event.InfoPtr)^='^') and (Title^='x^y')) then
  100. begin
  101. Select;
  102. DrawState(true);
  103. i:=GetDosTicks+2;
  104. repeat
  105. until GetDosTicks>i;
  106. DrawState(false);
  107. ClearEvent(Event);
  108. end;
  109. end;
  110. end;
  111. end;
  112. if Call then
  113. inherited HandleEvent(Event);
  114. end;
  115. constructor TCalcDisplay.Init(var Bounds: TRect);
  116. begin
  117. inherited Init(Bounds);
  118. Options := Options or ofSelectable;
  119. EventMask := evKeyDown + evBroadcast;
  120. Clear;
  121. HelpCtx:={hcCalculatorLine}0;
  122. end;
  123. constructor TCalcDisplay.Load(var S: TStream);
  124. begin
  125. inherited Load(S);
  126. S.Read(Status, SizeOf(Status) + SizeOf(Number) + SizeOf(Sign) +
  127. SizeOf(_Operator) + SizeOf(Operand));
  128. end;
  129. procedure TCalcDisplay.GetDisplay(var R: extended);
  130. begin
  131. { Val(Sign + Number, R, E);}
  132. R:=DispNumber;
  133. end;
  134. procedure TCalcDisplay.SetDisplay(R: extended);
  135. var
  136. S: string[MaxDigits];
  137. begin
  138. DispNumber:=R;
  139. Str(R: 0: MaxDecimals, S);
  140. if Pos('.',S)<>0 then
  141. while (length(S)>1) and (S[length(S)]='0') do Dec(S[0]);
  142. if S[1] <> '-' then Sign := ' ' else
  143. begin
  144. Delete(S, 1, 1);
  145. Sign := '-';
  146. end;
  147. if Length(S) > MaxDigits + 1 + MaxDecimals then Error
  148. else
  149. begin
  150. if S[Length(S)] = '.' then Dec(S[0]);
  151. Number := S;
  152. end;
  153. end;
  154. procedure TCalcDisplay.Error;
  155. begin
  156. Status := csError;
  157. Number := 'Error';
  158. Sign := ' ';
  159. DrawView;
  160. end;
  161. function TCalcDisplay.CalcKey(Key: string): boolean;
  162. var
  163. R,D: extended;
  164. procedure CheckFirst;
  165. begin
  166. if Status = csFirst then
  167. begin
  168. Status := csValid;
  169. { Number := '0';
  170. Sign := ' ';}
  171. SetDisplay(0);
  172. end;
  173. end;
  174. begin
  175. CalcKey:=true;
  176. Key := UpCaseStr(Key);
  177. if (Status = csError) and (Key <> 'C') then Key := ' ';
  178. if Key='X^Y' then Key:='^';
  179. if length(Key)>1 then
  180. begin
  181. { if Status = csFirst then}
  182. begin
  183. { Status := csValid;}
  184. GetDisplay(R);
  185. if Key='1/X' then begin if R=0 then Error else SetDisplay(1/R) end else
  186. if Key='SQR' then begin if R<0 then Error else SetDisplay(sqrt(R)) end else
  187. if Key='X^2' then SetDisplay(R*R) else
  188. if Key='M+' then Memory:=Memory+R else
  189. if Key='M-' then Memory:=Memory-R else
  190. if Key='M'#26 then SetDisplay(Memory) else
  191. if Key='M'#27 then Memory:=R else
  192. if Key='M'#29 then begin D:=Memory; Memory:=R; SetDisplay(D); end;
  193. end;
  194. end
  195. else
  196. case Key[1] of
  197. '0'..'9':
  198. if Length(Number)<MaxDigits then
  199. begin
  200. CheckFirst;
  201. if Number = '0' then Number := '';
  202. Number := Number + Key;
  203. SetDisplay(StrToExtended(Number)); { !!! }
  204. end;
  205. '.':
  206. begin
  207. CheckFirst;
  208. if Pos('.', Number) = 0 then Number := Number + '.';
  209. end;
  210. #8, #27:
  211. begin
  212. CheckFirst;
  213. if Length(Number) = 1 then Number := '0' else Dec(Number[0]);
  214. SetDisplay(StrToExtended(Number)); { !!! }
  215. end;
  216. '_', #241:
  217. if Sign = ' ' then Sign := '-' else Sign := ' ';
  218. '+', '-', '*', '/', '=', '%', #13, '^':
  219. begin
  220. if Status = csValid then
  221. begin
  222. Status := csFirst;
  223. GetDisplay(R);
  224. if Key = '%' then
  225. case _Operator of
  226. '+', '-': R := Operand * R / 100;
  227. '*', '/': R := R / 100;
  228. end;
  229. case _Operator of
  230. '^': SetDisplay(Power(Operand,R));
  231. '+': SetDisplay(Operand + R);
  232. '-': SetDisplay(Operand - R);
  233. '*': SetDisplay(Operand * R);
  234. '/': if R = 0 then Error else SetDisplay(Operand / R);
  235. end;
  236. end;
  237. _Operator := Key[1];
  238. GetDisplay(Operand);
  239. end;
  240. 'C':
  241. Clear;
  242. else CalcKey:=false;
  243. end;
  244. DrawView;
  245. end;
  246. procedure TCalcDisplay.Clear;
  247. begin
  248. Status := csFirst;
  249. Number := '0';
  250. Sign := ' ';
  251. _Operator := '=';
  252. end;
  253. procedure TCalcDisplay.Draw;
  254. var
  255. Color: Byte;
  256. I: Integer;
  257. B: TDrawBuffer;
  258. begin
  259. Color := GetColor(1);
  260. I := Size.X - Length(Number) - 2;
  261. MoveChar(B, ' ', Color, Size.X);
  262. MoveChar(B[I], Sign, Color, 1);
  263. MoveStr(B[I + 1], Number, Color);
  264. WriteBuf(0, 0, Size.X, 1, B);
  265. end;
  266. function TCalcDisplay.GetPalette: PPalette;
  267. const
  268. P: string[1] = #19;
  269. begin
  270. GetPalette := @P;
  271. end;
  272. procedure TCalcDisplay.HandleEvent(var Event: TEvent);
  273. var S: string[3];
  274. begin
  275. inherited HandleEvent(Event);
  276. case Event.What of
  277. evKeyDown:
  278. if Owner<>nil then
  279. if (Owner^.State and sfSelected)<>0 then
  280. begin
  281. S:=Event.CharCode;
  282. Message(Owner,evBroadcast,cmPressButton,@S);
  283. if CalcKey(Event.CharCode) then
  284. ClearEvent(Event);
  285. end;
  286. evBroadcast:
  287. if Event.Command = cmCalcButton then
  288. begin
  289. CalcKey(PButton(Event.InfoPtr)^.Title^);
  290. ClearEvent(Event);
  291. end;
  292. end;
  293. end;
  294. procedure TCalcDisplay.Store(var S: TStream);
  295. begin
  296. TView.Store(S);
  297. S.Write(Status, SizeOf(Status) + SizeOf(Number) + SizeOf(Sign) +
  298. SizeOf(_Operator) + SizeOf(Operand));
  299. end;
  300. { TCalculator }
  301. constructor TCalculator.Init;
  302. const
  303. Keys: array[0..29] of string[3] =
  304. ('M+', 'x^y','C' ,#27 ,'%' ,#241 ,
  305. 'M-', 'x^2','7' ,'8' ,'9' ,'/' ,
  306. 'M'#26,'1/x','4' ,'5' ,'6' ,'*' ,
  307. 'M'#27,'sqr','1' ,'2' ,'3' ,'-' ,
  308. 'M'#29,'log','0' ,'.' ,'=' ,'+' );
  309. var
  310. I: Integer;
  311. P: PView;
  312. R: TRect;
  313. begin
  314. R.Assign(5, 3, 43, 18);
  315. inherited Init(R, 'Calculator');
  316. Options := Options or ofFirstClick or ofTopSelect;
  317. HelpCtx:=hcCalcWindow;
  318. for I := 0 to 29 do
  319. begin
  320. R.A.X := (I mod 6) * 5 + 2;
  321. R.A.Y := (I div 6) * 2 + 4;
  322. R.B.X := R.A.X + 5;
  323. R.B.Y := R.A.Y + 2;
  324. if (I mod 6)=0 then Inc(R.B.X,1) else
  325. if (I mod 6)=1 then begin R.Move(1,0); Inc(R.B.X,2) end else
  326. R.Move(3,0);
  327. P := New(PCalcButton, Init(R, Keys[I], cmCalcButton,
  328. bfNormal + bfBroadcast+bfGrabFocus));
  329. P^.Options := P^.Options {and not ofSelectable};
  330. Insert(P);
  331. end;
  332. R.Assign(3, 2, 35, 3);
  333. New(CD, Init(R));
  334. CD^.Options:=CD^.Options or ofSelectable;
  335. Insert(CD);
  336. end;
  337. procedure TCalculator.HandleEvent(var Event: TEvent);
  338. var R: extended;
  339. Re: real;
  340. begin
  341. if (State and sfSelected)<>0 then
  342. case Event.What of
  343. evCommand :
  344. case Event.Command of
  345. cmCalculatorPaste :
  346. Message(@Self,evKeyDown,kbCtrlEnter,nil);
  347. end;
  348. evKeyDown :
  349. case Event.KeyCode of
  350. kbEnter :
  351. begin
  352. Event.KeyCode:=0;
  353. Event.CharCode:='=';
  354. end;
  355. kbCtrlEnter :
  356. begin
  357. ClearEvent(Event);
  358. CD^.GetDisplay(R); Re:=R;
  359. Close;
  360. CalcClipboard:=R;
  361. Message(Application,evBroadcast,cmCalculatorPaste,nil);
  362. end;
  363. kbEsc :
  364. begin
  365. CD^.GetDisplay(R);
  366. if R<>0 then begin
  367. CD^.SetDisplay(0);
  368. CD^.DrawView;
  369. end
  370. else Close;
  371. ClearEvent(Event);
  372. end;
  373. end;
  374. end;
  375. inherited HandleEvent(Event);
  376. if Event.What=evKeyDown then
  377. Message(CD,Event.What,Event.KeyCode,Event.InfoPtr);
  378. end;
  379. procedure TCalculator.Show;
  380. begin
  381. { if GetState(sfVisible)=false then CD^.Clear;}
  382. inherited Show;
  383. end;
  384. procedure TCalculator.Close;
  385. begin
  386. Hide;
  387. end;
  388. procedure RegisterFPCalc;
  389. begin
  390. RegisterType(RCalcButton);
  391. RegisterType(RCalcDisplay);
  392. RegisterType(RCalculator);
  393. end;
  394. end.
  395. {
  396. $Log$
  397. Revision 1.4 1999-04-07 21:55:41 peter
  398. + object support for browser
  399. * html help fixes
  400. * more desktop saving things
  401. * NODEBUG directive to exclude debugger
  402. Revision 1.3 1999/03/01 15:41:49 peter
  403. + Added dummy entries for functions not yet implemented
  404. * MenuBar didn't update itself automatically on command-set changes
  405. * Fixed Debugging/Profiling options dialog
  406. * TCodeEditor converts spaces to tabs at save only if efUseTabChars is
  407. set
  408. * efBackSpaceUnindents works correctly
  409. + 'Messages' window implemented
  410. + Added '$CAP MSG()' and '$CAP EDIT' to available tool-macros
  411. + Added TP message-filter support (for ex. you can call GREP thru
  412. GREP2MSG and view the result in the messages window - just like in TP)
  413. * A 'var' was missing from the param-list of THelpFacility.TopicSearch,
  414. so topic search didn't work...
  415. * In FPHELP.PAS there were still context-variables defined as word instead
  416. of THelpCtx
  417. * StdStatusKeys() was missing from the statusdef for help windows
  418. + Topic-title for index-table can be specified when adding a HTML-files
  419. Revision 1.1 1998/12/22 14:27:54 peter
  420. * moved
  421. Revision 1.2 1998/12/22 10:39:39 peter
  422. + options are now written/read
  423. + find and replace routines
  424. }