Componentes.Terceros.DevExp.../official/x.42/ExpressEditors Library 3/Sources/dxCalc.pas
2009-02-27 12:02:10 +00:00

1366 lines
43 KiB
ObjectPascal

{*******************************************************************}
{ }
{ Developer Express Visual Component Library }
{ Express Calculator }
{ }
{ Copyright (c) 1998-2009 Developer Express Inc. }
{ ALL RIGHTS RESERVED }
{ }
{ The entire contents of this file is protected by U.S. and }
{ International Copyright Laws. Unauthorized reproduction, }
{ reverse-engineering, and distribution of all or any portion of }
{ the code contained in this file is strictly prohibited and may }
{ result in severe civil and criminal penalties and will be }
{ prosecuted to the maximum extent possible under the law. }
{ }
{ RESTRICTIONS }
{ }
{ THE SOURCE CODE CONTAINED WITHIN THIS FILE AND ALL RELATED }
{ FILES OR ANY PORTION OF ITS CONTENTS SHALL AT NO TIME BE }
{ COPIED, TRANSFERRED, SOLD, DISTRIBUTED, OR OTHERWISE MADE }
{ AVAILABLE TO OTHER INDIVIDUALS WITHOUT EXPRESS WRITTEN CONSENT }
{ AND PERMISSION FROM DEVELOPER EXPRESS INC. }
{ }
{ CONSULT THE END USER LICENSE AGREEMENT FOR INFORMATION ON }
{ ADDITIONAL RESTRICTIONS. }
{ }
{*******************************************************************}
unit dxCalc;
interface
{$I dxEdVer.inc}
uses
Windows, Messages, SysUtils, Classes, Graphics, Controls, Forms, Dialogs,
StdCtrls, Clipbrd, dxCntner;
const
dxDefCalcPrecision = 13;
// Size
dxMinCalcFontSize = 8;
dxCalcMinBoldFontSize = 10;
dxMinCalcBtnWidth = 28;
dxMinCalcBtnHeight = 22;
dxMinCalcLargeBtnWidth = Integer(Trunc(1.7*dxMinCalcBtnWidth));
dxMinCalcXOfs = 4;
dxMinCalcYOfs = 4;
dxMinCalcWidth = (dxMinCalcXOfs+dxMinCalcBtnWidth)*6+dxMinCalcXOfs*3+3;
dxMinCalcHeight = (dxMinCalcYOfs+dxMinCalcBtnHeight)*5+dxMinCalcYOfs+3;
// String resource
dx_Error = 38951;
var
sdxCalcError: string; // 'Error'
type
TdxCalcState = (csFirst, csValid, csError);
TdxButtonStyle = (bsStandard, bsFlat, bsExtraFlat);
TdxCalcButtonKind =
(cbBack, cbCancel, cbClear,
cbMC, cbMR, cbMS, cbMP,
cbNum0, cbNum1, cbNum2, cbNum3, cbNum4, cbNum5, cbNum6, cbNum7, cbNum8, cbNum9,
cbSign, cbDecimal,
cbDiv, cbMul, cbSub, cbAdd,
cbSqrt, cbPercent, cbRev, cbEqual, cbNone);
TdxButtonInfo = record
Kind : TdxCalcButtonKind;
Text : String[4];
FontColor : TColor;
BtnRect : TRect;
Down : Boolean;
Grayed : Boolean;
end;
TCalcButtons = array [TdxCalcButtonKind] of TdxButtonInfo;
TdxCalcButtonClick = procedure(Sender: TObject; var ButtonKind : TdxCalcButtonKind) of object;
TdxCalcGetEditValue = procedure(Sender: TObject; var Value : String) of object;
TdxCalcSetEditValue = procedure(Sender: TObject; const Value : String) of object;
TCustomdxCalculator = class(TdxInplacePopupControl)
private
{calc style}
FAutoFontSize : Boolean;
FBeepOnError: Boolean;
FButtonStyle : TdxButtonStyle;
FBorderStyle : TBorderStyle;
FButtonFrameVisible : Boolean;
FFocusRectVisible : Boolean;
{calc size}
FCalcFontSize : Integer;
FCalcBtnWidth : Integer;
FCalcBtnHeight : Integer;
FCalcLargeBtnWidth : Integer;
FCalcXOfs : Integer;
FCalcYOfs : Integer;
FCalcWidth : Integer;
FCalcHeight : Integer;
{math}
FMemory : Extended;
FOperator: TdxCalcButtonKind;
FOperand: Extended;
FPrecision: Byte;
FStatus: TdxCalcState;
{control}
FButtons : TCalcButtons;
FActiveButton : TdxCalcButtonKind;
FDownButton : TdxCalcButtonKind;
FPressedButton : TdxCalcButtonKind;
FTracking: Boolean;
// events
FOnDisplayChange: TNotifyEvent;
FOnButtonClick: TdxCalcButtonClick;
FOnError: TNotifyEvent;
FOnResult: TNotifyEvent;
function GetDisplay: Extended;
procedure SetDisplay(Value: Extended);
function GetMemory: Extended;
procedure SetAutoFontSize(Value : Boolean);
procedure SetBorderStyle(Value: TBorderStyle);
procedure SetButtonStyle(Value: TdxButtonStyle);
procedure SetButtonFrameVisible(Value: Boolean);
procedure SetFocusRectVisible(Value : Boolean);
procedure FontChanged(Sender: TObject);
procedure StopTracking;
procedure TrackButton(X,Y: Integer);
procedure InvalidateButton(ButtonKind : TdxCalcButtonKind);
procedure DoButtonDown(ButtonKind : TdxCalcButtonKind);
procedure DoButtonUp(ButtonKind : TdxCalcButtonKind);
procedure Error;
procedure CheckFirst;
procedure Clear;
procedure CalcSize(AWidth, AHeight : Integer);
procedure UpdateMemoryButtons;
procedure InvalidateMemoryButtons;
procedure ResetOperands;
// messages
procedure WMEraseBkgnd(var Message: TWMEraseBkgnd); message WM_ERASEBKGND;
procedure WMGetDlgCode(var Msg: TWMGetDlgCode); message WM_GETDLGCODE;
procedure WMKillFocus(var Msg: TWMKillFocus); message WM_KILLFOCUS;
procedure WMSetFocus(var Msg: TWMSetFocus); message WM_SETFOCUS;
procedure WMSize(var Msg: TWMSize); message WM_SIZE;
procedure CMCtl3DChanged(var Message: TMessage); message CM_CTL3DCHANGED;
procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
procedure CMEnabledChanged(var Message: TMessage); message CM_ENABLEDCHANGED;
procedure CMMouseLeave(var Message: TMessage); message CM_MOUSELEAVE;
protected
IsPopup : Boolean;
procedure Paint; override;
procedure CreateParams(var Params: TCreateParams); override;
procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
procedure MouseMove(Shift: TShiftState; X, Y: Integer); override;
procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override;
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
procedure KeyPress(var Key: Char); override;
procedure KeyUp(var Key: Word; Shift: TShiftState); override;
procedure CreateLayout;
procedure ButtonClick(ButtonKind : TdxCalcButtonKind);
// for link with EditControl
function GetEditValue: String; virtual;
procedure SetEditValue(const Value: String); virtual;
property Color default clBtnFace;
property ParentColor default False;
property Ctl3D default False;
property ParentCtl3D default False;
property BorderStyle: TBorderStyle read FBorderStyle write SetBorderStyle default bsNone;
property AutoFontSize : Boolean read FAutoFontSize write SetAutoFontSize default True;
property BeepOnError: Boolean read FBeepOnError write FBeepOnError default True;
property ButtonStyle : TdxButtonStyle read FButtonStyle write SetButtonStyle default bsStandard;
property ShowButtonFrame : Boolean read FButtonFrameVisible write SetButtonFrameVisible default False;
property ShowFocusRect : Boolean read FFocusRectVisible write SetFocusRectVisible default True;
property Precision: Byte read FPrecision write FPrecision default dxDefCalcPrecision;
property EditValue : String read GetEditValue write SetEditValue;
property OnDisplayChange: TNotifyEvent read FOnDisplayChange write FOnDisplayChange;
property OnButtonClick: TdxCalcButtonClick read FOnButtonClick write FOnButtonClick;
property OnError: TNotifyEvent read FOnError write FOnError;
property OnResult: TNotifyEvent read FOnResult write FOnResult;
public
constructor Create(AOwner: TComponent); override;
function GetButtonKindAt(X, Y : Integer) : TdxCalcButtonKind;
function GetButtonKindChar(Ch : Char) : TdxCalcbuttonKind;
function GetButtonKindKey(Key: Word; Shift: TShiftState) : TdxCalcbuttonKind;
procedure CopyToClipboard;
procedure PasteFromClipboard;
property Memory: Extended read GetMemory;
property Value: Extended read GetDisplay write SetDisplay;
published
property TabStop default True;
end;
TdxCalculator = class(TCustomdxCalculator)
private
FAssociate : TWinControl;
FOnGetEditValue : TdxCalcGetEditValue;
FOnSetEditValue : TdxCalcSetEditValue;
procedure SetAssociate(Value : TWinControl);
protected
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
function GetEditValue: String; override;
procedure SetEditValue(const Value: String); override;
published
property BorderStyle;
property Ctl3D;
property DragCursor;
property DragMode;
property Enabled;
property Font;
property ParentCtl3D;
property ParentFont;
property ParentShowHint;
property ShowHint;
property TabOrder;
property TabStop;
property Visible;
property OnClick;
property OnEnter;
property OnExit;
property OnKeyDown;
property OnKeyPress;
property OnKeyUp;
property OnMouseDown;
property OnMouseMove;
property OnMouseUp;
property OnStartDrag;
property OnDragDrop;
property OnDragOver;
property OnEndDrag;
property Associate : TWinControl read FAssociate write SetAssociate;
property AutoFontSize;
property BeepOnError;
property ButtonStyle;
property ShowButtonFrame;
property ShowFocusRect;
property Precision;
property OnDisplayChange;
property OnButtonClick;
property OnError;
property OnResult;
property OnGetEditValue : TdxCalcGetEditValue read FOnGetEditValue write FOnGetEditValue;
property OnSetEditValue : TdxCalcSetEditValue read FOnSetEditValue write FOnSetEditValue;
end;
{TdxCalcDisplay}
TdxCalcDisplay = class(TCustomControl)
private
procedure AdjustHeight;
procedure WMSize(var Msg: TWMSize); message WM_SIZE;
procedure CMFontChanged(var Message: TMessage); message CM_FONTCHANGED;
procedure CMTextChanged(var Message: TMessage); message CM_TEXTCHANGED;
protected
procedure CreateParams(var Params: TCreateParams); override;
procedure Paint; override;
public
constructor Create(AOwner: TComponent); override;
published
property Color default clWindow;
property Font;
property ParentColor default False;
property TabStop default True;
property Text;
end;
implementation
{$R dxClcStr.res}
const
DrawBitmap : TBitmap = nil;
ResultButtons = [cbEqual, cbPercent];
RepeatButtons = [cbBack];
OperationButtons = [cbAdd, cbSub, cbMul, cbDiv];
BorderWidth = 4;
function Max(X, Y: Integer): Integer;
begin
Result := Y;
if X > Y then Result := X;
end;
procedure DrawButton(ACanvas : TCanvas; ARect : TRect; const AText : String;
AButtonStyle: TdxButtonStyle; AFlat : Boolean; AFontColor : TColor;
ADown : Boolean; AFrame : Boolean; AEnabled : Boolean; AFocused : Boolean;
AGrayed : Boolean);
const AlignFlag : Integer = DT_CENTER or DT_EXPANDTABS or DT_NOPREFIX or
DT_VCENTER or DT_SINGLELINE;
DownStyles: array[Boolean] of Integer = (BDR_RAISEDINNER, BDR_SUNKENOUTER);
FillStyles: array[Boolean] of Integer = (BF_MIDDLE, 0);
var R, B : TRect;
DrawFlags: Integer;
Ofs : Integer;
begin
with DrawBitmap, ARect do { Use offscreen bitmap to eliminate flicker and }
begin { brush origin tics in painting / scrolling. }
Width := Max(Width, Right - Left);
Height := Max(Height, Bottom - Top);
R := Rect(2, 2, Right - Left - 2, Bottom - Top - 2);
B := Rect(0, 0, Right - Left, Bottom - Top);
end;
with DrawBitmap.Canvas do
begin
Font := ACanvas.Font;
if AGrayed then
begin
AFontColor := clBtnShadow;
ADown := False;
end;
Font.Color := AFontColor;
Brush := ACanvas.Brush;
Brush.Style := bsSolid;
FillRect(B);
{Edge}
if AButtonStyle = bsStandard then
begin
DrawFlags := DFCS_BUTTONPUSH;
if ADown then
DrawFlags := DrawFlags or DFCS_PUSHED;
DrawFrameControl(Handle, B, DFC_BUTTON, DrawFlags);
end
else
begin
if not AFlat or ADown then
DrawEdge(Handle, B, DownStyles[ADown], BF_RECT);
end;
{Text}
SetBkMode(Handle, TRANSPARENT);
if ADown then Ofs := 2 else Ofs := 0;
R.Left := R.Left + Ofs;
R.Top := R.Top + Ofs;
if not AEnabled then
begin
Font.Color := clBtnHighlight;
OffsetRect(R, 1, 1);
DrawText(Handle, PChar(AText), Length(AText), R, AlignFlag);
OffsetRect(R, -1, -1);
Font.Color := clBtnShadow;
DrawText(Handle, PChar(AText), Length(AText), R, AlignFlag);
end
else
DrawText(Handle, PChar(AText), Length(AText), R, AlignFlag);
{Frame}
R := B;
InflateRect(R, -3, -3);
Pen.Color := clBtnShadow;
if AFrame then
with R do
begin
OffsetRect(R, Ofs div 2, Ofs div 2);
Brush.Style := bsClear;
RoundRect(Left, Top , Right, Bottom, (Bottom-Top)-4, (Bottom-Top)-4);
end;
end;
ACanvas.CopyRect(ARect, DrawBitmap.Canvas, B);
if AFocused then
begin
InflateRect(ARect, -3, -3);
ACanvas.Brush.Style := bsSolid;
ACanvas.DrawFocusRect(ARect);
end;
end;
{TCustomdxCalculator}
constructor TCustomdxCalculator.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
{init size variables}
FCalcFontSize := dxMinCalcFontSize;
FCalcBtnWidth := dxMinCalcBtnWidth;
FCalcBtnHeight := dxMinCalcBtnHeight;
FCalcLargeBtnWidth := dxMinCalcLargeBtnWidth;
FCalcXOfs := dxMinCalcXOfs;
FCalcYOfs := dxMinCalcYOfs;
FCalcWidth := dxMinCalcWidth;
FCalcHeight := dxMinCalcHeight;
{default size}
Width := FCalcWidth;
Height := FCalcHeight;
{style}
ControlStyle := [csCaptureMouse, csOpaque];
if NewStyleControls then
ControlStyle := ControlStyle else
ControlStyle := ControlStyle + [csFramed];
Color := clBtnFace;
Ctl3d := False;
ParentColor := False;
ParentCtl3d := False;
TabStop := True;
FAutoFontSize := True;
FBorderStyle := bsNone;
FBeepOnError := True;
FDownButton := cbNone;
FActiveButton := cbNone;
FPressedButton := cbNone;
FFocusRectVisible := True;
FOperator := cbEqual;
FPrecision := dxDefCalcPrecision;
Font.OnChange := FontChanged;
CreateLayout;
end;
function TCustomdxCalculator.GetButtonKindAt(X, Y : Integer) : TdxCalcButtonKind;
var i : TdxCalcButtonKind;
begin
Result := cbNone;
for i := cbBack to cbEqual do
if PtInRect(FButtons[i].BtnRect, Point(X, Y)) then
begin
Result := i;
Exit;
end;
end;
// protected
procedure TCustomdxCalculator.Paint;
var CRect : TRect;
i : TdxCalcButtonKind;
AFocused : Boolean;
Rgn: HRGN;
procedure ExcludeRect(var MainRgn: HRGN; R: TRect);
var
TmpRgn: HRGN;
begin
TmpRgn := CreateRectRgnIndirect(R);
CombineRgn(MainRgn, TmpRgn, MainRgn, RGN_XOR);
DeleteObject(TmpRgn);
end;
begin
if not HandleAllocated then Exit;
CRect := ClientRect;
Rgn := CreateRectRgnIndirect(CRect);
AFocused := Windows.GetFocus = Handle;
{Draw buttons}
with Canvas do
begin
Font := Self.Font;
if AutoFontSize then
begin
Font.Size := FCalcFontSize;
if Font.Size >= dxCalcMinBoldFontSize then Font.Style := [fsBold]
else Font.Style := [];
end;
Brush.Color := Self.Color;
end;
for i := cbBack to cbEqual do
with FButtons[i] do
if RectVisible(Canvas.Handle, BtnRect) then
begin
DrawButton(Canvas, BtnRect, Text, ButtonStyle,
(ButtonStyle = bsExtraFlat) and (FActiveButton <> i) {AFlat},
FontColor, Down, ShowButtonFrame, Enabled,
ShowFocusRect and AFocused and (i=cbEqual),
Grayed);
ExcludeRect(Rgn, BtnRect);
end;
{Fill Background}
Canvas.Brush.Color := Self.Color;
PaintRgn(Canvas.Handle, Rgn);
DeleteObject(Rgn);
end;
procedure TCustomdxCalculator.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
with Params do
begin
Style := Style or WS_TABSTOP or WS_CLIPCHILDREN;
WindowClass.Style := WindowClass.Style and not CS_DBLCLKS;
if FIsPopupControl then
Style := Style and not WS_BORDER
else
if FBorderStyle = bsSingle then
if NewStyleControls and Ctl3D then
begin
Style := Style and not WS_BORDER;
ExStyle := ExStyle or WS_EX_CLIENTEDGE;
end
else
Style := Style or WS_BORDER;
end;
end;
procedure TCustomdxCalculator.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var ButtonKind : TdxCalcButtonkind;
begin
if not (csDesigning in ComponentState) and
(CanFocus or (GetParentForm(Self) = nil)) and
not IsPopup then SetFocus;
ButtonKind := GetButtonKindAt(X, Y);
if (Button = mbLeft) and
(ButtonKind <> cbNone) then
begin
MouseCapture := True;
FTracking := True;
FDownButton := ButtonKind;
TrackButton(X, Y);
end;
inherited MouseDown(Button, Shift, X, Y);
end;
procedure TCustomdxCalculator.MouseMove(Shift: TShiftState; X, Y: Integer);
var OldButton : TdxCalcButtonKind;
begin
if FTracking then
TrackButton(X, Y)
else
if (ButtonStyle = bsExtraFlat) and Enabled and not Dragging then
begin
OldButton := FActiveButton;
FActiveButton := GetButtonKindAt(X, Y);
if FActiveButton <> OldButton then
begin
InvalidateButton(OldButton);
InvalidateButton(FActiveButton);
end;
end;
inherited MouseMove(Shift, X, Y);
end;
procedure TCustomdxCalculator.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
var
WasPressed: Boolean;
begin
WasPressed := (FDownButton <> cbNone) and FButtons[FDownButton].Down;
StopTracking;
if (Button = mbLeft) and WasPressed then ButtonClick(FDownButton);
FDownButton := cbNone;
inherited MouseUp(Button, Shift, X, Y);
end;
procedure TCustomdxCalculator.KeyDown(var Key: Word; Shift: TShiftState);
var NewButton, OldButton : TdxCalcButtonKind;
begin
inherited KeyDown(Key, Shift);
if (Key = VK_INSERT) then
if (Shift = [ssShift]) then PasteFromClipboard
else if (Shift = [ssCtrl]) then CopyToClipboard;
OldButton := FPressedButton;
NewButton := GetButtonKindKey(Key, Shift);
if NewButton <> cbNone then
if OldButton <> NewButton then
begin
DoButtonUp(OldButton);
FPressedButton := NewButton;
DoButtonDown(FPressedButton);
end;
end;
procedure TCustomdxCalculator.KeyPress(var Key: Char);
var NewButton, OldButton : TdxCalcButtonKind;
begin
inherited KeyPress(Key);
if (Key = ^V) then PasteFromClipboard
else if (Key = ^C) then CopyToClipboard;
OldButton := FPressedButton;
NewButton := GetButtonKindChar(Key);
if NewButton <> cbNone then
if OldButton <> NewButton then
begin
DoButtonUp(OldButton);
FPressedButton := NewButton;
DoButtonDown(FPressedButton);
end;
if FPressedButton in RepeatButtons {cbBack} then ButtonClick(FPressedButton);
end;
procedure TCustomdxCalculator.KeyUp(var Key: Word; Shift: TShiftState);
begin
inherited KeyUp(Key, Shift);
DoButtonUp(FPressedButton);
end;
procedure TCustomdxCalculator.DoButtonDown(ButtonKind : TdxCalcButtonKind);
begin
if ButtonKind <> cbNone then
begin
FButtons[ButtonKind].Down := True;
InvalidateButton(ButtonKind);
Update;
if not (ButtonKind in RepeatButtons) {cbBack} then ButtonClick(ButtonKind);
end;
end;
procedure TCustomdxCalculator.DoButtonUp(ButtonKind : TdxCalcButtonKind);
begin
if ButtonKind <> cbNone then
begin
FButtons[ButtonKind].Down := False;
InvalidateButton(ButtonKind);
FPressedButton := cbNone;
Update;
end;
end;
function TCustomdxCalculator.GetEditValue: String;
begin
Result := '';
end;
procedure TCustomdxCalculator.SetEditValue(const Value: String);
begin
end;
procedure TCustomdxCalculator.CreateLayout;
const
BtnCaptions : array [cbBack..cbEqual] of String[4] = ('Back', 'CE', 'C',
'MC', 'MR', 'MS', 'M+',
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
'+/-', ',',
'/', '*', '-', '+',
'sqrt', '%', '1/x', '=');
BtnColors : array [cbBack..cbEqual] of TColor = (clMaroon, clMaroon, clMaroon,
clRed, clRed, clRed, clRed,
clBlue, clBlue, clBlue, clBlue, clBlue, clBlue, clBlue, clBlue, clBlue, clBlue,
clBlue, clBlue,
clRed, clRed, clRed, clRed,
clNavy, clNavy, clNavy, clRed);
var i : TdxCalcButtonKind;
X : Integer;
begin
for i := cbBack to cbEqual do
begin
FButtons[i].Kind := i;
FButtons[i].Text := BtnCaptions[i];
if i = cbDecimal then FButtons[i].Text := SysUtils.DecimalSeparator
else FButtons[i].Text := BtnCaptions[i];
FButtons[i].FontColor := BtnColors[i];
FButtons[i].BtnRect := Rect(0, 0, 0, 0);
FButtons[i].Down := False;
FButtons[i].Grayed := False;
end;
{coord buttons}
FButtons[cbMC].BtnRect := Rect(FCalcXOfs,
(FCalcYOfs+FCalcBtnHeight)+FCalcYOfs,
FCalcXOfs+FCalcBtnWidth,
(FCalcYOfs+FCalcBtnHeight)*2);
FButtons[cbMR].BtnRect := Rect(FCalcXOfs,
(FCalcYOfs+FCalcBtnHeight)*2+FCalcYOfs,
FCalcXOfs+FCalcBtnWidth,
(FCalcYOfs+FCalcBtnHeight)*3);
FButtons[cbMS].BtnRect := Rect(FCalcXOfs,
(FCalcYOfs+FCalcBtnHeight)*3+FCalcYOfs,
FCalcXOfs+FCalcBtnWidth,
(FCalcYOfs+FCalcBtnHeight)*4);
FButtons[cbMP].BtnRect := Rect(FCalcXOfs,
(FCalcYOfs+FCalcBtnHeight)*4+FCalcYOfs,
FCalcXOfs+FCalcBtnWidth,
(FCalcYOfs+FCalcBtnHeight)*5);
X := FCalcXOfs+FCalcBtnWidth + FCalcXOfs + 4;
{7, 8, 9, /, sqrt}
FButtons[cbNum7].BtnRect := Rect(X+FCalcXOfs,
(FCalcYOfs+FCalcBtnHeight)+FCalcYOfs,
X+FCalcXOfs+FCalcBtnWidth,
(FCalcYOfs+FCalcBtnHeight)*2);
FButtons[cbNum8].BtnRect := Rect(X+FCalcXOfs+(FCalcXOfs+FCalcBtnWidth),
(FCalcYOfs+FCalcBtnHeight)+FCalcYOfs,
X+(FCalcXOfs+FCalcBtnWidth)*2,
(FCalcYOfs+FCalcBtnHeight)*2);
FButtons[cbNum9].BtnRect := Rect(X+FCalcXOfs+(FCalcXOfs+FCalcBtnWidth)*2,
(FCalcYOfs+FCalcBtnHeight)+FCalcYOfs,
X+(FCalcXOfs+FCalcBtnWidth)*3,
(FCalcYOfs+FCalcBtnHeight)*2);
FButtons[cbDiv].BtnRect := Rect(X+FCalcXOfs+(FCalcXOfs+FCalcBtnWidth)*3,
(FCalcYOfs+FCalcBtnHeight)+FCalcYOfs,
X+(FCalcXOfs+FCalcBtnWidth)*4,
(FCalcYOfs+FCalcBtnHeight)*2);
FButtons[cbSqrt].BtnRect := Rect(X+FCalcXOfs+(FCalcXOfs+FCalcBtnWidth)*4,
(FCalcYOfs+FCalcBtnHeight)+FCalcYOfs,
X+(FCalcXOfs+FCalcBtnWidth)*5,
(FCalcYOfs+FCalcBtnHeight)*2);
{4, 5, 6, *, %}
FButtons[cbNum4].BtnRect := Rect(X+FCalcXOfs,
(FCalcYOfs+FCalcBtnHeight)*2+FCalcYOfs,
X+FCalcXOfs+FCalcBtnWidth,
(FCalcYOfs+FCalcBtnHeight)*3);
FButtons[cbNum5].BtnRect := Rect(X+FCalcXOfs+(FCalcXOfs+FCalcBtnWidth),
(FCalcYOfs+FCalcBtnHeight)*2+FCalcYOfs,
X+(FCalcXOfs+FCalcBtnWidth)*2,
(FCalcYOfs+FCalcBtnHeight)*3);
FButtons[cbNum6].BtnRect := Rect(X+FCalcXOfs+(FCalcXOfs+FCalcBtnWidth)*2,
(FCalcYOfs+FCalcBtnHeight)*2+FCalcYOfs,
X+(FCalcXOfs+FCalcBtnWidth)*3,
(FCalcYOfs+FCalcBtnHeight)*3);
FButtons[cbMul].BtnRect := Rect(X+FCalcXOfs+(FCalcXOfs+FCalcBtnWidth)*3,
(FCalcYOfs+FCalcBtnHeight)*2+FCalcYOfs,
X+(FCalcXOfs+FCalcBtnWidth)*4,
(FCalcYOfs+FCalcBtnHeight)*3);
FButtons[cbPercent].BtnRect := Rect(X+FCalcXOfs+(FCalcXOfs+FCalcBtnWidth)*4,
(FCalcYOfs+FCalcBtnHeight)*2+FCalcYOfs,
X+(FCalcXOfs+FCalcBtnWidth)*5,
(FCalcYOfs+FCalcBtnHeight)*3);
{1, 2, 3, -, 1/x}
FButtons[cbNum1].BtnRect := Rect(X+FCalcXOfs,
(FCalcYOfs+FCalcBtnHeight)*3+FCalcYOfs,
X+FCalcXOfs+FCalcBtnWidth,
(FCalcYOfs+FCalcBtnHeight)*4);
FButtons[cbNum2].BtnRect := Rect(X+FCalcXOfs+(FCalcXOfs+FCalcBtnWidth),
(FCalcYOfs+FCalcBtnHeight)*3+FCalcYOfs,
X+(FCalcXOfs+FCalcBtnWidth)*2,
(FCalcYOfs+FCalcBtnHeight)*4);
FButtons[cbNum3].BtnRect := Rect(X+FCalcXOfs+(FCalcXOfs+FCalcBtnWidth)*2,
(FCalcYOfs+FCalcBtnHeight)*3+FCalcYOfs,
X+(FCalcXOfs+FCalcBtnWidth)*3,
(FCalcYOfs+FCalcBtnHeight)*4);
FButtons[cbSub].BtnRect := Rect(X+FCalcXOfs+(FCalcXOfs+FCalcBtnWidth)*3,
(FCalcYOfs+FCalcBtnHeight)*3+FCalcYOfs,
X+(FCalcXOfs+FCalcBtnWidth)*4,
(FCalcYOfs+FCalcBtnHeight)*4);
FButtons[cbRev].BtnRect := Rect(X+FCalcXOfs+(FCalcXOfs+FCalcBtnWidth)*4,
(FCalcYOfs+FCalcBtnHeight)*3+FCalcYOfs,
X+(FCalcXOfs+FCalcBtnWidth)*5,
(FCalcYOfs+FCalcBtnHeight)*4);
{0, +/-, ., +, =}
FButtons[cbNum0].BtnRect := Rect(X+FCalcXOfs,
(FCalcYOfs+FCalcBtnHeight)*4+FCalcYOfs,
X+FCalcXOfs+FCalcBtnWidth,
(FCalcYOfs+FCalcBtnHeight)*5);
FButtons[cbSign].BtnRect := Rect(X+FCalcXOfs+(FCalcXOfs+FCalcBtnWidth),
(FCalcYOfs+FCalcBtnHeight)*4+FCalcYOfs,
X+(FCalcXOfs+FCalcBtnWidth)*2,
(FCalcYOfs+FCalcBtnHeight)*5);
FButtons[cbDecimal].BtnRect := Rect(X+FCalcXOfs+(FCalcXOfs+FCalcBtnWidth)*2,
(FCalcYOfs+FCalcBtnHeight)*4+FCalcYOfs,
X+(FCalcXOfs+FCalcBtnWidth)*3,
(FCalcYOfs+FCalcBtnHeight)*5);
FButtons[cbAdd].BtnRect := Rect(X+FCalcXOfs+(FCalcXOfs+FCalcBtnWidth)*3,
(FCalcYOfs+FCalcBtnHeight)*4+FCalcYOfs,
X+(FCalcXOfs+FCalcBtnWidth)*4,
(FCalcYOfs+FCalcBtnHeight)*5);
FButtons[cbEqual].BtnRect := Rect(X+FCalcXOfs+(FCalcXOfs+FCalcBtnWidth)*4,
(FCalcYOfs+FCalcBtnHeight)*4+FCalcYOfs,
X+(FCalcXOfs+FCalcBtnWidth)*5,
(FCalcYOfs+FCalcBtnHeight)*5);
{C}
FButtons[cbClear].BtnRect := FButtons[cbEqual].BtnRect;
FButtons[cbClear].BtnRect.Left := FButtons[cbClear].BtnRect.Right - FCalcLargeBtnWidth;
FButtons[cbClear].BtnRect.Top := FCalcYOfs;
FButtons[cbClear].BtnRect.Bottom := FCalcYOfs + FCalcBtnHeight;
{CE}
FButtons[cbCancel].BtnRect := FButtons[cbClear].BtnRect;
FButtons[cbCancel].BtnRect.Right := FButtons[cbClear].BtnRect.Left - FCalcYOfs;
FButtons[cbCancel].BtnRect.Left := FButtons[cbCancel].BtnRect.Right - FCalcLargeBtnWidth;
{Back}
FButtons[cbBack].BtnRect := FButtons[cbCancel].BtnRect;
FButtons[cbBack].BtnRect.Right := FButtons[cbBack].BtnRect.Left - FCalcYOfs;
FButtons[cbBack].BtnRect.Left := FButtons[cbBack].BtnRect.Right - FCalcLargeBtnWidth;
// ResetOperands;
ResetOperands;
// Update Memory display
UpdateMemoryButtons;
end;
//private
procedure TCustomdxCalculator.ResetOperands;
begin
FOperator := cbEqual;
FStatus := csFirst;
FMemory := 0.0;
end;
procedure TCustomdxCalculator.SetBorderStyle(Value: TBorderStyle);
begin
if FBorderStyle <> Value then
begin
FBorderStyle := Value;
RecreateWnd;
end;
end;
procedure TCustomdxCalculator.SetButtonStyle(Value: TdxButtonStyle);
begin
if FButtonStyle <> Value then
begin
FButtonStyle := Value;
Invalidate;
end;
end;
procedure TCustomdxCalculator.SetButtonFrameVisible(Value : Boolean);
begin
if FButtonFrameVisible <> Value then
begin
FButtonFrameVisible := Value;
Invalidate;
end;
end;
procedure TCustomdxCalculator.SetFocusRectVisible(Value : Boolean);
begin
if FFocusRectVisible <> Value then
begin
FFocusRectVisible := Value;
Invalidate;
end;
end;
procedure TCustomdxCalculator.WMEraseBkgnd(var Message: TWMEraseBkgnd);
begin
inherited;
Message.Result := 1;
end;
procedure TCustomdxCalculator.WMGetDlgCode(var Msg: TWMGetDlgCode);
begin
Msg.Result := DLGC_WANTARROWS;
end;
procedure TCustomdxCalculator.CalcSize(AWidth, AHeight : Integer);
var
h, NearHeight, d, dMin : Integer;
function CalcHeight(ABtnHeight:Integer):Integer;
var FYOfs : Integer;
begin
FYOfs := MulDiv(ABtnHeight, dxMinCalcYOfs, dxMinCalcBtnHeight);
Result := (FYOfs+ABtnHeight)*5+FYOfs;
end;
begin
h := MulDiv(AWidth, dxMinCalcHeight, dxMinCalcWidth);
if AHeight > h then AHeight := h;
{Calculate nearest FCalcHeight }
h := dxMinCalcBtnHeight;
NearHeight := h;
dMin := AHeight;
while True do
begin
d := abs(CalcHeight(h) - AHeight);
if d < dMin then
begin
dMin := d;
NearHeight := h;
end
else
Break;
inc(h);
end;
FCalcBtnHeight := NearHeight;
FCalcBtnWidth := MulDiv(FCalcBtnHeight, dxMinCalcBtnWidth, dxMinCalcBtnHeight);
FCalcYOfs := MulDiv(FCalcBtnHeight, dxMinCalcYOfs, dxMinCalcBtnHeight);
FCalcXOfs := FCalcYOfs;
FCalcLargeBtnWidth := MulDiv(FCalcBtnWidth, 17, 10);
FCalcFontSize := MulDiv(FCalcBtnHeight, dxMinCalcFontSize, dxMinCalcBtnHeight);
FCalcHeight := (FCalcYOfs+FCalcBtnHeight)*5+FCalcYOfs;
FCalcWidth := (FCalcXOfs+FCalcBtnWidth)*6+FCalcXOfs*2+4;
// reCalc rect buttons
CreateLayout;
end;
procedure TCustomdxCalculator.WMSize(var Msg: TWMSize);
begin
inherited;
CalcSize(ClientWidth, ClientHeight);
ClientWidth := FCalcWidth;
ClientHeight := FCalcHeight;
end;
procedure TCustomdxCalculator.WMSetFocus(var Msg: TWMSetFocus);
begin
inherited;
InvalidateButton(cbEqual);
end;
procedure TCustomdxCalculator.WMKillFocus(var Msg: TWMKillFocus);
begin
inherited;
InvalidateButton(cbEqual);
end;
procedure TCustomdxCalculator.CMCtl3DChanged(var Message: TMessage);
begin
inherited;
if FBorderStyle = bsSingle then RecreateWnd;
end;
procedure TCustomdxCalculator.CMFontChanged(var Message: TMessage);
begin
inherited;
Invalidate;
end;
procedure TCustomdxCalculator.FontChanged(Sender: TObject);
begin
if not (csLoading in ComponentState) then ParentFont := False;
Invalidate;
end;
procedure TCustomdxCalculator.CMEnabledChanged(var Message: TMessage);
begin
inherited;
Invalidate;
end;
procedure TCustomdxCalculator.StopTracking;
begin
if FTracking then
begin
TrackButton(-1, -1);
FTracking := False;
MouseCapture := False;
if FDownButton <> cbNone then
FButtons[FDownButton].Down := False;
end;
end;
procedure TCustomdxCalculator.TrackButton(X,Y: Integer);
var
FlagRepaint : Boolean;
begin
if FDownButton <> cbNone then
begin
FlagRepaint := (GetButtonKindAt(X, Y)=FDownButton) <> FButtons[FDownButton].Down;
FButtons[FDownButton].Down := (GetButtonKindAt(X, Y)=FDownButton);
if FlagRepaint then
begin
InvalidateButton(FDownButton);
end;
end;
end;
procedure TCustomdxCalculator.InvalidateButton(ButtonKind : TdxCalcButtonKind);
var
R: TRect;
begin
if ButtonKind <> cbNone then
begin
R := FButtons[ButtonKind].BtnRect;
InvalidateRect(Handle, @R, False);
end;
end;
procedure TCustomdxCalculator.CMMouseLeave(var Message: TMessage);
begin
inherited;
if (ButtonStyle = bsExtraFlat) and Enabled and
not Dragging and (FActiveButton <> cbNone) then
begin
InvalidateButton(FActiveButton);
FActiveButton := cbNone;
end;
end;
function TCustomdxCalculator.GetButtonKindChar(Ch : Char) : TdxCalcbuttonKind;
begin
Result := cbNone;
case Ch of
'0'..'9' : Result := TdxCalcbuttonKind(Ord(cbNum0)+Ord(Ch)-Ord('0'));
'+' : Result := cbAdd;
'-' : Result := cbSub;
'*' : Result := cbMul;
'/' : Result := cbDiv;
'%' : Result := cbPercent;
{#13,} '=' : Result := cbEqual;
#8 : Result := cbBack;
// #27 : Result := cbClear;
'@' : Result := cbSqrt;
else
if DecimalSeparator = Ch then Result := cbDecimal;
end;
end;
function TCustomdxCalculator.GetButtonKindKey(Key: Word; Shift: TShiftState) : TdxCalcbuttonKind;
begin
Result := cbNone;
case Key of
VK_RETURN : Result := cbEqual;
VK_ESCAPE : Result := cbClear;
VK_F9 : Result := cbSign;
VK_DELETE : Result := cbCancel;
Ord('C'){VK_C} : if not (ssCtrl in Shift) then Result := cbClear;
Ord('P'){VK_P} : if ssCtrl in Shift then Result := cbMP;
Ord('L'){VK_L} : if ssCtrl in Shift then Result := cbMC;
Ord('R'){VK_R} : if ssCtrl in Shift then Result := cbMR
else Result := cbRev;
Ord('M'){VK_M} : if ssCtrl in Shift then Result := cbMS;
end;
end;
procedure TCustomdxCalculator.CopyToClipboard;
begin
Clipboard.AsText := GetEditValue;
end;
procedure TCustomdxCalculator.PasteFromClipboard;
var S, S1 : String;
i : Integer;
begin
if Clipboard.HasFormat(CF_TEXT) then
try
S := Clipboard.AsText;
S1 := '';
repeat
i := Pos(CurrencyString, S);
if i > 0 then
begin
S1 := S1 + Copy(S, 1, i - 1);
S := Copy(S, i + Length(CurrencyString), MaxInt);
end
else
S1 := S1 + S;
until i <= 0;
SetDisplay(StrToFloat(Trim(S1)));
FStatus := csValid;
except
SetDisplay(0.0);
end;
end;
procedure TCustomdxCalculator.SetAutoFontSize(Value : Boolean);
begin
if AutoFontSize <> Value then
begin
FAutoFontSize := Value;
Font.OnChange(Nil);
end;
end;
// math routines
procedure TCustomdxCalculator.Error;
begin
FStatus := csError;
SetEditValue(sdxCalcError{LoadStr(dx_Error)});
if FBeepOnError then MessageBeep(0);
if Assigned(FOnError) then FOnError(Self);
end;
procedure TCustomdxCalculator.CheckFirst;
begin
if FStatus = csFirst then
begin
FStatus := csValid;
SetEditValue('0');
end;
end;
procedure TCustomdxCalculator.Clear;
begin
FStatus := csFirst;
SetDisplay(0.0);
FOperator := cbEqual;
end;
procedure TCustomdxCalculator.ButtonClick(ButtonKind : TdxCalcButtonKind);
var Value : Extended;
begin
if Assigned(FOnButtonClick) then FOnButtonClick(Self, ButtonKind);
if (FStatus = csError) and not (ButtonKind in [cbClear, cbCancel]) then
begin
Error;
Exit;
end;
if ButtonKind = cbDecimal then
begin
CheckFirst;
if Pos(DecimalSeparator, EditValue) = 0 then
SetEditValue(EditValue + DecimalSeparator);
Exit;
end;
case ButtonKind of
cbRev:
if FStatus in [csValid, csFirst] then
begin
FStatus := csFirst;
if FOperator in OperationButtons then
FStatus := csValid;
if GetDisplay = 0 then Error else SetDisplay(1.0 / GetDisplay);
end;
cbSqrt:
if FStatus in [csValid, csFirst] then
begin
FStatus := csFirst;
if FOperator in OperationButtons then
FStatus := csValid;
if GetDisplay < 0 then Error else SetDisplay(Sqrt(GetDisplay));
end;
cbNum0..cbNum9:
begin
CheckFirst;
if EditValue = '0' then SetEditValue('');
if Length(EditValue) < Max(2, FPrecision) + Ord(Boolean(Pos('-', EditValue))) then
SetEditvalue(EditValue + Char(Ord('0')+Byte(ButtonKind)-Byte(cbNum0)))
else if FBeepOnError then MessageBeep(0);
end;
cbBack:
begin
CheckFirst;
if (Length(EditValue) = 1) or ((Length(EditValue) = 2) and (EditValue[1] = '-')) then
SetEditValue('0')
else
SetEditValue(System.Copy(EditValue, 1, Length(EditValue) - 1));
end;
cbSign: SetDisplay(-GetDisplay);
cbAdd, cbSub, cbMul, cbDiv, cbEqual, cbPercent :
begin
if FStatus = csValid then
begin
FStatus := csFirst;
Value := GetDisplay;
if ButtonKind = cbPercent then
case FOperator of
cbAdd, cbSub : Value := FOperand * Value / 100.0;
cbMul, cbDiv : Value := Value / 100.0;
end;
case FOperator of
cbAdd : SetDisplay(FOperand + Value);
cbSub : SetDisplay(FOperand - Value);
cbMul : SetDisplay(FOperand * Value);
cbDiv : if Value = 0 then Error else SetDisplay(FOperand / Value);
end;
end;
FOperator := ButtonKind;
FOperand := GetDisplay;
if (ButtonKind in ResultButtons) and Assigned(FOnResult) then FOnResult(Self);
end;
cbClear, cbCancel: Clear;
cbMP:
if FStatus in [csValid, csFirst] then
begin
FStatus := csFirst;
FMemory := FMemory + GetDisplay;
UpdateMemoryButtons;
InvalidateMemoryButtons;
end;
cbMS:
if FStatus in [csValid, csFirst] then
begin
FStatus := csFirst;
FMemory := GetDisplay;
UpdateMemoryButtons;
InvalidateMemoryButtons;
end;
cbMR:
if FStatus in [csValid, csFirst] then
begin
FStatus := csFirst;
CheckFirst;
SetDisplay(FMemory);
end;
cbMC:
begin
FMemory := 0.0;
UpdateMemoryButtons;
InvalidateMemoryButtons;
end;
end;
end;
procedure TCustomdxCalculator.UpdateMemoryButtons;
begin
// Disable buttons
if FMemory <> 0.0 then
begin
FButtons[cbMC].Grayed := False;
FButtons[cbMR].Grayed := False;
end
else
begin
FButtons[cbMC].Grayed := True;
FButtons[cbMR].Grayed := True;
end;
end;
procedure TCustomdxCalculator.InvalidateMemoryButtons;
begin
InvalidateButton(cbMC);
InvalidateButton(cbMR);
end;
function TCustomdxCalculator.GetDisplay: Extended;
var
S: string;
begin
if FStatus = csError then Result := 0.0
else
begin
S := Trim(GetEditValue);
if S = '' then S := '0';
Result := StrToFloat(S);
end;
end;
procedure TCustomdxCalculator.SetDisplay(Value: Extended);
var
S: string;
begin
S := FloatToStrF(Value, ffGeneral, Max(2, FPrecision), 0); {TODO e-+!}
if GetEditValue <> S then
begin
SetEditValue(S);
if Assigned(FOnDisplayChange) then FOnDisplayChange(Self);
end;
end;
function TCustomdxCalculator.GetMemory: Extended;
begin
Result := FMemory;
end;
{TdxCalculator}
procedure TdxCalculator.SetAssociate(Value : TWinControl);
begin
FAssociate := Value;
if Value <> Nil then
Value.FreeNotification(Self);
try
StrToFloat(GetEditValue);
except
SetEditValue('0');
end;
end;
procedure TdxCalculator.Notification(AComponent: TComponent; Operation: TOperation);
begin
inherited Notification(AComponent, Operation);
if Operation = opRemove then
if AComponent = FAssociate then Associate := nil;
end;
type
TWinControlCracker = class(TWinControl)
public
property Text;
end;
function TdxCalculator.GetEditValue: String;
begin
if Assigned(Associate) then Result := TWinControlCracker(Associate).Text
else Result := '0';
if Assigned(FOnGetEditValue) then FOnGetEditValue(Self, Result);
end;
procedure TdxCalculator.SetEditValue(const Value: String);
begin
if Assigned(Associate) then
TWinControlCracker(Associate).Text := Value;
if Assigned(FOnSetEditValue) then FOnSetEditValue(Self, Value);
end;
{TdxCalcDisplay}
constructor TdxCalcDisplay.Create(AOwner: TComponent);
begin
inherited Create(AOwner);
ControlStyle := [csOpaque];
if not NewStyleControls then
ControlStyle := ControlStyle + [csFramed];
ParentColor := False;
ParentCtl3d := False;
Color := clWindow;
Ctl3d := True;
Width := 100;
Text := '0';
AdjustHeight;
end;
procedure TdxCalcDisplay.CreateParams(var Params: TCreateParams);
begin
inherited CreateParams(Params);
with Params do
begin
WindowClass.Style := WindowClass.Style and not CS_DBLCLKS;
if NewStyleControls and Ctl3D then
begin
Style := Style and not WS_BORDER;
ExStyle := ExStyle or WS_EX_CLIENTEDGE;
end
else
Style := Style or WS_BORDER;
end;
end;
procedure TdxCalcDisplay.Paint;
const AlignFlag : Integer = DT_RIGHT or DT_EXPANDTABS or DT_NOPREFIX or
DT_VCENTER or DT_SINGLELINE;
var R : TRect;
begin
if not HandleAllocated then Exit;
R := ClientRect;
with Canvas do
begin
Font := Self.Font;
Brush.Color := Self.Color;
FillRect(R);
InflateRect(R, -BorderWidth, -BorderWidth);
DrawText(Handle, PChar(Text), Length(Text), R, AlignFlag);
end;
end;
procedure TdxCalcDisplay.WMSize(var Msg: TWMSize);
begin
inherited;
AdjustHeight;
end;
procedure TdxCalcDisplay.CMFontChanged(var Message: TMessage);
begin
inherited;
AdjustHeight;
end;
procedure TdxCalcDisplay.CMTextChanged(var Message: TMessage);
begin
inherited;
Invalidate;
end;
procedure TdxCalcDisplay.AdjustHeight;
var
DC: HDC;
SaveFont: HFont;
I: Integer;
SysMetrics, 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;
Height := Metrics.tmHeight + I + BorderWidth;
end;
initialization
DrawBitmap := TBitmap.Create;
sdxCalcError := LoadStr(dx_Error);
finalization
if DrawBitmap <> nil then
begin
DrawBitmap.Free;
DrawBitmap := nil;
end;
end.