lazarus-ccr/components/orpheus/ovccalc.pas

2706 lines
75 KiB
ObjectPascal

{*********************************************************}
{* OVCCALC.PAS 4.06 *}
{*********************************************************}
{* ***** BEGIN LICENSE BLOCK ***** *}
{* Version: MPL 1.1 *}
{* *}
{* The contents of this file are subject to the Mozilla Public License *}
{* Version 1.1 (the "License"); you may not use this file except in *}
{* compliance with the License. You may obtain a copy of the License at *}
{* http://www.mozilla.org/MPL/ *}
{* *}
{* Software distributed under the License is distributed on an "AS IS" basis, *}
{* WITHOUT WARRANTY OF ANY KIND, either express or implied. See the License *}
{* for the specific language governing rights and limitations under the *}
{* License. *}
{* *}
{* The Original Code is TurboPower Orpheus *}
{* *}
{* The Initial Developer of the Original Code is TurboPower Software *}
{* *}
{* Portions created by TurboPower Software Inc. are Copyright (C)1995-2002 *}
{* TurboPower Software Inc. All Rights Reserved. *}
{* *}
{* Contributor(s): *}
{* *}
{* ***** END LICENSE BLOCK ***** *}
{$I OVC.INC}
{$B-} {Complete Boolean Evaluation}
{$I+} {Input/Output-Checking}
{$P+} {Open Parameters}
{$T-} {Typed @ Operator}
{.W-} {Windows Stack Frame}
{$X+} {Extended Syntax}
unit ovccalc;
{-calculator component}
interface
uses
{$IFNDEF LCL} Windows, Messages, {$ELSE} LclIntf, LMessages, Types, LclType, GraphType, MyMisc, {$ENDIF}
Buttons, Classes, ClipBrd, Controls, ExtCtrls, Forms, Graphics,
Menus, StdCtrls, SysUtils,
OvcData, OvcConst, OvcBase, OvcMisc;
type
TOvcCalculatorButton = (
cbNone, cbTape, cbBack, cbClearEntry, cbClear, cbAdd, cbSub, cbMul, cbDiv,
cb0, cb1, cb2, cb3, cb4, cb5, cb6, cb7, cb8, cb9,
cbDecimal, cbEqual, cbInvert, cbChangeSign, cbPercent, cbSqrt,
cbMemClear, cbMemRecall, cbMemStore, cbMemAdd, cbMemSub, cbSubTotal);
TOvcButtonInfo = packed record
Position : TRect; {position and size}
Caption : string[10]; {button text}
Visible : Boolean; {true to display button}
end;
TOvcButtonArray = array[cbTape..cbMemSub] of TOvcButtonInfo;
type
TOvcCalculatorOperation = (
coNone, coAdd, coSub, coMul, coDiv,
coEqual, coInvert, coPercent, coSqrt,
coMemClear, coMemRecall, coMemStore, coMemAdd, coMemSub, coSubTotal);
TOvcCalcState = (csValid, csLocked, csClear);
TOvcCalcStates = set of TOvcCalcState;
type
TOvcCalcColorArray = array[0..7] of TColor;
TOvcCalcColorScheme = (cscalcCustom, cscalcWindows, cscalcDark,
cscalcOcean, cscalcPlain);
TOvcCalcSchemeArray = array[TOvcCalcColorScheme] of TOvcCalcColorArray;
TOvcCalcDisplayString = array[TOvcCalculatorButton] of string;
TOvcCalcButtonToOperation = array[cbNone..cbSubTotal] of TOvcCalculatorOperation;
const
{DisabledMemoryButtons, Display, DisplayTextColor, EditButtons,
FunctionButtons, MemoryButtons, NumberButtons, OperatorButtons}
CalcScheme : TOvcCalcSchemeArray =
((0, 0, 0, 0, 0, 0, 0, 0),
(clGray, clWindow, clWindowText, clMaroon, clNavy, clRed, clBlue, clRed),
(clGray, clBlack, clAqua, clBlack, clTeal, clNavy, clMaroon, clBlue),
(clGray, clAqua, clBlack, clPurple, clNavy, clNavy, clAqua, clBlue),
(clGray, clWhite, clNavy, clBlack, clNavy, clNavy, clBlue, clBlue)
);
{ You must set the Length of the first entry (cbNone) to the Length of the largest entry}
CalcDisplayString : TOvcCalcDisplayString =
(' ',' ',' ','CE','C' ,'+' ,'-' ,'*' ,'/',
' ',' ',' ',' ',' ',' ',' ',' ',' ',' ',
' ','=' ,'1/','-+','%' ,'SQ',
'MC','MR','MS','M+','M-','*' );
CalcButtontoOperation : TOvcCalcButtonToOperation =
(coNone, coNone, coNone, coNone, coNone, coAdd, coSub, coMul, coDiv,
coNone, coNone, coNone, coNone, coNone, coNone, coNone, coNone, coNone, coNone,
coNone, coEqual, coInvert, coNone, coPercent, coSqrt,
coMemClear, coMemRecall, coMemStore, coMemAdd, coMemSub, coSubTotal);
type
TOvcCalcColors = class(TPersistent)
{.Z+}
private
{property variables}
FUpdating : Boolean;
FOnChange : TNotifyEvent;
{internal variables}
SettingScheme : Boolean;
{internal methods}
procedure DoOnChange;
{property methods}
function GetColor(const Index : Integer) : TColor;
procedure SetColor(const Index : Integer; const Value : TColor);
procedure SetColorScheme(const Value : TOvcCalcColorScheme);
procedure SetDisplayTextColor(const Value : TColor);
public
{property variables}
FCalcColors : TOvcCalcColorArray;
FColorScheme : TOvcCalcColorScheme;
procedure Assign(Source : TPersistent);
override;
procedure BeginUpdate;
procedure EndUpdate;
property OnChange : TNotifyEvent
read FOnChange write FOnChange;
{.Z-}
published
property ColorScheme : TOvcCalcColorScheme
read FColorScheme write SetColorScheme;
property DisabledMemoryButtons : TColor index 0
read GetColor write SetColor;
property Display : TColor index 1
read GetColor write SetColor;
property DisplayTextColor : TColor
read FCalcColors[2] write SetDisplayTextColor nodefault;
property EditButtons : TColor index 3
read GetColor write SetColor;
property FunctionButtons : TColor index 4
read GetColor write SetColor;
property MemoryButtons : TColor index 5
read GetColor write SetColor;
property NumberButtons : TColor index 6
read GetColor write SetColor;
property OperatorButtons : TColor index 7
read GetColor write SetColor;
end;
type
{.Z+}
TOvcCalcPanel = class(TPanel)
protected
procedure Click;
override;
public
end;
{.Z-}
type
{.Z+}
TOvcCustomCalculatorEngine = class
protected {private}
{property variables}
FDecimals : Integer;
FShowSeparatePercent : Boolean;
{internal variables}
cCalculated : Extended;
cLastOperation : TOvcCalculatorOperation;
cOperationCount : Integer;
cMemory : Extended; {value stored in memory register}
cOperands : array [0..3] of Extended; {the operand stack}
cState : TOvcCalcStates;
public
function AddOperand(const Value : Extended; const Button : TOvcCalculatorOperation) : Boolean;
virtual; abstract;
function AddOperation(const Button : TOvcCalculatorOperation) : Boolean;
virtual; abstract;
procedure ClearAll;
procedure PushOperand(const Value : Extended);
function PopOperand : Extended;
function TopOperand : Extended;
{public properties}
property Decimals : Integer
read FDecimals write FDecimals;
property LastOperation : TOvcCalculatorOperation
read cLastOperation write cLastOperation;
property Memory : Extended
read cMemory write cMemory;
property OperationCount : Integer
read cOperationCount write cOperationCount;
property ShowSeparatePercent : Boolean
read FShowSeparatePercent write FShowSeparatePercent;
property State : TOvcCalcStates
read cState write cState;
end;
{.Z-}
type
{.Z+}
TOvcCalcTape = class(TObject)
protected {private}
{property variables}
FMaxPaperCount : Integer;
FShowTape : Boolean;
FTapeDisplaySpace : Integer;
FVisible : Boolean;
{internal variables}
taListBox : TListBox;
taTapeColor : TColor;
taHeight : Integer;
taOwner : TComponent;
taOperandSize : Integer;
taFont : TFont;
taMaxTapeCount : Integer;
taTapeInitialized : Boolean;
taWidth : Integer;
procedure ValidateListBox;
function GetFont : TFont;
procedure SetFont(const Value : TFont);
function GetHeight : Integer;
procedure SetHeight(const Value : Integer);
function GetTape : TStrings;
procedure SetTape(const Value : TStrings);
function GetTapeColor : TColor;
procedure SetTapeColor(const Value : TColor);
function GetTop : Integer;
procedure SetTop(const Value : Integer);
function GetTopIndex : Integer;
procedure SetTopIndex(const Value : Integer);
function GetVisible : Boolean;
procedure SetVisible(const Value : Boolean);
function GetWidth : Integer;
procedure SetWidth(const Value : Integer);
protected
procedure Add(const Value : string);
procedure DeleteFirst;
procedure taOnClick(Sender : TObject);
procedure taOnDblClick(Sender : TObject);
procedure taOnDrawItem(Control: TWinControl; Index: Integer;
Rect:TRect;State: TOwnerDrawState);
procedure taTapeFontChange(Sender : TObject);
public
constructor Create(const AOwner : TComponent; const AOperandSize : Integer);
destructor Destroy;
override;
procedure InitializeTape;
procedure SetBounds(const ALeft, ATop, AWidth, AHeight : Integer);
function GetDisplayedItemCount : Integer;
procedure AddToTape(const Value : string;
const OpString : string);
procedure AddToTapeLeft(const Value : string);
procedure ClearTape;
procedure RefreshDisplays;
procedure SpaceTape(const Value : char);
property Font : TFont
read GetFont write SetFont;
property Height : Integer
read GetHeight write SetHeight;
property MaxPaperCount : Integer
read FMaxPaperCount write FMaxPaperCount;
property ShowTape : Boolean
read FShowTape write FShowTape;
property Tape : TStrings
read GetTape write SetTape;
property TapeColor : TColor
read GetTapeColor write SetTapeColor;
property TapeDisplaySpace : Integer
read FTapeDisplaySpace write FTapeDisplaySpace;
property Top : Integer
read GetTop write SetTop;
property TopIndex : Integer
read GetTopIndex write SetTopIndex;
property Visible : Boolean
read GetVisible write SetVisible;
property Width : Integer
read GetWidth write SetWidth;
end;
{.Z-}
type
TOvcCalcButtonPressedEvent =
procedure(Sender : TObject; Button : TOvcCalculatorButton)
of object;
TOvcCalculatorOption = (coShowItemCount, coShowMemoryButtons,
coShowClearTapeButton, coShowTape, coShowSeparatePercent);
TOvcCalculatorOptions = set of TOvcCalculatorOption;
TOvcCustomCalculator = class(TOvcCustomControl)
{.Z+}
protected {private}
{property variables}
FBorderStyle : TBorderStyle;
FColors : TOvcCalcColors;
FDisplay : Extended; {the calculated value}
FDisplayStr : string; {the string that is displayed}
FLastOperand : Extended;
FOptions : TOvcCalculatorOptions;
FTapeSeparatorChar : Char;
{$IFDEF LCL}
FCtl3D : Boolean;
{$ENDIF}
{event variables}
FOnButtonPressed : TOvcCalcButtonPressedEvent;
{internal variables}
cButtons : TOvcButtonArray;
cDecimalEntered : Boolean;
cDownButton : TOvcCalculatorButton;
cHitTest : TPoint; {location of mouse cursor}
cLastButton : TOvcCalculatorButton;
cMargin : Integer;
cMinus0 : Boolean;
cOverBar : Boolean;
cPanel : TOvcCalcPanel;
cPopup : Boolean; {true if being created as a popup}
cScrBarWidth : Integer;
cSizeOffset : Integer; { the offset of the sizing line }
cSizing : Boolean; { Are we showing the sizing cursor? }
cTabCursor : HCursor; {design-time tab slecting cursor handle}
cTape : TOvcCalcTape;
cEngine : TOvcCustomCalculatorEngine;
{internal methods}
procedure cAdjustHeight;
procedure cCalculateLook;
procedure cClearAll;
procedure cColorChange(Sender : TObject);
procedure cDisplayError;
procedure cDrawCalcButton(const Button : TOvcButtonInfo; const Pressed : Boolean);
procedure cDrawFocusState;
procedure cDrawSizeLine;
procedure cEvaluate(const Button : TOvcCalculatorButton);
function cFormatString(const Value : Extended) : string;
function cGetFontWidth : Integer;
procedure cInvalidateIndicator;
procedure cRefreshDisplays;
procedure cSetDisplayString(const Value : string);
procedure cTapeFontChange(Sender : TObject);
{property methods}
function GetDecimals : Integer;
function GetMaxPaperCount : Integer;
function GetMemory : Extended;
function GetOperand : Extended;
function GetTape : TStrings;
function GetTapeFont : TFont;
function GetTapeHeight : Integer;
function GetVisible : Boolean;
procedure SetBorderStyle(const Value : TBorderStyle);
procedure SetDecimals(const Value : Integer);
procedure SetDisplay(const Value : Extended);
procedure SetDisplayStr(const Value : string);
procedure SetMaxPaperCount(const Value : Integer);
procedure SetMemory(const Value : Extended);
procedure SetOperand(const Value : Extended);
procedure SetOptions(const Value : TOvcCalculatorOptions);
procedure SetTape(const Value : TStrings);
procedure SetTapeFont(const Value : TFont);
procedure SetTapeHeight(const Value : Integer);
procedure SetVisible(const Value : Boolean);
{VCL control methods}
{$IFNDEF LCL}
procedure CMCtl3DChanged(var Msg : TMessage);
message CM_CTL3DCHANGED;
{$ENDIF}
procedure CMDesignHitTest(var Msg : TCMDesignHitTest);
message CM_DESIGNHITTEST;
procedure CMEnter(var Msg : TMessage);
message CM_ENTER;
procedure CMExit(var Msg : TMessage);
message CM_EXIT;
procedure CMFontChanged(var Msg : TMessage);
message CM_FONTCHANGED;
{windows message handlers}
procedure WMCancelMode(var Msg : TMessage);
message WM_CANCELMODE;
procedure WMEraseBkgnd(var Msg : TWMEraseBkgnd);
message WM_ERASEBKGND;
procedure WMGetText(var Msg : TWMGetText);
message WM_GETTEXT;
procedure WMGetTextLength(var Msg : TWMGetTextLength);
message WM_GETTEXTLENGTH;
procedure WMKeyDown(var Msg : TWMKeyDown);
message WM_KEYDOWN;
procedure WMKillFocus(var Msg : TWMKillFocus);
message WM_KILLFOCUS;
procedure WMLButtonDown(var Msg : TWMMouse);
message WM_LBUTTONDOWN;
procedure WMLButtonUp(var Msg : TWMMouse);
message WM_LBUTTONUP;
procedure WMMouseMove(var Msg : TWMMouse);
message WM_MOUSEMOVE;
procedure WMNCHitTest(var Msg : TWMNCHitTest);
message WM_NCHITTEST;
procedure WMSetText(var Msg : TWMSetText);
message WM_SETTEXT;
procedure WMSetCursor(var Msg : TWMSetCursor);
message WM_SETCURSOR;
protected
procedure CreateParams(var Params : TCreateParams);
override;
procedure CreateWnd;
override;
procedure KeyDown(var Key : Word; Shift : TShiftState);
override;
procedure MouseDown(Button : TMouseButton; Shift : TShiftState; X, Y : Integer);
override;
procedure MouseUp(Button : TMouseButton; Shift : TShiftState; X, Y : Integer);
override;
procedure Paint;
override;
{.Z-}
{protected properties}
property BorderStyle : TBorderStyle
read FBorderStyle write SetBorderStyle;
property Colors : TOvcCalcColors
read FColors write FColors;
property Decimals : Integer
read GetDecimals write SetDecimals;
property MaxPaperCount : Integer
read GetMaxPaperCount write SetMaxPaperCount;
property Options : TOvcCalculatorOptions
read FOptions write SetOptions;
property TapeFont : TFont
read GetTapeFont write SetTapeFont;
property TapeHeight : Integer
read GetTapeHeight write SetTapeHeight;
property TapeSeparatorChar : Char
read FTapeSeparatorChar write FTapeSeparatorChar;
property Visible : Boolean
read GetVisible write SetVisible;
{$IFDEF LCL}
property Ctl3D : Boolean read FCtl3D write FCtl3D;
{$ENDIF}
{protected events}
property OnButtonPressed : TOvcCalcButtonPressedEvent
read FOnButtonPressed write FOnButtonPressed;
public
{.Z+}
constructor Create(AOwner : TComponent);
override;
constructor CreateEx(AOwner : TComponent; AsPopup : Boolean);
virtual;
destructor Destroy;
override;
procedure KeyPress(var Key : Char);
override;
procedure PushOperand(const Value : Extended);
procedure SetBounds(ALeft, ATop, AWidth, AHeight : Integer);
override;
{.Z-}
procedure CopyToClipboard;
procedure PasteFromClipboard;
procedure PressButton(Button : TOvcCalculatorButton);
{public properties}
property LastOperand : Extended
read FLastOperand write FLastOperand;
property Memory : Extended
read GetMemory write SetMemory;
property Operand : Extended
read GetOperand write SetOperand;
property DisplayStr : string
read FDisplayStr write SetDisplayStr;
property DisplayValue : Extended
read FDisplay write SetDisplay;
property Tape : TStrings
read GetTape write SetTape;
end;
TOvcCalculator = class(TOvcCustomCalculator)
published
{properties}
{$IFDEF VERSION4}
property Anchors;
property Constraints;
property DragKind;
{$ENDIF}
property About;
property Align;
property BorderStyle default bsNone;
property Ctl3D;
property Font; {must be prior to "Colors"}
property TapeFont; {must be prior to "Colors"}
property Colors;
property Cursor;
property Decimals;
property DragCursor;
property DragMode;
property Enabled;
property LabelInfo;
property MaxPaperCount default 9999;
property TapeHeight ; {Must be Prior to Options}
property Options default [coShowMemoryButtons, coShowItemCount];
{$IFNDEF LCL}
property ParentCtl3D;
{$ENDIF}
property ParentFont;
property ParentShowHint;
property PopupMenu;
property ShowHint;
property TabOrder;
property TabStop default True;
property TapeSeparatorChar default '_';
property Visible default True;
{events}
property OnButtonPressed;
property OnDragDrop;
property OnDragOver;
property OnEndDrag;
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnMouseWheel;
property OnStartDrag;
end;
implementation
const
calcDefMinSize = 30;
{*** TOvcCalcColors ***}
procedure TOvcCalcColors.Assign(Source : TPersistent);
begin
if Source is TOvcCalcColors then begin
FCalcColors := TOvcCalcColors(Source).FCalcColors;
FColorScheme := TOvcCalcColors(Source).FColorScheme;
FOnChange := TOvcCalcColors(Source).FOnChange;
end else
inherited Assign(Source);
end;
procedure TOvcCalcColors.BeginUpdate;
begin
FUpdating := True;
end;
procedure TOvcCalcColors.EndUpdate;
begin
FUpdating := False;
DoOnChange;
end;
procedure TOvcCalcColors.DoOnChange;
begin
if not FUpdating and Assigned(FOnChange) then
FOnChange(Self);
if not SettingScheme then
FColorScheme := cscalcCustom;
end;
function TOvcCalcColors.GetColor(const Index : Integer) : TColor;
begin
Result := FCalcColors[Index];
end;
procedure TOvcCalcColors.SetColor(const Index : Integer; const Value : TColor);
begin
if Value <> FCalcColors[Index] then begin
FCalcColors[Index] := Value;
DoOnChange;
end;
end;
procedure TOvcCalcColors.SetColorScheme(const Value : TOvcCalcColorScheme);
begin
if Value <> FColorScheme then begin
SettingScheme := True;
try
FColorScheme := Value;
if Value <> cscalcCustom then begin
FCalcColors := CalcScheme[Value];
DoOnChange;
end;
finally
SettingScheme := False;
end;
end;
end;
procedure TOvcCalcColors.SetDisplayTextColor(const Value : TColor);
begin
if Value <> FCalcColors[2] then begin
FCalcColors[2] := Value;
DoOnChange;
end;
end;
{*** TOvcCalcTape ***}
constructor TOvcCalcTape.Create(const AOwner : TComponent; const AOperandSize : Integer);
begin
inherited Create;
taOwner := AOwner;
FVisible := False;
taOperandSize := AOperandSize;
taFont := TFont.Create;
taFont.Name := 'Courier New';
taFont.Size := 10;
taFont.Style := [];
end;
destructor TOvcCalcTape.Destroy;
begin
taFont.Free;
taFont := nil;
inherited Destroy;
end;
procedure TOvcCalcTape.ValidateListBox;
begin
if not Assigned(taListBox) then begin
taListBox := TListBox.Create(taOwner);
with taListBox do begin
OnClick := taOnClick;
OnDblClick := taOnDblClick;
OnDrawItem := taOnDrawItem;
Style := lbOwnerDrawFixed;
Parent := taOwner as TWinControl;
ParentFont := False;
{$IFNDEF LCL}
ParentCtl3D := True;
{$ENDIF}
BorderStyle := bsSingle;
Color := taTapeColor;
Visible := FVisible;
Width := taWidth;
Height := taHeight;
Font.Assign(taFont);
Font.OnChange := taFont.OnChange;
taFont.OnChange := taTapeFontChange;
TabStop := False;
end;
taTapeInitialized := False;
end;
InitializeTape;
end;
procedure TOvcCalcTape.Add(const Value : string);
begin
ValidateListBox;
taListBox.Items.Add(Value);
end;
procedure TOvcCalcTape.DeleteFirst;
begin
ValidateListBox;
with taListBox, Items do
if Strings[0] = '' then
taListBox.Items.Delete(0)
else
Inc(taMaxTapeCount);
end;
procedure TOvcCalcTape.SetFont(const Value : TFont);
begin
taFont.Assign(Value);
taFont.OnChange(Self);
end;
function TOvcCalcTape.GetFont : TFont;
begin
Result := taFont;
end;
procedure TOvcCalcTape.SetHeight(const Value : Integer);
begin
taHeight := Value;
if Visible then begin
ValidateListBox;
taListBox.Height := Value;
end;
end;
function TOvcCalcTape.GetHeight : Integer;
begin
if Visible then begin
ValidateListBox;
Result := taListBox.Height;
end else
Result := taHeight;
end;
function TOvcCalcTape.GetTape : TStrings;
begin
ValidateListBox;
Result := taListBox.Items;
end;
procedure TOvcCalcTape.SetTape(const Value : TStrings);
begin
ValidateListBox;
taListBox.Items.Assign(Value);
end;
function TOvcCalcTape.GetTapeColor : TColor;
begin
if Visible then begin
ValidateListBox;
Result := taListBox.Color;
end else
Result := taTapeColor;
end;
procedure TOvcCalcTape.SetTapeColor(const Value : TColor);
begin
taTapeColor := Value;
if Visible then begin
ValidateListBox;
taListBox.Color := Value;
end;
end;
procedure TOvcCalcTape.SetTop(const Value : Integer);
begin
ValidateListBox;
taListBox.Top := Value;
end;
function TOvcCalcTape.GetTop : Integer;
begin
ValidateListBox;
Result := taListBox.Top;
end;
function TOvcCalcTape.GetVisible : Boolean;
begin
Result := FVisible;
end;
procedure TOvcCalcTape.SetVisible(const Value : Boolean);
begin
FVisible := Value;
if Assigned(taListBox) then begin
if not Value and taListBox.Visible then begin
if csDesigning in taListBox.Owner.ComponentState then begin
{$IFDEF VERSION4}
taListBox.Visible := Value;
taListBox.Height := 0;
{$ELSE}
taListBox.Free;
taListBox := nil;
{$ENDIF}
end else
taListBox.Visible := Value;
end else if Value and not taListBox.Visible then begin
taListBox.Visible := Value;
{$IFDEF VERSION4}
taListBox.Height := taHeight;
{$ENDIF}
end;
end else if Value then begin
ValidateListBox;
taListBox.Visible := Value;
end;
end;
procedure TOvcCalcTape.SetWidth(const Value : Integer);
begin
taWidth := Value;
if Visible then begin
ValidateListBox;
taListBox.Width := Value;
end;
end;
function TOvcCalcTape.GetWidth : Integer;
begin
if Visible then begin
ValidateListBox;
Result := taListBox.Width;
end else
Result := taWidth;
end;
procedure TOvcCalcTape.SetTopIndex(const Value : Integer);
begin
ValidateListBox;
taListBox.TopIndex := Value;
end;
function TOvcCalcTape.GetTopIndex : Integer;
begin
ValidateListBox;
Result := taListBox.TopIndex;
end;
procedure TOvcCalcTape.SetBounds(const ALeft, ATop, AWidth, AHeight : Integer);
begin
ValidateListBox;
taListBox.SetBounds(ALeft, ATop, AWidth, AHeight);
end;
procedure TOvcCalcTape.InitializeTape;
begin
if not Assigned(taListBox) then
Exit;
if csDesigning in taListBox.Owner.ComponentState then
if not taListBox.HandleAllocated then
Exit;
if taTapeInitialized then
Exit;
ClearTape;
taTapeInitialized := True;
end;
procedure TOvcCalcTape.taOnClick(Sender : TObject);
begin
ValidateListBox;
(taListBox.Owner as TOvcCustomCalculator).SetFocus;
end;
procedure TOvcCalcTape.taOnDblClick(Sender : TObject);
var
Str : string;
begin
ValidateListBox;
if (taListBox.Items.Count < 1) then
Exit;
Str := taListBox.Items.Strings[taListBox.ItemIndex];
try
if (Str[1] = '0') and
(Str[2] <> '.') then
Exit;
if taListBox.Items.Strings[taListBox.ItemIndex] <> '' then begin
(taListBox.Owner as TOvcCustomCalculator).DisplayValue :=
StrToFloat(Copy(Str,1, Length(Str) - taOperandSize));
(taListBox.Owner as TOvcCustomCalculator).LastOperand :=
StrToFloat(Copy(Str,1, Length(Str) - taOperandSize));
(taListBox.Owner as TOvcCustomCalculator).Operand :=
StrToFloat(Copy(Str,1, Length(Str) - taOperandSize));
(taListBox.Owner as TOvcCustomCalculator).DisplayStr :=
Copy(Str,1, Length(Str) - taOperandSize);
(taListBox.Owner as TOvcCustomCalculator).SetFocus;
end;
except
end;
end;
procedure TOvcCalcTape.taOnDrawItem(Control: TWinControl; Index: Integer;
Rect:TRect;State: TOwnerDrawState);
var
SaveColor : TColor;
SaveBack : TColor;
Str : String;
I, FirstUsedIndex : Integer;
begin
FirstUsedIndex := 0;
if Index > FMaxPaperCount then
with (Control as TListBox) do begin
for I := 0 to Index do begin
if Items[I] <> '' then begin
FirstUsedIndex := I;
Break;
end;
end;
end;
Str := (Control as TListBox).Items[Index];
with (Control as TListBox).Canvas do begin { draw on control canvas, not on the form }
FillRect(Rect); { clear the rectangle }
SaveColor := (Control as TListBox).Canvas.Font.Color;
try
SaveBack := (Control as TListBox).Canvas.Brush.Color;
try
if (Trim(Str) <> '') then begin
if (Trim(Str)[1] = '-') then
(Control as TListBox).Canvas.Font.Color := clRed;
if FTapeDisplaySpace > Length(Str) then
Str := Str + StringOfChar(' ', FTapeDisplaySpace - Length(Str));
TextOut(Rect.Left, Rect.Top, Copy(Str, 1, Length(Str) - 1));
if Index - FirstUsedIndex >= FMaxPaperCount then
(Control as TListBox).Canvas.Brush.Color := clRed;
TextOut(PenPos.X, PenPos.Y, Copy(Str, Length(Str), 1));
end;
finally
(Control as TListBox).Canvas.Brush.Color := SaveBack;
end;
finally
(Control as TListBox).Canvas.Font.Color := SaveColor;
end;
end;
end;
procedure TOvcCalcTape.taTapeFontChange(Sender : TObject);
begin
if Visible then begin
taListBox.Font.Assign(taFont);
taListBox.Font.OnChange(Sender);
end;
end;
function TOvcCalcTape.GetDisplayedItemCount : Integer;
var
DC : hDC;
SaveFont : hFont;
Size : TSize;
begin
if not Assigned(taListBox) then begin
Result := 0;
Exit;
end;
DC := GetDC(0);
SaveFont := SelectObject(DC, taListBox.Font.Handle);
GetTextExtentPoint(DC, ' 0123456789', 11, Size);
Result := taListBox.ClientHeight div Size.cy;
if Result < 3 then
Result := 3;
SelectObject(DC, SaveFont);
ReleaseDC(0, DC);
end;
procedure TOvcCalcTape.AddToTape(const Value : string; const OpString : string);
{-adds an operand to the tape display}
var
TapeString : string;
DSpace : Integer;
begin
DSpace := FTapeDisplaySpace - Length(Value);
TapeString := StringOfChar(' ', DSpace - taOperandSize);
TapeString := TapeString + Value + ' ' + OpString;
Add(TapeString);
DeleteFirst;
TopIndex := taMaxTapeCount - GetDisplayedItemCount + 2;
end;
{adds an operand to the tape display}
procedure TOvcCalcTape.AddToTapeLeft(const Value : string);
var
TapeString : string;
DSpace : Integer;
begin
DSpace := FTapeDisplaySpace - Length(Value);
TapeString := StringOfChar(' ', DSpace);
TapeString := Value + TapeString;
Add(Value);
DeleteFirst;
TopIndex := taMaxTapeCount - GetDisplayedItemCount + 2;
end;
procedure TOvcCalcTape.ClearTape;
var
I : Integer;
begin
if not Assigned(taListBox) then
Exit;
if csDesigning in taListBox.Owner.ComponentState then
if not taListBox.HandleAllocated then
Exit;
taMaxTapeCount := 30; {set starting line count}
taListBox.Items.Clear;
for I := 0 to taMaxTapeCount - 1 do
taListBox.Items.Add('');
taListBox.TopIndex := taMaxTapeCount - GetDisplayedItemCount + 2;
end;
procedure TOvcCalcTape.RefreshDisplays;
var
I, Diff : Integer;
S : string;
function AllSame(const Str : string) : Boolean;
var
I : Integer;
begin
Result := True;
for I := 2 to Length(Str) do begin
if Str[1] <> Str[I] then
Exit;
end;
end;
begin
if not Assigned(taListBox) then
Exit;
if not taListBox.HandleAllocated then
Exit;
if FShowTape then begin
for I := 0 to taMaxTapeCount - 1 do begin
S := taListBox.Items.Strings[I];
if S <> '' then begin
Diff := FTapeDisplaySpace - Length(S);
if S[1] = ' ' then begin
if Diff >= 0 then
S := StringOfChar(' ', Diff) + S
else if AllSame(copy(S, 1, -Diff)) then
S := copy(S,-Diff + 1, Length(S));
end else begin
if AllSame(S) and (not (S[1] in ['0'..'9'])) then
if Diff >= 0 then
S := S + StringOfChar(S[1], Diff)
else
S := copy(S, 1, Length(S)-Diff + 1)
else if (Diff >= 0) and not ((S[1] <> '0') or (S[2] <> '.')) then
S := StringOfChar(' ', Diff) + S;
end;
taListBox.Items.Strings[I] := S;
end;
end;
taListBox.TopIndex := taMaxTapeCount - GetDisplayedItemCount + 2;
end;
end;
procedure TOvcCalcTape.SpaceTape(const Value : char);
var
TapeString : string;
begin
TapeString := StringOfChar(Value, FTapeDisplaySpace);
Add(TapeString);
DeleteFirst;
TopIndex := taMaxTapeCount - GetDisplayedItemCount + 2;
end;
{*** TOvcCustomCalculatorEngine ***}
procedure TOvcCustomCalculatorEngine.ClearAll;
var
I : Integer;
begin
for I := 0 to 3 do
cOperands[I] := 0;
cLastOperation := coNone;
cOperationCount := 0;
cState := [csValid, csClear];
end;
procedure TOvcCustomCalculatorEngine.PushOperand(const Value : Extended);
var
I : Integer;
begin
for I := 2 downto 0 do
cOperands[I+1] := cOperands[I];
cOperands[0] := Value;
end;
function TOvcCustomCalculatorEngine.PopOperand : Extended;
var
I : Integer;
begin
Result := cOperands[0];
for I := 0 to 2 do
cOperands[I] := cOperands[I+1];
cOperands[3] := 0;
end;
function TOvcCustomCalculatorEngine.TopOperand : Extended;
begin
Result := cOperands[0];
end;
{*** TOvcBasicCalculatorEngine ***}
type
TOvcBasicCalculatorEngine = class(TOvcCustomCalculatorEngine)
protected {private}
{internal methods}
procedure cEvaluate(const Operation : TOvcCalculatorOperation);
public
function AddOperand(const Value : Extended; const Button : TOvcCalculatorOperation) : Boolean;
override;
function AddOperation(const Button : TOvcCalculatorOperation) : Boolean;
override;
end;
function TOvcBasicCalculatorEngine.AddOperand(
const Value : Extended;
const Button : TOvcCalculatorOperation) : Boolean;
var
I : Integer;
begin
Result := False;
if Button <> coNone then begin
if csValid in cState then begin
Result := True;
for I := 2 downto 0 do
cOperands[I+1] := cOperands[I];
cOperands[0] := Value;
end;
end;
end;
procedure TOvcBasicCalculatorEngine.cEvaluate(const Operation : TOvcCalculatorOperation);
begin
if csValid in cState then begin
{evaluate the expression}
case Operation of
coAdd : begin
cOperands[1] := cOperands[1] + cOperands[0];
PopOperand;
end;
coSub : begin
cOperands[1] := cOperands[1] - cOperands[0];
PopOperand;
end;
coMul : begin
cOperands[1] := cOperands[1] * cOperands[0];
PopOperand;
end;
coDiv : begin
cOperands[1] := cOperands[1] / cOperands[0];
PopOperand;
end;
coEqual : ;
coNone : ;
coPercent : begin
if cLastOperation in [coAdd, coSub] then
cOperands[0] := (cOperands[0] / 100) * cOperands[1] {do markup/down}
else
cOperands[0] := cOperands[0] / 100; {as a percentage}
cState := [csValid, csClear];
end;
coMemStore : begin
cMemory := cOperands[0];
Include(cState, csClear);
end;
coMemRecall : begin
cOperands[0] := cMemory;
cState := [csValid, csClear];
end;
coMemClear : begin
cMemory := 0;
end;
coMemAdd,
coMemSub : begin
try
if Operation = coMemAdd then
cMemory := cMemory + cOperands[0]
else
cMemory := cMemory - cOperands[0];
except
cMemory := 0;
end;
Include(cState, csClear);
end;
coInvert : begin
cOperands[0] := 1 / cOperands[0];
end;
coSqrt : begin
cOperands[0] := Sqrt(cOperands[0]);
end;
end;
end;
end;
function TOvcBasicCalculatorEngine.AddOperation(const Button : TOvcCalculatorOperation) : Boolean;
begin
Result := False;
if csValid in cState then begin
{evaluate the expression}
case Button of
coAdd : begin
cEvaluate(cLastOperation);
cState := [csValid, csClear];
if cLastOperation in [coAdd, coSub] then
Inc(cOperationCount)
else
cOperationCount := 1;
cLastOperation := Button;
Result := True;
end;
coSub : begin
cEvaluate(cLastOperation);
cState := [csValid, csClear];
if cLastOperation in [coAdd, coSub] then
Inc(cOperationCount)
else
cOperationCount := 1;
cLastOperation := Button;
Result := True;
end;
coMul : begin
cEvaluate(cLastOperation);
cState := [csValid, csClear];
if cLastOperation = Button then
cOperationCount := cOperationCount + 1
else
cOperationCount := 1;
cLastOperation := Button;
Result := True;
end;
coDiv : begin
cEvaluate(cLastOperation);
cState := [csValid, csClear];
if cLastOperation = Button then
cOperationCount := cOperationCount + 1
else
cOperationCount := 1;
cLastOperation := Button;
Result := True;
end;
coEqual : begin
Include(cState, csClear);
if cLastOperation <> coNone then begin
cEvaluate(cLastOperation);
cState := [csClear, csValid];
if cLastOperation = coEqual then
cLastOperation := coNone
else
cLastOperation := Button;
end;
Result := True;
end;
coNone : Result := True;
coPercent : begin
cEvaluate(Button);
if not ShowSeparatePercent then begin
cEvaluate(cLastOperation);
cState := [csValid, csClear];
if cLastOperation = Button then
cOperationCount := cOperationCount + 1
else
cOperationCount := 0;
cLastOperation := coEqual;
Result := True;
end else begin
if cLastOperation = Button then
cOperationCount := cOperationCount + 1
else
cOperationCount := 0;
Result := True;
end;
end;
coMemStore : begin
cEvaluate(Button);
end;
coMemRecall : begin
cEvaluate(Button);
Result := True;
end;
coMemClear : begin
cEvaluate(Button);
end;
coMemAdd,
coMemSub : begin
cEvaluate(Button);
end;
coInvert : begin
cEvaluate(Button);
Result := True;
end;
coSqrt : begin
cEvaluate(Button);
Result := True;
end;
end;
end;
end;
{*** TOvcCalcPanel ***}
procedure TOvcCalcPanel.Click;
begin
(Owner as TOvcCustomCalculator).SetFocus;
end;
{*** TOvcCustomCalculator ***}
procedure TOvcCustomCalculator.cAdjustHeight;
var
DC : hDC;
SaveFont : hFont;
I : Integer;
SysMetrics : TTextMetric;
Metrics : TTextMetric;
begin
DC := GetDC(0);
GetTextMetrics(DC, SysMetrics);
SaveFont := SelectObject(DC, Font.Handle);
GetTextMetrics(DC, Metrics);
SelectObject(DC, SaveFont);
ReleaseDC(0, DC);
if NewStyleControls then begin
if Ctl3D then
I := 8
else
I := 6;
I := GetSystemMetrics(SM_CYBORDER) * I;
end else begin
I := SysMetrics.tmHeight;
if I > Metrics.tmHeight then
I := Metrics.tmHeight;
I := I div 4 + GetSystemMetrics(SM_CYBORDER) * 4;
end;
cPanel.Height := Metrics.tmHeight + I;
end;
procedure TOvcCustomCalculator.cCalculateLook;
var
CW : Integer; {client width}
BW : Integer; {button width}
BH : Integer; {button height}
LBW : Integer; {large button width}
M1 : Integer; {margin between buttons}
M2 : Integer; {left and right edge margins}
M3 : Integer; {margin between panel and frst row of buttons}
M4 : Integer; {margin between memory buttons and other buttons}
TM : Integer; {area where the panel is placed}
X : Integer;
Y : Integer;
PW : Integer; {panel width}
B : TOvcCalculatorButton;
begin
if not HandleAllocated then
Exit;
{set panel height based on font}
cAdjustHeight;
for B := Low(cButtons) to High(cButtons) do
cButtons[B].Visible := True;
CW := ClientWidth;
if Width <= 200 then begin
M1 := 2;
M2 := 4;
end else begin
M1 := 4;
M2 := 6;
end;
{save left/right/top/bottom margin value}
cMargin := M2;
M4 := M2;
if coShowMemoryButtons in FOptions then begin
BW := (CW - 3*M2 - 4*M1) div 6;
M4 := CW - 2*M2 - 6*BW - 4*M1;
end else begin
BW := (CW - 2*M2 - 4*M1) div 5;
if (CW - 2*M2 - 4*M1) div 6 >= 4 then
Inc(M2, 2)
else if (CW - 2*M2 - 4*M1) div 6 >= 2 then
Inc(M2, 1);
end;
{button height, using an estimate for TM}
TM := M2 + M2 + cPanel.Height;
if coShowTape in FOptions then
TM := TM + M2 + cTape.Height;
BH := (ClientHeight - TM - M2 - 4*M1) div 5;
{calculate actual area below panel}
M3 := ClientHeight - M2 - cPanel.Height - 5*BH - 4*M1 - M2;
{calculate actual height of area above buttons}
TM := M2 + M3 + cPanel.Height;
{large button width}
if coShowClearTapeButton in FOptions then
LBW := (5*BW + 3*M1 - 2*M1) div 4
else
LBW := (4*BW + 3*M1 - 2*M1) div 3;
{calculate the width of the edit window}
cMargin := M2;
if coShowMemoryButtons in FOptions then
PW := 6*BW + M4 + 4*M1
else
PW := 5*BW + 4*M1;
if coShowTape in FOptions then
PW := PW - cScrBarWidth;
{position tape display and edit panel}
if coShowTape in FOptions then begin
cTape.Visible := True;
cTape.SetBounds(cMargin, cMargin, PW + cScrBarWidth, cTape.Height);
cPanel.SetBounds(cMargin + 2, cTape.Height + M2 +
cMargin, PW, cPanel.Height);
end else begin
cTape.Visible := False;
cPanel.SetBounds(cMargin, cMargin, PW, cPanel.Height);
end;
{calculate # of characters required to fill display space}
{"FontWidth div 2" makes sure there is no cut off charaters}
if coShowTape in FOptions then
cTape.TapeDisplaySpace := (cTape.Width - cScrBarWidth - (cGetFontWidth div 2))
div cGetFontWidth
else
cTape.TapeDisplaySpace := (cPanel.Width - (cGetFontWidth div 2)) div cGetFontWidth;
cTape.InitializeTape;
{redraw the edit panel and Tape}
cRefreshDisplays;
{memory column}
if coShowMemoryButtons in FOptions then begin
X := M2;
Y := TM;
cButtons[cbMemClear].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cbMemClear].Caption := GetOrphStr(SCCalcMC);
Y := TM + BH + M1;
cButtons[cbMemRecall].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cbMemRecall].Caption := GetOrphStr(SCCalcMR);
Y := TM + 2*BH + 2*M1;
cButtons[cbMemStore].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cbMemStore].Caption := GetOrphStr(SCCalcMS);
Y := TM + 3*BH + 3*M1;
cButtons[cbMemAdd].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cbMemAdd].Caption := GetOrphStr(SCCalcMPlus);
Y := TM + 4*BH + 4*M1;
cButtons[cbMemSub].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cbMemSub].Caption := GetOrphStr(SCCalcMMinus);
end else
for B := cbMemClear to cbMemSub do
cButtons[B].Visible := False;
{row 1 - large buttons}
Y := TM;
if coShowMemoryButtons in FOptions then
if coShowClearTapeButton in FOptions then
X := BW + M2 + M4
else
X := 2*BW + M4 + M2 + M1
else
if coShowClearTapeButton in FOptions then
X := M2
else
X := BW + M2 + M1;
cButtons[cbTape].Position := Rect(X, Y, X+LBW, Y+BH);
cButtons[cbTape].Caption := GetOrphStr(SCCalcCT);
if coShowClearTapeButton in FOptions then begin
cButtons[cbTape].Visible := True;
Inc(X, LBW+M1);
if ((BW+M1)*5 - (LBW+M1)*4) >= 3 then
Inc(X, 1);
end else begin
cButtons[cbTape].Visible := False;
end;
cButtons[cbBack].Position := Rect(X, Y, X+LBW, Y+BH);
cButtons[cbBack].Caption := GetOrphStr(SCCalcBack);
Inc(X, LBW+M1);
if coShowClearTapeButton in FOptions then begin
if ((BW+M1)*5 - (LBW+M1)*4) >= 2 then
Inc(X, 1);
end else begin
if ((BW+M1)*4 - (LBW+M1)*3) >= 2 then
Inc(X, 1);
end;
cButtons[cbClearEntry].Position := Rect(X, Y, X+LBW, Y+BH);
cButtons[cbClearEntry].Caption := GetOrphStr(SCCalcCE);
Inc(X, LBW+M1);
if coShowClearTapeButton in FOptions then begin
if ((BW+M1)*5 - (LBW+M1)*4) >= 1 then
Inc(X, 1);
end else begin
if ((BW+M1)*4 - (LBW+M1)*3) >= 1 then
Inc(X, 1);
end;
cButtons[cbClear].Position := Rect(X, Y, X+LBW, Y+BH);
cButtons[cbClear].Caption := GetOrphStr(SCCalcC);
{row 2}
Y := TM + BH + M1;
if coShowMemoryButtons in FOptions then
X := M2 + BW + M4
else
X := M2;
cButtons[cb7].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cb7].Caption := '7';
Inc(X, BW+M1);
cButtons[cb8].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cb8].Caption := '8';
Inc(X, BW+M1);
cButtons[cb9].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cb9].Caption := '9';
Inc(X, BW+M1);
cButtons[cbDiv].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cbDiv].Caption := '/';
Inc(X, BW+M1);
cButtons[cbSqrt].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cbSqrt].Caption := GetOrphStr(SCCalcSqrt);
{row 3}
Y := TM + 2*BH + 2*M1;
if coShowMemoryButtons in FOptions then
X := M2 + BW + M4
else
X := M2;
cButtons[cb4].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cb4].Caption := '4';
Inc(X, BW+M1);
cButtons[cb5].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cb5].Caption := '5';
Inc(X, BW+M1);
cButtons[cb6].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cb6].Caption := '6';
Inc(X, BW+M1);
cButtons[cbMul].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cbMul].Caption := '*';
Inc(X, BW+M1);
cButtons[cbPercent].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cbPercent].Caption := '%';
{row 4}
Y := TM + 3*BH + 3*M1;
if coShowMemoryButtons in FOptions then
X := M2 + BW + M4
else
X := M2;
cButtons[cb1].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cb1].Caption := '1';
Inc(X, BW+M1);
cButtons[cb2].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cb2].Caption := '2';
Inc(X, BW+M1);
cButtons[cb3].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cb3].Caption := '3';
Inc(X, BW+M1);
cButtons[cbSub].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cbSub].Caption := '-';
Inc(X, BW+M1);
cButtons[cbInvert].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cbInvert].Caption := '1/x';
{row 5}
Y := TM + 4*BH + 4*M1;
if coShowMemoryButtons in FOptions then
X := M2 + BW + M4
else
X := M2;
cButtons[cb0].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cb0].Caption := '0';
Inc(X, BW+M1);
cButtons[cbChangeSign].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cbChangeSign].Caption := '+/-';
Inc(X, BW+M1);
cButtons[cbDecimal].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cbDecimal].Caption := DecimalSeparator;
Inc(X, BW+M1);
cButtons[cbAdd].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cbAdd].Caption := '+';
Inc(X, BW+M1);
cButtons[cbEqual].Position := Rect(X, Y, X+BW, Y+BH);
cButtons[cbEqual].Caption := '=';
end;
procedure TOvcCustomCalculator.cClearAll;
begin
if not HandleAllocated then
Exit;
cEngine.ClearAll;
FLastOperand := 0;
DisplayValue := 0;
FDisplayStr := '0';
cMinus0 := False;
cTape.InitializeTape;
cPanel.Caption := StringOfChar(' ',
(cTape.TapeDisplaySpace
- Length('0')
- Length(CalcDisplayString[cbNone]))
) + '0' + ' ';
end;
procedure TOvcCustomCalculator.cColorChange(Sender : TObject);
begin
{update panel background color}
if Assigned(cPanel) then begin
cPanel.Color := FColors.Display;
cPanel.Font.Color := FColors.DisplayTextColor;
{update the main font color}
if not (csLoading in ComponentState) and (Font <> nil) then
Font.Color := FColors.DisplayTextColor;
end;
if Assigned(cTape) then begin
cTape.TapeColor := FColors.Display;
end;
Invalidate;
end;
procedure TOvcCustomCalculator.cDisplayError;
begin
cSetDisplayString('****** ');
cEngine.State := [csLocked]; {user will have to clear this}
MessageBeep(0);
end;
procedure TOvcCustomCalculator.cDrawCalcButton(const Button : TOvcButtonInfo; const Pressed : Boolean);
var
TR : TRect;
Buf : array[0..255] of Char;
begin
if Button.Visible then begin
TR := DrawButtonFace(Canvas, Button.Position, 1, bsNew, False, Pressed, False);
StrPLCopy(Buf, Button.Caption, 255);
DrawText(Canvas.Handle, Buf, StrLen(Buf), TR,
DT_CENTER or DT_VCENTER or DT_SINGLELINE);
if Focused and (Button.Caption = '=') then
cDrawFocusState;
end;
end;
procedure TOvcCustomCalculator.cDrawFocusState;
var
R : TRect;
begin
R := cButtons[cbEqual].Position;
InflateRect(R, -3, -3);
{$IFNDEF LCL}
Canvas.DrawFocusRect(R);
{$ENDIF}
end;
procedure TOvcCustomCalculator.cDrawSizeLine;
var
OldPen : TPen;
begin
if (cSizing) then
with Canvas do begin
OldPen := TPen.Create;
try
OldPen.Assign(Pen);
Pen.Color := clBlack;
Pen.Mode := pmXor;
Pen.Style := psDot;
Pen.Width := 1;
MoveTo(0, cSizeOffset);
LineTo(ClientWidth, cSizeOffset);
finally
Canvas.Pen := OldPen;
OldPen.Free;
end;
end;
end;
procedure TOvcCustomCalculator.cEvaluate(const Button : TOvcCalculatorButton);
begin
if csValid in cEngine.State then begin
try
{evaluate the expression}
if cEngine.AddOperation(CalcButtontoOperation[Button]) then begin
DisplayValue := cEngine.TopOperand;
if Button in [cbAdd, cbSub, cbMul, cbDiv, cbEqual, cbPercent, cbNone] then
if (Button in [cbAdd, cbSub, cbMul, cbDiv]) and (cLastButton = Button) then
cTape.AddToTape(cFormatString(LastOperand), CalcDisplayString[Button])
else
cTape.AddToTape(FDisplayStr, CalcDisplayString[Button]);
if (Button = cbEqual) and (cEngine.LastOperation = coEqual) then begin
if coShowItemCount in FOptions then
cTape.AddToTapeLeft(Format('%3.3d',[cEngine.OperationCount+1]));
cTape.AddToTape(cFormatString(DisplayValue), CalcDisplayString[cbSubTotal]);
cTape.SpaceTape(TapeSeparatorChar);
end;
FDisplayStr := cFormatString(DisplayValue);
end;
except
cDisplayError;
end;
end;
end;
function TOvcCustomCalculator.cFormatString(const Value : Extended) : string;
begin
if cEngine.Decimals = 0 then
Result := Format('%g',[Value])
else if cEngine.Decimals < 0 then
Result := Format('%.*f',[-cEngine.Decimals, Value])
else
Result := Format('%.*f',[cEngine.Decimals, Value]);
end;
function TOvcCustomCalculator.cGetFontWidth : Integer;
var
DC : hDC;
SaveFont : hFont;
Size : TSize;
begin
if not assigned(cPanel) then begin
Result := 8; {Return something resonable }
Exit;
end;
DC := GetDC(0);
SaveFont := SelectObject(DC, cPanel.Font.Handle);
GetTextExtentPoint(DC, ' 0123456789', 11, Size);
Result := Round(Size.cx/11);
SelectObject(DC, SaveFont);
ReleaseDC(0, DC);
end;
procedure TOvcCustomCalculator.cInvalidateIndicator;
begin
InvalidateRect(Handle, @cButtons[cbMemRecall].Position, False);
InvalidateRect(Handle, @cButtons[cbMemClear].Position, False);
end;
procedure TOvcCustomCalculator.cRefreshDisplays;
begin
if not cPanel.HandleAllocated then
Exit;
cTape.RefreshDisplays;
{ DisplayValue := DisplayValue; }
end;
procedure TOvcCustomCalculator.cSetDisplayString(const Value : string);
var
DSpace : Integer;
begin
try
if cPanel.HandleAllocated then begin
DSpace := cTape.TapeDisplaySpace
- Length(Value)
- Length(CalcDisplayString[cbNone]);
cPanel.Caption := StringOfChar(' ', DSpace) + Value + ' ';
end;
except
cDisplayError;
end;
end;
procedure TOvcCustomCalculator.cTapeFontChange(Sender : TObject);
begin
cPanel.Font := TapeFont;
end;
procedure TOvcCustomCalculator.SetBorderStyle(const Value : TBorderStyle);
begin
if Value <> FBorderStyle then begin
FBorderStyle := Value;
{$IFNDEF LCL}
RecreateWnd;
{$ELSE}
RecreateWnd(Self);
{$ENDIF}
end;
end;
function TOvcCustomCalculator.GetDecimals : Integer;
begin
Result := cEngine.Decimals;
end;
procedure TOvcCustomCalculator.SetDecimals(const Value : Integer);
begin
if Value <> cEngine.Decimals then begin
cEngine.Decimals := Value;
ccalculateLook;
Invalidate;
end;
end;
function TOvcCustomCalculator.GetMemory : Extended;
begin
Result := cEngine.Memory;
end;
procedure TOvcCustomCalculator.SetMemory(const Value : Extended);
begin
if Value <> cEngine.Memory then begin
cEngine.Memory := Value;
cCalculateLook;
Invalidate;
end;
end;
procedure TOvcCustomCalculator.SetMaxPaperCount(const Value : Integer);
begin
if Value <> cTape.MaxPaperCount then begin
cTape.MaxPaperCount := Value;
Invalidate;
end;
end;
function TOvcCustomCalculator.GetMaxPaperCount : Integer;
begin
Result := cTape.MaxPaperCount;
end;
procedure TOvcCustomCalculator.SetOptions(const Value : TOvcCalculatorOptions);
begin
if Value <> FOptions then begin
FOptions := Value;
cTape.ShowTape := coShowTape in FOptions;
cTape.Visible := coShowTape in FOptions;
cEngine.ShowSeparatePercent := coShowSeparatePercent in FOptions;
cCalculateLook;
Invalidate;
end;
end;
function TOvcCustomCalculator.GetTape : TStrings;
begin
Result := cTape.Tape;
end;
procedure TOvcCustomCalculator.SetTape(const Value : TStrings);
begin
cTape.Tape := Value;
end;
function TOvcCustomCalculator.GetTapeFont : TFont;
begin
Result := cTape.Font;
end;
procedure TOvcCustomCalculator.SetTapeFont(const Value : TFont);
begin
cTape.Font := Value;
end;
function TOvcCustomCalculator.GetTapeHeight : Integer;
begin
Result := cTape.Height;
end;
procedure TOvcCustomCalculator.SetTapeHeight(const Value : Integer);
begin
cTape.Height := Value;
cCalculateLook;
Invalidate;
end;
function TOvcCustomCalculator.GetVisible : Boolean;
begin
Result := inherited Visible;
end;
procedure TOvcCustomCalculator.SetVisible(const Value : Boolean);
begin
inherited Visible := Value;
cTape.Visible := cTape.ShowTape;
end;
procedure TOvcCustomCalculator.SetDisplay(const Value : Extended);
var
ValueString : string;
begin
try
FDisplay := Value;
if cPanel.HandleAllocated then begin
ValueString := cFormatString(Value);
cSetDisplayString(ValueString);
end;
except
cDisplayError;
end;
end;
procedure TOvcCustomCalculator.SetDisplayStr(const Value : string);
begin
FDisplayStr := Value;
while (Length(FDisplayStr) > 0) and (FDisplayStr[1] = ' ') do
FDisplayStr := Copy(FDisplayStr, 2, Length(FDisplayStr) - 1);
end;
function TOvcCustomCalculator.GetOperand : Extended;
begin
Result := cEngine.TopOperand;
end;
procedure TOvcCustomCalculator.SetOperand(const Value : Extended);
begin
if Value = cEngine.TopOperand then
Exit;
cEngine.PushOperand(Value);
end;
{$IFNDEF LCL}
procedure TOvcCustomCalculator.CMCtl3DChanged(var Msg : TMessage);
begin
inherited;
if (csLoading in ComponentState) or not HandleAllocated then
Exit;
if NewStyleControls and (FBorderStyle = bsSingle) then
{$IFNDEF LCL}
RecreateWnd;
{$ENDIF}
Invalidate;
end;
{$ENDIF}
procedure TOvcCustomCalculator.CMDesignHitTest(var Msg : TCMDesignHitTest);
begin
Msg.Result := LongInt(cOverBar);
end;
procedure TOvcCustomCalculator.CMEnter(var Msg : TMessage);
var
R : TRect;
begin
inherited;
{invalidate the "=" button to ensure that the focus rect is painted}
R := cButtons[cbEqual].Position;
InvalidateRect(Handle, @R, False);
end;
procedure TOvcCustomCalculator.CMExit(var Msg : TMessage);
var
R : TRect;
begin
inherited;
{invalidate the "=" button to ensure that the focus rect is painted}
R := cButtons[cbEqual].Position;
InvalidateRect(Handle, @R, False);
end;
procedure TOvcCustomCalculator.CMFontChanged(var Msg : TMessage);
begin
inherited;
if not (csLoading in ComponentState) and Assigned(cPanel) then begin
cPanel.Color := FColors.Display;
cPanel.Font.Color := FColors.DisplayTextColor;
FColors.FCalcColors[2] := Font.Color;
end;
cCalculateLook;
Invalidate;
end;
procedure TOvcCustomCalculator.WMEraseBkgnd(var Msg : TWMEraseBkgnd);
begin
Msg.Result := 1; {don't erase background, just say we did}
end;
procedure TOvcCustomCalculator.WMGetText(var Msg : TWMGetText);
begin
if not cPanel.HandleAllocated then
Exit;
Msg.Result := SendMessage(cPanel.Handle, WM_GETTEXT,
TMessage(Msg).wParam, TMessage(Msg).lParam);
end;
procedure TOvcCustomCalculator.WMGetTextLength(var Msg : TWMGetTextLength);
begin
if not cPanel.HandleAllocated then
Exit;
Msg.Result := SendMessage(cPanel.Handle, WM_GETTEXTLENGTH,
TMessage(Msg).wParam, TMessage(Msg).lParam);
end;
procedure TOvcCustomCalculator.WMKeyDown(var Msg : TWMKeyDown);
begin
if Msg.CharCode = Ord('M') then begin
if ({$IFNDEF LCL} GetAsyncKeyState(VK_CONTROL) {$ELSE} GetKeyState(VK_CONTROL) {$ENDIF} and $8000) <> 0 then begin
PressButton(cbMemStore);
end;
end else if Msg.CharCode = VK_RETURN then
PressButton(cbEqual);
inherited;
end;
procedure TOvcCustomCalculator.WMSetText(var Msg : TWMSetText);
var
I : Integer;
C : AnsiChar;
begin
cClearAll;
for I := 0 to Pred(StrLen(Msg.Text)) do begin
C := Msg.Text[I];
KeyPress(C);
end;
Msg.Result := 1{true};
end;
procedure TOvcCustomCalculator.WMNCHitTest(var Msg : TWMNCHitTest);
begin
inherited;
cHitTest.X := Msg.Pos.X;
cHitTest.Y := Msg.Pos.Y;
end;
procedure TOvcCustomCalculator.WMSetCursor(var Msg : TWMSetCursor);
var
vHitTest : TPoint;
procedure SetNewCursor(C : HCursor);
begin
{$IFNDEF LCL}
SetCursor(C);
{$ELSE}
LclIntf.SetCursor(C); {Don't call control's SetCursor!}
{$ENDIF}
Msg.Result := Ord(True);
end;
begin
if not (coShowTape in FOptions) then
Exit;
if csDesigning in ComponentState then begin
if (Msg.HitTest = HTCLIENT) then begin
cOverBar := False;
vHitTest := ScreenToClient(cHitTest);
if vHitTest.Y > cTape.Top + cTape.Height then
if vHitTest.Y < cTape.Top + cTape.Height+4 then
cOverBar := True;
end;
{set appropriate cursor}
if cOverBar then
SetNewCursor(cTabCursor)
else
inherited;
end else
inherited;
end;
procedure TOvcCustomCalculator.WMCancelMode(var Msg : TMessage);
begin
inherited;
cSizing := False;
end;
procedure TOvcCustomCalculator.WMKillFocus(var Msg : TWMKillFocus);
begin
inherited;
Invalidate;
end;
procedure TOvcCustomCalculator.WMLButtonDown(var Msg : TWMMouse);
begin
inherited;
{are we currently showing a sizing cursor? if so the user wants to
resize a column/row}
if (cOverBar) then begin
cSizeOffset := Msg.YPos;
cSizing := True;
cDrawSizeLine;
end;
end;
procedure TOvcCustomCalculator.WMLButtonUp(var Msg : TWMMouse);
var
Form : TForm;
begin
inherited;
if (cSizing) then begin
cDrawSizeLine;
cSizing := False;
cTape.Height := cSizeOffset - 8;
cCalculateLook;
Refresh;
if (csDesigning in ComponentState) then begin
Form := TForm(GetParentForm(Self));
if (Form <> nil) and (Form.Designer <> nil) then
Form.Designer.Modified;
end;
end;
end;
procedure TOvcCustomCalculator.WMMouseMove(var Msg : TWMMouse);
begin
inherited;
if (cSizing) then begin
cDrawSizeLine;
if Msg.YPos >= calcDefMinSize + cTape.Top then
if Msg.YPos <= Height - calcDefMinSize then
cSizeOffset := Msg.YPos + 2
else
cSizeOffset := Height - calcDefMinSize
else
cSizeOffset := calcDefMinSize + cTape.Top;
cDrawSizeLine;
end;
end;
procedure TOvcCustomCalculator.CopyToClipboard;
begin
Clipboard.AsText := Text;
end;
constructor TOvcCustomCalculator.Create(AOwner : TComponent);
begin
inherited Create(AOwner);
if cPopup then
ControlStyle := ControlStyle + [csClickEvents, csFramed] - [csCaptureMouse]
else
ControlStyle := ControlStyle + [csClickEvents, csFramed, csCaptureMouse];
Color := clBtnFace;
TabStop := True;
Width := 200;
Font.Name := 'MS Sans Serif';
Font.Size := 8;
Font.Style := [];
cDecimalEntered := False;
cSizing := False;
cScrBarWidth := 18;
{create edit control}
cPanel := TOvcCalcPanel.Create(Self);
cPanel.Parent := Self;
cPanel.ParentFont := False;
cPanel.Font.Name := 'Courier New';
cPanel.Font.Size := 10;
cPanel.Font.Style := [];
{$IFNDEF LCL}
cPanel.ParentCtl3D := True;
{$ENDIF}
cPanel.Alignment := taLeftJustify;
cPanel.BevelOuter := bvLowered;
cPanel.BorderStyle := bsNone;
cPanel.Color := clWindow;
cPanel.BevelWidth := 2;
cPanel.Caption := '0 ';
{set property defaults}
FBorderStyle := bsNone;
Height := 140;
FTapeSeparatorChar := '_';
FOptions := [coShowMemoryButtons, coShowItemCount];
FColors := TOvcCalcColors.Create;
FColors.OnChange := cColorChange;
{assign default color scheme}
FColors.FCalcColors := CalcScheme[cscalcWindows];
{create tape}
cTape := TOvcCalcTape.Create(Self, Length(CalcDisplayString[cbNone]));
cTape.ShowTape := False;
cTape.TapeColor := clWindow;
cTape.MaxPaperCount := 9999;
TapeHeight := Height div 3;
TapeFont.OnChange := cTapeFontChange;
TapeFont.Name := 'Courier New';
TapeFont.Size := 10;
TapeFont.Style := [];
cTape.Visible := cTape.ShowTape;
cEngine := TOvcBasicCalculatorEngine.Create;
cEngine.Decimals := 2;
cEngine.ShowSeparatePercent := False;
if csDesigning in ComponentState then
cTabCursor := Screen.Cursors[crVSplit];
end;
constructor TOvcCustomCalculator.CreateEx(AOwner : TComponent; AsPopup : Boolean);
begin
cPopup := AsPopup;
Create(AOwner);
end;
procedure TOvcCustomCalculator.CreateParams(var Params : TCreateParams);
const
BorderStyles : array[TBorderStyle] of LongInt = (0, WS_BORDER);
begin
inherited CreateParams(Params);
with Params do begin
Style := LongInt(Style) or BorderStyles[FBorderStyle];
if cPopup then begin
Style := WS_POPUP or WS_BORDER;
WindowClass.Style := WindowClass.Style or CS_SAVEBITS;
end;
end;
if NewStyleControls and (Ctl3D or cPopup) and (FBorderStyle = bsSingle) then begin
if not cPopup then
Params.Style := Params.Style and not WS_BORDER;
Params.ExStyle := Params.ExStyle or WS_EX_CLIENTEDGE;
end;
end;
procedure TOvcCustomCalculator.CreateWnd;
begin
inherited CreateWnd;
cCalculateLook;
cClearAll;
cPanel.Color := FColors.Display;
end;
destructor TOvcCustomCalculator.Destroy;
begin
cTape.Free;
cTape := nil;
cEngine.Free;
cEngine := nil;
FColors.Free;
FColors := nil;
cTabCursor := 0;
inherited Destroy;
end;
procedure TOvcCustomCalculator.KeyDown(var Key : Word; Shift : TShiftState);
begin
inherited KeyDown(Key, Shift);
case Key of
VK_DELETE : if Shift = [] then
PressButton(cbClearEntry);
VK_F9 : if Shift = [] then
PressButton(cbChangeSign);
end;
end;
procedure TOvcCustomCalculator.KeyPress(var Key : Char);
begin
inherited KeyPress(Key);
case Key of
'0' : PressButton(cb0);
'1' : PressButton(cb1);
'2' : PressButton(cb2);
'3' : PressButton(cb3);
'4' : PressButton(cb4);
'5' : PressButton(cb5);
'6' : PressButton(cb6);
'7' : PressButton(cb7);
'8' : PressButton(cb8);
'9' : PressButton(cb9);
'+' : PressButton(cbAdd);
'-' : PressButton(cbSub);
'*' : PressButton(cbMul);
'/' : PressButton(cbDiv);
'.' : PressButton(cbDecimal);
'=' : PressButton(cbEqual);
'r' : PressButton(cbInvert);
'%' : PressButton(cbPercent);
'@' : PressButton(cbSqrt);
^L : PressButton(cbMemClear); {^L}
^R : PressButton(cbMemRecall); {^R}
^P : PressButton(cbMemAdd); {^P}
^S : PressButton(cbMemSub); {^S}
^T : PressButton(cbTape); {^T}
^C : CopyToClipboard; {^C}{copy}
^V : PasteFromClipboard; {^V}{paste}
#8 : PressButton(cbBack); {backspace}
#27 : PressButton(cbClear); {esc}
else
if Key = DecimalSeparator then
PressButton(cbDecimal);
end;
end;
procedure TOvcCustomCalculator.MouseDown(Button : TMouseButton; Shift : TShiftState; X, Y : Integer);
var
B : TOvcCalculatorButton;
begin
SetFocus;
if Button = mbLeft then begin
cDownButton := cbNone;
for B := Low(cButtons) to High(cButtons) do
if cButtons[B].Visible and PtInRect(cButtons[B].Position, Point(X,Y)) then begin
if (B in [cbMemClear, cbMemRecall]) and (cEngine.Memory = 0) then
Exit;
cDownButton := B;
InvalidateRect(Handle, @cButtons[cDownButton].Position, False);
Break;
end;
end;
inherited MouseDown(Button, Shift, X, Y);
end;
procedure TOvcCustomCalculator.MouseUp(Button : TMouseButton; Shift : TShiftState; X, Y : Integer);
begin
if cDownButton = cbNone then
Exit;
InvalidateRect(Handle, @cButtons[cDownButton].Position, False);
{if still over the button...}
if PtInRect(cButtons[cDownButton].Position, Point(X,Y)) then
PressButton(cDownButton);
cDownButton := cbNone;
inherited MouseUp(Button, Shift, X, Y);
end;
procedure TOvcCustomCalculator.PasteFromClipboard;
var
I : Integer;
C : AnsiChar;
S : string;
begin
S := Clipboard.AsText;
if S > '' then begin
cClearAll;
for I := 1 to Length(S) do begin
C := S[I];
if (C in ['0'..'9', DecimalSeparator, '.', '+', '-', '*', '/', '=', '%']) then
KeyPress(C);
end;
end;
end;
procedure TOvcCustomCalculator.PressButton(Button : TOvcCalculatorButton);
procedure Initialize;
begin
if (cLastButton <> cbClear) and (Button = cbClear) then begin
cClearAll;
cTape.SpaceTape(TapeSeparatorChar);
end;
if (csLocked in cEngine.State) then begin
MessageBeep(0);
Exit;
end;
{this logic is here to make cbEqual clear all the second time}
if (cLastButton in [cbEqual, cbClear, cbNone]) and (Button = cbEqual) then begin
Button := cbClear;
cClearAll;
end;
if (cLastButton = cbPercent) and (Button in [cbAdd, cbSub, cbMul, cbDiv, cbEqual]) then
cEvaluate(Button)
else if ((((cLastButton in [cbEqual, cbMemRecall]) and
(Button in [cbAdd, cbSub, cbMul, cbDiv])))) and
cEngine.AddOperand(StrToFloat(FDisplayStr), CalcButtontoOperation[Button]) then begin
cEvaluate(Button);
end else if (Button = cbMemStore) then begin
if (cLastButton <> cbEqual) then
cEvaluate(Button);
SetMemory(DisplayValue);
end else if cEngine.AddOperand(LastOperand, CalcButtontoOperation[Button]) then begin
cEvaluate(Button);
{remove special operations from stack}
if Button in [cbInvert, cbSqrt, cbEqual] then
LastOperand := cEngine.PopOperand;
end;
end;
procedure NumberButton;
var
D : Extended;
DP : Integer;
begin
begin
if cEngine.LastOperation = coEqual then begin
{clear pending operations if last command was =}
cClearAll;
end;
if csClear in cEngine.State then begin
if (Decimals < 0) then begin
FDisplayStr := '0.' + StringOfChar('0', -Decimals);
end else begin
FDisplayStr := '';
cDecimalEntered := False;
end;
end;
FDisplayStr := FDisplayStr + cButtons[Button].Caption[1];
if cMinus0 then begin
FDisplayStr := '-' + FDisplayStr;
cMinus0 := False;
end;
if (Decimals < 0) and not cDecimalEntered then begin
if Pos(DecimalSeparator, FDisplayStr) > 0 then begin
DP := Pos(DecimalSeparator, FDisplayStr);
if FDisplayStr[1] = '0' then
FDisplayStr := Copy(FDisplayStr,2,DP-2) +
Copy(FDisplayStr,DP+1,1) +
DecimalSeparator +
Copy(FDisplayStr,DP+2,Length(FDisplayStr) - DP)
else
FDisplayStr := Copy(FDisplayStr,1,DP-1) +
Copy(FDisplayStr,DP+1,1) +
DecimalSeparator +
Copy(FDisplayStr,DP+2,Length(FDisplayStr) - DP);
end;
end;
D := StrToFloat(FDisplayStr);
LastOperand := D;
if (D <> 0) or
(Pos(DecimalSeparator, FDisplayStr) > 0) then begin
DisplayValue := D;
cSetDisplayString(FDisplayStr);
cEngine.State := [csValid];
end else begin
FDisplayStr := '0';
DisplayValue := D;
cEngine.State := [csValid, csClear];
end;
end;
end;
procedure DecimalButton;
var
D : Extended;
begin
{check if the decimal was first character entered after a command}
if csClear in cEngine.State then begin
FDisplayStr := '0' + DecimalSeparator;
cSetDisplayString(FDisplayStr);
cDecimalEntered := True;
cEngine.State := [csValid];
end;
{check if there is already a decimal separator in the string}
if Pos(DecimalSeparator, FDisplayStr) = 0 then begin
FDisplayStr := FDisplayStr + DecimalSeparator;
if (pos(DecimalSeparator, FDisplayStr) = 1) then
FDisplayStr := '0' + FDisplayStr;
D := StrToFloat(FDisplayStr);
cSetDisplayString(FDisplayStr);
LastOperand := D;
cEngine.State := [csValid];
cDecimalEntered := True;
end;
end;
procedure BackButton;
var
D : Extended;
DP : Integer;
SaveSign : string;
begin
if FDisplayStr = '' then exit;
D := StrToFloat(FDisplayStr);
if D <> 0 then begin
if Length(FDisplayStr) > 1 then begin
if (Decimals < 0) and not cDecimalEntered then begin
if Pos(DecimalSeparator, FDisplayStr) > 0 then begin
if FDisplayStr[1] = '-' then begin
SaveSign :='-';
FDisplayStr := Copy(FDisplayStr,2,Length(FDisplayStr)-1);
end else begin
SaveSign :='';
end;
DP := Pos(DecimalSeparator, FDisplayStr);
FDisplayStr := '0' + Copy(FDisplayStr,1,DP-2) +
DecimalSeparator +
Copy(FDisplayStr,DP-1,1) +
Copy(FDisplayStr,DP+1,Length(FDisplayStr) - DP);
if (FDisplayStr[1] = '0') and (FDisplayStr[2] <> '.') then
FDisplayStr := Copy(FDisplayStr,2,Length(FDisplayStr)-1);
FDisplayStr := SaveSign + FDisplayStr;
end;
end;
FDisplayStr := Copy(FDisplayStr, 1, Length(FDisplayStr)-1);
LastOperand := StrToFloat(FDisplayStr);
cSetDisplayString(FDisplayStr);
end else begin
LastOperand := 0;
cMinus0 := False;
DisplayValue := LastOperand;
cEngine.State := [csValid, csClear];
end;
end;
end;
procedure ClearEntryButton;
begin
begin
FDisplayStr := '';
LastOperand := 0;
cMinus0 := False;
DisplayValue := LastOperand;
end;
end;
procedure ChangeSignButton;
begin
if Length(FDisplayStr) > 0 then begin
if FDisplayStr[1] <> '-' then begin
FDisplayStr := '-' + FDisplayStr;
LastOperand := StrToFloat(FDisplayStr);
cSetDisplayString(FDisplayStr);
end else begin
FDisplayStr := Copy(FDisplayStr, 2, Length(FDisplayStr)-1);
LastOperand := StrToFloat(FDisplayStr);
cSetDisplayString(FDisplayStr);
end;
DisplayValue := LastOperand;
end else begin
LastOperand := 0;
cMinus0 := not cMinus0;
DisplayValue := LastOperand;
if cMinus0 then
FDisplayStr := '-';
cEngine.State := [csValid, csClear];
end;
end;
procedure ClearTapeButton;
var
I : Integer;
begin
with Tape do begin
for I := 0 to Count - 1 do begin
Strings[I] := '';
end;
cTape.RefreshDisplays;
end;
end;
begin
if not HandleAllocated then
Exit;
{simulate a button down if needed}
if cDownButton = cbNone then begin
cDownButton := Button;
InvalidateRect(Handle, @cButtons[cDownButton].Position, False);
Update;
end;
try try
Initialize;
case Button of
cb0..cb9 : NumberButton;
cbDecimal : DecimalButton;
cbBack : BackButton;
cbClearEntry : ClearEntryButton;
cbMemStore,
cbMemClear,
cbMemAdd,
cbMemSub : cInvalidateIndicator;
cbChangeSign : ChangeSignButton;
cbTape : ClearTapeButton;
cbSqrt,
cbInvert : {};
end;
except
cDisplayError;
end;
finally
{simulate a button up, if the mouse button is up or we aren't focused}
if not Focused or ({$IFNDEF LCL} GetAsyncKeyState(GetLeftButton) {$ELSE} GetKeyState(GetLeftButton) {$ENDIF} and $8000 = 0) then begin
InvalidateRect(Handle, @cButtons[cDownButton].Position, False);
cDownButton := cbNone;
Update;
end;
end;
cLastButton := Button;
if Assigned(FOnButtonPressed) then
FOnButtonPressed(Self, Button);
end;
procedure TOvcCustomCalculator.PushOperand(const Value : Extended);
begin
cEngine.PushOperand(Value);
LastOperand := Value;
DisplayValue := Value;
end;
procedure TOvcCustomCalculator.Paint;
var
B : TOvcCalculatorButton;
begin
Canvas.Font := Font;
Canvas.Brush.Color := clBtnFace;
Canvas.FillRect(ClientRect);
if Ctl3D then begin
cPanel.BevelOuter := bvLowered;
cPanel.BorderStyle := bsNone;
end else begin
cPanel.BevelOuter := bvNone;
cPanel.BorderStyle := bsSingle;
end;
{draw buttons}
for B := Low(cButtons) to High(cButtons) do begin
if (B in [cbMemClear, cbMemRecall, cbMemStore, cbMemAdd, cbMemSub]) then begin
if (B in [cbMemClear, cbMemRecall]) and (cEngine.Memory = 0) then
Canvas.Font.Color := FColors.DisabledMemoryButtons
else
Canvas.Font.Color := FColors.MemoryButtons;
end else if (B in [cbBack, cbClearEntry, cbClear, cbTape]) then
Canvas.Font.Color := FColors.EditButtons
else if (B in [cbAdd, cbSub, cbMul, cbDiv, cbEqual]) then
Canvas.Font.Color := FColors.OperatorButtons
else if (B in [cb0..cb9, cbDecimal]) then
Canvas.Font.Color := FColors.NumberButtons
else if (B in [cbInvert, cbChangeSign, cbPercent, cbSqrt]) then
Canvas.Font.Color := FColors.FunctionButtons;
cDrawCalcButton(cButtons[B], (B = cDownButton));
end;
end;
procedure TOvcCustomCalculator.SetBounds(ALeft, ATop, AWidth, AHeight : Integer);
begin
if Height <> AHeight then
if coShowTape in FOptions then
if Top <> ATop then begin
if TapeHeight + (AHeight - Height) > calcDefMinSize then begin
TapeHeight := TapeHeight + (AHeight - Height);
end else begin
TapeHeight := calcDefMinSize;
end
end;
inherited Setbounds(ALeft, ATop, AWidth, AHeight);
cCalculateLook;
end;
end.