1921 lines
59 KiB
ObjectPascal
1921 lines
59 KiB
ObjectPascal
|
|
{********************************************************************}
|
|
{ }
|
|
{ Developer Express Visual Component Library }
|
|
{ ExpressEditors }
|
|
{ }
|
|
{ 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 }
|
|
{ }
|
|
{ THIS SOURCE CODE AND ALL RESULTING INTERMEDIATE FILES }
|
|
{ (DCU, OBJ, DLL, ETC.) ARE CONFIDENTIAL AND PROPRIETARY TRADE }
|
|
{ SECRETS OF DEVELOPER EXPRESS INC. THE REGISTERED DEVELOPER IS }
|
|
{ LICENSED TO DISTRIBUTE THE EXPRESSEDITORS AND ALL }
|
|
{ ACCOMPANYING VCL CONTROLS AS PART OF AN EXECUTABLE PROGRAM ONLY. }
|
|
{ }
|
|
{ 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 cxCalc;
|
|
|
|
{$I cxVer.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
Windows, Messages,
|
|
SysUtils, Classes, Graphics, Controls, Forms, StdCtrls, Clipbrd,
|
|
cxClasses, cxControls, cxContainer, cxGraphics, cxDataStorage, cxDataUtils,
|
|
cxButtons, cxEdit, cxDropDownEdit, cxEditConsts, cxFormats, cxLookAndFeelPainters,
|
|
cxTextEdit, cxFilterControlUtils;
|
|
|
|
const
|
|
cxMaxCalcPrecision = cxEditDefaultPrecision;
|
|
cxDefCalcPrecision = cxMaxCalcPrecision;
|
|
// Size
|
|
cxMinCalcFontSize = 8;
|
|
cxCalcMinBoldFontSize = 10;
|
|
cxMinCalcBtnWidth = 28;
|
|
cxMinCalcBtnHeight = 22;
|
|
cxMinCalcLargeBtnWidth = Integer(Trunc(1.7*cxMinCalcBtnWidth));
|
|
cxMinCalcXOfs = 3;
|
|
cxMinCalcYOfs = 3;
|
|
cxMinCalcWidth = (cxMinCalcXOfs+cxMinCalcBtnWidth)*6+cxMinCalcXOfs*3+3;
|
|
cxMinCalcHeight = (cxMinCalcYOfs+cxMinCalcBtnHeight)*5+cxMinCalcYOfs+3;
|
|
|
|
type
|
|
TcxCalcState = (csFirst, csValid, csError);
|
|
|
|
const
|
|
BtnCaptions : array [cbBack..cbEqual] of string = ('Back', 'CE', 'C',
|
|
'MC', 'MR', 'MS', 'M+',
|
|
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9',
|
|
'+/-', ',', '/', '*', '-', '+', 'sqrt', '%', '1/x', '=');
|
|
|
|
type
|
|
TcxButtonInfo = record
|
|
BtnRect: TRect;
|
|
Down: Boolean;
|
|
Grayed: Boolean;
|
|
Kind: TcxCalcButtonKind;
|
|
Text: string;
|
|
end;
|
|
|
|
TCalcButtons = array [TcxCalcButtonKind] of TcxButtonInfo;
|
|
|
|
{ TcxCustomCalculator }
|
|
|
|
TcxCalcButtonClick = procedure(Sender: TObject; var ButtonKind : TcxCalcButtonKind) of object;
|
|
TcxCalcGetEditValue = procedure(Sender: TObject; var Value : String) of object;
|
|
TcxCalcSetEditValue = procedure(Sender: TObject; const Value : String) of object;
|
|
|
|
TcxCustomCalculator = class(TcxControl)
|
|
private
|
|
{calc style}
|
|
FAutoFontSize : Boolean;
|
|
FBeepOnError: Boolean;
|
|
FBorderStyle : TBorderStyle;
|
|
FFocusRectVisible : Boolean;
|
|
{calc size}
|
|
FCalcFontSize : Integer;
|
|
FCalcBtnWidth : Integer;
|
|
FCalcBtnHeight : Integer;
|
|
FCalcLargeBtnWidth : Integer;
|
|
FCalcXOfs : Integer;
|
|
FCalcYOfs : Integer;
|
|
FCalcWidth : Integer;
|
|
FCalcHeight : Integer;
|
|
{math}
|
|
FMemory : Extended;
|
|
FOperator: TcxCalcButtonKind;
|
|
FOperand: Extended;
|
|
FPrecision: Byte;
|
|
FStatus: TcxCalcState;
|
|
{control}
|
|
FButtons : TCalcButtons;
|
|
FActiveButton : TcxCalcButtonKind;
|
|
FDownButton : TcxCalcButtonKind;
|
|
FPressedButton : TcxCalcButtonKind;
|
|
FTracking: Boolean;
|
|
// events
|
|
FOnDisplayChange: TNotifyEvent;
|
|
FOnButtonClick: TcxCalcButtonClick;
|
|
FOnResult: TNotifyEvent;
|
|
FOnHidePopup: TcxEditClosePopupEvent;
|
|
|
|
function GetDisplay: Extended;
|
|
procedure SetDisplay(Value: Extended);
|
|
function GetMemory: Extended;
|
|
|
|
procedure SetAutoFontSize(Value : Boolean);
|
|
procedure SetBorderStyle(Value: TBorderStyle);
|
|
procedure SetFocusRectVisible(Value : Boolean);
|
|
|
|
procedure StopTracking;
|
|
procedure TrackButton(X,Y: Integer);
|
|
procedure InvalidateButton(ButtonKind : TcxCalcButtonKind);
|
|
procedure DoButtonDown(ButtonKind : TcxCalcButtonKind);
|
|
procedure DoButtonUp(ButtonKind : TcxCalcButtonKind);
|
|
procedure Error;
|
|
procedure CheckFirst;
|
|
procedure Clear;
|
|
procedure CalcSize(AWidth, AHeight : Integer);
|
|
procedure UpdateMemoryButtons;
|
|
procedure InvalidateMemoryButtons;
|
|
procedure ResetOperands;
|
|
protected
|
|
IsPopupControl : Boolean;
|
|
function GetPainter: TcxCustomLookAndFeelPainterClass; virtual;
|
|
procedure Paint; override;
|
|
procedure CreateParams(var Params: TCreateParams); override;
|
|
procedure FontChanged; override;
|
|
procedure FocusChanged; override;
|
|
procedure MouseDown(Button: TMouseButton; Shift: TShiftState;
|
|
X, Y: Integer); override;
|
|
procedure MouseLeave(AControl: TControl); 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 Resize; override;
|
|
procedure SetEnabled( Value: Boolean); override;
|
|
procedure CreateLayout;
|
|
procedure ButtonClick(ButtonKind : TcxCalcButtonKind);
|
|
// for link with EditControl
|
|
function GetEditorValue: String; virtual;
|
|
procedure SetEditorValue(const Value: String); virtual;
|
|
procedure HidePopup(Sender: TcxControl; AReason: TcxEditCloseUpReason); virtual;
|
|
procedure LockChanges(ALock: Boolean; AInvokeChangedOnUnlock: Boolean = True); virtual;
|
|
|
|
property Color default clBtnFace;
|
|
property ParentColor 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 ShowFocusRect : Boolean
|
|
read FFocusRectVisible write SetFocusRectVisible default True;
|
|
|
|
property Precision: Byte read FPrecision write FPrecision
|
|
default cxDefCalcPrecision;
|
|
property EditorValue : string read GetEditorValue write SetEditorValue;
|
|
|
|
property OnHidePopup: TcxEditClosePopupEvent read FOnHidePopup write FOnHidePopup;
|
|
property OnDisplayChange: TNotifyEvent
|
|
read FOnDisplayChange write FOnDisplayChange;
|
|
property OnButtonClick: TcxCalcButtonClick
|
|
read FOnButtonClick write FOnButtonClick;
|
|
property OnResult: TNotifyEvent read FOnResult write FOnResult;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
function GetButtonKindAt(X, Y : Integer) : TcxCalcButtonKind;
|
|
function GetButtonKindChar(Ch : Char) : TcxCalcbuttonKind;
|
|
function GetButtonKindKey(Key: Word; Shift: TShiftState) : TcxCalcbuttonKind;
|
|
procedure CopyToClipboard;
|
|
procedure PasteFromClipboard;
|
|
property Memory: Extended read GetMemory;
|
|
property Value: Extended read GetDisplay write SetDisplay;
|
|
published
|
|
property TabStop default True;
|
|
end;
|
|
|
|
{ TcxPopupCalculator }
|
|
|
|
TcxCustomCalcEdit = class;
|
|
|
|
TcxPopupCalculator = class(TcxCustomCalculator)
|
|
private
|
|
FEdit: TcxCustomCalcEdit;
|
|
protected
|
|
function GetEditorValue: string; override;
|
|
function GetPainter: TcxCustomLookAndFeelPainterClass; override;
|
|
procedure KeyDown(var Key: Word; Shift: TShiftState); override;
|
|
procedure KeyPress(var Key: Char); override;
|
|
procedure SetEditorValue(const Value: string); override;
|
|
procedure LockChanges(ALock: Boolean; AInvokeChangedOnUnlock: Boolean = True); override;
|
|
property Edit: TcxCustomCalcEdit read FEdit write FEdit;
|
|
public
|
|
constructor Create(AOwner: TComponent); override;
|
|
procedure Init; virtual;
|
|
end;
|
|
|
|
{ TcxCalcEditPropertiesValues }
|
|
|
|
TcxCalcEditPropertiesValues = class(TcxTextEditPropertiesValues)
|
|
private
|
|
FPrecision: Boolean;
|
|
procedure SetPrecision(Value: Boolean);
|
|
public
|
|
procedure Assign(Source: TPersistent); override;
|
|
procedure RestoreDefaults; override;
|
|
published
|
|
property Precision: Boolean read FPrecision write SetPrecision stored False;
|
|
end;
|
|
|
|
{ TcxCustomCalcEditProperties }
|
|
|
|
TcxCustomCalcEditProperties = class(TcxCustomPopupEditProperties)
|
|
private
|
|
FBeepOnError: Boolean;
|
|
FPrecision: Byte;
|
|
FQuickClose: Boolean;
|
|
FScientificFormat: Boolean;
|
|
FUseThousandSeparator: Boolean;
|
|
function GetAssignedValues: TcxCalcEditPropertiesValues;
|
|
function GetPrecision: Byte;
|
|
function IsPrecisionStored: Boolean;
|
|
procedure SetAssignedValues(Value: TcxCalcEditPropertiesValues);
|
|
procedure SetBeepOnError(Value: Boolean);
|
|
procedure SetPrecision(Value: Byte);
|
|
procedure SetQuickClose(Value: Boolean);
|
|
procedure SetScientificFormat(Value: Boolean);
|
|
procedure SetUseThousandSeparator(Value: Boolean);
|
|
protected
|
|
function GetAlwaysPostEditValue: Boolean; override;
|
|
class function GetAssignedValuesClass: TcxCustomEditPropertiesValuesClass; override;
|
|
function HasDigitGrouping(AIsDisplayValueSynchronizing: Boolean): Boolean; override;
|
|
function PopupWindowAcceptsAnySize: Boolean; override;
|
|
function StrToFloatEx(S: string; var Value: Extended): Boolean;
|
|
property AssignedValues: TcxCalcEditPropertiesValues read GetAssignedValues
|
|
write SetAssignedValues;
|
|
public
|
|
constructor Create(AOwner: TPersistent); override;
|
|
procedure Assign(Source: TPersistent); override;
|
|
class function GetContainerClass: TcxContainerClass; override;
|
|
function GetEditValueSource(AEditFocused: Boolean): TcxDataEditValueSource; override;
|
|
function IsDisplayValueValid(var DisplayValue: TcxEditValue;
|
|
AEditFocused: Boolean): Boolean; override;
|
|
function IsEditValueValid(var EditValue: TcxEditValue;
|
|
AEditFocused: Boolean): Boolean; override;
|
|
procedure PrepareDisplayValue(const AEditValue: TcxEditValue;
|
|
var DisplayValue: TcxEditValue; AEditFocused: Boolean); override;
|
|
procedure ValidateDisplayValue(var ADisplayValue: TcxEditValue;
|
|
var AErrorText: TCaption; var Error: Boolean; AEdit: TcxCustomEdit); override;
|
|
// !!!
|
|
property BeepOnError: Boolean read FBeepOnError write SetBeepOnError
|
|
default True;
|
|
property ImmediateDropDown default False;
|
|
property Precision: Byte read GetPrecision write SetPrecision
|
|
stored IsPrecisionStored;
|
|
property QuickClose: Boolean read FQuickClose write SetQuickClose
|
|
default False;
|
|
property ScientificFormat: Boolean read FScientificFormat
|
|
write SetScientificFormat default False;
|
|
property UseThousandSeparator: Boolean read FUseThousandSeparator
|
|
write SetUseThousandSeparator default False;
|
|
end;
|
|
|
|
{ TcxCalcEditProperties }
|
|
|
|
TcxCalcEditProperties = class(TcxCustomCalcEditProperties)
|
|
published
|
|
property Alignment;
|
|
property AssignedValues;
|
|
property AutoSelect;
|
|
property BeepOnError;
|
|
property ButtonGlyph;
|
|
property ClearKey;
|
|
property DisplayFormat;
|
|
property ImeMode;
|
|
property ImeName;
|
|
property ImmediatePost;
|
|
property Precision;
|
|
property ReadOnly;
|
|
property QuickClose;
|
|
property ScientificFormat;
|
|
property UseLeftAlignmentOnEditing;
|
|
property UseThousandSeparator;
|
|
property ValidateOnEnter;
|
|
property OnChange;
|
|
property OnCloseUp;
|
|
property OnEditValueChanged;
|
|
property OnInitPopup;
|
|
property OnPopup;
|
|
property OnValidate;
|
|
end;
|
|
|
|
{ TcxCustomCalcEdit }
|
|
|
|
TcxCustomCalcEdit = class(TcxCustomPopupEdit)
|
|
private
|
|
FCalculator: TcxPopupCalculator;
|
|
function GetProperties: TcxCustomCalcEditProperties;
|
|
function GetActiveProperties: TcxCustomCalcEditProperties;
|
|
function GetValue: Extended;
|
|
procedure SetProperties(Value: TcxCustomCalcEditProperties);
|
|
procedure SetValue(const Value: Extended);
|
|
protected
|
|
// IcxFormatControllerListener
|
|
procedure FormatChanged; override;
|
|
|
|
function CanDropDown: Boolean; override;
|
|
procedure CreatePopupWindow; override;
|
|
procedure DoEnter; override;
|
|
procedure DoExit; override;
|
|
procedure DoInitPopup; override;
|
|
procedure Initialize; override;
|
|
procedure InitializePopupWindow; override;
|
|
function InternalGetEditingValue: TcxEditValue; override;
|
|
function IsValidChar(Key: Char): Boolean; override;
|
|
procedure KeyPress(var Key: Char); override;
|
|
procedure PopupWindowClosed(Sender: TObject); override;
|
|
procedure PopupWindowShowed(Sender: TObject); override;
|
|
procedure PropertiesChanged(Sender: TObject); override;
|
|
function InternalPrepareEditValue(const ADisplayValue: string;
|
|
out EditValue: TcxEditValue): Boolean;
|
|
property Calculator: TcxPopupCalculator read FCalculator;
|
|
public
|
|
destructor Destroy; override;
|
|
class function GetPropertiesClass: TcxCustomEditPropertiesClass; override;
|
|
procedure PasteFromClipboard; override;
|
|
procedure PrepareEditValue(const ADisplayValue: TcxEditValue;
|
|
out EditValue: TcxEditValue; AEditFocused: Boolean); override;
|
|
property ActiveProperties: TcxCustomCalcEditProperties
|
|
read GetActiveProperties;
|
|
property Properties: TcxCustomCalcEditProperties read GetProperties
|
|
write SetProperties;
|
|
property Value: Extended read GetValue write SetValue stored False;
|
|
end;
|
|
|
|
{ TcxCalcEdit }
|
|
|
|
TcxCalcEdit = class(TcxCustomCalcEdit)
|
|
private
|
|
function GetActiveProperties: TcxCalcEditProperties;
|
|
function GetProperties: TcxCalcEditProperties;
|
|
procedure SetProperties(Value: TcxCalcEditProperties);
|
|
public
|
|
class function GetPropertiesClass: TcxCustomEditPropertiesClass; override;
|
|
property ActiveProperties: TcxCalcEditProperties read GetActiveProperties;
|
|
published
|
|
property Anchors;
|
|
property AutoSize;
|
|
property BeepOnEnter;
|
|
property Constraints;
|
|
property DragCursor;
|
|
property DragKind;
|
|
property DragMode;
|
|
property EditValue;
|
|
property Enabled;
|
|
property ImeMode;
|
|
property ImeName;
|
|
property ParentColor;
|
|
property ParentFont;
|
|
property ParentShowHint;
|
|
property PopupMenu;
|
|
property Properties: TcxCalcEditProperties read GetProperties
|
|
write SetProperties;
|
|
property ShowHint;
|
|
property Style;
|
|
property StyleDisabled;
|
|
property StyleFocused;
|
|
property StyleHot;
|
|
property TabOrder;
|
|
property TabStop default True;
|
|
{$IFDEF DELPHI12}
|
|
property TextHint;
|
|
{$ENDIF}
|
|
property Value;
|
|
property Visible;
|
|
property OnClick;
|
|
{$IFDEF DELPHI5}
|
|
property OnContextPopup;
|
|
{$ENDIF}
|
|
property OnDblClick;
|
|
property OnDragDrop;
|
|
property OnDragOver;
|
|
property OnEditing;
|
|
property OnEndDrag;
|
|
property OnEnter;
|
|
property OnExit;
|
|
property OnKeyDown;
|
|
property OnKeyPress;
|
|
property OnKeyUp;
|
|
property OnMouseDown;
|
|
property OnMouseMove;
|
|
property OnMouseUp;
|
|
property OnStartDrag;
|
|
property BiDiMode;
|
|
property ParentBiDiMode;
|
|
property OnEndDock;
|
|
property OnStartDock;
|
|
end;
|
|
|
|
{ TcxFilterCalcEditHelper }
|
|
|
|
TcxFilterCalcEditHelper = class(TcxFilterDropDownEditHelper)
|
|
public
|
|
class function GetFilterEditClass: TcxCustomEditClass; override;
|
|
class function GetSupportedFilterOperators(
|
|
AProperties: TcxCustomEditProperties;
|
|
AValueTypeClass: TcxValueTypeClass;
|
|
AExtendedSet: Boolean = False): TcxFilterControlOperators; override;
|
|
class procedure InitializeProperties(AProperties,
|
|
AEditProperties: TcxCustomEditProperties; AHasButtons: Boolean); override;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
{$IFDEF DELPHI6}
|
|
Variants,
|
|
{$ENDIF}
|
|
Math, cxLookAndFeels, cxVariants, dxThemeManager, dxUxTheme, dxCore;
|
|
|
|
const
|
|
ResultButtons = [cbEqual, cbPercent];
|
|
RepeatButtons = [cbBack];
|
|
OperationButtons = [cbAdd, cbSub, cbMul, cbDiv];
|
|
BorderWidth = 4;
|
|
|
|
{TcxCustomCalculator}
|
|
|
|
constructor TcxCustomCalculator.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
{init size variables}
|
|
FCalcFontSize := cxMinCalcFontSize;
|
|
FCalcBtnWidth := cxMinCalcBtnWidth;
|
|
FCalcBtnHeight := cxMinCalcBtnHeight;
|
|
FCalcLargeBtnWidth := cxMinCalcLargeBtnWidth;
|
|
FCalcXOfs := cxMinCalcXOfs;
|
|
FCalcYOfs := cxMinCalcYOfs;
|
|
FCalcWidth := cxMinCalcWidth;
|
|
FCalcHeight := cxMinCalcHeight;
|
|
{default size}
|
|
Width := FCalcWidth;
|
|
Height := FCalcHeight;
|
|
{style}
|
|
ControlStyle := [csCaptureMouse, csOpaque];
|
|
Color := clBtnFace;
|
|
ParentColor := False;
|
|
TabStop := True;
|
|
FAutoFontSize := True;
|
|
FBorderStyle := bsNone;
|
|
FBeepOnError := True;
|
|
FDownButton := cbNone;
|
|
FActiveButton := cbNone;
|
|
FPressedButton := cbNone;
|
|
FFocusRectVisible := True;
|
|
FOperator := cbEqual;
|
|
FPrecision := cxDefCalcPrecision;
|
|
Keys := [kAll, kArrows, kChars, kTab];
|
|
CreateLayout;
|
|
end;
|
|
|
|
function TcxCustomCalculator.GetButtonKindAt(X, Y : Integer) : TcxCalcButtonKind;
|
|
var i : TcxCalcButtonKind;
|
|
begin
|
|
Result := cbNone;
|
|
for i := cbBack to cbEqual do
|
|
if PtInRect(FButtons[i].BtnRect, Point(X, Y)) then
|
|
begin
|
|
Result := i;
|
|
Exit;
|
|
end;
|
|
end;
|
|
|
|
function TcxCustomCalculator.GetPainter: TcxCustomLookAndFeelPainterClass;
|
|
begin
|
|
Result := TcxStandardLookAndFeelPainter;
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.Paint;
|
|
|
|
function CalculateButtonState(const AButton: TcxButtonInfo): TcxButtonState;
|
|
begin
|
|
if AButton.Grayed or not Enabled then
|
|
Result := cxbsDisabled
|
|
else
|
|
if AButton.Down then
|
|
Result := cxbsPressed
|
|
else
|
|
if (FActiveButton = AButton.Kind) and (FDownButton <> AButton.Kind) then
|
|
Result := cxbsHot
|
|
else
|
|
if IsFocused and (AButton.Kind = cbEqual) then
|
|
Result := cxbsDefault
|
|
else
|
|
Result := cxbsNormal;
|
|
end;
|
|
|
|
var
|
|
AState: TcxButtonState;
|
|
I: TcxCalcButtonKind;
|
|
begin
|
|
if not HandleAllocated then Exit;
|
|
with Canvas do
|
|
begin
|
|
{Fill Background}
|
|
Brush.Color := Self.Color;
|
|
if IsPopupControl then
|
|
GetPainter.DrawWindowContent(Self.Canvas, ClientRect)
|
|
else
|
|
GetPainter.DrawWindowContent(Self.Canvas, BoundsRect);
|
|
{Draw buttons}
|
|
Font := Self.Font;
|
|
if AutoFontSize then
|
|
begin
|
|
Font.Size := FCalcFontSize;
|
|
if Font.Size >= cxCalcMinBoldFontSize 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
|
|
AState := CalculateButtonState(FButtons[i]);
|
|
with GetPainter, Canvas do
|
|
begin
|
|
DrawButton(Self.Canvas, BtnRect, '', AState);
|
|
Font.Color := CalcEditButtonTextColor(Kind);
|
|
Brush.Style := bsClear;
|
|
if AState = cxbsPressed then
|
|
begin
|
|
OffsetRect(BtnRect, ButtonTextShift, ButtonTextShift);
|
|
DrawText(Text, BtnRect, cxAlignHCenter or cxAlignVCenter or cxSingleLine or
|
|
cxShowPrefix, AState <> cxbsDisabled);
|
|
OffsetRect(BtnRect, -ButtonTextShift, -ButtonTextShift);
|
|
end
|
|
else
|
|
DrawText(Text, BtnRect, cxAlignHCenter or cxAlignVCenter or cxSingleLine or
|
|
cxShowPrefix, AState <> cxbsDisabled);
|
|
Brush.Style := bsSolid;
|
|
end;
|
|
if FFocusRectVisible and IsFocused and (i = cbEqual) then
|
|
begin
|
|
InflateRect(BtnRect, -3, -3);
|
|
Canvas.DrawFocusRect(BtnRect);
|
|
InflateRect(BtnRect, 3, 3);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.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 IsPopupControl 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 TcxCustomCalculator.MouseDown(Button: TMouseButton; Shift: TShiftState;
|
|
X, Y: Integer);
|
|
var ButtonKind : TcxCalcButtonkind;
|
|
begin
|
|
if not (csDesigning in ComponentState) and
|
|
(CanFocus or (GetParentForm(Self) = nil)) and not IsPopupControl then
|
|
SetFocus;
|
|
|
|
ButtonKind := GetButtonKindAt(X, Y);
|
|
if (Button = mbLeft) and (ButtonKind <> cbNone) and not FButtons[ButtonKind].Grayed then
|
|
begin
|
|
MouseCapture := True;
|
|
FTracking := True;
|
|
FDownButton := ButtonKind;
|
|
TrackButton(X, Y);
|
|
end;
|
|
inherited MouseDown(Button, Shift, X, Y);
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.MouseMove(Shift: TShiftState; X, Y: Integer);
|
|
var OldButton : TcxCalcButtonKind;
|
|
begin
|
|
if FTracking then
|
|
TrackButton(X, Y)
|
|
else
|
|
if GetPainter.IsButtonHotTrack and Enabled and not Dragging then
|
|
begin
|
|
OldButton := FActiveButton;
|
|
FActiveButton := GetButtonKindAt(X, Y);
|
|
if FActiveButton <> OldButton then
|
|
begin
|
|
if not FButtons[OldButton].Grayed then
|
|
InvalidateButton(OldButton);
|
|
if not FButtons[FActiveButton].Grayed then
|
|
InvalidateButton(FActiveButton);
|
|
end;
|
|
end;
|
|
inherited MouseMove(Shift, X, Y);
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.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 TcxCustomCalculator.KeyDown(var Key: Word; Shift: TShiftState);
|
|
var
|
|
NewButton, OldButton : TcxCalcButtonKind;
|
|
begin
|
|
inherited KeyDown(Key, Shift);
|
|
OldButton := FPressedButton;
|
|
NewButton := GetButtonKindKey(Key, Shift);
|
|
if (NewButton <> cbNone) and (OldButton <> NewButton) then
|
|
begin
|
|
DoButtonUp(OldButton);
|
|
FPressedButton := NewButton;
|
|
DoButtonDown(FPressedButton);
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.KeyPress(var Key: Char);
|
|
var
|
|
NewButton, OldButton : TcxCalcButtonKind;
|
|
begin
|
|
inherited KeyPress(Key);
|
|
if (Key = ^V) then
|
|
PasteFromClipboard
|
|
else
|
|
if (Key = ^C) then CopyToClipboard;
|
|
|
|
OldButton := FPressedButton;
|
|
NewButton := GetButtonKindChar(Key);
|
|
if (NewButton <> cbNone) and (OldButton <> NewButton) then
|
|
begin
|
|
DoButtonUp(OldButton);
|
|
FPressedButton := NewButton;
|
|
DoButtonDown(FPressedButton);
|
|
end;
|
|
if FPressedButton in RepeatButtons {cbBack} then ButtonClick(FPressedButton);
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.KeyUp(var Key: Word; Shift: TShiftState);
|
|
begin
|
|
inherited KeyUp(Key, Shift);
|
|
DoButtonUp(FPressedButton);
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.Resize;
|
|
begin
|
|
CalcSize(ClientWidth, ClientHeight);
|
|
ClientWidth := FCalcWidth;
|
|
ClientHeight := FCalcHeight;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.DoButtonDown(ButtonKind : TcxCalcButtonKind);
|
|
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 TcxCustomCalculator.DoButtonUp(ButtonKind : TcxCalcButtonKind);
|
|
begin
|
|
if ButtonKind <> cbNone then
|
|
begin
|
|
FButtons[ButtonKind].Down := False;
|
|
InvalidateButton(ButtonKind);
|
|
FPressedButton := cbNone;
|
|
Update;
|
|
end;
|
|
end;
|
|
|
|
function TcxCustomCalculator.GetEditorValue: String;
|
|
begin
|
|
Result := '';
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.SetEditorValue(const Value: String);
|
|
begin
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.CreateLayout;
|
|
var
|
|
I: TcxCalcButtonKind;
|
|
X: Integer;
|
|
begin
|
|
for I := cbBack to cbEqual do
|
|
begin
|
|
FButtons[I].Kind := I;
|
|
FButtons[I].Text := BtnCaptions[I];
|
|
FButtons[I].BtnRect := cxEmptyRect;
|
|
FButtons[I].Down := False;
|
|
FButtons[I].Grayed := False;
|
|
if I = cbDecimal then
|
|
FButtons[I].Text := SysUtils.DecimalSeparator
|
|
else
|
|
FButtons[I].Text := BtnCaptions[i];
|
|
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;
|
|
|
|
procedure TcxCustomCalculator.ResetOperands;
|
|
begin
|
|
FOperator := cbEqual;
|
|
FStatus := csFirst;
|
|
FMemory := 0.0;
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.SetBorderStyle(Value: TBorderStyle);
|
|
begin
|
|
if FBorderStyle <> Value then
|
|
begin
|
|
FBorderStyle := Value;
|
|
RecreateWnd;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.SetFocusRectVisible(Value : Boolean);
|
|
begin
|
|
if FFocusRectVisible <> Value then
|
|
begin
|
|
FFocusRectVisible := Value;
|
|
Invalidate;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.CalcSize(AWidth, AHeight : Integer);
|
|
var
|
|
h, NearHeight, d, dMin : Integer;
|
|
|
|
function CalcHeight(ABtnHeight:Integer):Integer;
|
|
var FYOfs : Integer;
|
|
begin
|
|
FYOfs := MulDiv(ABtnHeight, cxMinCalcYOfs, cxMinCalcBtnHeight);
|
|
Result := (FYOfs + ABtnHeight) * 5 + FYOfs;
|
|
end;
|
|
|
|
begin
|
|
if AutoFontSize then
|
|
begin
|
|
h := MulDiv(AWidth, cxMinCalcHeight, cxMinCalcWidth);
|
|
if AHeight > h then AHeight := h;
|
|
{Calculate nearest FCalcHeight }
|
|
h := cxMinCalcBtnHeight;
|
|
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;
|
|
end
|
|
else
|
|
NearHeight := Canvas.FontHeight(Font) * 2;
|
|
FCalcBtnHeight := NearHeight;
|
|
FCalcBtnWidth := MulDiv(FCalcBtnHeight, cxMinCalcBtnWidth, cxMinCalcBtnHeight);
|
|
FCalcYOfs := MulDiv(FCalcBtnHeight, cxMinCalcYOfs, cxMinCalcBtnHeight);
|
|
FCalcXOfs := FCalcYOfs;
|
|
FCalcLargeBtnWidth := MulDiv(FCalcBtnWidth, 17, 10);
|
|
FCalcFontSize := MulDiv(FCalcBtnHeight, cxMinCalcFontSize, cxMinCalcBtnHeight);
|
|
FCalcHeight := (FCalcYOfs+FCalcBtnHeight)*5+FCalcYOfs;
|
|
FCalcWidth := (FCalcXOfs+FCalcBtnWidth)*6+FCalcXOfs*2+4;
|
|
// reCalc rect buttons
|
|
CreateLayout;
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.FontChanged;
|
|
begin
|
|
if not (csLoading in ComponentState) then ParentFont := False;
|
|
inherited FontChanged;
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.FocusChanged;
|
|
begin
|
|
inherited FocusChanged;
|
|
InvalidateButton(cbEqual);
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.SetEnabled( Value: Boolean);
|
|
begin
|
|
inherited;
|
|
Invalidate;
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.StopTracking;
|
|
begin
|
|
if FTracking then
|
|
begin
|
|
TrackButton(-1, -1);
|
|
FTracking := False;
|
|
MouseCapture := False;
|
|
if FDownButton <> cbNone then
|
|
FButtons[FDownButton].Down := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.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
|
|
InvalidateButton(FDownButton);
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.InvalidateButton(ButtonKind : TcxCalcButtonKind);
|
|
var
|
|
R: TRect;
|
|
begin
|
|
if ButtonKind <> cbNone then
|
|
begin
|
|
R := FButtons[ButtonKind].BtnRect;
|
|
InvalidateRect(R, False);
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.MouseLeave(AControl: TControl);
|
|
begin
|
|
inherited;
|
|
if GetPainter.IsButtonHotTrack and Enabled and
|
|
not Dragging and (FActiveButton <> cbNone) then
|
|
begin
|
|
InvalidateButton(FActiveButton);
|
|
FActiveButton := cbNone;
|
|
end;
|
|
end;
|
|
|
|
function TcxCustomCalculator.GetButtonKindChar(Ch : Char) : TcxCalcbuttonKind;
|
|
begin
|
|
case Ch of
|
|
'0'..'9' : Result := TcxCalcbuttonKind(Ord(cbNum0)+Ord(Ch)-Ord('0'));
|
|
'+' : Result := cbAdd;
|
|
'-' : Result := cbSub;
|
|
'*' : Result := cbMul;
|
|
'/' : Result := cbDiv;
|
|
'%' : Result := cbPercent;
|
|
'=' : Result := cbEqual;
|
|
#8 : Result := cbBack;
|
|
'@' : Result := cbSqrt;
|
|
'.', ',': Result := cbDecimal;
|
|
else
|
|
Result := cbNone;
|
|
end;
|
|
end;
|
|
|
|
function TcxCustomCalculator.GetButtonKindKey(Key: Word; Shift: TShiftState) : TcxCalcbuttonKind;
|
|
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 TcxCustomCalculator.CopyToClipboard;
|
|
begin
|
|
Clipboard.AsText := GetEditorValue;
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.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 TcxCustomCalculator.SetAutoFontSize(Value : Boolean);
|
|
begin
|
|
if AutoFontSize <> Value then
|
|
begin
|
|
FAutoFontSize := Value;
|
|
Font.OnChange(nil);
|
|
end;
|
|
end;
|
|
|
|
// math routines
|
|
procedure TcxCustomCalculator.Error;
|
|
begin
|
|
FStatus := csError;
|
|
SetEditorValue(cxGetResourceString(@scxSCalcError));
|
|
if FBeepOnError then MessageBeep(0);
|
|
// if Assigned(FOnError) then FOnError(Self);
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.CheckFirst;
|
|
begin
|
|
if FStatus = csFirst then
|
|
begin
|
|
FStatus := csValid;
|
|
SetEditorValue('0');
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.Clear;
|
|
begin
|
|
FStatus := csFirst;
|
|
SetDisplay(0.0);
|
|
FOperator := cbEqual;
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.ButtonClick(ButtonKind : TcxCalcButtonKind);
|
|
var
|
|
AValue : Extended;
|
|
AOldEditorValue: string;
|
|
begin
|
|
if Assigned(FOnButtonClick) then FOnButtonClick(Self, ButtonKind);
|
|
if (FStatus = csError) and not (ButtonKind in [cbClear, cbCancel]) then
|
|
begin
|
|
Error;
|
|
Exit;
|
|
end;
|
|
AOldEditorValue := EditorValue;
|
|
LockChanges(True);
|
|
try
|
|
case ButtonKind of
|
|
cbDecimal:
|
|
begin
|
|
CheckFirst;
|
|
if Pos(DecimalSeparator, EditorValue) = 0 then
|
|
SetEditorValue(EditorValue + DecimalSeparator);
|
|
end;
|
|
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 EditorValue = '0' then SetEditorValue('');
|
|
if Length(EditorValue) < Max(2, FPrecision) + Ord(Boolean(Pos('-', EditorValue))) then
|
|
SetEditorValue(EditorValue + Char(Ord('0')+Byte(ButtonKind)-Byte(cbNum0)))
|
|
else
|
|
if FBeepOnError then MessageBeep(0);
|
|
end;
|
|
cbBack:
|
|
begin
|
|
CheckFirst;
|
|
if (Length(EditorValue) = 1) or ((Length(EditorValue) = 2) and (EditorValue[1] = '-')) then
|
|
SetEditorValue('0')
|
|
else
|
|
SetEditorValue(Copy(EditorValue, 1, Length(EditorValue) - 1));
|
|
end;
|
|
cbSign: SetDisplay(-GetDisplay);
|
|
cbAdd, cbSub, cbMul, cbDiv, cbEqual, cbPercent :
|
|
begin
|
|
if FStatus = csValid then
|
|
begin
|
|
FStatus := csFirst;
|
|
AValue := GetDisplay;
|
|
if ButtonKind = cbPercent then
|
|
case FOperator of
|
|
cbAdd, cbSub : AValue := FOperand * AValue / 100.0;
|
|
cbMul, cbDiv : AValue := AValue / 100.0;
|
|
end;
|
|
case FOperator of
|
|
cbAdd : SetDisplay(FOperand + AValue);
|
|
cbSub : SetDisplay(FOperand - AValue);
|
|
cbMul : SetDisplay(FOperand * AValue);
|
|
cbDiv : if AValue = 0 then Error else SetDisplay(FOperand / AValue);
|
|
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;
|
|
finally
|
|
LockChanges(False, AOldEditorValue <> EditorValue);
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.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 TcxCustomCalculator.InvalidateMemoryButtons;
|
|
begin
|
|
InvalidateButton(cbMC);
|
|
InvalidateButton(cbMR);
|
|
end;
|
|
|
|
function TcxCustomCalculator.GetDisplay: Extended;
|
|
var
|
|
S: string;
|
|
begin
|
|
if FStatus = csError then
|
|
Result := 0.0
|
|
else
|
|
begin
|
|
S := Trim(GetEditorValue);
|
|
if S = '' then S := '0';
|
|
RemoveThousandSeparator(S);
|
|
Result := StrToFloat(S);
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.SetDisplay(Value: Extended);
|
|
var
|
|
S: string;
|
|
begin
|
|
S := FloatToStrF(Value, ffGeneral, Max(2, FPrecision), 0);
|
|
if GetEditorValue <> S then
|
|
begin
|
|
SetEditorValue(S);
|
|
if Assigned(FOnDisplayChange) then FOnDisplayChange(Self);
|
|
end;
|
|
end;
|
|
|
|
function TcxCustomCalculator.GetMemory: Extended;
|
|
begin
|
|
Result := FMemory;
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.HidePopup(Sender: TcxControl; AReason: TcxEditCloseUpReason);
|
|
begin
|
|
if Assigned(FOnHidePopup) then FOnHidePopup(Self, AReason);
|
|
end;
|
|
|
|
procedure TcxCustomCalculator.LockChanges(ALock: Boolean; AInvokeChangedOnUnlock: Boolean = True);
|
|
begin
|
|
end;
|
|
|
|
{ TcxPopupCalculator }
|
|
|
|
constructor TcxPopupCalculator.Create(AOwner: TComponent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
IsPopupControl := True;
|
|
end;
|
|
|
|
procedure TcxPopupCalculator.Init;
|
|
begin
|
|
FPressedButton := cbNone;
|
|
end;
|
|
|
|
function TcxPopupCalculator.GetEditorValue: string;
|
|
begin
|
|
Result := Edit.Text;
|
|
end;
|
|
|
|
function TcxPopupCalculator.GetPainter: TcxCustomLookAndFeelPainterClass;
|
|
begin
|
|
if Edit.ViewInfo.Painter <> nil then
|
|
Result := Edit.ViewInfo.Painter
|
|
else
|
|
Result := GetButtonPainterClass(Edit.PopupControlsLookAndFeel);
|
|
end;
|
|
|
|
procedure TcxPopupCalculator.KeyDown(var Key: Word; Shift: TShiftState);
|
|
begin
|
|
inherited KeyDown(Key, Shift);
|
|
case Key of
|
|
VK_ESCAPE: HidePopup(Self, crCancel);
|
|
VK_INSERT:
|
|
if (Shift = [ssShift]) then
|
|
PasteFromClipboard
|
|
else
|
|
if (Shift = [ssCtrl]) then
|
|
CopyToClipboard;
|
|
VK_F4:
|
|
if not (ssAlt in Shift) then
|
|
HidePopup(Self, crClose);
|
|
VK_UP, VK_DOWN:
|
|
if Shift = [ssAlt] then
|
|
HidePopup(Self, crClose);
|
|
VK_TAB:
|
|
Edit.DoEditKeyDown(Key, Shift);
|
|
VK_RETURN:
|
|
HidePopup(Self, crEnter);
|
|
end;
|
|
end;
|
|
|
|
procedure TcxPopupCalculator.KeyPress(var Key: Char);
|
|
begin
|
|
inherited KeyPress(Key);
|
|
if (Key = '=') and FEdit.ActiveProperties.QuickClose then
|
|
HidePopup(Self, crEnter);
|
|
end;
|
|
|
|
procedure TcxPopupCalculator.SetEditorValue(const Value: string);
|
|
begin
|
|
if Edit.DoEditing then
|
|
begin
|
|
Edit.InnerEdit.EditValue := Value;
|
|
Edit.ModifiedAfterEnter := True;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxPopupCalculator.LockChanges(ALock: Boolean; AInvokeChangedOnUnlock: Boolean = True);
|
|
begin
|
|
inherited;
|
|
Edit.LockChangeEvents(ALock, AInvokeChangedOnUnlock);
|
|
end;
|
|
|
|
{ TcxCalcEditPropertiesValues }
|
|
|
|
procedure TcxCalcEditPropertiesValues.Assign(Source: TPersistent);
|
|
begin
|
|
if Source is TcxCalcEditPropertiesValues then
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
inherited Assign(Source);
|
|
Precision := TcxCalcEditPropertiesValues(Source).Precision;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end
|
|
else
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
procedure TcxCalcEditPropertiesValues.RestoreDefaults;
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
inherited RestoreDefaults;
|
|
Precision := False;
|
|
finally
|
|
EndUpdate;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCalcEditPropertiesValues.SetPrecision(Value: Boolean);
|
|
begin
|
|
if Value <> FPrecision then
|
|
begin
|
|
FPrecision := Value;
|
|
Changed;
|
|
end;
|
|
end;
|
|
|
|
{ TcxCustomCalcEditProperties }
|
|
|
|
constructor TcxCustomCalcEditProperties.Create(AOwner: TPersistent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
FBeepOnError := True;
|
|
FPrecision := cxDefCalcPrecision;
|
|
// MaxLength := cxDefCalcPrecision + 2;
|
|
FQuickClose := False;
|
|
PopupSizeable := False;
|
|
ImmediateDropDown := False;
|
|
end;
|
|
|
|
function TcxCustomCalcEditProperties.GetAssignedValues: TcxCalcEditPropertiesValues;
|
|
begin
|
|
Result := TcxCalcEditPropertiesValues(FAssignedValues);
|
|
end;
|
|
|
|
function TcxCustomCalcEditProperties.GetPrecision: Byte;
|
|
begin
|
|
if AssignedValues.Precision then
|
|
Result := FPrecision
|
|
else
|
|
if IDefaultValuesProvider <> nil then
|
|
Result := IDefaultValuesProvider.DefaultPrecision
|
|
else
|
|
Result := cxDefCalcPrecision;
|
|
if Result > cxMaxCalcPrecision then
|
|
Result := cxMaxCalcPrecision;
|
|
end;
|
|
|
|
function TcxCustomCalcEditProperties.IsPrecisionStored: Boolean;
|
|
begin
|
|
Result := AssignedValues.Precision;
|
|
end;
|
|
|
|
procedure TcxCustomCalcEditProperties.SetAssignedValues(
|
|
Value: TcxCalcEditPropertiesValues);
|
|
begin
|
|
FAssignedValues.Assign(Value);
|
|
end;
|
|
|
|
procedure TcxCustomCalcEditProperties.SetBeepOnError(Value: Boolean);
|
|
begin
|
|
if Value <> FBeepOnError then
|
|
begin
|
|
FBeepOnError := Value;
|
|
Changed;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomCalcEditProperties.SetPrecision(Value: Byte);
|
|
begin
|
|
if AssignedValues.Precision and (Value = FPrecision) then
|
|
Exit;
|
|
|
|
AssignedValues.FPrecision := True;
|
|
FPrecision := Value;
|
|
Changed;
|
|
end;
|
|
|
|
procedure TcxCustomCalcEditProperties.SetQuickClose(Value: Boolean);
|
|
begin
|
|
if Value <> FQuickClose then
|
|
begin
|
|
FQuickClose := Value;
|
|
Changed;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomCalcEditProperties.SetScientificFormat(Value: Boolean);
|
|
begin
|
|
if Value <> FScientificFormat then
|
|
begin
|
|
FScientificFormat := Value;
|
|
Changed;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomCalcEditProperties.SetUseThousandSeparator(Value: Boolean);
|
|
begin
|
|
if Value <> FUseThousandSeparator then
|
|
begin
|
|
FUseThousandSeparator := Value;
|
|
Changed;
|
|
end;
|
|
end;
|
|
|
|
function TcxCustomCalcEditProperties.GetAlwaysPostEditValue: Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
class function TcxCustomCalcEditProperties.GetAssignedValuesClass: TcxCustomEditPropertiesValuesClass;
|
|
begin
|
|
Result := TcxCalcEditPropertiesValues;
|
|
end;
|
|
|
|
function TcxCustomCalcEditProperties.HasDigitGrouping(
|
|
AIsDisplayValueSynchronizing: Boolean): Boolean;
|
|
begin
|
|
Result := not ScientificFormat and UseThousandSeparator;
|
|
end;
|
|
|
|
function TcxCustomCalcEditProperties.PopupWindowAcceptsAnySize: Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
function TcxCustomCalcEditProperties.StrToFloatEx(S: string;
|
|
var Value: Extended): Boolean;
|
|
var
|
|
E: Extended;
|
|
I: Integer;
|
|
begin
|
|
// Ignore Thousand Separators
|
|
for I := Length(S) downto 1 do
|
|
if S[I] = ThousandSeparator then
|
|
Delete(S, I, 1);
|
|
if not TextToFloat(PChar(S), E, fvExtended) or
|
|
((E <> 0) and ((Abs(E) < MinDouble) or (Abs(E) > MaxDouble))) then
|
|
begin
|
|
Value := 0;
|
|
Result := False;
|
|
end
|
|
else
|
|
begin
|
|
Value := E;
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomCalcEditProperties.Assign(Source: TPersistent);
|
|
begin
|
|
if Source is TcxCustomCalcEditProperties then
|
|
begin
|
|
BeginUpdate;
|
|
try
|
|
inherited Assign(Source);
|
|
with TcxCustomCalcEditProperties(Source) do
|
|
begin
|
|
Self.BeepOnError := BeepOnError;
|
|
|
|
Self.AssignedValues.Precision := False;
|
|
if AssignedValues.Precision then
|
|
Self.Precision := Precision;
|
|
|
|
Self.QuickClose := QuickClose;
|
|
Self.ScientificFormat := ScientificFormat;
|
|
Self.UseThousandSeparator := UseThousandSeparator;
|
|
end;
|
|
finally
|
|
EndUpdate
|
|
end
|
|
end
|
|
else
|
|
inherited Assign(Source);
|
|
end;
|
|
|
|
class function TcxCustomCalcEditProperties.GetContainerClass: TcxContainerClass;
|
|
begin
|
|
Result := TcxCalcEdit;
|
|
end;
|
|
|
|
function TcxCustomCalcEditProperties.GetEditValueSource(AEditFocused: Boolean): TcxDataEditValueSource;
|
|
begin
|
|
if not AEditFocused and not AssignedValues.DisplayFormat and
|
|
(IDefaultValuesProvider <> nil) and
|
|
IDefaultValuesProvider.IsDisplayFormatDefined(True) then
|
|
Result := evsText
|
|
else
|
|
Result := evsValue;
|
|
end;
|
|
|
|
function TcxCustomCalcEditProperties.IsDisplayValueValid(
|
|
var DisplayValue: TcxEditValue; AEditFocused: Boolean): Boolean;
|
|
begin
|
|
// if AEditFocused
|
|
|
|
Result := True;
|
|
end;
|
|
|
|
function TcxCustomCalcEditProperties.IsEditValueValid(var EditValue: TcxEditValue;
|
|
AEditFocused: Boolean): Boolean;
|
|
var
|
|
AValue: Extended;
|
|
begin
|
|
Result := VarIsNumericEx(EditValue) or VarIsSoftNull(EditValue);
|
|
if not Result then
|
|
Result := VarIsStr(EditValue) and
|
|
TextToFloat(PChar(VarToStr(EditValue)), AValue, fvExtended);
|
|
end;
|
|
|
|
procedure TcxCustomCalcEditProperties.PrepareDisplayValue(
|
|
const AEditValue: TcxEditValue; var DisplayValue: TcxEditValue;
|
|
AEditFocused: Boolean);
|
|
|
|
procedure RemoveInsignificantZeros(var S: string);
|
|
var
|
|
AExponentialPart: string;
|
|
I: Integer;
|
|
begin
|
|
if Pos(DecimalSeparator, S) = 0 then
|
|
Exit;
|
|
AExponentialPart := RemoveExponentialPart(S);
|
|
I := Length(S);
|
|
while S[I] = '0' do
|
|
Dec(I);
|
|
Delete(S, I + 1, Length(S) - I);
|
|
if S[Length(S)] = DecimalSeparator then
|
|
Delete(S, Length(S), 1);
|
|
S := S + AExponentialPart;
|
|
end;
|
|
|
|
var
|
|
AFormat: TFloatFormat;
|
|
APrecision: Byte;
|
|
S: string;
|
|
begin
|
|
if VarIsSoftNull(AEditValue) then
|
|
S := ''
|
|
else
|
|
if not AEditFocused and AssignedValues.DisplayFormat then
|
|
S := FormatFloat(DisplayFormat, AEditValue)
|
|
else
|
|
begin
|
|
if ScientificFormat then
|
|
AFormat := ffExponent
|
|
else
|
|
AFormat := ffGeneral;
|
|
APrecision := Precision;
|
|
if APrecision = 0 then
|
|
APrecision := cxDefCalcPrecision;
|
|
|
|
S := FloatToStrF(AEditValue, AFormat, APrecision, 0);
|
|
if UseThousandSeparator and not ScientificFormat then
|
|
InsertThousandSeparator(S);
|
|
if ScientificFormat then
|
|
RemoveInsignificantZeros(S);
|
|
end;
|
|
DisplayValue := S;
|
|
end;
|
|
|
|
procedure TcxCustomCalcEditProperties.ValidateDisplayValue(
|
|
var ADisplayValue: TcxEditValue; var AErrorText: TCaption;
|
|
var Error: Boolean; AEdit: TcxCustomEdit);
|
|
begin
|
|
Error := False;
|
|
inherited ValidateDisplayValue(ADisplayValue, AErrorText, Error, AEdit);
|
|
end;
|
|
|
|
{ TcxCustomCalcEdit }
|
|
|
|
destructor TcxCustomCalcEdit.Destroy;
|
|
begin
|
|
FreeAndNil(FCalculator);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TcxCustomCalcEdit.GetProperties: TcxCustomCalcEditProperties;
|
|
begin
|
|
Result := TcxCustomCalcEditProperties(FProperties);
|
|
end;
|
|
|
|
function TcxCustomCalcEdit.GetActiveProperties: TcxCustomCalcEditProperties;
|
|
begin
|
|
Result := TcxCustomCalcEditProperties(InternalGetActiveProperties);
|
|
end;
|
|
|
|
function TcxCustomCalcEdit.GetValue: Extended;
|
|
begin
|
|
if VarIsNull(EditValue) or (VarIsStr(EditValue) and (EditValue = '')) then
|
|
Result := 0
|
|
else
|
|
Result := EditValue;
|
|
end;
|
|
|
|
procedure TcxCustomCalcEdit.SetProperties(Value: TcxCustomCalcEditProperties);
|
|
begin
|
|
FProperties.Assign(Value);
|
|
end;
|
|
|
|
procedure TcxCustomCalcEdit.SetValue(const Value: Extended);
|
|
begin
|
|
InternalEditValue := Value;
|
|
end;
|
|
|
|
procedure TcxCustomCalcEdit.FormatChanged;
|
|
begin
|
|
DataBinding.UpdateDisplayValue;
|
|
end;
|
|
|
|
function TcxCustomCalcEdit.CanDropDown: Boolean;
|
|
begin
|
|
Result := (not ActiveProperties.ReadOnly) and DataBinding.IsDataAvailable;
|
|
end;
|
|
|
|
procedure TcxCustomCalcEdit.CreatePopupWindow;
|
|
begin
|
|
inherited CreatePopupWindow;
|
|
PopupWindow.ModalMode := False;
|
|
end;
|
|
|
|
procedure TcxCustomCalcEdit.DoEnter;
|
|
begin
|
|
SynchronizeDisplayValue;
|
|
inherited;
|
|
end;
|
|
|
|
procedure TcxCustomCalcEdit.DoExit;
|
|
begin
|
|
inherited;
|
|
DataBinding.UpdateDisplayValue;
|
|
end;
|
|
|
|
procedure TcxCustomCalcEdit.DoInitPopup;
|
|
begin
|
|
inherited DoInitPopup;
|
|
ActiveProperties.PopupControl := FCalculator;
|
|
end;
|
|
|
|
procedure TcxCustomCalcEdit.Initialize;
|
|
begin
|
|
inherited Initialize;
|
|
Value := 0;
|
|
FCalculator := TcxPopupCalculator.Create(Self);
|
|
FCalculator.Parent := PopupWindow;
|
|
FCalculator.Edit := Self;
|
|
FCalculator.AutoFontSize := False;
|
|
FCalculator.OnHidePopup := HidePopup;
|
|
ActiveProperties.PopupControl := FCalculator;
|
|
end;
|
|
|
|
procedure TcxCustomCalcEdit.InitializePopupWindow;
|
|
begin
|
|
inherited InitializePopupWindow;
|
|
with Calculator do
|
|
begin
|
|
HandleNeeded;
|
|
Font.Assign(Self.VisibleFont);
|
|
FontChanged;
|
|
Resize;
|
|
end;
|
|
end;
|
|
|
|
function TcxCustomCalcEdit.InternalGetEditingValue: TcxEditValue;
|
|
begin
|
|
PrepareEditValue(Text, Result, True);
|
|
end;
|
|
|
|
function TcxCustomCalcEdit.IsValidChar(Key: Char): Boolean;
|
|
|
|
function NumDigits(const S: string): Byte;
|
|
var
|
|
I: Integer;
|
|
begin
|
|
Result := 0;
|
|
for I := 1 to Length(S) do
|
|
if (S[I] = 'e') or (S[I] = 'E') then
|
|
Break
|
|
else
|
|
if dxCharInSet(S[I], ['0'..'9']) then
|
|
Inc(Result);
|
|
end;
|
|
|
|
var
|
|
S: string;
|
|
V: Extended;
|
|
StartPos, StopPos: Integer;
|
|
begin
|
|
Result := False;
|
|
if not IsNumericChar(Key, ntExponent) then
|
|
Exit;
|
|
S := Text;
|
|
StartPos := SelStart;
|
|
StopPos := SelStart + SelLength;
|
|
Delete(S, SelStart + 1, StopPos - StartPos);
|
|
if (Key = '-') and (S = '') then
|
|
begin
|
|
Result := True;
|
|
Exit;
|
|
end;
|
|
Insert(Key, S, StartPos + 1);
|
|
Result := ActiveProperties.StrToFloatEx(S, V);
|
|
end;
|
|
|
|
procedure TcxCustomCalcEdit.KeyPress(var Key: Char);
|
|
begin
|
|
if (Key = '.') or (Key = ',') then
|
|
Key := DecimalSeparator;
|
|
if IsTextChar(Key) and not IsValidChar(Key) then
|
|
begin
|
|
Key := #0;
|
|
if ActiveProperties.BeepOnError then Beep;
|
|
end;
|
|
inherited KeyPress(Key);
|
|
end;
|
|
|
|
procedure TcxCustomCalcEdit.PopupWindowClosed(Sender: TObject);
|
|
begin
|
|
if Text = cxGetResourceString(@scxSCalcError) then InternalEditValue := 0;
|
|
if ActiveProperties.AutoSelect then SelectAll else SelStart := Length(Text);
|
|
inherited PopupWindowClosed(Sender);
|
|
end;
|
|
|
|
procedure TcxCustomCalcEdit.PopupWindowShowed(Sender: TObject);
|
|
begin
|
|
inherited PopupWindowShowed(Sender);
|
|
FCalculator.Init;
|
|
end;
|
|
|
|
procedure TcxCustomCalcEdit.PropertiesChanged(Sender: TObject);
|
|
begin
|
|
if (Sender <> nil) and ActiveProperties.FormatChanging then
|
|
Exit;
|
|
inherited PropertiesChanged(Sender);
|
|
if not PropertiesChangeLocked then
|
|
begin
|
|
FCalculator.BeepOnError := ActiveProperties.BeepOnError;
|
|
FCalculator.Precision := ActiveProperties.Precision;
|
|
ActiveProperties.FChangedLocked := True;
|
|
ActiveProperties.PopupControl := FCalculator;
|
|
ActiveProperties.FChangedLocked := False;
|
|
end;
|
|
end;
|
|
|
|
function TcxCustomCalcEdit.InternalPrepareEditValue(const ADisplayValue: string;
|
|
out EditValue: TcxEditValue): Boolean;
|
|
var
|
|
AValue: Extended;
|
|
S: string;
|
|
begin
|
|
Result := True;
|
|
S := VarToStr(ADisplayValue);
|
|
if not ActiveProperties.ScientificFormat and ActiveProperties.UseThousandSeparator then
|
|
RemoveThousandSeparator(S);
|
|
if Trim(S) = '' then
|
|
EditValue := Null
|
|
else
|
|
begin
|
|
Result := TextToFloat(PChar(S), AValue, fvExtended);
|
|
if Result then
|
|
EditValue := AValue
|
|
else
|
|
EditValue := Null;
|
|
end;
|
|
end;
|
|
|
|
class function TcxCustomCalcEdit.GetPropertiesClass: TcxCustomEditPropertiesClass;
|
|
begin
|
|
Result := TcxCustomCalcEditProperties;
|
|
end;
|
|
|
|
procedure TcxCustomCalcEdit.PasteFromClipboard;
|
|
begin
|
|
if DoEditing then
|
|
Calculator.PasteFromClipboard;
|
|
end;
|
|
|
|
procedure TcxCustomCalcEdit.PrepareEditValue(
|
|
const ADisplayValue: TcxEditValue; out EditValue: TcxEditValue;
|
|
AEditFocused: Boolean);
|
|
begin
|
|
InternalPrepareEditValue(ADisplayValue, EditValue);
|
|
end;
|
|
|
|
{ TcxCalcEdit }
|
|
|
|
class function TcxCalcEdit.GetPropertiesClass: TcxCustomEditPropertiesClass;
|
|
begin
|
|
Result := TcxCalcEditProperties;
|
|
end;
|
|
|
|
function TcxCalcEdit.GetActiveProperties: TcxCalcEditProperties;
|
|
begin
|
|
Result := TcxCalcEditProperties(InternalGetActiveProperties);
|
|
end;
|
|
|
|
function TcxCalcEdit.GetProperties: TcxCalcEditProperties;
|
|
begin
|
|
Result := TcxCalcEditProperties(FProperties);
|
|
end;
|
|
|
|
procedure TcxCalcEdit.SetProperties(Value: TcxCalcEditProperties);
|
|
begin
|
|
FProperties.Assign(Value);
|
|
end;
|
|
|
|
{ TcxFilterCalcEditHelper }
|
|
|
|
class function TcxFilterCalcEditHelper.GetFilterEditClass: TcxCustomEditClass;
|
|
begin
|
|
Result := TcxCalcEdit;
|
|
end;
|
|
|
|
class function TcxFilterCalcEditHelper.GetSupportedFilterOperators(
|
|
AProperties: TcxCustomEditProperties;
|
|
AValueTypeClass: TcxValueTypeClass;
|
|
AExtendedSet: Boolean = False): TcxFilterControlOperators;
|
|
begin
|
|
Result := [fcoEqual, fcoNotEqual, fcoLess, fcoLessEqual, fcoGreater,
|
|
fcoGreaterEqual, fcoBlanks, fcoNonBlanks];
|
|
if AExtendedSet then
|
|
Result := Result + [fcoBetween, fcoNotBetween, fcoInList, fcoNotInList];
|
|
end;
|
|
|
|
class procedure TcxFilterCalcEditHelper.InitializeProperties(AProperties,
|
|
AEditProperties: TcxCustomEditProperties; AHasButtons: Boolean);
|
|
begin
|
|
inherited InitializeProperties(AProperties, AEditProperties, AHasButtons);
|
|
with TcxCustomCalcEditProperties(AProperties) do
|
|
QuickClose := True;
|
|
end;
|
|
|
|
initialization
|
|
GetRegisteredEditProperties.Register(TcxCalcEditProperties, scxSEditRepositoryCalcItem);
|
|
FilterEditsController.Register(TcxCalcEditProperties, TcxFilterCalcEditHelper);
|
|
|
|
finalization
|
|
FilterEditsController.Unregister(TcxCalcEditProperties, TcxFilterCalcEditHelper);
|
|
|
|
end.
|