{********************************************************************} { } { Developer Express Visual Component Library } { ExpressEditors } { } { Copyright (c) 1998-2008 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.