fpcalc.pas 13 KB

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