561 lines
18 KiB
ObjectPascal
561 lines
18 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 cxSpinButton;
|
|
|
|
{$I cxVer.inc}
|
|
|
|
interface
|
|
|
|
uses
|
|
{$IFDEF DELPHI6}
|
|
Variants,
|
|
{$ENDIF}
|
|
Windows, Classes, Controls, Forms, Graphics, Messages, StdCtrls, SysUtils,
|
|
cxClasses, cxContainer, cxControls, cxCustomData, cxEdit, cxExtEditConsts,
|
|
cxExtEditUtils, cxGraphics, cxMaskEdit, cxSpinEdit, cxTextEdit, cxVariants;
|
|
|
|
type
|
|
{ TcxSpinButtonViewData }
|
|
|
|
TcxCustomSpinButtonProperties = class;
|
|
|
|
TcxSpinButtonViewData = class(TcxSpinEditViewData)
|
|
private
|
|
function GetProperties: TcxCustomSpinButtonProperties;
|
|
protected
|
|
function CanPressButton(AViewInfo: TcxCustomEditViewInfo; AButtonVisibleIndex: Integer):
|
|
Boolean; override;
|
|
function IsButtonPressed(AViewInfo: TcxCustomEditViewInfo; AButtonVisibleIndex:
|
|
Integer): Boolean; override;
|
|
public
|
|
PressedState: TcxSpinEditPressedState;
|
|
procedure Calculate(ACanvas: TcxCanvas; const ABounds: TRect; const P: TPoint;
|
|
Button: TcxMouseButton; Shift: TShiftState; AViewInfo: TcxCustomEditViewInfo;
|
|
AIsMouseEvent: Boolean); override;
|
|
property Properties: TcxCustomSpinButtonProperties read GetProperties;
|
|
end;
|
|
|
|
{ TcxCustomSpinButtonProperties }
|
|
|
|
TcxCustomSpinButton = class;
|
|
|
|
TcxCustomSpinButtonProperties = class(TcxCustomSpinEditProperties)
|
|
protected
|
|
class function GetViewDataClass: TcxCustomEditViewDataClass; override;
|
|
function IsDisplayValueNumeric: Boolean; override;
|
|
function IsEditValueNumeric: Boolean; override;
|
|
function PreserveSelection: Boolean; override;
|
|
public
|
|
constructor Create(AOwner: TPersistent); override;
|
|
class function GetContainerClass: TcxContainerClass; override;
|
|
end;
|
|
|
|
{ TcxSpinButtonProperties }
|
|
|
|
TcxSpinButtonProperties = class(TcxCustomSpinButtonProperties)
|
|
published
|
|
property Alignment;
|
|
property AssignedValues;
|
|
property AutoSelect;
|
|
property BeepOnError;
|
|
property HideSelection;
|
|
property ImmediatePost;
|
|
property Increment;
|
|
property LargeIncrement;
|
|
property MaxValue;
|
|
property MinValue;
|
|
property ReadOnly;
|
|
property SpinButtons;
|
|
property UseCtrlIncrement;
|
|
property UseLeftAlignmentOnEditing;
|
|
property ValueType default vtInt;
|
|
property OnChange;
|
|
property OnEditValueChanged;
|
|
end;
|
|
|
|
{ TcxSpinButtonControlHook }
|
|
|
|
TcxSpinButtonControlHook = class(TcxControlHook)
|
|
private
|
|
FParent: TWinControl;
|
|
protected
|
|
procedure HookWndProc(var AMsg: TMessage); override;
|
|
public
|
|
destructor Destroy; override;
|
|
end;
|
|
|
|
{ TcxCustomSpinButton }
|
|
|
|
TcxCustomSpinButton = class(TcxCustomSpinEdit)
|
|
private
|
|
FAssociate: TWinControl;
|
|
FAutoWidth: Boolean;
|
|
FSpinButtonControlHook: TcxSpinButtonControlHook;
|
|
function GetActiveProperties: TcxCustomSpinButtonProperties;
|
|
function GetProperties: TcxCustomSpinButtonProperties;
|
|
procedure SetAssociate(AValue: TWinControl);
|
|
procedure SetAutoWidth(Value: Boolean);
|
|
procedure SetProperties(Value: TcxCustomSpinButtonProperties);
|
|
protected
|
|
procedure InternalSetEditValue(const Value: TcxEditValue;
|
|
AValidateEditValue: Boolean); override;
|
|
procedure InternalSetDisplayValue(const Value: TcxEditValue); override;
|
|
procedure Notification(AComponent: TComponent; Operation: TOperation); override;
|
|
function CanFocusOnClick: Boolean; override;
|
|
procedure SetSize; override;
|
|
procedure Initialize; override;
|
|
function InternalDoEditing: Boolean; override;
|
|
procedure JoinToAssociate; virtual;
|
|
procedure SetAssociateText(const AValue: Variant); virtual;
|
|
function GetValue: Variant; override;
|
|
procedure SynchronizeEditValueFromAssociate; virtual;
|
|
property Associate: TWinControl read FAssociate write SetAssociate;
|
|
property AutoWidth: Boolean read FAutoWidth write SetAutoWidth default True;
|
|
property TabStop default False;
|
|
public
|
|
destructor Destroy; override;
|
|
class function GetPropertiesClass: TcxCustomEditPropertiesClass; override;
|
|
function Increment(AButton: TcxSpinEditButton): Boolean; override;
|
|
property ActiveProperties: TcxCustomSpinButtonProperties read GetActiveProperties;
|
|
property Properties: TcxCustomSpinButtonProperties read GetProperties
|
|
write SetProperties;
|
|
end;
|
|
|
|
{ TcxSpinButton }
|
|
|
|
TcxSpinButton = class(TcxCustomSpinButton)
|
|
private
|
|
function GetActiveProperties: TcxSpinButtonProperties;
|
|
function GetProperties: TcxSpinButtonProperties;
|
|
procedure SetProperties(Value: TcxSpinButtonProperties);
|
|
public
|
|
class function GetPropertiesClass: TcxCustomEditPropertiesClass; override;
|
|
property ActiveProperties: TcxSpinButtonProperties read GetActiveProperties;
|
|
published
|
|
property Anchors;
|
|
property Associate;
|
|
property AutoSize;
|
|
property AutoWidth;
|
|
property BeepOnEnter;
|
|
property Constraints;
|
|
property DragCursor;
|
|
property DragKind;
|
|
property DragMode;
|
|
property Enabled;
|
|
property ParentColor;
|
|
property ParentFont;
|
|
property ParentShowHint;
|
|
property PopupMenu;
|
|
property Properties: TcxSpinButtonProperties read GetProperties
|
|
write SetProperties;
|
|
property ShowHint;
|
|
property Style;
|
|
property StyleDisabled;
|
|
property StyleFocused;
|
|
property StyleHot;
|
|
property TabOrder;
|
|
property TabStop;
|
|
property Value;
|
|
property Visible;
|
|
property OnClick;
|
|
property OnContextPopup;
|
|
property OnDblClick;
|
|
property OnDragDrop;
|
|
property OnDragOver;
|
|
property OnEditing;
|
|
property OnEndDock;
|
|
property OnEndDrag;
|
|
property OnEnter;
|
|
property OnExit;
|
|
property OnKeyDown;
|
|
property OnKeyPress;
|
|
property OnKeyUp;
|
|
property OnMouseDown;
|
|
property OnMouseEnter;
|
|
property OnMouseLeave;
|
|
property OnMouseMove;
|
|
property OnMouseUp;
|
|
property OnStartDock;
|
|
property OnStartDrag;
|
|
end;
|
|
|
|
implementation
|
|
|
|
uses
|
|
cxEditConsts, cxEditUtils, dxThemeConsts, dxThemeManager;
|
|
|
|
type
|
|
TWinControlAccess = class(TWinControl);
|
|
|
|
{ TcxSpinButtonControlHook }
|
|
|
|
destructor TcxSpinButtonControlHook.Destroy;
|
|
begin
|
|
FParent := nil;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TcxSpinButtonControlHook.HookWndProc(var AMsg: TMessage);
|
|
var
|
|
AKey: Longint;
|
|
begin
|
|
if Assigned(WinControl) and not IsDestroying and
|
|
((AMsg.Msg = WM_KEYDOWN) or (AMsg.Msg = WM_KEYUP)) then
|
|
begin
|
|
AKey := AMsg.WParam;
|
|
if (FParent <> nil) and (AKey in [VK_UP, VK_DOWN, VK_NEXT, VK_PRIOR]) then
|
|
PostMessage(FParent.Handle, AMsg.Msg, AKey, AMsg.LParam);
|
|
end;
|
|
inherited HookWndProc(AMsg);
|
|
end;
|
|
|
|
{ TcxSpinButtonViewData }
|
|
|
|
procedure TcxSpinButtonViewData.Calculate(ACanvas: TcxCanvas; const ABounds: TRect;
|
|
const P: TPoint; Button: TcxMouseButton; Shift: TShiftState; AViewInfo: TcxCustomEditViewInfo;
|
|
AIsMouseEvent: Boolean);
|
|
begin
|
|
inherited Calculate(ACanvas, ABounds, P, Button, Shift, AViewInfo, AIsMouseEvent);
|
|
TcxSpinEditViewInfo(AViewInfo).Text := '';
|
|
end;
|
|
|
|
function TcxSpinButtonViewData.CanPressButton(AViewInfo: TcxCustomEditViewInfo;
|
|
AButtonVisibleIndex: Integer): Boolean;
|
|
begin
|
|
Result := inherited CanPressButton(AViewInfo, AButtonVisibleIndex);
|
|
end;
|
|
|
|
function TcxSpinButtonViewData.IsButtonPressed(AViewInfo: TcxCustomEditViewInfo;
|
|
AButtonVisibleIndex: Integer): Boolean;
|
|
begin
|
|
Result := inherited IsButtonPressed(AViewInfo, AButtonVisibleIndex);
|
|
end;
|
|
|
|
function TcxSpinButtonViewData.GetProperties: TcxCustomSpinButtonProperties;
|
|
begin
|
|
Result := TcxCustomSpinButtonProperties(FProperties);
|
|
end;
|
|
|
|
{ TcxCustomSpinButtonProperties }
|
|
|
|
constructor TcxCustomSpinButtonProperties.Create(AOwner: TPersistent);
|
|
begin
|
|
inherited Create(AOwner);
|
|
HideCursor := True;
|
|
end;
|
|
|
|
class function TcxCustomSpinButtonProperties.GetContainerClass: TcxContainerClass;
|
|
begin
|
|
Result := TcxSpinButton;
|
|
end;
|
|
|
|
class function TcxCustomSpinButtonProperties.GetViewDataClass: TcxCustomEditViewDataClass;
|
|
begin
|
|
Result := TcxSpinButtonViewData;
|
|
end;
|
|
|
|
function TcxCustomSpinButtonProperties.IsDisplayValueNumeric: Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
function TcxCustomSpinButtonProperties.IsEditValueNumeric: Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
function TcxCustomSpinButtonProperties.PreserveSelection: Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
{ TcxCustomSpinButton }
|
|
|
|
destructor TcxCustomSpinButton.Destroy;
|
|
begin
|
|
FSpinButtonControlHook.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
class function TcxCustomSpinButton.GetPropertiesClass: TcxCustomEditPropertiesClass;
|
|
begin
|
|
Result := TcxCustomSpinButtonProperties;
|
|
end;
|
|
|
|
function TcxCustomSpinButton.GetValue: Variant;
|
|
const
|
|
AVarTypeMap: array [TcxSpinEditValueType] of TVarType = (varInteger, varDouble);
|
|
begin
|
|
PrepareEditValue(Text, Result, InternalFocused);
|
|
if not VarIsNumeric(Result) then
|
|
Result := VarAsType(ActiveProperties.MinValue, AVarTypeMap[ActiveProperties.ValueType]);
|
|
end;
|
|
|
|
procedure TcxCustomSpinButton.InternalSetDisplayValue(const Value: TcxEditValue);
|
|
begin
|
|
if IsDestroying then
|
|
Exit;
|
|
inherited InternalSetDisplayValue(Value);
|
|
SetAssociateText(Value);
|
|
end;
|
|
|
|
procedure TcxCustomSpinButton.InternalSetEditValue(const Value: TcxEditValue; AValidateEditValue: Boolean);
|
|
begin
|
|
if IsDestroying then
|
|
Exit;
|
|
inherited InternalSetEditValue(Value, AValidateEditValue);
|
|
SetAssociateText(Value);
|
|
end;
|
|
|
|
procedure TcxCustomSpinButton.Notification(AComponent: TComponent;
|
|
Operation: TOperation);
|
|
begin
|
|
inherited Notification(AComponent, Operation);
|
|
if (Operation = opRemove) and (AComponent = FAssociate) then
|
|
Associate := nil;
|
|
end;
|
|
|
|
function TcxCustomSpinButton.CanFocusOnClick: Boolean;
|
|
begin
|
|
Result := False;
|
|
end;
|
|
|
|
function TcxCustomSpinButton.Increment(AButton: TcxSpinEditButton): Boolean;
|
|
begin
|
|
if Assigned(Associate) then SynchronizeEditValueFromAssociate;
|
|
Result := inherited Increment(AButton);
|
|
if not Result then
|
|
Exit;
|
|
KeyboardAction := True;
|
|
try
|
|
SynchronizeEditValue;
|
|
SetAssociateText(EditValue);
|
|
finally
|
|
KeyboardAction := False;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomSpinButton.SynchronizeEditValueFromAssociate;
|
|
var
|
|
FAssociateValue: TcxEditValue;
|
|
begin
|
|
if not((FAssociate is TCustomEdit) or (FAssociate is TcxCustomTextEdit)) then
|
|
Exit;
|
|
if ActiveProperties.ValueType = vtInt then
|
|
begin
|
|
if FAssociate is TcxCustomTextEdit then
|
|
FAssociateValue := cxStrToInt(TcxCustomTextEdit(FAssociate).Text, True)
|
|
else
|
|
FAssociateValue := cxStrToInt(TCustomEdit(FAssociate).Text, True);
|
|
end
|
|
else
|
|
begin
|
|
if FAssociate is TcxCustomTextEdit then
|
|
FAssociateValue := cxStrToFloat(TcxCustomTextEdit(FAssociate).Text, True)
|
|
else
|
|
FAssociateValue := cxStrToFloat(TCustomEdit(FAssociate).Text, True);
|
|
end;
|
|
if FAssociateValue <> Value then
|
|
Value := FAssociateValue;
|
|
end;
|
|
|
|
procedure TcxCustomSpinButton.SetSize;
|
|
var
|
|
AWidth: Integer;
|
|
begin
|
|
inherited SetSize;
|
|
if not AutoWidth then
|
|
Exit;
|
|
with ViewInfo do
|
|
begin
|
|
AWidth := (BorderRect.Right - BorderRect.Left) - (TextRect.Right - TextRect.Left);
|
|
if Painter <> nil then
|
|
Dec(AWidth)
|
|
else
|
|
if Length(ButtonsInfo) > 0 then
|
|
if not ButtonsInfo[0].Data.NativeStyle then
|
|
begin
|
|
AWidth := Succ(AWidth);
|
|
if Shadow then
|
|
AWidth := AWidth + cxContainerShadowWidth;
|
|
end;
|
|
end;
|
|
Width := AWidth;
|
|
end;
|
|
|
|
procedure TcxCustomSpinButton.Initialize;
|
|
begin
|
|
inherited Initialize;
|
|
FAutoWidth := True;
|
|
FSpinButtonControlHook := TcxSpinButtonControlHook.Create;
|
|
FSpinButtonControlHook.FParent := Self;
|
|
AutoSize := False;
|
|
TabStop := False;
|
|
end;
|
|
|
|
function TcxCustomSpinButton.InternalDoEditing: Boolean;
|
|
begin
|
|
Result := True;
|
|
end;
|
|
|
|
function TcxCustomSpinButton.GetActiveProperties: TcxCustomSpinButtonProperties;
|
|
begin
|
|
Result := TcxCustomSpinButtonProperties(InternalGetActiveProperties);
|
|
end;
|
|
|
|
function TcxCustomSpinButton.GetProperties: TcxCustomSpinButtonProperties;
|
|
begin
|
|
Result := TcxCustomSpinButtonProperties(FProperties);
|
|
end;
|
|
|
|
procedure TcxCustomSpinButton.SetAssociate(AValue: TWinControl);
|
|
var
|
|
I: Integer;
|
|
FCompoundControl: IcxCompoundControl;
|
|
|
|
function IsClass(ClassType: TClass; const Name: string): Boolean;
|
|
begin
|
|
Result := True;
|
|
while ClassType <> nil do
|
|
begin
|
|
if ClassType.ClassNameIs(Name) then Exit;
|
|
ClassType := ClassType.ClassParent;
|
|
end;
|
|
Result := False;
|
|
end;
|
|
|
|
begin
|
|
if AValue <> nil then
|
|
for I := 0 to Parent.ControlCount - 1 do {Is control already associated ?}
|
|
if (Parent.Controls[I] is TcxCustomSpinButton) and (Parent.Controls[I] <> Self) then
|
|
if TcxCustomSpinButton(Parent.Controls[I]).Associate = AValue then
|
|
raise EcxEditError.Create(AValue.Name +
|
|
cxGetResourceString(@scxUDAssociated) + Parent.Controls[I].Name);
|
|
|
|
if FAssociate <> nil then
|
|
begin
|
|
FSpinButtonControlHook.WinControl := nil;
|
|
FAssociate := nil;
|
|
end;
|
|
|
|
if (AValue <> nil) and (AValue.Parent = Self.Parent) and
|
|
not (AValue is TcxCustomSpinButton) and
|
|
not IsClass(AValue.ClassType, 'TcxDBTextEdit') and
|
|
not IsClass(AValue.ClassType, 'TcxDBMemo') and
|
|
not IsClass(AValue.ClassType, 'TDBTextEdit') and
|
|
not IsClass(AValue.ClassType, 'TDBMemo') then
|
|
begin
|
|
FAssociate := AValue;
|
|
if Supports(FAssociate, IcxCompoundControl, FCompoundControl) then
|
|
FSpinButtonControlHook.WinControl := FCompoundControl.ActiveControl
|
|
else
|
|
FSpinButtonControlHook.WinControl := FAssociate;
|
|
JoinToAssociate;
|
|
SetAssociateText(Value);
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomSpinButton.SetAutoWidth(Value: Boolean);
|
|
begin
|
|
if FAutoWidth <> Value then
|
|
begin
|
|
FAutoWidth := Value;
|
|
if Value then
|
|
begin
|
|
CheckHandle;
|
|
ActiveProperties.ViewStyle := vsNormal;
|
|
end
|
|
else
|
|
ActiveProperties.ViewStyle := vsButtonsOnly;
|
|
if Value then
|
|
begin
|
|
SetSize;
|
|
ShortRefreshContainer(False);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TcxCustomSpinButton.SetProperties(Value: TcxCustomSpinButtonProperties);
|
|
begin
|
|
FProperties.Assign(Value);
|
|
end;
|
|
|
|
procedure TcxCustomSpinButton.JoinToAssociate;
|
|
begin
|
|
if FAssociate is TcxCustomEdit then
|
|
Font := TcxCustomEdit(FAssociate).Style.Font
|
|
else
|
|
Font := TWinControlAccess(FAssociate).Font;
|
|
Top := FAssociate.Top;
|
|
Left := FAssociate.Left + FAssociate.Width;
|
|
Height := FAssociate.Height;
|
|
end;
|
|
|
|
procedure TcxCustomSpinButton.SetAssociateText(const AValue: Variant);
|
|
begin
|
|
if (FAssociate = nil) or ((not (FAssociate is TcxCustomTextEdit)) and
|
|
(not (FAssociate is TCustomEdit))) then Exit;
|
|
if (FAssociate is TcxCustomTextEdit) then
|
|
TcxCustomTextEdit(FAssociate).Text := VarToStr(AValue)
|
|
else
|
|
if (FAssociate is TCustomEdit) then
|
|
TCustomEdit(FAssociate).Text := VarToStr(AValue);
|
|
end;
|
|
|
|
{ TcxSpinButton }
|
|
|
|
class function TcxSpinButton.GetPropertiesClass: TcxCustomEditPropertiesClass;
|
|
begin
|
|
Result := TcxSpinButtonProperties;
|
|
end;
|
|
|
|
function TcxSpinButton.GetActiveProperties: TcxSpinButtonProperties;
|
|
begin
|
|
Result := TcxSpinButtonProperties(InternalGetActiveProperties);
|
|
end;
|
|
|
|
function TcxSpinButton.GetProperties: TcxSpinButtonProperties;
|
|
begin
|
|
Result := TcxSpinButtonProperties(FProperties);
|
|
end;
|
|
|
|
procedure TcxSpinButton.SetProperties(Value: TcxSpinButtonProperties);
|
|
begin
|
|
FProperties.Assign(Value);
|
|
end;
|
|
|
|
end.
|