fpcalc.pas 13 KB

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