{********************************************************************} { } { Developer Express Visual Component Library } { ExpressLayoutControl main components } { } { Copyright (c) 2001-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 EXPRESSLAYOUTCONTROL 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 dxLayoutControl; {$I cxVer.inc} interface uses Messages, Windows, SysUtils, Classes, Controls, Graphics, Forms, StdCtrls, ExtCtrls, IniFiles, dxCore, cxClasses, cxGraphics, cxControls, cxLookAndFeels, dxLayoutLookAndFeels, cxLibraryConsts, dxLayoutCommon; const htError = -1; htNone = 0; htCustomizeForm = 1; htItem = 10; htGroup = 20; htClientArea = 30; dxLayoutItemControlDefaultMinHeight = 20; dxLayoutItemControlDefaultMinWidth = 20; // CM_FREEITEM = WM_DX + 25; CM_PLACECONTROLS = WM_DX + 26; type TdxCustomLayoutItem = class; TdxLayoutItem = class; TdxLayoutGroupClass = class of TdxLayoutGroup; TdxLayoutGroup = class; TdxLayoutAlignmentConstraint = class; TdxCustomLayoutControl = class; TdxCustomLayoutHitTest = class; TdxLayoutItemPainterClass = class of TdxLayoutItemPainter; TdxLayoutItemPainter = class; TdxLayoutGroupPainterClass = class of TdxLayoutGroupPainter; TdxLayoutGroupPainter = class; TdxLayoutControlPainterClass = class of TdxLayoutControlPainter; TdxLayoutControlPainter = class; TdxCustomLayoutItemElementViewInfo = class; TdxCustomLayoutItemCaptionViewInfo = class; TdxCustomLayoutItemViewInfoClass = class of TdxCustomLayoutItemViewInfo; TdxCustomLayoutItemViewInfo = class; TdxLayoutItemControlViewInfo = class; TdxLayoutItemViewInfoClass = class of TdxLayoutItemViewInfo; TdxLayoutItemViewInfo = class; TdxLayoutGroupViewInfoClass = class of TdxLayoutGroupViewInfo; TdxLayoutGroupViewInfo = class; TdxLayoutGroupStandardViewInfo = class; TdxLayoutGroupWebViewInfo = class; TdxLayoutControlViewInfoClass = class of TdxLayoutControlViewInfo; TdxLayoutControlViewInfo = class; // custom item TdxLayoutAlignHorz = (ahLeft, ahCenter, ahRight, ahClient); TdxLayoutAlignVert = (avTop, avCenter, avBottom, avClient); TdxLayoutAutoAlign = (aaHorizontal, aaVertical); TdxLayoutAutoAligns = set of TdxLayoutAutoAlign; TdxLayoutDirection = (ldHorizontal, ldVertical); TdxCustomLayoutItemOptions = class(TPersistent) private FItem: TdxCustomLayoutItem; protected procedure Changed; virtual; property Item: TdxCustomLayoutItem read FItem; public constructor Create(AItem: TdxCustomLayoutItem); virtual; end; TdxCustomLayoutItemCaptionOptionsClass = class of TdxCustomLayoutItemCaptionOptions; TdxCustomLayoutItemCaptionOptions = class(TdxCustomLayoutItemOptions) private FAlignHorz: TAlignment; FShowAccelChar: Boolean; procedure SetAlignHorz(Value: TAlignment); procedure SetShowAccelChar(Value: Boolean); public constructor Create(AItem: TdxCustomLayoutItem); override; published property AlignHorz: TAlignment read FAlignHorz write SetAlignHorz default taLeftJustify; property ShowAccelChar: Boolean read FShowAccelChar write SetShowAccelChar default True; end; TdxLayoutOffsets = class(TdxCustomLayoutItemOptions) private FBottom: Integer; FLeft: Integer; FRight: Integer; FTop: Integer; function GetValue(Index: Integer): Integer; procedure SetValue(Index: Integer; Value: Integer); published property Bottom: Integer index 1 read GetValue write SetValue default 0; property Left: Integer index 2 read GetValue write SetValue default 0; property Right: Integer index 3 read GetValue write SetValue default 0; property Top: Integer index 4 read GetValue write SetValue default 0; end; TdxCustomLayoutItemClass = class of TdxCustomLayoutItem; TdxCustomLayoutItem = class(TComponent, IdxLayoutLookAndFeelUser) private FAlignHorz: TdxLayoutAlignHorz; FAlignmentConstraint: TdxLayoutAlignmentConstraint; FAlignVert: TdxLayoutAlignVert; FAllowRemove: Boolean; FAutoAligns: TdxLayoutAutoAligns; FCachedTextHeight: Integer; FCaption: string; FCaptionOptions: TdxCustomLayoutItemCaptionOptions; FContainer: TdxCustomLayoutControl; FEnabled: Boolean; FLookAndFeel: TdxCustomLayoutLookAndFeel; FOffsets: TdxLayoutOffsets; FParent: TdxLayoutGroup; FShowCaption: Boolean; FViewInfo: TdxCustomLayoutItemViewInfo; FVisible: Boolean; FOnCaptionClick: TNotifyEvent; function GetActuallyVisible: Boolean; function GetAlignHorz: TdxLayoutAlignHorz; function GetAlignVert: TdxLayoutAlignVert; function GetCaptionForCustomizeForm: string; function GetHasMouse: Boolean; function GetIndex: Integer; function GetIsDesigning: Boolean; function GetIsDestroying: Boolean; function GetIsLoading: Boolean; function GetIsRoot: Boolean; function GetVisibleIndex: Integer; procedure SetAlignHorz(Value: TdxLayoutAlignHorz); procedure SetAlignmentConstraint(Value: TdxLayoutAlignmentConstraint); procedure SetAlignVert(Value: TdxLayoutAlignVert); procedure SetAutoAligns(Value: TdxLayoutAutoAligns); procedure SetCaption(const Value: string); procedure SetContainer(Value: TdxCustomLayoutControl); procedure SetEnabled(Value: Boolean); procedure SetLookAndFeel(Value: TdxCustomLayoutLookAndFeel); procedure SetHasMouse(Value: Boolean); procedure SetIndex(Value: Integer); procedure SetParent(Value: TdxLayoutGroup); procedure SetShowCaption(Value: Boolean); procedure SetVisible(Value: Boolean); procedure SetVisibleIndex(Value: Integer); procedure CheckActuallyVisible(APrevActuallyVisible: Boolean); function IsAlignHorzStored: Boolean; function IsAlignVertStored: Boolean; protected procedure SetName(const Value: TComponentName); override; procedure SetParentComponent(Value: TComponent); override; procedure LookAndFeelChanged; virtual; procedure LookAndFeelChanging; virtual; // IdxLayoutLookAndFeelUser procedure BeginLookAndFeelDestroying; stdcall; procedure EndLookAndFeelDestroying; stdcall; procedure IdxLayoutLookAndFeelUser.LookAndFeelChanged = LookAndFeelChangedImpl; procedure LookAndFeelChangedImpl; stdcall; procedure LookAndFeelDestroyed; stdcall; procedure ActuallyVisibleChanged; virtual; function CanProcessAccel(out AItem: TdxCustomLayoutItem): Boolean; virtual; abstract; function CanRemove: Boolean; virtual; procedure DoCaptionClick; dynamic; function DoProcessAccel: Boolean; dynamic; procedure EnabledChanged; virtual; function GetAutoAlignHorz: TdxLayoutAlignHorz; virtual; abstract; function GetAutoAlignVert: TdxLayoutAlignVert; virtual; abstract; function GetBaseName: string; virtual; function GetCursor(X, Y: Integer): TCursor; virtual; function GetEnabledForWork: Boolean; virtual; function GetLookAndFeel: TdxCustomLayoutLookAndFeel; function GetShowCaption: Boolean; virtual; function GetViewInfoClass: TdxCustomLayoutItemViewInfoClass; virtual; abstract; function GetVisible: Boolean; function HasAsParent(AGroup: TdxLayoutGroup): Boolean; function HasCaption: Boolean; virtual; procedure Init; virtual; procedure MouseEnter; dynamic; procedure MouseLeave; dynamic; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); dynamic; procedure MouseMove(Shift: TShiftState; X, Y: Integer); dynamic; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); dynamic; procedure ParentChanged(APrevParent: TdxLayoutGroup); virtual; procedure ProcessAccel; dynamic; function ProcessDialogChar(ACharCode: Word): Boolean; virtual; procedure RestoreItemControlSize; virtual; abstract; procedure SelectionChanged; virtual; procedure VisibleChanged; virtual; function GetCaptionOptionsClass: TdxCustomLayoutItemCaptionOptionsClass; virtual; procedure ResetCachedTextHeight; property CachedTextHeight: Integer read FCachedTextHeight write FCachedTextHeight; property EnabledForWork: Boolean read GetEnabledForWork; property HasMouse: Boolean read GetHasMouse write SetHasMouse; property IsDesigning: Boolean read GetIsDesigning; property IsDestroying: Boolean read GetIsDestroying; property IsLoading: Boolean read GetIsLoading; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure BeforeDestruction; override; function GetParentComponent: TComponent; override; function HasParent: Boolean; override; procedure Changed(AHardRefresh: Boolean = True); virtual; function CanMoveTo(AParent: TdxCustomLayoutItem): Boolean; virtual; procedure MakeVisible; function Move(AParent: TdxLayoutGroup; AIndex: Integer; APack: Boolean = False): Boolean; function MoveTo(AParent: TdxLayoutGroup; AVisibleIndex: Integer; APack: Boolean = False): Boolean; procedure Pack; virtual; function PutIntoHiddenGroup(ALayoutDirection: TdxLayoutDirection): TdxLayoutGroup; property ActuallyVisible: Boolean read GetActuallyVisible; property CaptionForCustomizeForm: string read GetCaptionForCustomizeForm; property Container: TdxCustomLayoutControl read FContainer write SetContainer; property Index: Integer read GetIndex write SetIndex; property IsRoot: Boolean read GetIsRoot; property Parent: TdxLayoutGroup read FParent write SetParent; property ViewInfo: TdxCustomLayoutItemViewInfo read FViewInfo; property VisibleIndex: Integer read GetVisibleIndex write SetVisibleIndex; published property AutoAligns: TdxLayoutAutoAligns read FAutoAligns write SetAutoAligns default [aaHorizontal, aaVertical]; // must be loaded before AlignHorz/Vert property AlignHorz: TdxLayoutAlignHorz read GetAlignHorz write SetAlignHorz stored IsAlignHorzStored; property AlignmentConstraint: TdxLayoutAlignmentConstraint read FAlignmentConstraint write SetAlignmentConstraint; property AlignVert: TdxLayoutAlignVert read GetAlignVert write SetAlignVert stored IsAlignVertStored; property AllowRemove: Boolean read FAllowRemove write FAllowRemove default True; property Caption: string read FCaption write SetCaption; property CaptionOptions: TdxCustomLayoutItemCaptionOptions read FCaptionOptions write FCaptionOptions; property Enabled: Boolean read FEnabled write SetEnabled default True; property LookAndFeel: TdxCustomLayoutLookAndFeel read FLookAndFeel write SetLookAndFeel; property Offsets: TdxLayoutOffsets read FOffsets write FOffsets; property ShowCaption: Boolean read GetShowCaption write SetShowCaption default True; property Visible: Boolean read FVisible write SetVisible default True; property OnCaptionClick: TNotifyEvent read FOnCaptionClick write FOnCaptionClick; end; // item TdxCustomLayoutControlAdapterClass = class of TdxCustomLayoutControlAdapter; TdxCustomLayoutControlAdapter = class private FItem: TdxLayoutItem; function GetControl: TControl; function GetLookAndFeel: TdxCustomLayoutLookAndFeel; protected function AllowCheckSize: Boolean; virtual; procedure HideControlBorder; virtual; procedure Init; virtual; function ShowBorder: Boolean; virtual; function ShowItemCaption: Boolean; virtual; function UseItemColor: Boolean; virtual; property Control: TControl read GetControl; property Item: TdxLayoutItem read FItem; property LookAndFeel: TdxCustomLayoutLookAndFeel read GetLookAndFeel; public constructor Create(AItem: TdxLayoutItem); virtual; procedure LookAndFeelChanged; virtual; class procedure Register(AControlClass: TControlClass); class procedure Unregister(AControlClass: TControlClass); end; TdxCaptionLayout = (clLeft, clTop, clRight, clBottom); TdxAlignmentVert = (tavTop, tavCenter, tavBottom); TdxLayoutItemCaptionOptions = class(TdxCustomLayoutItemCaptionOptions) private FAlignVert: TdxAlignmentVert; FLayout: TdxCaptionLayout; FWidth: Integer; procedure SetAlignVert(Value: TdxAlignmentVert); procedure SetLayout(Value: TdxCaptionLayout); procedure SetWidth(Value: Integer); published constructor Create(AItem: TdxCustomLayoutItem); override; property AlignVert: TdxAlignmentVert read FAlignVert write SetAlignVert default tavCenter; property Layout: TdxCaptionLayout read FLayout write SetLayout default clLeft; property Width: Integer read FWidth write SetWidth default 0; end; TdxLayoutItemControlOptionsClass = class of TdxLayoutItemControlOptions; TdxLayoutItemControlOptions = class(TdxCustomLayoutItemOptions) private FAutoAlignment: Boolean; FAutoColor: Boolean; FFixedSize: Boolean; FMinHeight: Integer; FMinWidth: Integer; FOpaque: Boolean; FShowBorder: Boolean; procedure SetAutoAlignment(Value: Boolean); procedure SetAutoColor(Value: Boolean); procedure SetFixedSize(Value: Boolean); procedure SetMinHeight(Value: Integer); procedure SetMinWidth(Value: Integer); procedure SetOpaque(Value: Boolean); procedure SetShowBorder(Value: Boolean); public constructor Create(AItem: TdxCustomLayoutItem); override; published property AutoAlignment: Boolean read FAutoAlignment write SetAutoAlignment default True; property AutoColor: Boolean read FAutoColor write SetAutoColor default False; property FixedSize: Boolean read FFixedSize write SetFixedSize default False; property MinHeight: Integer read FMinHeight write SetMinHeight default dxLayoutItemControlDefaultMinHeight; property MinWidth: Integer read FMinWidth write SetMinWidth default dxLayoutItemControlDefaultMinWidth; property Opaque: Boolean read FOpaque write SetOpaque default False; property ShowBorder: Boolean read FShowBorder write SetShowBorder default True; end; TdxLayoutItemClass = class of TdxLayoutItem; TdxLayoutItem = class(TdxCustomLayoutItem) private FControl: TControl; FControlAdapter: TdxCustomLayoutControlAdapter; FControlOptions: TdxLayoutItemControlOptions; FControlSizeBeforeDestruction: TPoint; FOriginalControlSize: TPoint; FPrevControlWndProc: TWndMethod; function GetCaptionOptions: TdxLayoutItemCaptionOptions; function GetViewInfo: TdxLayoutItemViewInfo; procedure SetCaptionOptions(Value: TdxLayoutItemCaptionOptions); procedure SetControl(Value: TControl); procedure CreateControlAdapter; //procedure PostFree; protected procedure ActuallyVisibleChanged; override; function CanProcessAccel(out AItem: TdxCustomLayoutItem): Boolean; override; procedure EnabledChanged; override; function GetAutoAlignHorz: TdxLayoutAlignHorz; override; function GetAutoAlignVert: TdxLayoutAlignVert; override; function GetBaseName: string; override; function GetViewInfoClass: TdxCustomLayoutItemViewInfoClass; override; function HasCaption: Boolean; override; procedure Init; override; procedure Loaded; override; procedure LookAndFeelChanged; override; //procedure Notification(AComponent: TComponent; Operation: TOperation); override; procedure ParentChanged(APrevParent: TdxLayoutGroup); override; procedure ProcessAccel; override; procedure RestoreItemControlSize; override; function GetCaptionOptionsClass: TdxCustomLayoutItemCaptionOptionsClass; override; function GetControlOptionsClass: TdxLayoutItemControlOptionsClass; virtual; function CanFocusControl: Boolean; virtual; procedure ControlWndProc(var Message: TMessage); virtual; function HasControl: Boolean; function HasWinControl: Boolean; procedure SaveControlSizeBeforeDestruction; procedure SaveOriginalControlSize; procedure SetControlEnablement; procedure SetControlVisibility; property ControlAdapter: TdxCustomLayoutControlAdapter read FControlAdapter; property ControlSizeBeforeDestruction: TPoint read FControlSizeBeforeDestruction; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; property OriginalControlSize: TPoint read FOriginalControlSize write FOriginalControlSize; property ViewInfo: TdxLayoutItemViewInfo read GetViewInfo; published property CaptionOptions: TdxLayoutItemCaptionOptions read GetCaptionOptions write SetCaptionOptions; property Control: TControl read FControl write SetControl; property ControlOptions: TdxLayoutItemControlOptions read FControlOptions write FControlOptions; end; // group TdxLayoutGroup = class(TdxCustomLayoutItem) private FHidden: Boolean; FIsPacking: Boolean; FIsUserDefined: Boolean; FItems: TList; FLayoutDirection: TdxLayoutDirection; FLocked: Boolean; FLookAndFeelException: Boolean; FShowBorder: Boolean; FUseIndent: Boolean; FVisibleItems: TList; function GetCount: Integer; function GetItem(Index: Integer): TdxCustomLayoutItem; function GetShowBorder: Boolean; function GetViewInfo: TdxLayoutGroupViewInfo; function GetVisibleCount: Integer; function GetVisibleItem(Index: Integer): TdxCustomLayoutItem; procedure SetHidden(Value: Boolean); procedure SetLayoutDirection(Value: TdxLayoutDirection); procedure SetLocked(Value: Boolean); procedure SetLookAndFeelException(Value: Boolean); procedure SetShowBorder(Value: Boolean); procedure SetUseIndent(Value: Boolean); procedure AddItem(AItem: TdxCustomLayoutItem); procedure RemoveItem(AItem: TdxCustomLayoutItem); procedure DestroyItems; protected procedure ActuallyVisibleChanged; override; function CanProcessAccel(out AItem: TdxCustomLayoutItem): Boolean; override; function CanRemove: Boolean; override; procedure EnabledChanged; override; function GetAutoAlignHorz: TdxLayoutAlignHorz; override; function GetAutoAlignVert: TdxLayoutAlignVert; override; function GetBaseName: string; override; procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override; function GetShowCaption: Boolean; override; function GetViewInfoClass: TdxCustomLayoutItemViewInfoClass; override; procedure Loaded; override; procedure LookAndFeelChanged; override; procedure LookAndFeelChanging; override; function ProcessDialogChar(ACharCode: Word): Boolean; override; procedure RestoreItemControlSize; override; procedure SelectionChanged; override; procedure SetChildOrder(Child: TComponent; Order: Integer); override; procedure SetParentComponent(Value: TComponent); override; function CanDestroy: Boolean; virtual; procedure BuildVisibleItemsList; function GetLookAndFeelAsParent: TdxCustomLayoutLookAndFeel; procedure ChangeItemIndex(AItem: TdxCustomLayoutItem; Value: Integer); procedure ChangeItemVisibleIndex(AItem: TdxCustomLayoutItem; Value: Integer); function GetItemIndex(AItemVisibleIndex: Integer): Integer; function IndexOf(AItem: TdxCustomLayoutItem): Integer; function VisibleIndexOf(AItem: TdxCustomLayoutItem): Integer; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; function CreateGroup(AGroupClass: TdxLayoutGroupClass = nil): TdxLayoutGroup; function CreateItem(AItemClass: TdxCustomLayoutItemClass = nil): TdxCustomLayoutItem; function CreateItemForControl(AControl: TControl): TdxLayoutItem; function CanMoveTo(AParent: TdxCustomLayoutItem): Boolean; override; procedure MoveChildrenToParent; procedure Pack; override; function PutChildrenIntoHiddenGroup: TdxLayoutGroup; property Count: Integer read GetCount; property Items[Index: Integer]: TdxCustomLayoutItem read GetItem; default; property IsUserDefined: Boolean read FIsUserDefined; property ViewInfo: TdxLayoutGroupViewInfo read GetViewInfo; property VisibleCount: Integer read GetVisibleCount; property VisibleItems[Index: Integer]: TdxCustomLayoutItem read GetVisibleItem; published property Hidden: Boolean read FHidden write SetHidden default False; property LayoutDirection: TdxLayoutDirection read FLayoutDirection write SetLayoutDirection default ldVertical; property Locked: Boolean read FLocked write SetLocked default False; property LookAndFeelException: Boolean read FLookAndFeelException write SetLookAndFeelException default False; property ShowBorder: Boolean read GetShowBorder write SetShowBorder default True; property UseIndent: Boolean read FUseIndent write SetUseIndent default True; end; // alignment constraint TdxLayoutAlignmentConstraintKind = (ackLeft, ackTop, ackRight, ackBottom); TdxLayoutAlignmentConstraintClass = class of TdxLayoutAlignmentConstraint; TdxLayoutAlignmentConstraint = class(TComponent) private FControl: TdxCustomLayoutControl; FItems: TList; FKind: TdxLayoutAlignmentConstraintKind; function GetCount: Integer; function GetItem(Index: Integer): TdxCustomLayoutItem; procedure SetKind(Value: TdxLayoutAlignmentConstraintKind); procedure CreateItems; procedure DestroyItems; protected procedure SetParentComponent(Value: TComponent); override; procedure BeginUpdate; function CanAddItem(AItem: TdxCustomLayoutItem): Boolean; virtual; procedure Changed; virtual; procedure EndUpdate; property Control: TdxCustomLayoutControl read FControl; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; function GetParentComponent: TComponent; override; function HasParent: Boolean; override; procedure AddItem(AItem: TdxCustomLayoutItem); procedure RemoveItem(AItem: TdxCustomLayoutItem); property Count: Integer read GetCount; property Items[Index: Integer]: TdxCustomLayoutItem read GetItem; published property Kind: TdxLayoutAlignmentConstraintKind read FKind write SetKind default ackLeft; end; { controls } TdxLayoutAreaPart = (apNone, apLeft, apTop, apRight, apBottom, apCenter, apBeforeContent, apAfterContent); TdxLayoutDragSource = (dsControl, dsCustomizeForm); TdxLayoutControlDragAndDropObject = class(TcxDragAndDropObject) private FAreaPart: TdxLayoutAreaPart; FDestItem: TdxCustomLayoutItem; FSource: TdxLayoutDragSource; FSourceItem: TdxCustomLayoutItem; FSourceItemBounds: TRect; function GetControl: TdxCustomLayoutControl; procedure SetAreaPart(Value: TdxLayoutAreaPart); procedure SetDestItem(Value: TdxCustomLayoutItem); procedure SetSourceItem(Value: TdxCustomLayoutItem); procedure HideSourceItemMark; procedure ShowSourceItemMark; protected procedure DirtyChanged; override; function GetDragAndDropCursor(Accepted: Boolean): TCursor; override; function GetCenterAreaBounds(const AItemBounds: TRect): TRect; property Control: TdxCustomLayoutControl read GetControl; property AreaPart: TdxLayoutAreaPart read FAreaPart write SetAreaPart; property DestItem: TdxCustomLayoutItem read FDestItem write SetDestItem; property Source: TdxLayoutDragSource read FSource write FSource; property SourceItemBounds: TRect read FSourceItemBounds; public destructor Destroy; override; procedure BeginDragAndDrop; override; procedure DragAndDrop(const P: TPoint; var Accepted: Boolean); override; procedure EndDragAndDrop(Accepted: Boolean); override; procedure Init(ASource: TdxLayoutDragSource; ASourceItem: TdxCustomLayoutItem); virtual; property SourceItem: TdxCustomLayoutItem read FSourceItem write SetSourceItem; end; TdxLayoutAutoContentSize = (acsWidth, acsHeight); TdxLayoutAutoContentSizes = set of TdxLayoutAutoContentSize; TdxCustomLayoutControl = class(TcxControl, IdxLayoutLookAndFeelUser, IdxLayoutComponent, IdxSkinSupport) private FAbsoluteItems: TList; FAlignmentConstraints: TList; FAutoContentSizes: TdxLayoutAutoContentSizes; FAutoControlAlignment: Boolean; FAutoControlTabOrders: Boolean; FAvailableItems: TList; FBoldFont: TFont; FCustomization: Boolean; FCustomizeForm: TCustomForm; FCustomizeFormBounds: TRect; FCustomizeFormClass: TFormClass; FDesignFormBounds: TRect; FIniFileName: string; FItems: TdxLayoutGroup; FIsPlaceControlsNeeded: Boolean; FIsPlacingControls: Boolean; FItemWithMouse: TdxCustomLayoutItem; FLeftPos: Integer; FLookAndFeel: TdxCustomLayoutLookAndFeel; FMayPack: Boolean; FPainter: TdxLayoutControlPainter; FRegistryPath: string; FRightButtonPressed: Boolean; FShowHiddenGroupsBounds: Boolean; FStoreInIniFile: Boolean; FStoreInRegistry: Boolean; FTopPos: Integer; FUpdateLockCount: Integer; FViewInfo: TdxLayoutControlViewInfo; FOnCustomization: TNotifyEvent; function GetAbsoluteItem(Index: Integer): TdxCustomLayoutItem; function GetAbsoluteItemCount: Integer; function GetAlignmentConstraint(Index: Integer): TdxLayoutAlignmentConstraint; function GetAlignmentConstraintCount: Integer; function GetAvailableItem(Index: Integer): TdxCustomLayoutItem; function GetAvailableItemCount: Integer; function GetIsCustomizationMode: Boolean; function GetContentBounds: TRect; function GetOccupiedClientWidth: Integer; function GetOccupiedClientHeight: Integer; function GetLayoutDirection: TdxLayoutDirection; procedure SetAutoContentSizes(Value: TdxLayoutAutoContentSizes); procedure SetAutoControlAlignment(Value: Boolean); procedure SetAutoControlTabOrders(Value: Boolean); procedure SetCustomization(Value: Boolean); procedure SetCustomizationModeForm(Value: TCustomForm); procedure SetIsCustomizationMode(Value: Boolean); procedure SetIsPlaceControlsNeeded(Value: Boolean); procedure SetItems(Value: TdxLayoutGroup); procedure SetItemWithMouse(Value: TdxCustomLayoutItem); procedure SetLayoutDirection(Value: TdxLayoutDirection); procedure SetLeftPos(Value: Integer); procedure SetLookAndFeel(Value: TdxCustomLayoutLookAndFeel); procedure SetShowHiddenGroupsBounds(Value: Boolean); procedure SetTopPos(Value: Integer); procedure CreateHandlers; procedure DestroyHandlers; procedure CreateConstraints; procedure DestroyConstraints; procedure AddAlignmentConstraint(AConstraint: TdxLayoutAlignmentConstraint); procedure RemoveAlignmentConstraint(AConstraint: TdxLayoutAlignmentConstraint); procedure RefreshBoldFont; procedure AddAbsoluteItem(AItem: TdxCustomLayoutItem); procedure RemoveAbsoluteItem(AItem: TdxCustomLayoutItem); procedure AddAvailableItem(AItem: TdxCustomLayoutItem); procedure RemoveAvailableItem(AItem: TdxCustomLayoutItem); procedure DestroyAvailableItems; procedure WMNCDestroy(var Message: TWMNCDestroy); message WM_NCDESTROY; {$IFNDEF DELPHI7} procedure WMPrintClient(var Message: TWMPrintClient); message WM_PRINTCLIENT; {$ENDIF} procedure CMControlChange(var Message: TCMControlChange); message CM_CONTROLCHANGE; procedure CMDialogChar(var Message: TCMDialogChar); message CM_DIALOGCHAR; //procedure CMFreeItem(var Message: TMessage); message CM_FREEITEM; procedure CMPlaceControls(var Message: TMessage); message CM_PLACECONTROLS; protected procedure AlignControls(AControl: TControl; var Rect: TRect); override; function AllowAutoDragAndDropAtDesignTime(X, Y: Integer; Shift: TShiftState): Boolean; override; function AllowDragAndDropWithoutFocus: Boolean; override; procedure BoundsChanged; override; function CanDrag(X, Y: Integer): Boolean; override; procedure CreateParams(var Params: TCreateParams); override; procedure FontChanged; override; {$IFNDEF DELPHI12} procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override; {$ENDIF} function GetCursor(X, Y: Integer): TCursor; override; function GetDesignHitTest(X, Y: Integer; Shift: TShiftState): Boolean; override; function HasBackground: Boolean; override; procedure Loaded; 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 Paint; override; procedure SetName(const Value: TComponentName); override; {$IFDEF DELPHI7} procedure SetParentBackground(Value: Boolean); override; {$ENDIF} procedure WndProc(var Message: TMessage); override; procedure WriteState(Writer: TWriter); override; procedure InitScrollBarsParameters; override; function NeedsToBringInternalControlsToFront: Boolean; override; procedure Scroll(AScrollBarKind: TScrollBarKind; AScrollCode: TScrollCode; var AScrollPos: Integer); override; function CanDragAndDrop: Boolean; function GetDragAndDropObjectClass: TcxDragAndDropObjectClass; override; function StartDragAndDrop(const P: TPoint): Boolean; override; function GetLookAndFeel: TdxCustomLayoutLookAndFeel; // IdxLayoutLookAndFeelUser procedure BeginLookAndFeelDestroying; stdcall; procedure EndLookAndFeelDestroying; stdcall; procedure LookAndFeelChanged; reintroduce; stdcall; procedure LookAndFeelDestroyed; stdcall; // IdxLayoutComponent procedure SelectionChanged; stdcall; function GetPainterClass: TdxLayoutControlPainterClass; virtual; function GetViewInfoClass: TdxLayoutControlViewInfoClass; virtual; procedure AssignItemWithMouse(X, Y: Integer); procedure AvailableItemListChanged(AItem: TdxCustomLayoutItem; AIsItemAdded: Boolean); dynamic; function CalculateCustomizeFormBounds(const AFormBounds: TRect): TRect; function CanMultiSelect: Boolean; virtual; function CanShowSelection: Boolean; virtual; procedure CheckLeftPos(var Value: Integer); procedure CheckPositions; procedure CheckTopPos(var Value: Integer); procedure DoCustomization; dynamic; procedure DragAndDropBegan; dynamic; function GetAlignmentConstraintClass: TdxLayoutAlignmentConstraintClass; dynamic; function GetDefaultGroupClass: TdxLayoutGroupClass; virtual; function GetDefaultItemClass: TdxLayoutItemClass; virtual; function IsCustomization: Boolean; function IsUpdateLocked: Boolean; procedure LayoutChanged; virtual; //procedure PostFree(AObject: TObject); procedure ScrollContent(APrevPos, ACurPos: Integer; AHorzScrolling: Boolean); procedure UpdateLookAndFeelSkinName; procedure LoadFromCustomIniFile(AIniFile: TCustomIniFile; const ARootSection: string); virtual; procedure SaveToCustomIniFile(AIniFile: TCustomIniFile; const ARootSection: string); virtual; property BoldFont: TFont read FBoldFont; property CustomizationModeForm: TCustomForm write SetCustomizationModeForm; property DesignFormBounds: TRect read FDesignFormBounds write FDesignFormBounds; property IsCustomizationMode: Boolean read GetIsCustomizationMode write SetIsCustomizationMode; property IsPlaceControlsNeeded: Boolean read FIsPlaceControlsNeeded write SetIsPlaceControlsNeeded; property ItemWithMouse: TdxCustomLayoutItem read FItemWithMouse write SetItemWithMouse; property MayPack: Boolean read FMayPack write FMayPack; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; procedure Clear; function CreateAlignmentConstraint: TdxLayoutAlignmentConstraint; function FindItem(AControl: TControl): TdxLayoutItem; overload; function FindItem(const AName: string): TdxCustomLayoutItem; overload; {$IFDEF DELPHI12} procedure GetChildren(Proc: TGetChildProc; Root: TComponent); override; {$ENDIF} function GetHitTest(const P: TPoint): TdxCustomLayoutHitTest; overload; function GetHitTest(X, Y: Integer): TdxCustomLayoutHitTest; overload; procedure BeginUpdate; procedure EndUpdate; function CreateGroup(AGroupClass: TdxLayoutGroupClass = nil; AParent: TdxLayoutGroup = nil): TdxLayoutGroup; function CreateItem(AItemClass: TdxCustomLayoutItemClass = nil; AParent: TdxLayoutGroup = nil): TdxCustomLayoutItem; function CreateItemForControl(AControl: TControl; AParent: TdxLayoutGroup = nil): TdxLayoutItem; procedure LoadFromIniFile(const AFileName: string); procedure LoadFromRegistry(const ARegistryPath: string); procedure LoadFromStream(AStream: TStream); procedure SaveToIniFile(const AFileName: string); procedure SaveToRegistry(const ARegistryPath: string); procedure SaveToStream(AStream: TStream); property AbsoluteItemCount: Integer read GetAbsoluteItemCount; property AbsoluteItems[Index: Integer]: TdxCustomLayoutItem read GetAbsoluteItem; property AlignmentConstraintCount: Integer read GetAlignmentConstraintCount; property AlignmentConstraints[Index: Integer]: TdxLayoutAlignmentConstraint read GetAlignmentConstraint; property AutoContentSizes: TdxLayoutAutoContentSizes read FAutoContentSizes write SetAutoContentSizes default []; property AutoControlAlignment: Boolean read FAutoControlAlignment write SetAutoControlAlignment default True; property AutoControlTabOrders: Boolean read FAutoControlTabOrders write SetAutoControlTabOrders default True; property AvailableItemCount: Integer read GetAvailableItemCount; property AvailableItems[Index: Integer]: TdxCustomLayoutItem read GetAvailableItem; property Customization: Boolean read FCustomization write SetCustomization; property CustomizeForm: TCustomForm read FCustomizeForm; property CustomizeFormBounds: TRect read FCustomizeFormBounds write FCustomizeFormBounds; property CustomizeFormClass: TFormClass read FCustomizeFormClass write FCustomizeFormClass; // must be descendant of TLayoutCustomizeForm property Items: TdxLayoutGroup read FItems; property IsPlacingControls: Boolean read FIsPlacingControls; property LayoutDirection: TdxLayoutDirection read GetLayoutDirection write SetLayoutDirection; property LeftPos: Integer read FLeftPos write SetLeftPos; property LookAndFeel: TdxCustomLayoutLookAndFeel read FLookAndFeel write SetLookAndFeel; property ShowHiddenGroupsBounds: Boolean read FShowHiddenGroupsBounds write SetShowHiddenGroupsBounds; property TopPos: Integer read FTopPos write SetTopPos; property ContentBounds: TRect read GetContentBounds; property OccupiedClientWidth: Integer read GetOccupiedClientWidth; property OccupiedClientHeight: Integer read GetOccupiedClientHeight; property IniFileName: string read FIniFileName write FIniFileName; property RegistryPath: string read FRegistryPath write FRegistryPath; property StoreInIniFile: Boolean read FStoreInIniFile write FStoreInIniFile default False; property StoreInRegistry: Boolean read FStoreInRegistry write FStoreInRegistry default False; property Painter: TdxLayoutControlPainter read FPainter; property ViewInfo: TdxLayoutControlViewInfo read FViewInfo; property OnCustomization: TNotifyEvent read FOnCustomization write FOnCustomization; end; TdxLayoutControl = class(TdxCustomLayoutControl) published property Align; property Anchors; {$IFDEF DELPHI6} property BevelEdges; property BevelInner; property BevelOuter; property BevelKind; property BevelWidth; property BorderWidth; {$ENDIF} property Constraints; property DragCursor; property DragKind; property DragMode; property Enabled; property FocusOnClick; property Font; {$IFDEF DELPHI7} property ParentBackground default False; {$ENDIF} property ParentFont; property ParentShowHint; property PopupMenu; property ShowHint; property TabOrder; property TabStop; property Visible; property OnClick; property OnContextPopup; property OnDblClick; property OnDragDrop; property OnDragOver; property OnEndDock; property OnEndDrag; property OnEnter; property OnExit; property OnKeyDown; property OnKeyPress; property OnKeyUp; property OnMouseDown; property OnMouseMove; property OnMouseUp; property OnMouseWheel; property OnMouseWheelDown; property OnMouseWheelUp; property OnResize; property OnStartDock; property OnStartDrag; property AutoContentSizes; property AutoControlAlignment; property AutoControlTabOrders; property IniFileName; property LayoutDirection stored False; property LookAndFeel; property RegistryPath; property StoreInIniFile; property StoreInRegistry; property OnCustomization; property OnMouseEnter; property OnMouseLeave; end; { hit tests } TdxCustomLayoutHitTestClass = class of TdxCustomLayoutHitTest; TdxCustomLayoutHitTest = class public function Cursor: TCursor; dynamic; class function HitTestCode: Integer; virtual; class function Instance: TdxCustomLayoutHitTest; end; TdxLayoutNoneHitTest = class(TdxCustomLayoutHitTest) public class function HitTestCode: Integer; override; end; TdxCustomLayoutItemHitTestClass = class of TdxCustomLayoutItemHitTest; TdxCustomLayoutItemHitTest = class(TdxCustomLayoutHitTest) private FItem: TdxCustomLayoutItem; public property Item: TdxCustomLayoutItem read FItem write FItem; end; TdxLayoutItemHitTest = class(TdxCustomLayoutItemHitTest) private function GetItem: TdxLayoutItem; procedure SetItem(Value: TdxLayoutItem); public class function HitTestCode: Integer; override; property Item: TdxLayoutItem read GetItem write SetItem; end; TdxLayoutGroupHitTest = class(TdxCustomLayoutItemHitTest) private function GetItem: TdxLayoutGroup; procedure SetItem(Value: TdxLayoutGroup); public class function HitTestCode: Integer; override; property Item: TdxLayoutGroup read GetItem write SetItem; end; TdxLayoutCustomizeFormHitTest = class(TdxCustomLayoutHitTest) public class function HitTestCode: Integer; override; end; TdxLayoutClientAreaHitTest = class(TdxCustomLayoutHitTest) private FControl: TdxCustomLayoutControl; public class function HitTestCode: Integer; override; property Control: TdxCustomLayoutControl read FControl write FControl; end; { custom handler } TdxCustomLayoutControlHandler = class private FControl: TdxCustomLayoutControl; function GetViewInfo: TdxLayoutControlViewInfo; protected property Control: TdxCustomLayoutControl read FControl; property ViewInfo: TdxLayoutControlViewInfo read GetViewInfo; public constructor Create(AControl: TdxCustomLayoutControl); virtual; end; { painters } // custom TdxCustomLayoutItemElementPainter = class private FCanvas: TcxCanvas; FViewInfo: TdxCustomLayoutItemElementViewInfo; function GetLookAndFeel: TdxCustomLayoutLookAndFeel; protected property Canvas: TcxCanvas read FCanvas; property LookAndFeel: TdxCustomLayoutLookAndFeel read GetLookAndFeel; property ViewInfo: TdxCustomLayoutItemElementViewInfo read FViewInfo; public constructor Create(ACanvas: TcxCanvas; AViewInfo: TdxCustomLayoutItemElementViewInfo); virtual; procedure Paint; virtual; abstract; end; TdxCustomLayoutItemCaptionPainterClass = class of TdxCustomLayoutItemCaptionPainter; TdxCustomLayoutItemCaptionPainter = class(TdxCustomLayoutItemElementPainter) private function GetViewInfo: TdxCustomLayoutItemCaptionViewInfo; protected procedure AfterDrawText; virtual; procedure BeforeDrawText; virtual; procedure DrawBackground; virtual; procedure DrawText; virtual; property ViewInfo: TdxCustomLayoutItemCaptionViewInfo read GetViewInfo; public procedure Paint; override; end; TdxCustomLayoutItemPainterClass = class of TdxCustomLayoutItemPainter; TdxCustomLayoutItemPainter = class private FCanvas: TcxCanvas; FViewInfo: TdxCustomLayoutItemViewInfo; function GetLookAndFeel: TdxCustomLayoutLookAndFeel; protected function GetCaptionPainterClass: TdxCustomLayoutItemCaptionPainterClass; virtual; abstract; procedure DrawCaption; virtual; procedure DrawSelection; virtual; procedure InternalDrawSelection; property Canvas: TcxCanvas read FCanvas; property LookAndFeel: TdxCustomLayoutLookAndFeel read GetLookAndFeel; property ViewInfo: TdxCustomLayoutItemViewInfo read FViewInfo; public constructor Create(ACanvas: TcxCanvas; AViewInfo: TdxCustomLayoutItemViewInfo); virtual; procedure DrawSelections; virtual; procedure Paint; virtual; end; // item TdxLayoutItemCaptionPainter = class(TdxCustomLayoutItemCaptionPainter); TdxLayoutItemControlPainterClass = class of TdxLayoutItemControlPainter; TdxLayoutItemControlPainter = class(TdxCustomLayoutItemElementPainter) private function GetViewInfo: TdxLayoutItemControlViewInfo; protected procedure DrawBorders; virtual; property ViewInfo: TdxLayoutItemControlViewInfo read GetViewInfo; public procedure Paint; override; end; TdxLayoutItemPainter = class(TdxCustomLayoutItemPainter) private function GetViewInfo: TdxLayoutItemViewInfo; protected function GetCaptionPainterClass: TdxCustomLayoutItemCaptionPainterClass; override; function GetControlPainterClass: TdxLayoutItemControlPainterClass; virtual; procedure DrawControl; virtual; property ViewInfo: TdxLayoutItemViewInfo read GetViewInfo; public procedure Paint; override; end; // group TdxLayoutGroupCaptionPainter = class(TdxCustomLayoutItemCaptionPainter); TdxLayoutGroupPainter = class(TdxCustomLayoutItemPainter) private function GetViewInfo: TdxLayoutGroupViewInfo; protected function GetCaptionPainterClass: TdxCustomLayoutItemCaptionPainterClass; override; procedure DrawBorders; virtual; procedure DrawBoundsFrame; virtual; procedure DrawItems; virtual; procedure DrawItemsArea; virtual; property ViewInfo: TdxLayoutGroupViewInfo read GetViewInfo; public procedure DrawSelections; override; procedure Paint; override; end; TdxLayoutGroupCaptionStandardPainter = class(TdxLayoutGroupCaptionPainter) protected procedure DrawText; override; end; TdxLayoutGroupStandardPainter = class(TdxLayoutGroupPainter) private function GetViewInfo: TdxLayoutGroupStandardViewInfo; protected function GetCaptionPainterClass: TdxCustomLayoutItemCaptionPainterClass; override; procedure DrawBorders; override; procedure DrawFrame; virtual; property ViewInfo: TdxLayoutGroupStandardViewInfo read GetViewInfo; end; TdxLayoutGroupOfficePainter = class(TdxLayoutGroupStandardPainter) protected function GetCaptionPainterClass: TdxCustomLayoutItemCaptionPainterClass; override; procedure DrawFrame; override; end; TdxLayoutGroupWebPainter = class(TdxLayoutGroupPainter) private function GetLookAndFeel: TdxLayoutWebLookAndFeel; function GetViewInfo: TdxLayoutGroupWebViewInfo; protected procedure DrawBorders; override; procedure DrawCaptionSeparator; virtual; procedure DrawFrame; virtual; property LookAndFeel: TdxLayoutWebLookAndFeel read GetLookAndFeel; property ViewInfo: TdxLayoutGroupWebViewInfo read GetViewInfo; end; // control TdxLayoutControlPainter = class(TdxCustomLayoutControlHandler) private FCanvas: TcxCanvas; protected function GetInternalCanvas: TcxCanvas; virtual; procedure MakeCanvasClipped(ACanvas: TcxCanvas); procedure DrawEmptyArea; virtual; procedure DrawItems; virtual; procedure PlaceControls; virtual; property InternalCanvas: TcxCanvas read GetInternalCanvas; property Canvas: TcxCanvas read FCanvas; public function GetCanvas: TcxCanvas; virtual; function GetCustomizationCanvas: TcxCanvas; procedure DrawSelections; virtual; procedure Paint; virtual; end; { view infos } // custom item TdxCustomLayoutItemElementViewInfo = class private FItemViewInfo: TdxCustomLayoutItemViewInfo; FHeight: Integer; FPressed: Boolean; FWidth: Integer; function GetHeight: Integer; function GetItem: TdxCustomLayoutItem; function GetLookAndFeel: TdxCustomLayoutLookAndFeel; function GetWidth: Integer; procedure SetHeight(Value: Integer); procedure SetWidth(Value: Integer); protected function GetEnabled: Boolean; virtual; function GetEnabledForWork: Boolean; virtual; function GetCursor(X, Y: Integer): TCursor; virtual; function GetVisible: Boolean; virtual; procedure Invalidate(const ABounds: TRect); virtual; procedure MouseEnter; dynamic; procedure MouseLeave; dynamic; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); dynamic; procedure MouseMove(Shift: TShiftState; X, Y: Integer); dynamic; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); dynamic; function WantsMouse(X, Y: Integer): Boolean; property Item: TdxCustomLayoutItem read GetItem; property ItemViewInfo: TdxCustomLayoutItemViewInfo read FItemViewInfo; property LookAndFeel: TdxCustomLayoutLookAndFeel read GetLookAndFeel; property Pressed: Boolean read FPressed write FPressed; property Visible: Boolean read GetVisible; public Bounds: TRect; constructor Create(AItemViewInfo: TdxCustomLayoutItemViewInfo); virtual; procedure Calculate(const ABounds: TRect); virtual; function CalculateHeight: Integer; virtual; abstract; function CalculateWidth: Integer; virtual; abstract; property Enabled: Boolean read GetEnabled; property EnabledForWork: Boolean read GetEnabledForWork; property Height: Integer read GetHeight write SetHeight; property Width: Integer read GetWidth write SetWidth; end; TdxCustomLayoutItemCaptionViewInfoClass = class of TdxCustomLayoutItemCaptionViewInfo; TdxCustomLayoutItemCaptionViewInfo = class(TdxCustomLayoutItemElementViewInfo) private FHotTracked: Boolean; function GetCanvas: TcxCanvas; function GetIsCustomization: Boolean; function GetTextHeight: Integer; function GetTextWidth: Integer; procedure SetHotTracked(Value: Boolean); protected function GetCursor(X, Y: Integer): TCursor; override; function GetVisible: Boolean; override; procedure MouseLeave; override; procedure MouseMove(Shift: TShiftState; X, Y: Integer); override; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); override; function CalculateTextFlags: Integer; virtual; function CanDoCaptionClick(X, Y: Integer): Boolean; virtual; function GetAlignHorz: TAlignment; virtual; function GetAlignVert: TdxAlignmentVert; virtual; abstract; function GetColor: TColor; virtual; function GetFont: TFont; virtual; function GetHotTrackBounds: TRect; virtual; function GetHotTrackStyles: TdxLayoutHotTrackStyles; virtual; function GetIsDefaultColor: Boolean; virtual; function GetIsHotTrackable: Boolean; virtual; function GetIsTextUnderlined: Boolean; virtual; function GetIsTransparent: Boolean; virtual; function GetMultiLine: Boolean; virtual; abstract; function GetOptions: TdxLayoutLookAndFeelCaptionOptions; virtual; function GetText: string; virtual; function GetTextAreaBounds: TRect; virtual; function GetTextColor: TColor; virtual; function GetTextHotColor: TColor; virtual; function GetTextNormalColor: TColor; virtual; function GetVisibleText: string; virtual; function IsPointInHotTrackBounds(const P: TPoint): Boolean; virtual; procedure PrepareCanvas; virtual; property AlignHorz: TAlignment read GetAlignHorz; property AlignVert: TdxAlignmentVert read GetAlignVert; property Canvas: TcxCanvas read GetCanvas; property HotTrackBounds: TRect read GetHotTrackBounds; property HotTrackStyles: TdxLayoutHotTrackStyles read GetHotTrackStyles; property IsCustomization: Boolean read GetIsCustomization; property IsDefaultColor: Boolean read GetIsDefaultColor; property IsHotTrackable: Boolean read GetIsHotTrackable; property IsTransparent: Boolean read GetIsTransparent; property MultiLine: Boolean read GetMultiLine; property Options: TdxLayoutLookAndFeelCaptionOptions read GetOptions; property TextHeight: Integer read GetTextHeight; property TextWidth: Integer read GetTextWidth; public function CalculateHeight: Integer; override; function CalculateWidth: Integer; override; property Color: TColor read GetColor; property Font: TFont read GetFont; property HotTracked: Boolean read FHotTracked write SetHotTracked; property IsTextUnderlined: Boolean read GetIsTextUnderlined; property Text: string read GetText; property TextAreaBounds: TRect read GetTextAreaBounds; property TextColor: TColor read GetTextColor; property VisibleText: string read GetVisibleText; end; TdxCustomLayoutItemViewInfo = class private FCaptionViewInfo: TdxCustomLayoutItemCaptionViewInfo; FContainerViewInfo: TdxLayoutControlViewInfo; FElementWithMouse: TdxCustomLayoutItemElementViewInfo; FItem: TdxCustomLayoutItem; FOffsets: array[TdxLayoutSide] of Integer; FParentViewInfo: TdxLayoutGroupViewInfo; function GetAlignHorz: TdxLayoutAlignHorz; function GetAlignVert: TdxLayoutAlignVert; function GetIsCustomization: Boolean; function GetIsParentLocked: Boolean; function GetLookAndFeel: TdxCustomLayoutLookAndFeel; function GetMinHeight: Integer; function GetMinWidth: Integer; function GetOffset(ASide: TdxLayoutSide): Integer; function GetOffsetsHeight: Integer; function GetOffsetsWidth: Integer; function GetSelected: Boolean; procedure SetElementWithMouse(Value: TdxCustomLayoutItemElementViewInfo); procedure SetOffset(ASide: TdxLayoutSide; Value: Integer); protected procedure CreateViewInfos; virtual; procedure DestroyViewInfos; virtual; function GetCaptionViewInfoClass: TdxCustomLayoutItemCaptionViewInfoClass; virtual; abstract; function GetHitTestClass: TdxCustomLayoutItemHitTestClass; virtual; abstract; function GetPainterClass: TdxCustomLayoutItemPainterClass; virtual; abstract; function CalculateMinHeight: Integer; function CalculateMinWidth: Integer; function CalculateOffset(ASide: TdxLayoutSide): Integer; virtual; function DoCalculateHeight(AIsMinHeight: Boolean = False): Integer; virtual; function DoCalculateWidth(AIsMinWidth: Boolean = False): Integer; virtual; function GetColor: TColor; virtual; abstract; function GetCursor(X, Y: Integer): TCursor; virtual; function GetElement(Index: Integer): TdxCustomLayoutItemElementViewInfo; virtual; function GetElementCount: Integer; virtual; function GetEnabled: Boolean; virtual; function GetEnabledForWork: Boolean; virtual; function GetIsDefaultColor: Boolean; virtual; abstract; function GetIsTransparent: Boolean; virtual; function GetOptions: TdxCustomLayoutLookAndFeelOptions; virtual; abstract; function GetSelectionAreaBounds(Index: Integer): TRect; virtual; function GetSelectionAreaCount: Integer; virtual; function HasCaption: Boolean; virtual; procedure MouseEnter; dynamic; procedure MouseLeave; dynamic; procedure MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); dynamic; procedure MouseMove(Shift: TShiftState; X, Y: Integer); dynamic; procedure MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); dynamic; property ContainerViewInfo: TdxLayoutControlViewInfo read FContainerViewInfo; property ElementCount: Integer read GetElementCount; property Elements[Index: Integer]: TdxCustomLayoutItemElementViewInfo read GetElement; property ElementWithMouse: TdxCustomLayoutItemElementViewInfo read FElementWithMouse write SetElementWithMouse; property IsCustomization: Boolean read GetIsCustomization; property IsDefaultColor: Boolean read GetIsDefaultColor; property IsParentLocked: Boolean read GetIsParentLocked; property IsTransparent: Boolean read GetIsTransparent; property Item: TdxCustomLayoutItem read FItem; property LookAndFeel: TdxCustomLayoutLookAndFeel read GetLookAndFeel; property OffsetsHeight: Integer read GetOffsetsHeight; property OffsetsWidth: Integer read GetOffsetsWidth; property Options: TdxCustomLayoutLookAndFeelOptions read GetOptions; property ParentViewInfo: TdxLayoutGroupViewInfo read FParentViewInfo; public Bounds: TRect; constructor Create(AContainerViewInfo: TdxLayoutControlViewInfo; AParentViewInfo: TdxLayoutGroupViewInfo; AItem: TdxCustomLayoutItem); virtual; destructor Destroy; override; procedure Calculate(const ABounds: TRect); virtual; function CalculateHeight: Integer; function CalculateWidth: Integer; procedure CalculateTabOrders(var AAvailTabOrder: Integer); virtual; abstract; function GetHitTest(const P: TPoint): TdxCustomLayoutHitTest; virtual; procedure ResetOffset(ASide: TdxLayoutSide); property AlignHorz: TdxLayoutAlignHorz read GetAlignHorz; property AlignVert: TdxLayoutAlignVert read GetAlignVert; property CaptionViewInfo: TdxCustomLayoutItemCaptionViewInfo read FCaptionViewInfo; property Color: TColor read GetColor; property Enabled: Boolean read GetEnabled; property EnabledForWork: Boolean read GetEnabledForWork; property MinWidth: Integer read GetMinWidth; property MinHeight: Integer read GetMinHeight; property Offsets[ASide: TdxLayoutSide]: Integer read GetOffset write SetOffset; property Selected: Boolean read GetSelected; property SelectionAreaBounds[Index: Integer]: TRect read GetSelectionAreaBounds; property SelectionAreaCount: Integer read GetSelectionAreaCount; end; // item TdxLayoutItemCaptionViewInfo = class(TdxCustomLayoutItemCaptionViewInfo) private function GetItem: TdxLayoutItem; function GetItemViewInfo: TdxLayoutItemViewInfo; protected function GetAlignVert: TdxAlignmentVert; override; function GetIsFixedWidth: Boolean; virtual; function GetMinWidth: Integer; virtual; function GetMultiLine: Boolean; override; function GetTextAreaBounds: TRect; override; property IsFixedWidth: Boolean read GetIsFixedWidth; property Item: TdxLayoutItem read GetItem; property ItemViewInfo: TdxLayoutItemViewInfo read GetItemViewInfo; public function CalculateWidth: Integer; override; property MinWidth: Integer read GetMinWidth; end; TdxLayoutItemControlViewInfoClass = class of TdxLayoutItemControlViewInfo; TdxLayoutItemControlViewInfo = class(TdxCustomLayoutItemElementViewInfo) private FControlBounds: TRect; function GetBorderColor: TColor; function GetBorderStyle: TdxLayoutBorderStyle; function GetControl: TControl; function GetHasBorder: Boolean; function GetItem: TdxLayoutItem; function GetItemViewInfo: TdxLayoutItemViewInfo; function GetOpaqueControl: Boolean; protected function GetVisible: Boolean; override; function CalculateControlBounds: TRect; virtual; function GetBorderWidth(ASide: TdxLayoutSide): Integer; virtual; function GetHeight(AControlHeight: Integer): Integer; virtual; function GetWidth(AControlWidth: Integer): Integer; virtual; property BorderWidths[ASide: TdxLayoutSide]: Integer read GetBorderWidth; property Item: TdxLayoutItem read GetItem; property ItemViewInfo: TdxLayoutItemViewInfo read GetItemViewInfo; public procedure Calculate(const ABounds: TRect); override; function CalculateHeight: Integer; override; function CalculateWidth: Integer; override; function CalculateMinHeight: Integer; virtual; function CalculateMinWidth: Integer; virtual; procedure CalculateTabOrder(var AAvailTabOrder: Integer); virtual; property BorderColor: TColor read GetBorderColor; property BorderStyle: TdxLayoutBorderStyle read GetBorderStyle; property Control: TControl read GetControl; property ControlBounds: TRect read FControlBounds; property HasBorder: Boolean read GetHasBorder; property OpaqueControl: Boolean read GetOpaqueControl; end; TdxLayoutItemViewInfo = class(TdxCustomLayoutItemViewInfo) private FControlViewInfo: TdxLayoutItemControlViewInfo; function GetCaptionViewInfo: TdxLayoutItemCaptionViewInfo; function GetItem: TdxLayoutItem; function GetOptionsEx: TdxLayoutLookAndFeelItemOptions; protected procedure CreateViewInfos; override; procedure DestroyViewInfos; override; function GetCaptionViewInfoClass: TdxCustomLayoutItemCaptionViewInfoClass; override; function GetControlViewInfoClass: TdxLayoutItemControlViewInfoClass; virtual; function GetHitTestClass: TdxCustomLayoutItemHitTestClass; override; function GetPainterClass: TdxCustomLayoutItemPainterClass; override; procedure CalculateViewInfosBounds(var ACaptionBounds, AControlBounds: TRect); virtual; function DoCalculateHeight(AIsMinHeight: Boolean = False): Integer; override; function DoCalculateWidth(AIsMinWidth: Boolean = False): Integer; override; function GetAutoControlAlignment: Boolean; virtual; function GetCaptionLayout: TdxCaptionLayout; virtual; function GetColor: TColor; override; function GetContentBounds: TRect; virtual; function GetControlOffsetHorz: Integer; virtual; function GetControlOffsetVert: Integer; virtual; function GetElement(Index: Integer): TdxCustomLayoutItemElementViewInfo; override; function GetElementCount: Integer; override; function GetIsDefaultColor: Boolean; override; function GetOptions: TdxCustomLayoutLookAndFeelOptions; override; function HasControl: Boolean; virtual; property ControlOffsetHorz: Integer read GetControlOffsetHorz; property ControlOffsetVert: Integer read GetControlOffsetVert; property Item: TdxLayoutItem read GetItem; property Options: TdxLayoutLookAndFeelItemOptions read GetOptionsEx; public procedure Calculate(const ABounds: TRect); override; procedure CalculateTabOrders(var AAvailTabOrder: Integer); override; property AutoControlAlignment: Boolean read GetAutoControlAlignment; property CaptionLayout: TdxCaptionLayout read GetCaptionLayout; property CaptionViewInfo: TdxLayoutItemCaptionViewInfo read GetCaptionViewInfo; property ContentBounds: TRect read GetContentBounds; property ControlViewInfo: TdxLayoutItemControlViewInfo read FControlViewInfo; end; // group TdxLayoutGroupCaptionViewInfo = class(TdxCustomLayoutItemCaptionViewInfo) protected function GetAlignVert: TdxAlignmentVert; override; function GetMultiLine: Boolean; override; function GetMinWidth: Integer; virtual; public property MinWidth: Integer read GetMinWidth; end; TdxLayoutGroupViewInfoGetItemSizeEvent = function(AViewInfo: TdxCustomLayoutItemViewInfo): Integer of object; TdxLayoutGroupViewInfoSpecificClass = class of TdxLayoutGroupViewInfoSpecific; TdxLayoutGroupViewInfoSpecific = class private FGroupViewInfo: TdxLayoutGroupViewInfo; function GetItemOffset: Integer; function GetItemViewInfo(Index: Integer): TdxCustomLayoutItemViewInfo; function GetItemViewInfoCount: Integer; function GetLayoutDirection: TdxLayoutDirection; protected function DoCalculateHeight: Integer; function DoCalculateWidth: Integer; function DoCalculateMinHeight: Integer; function DoCalculateMinWidth: Integer; function GetCustomHeight(AGetItemCustomHeight: TdxLayoutGroupViewInfoGetItemSizeEvent): Integer; function GetCustomWidth(AGetItemCustomWidth: TdxLayoutGroupViewInfoGetItemSizeEvent): Integer; procedure ConvertCoords(var R: TRect); virtual; function GetItemAlignHorz(AViewInfo: TdxCustomLayoutItemViewInfo): TdxLayoutAlignHorz; virtual; abstract; function GetItemAlignVert(AViewInfo: TdxCustomLayoutItemViewInfo): TdxLayoutAlignVert; virtual; abstract; function GetItemHeight(AViewInfo: TdxCustomLayoutItemViewInfo): Integer; virtual; abstract; function GetItemMinHeight(AViewInfo: TdxCustomLayoutItemViewInfo): Integer; virtual; abstract; function GetItemMinWidth(AViewInfo: TdxCustomLayoutItemViewInfo): Integer; virtual; abstract; function GetItemWidth(AViewInfo: TdxCustomLayoutItemViewInfo): Integer; virtual; abstract; property GroupViewInfo: TdxLayoutGroupViewInfo read FGroupViewInfo; property ItemOffset: Integer read GetItemOffset; property ItemViewInfoCount: Integer read GetItemViewInfoCount; property ItemViewInfos[Index: Integer]: TdxCustomLayoutItemViewInfo read GetItemViewInfo; property LayoutDirection: TdxLayoutDirection read GetLayoutDirection; public constructor Create(AGroupViewInfo: TdxLayoutGroupViewInfo); virtual; procedure CalculateItemsBounds(AItemsAreaBounds: TRect); function CalculateHeight(AIsMinHeight: Boolean = False): Integer; virtual; function CalculateWidth(AIsMinWidth: Boolean = False): Integer; virtual; function IsAtInsertionPos(const R: TRect; const P: TPoint): Boolean; virtual; abstract; end; TdxLayoutGroupViewInfoHorizontalSpecific = class(TdxLayoutGroupViewInfoSpecific) protected function GetItemAlignHorz(AViewInfo: TdxCustomLayoutItemViewInfo): TdxLayoutAlignHorz; override; function GetItemAlignVert(AViewInfo: TdxCustomLayoutItemViewInfo): TdxLayoutAlignVert; override; function GetItemHeight(AViewInfo: TdxCustomLayoutItemViewInfo): Integer; override; function GetItemMinHeight(AViewInfo: TdxCustomLayoutItemViewInfo): Integer; override; function GetItemMinWidth(AViewInfo: TdxCustomLayoutItemViewInfo): Integer; override; function GetItemWidth(AViewInfo: TdxCustomLayoutItemViewInfo): Integer; override; public function IsAtInsertionPos(const R: TRect; const P: TPoint): Boolean; override; end; TdxLayoutGroupViewInfoVerticalSpecific = class(TdxLayoutGroupViewInfoSpecific) protected procedure ConvertCoords(var R: TRect); override; function GetItemAlignHorz(AViewInfo: TdxCustomLayoutItemViewInfo): TdxLayoutAlignHorz; override; function GetItemAlignVert(AViewInfo: TdxCustomLayoutItemViewInfo): TdxLayoutAlignVert; override; function GetItemHeight(AViewInfo: TdxCustomLayoutItemViewInfo): Integer; override; function GetItemMinHeight(AViewInfo: TdxCustomLayoutItemViewInfo): Integer; override; function GetItemMinWidth(AViewInfo: TdxCustomLayoutItemViewInfo): Integer; override; function GetItemWidth(AViewInfo: TdxCustomLayoutItemViewInfo): Integer; override; public function CalculateHeight(AIsMinHeight: Boolean = False): Integer; override; function CalculateWidth(AIsMinWidth: Boolean = False): Integer; override; function IsAtInsertionPos(const R: TRect; const P: TPoint): Boolean; override; end; TdxLayoutGroupViewInfo = class(TdxCustomLayoutItemViewInfo) private FConstsCalculated: Boolean; FItemOffset: Integer; FItemsAreaBounds: TRect; FItemsAreaOffsetHorz: Integer; FItemsAreaOffsetVert: Integer; FItemViewInfos: TList; FSpecific: TdxLayoutGroupViewInfoSpecific; function GetBorderBounds(ASide: TdxLayoutSide): TRect; function GetBorderRestSpaceBounds(ASide: TdxLayoutSide): TRect; function GetBordersHeight: Integer; function GetBordersWidth: Integer; function GetCaptionViewInfo: TdxLayoutGroupCaptionViewInfo; function GetGroup: TdxLayoutGroup; function GetIsLocked: Boolean; function GetItemViewInfo(Index: Integer): TdxCustomLayoutItemViewInfo; function GetItemViewInfoCount: Integer; function GetLayoutDirection: TdxLayoutDirection; function GetOptionsEx: TdxLayoutLookAndFeelGroupOptions; procedure CreateItemViewInfos; procedure CreateSpecific; procedure DestroyItemViewInfos; procedure DestroySpecific; protected function GetCaptionViewInfoClass: TdxCustomLayoutItemCaptionViewInfoClass; override; function GetHitTestClass: TdxCustomLayoutItemHitTestClass; override; function GetPainterClass: TdxCustomLayoutItemPainterClass; override; function DoCalculateHeight(AIsMinHeight: Boolean = False): Integer; override; function DoCalculateWidth(AIsMinWidth: Boolean = False): Integer; override; function CalculateCaptionViewInfoBounds: TRect; virtual; function CalculateItemsAreaBounds: TRect; virtual; procedure CalculateConsts; virtual; function GetBorderWidth(ASide: TdxLayoutSide): Integer; virtual; function GetClientBounds: TRect; virtual; function GetColor: TColor; override; function GetConst(Index: Integer): Integer; virtual; function GetHeight(AItemsAreaHeight: Integer): Integer; virtual; function GetIsDefaultColor: Boolean; override; function GetItemViewInfoClass(AItem: TdxCustomLayoutItem): TdxCustomLayoutItemViewInfoClass; virtual; function GetMinVisibleWidth: Integer; virtual; function GetOptions: TdxCustomLayoutLookAndFeelOptions; override; function GetRestSpaceBounds: TRect; virtual; function GetSpecificClass: TdxLayoutGroupViewInfoSpecificClass; virtual; function GetWidth(AItemsAreaWidth: Integer): Integer; virtual; function HasBorder: Boolean; virtual; function HasBoundsFrame: Boolean; virtual; function UseItemOffset: Boolean; virtual; function UseItemsAreaOffsets: Boolean; virtual; property ItemOffset: Integer index 2 read GetConst write FItemOffset; property ItemsAreaOffsetHorz: Integer index 3 read GetConst write FItemsAreaOffsetHorz; property ItemsAreaOffsetVert: Integer index 4 read GetConst write FItemsAreaOffsetVert; property MinVisibleWidth: Integer read GetMinVisibleWidth; property RestSpaceBounds: TRect read GetRestSpaceBounds; property Group: TdxLayoutGroup read GetGroup; property LayoutDirection: TdxLayoutDirection read GetLayoutDirection; property Options: TdxLayoutLookAndFeelGroupOptions read GetOptionsEx; property Specific: TdxLayoutGroupViewInfoSpecific read FSpecific; public constructor Create(AControlViewInfo: TdxLayoutControlViewInfo; AParentViewInfo: TdxLayoutGroupViewInfo; AItem: TdxCustomLayoutItem); override; destructor Destroy; override; procedure Calculate(const ABounds: TRect); override; procedure CalculateTabOrders(var AAvailTabOrder: Integer); override; function GetHitTest(const P: TPoint): TdxCustomLayoutHitTest; override; function GetInsertionPos(const P: TPoint): Integer; virtual; property BorderBounds[ASide: TdxLayoutSide]: TRect read GetBorderBounds; property BorderRestSpaceBounds[ASide: TdxLayoutSide]: TRect read GetBorderRestSpaceBounds; property BorderWidths[ASide: TdxLayoutSide]: Integer read GetBorderWidth; property BordersHeight: Integer read GetBordersHeight; property BordersWidth: Integer read GetBordersWidth; property CaptionViewInfo: TdxLayoutGroupCaptionViewInfo read GetCaptionViewInfo; property ClientBounds: TRect read GetClientBounds; property IsLocked: Boolean read GetIsLocked; property ItemsAreaBounds: TRect read FItemsAreaBounds; property ItemViewInfoCount: Integer read GetItemViewInfoCount; property ItemViewInfos[Index: Integer]: TdxCustomLayoutItemViewInfo read GetItemViewInfo; end; // standard TdxLayoutGroupStandardCaptionViewInfo = class(TdxLayoutGroupCaptionViewInfo) private function GetItemViewInfo: TdxLayoutGroupStandardViewInfo; protected function GetAlignHorz: TAlignment; override; property ItemViewInfo: TdxLayoutGroupStandardViewInfo read GetItemViewInfo; public function CalculateWidth: Integer; override; end; TdxLayoutGroupStandardViewInfo = class(TdxLayoutGroupViewInfo) private function GetLookAndFeel: TdxLayoutStandardLookAndFeel; protected function CalculateCaptionViewInfoBounds: TRect; override; function GetCaptionViewInfoClass: TdxCustomLayoutItemCaptionViewInfoClass; override; function GetMinVisibleWidth: Integer; override; function GetCaptionViewInfoOffset: Integer; virtual; function GetFrameBounds: TRect; virtual; property CaptionViewInfoOffset: Integer read GetCaptionViewInfoOffset; property LookAndFeel: TdxLayoutStandardLookAndFeel read GetLookAndFeel; public property FrameBounds: TRect read GetFrameBounds; end; // office TdxLayoutGroupOfficeCaptionViewInfo = class(TdxLayoutGroupCaptionViewInfo) public function CalculateWidth: Integer; override; end; TdxLayoutGroupOfficeViewInfo = class(TdxLayoutGroupStandardViewInfo) protected function GetCaptionViewInfoClass: TdxCustomLayoutItemCaptionViewInfoClass; override; function GetCaptionViewInfoOffset: Integer; override; function GetFrameBounds: TRect; override; function GetMinVisibleWidth: Integer; override; end; // web TdxLayoutGroupWebCaptionViewInfo = class(TdxLayoutGroupCaptionViewInfo) private function GetItemViewInfo: TdxLayoutGroupWebViewInfo; function GetLookAndFeel: TdxLayoutWebLookAndFeel; function GetOptionsEx: TdxLayoutWebLookAndFeelGroupCaptionOptions; function GetSeparatorWidth: Integer; protected function GetAlignVert: TdxAlignmentVert; override; function GetColor: TColor; override; function GetIsDefaultColor: Boolean; override; function GetMinWidth: Integer; override; function GetTextAreaBounds: TRect; override; function GetTextOffset: Integer; virtual; property ItemViewInfo: TdxLayoutGroupWebViewInfo read GetItemViewInfo; property LookAndFeel: TdxLayoutWebLookAndFeel read GetLookAndFeel; property Options: TdxLayoutWebLookAndFeelGroupCaptionOptions read GetOptionsEx; property TextOffset: Integer read GetTextOffset; public function CalculateHeight: Integer; override; property SeparatorWidth: Integer read GetSeparatorWidth; end; TdxLayoutGroupWebViewInfo = class(TdxLayoutGroupViewInfo) private function GetCaptionViewInfo: TdxLayoutGroupWebCaptionViewInfo; function GetInsideFrameBounds: TRect; function GetLookAndFeel: TdxLayoutWebLookAndFeel; function GetOptionsEx: TdxLayoutWebLookAndFeelGroupOptions; protected function CalculateCaptionViewInfoBounds: TRect; override; function GetCaptionViewInfoClass: TdxCustomLayoutItemCaptionViewInfoClass; override; function GetMinVisibleWidth: Integer; override; function GetRestSpaceBounds: TRect; override; function GetCaptionSeparatorAreaBounds: TRect; virtual; function GetCaptionSeparatorBounds: TRect; virtual; property LookAndFeel: TdxLayoutWebLookAndFeel read GetLookAndFeel; property InsideFrameBounds: TRect read GetInsideFrameBounds; property Options: TdxLayoutWebLookAndFeelGroupOptions read GetOptionsEx; public property CaptionSeparatorAreaBounds: TRect read GetCaptionSeparatorAreaBounds; property CaptionSeparatorBounds: TRect read GetCaptionSeparatorBounds; property CaptionViewInfo: TdxLayoutGroupWebCaptionViewInfo read GetCaptionViewInfo; end; // control TdxLayoutControlViewInfo = class(TdxCustomLayoutControlHandler) private FCanvas: TcxCanvas; FContentBounds: TRect; FHideHiddenGroupsFromHitTest: Boolean; FItemsViewInfo: TdxLayoutGroupViewInfo; function GetClientHeight: Integer; function GetClientWidth: Integer; function GetContentHeight: Integer; function GetContentWidth: Integer; function GetLookAndFeel: TdxCustomLayoutLookAndFeel; protected procedure CreateViewInfos; virtual; procedure DestroyViewInfos; virtual; function GetItemsViewInfoClass: TdxLayoutGroupViewInfoClass; virtual; procedure RecreateViewInfos; procedure AlignItems; virtual; procedure AutoAlignControls; virtual; procedure CalculateItemsViewInfo; virtual; procedure CalculateTabOrders; virtual; function GetIsTransparent: Boolean; virtual; function HasBackground: Boolean; procedure PrepareData; virtual; procedure ResetContentBounds; function GetCanvas: TcxCanvas; virtual; function GetClientBounds: TRect; virtual; function GetContentBounds: TRect; virtual; property Canvas: TcxCanvas read GetCanvas; property IsTransparent: Boolean read GetIsTransparent; public constructor Create(AControl: TdxCustomLayoutControl); override; destructor Destroy; override; procedure Calculate; virtual; procedure DoCalculateTabOrders; virtual; function GetHitTest(const P: TPoint): TdxCustomLayoutHitTest; overload; virtual; function GetHitTest(X, Y: Integer): TdxCustomLayoutHitTest; overload; property ClientBounds: TRect read GetClientBounds; property ClientHeight: Integer read GetClientHeight; property ClientWidth: Integer read GetClientWidth; property ContentBounds: TRect read GetContentBounds; property ContentHeight: Integer read GetContentHeight; property ContentWidth: Integer read GetContentWidth; property HideHiddenGroupsFromHitTest: Boolean read FHideHiddenGroupsFromHitTest write FHideHiddenGroupsFromHitTest; property ItemsViewInfo: TdxLayoutGroupViewInfo read FItemsViewInfo; property LookAndFeel: TdxCustomLayoutLookAndFeel read GetLookAndFeel; end; { other } TdxLayoutCustomizeListBox = class(TcxCustomizeListBox) private FControl: TdxCustomLayoutControl; function GetDragAndDropItemObject: TdxCustomLayoutItem; protected procedure BeginDragAndDrop; override; property DragAndDropItemObject: TdxCustomLayoutItem read GetDragAndDropItemObject; public property Control: TdxCustomLayoutControl read FControl write FControl; end; implementation {$R *.res} uses TypInfo, Menus, Registry, {$IFDEF DELPHI6} Variants, {$ENDIF} {$IFDEF DELPHI7} UxTheme, Themes, {$ENDIF} dxLayoutControlAdapters, dxLayoutCustomizeForm; const ScrollStep = 10; type TControlAccess = class(TControl); TLookAndFeelAccess = class(TdxCustomLayoutLookAndFeel); resourcestring sContainerCannotBeControl = 'Container cannot be a control for its item.'; sControlIsUsed = 'The %s control is already used by %s item.'; function GetOrthogonalDirection(ADirection: TdxLayoutDirection): TdxLayoutDirection; begin if ADirection = ldHorizontal then Result := ldVertical else Result := ldHorizontal; end; { TCustomizationCanvas } type TCustomizationCanvas = class(TCanvas) private FControl: TcxControl; procedure FreeHandle; protected procedure CreateHandle; override; public constructor Create(AControl: TcxControl); reintroduce; destructor Destroy; override; end; constructor TCustomizationCanvas.Create(AControl: TcxControl); begin inherited Create; FControl := AControl; end; destructor TCustomizationCanvas.Destroy; begin FreeHandle; inherited; end; procedure TCustomizationCanvas.FreeHandle; begin ReleaseDC(FControl.Handle, Handle); Handle := 0; end; procedure TCustomizationCanvas.CreateHandle; begin Handle := GetDCEx(FControl.Handle, 0, DCX_CACHE or DCX_CLIPSIBLINGS); end; { TcxCustomizationCanvas } type TcxCustomizationCanvas = class(TcxCanvas) public constructor Create(AControl: TcxControl); reintroduce; destructor Destroy; override; end; constructor TcxCustomizationCanvas.Create(AControl: TcxControl); begin inherited Create(TCustomizationCanvas.Create(AControl)); end; destructor TcxCustomizationCanvas.Destroy; begin Canvas.Free; inherited; end; { TdxCustomLayoutItemOptions } constructor TdxCustomLayoutItemOptions.Create(AItem: TdxCustomLayoutItem); begin inherited Create; FItem := AItem; end; procedure TdxCustomLayoutItemOptions.Changed; begin FItem.Changed; end; { TdxCustomLayoutItemCaptionOptions } constructor TdxCustomLayoutItemCaptionOptions.Create(AItem: TdxCustomLayoutItem); begin inherited; FShowAccelChar := True; end; procedure TdxCustomLayoutItemCaptionOptions.SetAlignHorz(Value: TAlignment); begin if FAlignHorz <> Value then begin FAlignHorz := Value; Changed; end; end; procedure TdxCustomLayoutItemCaptionOptions.SetShowAccelChar(Value: Boolean); begin if FShowAccelChar <> Value then begin FShowAccelChar := Value; Changed; end; end; { TdxLayoutOffsets } function TdxLayoutOffsets.GetValue(Index: Integer): Integer; begin case Index of 1: Result := FBottom; 2: Result := FLeft; 3: Result := FRight; 4: Result := FTop; else Result := 0; end; end; procedure TdxLayoutOffsets.SetValue(Index: Integer; Value: Integer); begin if Value < 0 then Value := 0; if GetValue(Index) <> Value then begin case Index of 1: FBottom := Value; 2: FLeft := Value; 3: FRight := Value; 4: FTop := Value; end; Changed; end; end; { TdxCustomLayoutItem } constructor TdxCustomLayoutItem.Create(AOwner: TComponent); begin inherited; FAllowRemove := True; FAutoAligns := [aaHorizontal, aaVertical]; FCaptionOptions := GetCaptionOptionsClass.Create(Self); FEnabled := True; FOffsets := TdxLayoutOffsets.Create(Self); FShowCaption := True; FVisible := True; end; destructor TdxCustomLayoutItem.Destroy; begin HasMouse := False; Parent := nil; FContainer.RemoveAvailableItem(Self); FContainer.RemoveAbsoluteItem(Self); LookAndFeel := nil; FOffsets.Free; FCaptionOptions.Free; inherited; end; function TdxCustomLayoutItem.GetActuallyVisible: Boolean; begin Result := GetVisible and (IsRoot or (FParent <> nil) and FParent.ActuallyVisible); end; function TdxCustomLayoutItem.GetAlignHorz: TdxLayoutAlignHorz; begin if aaHorizontal in FAutoAligns then Result := GetAutoAlignHorz else Result := FAlignHorz; end; function TdxCustomLayoutItem.GetAlignVert: TdxLayoutAlignVert; begin if aaVertical in FAutoAligns then Result := GetAutoAlignVert else Result := FAlignVert; end; function TdxCustomLayoutItem.GetCaptionForCustomizeForm: string; begin Result := StripHotKey(FCaption); end; function TdxCustomLayoutItem.GetHasMouse: Boolean; begin Result := FContainer.ItemWithMouse = Self; end; function TdxCustomLayoutItem.GetIndex: Integer; begin if FParent = nil then Result := -1 else Result := FParent.IndexOf(Self); end; function TdxCustomLayoutItem.GetIsDesigning: Boolean; begin Result := csDesigning in ComponentState; end; function TdxCustomLayoutItem.GetIsDestroying: Boolean; begin Result := csDestroying in ComponentState; end; function TdxCustomLayoutItem.GetIsLoading: Boolean; begin Result := csLoading in ComponentState; end; function TdxCustomLayoutItem.GetIsRoot: Boolean; begin Result := (FContainer <> nil) and (FContainer.Items = Self); end; function TdxCustomLayoutItem.GetVisibleIndex: Integer; begin if FParent = nil then Result := -1 else Result := FParent.VisibleIndexOf(Self); end; procedure TdxCustomLayoutItem.SetAlignHorz(Value: TdxLayoutAlignHorz); begin if AlignHorz <> Value then begin FAlignHorz := Value; Exclude(FAutoAligns, aaHorizontal); Changed; end; end; procedure TdxCustomLayoutItem.SetAlignmentConstraint(Value: TdxLayoutAlignmentConstraint); begin if FAlignmentConstraint <> Value then begin if FAlignmentConstraint <> nil then FAlignmentConstraint.RemoveItem(Self); if Value <> nil then Value.AddItem(Self); end; end; procedure TdxCustomLayoutItem.SetAlignVert(Value: TdxLayoutAlignVert); begin if AlignVert <> Value then begin FAlignVert := Value; Exclude(FAutoAligns, aaVertical); Changed; end; end; procedure TdxCustomLayoutItem.SetAutoAligns(Value: TdxLayoutAutoAligns); begin if FAutoAligns <> Value then begin FAutoAligns := Value; Changed; end; end; procedure TdxCustomLayoutItem.SetCaption(const Value: string); begin if FCaption <> Value then begin FCaption := Value; ResetCachedTextHeight; Changed; end; end; procedure TdxCustomLayoutItem.SetContainer(Value: TdxCustomLayoutControl); begin if FContainer <> Value then begin if not IsRoot and (FContainer <> nil) then FContainer.RemoveAbsoluteItem(Self); FContainer := Value; if not IsRoot then begin if FContainer <> nil then FContainer.AddAbsoluteItem(Self); SetComponentName(Self, GetBaseName, IsDesigning, IsLoading); end else Name := GetValidName(Self, GetBaseName + '_Root'); end; end; procedure TdxCustomLayoutItem.SetEnabled(Value: Boolean); begin if FEnabled <> Value then begin FEnabled := Value; EnabledChanged; end; end; procedure TdxCustomLayoutItem.SetLookAndFeel(Value: TdxCustomLayoutLookAndFeel); begin if FLookAndFeel <> Value then begin if FLookAndFeel <> nil then FLookAndFeel.RemoveUser(Self); FLookAndFeel := Value; if FLookAndFeel <> nil then FLookAndFeel.AddUser(Self); LookAndFeelChangedImpl; end; end; procedure TdxCustomLayoutItem.SetHasMouse(Value: Boolean); begin if HasMouse <> Value then if Value then FContainer.ItemWithMouse := Self else FContainer.ItemWithMouse := nil; end; procedure TdxCustomLayoutItem.SetIndex(Value: Integer); begin if FParent <> nil then FParent.ChangeItemIndex(Self, Value); end; procedure TdxCustomLayoutItem.SetParent(Value: TdxLayoutGroup); var APrevParent: TdxLayoutGroup; APrevActuallyVisible: Boolean; begin if (FParent <> Value) and CanMoveTo(Value) then begin APrevParent := FParent; APrevActuallyVisible := ActuallyVisible; if FParent <> nil then FParent.RemoveItem(Self) else if FContainer <> nil then FContainer.RemoveAvailableItem(Self); if Value <> nil then Value.AddItem(Self) else FContainer.AddAvailableItem(Self); CheckActuallyVisible(APrevActuallyVisible); ParentChanged(APrevParent); end; end; procedure TdxCustomLayoutItem.SetShowCaption(Value: Boolean); begin if FShowCaption <> Value then begin FShowCaption := Value; Changed; end; end; procedure TdxCustomLayoutItem.SetVisible(Value: Boolean); var APrevActuallyVisible: Boolean; begin if FVisible <> Value then begin APrevActuallyVisible := ActuallyVisible; FVisible := Value; FContainer.BeginUpdate; try VisibleChanged; CheckActuallyVisible(APrevActuallyVisible); finally FContainer.EndUpdate; end; end; end; procedure TdxCustomLayoutItem.SetVisibleIndex(Value: Integer); begin if FParent <> nil then FParent.ChangeItemVisibleIndex(Self, Value); end; procedure TdxCustomLayoutItem.CheckActuallyVisible(APrevActuallyVisible: Boolean); begin if not IsDestroying and (ActuallyVisible <> APrevActuallyVisible) then ActuallyVisibleChanged; end; function TdxCustomLayoutItem.IsAlignHorzStored: Boolean; begin Result := not (aaHorizontal in FAutoAligns) and (FAlignHorz <> ahLeft); end; function TdxCustomLayoutItem.IsAlignVertStored: Boolean; begin Result := not (aaVertical in FAutoAligns) and (FAlignVert <> avTop); end; procedure TdxCustomLayoutItem.SetName(const Value: TComponentName); begin inherited; if IsDesigning and not IsRoot then dxLayoutDesigner.ItemsChanged(FContainer); end; procedure TdxCustomLayoutItem.SetParentComponent(Value: TComponent); begin inherited; if Value is TdxLayoutGroup then Parent := TdxLayoutGroup(Value) else if Value is TdxCustomLayoutControl then TdxCustomLayoutControl(Value).AddAvailableItem(Self); end; procedure TdxCustomLayoutItem.LookAndFeelChanged; begin end; procedure TdxCustomLayoutItem.LookAndFeelChanging; begin ResetCachedTextHeight; end; procedure TdxCustomLayoutItem.BeginLookAndFeelDestroying; begin FContainer.BeginUpdate; end; procedure TdxCustomLayoutItem.EndLookAndFeelDestroying; begin FContainer.EndUpdate; end; procedure TdxCustomLayoutItem.LookAndFeelChangedImpl; begin if IsDestroying or not ActuallyVisible then Exit; LookAndFeelChanging; Changed; LookAndFeelChanged; end; procedure TdxCustomLayoutItem.LookAndFeelDestroyed; begin LookAndFeel := nil; end; procedure TdxCustomLayoutItem.ActuallyVisibleChanged; begin if not ActuallyVisible then HasMouse := False; LookAndFeelChangedImpl; if IsDesigning then dxLayoutDesigner.ItemsChanged(FContainer); end; function TdxCustomLayoutItem.CanRemove: Boolean; begin Result := FAllowRemove; end; procedure TdxCustomLayoutItem.DoCaptionClick; begin if Assigned(FOnCaptionClick) then FOnCaptionClick(Self); end; function TdxCustomLayoutItem.DoProcessAccel: Boolean; var AItem: TdxCustomLayoutItem; begin Result := CanProcessAccel(AItem); if Result then AItem.ProcessAccel; end; procedure TdxCustomLayoutItem.EnabledChanged; begin Changed(False); end; function TdxCustomLayoutItem.GetBaseName: string; begin Result := FContainer.Name; end; function TdxCustomLayoutItem.GetCursor(X, Y: Integer): TCursor; begin Result := ViewInfo.GetCursor(X, Y); end; function TdxCustomLayoutItem.GetEnabledForWork: Boolean; begin Result := FEnabled and ((FParent = nil) or FParent.EnabledForWork); end; function TdxCustomLayoutItem.GetLookAndFeel: TdxCustomLayoutLookAndFeel; begin Result := FLookAndFeel; if Result = nil then if FParent <> nil then Result := FParent.GetLookAndFeelAsParent else if IsRoot then Result := FContainer.GetLookAndFeel; end; function TdxCustomLayoutItem.GetShowCaption: Boolean; begin Result := FShowCaption; end; function TdxCustomLayoutItem.GetVisible: Boolean; begin Result := FVisible or IsDesigning; end; function TdxCustomLayoutItem.HasAsParent(AGroup: TdxLayoutGroup): Boolean; var AParent: TdxLayoutGroup; begin AParent := FParent; repeat Result := AParent = AGroup; if Result or (AParent = nil) then Break; AParent := AParent.Parent; until False; end; function TdxCustomLayoutItem.HasCaption: Boolean; begin Result := ShowCaption; end; procedure TdxCustomLayoutItem.Init; begin if GetLookAndFeel <> nil then LookAndFeelChanged; end; procedure TdxCustomLayoutItem.MouseEnter; begin ViewInfo.MouseEnter; end; procedure TdxCustomLayoutItem.MouseLeave; begin if FViewInfo <> nil then FViewInfo.MouseLeave; end; procedure TdxCustomLayoutItem.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin ViewInfo.MouseDown(Button, Shift, X, Y); if IsDesigning and not IsRoot then dxLayoutDesigner.SelectComponent(Container, Self, (ssShift in Shift) and Container.CanMultiSelect); end; procedure TdxCustomLayoutItem.MouseMove(Shift: TShiftState; X, Y: Integer); begin ViewInfo.MouseMove(Shift, X, Y); end; procedure TdxCustomLayoutItem.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin ViewInfo.MouseUp(Button, Shift, X, Y); end; procedure TdxCustomLayoutItem.ParentChanged(APrevParent: TdxLayoutGroup); begin if not IsLoading and (APrevParent <> nil) and not APrevParent.IsDestroying then FContainer.Items.Pack; end; procedure TdxCustomLayoutItem.ProcessAccel; begin end; function TdxCustomLayoutItem.ProcessDialogChar(ACharCode: Word): Boolean; begin Result := HasCaption and FCaptionOptions.ShowAccelChar and IsAccel(ACharCode, Caption) and DoProcessAccel; end; procedure TdxCustomLayoutItem.SelectionChanged; var I: Integer; R: TRect; begin if ViewInfo <> nil then for I := 0 to ViewInfo.SelectionAreaCount - 1 do begin R := ViewInfo.SelectionAreaBounds[I]; RedrawWindow(FContainer.Handle, @R, 0, RDW_ERASE or RDW_FRAME or RDW_INVALIDATE or RDW_ALLCHILDREN); end; end; procedure TdxCustomLayoutItem.VisibleChanged; begin if FParent <> nil then with FParent do begin BuildVisibleItemsList; Changed; end; end; function TdxCustomLayoutItem.GetCaptionOptionsClass: TdxCustomLayoutItemCaptionOptionsClass; begin Result := TdxCustomLayoutItemCaptionOptions; end; procedure TdxCustomLayoutItem.ResetCachedTextHeight; begin FCachedTextHeight := 0; end; procedure TdxCustomLayoutItem.BeforeDestruction; begin inherited; Container.FinishDragAndDrop(False); AlignmentConstraint := nil; end; function TdxCustomLayoutItem.GetParentComponent: TComponent; begin if FParent = nil then Result := FContainer else Result := FParent; end; function TdxCustomLayoutItem.HasParent: Boolean; begin Result := True; end; procedure TdxCustomLayoutItem.Changed(AHardRefresh: Boolean = True); begin if Container.IsLoading or Container.IsDestroying or Container.IsUpdateLocked or not ActuallyVisible then Exit; if AHardRefresh then begin Container.ViewInfo.Calculate; Container.Invalidate; end else if ViewInfo <> nil then Container.InvalidateRect(ViewInfo.Bounds, False); end; function TdxCustomLayoutItem.CanMoveTo(AParent: TdxCustomLayoutItem): Boolean; begin Result := AParent <> Self; end; procedure TdxCustomLayoutItem.MakeVisible; var R, AClientR: TRect; procedure MakeVisibleInOneDirection(AItemMin, AItemMax, AClientMin, AClientMax: Integer; AIsHorizontal: Boolean); var AOffset: Integer; procedure ChangeOffset(ADelta: Integer); begin Inc(AOffset, ADelta); Dec(AItemMin, ADelta); Dec(AItemMax, ADelta); end; procedure ApplyOffset; begin with FContainer do if AIsHorizontal then LeftPos := LeftPos + AOffset else TopPos := TopPos + AOffset; end; begin AOffset := 0; if AItemMax > AClientMax then ChangeOffset(AItemMax - AClientMax); if AItemMin < AClientMin then ChangeOffset(-(AClientMin - AItemMin)); ApplyOffset; end; begin if not ActuallyVisible then Exit; R := ViewInfo.Bounds; AClientR := FContainer.ClientBounds; MakeVisibleInOneDirection(R.Left, R.Right, AClientR.Left, AClientR.Right, True); MakeVisibleInOneDirection(R.Top, R.Bottom, AClientR.Top, AClientR.Bottom, False); end; function TdxCustomLayoutItem.Move(AParent: TdxLayoutGroup; AIndex: Integer; APack: Boolean = False): Boolean; var APrevMayPack: Boolean; AContainer: TdxCustomLayoutControl; begin Result := CanMoveTo(AParent); if not Result then Exit; APrevMayPack := Container.MayPack; Container.MayPack := False; try Parent := AParent; finally Container.MayPack := APrevMayPack; end; Index := AIndex; AContainer := Container; if APack then Container.Items.Pack; AContainer.Changed; end; function TdxCustomLayoutItem.MoveTo(AParent: TdxLayoutGroup; AVisibleIndex: Integer; APack: Boolean = False): Boolean; var AIndex: Integer; begin if AParent = nil then AIndex := -1 else AIndex := AParent.GetItemIndex(AVisibleIndex); Result := Move(AParent, AIndex, APack); end; procedure TdxCustomLayoutItem.Pack; begin end; function TdxCustomLayoutItem.PutIntoHiddenGroup(ALayoutDirection: TdxLayoutDirection): TdxLayoutGroup; var AIndex: Integer; begin if FParent = nil then Result := nil else begin AIndex := Index; Result := FParent.CreateGroup; with Result do begin Hidden := True; LayoutDirection := ALayoutDirection; Index := AIndex; end; Move(Result, 0); end; end; { TdxLayoutControlAdapterDefs } type PControlAdapterRecord = ^TControlAdapterRecord; TControlAdapterRecord = record ControlClass: TControlClass; AdapterClass: TdxCustomLayoutControlAdapterClass; end; TdxLayoutControlAdapterDefs = class private FItems: TList; function GetCount: Integer; function GetItem(Index: Integer): TControlAdapterRecord; procedure ClearItems; protected procedure Delete(AIndex: Integer); property Count: Integer read GetCount; property Items[Index: Integer]: TControlAdapterRecord read GetItem; public constructor Create; destructor Destroy; override; function GetAdapterClass(AControl: TControl): TdxCustomLayoutControlAdapterClass; procedure Register(AControlClass: TControlClass; AAdapterClass: TdxCustomLayoutControlAdapterClass); procedure Unregister(AControlClass: TControlClass; AAdapterClass: TdxCustomLayoutControlAdapterClass); end; var FdxLayoutControlAdapterDefs: TdxLayoutControlAdapterDefs; function dxLayoutControlAdapterDefs: TdxLayoutControlAdapterDefs; begin if FdxLayoutControlAdapterDefs = nil then FdxLayoutControlAdapterDefs := TdxLayoutControlAdapterDefs.Create; Result := FdxLayoutControlAdapterDefs; end; constructor TdxLayoutControlAdapterDefs.Create; begin inherited; FItems := TList.Create; end; destructor TdxLayoutControlAdapterDefs.Destroy; begin ClearItems; FItems.Free; inherited; end; function TdxLayoutControlAdapterDefs.GetCount: Integer; begin Result := FItems.Count; end; function TdxLayoutControlAdapterDefs.GetItem(Index: Integer): TControlAdapterRecord; begin Result := PControlAdapterRecord(FItems[Index])^; end; procedure TdxLayoutControlAdapterDefs.ClearItems; var I: Integer; begin for I := Count - 1 downto 0 do Delete(I); end; procedure TdxLayoutControlAdapterDefs.Delete(AIndex: Integer); begin Dispose(PControlAdapterRecord(FItems[AIndex])); FItems.Delete(AIndex); end; function TdxLayoutControlAdapterDefs.GetAdapterClass(AControl: TControl): TdxCustomLayoutControlAdapterClass; var I: Integer; AControlAdapterRecord: TControlAdapterRecord; begin for I := Count - 1 downto 0 do begin AControlAdapterRecord := Items[I]; if AControl.InheritsFrom(AControlAdapterRecord.ControlClass) then begin Result := AControlAdapterRecord.AdapterClass; Exit; end; end; Result := TdxCustomLayoutControlAdapter; end; procedure TdxLayoutControlAdapterDefs.Register(AControlClass: TControlClass; AAdapterClass: TdxCustomLayoutControlAdapterClass); var AControlAdapterRecord: PControlAdapterRecord; begin New(AControlAdapterRecord); with AControlAdapterRecord^ do begin ControlClass := AControlClass; AdapterClass := AAdapterClass; end; FItems.Add(AControlAdapterRecord); end; procedure TdxLayoutControlAdapterDefs.Unregister(AControlClass: TControlClass; AAdapterClass: TdxCustomLayoutControlAdapterClass); var I: Integer; AControlAdapterRecord: TControlAdapterRecord; begin for I := 0 to Count - 1 do begin AControlAdapterRecord := Items[I]; with AControlAdapterRecord do if (ControlClass = AControlClass) and (AdapterClass = AAdapterClass) then begin Delete(I); Break; end; end; if Count = 0 then FreeAndNil(FdxLayoutControlAdapterDefs); end; { TdxCustomLayoutControlAdapter } constructor TdxCustomLayoutControlAdapter.Create(AItem: TdxLayoutItem); begin inherited Create; FItem := AItem; if not FItem.IsLoading then begin Init; if FItem.ActuallyVisible then LookAndFeelChanged; end; end; function TdxCustomLayoutControlAdapter.GetControl: TControl; begin Result := FItem.Control; end; function TdxCustomLayoutControlAdapter.GetLookAndFeel: TdxCustomLayoutLookAndFeel; begin Result := FItem.GetLookAndFeel; end; function TdxCustomLayoutControlAdapter.AllowCheckSize: Boolean; begin Result := True; end; procedure TdxCustomLayoutControlAdapter.HideControlBorder; begin SetEnumProp(Control, 'BorderStyle', 'bsNone'); end; procedure TdxCustomLayoutControlAdapter.Init; var AHeight: Integer; begin FItem.ControlOptions.AutoColor := UseItemColor; if FItem.IsDesigning and (FItem.Caption = '') then FItem.Caption := Control.Name;//GetPlainString(TControlAccess(Control).Caption); FItem.SetControlEnablement; FItem.SetControlVisibility; if FItem.IsDesigning then FItem.ShowCaption := ShowItemCaption; FItem.ControlOptions.ShowBorder := ShowBorder; if ShowBorder then begin AHeight := Control.ClientHeight; HideControlBorder; Control.Height := AHeight; end; end; function TdxCustomLayoutControlAdapter.ShowBorder: Boolean; begin Result := IsPublishedProp(Control, 'BorderStyle') and (GetPropInfo(Control, 'BorderStyle').PropType^ = TypeInfo(Forms.TBorderStyle)); end; function TdxCustomLayoutControlAdapter.ShowItemCaption: Boolean; begin Result := not IsPublishedProp(Control, 'Caption'); end; function TdxCustomLayoutControlAdapter.UseItemColor: Boolean; begin Result := TControlAccess(Control).ParentColor and IsPublishedProp(Control, 'Color'); end; procedure TdxCustomLayoutControlAdapter.LookAndFeelChanged; begin if Item.ControlOptions.AutoColor and (Item.ViewInfo <> nil) then TControlAccess(Control).Color := Item.ViewInfo.Color; end; class procedure TdxCustomLayoutControlAdapter.Register(AControlClass: TControlClass); begin dxLayoutControlAdapterDefs.Register(AControlClass, Self); end; class procedure TdxCustomLayoutControlAdapter.Unregister(AControlClass: TControlClass); begin dxLayoutControlAdapterDefs.Unregister(AControlClass, Self); end; { TdxLayoutItemCaptionOptions } constructor TdxLayoutItemCaptionOptions.Create(AItem: TdxCustomLayoutItem); begin inherited; FAlignVert := tavCenter; end; procedure TdxLayoutItemCaptionOptions.SetAlignVert(Value: TdxAlignmentVert); begin if FAlignVert <> Value then begin FAlignVert := Value; Changed; end; end; procedure TdxLayoutItemCaptionOptions.SetLayout(Value: TdxCaptionLayout); begin if FLayout <> Value then begin FLayout := Value; Changed; end; end; procedure TdxLayoutItemCaptionOptions.SetWidth(Value: Integer); begin if Value < 0 then Value := 0; if FWidth <> Value then begin FWidth := Value; Item.ResetCachedTextHeight; Changed; end; end; { TdxLayoutItemControlOptions } constructor TdxLayoutItemControlOptions.Create(AItem: TdxCustomLayoutItem); begin inherited; FAutoAlignment := True; FMinHeight := dxLayoutItemControlDefaultMinHeight; FMinWidth := dxLayoutItemControlDefaultMinWidth; FShowBorder := True; end; procedure TdxLayoutItemControlOptions.SetAutoAlignment(Value: Boolean); begin if FAutoAlignment <> Value then begin FAutoAlignment := Value; Changed; end; end; procedure TdxLayoutItemControlOptions.SetAutoColor(Value: Boolean); begin if FAutoColor <> Value then begin FAutoColor := Value; Item.LookAndFeelChangedImpl; end; end; procedure TdxLayoutItemControlOptions.SetFixedSize(Value: Boolean); begin if FFixedSize <> Value then begin FFixedSize := Value; Changed; end; end; procedure TdxLayoutItemControlOptions.SetMinHeight(Value: Integer); begin if Value < 0 then Value := 0; if FMinHeight <> Value then begin FMinHeight := Value; Changed; end; end; procedure TdxLayoutItemControlOptions.SetMinWidth(Value: Integer); begin if Value < 0 then Value := 0; if FMinWidth <> Value then begin FMinWidth := Value; Changed; end; end; procedure TdxLayoutItemControlOptions.SetOpaque(Value: Boolean); begin if FOpaque <> Value then begin FOpaque := Value; Changed; end; end; procedure TdxLayoutItemControlOptions.SetShowBorder(Value: Boolean); begin if FShowBorder <> Value then begin FShowBorder := Value; Changed; end; end; { TdxLayoutItem } constructor TdxLayoutItem.Create(AOwner: TComponent); begin inherited; FControlOptions := GetControlOptionsClass.Create(Self); end; destructor TdxLayoutItem.Destroy; begin Control := nil; FControlOptions.Free; inherited; end; function TdxLayoutItem.GetCaptionOptions: TdxLayoutItemCaptionOptions; begin Result := TdxLayoutItemCaptionOptions(inherited CaptionOptions); end; function TdxLayoutItem.GetViewInfo: TdxLayoutItemViewInfo; begin Result := TdxLayoutItemViewInfo(inherited ViewInfo); end; procedure TdxLayoutItem.SetCaptionOptions(Value: TdxLayoutItemCaptionOptions); begin inherited CaptionOptions := Value; end; procedure TdxLayoutItem.SetControl(Value: TControl); procedure CheckValue; var AItem: TdxLayoutItem; begin if Value <> nil then begin if Value = Container then raise EdxException.Create(sContainerCannotBeControl); AItem := FContainer.FindItem(Value); if AItem <> nil then raise EdxException.Create(Format(sControlIsUsed, [Value.Name, AItem.Name])) end; end; procedure UnprepareControl; begin FreeAndNil(FControlAdapter); if IsDesigning then with FControl do ControlStyle := ControlStyle - [csNoDesignVisible]; //FControl.RemoveFreeNotification(Self); FControl.WindowProc := FPrevControlWndProc; if IsDesigning and not (csDestroying in FControl.ComponentState) then begin FControl.Left := 0; FControl.Top := 0; end; end; procedure PrepareControl; begin //FPrevControlWndProc := FControl.WindowProc; //FControl.WindowProc := ControlWndProc; //FControl.FreeNotification(Self); if IsDesigning then with FControl do ControlStyle := ControlStyle + [csNoDesignVisible]; FControl.Parent := Container; SaveOriginalControlSize; CreateControlAdapter; SaveOriginalControlSize; if HasWinControl and not TWinControl(Control).HandleAllocated then SaveControlSizeBeforeDestruction; FPrevControlWndProc := FControl.WindowProc; FControl.WindowProc := ControlWndProc; end; begin if FControl <> Value then begin CheckValue; if FControl <> nil then UnprepareControl; FControl := Value; if FControl <> nil then PrepareControl; Changed; end; end; procedure TdxLayoutItem.CreateControlAdapter; begin FControlAdapter := dxLayoutControlAdapterDefs.GetAdapterClass(FControl).Create(Self); end; {procedure TdxLayoutItem.PostFree; begin Container.PostFree(Self); end;} procedure TdxLayoutItem.ActuallyVisibleChanged; begin SetControlVisibility; inherited; end; function TdxLayoutItem.CanProcessAccel(out AItem: TdxCustomLayoutItem): Boolean; begin Result := CanFocusControl; if Result then AItem := Self; end; procedure TdxLayoutItem.EnabledChanged; begin inherited; SetControlEnablement; end; function TdxLayoutItem.GetAutoAlignHorz: TdxLayoutAlignHorz; begin if (FParent = nil) or (FParent.LayoutDirection = ldHorizontal) then Result := ahLeft else Result := ahClient; end; function TdxLayoutItem.GetAutoAlignVert: TdxLayoutAlignVert; begin Result := avTop; end; function TdxLayoutItem.GetBaseName: string; begin Result := inherited GetBaseName + 'Item'; end; function TdxLayoutItem.GetViewInfoClass: TdxCustomLayoutItemViewInfoClass; begin Result := TdxCustomLayoutItemViewInfoClass(GetLookAndFeel.GetItemViewInfoClass); end; function TdxLayoutItem.HasCaption: Boolean; begin Result := inherited HasCaption and (Caption <> ''); end; procedure TdxLayoutItem.Init; var ACommonValue: Variant; function IsCommonValue(AValueIndex: Integer; var ACommonValue: Variant): Boolean; var I: Integer; AValue: Variant; function CheckValue(AItem: TdxCustomLayoutItem): Boolean; begin if AItem <> Self then case AValueIndex of 0..2: Result := AItem is TdxLayoutItem; 3..4: Result := True; else Result := False; end else Result := False; end; function GetValue(AItem: TdxCustomLayoutItem): Variant; begin case AValueIndex of 0: Result := TdxLayoutItem(AItem).CaptionOptions.Layout; 1: Result := TdxLayoutItem(AItem).CaptionOptions.AlignHorz; 2: Result := TdxLayoutItem(AItem).CaptionOptions.AlignVert; 3: Result := AItem.AlignHorz; 4: Result := AItem.AlignVert; else Result := Null; end; end; begin Result := Parent <> nil; if not Result then Exit; Result := False; ACommonValue := Unassigned; for I := 0 to Parent.VisibleCount - 1 do if CheckValue(Parent.VisibleItems[I]) then begin AValue := GetValue(Parent.VisibleItems[I]); if VarIsEmpty(ACommonValue) then ACommonValue := AValue; Result := AValue = ACommonValue; if not Result then Break; end; end; begin inherited; if IsCommonValue(0, ACommonValue) then CaptionOptions.Layout := ACommonValue; if IsCommonValue(1, ACommonValue) then CaptionOptions.AlignHorz := ACommonValue; if IsCommonValue(2, ACommonValue) then CaptionOptions.AlignVert := ACommonValue; {if IsCommonValue(3, ACommonValue) then AlignHorz := ACommonValue; - items lose client alignment} {if IsCommonValue(4, ACommonValue) then AlignVert := ACommonValue; - because some controls cannot be made client aligned } end; procedure TdxLayoutItem.Loaded; begin inherited; if HasControl then begin SaveOriginalControlSize; SetControlVisibility; end; end; procedure TdxLayoutItem.LookAndFeelChanged; begin inherited; if FControlAdapter <> nil then FControlAdapter.LookAndFeelChanged; end; {procedure TdxLayoutItem.Notification(AComponent: TComponent; Operation: TOperation); begin inherited; if (Operation = opRemove) and (AComponent = FControl) then begin Control := nil; PostFree; end; end;} procedure TdxLayoutItem.ParentChanged(APrevParent: TdxLayoutGroup); begin inherited; SetControlEnablement; end; procedure TdxLayoutItem.ProcessAccel; begin TWinControl(FControl).SetFocus; end; procedure TdxLayoutItem.RestoreItemControlSize; begin if HasControl then with Control, FOriginalControlSize do SetBounds(Left, Top, X, Y); end; function TdxLayoutItem.GetCaptionOptionsClass: TdxCustomLayoutItemCaptionOptionsClass; begin Result := TdxLayoutItemCaptionOptions; end; function TdxLayoutItem.GetControlOptionsClass: TdxLayoutItemControlOptionsClass; begin Result := TdxLayoutItemControlOptions; end; function TdxLayoutItem.CanFocusControl: Boolean; begin Result := HasWinControl and TWinControl(FControl).CanFocus; end; procedure TdxLayoutItem.ControlWndProc(var Message: TMessage); function IsControlMoved: Boolean; begin Result := (Message.LParam = 0) or (PWindowPos(Message.LParam)^.flags and SWP_NOMOVE = 0); end; function IsControlResized: Boolean; begin Result := (Message.LParam = 0) or (PWindowPos(Message.LParam)^.flags and SWP_NOSIZE = 0); end; function ControlSizeChanged: Boolean; begin with Control, FOriginalControlSize do Result := (Width <> X) or (Height <> Y); end; begin FPrevControlWndProc(Message); with Message do case Msg of WM_CREATE: if (Control.Width <> ControlSizeBeforeDestruction.X) or (Control.Height <> ControlSizeBeforeDestruction.Y) then begin SaveOriginalControlSize; Changed; end; WM_DESTROY: SaveControlSizeBeforeDestruction; WM_PAINT, WM_NCPAINT: if IsDesigning and not Container.IsDestroying then Container.Painter.DrawSelections; WM_SETFOCUS: MakeVisible; WM_WINDOWPOSCHANGED: if not Container.IsPlacingControls and (IsControlMoved or IsControlResized) then begin if IsControlResized and FControlAdapter.AllowCheckSize and ControlSizeChanged then SaveOriginalControlSize; Changed; end; CM_TABSTOPCHANGED: Container.ViewInfo.DoCalculateTabOrders; end; end; function TdxLayoutItem.HasControl: Boolean; begin Result := FControl <> nil; end; function TdxLayoutItem.HasWinControl: Boolean; begin Result := HasControl and (FControl is TWinControl); end; procedure TdxLayoutItem.SaveControlSizeBeforeDestruction; begin FControlSizeBeforeDestruction := Point(Control.Width, Control.Height); end; procedure TdxLayoutItem.SaveOriginalControlSize; begin if HasWinControl and CanAllocateHandle(TWinControl(FControl)) then TWinControl(FControl).HandleNeeded; // for cxEditors FOriginalControlSize := Point(FControl.Width, FControl.Height); end; procedure TdxLayoutItem.SetControlEnablement; begin if HasControl then Control.Enabled := EnabledForWork; end; procedure TdxLayoutItem.SetControlVisibility; begin if HasControl then with Control do begin Visible := ActuallyVisible; // to make the control invisible on showing if not Visible then SetBounds(10000, 10000, FOriginalControlSize.X, FOriginalControlSize.Y); end; end; { TdxLayoutGroup } constructor TdxLayoutGroup.Create(AOwner: TComponent); begin inherited; FIsUserDefined := True; FItems := TList.Create; FLayoutDirection := ldVertical; FShowBorder := True; FUseIndent := True; FVisibleItems := TList.Create; end; destructor TdxLayoutGroup.Destroy; begin if IsRoot then Container.FItems := nil; DestroyItems; FreeAndNil(FVisibleItems); FreeAndNil(FItems); inherited; end; function TdxLayoutGroup.GetCount: Integer; begin Result := FItems.Count; end; function TdxLayoutGroup.GetItem(Index: Integer): TdxCustomLayoutItem; begin Result := TdxCustomLayoutItem(FItems[Index]); end; function TdxLayoutGroup.GetShowBorder: Boolean; begin if FHidden then Result := False else Result := FShowBorder; end; function TdxLayoutGroup.GetViewInfo: TdxLayoutGroupViewInfo; begin Result := TdxLayoutGroupViewInfo(inherited ViewInfo); end; function TdxLayoutGroup.GetVisibleCount: Integer; begin Result := FVisibleItems.Count; end; function TdxLayoutGroup.GetVisibleItem(Index: Integer): TdxCustomLayoutItem; begin Result := TdxCustomLayoutItem(FVisibleItems[Index]); end; procedure TdxLayoutGroup.SetHidden(Value: Boolean); begin if FHidden <> Value then begin FHidden := Value; if not IsRoot then begin Changed; if IsDesigning then dxLayoutDesigner.ItemsChanged(Container); end; end; end; procedure TdxLayoutGroup.SetLayoutDirection(Value: TdxLayoutDirection); begin if FLayoutDirection <> Value then begin FLayoutDirection := Value; Changed; end; end; procedure TdxLayoutGroup.SetLocked(Value: Boolean); begin if FLocked <> Value then begin FLocked := Value; end; end; procedure TdxLayoutGroup.SetLookAndFeelException(Value: Boolean); begin if FLookAndFeelException <> Value then begin FLookAndFeelException := Value; LookAndFeelChangedImpl; end; end; procedure TdxLayoutGroup.SetShowBorder(Value: Boolean); begin if FShowBorder <> Value then begin FShowBorder := Value; Changed; end; end; procedure TdxLayoutGroup.SetUseIndent(Value: Boolean); begin if FUseIndent <> Value then begin FUseIndent := Value; Changed; end; end; procedure TdxLayoutGroup.AddItem(AItem: TdxCustomLayoutItem); begin FItems.Add(AItem); AItem.FParent := Self; AItem.Container := FContainer; if AItem.GetVisible then BuildVisibleItemsList; Changed; if not IsLoading then AItem.Init; end; procedure TdxLayoutGroup.RemoveItem(AItem: TdxCustomLayoutItem); begin FItems.Remove(AItem); AItem.FParent := nil; if AItem.GetVisible then BuildVisibleItemsList; Changed; end; procedure TdxLayoutGroup.DestroyItems; var I: Integer; begin for I := Count - 1 downto 0 do Items[I].Free; end; procedure TdxLayoutGroup.ActuallyVisibleChanged; var I: Integer; begin inherited; for I := 0 to VisibleCount - 1 do VisibleItems[I].ActuallyVisibleChanged; end; function TdxLayoutGroup.CanProcessAccel(out AItem: TdxCustomLayoutItem): Boolean; var I: Integer; begin Result := False; for I := 0 to VisibleCount - 1 do begin AItem := VisibleItems[I]; Result := AItem.CanProcessAccel(AItem); if Result then Break; end; end; function TdxLayoutGroup.CanRemove: Boolean; var I: Integer; begin Result := inherited CanRemove; if Result then for I := 0 to Count - 1 do begin Result := Items[I].CanRemove; if not Result then Break; end; end; procedure TdxLayoutGroup.EnabledChanged; var I: Integer; begin for I := 0 to Count - 1 do Items[I].EnabledChanged; inherited; end; function TdxLayoutGroup.GetAutoAlignHorz: TdxLayoutAlignHorz; begin if IsRoot then if acsWidth in Container.AutoContentSizes then Result := ahClient else Result := ahLeft else if (Parent = nil) or (Parent.LayoutDirection = ldHorizontal) then Result := ahLeft else Result := ahClient; end; function TdxLayoutGroup.GetAutoAlignVert: TdxLayoutAlignVert; begin if IsRoot then if acsHeight in Container.AutoContentSizes then Result := avClient else Result := avTop else if (Parent <> nil) and (Parent.LayoutDirection = ldHorizontal) then Result := avClient else Result := avTop; end; function TdxLayoutGroup.GetBaseName: string; begin Result := inherited GetBaseName + 'Group'; end; procedure TdxLayoutGroup.GetChildren(Proc: TGetChildProc; Root: TComponent); var I: Integer; begin inherited; for I := 0 to Count - 1 do if Items[I].Owner = Root then Proc(Items[I]); end; function TdxLayoutGroup.GetShowCaption: Boolean; begin if FHidden then Result := False else Result := ShowBorder and inherited GetShowCaption; end; function TdxLayoutGroup.GetViewInfoClass: TdxCustomLayoutItemViewInfoClass; begin Result := TdxCustomLayoutItemViewInfoClass(GetLookAndFeel.GetGroupViewInfoClass); end; procedure TdxLayoutGroup.Loaded; begin inherited; FIsUserDefined := False; end; procedure TdxLayoutGroup.LookAndFeelChanged; var I: Integer; begin inherited; for I := 0 to VisibleCount - 1 do VisibleItems[I].LookAndFeelChanged; end; procedure TdxLayoutGroup.LookAndFeelChanging; var I: Integer; begin inherited; for I := 0 to VisibleCount - 1 do VisibleItems[I].LookAndFeelChanging; end; function TdxLayoutGroup.ProcessDialogChar(ACharCode: Word): Boolean; var I: Integer; begin Result := inherited ProcessDialogChar(ACharCode); if not Result then for I := 0 to VisibleCount - 1 do begin Result := VisibleItems[I].ProcessDialogChar(ACharCode); if Result then Break; end; end; procedure TdxLayoutGroup.RestoreItemControlSize; var I: Integer; begin for I := 0 to Count - 1 do Items[I].RestoreItemControlSize; end; procedure TdxLayoutGroup.SelectionChanged; var I: Integer; begin inherited; for I := 0 to VisibleCount - 1 do VisibleItems[I].SelectionChanged; end; procedure TdxLayoutGroup.SetChildOrder(Child: TComponent; Order: Integer); begin inherited; (Child as TdxCustomLayoutItem).Index := Order; end; procedure TdxLayoutGroup.SetParentComponent(Value: TComponent); begin if Value is TdxCustomLayoutControl and not TdxCustomLayoutControl(Value).Items.IsLoading and not (csAncestor in ComponentState) then TdxCustomLayoutControl(Value).SetItems(Self) else inherited; end; function TdxLayoutGroup.CanDestroy: Boolean; begin Result := Hidden and not IsRoot and not Locked; end; procedure TdxLayoutGroup.BuildVisibleItemsList; var I: Integer; begin FVisibleItems.Clear; for I := 0 to Count - 1 do if Items[I].GetVisible then FVisibleItems.Add(Items[I]); end; function TdxLayoutGroup.GetLookAndFeelAsParent: TdxCustomLayoutLookAndFeel; begin if FLookAndFeelException and (Parent <> nil) then Result := Parent.GetLookAndFeelAsParent else Result := GetLookAndFeel; end; procedure TdxLayoutGroup.ChangeItemIndex(AItem: TdxCustomLayoutItem; Value: Integer); begin if AItem.Index <> Value then begin FItems.Move(AItem.Index, Value); if AItem.GetVisible then begin BuildVisibleItemsList; Changed; end; end; end; procedure TdxLayoutGroup.ChangeItemVisibleIndex(AItem: TdxCustomLayoutItem; Value: Integer); begin ChangeItemIndex(AItem, GetItemIndex(Value)); end; function TdxLayoutGroup.GetItemIndex(AItemVisibleIndex: Integer): Integer; begin if (0 <= AItemVisibleIndex) and (AItemVisibleIndex < VisibleCount) then Result := VisibleItems[AItemVisibleIndex].Index else Result := Count; end; function TdxLayoutGroup.IndexOf(AItem: TdxCustomLayoutItem): Integer; begin Result := FItems.IndexOf(AItem); end; function TdxLayoutGroup.VisibleIndexOf(AItem: TdxCustomLayoutItem): Integer; begin Result := FVisibleItems.IndexOf(AItem); end; function TdxLayoutGroup.CreateGroup(AGroupClass: TdxLayoutGroupClass = nil): TdxLayoutGroup; begin Result := Container.CreateGroup(AGroupClass, Self); end; function TdxLayoutGroup.CreateItem(AItemClass: TdxCustomLayoutItemClass = nil): TdxCustomLayoutItem; begin Result := Container.CreateItem(AItemClass, Self); end; function TdxLayoutGroup.CreateItemForControl(AControl: TControl): TdxLayoutItem; begin Result := Container.CreateItemForControl(AControl, Self); end; function TdxLayoutGroup.CanMoveTo(AParent: TdxCustomLayoutItem): Boolean; begin Result := (AParent = nil) or inherited CanMoveTo(AParent) and not AParent.HasAsParent(Self); end; procedure TdxLayoutGroup.MoveChildrenToParent; var AInsertionIndex, I: Integer; begin AInsertionIndex := Index; for I := Count - 1 downto 0 do Items[I].Move(Parent, AInsertionIndex); end; procedure TdxLayoutGroup.Pack; var I: Integer; ASomethingDone: Boolean; AGroup: TdxLayoutGroup; begin if FIsPacking or not Container.MayPack then Exit; FIsPacking := True; for I := Count - 1 downto 0 do Items[I].Pack; repeat ASomethingDone := False; if (Count = 0) and CanDestroy then begin Free; Exit; end; if Count = 1 then begin if Items[0] is TdxLayoutGroup then begin AGroup := TdxLayoutGroup(Items[0]); if AGroup.CanDestroy then begin LayoutDirection := AGroup.LayoutDirection; AGroup.MoveChildrenToParent; AGroup.Free; ASomethingDone := True; end; end; if not ASomethingDone and CanDestroy then begin Items[0].Move(Parent, Index); ASomethingDone := True; end; end; until not ASomethingDone; FIsPacking := False; end; function TdxLayoutGroup.PutChildrenIntoHiddenGroup: TdxLayoutGroup; var I: Integer; begin Result := CreateGroup; Result.Hidden := True; Result.LayoutDirection := LayoutDirection; for I := Count - 2 downto 0 do Items[I].Move(Result, 0); end; { TdxLayoutAlignmentConstraint } constructor TdxLayoutAlignmentConstraint.Create(AOwner: TComponent); begin inherited; CreateItems; end; destructor TdxLayoutAlignmentConstraint.Destroy; begin DestroyItems; if FControl <> nil then FControl.RemoveAlignmentConstraint(Self); inherited; end; function TdxLayoutAlignmentConstraint.GetCount: Integer; begin Result := FItems.Count; end; function TdxLayoutAlignmentConstraint.GetItem(Index: Integer): TdxCustomLayoutItem; begin Result := FItems[Index]; end; procedure TdxLayoutAlignmentConstraint.SetKind(Value: TdxLayoutAlignmentConstraintKind); begin if FKind <> Value then begin FKind := Value; Changed; end; end; procedure TdxLayoutAlignmentConstraint.CreateItems; begin FItems := TList.Create; end; procedure TdxLayoutAlignmentConstraint.DestroyItems; var I: Integer; begin BeginUpdate; try for I := Count - 1 downto 0 do RemoveItem(Items[I]); finally EndUpdate; end; FItems.Free; end; procedure TdxLayoutAlignmentConstraint.SetParentComponent(Value: TComponent); begin inherited; if Value is TdxCustomLayoutControl then TdxCustomLayoutControl(Value).AddAlignmentConstraint(Self); end; procedure TdxLayoutAlignmentConstraint.BeginUpdate; begin FControl.BeginUpdate; end; function TdxLayoutAlignmentConstraint.CanAddItem(AItem: TdxCustomLayoutItem): Boolean; begin Result := (AItem <> nil) and (AItem.Container = Control); end; procedure TdxLayoutAlignmentConstraint.Changed; begin FControl.LayoutChanged; end; procedure TdxLayoutAlignmentConstraint.EndUpdate; begin FControl.EndUpdate; end; function TdxLayoutAlignmentConstraint.GetParentComponent: TComponent; begin Result := FControl; end; function TdxLayoutAlignmentConstraint.HasParent: Boolean; begin Result := FControl <> nil; end; procedure TdxLayoutAlignmentConstraint.AddItem(AItem: TdxCustomLayoutItem); begin if not CanAddItem(AItem) then Exit; AItem.AlignmentConstraint := nil; FItems.Add(AItem); AItem.FAlignmentConstraint := Self; Changed; end; procedure TdxLayoutAlignmentConstraint.RemoveItem(AItem: TdxCustomLayoutItem); begin if (AItem <> nil) and (FItems.Remove(AItem) <> -1) then begin AItem.FAlignmentConstraint := nil; Changed; if not (csDestroying in ComponentState) and (Count < 2) then Free; end; end; { TdxLayoutControlDragAndDropObject } destructor TdxLayoutControlDragAndDropObject.Destroy; begin SourceItem := nil; inherited; end; function TdxLayoutControlDragAndDropObject.GetControl: TdxCustomLayoutControl; begin Result := TdxCustomLayoutControl(inherited Control); end; procedure TdxLayoutControlDragAndDropObject.SetAreaPart(Value: TdxLayoutAreaPart); begin if FAreaPart <> Value then begin Dirty := True; FAreaPart := Value; end; end; procedure TdxLayoutControlDragAndDropObject.SetDestItem(Value: TdxCustomLayoutItem); begin if FDestItem <> Value then begin Dirty := True; FDestItem := Value; end; end; procedure TdxLayoutControlDragAndDropObject.SetSourceItem(Value: TdxCustomLayoutItem); begin if FSourceItem <> Value then begin if Value = nil then HideSourceItemMark; FSourceItem := Value; if Value <> nil then ShowSourceItemMark; end; end; procedure TdxLayoutControlDragAndDropObject.HideSourceItemMark; begin if Control.HandleAllocated and (FSourceItem.ViewInfo <> nil) then RedrawWindow(Control.Handle, @FSourceItemBounds, 0, RDW_ERASE or RDW_FRAME or RDW_INVALIDATE or RDW_ALLCHILDREN); end; procedure TdxLayoutControlDragAndDropObject.ShowSourceItemMark; var AMaskBounds: TRect; AMaskBitmap: TBitmap; function CreatePatternBitmap: TBitmap; var I, J: Integer; begin Result := TBitmap.Create; with Result do begin Monochrome := True; Width := 8; Height := 8; for I := 0 to Width - 1 do for J := 0 to Height - 1 do Canvas.Pixels[I, J] := clWhite * Byte(Odd(I) xor Odd(J)) end; end; function CreateMask: TBitmap; begin Result := TBitmap.Create; Result.Width := AMaskBounds.Right; Result.Height := AMaskBounds.Bottom; Result.Canvas.Brush.Bitmap := CreatePatternBitmap; end; function MaskCanvas: TCanvas; begin Result := AMaskBitmap.Canvas; end; begin if SourceItem.ViewInfo = nil then Exit; FSourceItemBounds := SourceItem.ViewInfo.Bounds; AMaskBounds := FSourceItemBounds; OffsetRect(AMaskBounds, -AMaskBounds.Left, -AMaskBounds.Top); with Control.Painter.GetCustomizationCanvas do try AMaskBitmap := CreateMask; try SetTextColor(MaskCanvas.Handle, 0); SetBkColor(MaskCanvas.Handle, $FFFFFF); MaskCanvas.FillRect(AMaskBounds); CopyMode := cmSrcAnd; Draw(FSourceItemBounds.Left, FSourceItemBounds.Top, AMaskBitmap); SetTextColor(MaskCanvas.Handle, ColorToRGB(clHighlight)); SetBkColor(MaskCanvas.Handle, 0); MaskCanvas.FillRect(AMaskBounds); CopyMode := cmSrcPaint; Draw(FSourceItemBounds.Left, FSourceItemBounds.Top, AMaskBitmap); finally CopyMode := cmSrcCopy; MaskCanvas.Brush.Bitmap.Free; MaskCanvas.Brush.Bitmap := nil; AMaskBitmap.Free; end; finally Free; end; end; procedure TdxLayoutControlDragAndDropObject.DirtyChanged; function GetAreaPartBounds: TRect; procedure CalculatePartBounds(AHorizontal, AFirstPart: Boolean); var AMiddle: Integer; begin with Result do if AHorizontal then begin AMiddle := (Left + Right) div 2; if AFirstPart then Right := AMiddle else Left := AMiddle; end else begin AMiddle := (Top + Bottom) div 2; if AFirstPart then Bottom := AMiddle else Top := AMiddle; end; end; begin if AreaPart in [apBeforeContent, apAfterContent] then with TdxLayoutGroup(DestItem) do begin Result := ViewInfo.ClientBounds; CalculatePartBounds(GetOrthogonalDirection(LayoutDirection) = ldHorizontal, AreaPart = apBeforeContent); end else begin Result := DestItem.ViewInfo.Bounds; if AreaPart = apCenter then Result := GetCenterAreaBounds(Result) else CalculatePartBounds(AreaPart in [apLeft, apRight], AreaPart in [apLeft, apTop]); end; end; procedure ShowAreaPartMark; const FrameBorderSize = 3; begin with Control.Painter.GetCustomizationCanvas do try InvertFrame(GetAreaPartBounds, FrameBorderSize); finally Free; end; end; procedure HideAreaPartMark; begin ShowAreaPartMark; end; begin inherited; if (DestItem = nil) or (AreaPart = apNone) then Exit; if Dirty then HideAreaPartMark else ShowAreaPartMark; end; function TdxLayoutControlDragAndDropObject.GetDragAndDropCursor(Accepted: Boolean): TCursor; begin if Accepted or (Control.ViewInfo.GetHitTest(CurMousePos).HitTestCode = htCustomizeForm) and SourceItem.CanRemove then Result := crdxLayoutControlDrag else if (Source = dsCustomizeForm) or not SourceItem.CanRemove then Result := crcxNoDrop else Result := crcxRemove; end; function TdxLayoutControlDragAndDropObject.GetCenterAreaBounds(const AItemBounds: TRect): TRect; begin Result := AItemBounds; with Result do InflateRect(Result, -(Right - Left) div 4, -(Bottom - Top) div 4); end; procedure TdxLayoutControlDragAndDropObject.BeginDragAndDrop; begin inherited; Control.DragAndDropBegan; end; procedure TdxLayoutControlDragAndDropObject.DragAndDrop(const P: TPoint; var Accepted: Boolean); var AHitTest: TdxCustomLayoutHitTest; function GetAreaPart(AItem: TdxCustomLayoutItem; const P: TPoint): TdxLayoutAreaPart; const ContentParts: array[Boolean] of TdxLayoutAreaPart = (apBeforeContent, apAfterContent); Parts: array[Boolean, Boolean] of TdxLayoutAreaPart = ((apBottom, apRight), (apLeft, apTop)); var AGroup: TdxLayoutGroup; ASign1, ASign2: Integer; function GetSign(const P1, P2, P: TPoint): Integer; begin Result := (P.X - P1.X) * (P2.Y - P1.Y) - (P.Y - P1.Y) * (P2.X - P1.X); end; begin Result := apNone; if AItem is TdxLayoutGroup and not TdxLayoutGroup(AItem).ViewInfo.IsLocked then begin AGroup := TdxLayoutGroup(AItem); if AGroup.VisibleCount = 0 then if PtInRect(GetCenterAreaBounds(AItem.ViewInfo.Bounds), P) then Result := apCenter else else if PtInRect(AGroup.ViewInfo.ClientBounds, P) then with AGroup.ViewInfo.ClientBounds do if AGroup.LayoutDirection = ldHorizontal then Result := ContentParts[P.Y >= (Top + Bottom) div 2] else Result := ContentParts[P.X >= (Left + Right) div 2]; end; if Result = apNone then begin with AItem.ViewInfo.Bounds do begin ASign1 := GetSign(Point(Left, Bottom), Point(Right, Top), P); ASign2 := GetSign(TopLeft, BottomRight, P); end; Result := Parts[ASign1 >= 0, ASign2 >= 0]; end; end; begin if IsWindowVisible(Control.Handle) then AHitTest := Control.ViewInfo.GetHitTest(P) else AHitTest := nil; Accepted := AHitTest is TdxCustomLayoutItemHitTest; if Accepted then begin DestItem := TdxCustomLayoutItemHitTest(AHitTest).Item; if SourceItem.CanMoveTo(DestItem) then AreaPart := GetAreaPart(DestItem, P) else AreaPart := apNone; end else if (AHitTest <> nil) and (AHitTest.HitTestCode = htClientArea) then begin Accepted := True; DestItem := Control.Items; if P.Y >= Control.ViewInfo.ContentBounds.Bottom then AreaPart := apBottom else AreaPart := apRight; end else DestItem := nil; inherited; end; procedure TdxLayoutControlDragAndDropObject.EndDragAndDrop(Accepted: Boolean); type TActionType = (atNone, atInsert, atCreateGroup, atContentInsert); function GetDestParent: TdxLayoutGroup; begin if AreaPart in [apCenter, apBeforeContent, apAfterContent] then Result := TdxLayoutGroup(DestItem) else begin Result := DestItem.Parent; if Result = nil then Result := DestItem as TdxLayoutGroup; end; end; function GetDestPosition: Integer; begin case AreaPart of apCenter: Result := 0; apBeforeContent: Result := 0; apAfterContent: Result := 1; else if DestItem.IsRoot then Result := 0 else Result := DestItem.VisibleIndex; if AreaPart in [apRight, apBottom] then Inc(Result); if (SourceItem.Parent <> nil) and (SourceItem.Parent = DestItem.Parent) and (SourceItem.VisibleIndex < Result) then Dec(Result); end; end; function GetLayoutDirection: TdxLayoutDirection; begin Result := GetDestParent.LayoutDirection; end; function IsHorizontalAreaPart: Boolean; begin Result := AreaPart in [apLeft, apRight]; end; function GetActionType: TActionType; begin if AreaPart = apNone then Result := atNone else if AreaPart in [apBeforeContent, apAfterContent] then Result := atContentInsert else if (AreaPart = apCenter) or not DestItem.IsRoot and ((GetLayoutDirection = ldHorizontal) and IsHorizontalAreaPart or (GetLayoutDirection = ldVertical) and not IsHorizontalAreaPart) then Result := atInsert else Result := atCreateGroup; end; procedure DoInsert; begin SourceItem.MoveTo(GetDestParent, GetDestPosition, True); end; procedure DoCreateGroup; const LayoutDirections: array[Boolean] of TdxLayoutDirection = (ldVertical, ldHorizontal); var AGroup: TdxLayoutGroup; begin if DestItem.IsRoot then begin GetDestParent.PutChildrenIntoHiddenGroup; GetDestParent.LayoutDirection := LayoutDirections[IsHorizontalAreaPart]; SourceItem.MoveTo(GetDestParent, GetDestPosition, True); end else begin AGroup := DestItem.PutIntoHiddenGroup(GetOrthogonalDirection(GetLayoutDirection)); SourceItem.MoveTo(AGroup, GetDestPosition, True); end; end; procedure DoContentInsert; begin GetDestParent.PutChildrenIntoHiddenGroup; GetDestParent.LayoutDirection := GetOrthogonalDirection(GetLayoutDirection); SourceItem.MoveTo(GetDestParent, GetDestPosition, True); end; begin Dirty := True; if Accepted then begin if DestItem <> nil then case GetActionType of atInsert: DoInsert; atCreateGroup: DoCreateGroup; atContentInsert: DoContentInsert; end else if (Source = dsControl) and SourceItem.CanRemove then SourceItem.Parent := nil; Control.Update; Control.Modified; end; inherited; end; procedure TdxLayoutControlDragAndDropObject.Init(ASource: TdxLayoutDragSource; ASourceItem: TdxCustomLayoutItem); begin Control.Update; // to update selections Source := ASource; SourceItem := ASourceItem; end; { TCustomizedControls } type TCustomizedControls = class private FForms: TList; FItems: TList; FPrevEnableds: TList; function GetCount: Integer; function GetForm(Index: Integer): TCustomForm; function GetItem(Index: Integer): TdxCustomLayoutControl; protected function IndexOf(AItem: TdxCustomLayoutControl): Integer; procedure InternalAddItem(AItem: TdxCustomLayoutControl); procedure InternalRemoveItem(AItem: TdxCustomLayoutControl); procedure InternalSetForm(AControl: TdxCustomLayoutControl; AForm: TCustomForm); property Count: Integer read GetCount; property Forms[Index: Integer]: TCustomForm read GetForm; property Items[Index: Integer]: TdxCustomLayoutControl read GetItem; public constructor Create; destructor Destroy; override; function ProcessMouseMessage(AMessage: WPARAM; AMessageData: TMouseHookStruct): Boolean; procedure ProcessWndProcMessage(AMessageData: TCWPStruct); class procedure AddItem(AItem: TdxCustomLayoutControl); class procedure RemoveItem(AItem: TdxCustomLayoutControl); class procedure SetForm(AControl: TdxCustomLayoutControl; AForm: TCustomForm); class function IsCustomized(AControl: TdxCustomLayoutControl): Boolean; end; var CustomizedControls: TCustomizedControls; MouseHookHandle: HHOOK; WndProcHookHandle: HHOOK; function MouseHookProc(Code: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; var AProcessed: Boolean; begin if Code = HC_ACTION then AProcessed := CustomizedControls.ProcessMouseMessage(wParam, PMouseHookStruct(lParam)^) else AProcessed := False; Result := CallNextHookEx(MouseHookHandle, Code, wParam, lParam); if AProcessed then Result := 1; end; function WndProcHookProc(Code: Integer; wParam: WPARAM; lParam: LPARAM): LRESULT; stdcall; begin if Code = HC_ACTION then CustomizedControls.ProcessWndProcMessage(PCWPStruct(lParam)^); Result := CallNextHookEx(WndProcHookHandle, Code, wParam, lParam); end; constructor TCustomizedControls.Create; begin inherited; FForms := TList.Create; FItems := TList.Create; FPrevEnableds := TList.Create; SetHook(MouseHookHandle, WH_MOUSE, MouseHookProc); SetHook(WndProcHookHandle, WH_CALLWNDPROC, WndProcHookProc); end; destructor TCustomizedControls.Destroy; begin ReleaseHook(WndProcHookHandle); ReleaseHook(MouseHookHandle); FPrevEnableds.Free; FItems.Free; FForms.Free; inherited; end; function TCustomizedControls.GetCount: Integer; begin Result := FItems.Count; end; function TCustomizedControls.GetForm(Index: Integer): TCustomForm; begin Result := FForms[Index]; end; function TCustomizedControls.GetItem(Index: Integer): TdxCustomLayoutControl; begin Result := TdxCustomLayoutControl(FItems[Index]); end; function TCustomizedControls.IndexOf(AItem: TdxCustomLayoutControl): Integer; begin Result := FItems.IndexOf(AItem); end; procedure TCustomizedControls.InternalAddItem(AItem: TdxCustomLayoutControl); begin FPrevEnableds.Add(Pointer(not EnableWindow(AItem.Handle, False))); FItems.Add(AItem); FForms.Count := Count; end; procedure TCustomizedControls.InternalRemoveItem(AItem: TdxCustomLayoutControl); var AIndex: Integer; begin AIndex := FItems.Remove(AItem); if AItem.HandleAllocated then EnableWindow(AItem.Handle, Boolean(FPrevEnableds[AIndex])); FPrevEnableds.Delete(AIndex); end; procedure TCustomizedControls.InternalSetForm(AControl: TdxCustomLayoutControl; AForm: TCustomForm); begin FForms[IndexOf(AControl)] := AForm; end; function TCustomizedControls.ProcessMouseMessage(AMessage: WPARAM; AMessageData: TMouseHookStruct): Boolean; var I: Integer; AItem: TdxCustomLayoutControl; P: TPoint; AControl: TWinControl; begin Result := False; for I := 0 to Count - 1 do begin AItem := Items[I]; if (AItem.Handle = AMessageData.hwnd) or (AItem.Parent.Handle = AMessageData.hwnd) and (GetCapture = 0) and PtInRect(AItem.BoundsRect, AItem.Parent.ScreenToClient(AMessageData.pt)) then begin Result := AMessage <> WM_MOUSEMOVE; // to provide normal cursor processing (to call WM_SETCURSOR) P := AItem.ScreenToClient(AMessageData.pt); if GetCapture = AItem.Handle then AControl := AItem else if AItem.HScrollBarVisible and PtInRect(AItem.HScrollBar.BoundsRect, P) then AControl := AItem.HScrollBar else if AItem.VScrollBarVisible and PtInRect(AItem.VScrollBar.BoundsRect, P) then AControl := AItem.VScrollBar else AControl := AItem; P := AControl.ScreenToClient(AMessageData.pt); AControl.Perform(AMessage, GetMouseKeys, LPARAM(PointToSmallPoint(P))); Break; end; end; end; procedure TCustomizedControls.ProcessWndProcMessage(AMessageData: TCWPStruct); var I: Integer; AParentForm: TWinControl; AHidden: Boolean; procedure CheckWindow(AWindow: HWND); const SetWindowPosParams: array[Boolean] of Integer = (SWP_SHOWWINDOW, SWP_HIDEWINDOW); begin SetWindowPos(AWindow, 0, 0, 0, 0, 0, SWP_NOZORDER or SWP_NOMOVE or SWP_NOSIZE or SWP_NOACTIVATE or SetWindowPosParams[AHidden]); end; begin with AMessageData do if message = WM_SIZE then for I := 0 to Count - 1 do begin AParentForm := GetParentForm(Items[I]); if (AParentForm <> nil) and (Forms[I] <> nil) and Forms[I].Visible then begin AHidden := IsIconic(AParentForm.Handle) or IsIconic(Application.Handle); CheckWindow(Forms[I].Handle); end; end; end; class procedure TCustomizedControls.AddItem(AItem: TdxCustomLayoutControl); begin if CustomizedControls = nil then CustomizedControls := Self.Create; CustomizedControls.InternalAddItem(AItem); end; class procedure TCustomizedControls.RemoveItem(AItem: TdxCustomLayoutControl); begin CustomizedControls.InternalRemoveItem(AItem); if CustomizedControls.Count = 0 then FreeAndNil(CustomizedControls); end; class procedure TCustomizedControls.SetForm(AControl: TdxCustomLayoutControl; AForm: TCustomForm); begin CustomizedControls.InternalSetForm(AControl, AForm); end; class function TCustomizedControls.IsCustomized(AControl: TdxCustomLayoutControl): Boolean; begin Result := (CustomizedControls <> nil) and (CustomizedControls.IndexOf(AControl) <> -1); end; { TdxCustomLayoutControl } constructor TdxCustomLayoutControl.Create(AOwner: TComponent); begin inherited; ControlStyle := ControlStyle + [csAcceptsControls, csOpaque]; {$IFDEF DELPHI7} ParentBackground := False; {$ENDIF} with inherited LookAndFeel do begin Kind := lfStandard; NativeStyle := True; end; TabStop := False; Width := 300; Height := 250; FAbsoluteItems := TList.Create; FAutoControlAlignment := True; FAutoControlTabOrders := True; FAvailableItems := TList.Create; FBoldFont := TFont.Create; RefreshBoldFont; FCustomizeFormClass := TLayoutCustomizeForm; GetLookAndFeel.AddUser(Self); SetItems(GetDefaultGroupClass.Create(Owner{nil})); FItems.Hidden := True; FMayPack := True; //FGroups.UseIndent := False; CreateConstraints; if IsDesigning then dxLayoutDesigner.RegisterComponent(Self); end; destructor TdxCustomLayoutControl.Destroy; begin if IsDesigning then dxLayoutDesigner.UnregisterComponent(Self); Customization := False; if not IsDesigning then begin if FStoreInIniFile then SaveToIniFile(FIniFileName); if FStoreInRegistry then SaveToRegistry(FRegistryPath); end; SetItems(nil); DestroyAvailableItems; FAvailableItems.Free; LookAndFeel := nil; GetLookAndFeel.RemoveUser(Self); DestroyConstraints; dxLayoutTextMetrics.Unregister(FBoldFont); dxLayoutTextMetrics.Unregister(Font); FBoldFont.Free; FAbsoluteItems.Free; inherited; end; function TdxCustomLayoutControl.GetAbsoluteItem(Index: Integer): TdxCustomLayoutItem; begin Result := FAbsoluteItems[Index]; end; function TdxCustomLayoutControl.GetAbsoluteItemCount: Integer; begin Result := FAbsoluteItems.Count; end; function TdxCustomLayoutControl.GetAlignmentConstraint(Index: Integer): TdxLayoutAlignmentConstraint; begin Result := FAlignmentConstraints[Index]; end; function TdxCustomLayoutControl.GetAlignmentConstraintCount: Integer; begin Result := FAlignmentConstraints.Count; end; function TdxCustomLayoutControl.GetAvailableItem(Index: Integer): TdxCustomLayoutItem; begin Result := FAvailableItems[Index]; end; function TdxCustomLayoutControl.GetAvailableItemCount: Integer; begin Result := FAvailableItems.Count; end; function TdxCustomLayoutControl.GetIsCustomizationMode: Boolean; begin Result := TCustomizedControls.IsCustomized(Self); end; function TdxCustomLayoutControl.GetContentBounds: TRect; begin Result := ViewInfo.ContentBounds; end; function TdxCustomLayoutControl.GetOccupiedClientWidth: Integer; begin Result := ViewInfo.ItemsViewInfo.CalculateWidth; end; function TdxCustomLayoutControl.GetOccupiedClientHeight: Integer; begin Result := ViewInfo.ItemsViewInfo.CalculateHeight; end; function TdxCustomLayoutControl.GetLayoutDirection: TdxLayoutDirection; begin Result := FItems.LayoutDirection; end; procedure TdxCustomLayoutControl.SetAutoContentSizes(Value: TdxLayoutAutoContentSizes); begin if FAutoContentSizes <> Value then begin FAutoContentSizes := Value; LayoutChanged; end; end; procedure TdxCustomLayoutControl.SetAutoControlAlignment(Value: Boolean); begin if FAutoControlAlignment <> Value then begin FAutoControlAlignment := Value; LayoutChanged; end; end; procedure TdxCustomLayoutControl.SetAutoControlTabOrders(Value: Boolean); begin if FAutoControlTabOrders <> Value then begin FAutoControlTabOrders := Value; LayoutChanged; end; end; procedure TdxCustomLayoutControl.SetCustomization(Value: Boolean); begin if (FCustomization <> Value) and (not Value or HandleAllocated) then begin FCustomization := Value; LayoutChanged; if FCustomization then begin IsCustomizationMode := True; FCustomizeForm := TLayoutCustomizeFormClass(CustomizeFormClass).Create(Self); FCustomizeForm.Show; CustomizationModeForm := FCustomizeForm; end else begin with FCustomizeForm do if not (csDestroying in ComponentState) then Free; FCustomizeForm := nil; IsCustomizationMode := False; end; DoCustomization; end; end; procedure TdxCustomLayoutControl.SetCustomizationModeForm(Value: TCustomForm); begin TCustomizedControls.SetForm(Self, Value); end; procedure TdxCustomLayoutControl.SetIsCustomizationMode(Value: Boolean); begin if IsCustomizationMode <> Value then if Value then TCustomizedControls.AddItem(Self) else TCustomizedControls.RemoveItem(Self); end; procedure TdxCustomLayoutControl.SetIsPlaceControlsNeeded(Value: Boolean); begin if FIsPlaceControlsNeeded <> Value then begin FIsPlaceControlsNeeded := Value; if Value then if (LookAndFeel <> nil) and TLookAndFeelAccess(LookAndFeel).ForceControlArrangement then SendMessage(Handle, CM_PLACECONTROLS, 0, 0) else PostMessage(Handle, CM_PLACECONTROLS, 0, 0); end; end; procedure TdxCustomLayoutControl.SetItems(Value: TdxLayoutGroup); begin ItemWithMouse := nil; DestroyHandlers; FItems.Free; FItems := Value; if Value = nil then Exit; FItems.Container := Self; CreateHandlers; end; procedure TdxCustomLayoutControl.SetItemWithMouse(Value: TdxCustomLayoutItem); begin if FItemWithMouse <> Value then begin if FItemWithMouse <> nil then FItemWithMouse.MouseLeave; FItemWithMouse := Value; if FItemWithMouse <> nil then FItemWithMouse.MouseEnter; end; end; procedure TdxCustomLayoutControl.SetLayoutDirection(Value: TdxLayoutDirection); begin FItems.LayoutDirection := Value; end; procedure TdxCustomLayoutControl.SetLeftPos(Value: Integer); var APrevLeftPos: Integer; begin CheckLeftPos(Value); if FLeftPos <> Value then begin Update; APrevLeftPos := FLeftPos; FLeftPos := Value; LayoutChanged; ScrollContent(APrevLeftPos, FLeftPos, True); end; end; procedure TdxCustomLayoutControl.SetLookAndFeel(Value: TdxCustomLayoutLookAndFeel); begin if FLookAndFeel <> Value then begin GetLookAndFeel.RemoveUser(Self); FLookAndFeel := Value; GetLookAndFeel.AddUser(Self); LookAndFeelChanged; end; end; procedure TdxCustomLayoutControl.SetShowHiddenGroupsBounds(Value: Boolean); begin if FShowHiddenGroupsBounds <> Value then begin FShowHiddenGroupsBounds := Value; LayoutChanged; end; end; procedure TdxCustomLayoutControl.SetTopPos(Value: Integer); var APrevTopPos: Integer; begin CheckTopPos(Value); if FTopPos <> Value then begin Update; APrevTopPos := FTopPos; FTopPos := Value; LayoutChanged; ScrollContent(APrevTopPos, FTopPos, False); end; end; procedure TdxCustomLayoutControl.CreateHandlers; begin FPainter := GetPainterClass.Create(Self); FViewInfo := GetViewInfoClass.Create(Self); end; procedure TdxCustomLayoutControl.DestroyHandlers; begin FreeAndNil(FViewInfo); FreeAndNil(FPainter); end; procedure TdxCustomLayoutControl.CreateConstraints; begin FAlignmentConstraints := TList.Create; end; procedure TdxCustomLayoutControl.DestroyConstraints; var I: Integer; begin for I := AlignmentConstraintCount - 1 downto 0 do AlignmentConstraints[I].Free; FreeAndNil(FAlignmentConstraints); end; procedure TdxCustomLayoutControl.AddAlignmentConstraint(AConstraint: TdxLayoutAlignmentConstraint); begin FAlignmentConstraints.Add(AConstraint); AConstraint.FControl := Self; SetComponentName(AConstraint, Name + 'AlignmentConstraint', IsDesigning, IsLoading); end; procedure TdxCustomLayoutControl.RemoveAlignmentConstraint(AConstraint: TdxLayoutAlignmentConstraint); begin FAlignmentConstraints.Remove(AConstraint); AConstraint.FControl := nil; end; procedure TdxCustomLayoutControl.RefreshBoldFont; begin FBoldFont.Assign(Font); with FBoldFont do Style := Style + [fsBold]; dxLayoutTextMetrics.Unregister(FBoldFont); end; procedure TdxCustomLayoutControl.AddAbsoluteItem(AItem: TdxCustomLayoutItem); begin FAbsoluteItems.Add(AItem); end; procedure TdxCustomLayoutControl.RemoveAbsoluteItem(AItem: TdxCustomLayoutItem); begin FAbsoluteItems.Remove(AItem); end; procedure TdxCustomLayoutControl.AddAvailableItem(AItem: TdxCustomLayoutItem); begin FAvailableItems.Add(AItem); AItem.Container := Self; AvailableItemListChanged(AItem, True); end; procedure TdxCustomLayoutControl.RemoveAvailableItem(AItem: TdxCustomLayoutItem); begin FAvailableItems.Remove(AItem); AvailableItemListChanged(AItem, False); end; procedure TdxCustomLayoutControl.DestroyAvailableItems; var I: Integer; begin for I := AvailableItemCount - 1 downto 0 do AvailableItems[I].Free; end; procedure TdxCustomLayoutControl.WMNCDestroy(var Message: TWMNCDestroy); begin IsPlaceControlsNeeded := False; inherited; end; {$IFNDEF DELPHI7} procedure TdxCustomLayoutControl.WMPrintClient(var Message: TWMPrintClient); begin with Message do if Result <> 1 then if ((Flags and PRF_CHECKVISIBLE) = 0) or Visible then PaintHandler(TWMPaint(Message)) else inherited else inherited; end; {$ENDIF} procedure TdxCustomLayoutControl.CMControlChange(var Message: TCMControlChange); var AControl: TControl; P: TPoint; AHitTest: TdxCustomLayoutHitTest; AGroup: TdxLayoutGroup; AIndex: Integer; begin inherited; if not (IsLoading or IsDestroying) then begin AControl := Message.Control; if Message.Inserting then begin if (csAncestor in AControl.ComponentState) or IsInternalControl(AControl) or (FindItem(AControl) <> nil) then Exit; P := AControl.BoundsRect.TopLeft; AHitTest := ViewInfo.GetHitTest(P); if AHitTest is TdxCustomLayoutItemHitTest then if AHitTest is TdxLayoutGroupHitTest then AGroup := TdxLayoutGroupHitTest(AHitTest).Item else AGroup := TdxCustomLayoutItemHitTest(AHitTest).Item.Parent else AGroup := Items; AIndex := AGroup.ViewInfo.GetInsertionPos(P); AGroup.CreateItemForControl(AControl).VisibleIndex := AIndex; end else FindItem(AControl).Free; end; end; procedure TdxCustomLayoutControl.CMDialogChar(var Message: TCMDialogChar); begin if FItems.ProcessDialogChar(Message.CharCode) then Message.Result := 1 else inherited; end; {procedure TdxCustomLayoutControl.CMFreeItem(var Message: TMessage); begin TObject(Message.WParam).Free; end;} procedure TdxCustomLayoutControl.CMPlaceControls(var Message: TMessage); begin IsPlaceControlsNeeded := False; Painter.PlaceControls; end; procedure TdxCustomLayoutControl.AlignControls(AControl: TControl; var Rect: TRect); begin end; function TdxCustomLayoutControl.AllowAutoDragAndDropAtDesignTime(X, Y: Integer; Shift: TShiftState): Boolean; begin Result := not GetDesignHitTest(X, Y, Shift); end; function TdxCustomLayoutControl.AllowDragAndDropWithoutFocus: Boolean; begin Result := FCustomization; end; procedure TdxCustomLayoutControl.BoundsChanged; begin inherited; LayoutChanged; end; function TdxCustomLayoutControl.CanDrag(X, Y: Integer): Boolean; begin Result := inherited CanDrag(X, Y) and not IsDesigning; end; procedure TdxCustomLayoutControl.CreateParams(var Params: TCreateParams); begin inherited; with Params do WindowClass.style := WindowClass.style and not (CS_HREDRAW or CS_VREDRAW); end; procedure TdxCustomLayoutControl.FontChanged; begin inherited; dxLayoutTextMetrics.Unregister(Font); RefreshBoldFont; LookAndFeelChanged; end; procedure TdxCustomLayoutControl.GetChildren(Proc: TGetChildProc; Root: TComponent); var I: Integer; begin inherited; if Owner = Root then begin Proc(FItems); for I := 0 to AvailableItemCount - 1 do Proc(AvailableItems[I]); for I := 0 to AlignmentConstraintCount - 1 do Proc(AlignmentConstraints[I]); end; end; function TdxCustomLayoutControl.GetCursor(X, Y: Integer): TCursor; var AHitTest: TdxCustomLayoutHitTest; begin AHitTest := ViewInfo.GetHitTest(X, Y); if AHitTest is TdxCustomLayoutItemHitTest then Result := TdxCustomLayoutItemHitTest(AHitTest).Item.GetCursor(X, Y) else Result := crDefault; if Result = crDefault then Result := inherited GetCursor(X, Y); end; function TdxCustomLayoutControl.GetDesignHitTest(X, Y: Integer; Shift: TShiftState): Boolean; var AHitTest: TdxCustomLayoutHitTest; begin Result := inherited GetDesignHitTest(X, Y, Shift); if not Result then begin AHitTest := ViewInfo.GetHitTest(X, Y); Result := not (ssRight in Shift) and not FRightButtonPressed and (AHitTest is TdxCustomLayoutItemHitTest) and not TdxCustomLayoutItemHitTest(AHitTest).Item.IsRoot and not dxLayoutDesigner.IsToolSelected; end; FRightButtonPressed := ssRight in Shift; end; function TdxCustomLayoutControl.HasBackground: Boolean; begin Result := {$IFDEF DELPHI7}ThemeServices.ThemesEnabled and ParentBackground{$ELSE}inherited HasBackground{$ENDIF}; end; procedure TdxCustomLayoutControl.Loaded; begin inherited; if not IsDesigning then begin if FStoreInIniFile then LoadFromIniFile(FIniFileName); if FStoreInRegistry then LoadFromRegistry(FRegistryPath); end; LookAndFeelChanged; end; procedure TdxCustomLayoutControl.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin AssignItemWithMouse(X, Y); if ItemWithMouse <> nil then ItemWithMouse.MouseDown(Button, Shift, X, Y); inherited; end; procedure TdxCustomLayoutControl.MouseLeave(AControl: TControl); begin inherited; ItemWithMouse := nil; end; procedure TdxCustomLayoutControl.MouseMove(Shift: TShiftState; X, Y: Integer); begin AssignItemWithMouse(X, Y); if ItemWithMouse <> nil then ItemWithMouse.MouseMove(Shift, X, Y); inherited; end; procedure TdxCustomLayoutControl.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin inherited; AssignItemWithMouse(X, Y); if ItemWithMouse <> nil then ItemWithMouse.MouseUp(Button, Shift, X, Y); end; procedure TdxCustomLayoutControl.Paint; begin inherited; if not IsUpdateLocked then Painter.Paint; end; procedure TdxCustomLayoutControl.SetName(const Value: TComponentName); var AOldName: string; function GetItem(ACaller: TComponent; Index: Integer): TComponent; begin with TdxCustomLayoutControl(ACaller) do if Index = 0 then Result := Items else Result := AbsoluteItems[Index - 1]; end; function GetAlignmentConstraint(ACaller: TComponent; Index: Integer): TComponent; begin Result := TdxCustomLayoutControl(ACaller).AlignmentConstraints[Index]; end; begin AOldName := Name; inherited; RenameComponents(Self, Owner, Name, AOldName, 1 + AbsoluteItemCount, @GetItem); RenameComponents(Self, Owner, Name, AOldName, AlignmentConstraintCount, @GetAlignmentConstraint); if IsDesigning then dxLayoutDesigner.ComponentNameChanged(Self); end; {$IFDEF DELPHI7} procedure TdxCustomLayoutControl.SetParentBackground(Value: Boolean); begin if Value then ControlStyle := ControlStyle - [csOpaque] else ControlStyle := ControlStyle + [csOpaque]; inherited; end; {$ENDIF} procedure TdxCustomLayoutControl.WndProc(var Message: TMessage); begin if (WM_MOUSEFIRST <= Message.Msg) and (Message.Msg <= WM_MOUSELAST) and IsCustomizationMode then Dispatch(Message) else inherited; end; procedure TdxCustomLayoutControl.WriteState(Writer: TWriter); begin if HandleAllocated then SendMessage(Handle, WM_SETREDRAW, 0, 0); try Items.RestoreItemControlSize; inherited; finally if HandleAllocated then SendMessage(Handle, WM_SETREDRAW, 1, 0); LayoutChanged; end; end; procedure TdxCustomLayoutControl.InitScrollBarsParameters; begin inherited; SetScrollBarInfo(sbHorizontal, 0, ViewInfo.ContentWidth - 1, ScrollStep, ViewInfo.ClientWidth, LeftPos, True, True); SetScrollBarInfo(sbVertical, 0, ViewInfo.ContentHeight - 1, ScrollStep, ViewInfo.ClientHeight, TopPos, True, True); end; function TdxCustomLayoutControl.NeedsToBringInternalControlsToFront: Boolean; begin Result := True; end; procedure TdxCustomLayoutControl.Scroll(AScrollBarKind: TScrollBarKind; AScrollCode: TScrollCode; var AScrollPos: Integer); function GetContentPos: Integer; begin if AScrollBarKind = sbHorizontal then Result := LeftPos else Result := TopPos; end; procedure SetContentPos(Value: Integer); begin if AScrollBarKind = sbHorizontal then LeftPos := Value else TopPos := Value; end; function GetPageScrollStep: Integer; begin if AScrollBarKind = sbHorizontal then Result := ClientWidth else Result := ClientHeight; end; begin inherited; case AScrollCode of scLineUp: SetContentPos(GetContentPos - ScrollStep); scLineDown: SetContentPos(GetContentPos + ScrollStep); scPageUp: SetContentPos(GetContentPos - GetPageScrollStep); scPageDown: SetContentPos(GetContentPos + GetPageScrollStep); scTrack: SetContentPos(AScrollPos); end; AScrollPos := GetContentPos; end; function TdxCustomLayoutControl.CanDragAndDrop: Boolean; begin Result := not IsDesigning or not (csInline in Owner.ComponentState); end; function TdxCustomLayoutControl.GetDragAndDropObjectClass: TcxDragAndDropObjectClass; begin Result := TdxLayoutControlDragAndDropObject; end; function TdxCustomLayoutControl.StartDragAndDrop(const P: TPoint): Boolean; var AHideHiddenGroupsFromHitTest: Boolean; AHitTest: TdxCustomLayoutHitTest; AItem: TdxCustomLayoutItem; begin Result := False; if IsCustomization and CanDragAndDrop then begin AHideHiddenGroupsFromHitTest := ViewInfo.HideHiddenGroupsFromHitTest; ViewInfo.HideHiddenGroupsFromHitTest := not IsDesigning; try AHitTest := ViewInfo.GetHitTest(P); finally ViewInfo.HideHiddenGroupsFromHitTest := AHideHiddenGroupsFromHitTest; end; if AHitTest is TdxCustomLayoutItemHitTest then begin AItem := TdxCustomLayoutItemHitTest(AHitTest).Item; if not AItem.IsRoot then begin (DragAndDropObject as TdxLayoutControlDragAndDropObject).Init(dsControl, AItem); Result := True; end end; end; end; function TdxCustomLayoutControl.GetLookAndFeel: TdxCustomLayoutLookAndFeel; begin Result := FLookAndFeel; if Result = nil then Result := dxLayoutDefaultLookAndFeel; end; procedure TdxCustomLayoutControl.BeginLookAndFeelDestroying; begin BeginUpdate; end; procedure TdxCustomLayoutControl.EndLookAndFeelDestroying; begin EndUpdate; end; procedure TdxCustomLayoutControl.LookAndFeelChanged; begin UpdateLookAndFeelSkinName; if (LookAndFeel <> nil) and not DoubleBuffered then DoubleBuffered := LookAndFeel.NeedDoubleBuffered; if (FItems <> nil) and (GetLookAndFeel <> nil) then FItems.LookAndFeelChangedImpl; end; procedure TdxCustomLayoutControl.LookAndFeelDestroyed; begin LookAndFeel := nil; end; procedure TdxCustomLayoutControl.SelectionChanged; begin Items.SelectionChanged; end; function TdxCustomLayoutControl.GetPainterClass: TdxLayoutControlPainterClass; begin Result := TdxLayoutControlPainter; end; function TdxCustomLayoutControl.GetViewInfoClass: TdxLayoutControlViewInfoClass; begin Result := TdxLayoutControlViewInfo; end; procedure TdxCustomLayoutControl.AssignItemWithMouse(X, Y: Integer); var AHitTest: TdxCustomLayoutHitTest; begin AHitTest := ViewInfo.GetHitTest(X, Y); if AHitTest is TdxCustomLayoutItemHitTest then ItemWithMouse := TdxCustomLayoutItemHitTest(AHitTest).Item else ItemWithMouse := nil; end; procedure TdxCustomLayoutControl.AvailableItemListChanged(AItem: TdxCustomLayoutItem; AIsItemAdded: Boolean); begin if FCustomization then TLayoutCustomizeForm(FCustomizeForm).AvailableItemListChanged(Aitem, AIsItemAdded); end; function TdxCustomLayoutControl.CalculateCustomizeFormBounds(const AFormBounds: TRect): TRect; var AControlBounds, ADesktopBounds: TRect; begin AControlBounds := BoundsRect; MapWindowPoints(Parent.Handle, 0, AControlBounds, 2); ADesktopBounds := GetDesktopWorkArea(AControlBounds.TopLeft); Result := AFormBounds; with AControlBounds do begin if (ADesktopBounds.Right - Right >= Result.Right - Result.Left) or (ADesktopBounds.Right - Right >= Left - ADesktopBounds.Left) then OffsetRect(Result, Right - Result.Left, 0) else OffsetRect(Result, Left - Result.Right, 0); OffsetRect(Result, 0, (Top + Bottom - (Result.Bottom - Result.Top)) div 2 - Result.Top); end; with ADesktopBounds do begin if Result.Left < Left then OffsetRect(Result, Left - Result.Left, 0); if Result.Right > Right then OffsetRect(Result, Right - Result.Right, 0); if Result.Top < Top then OffsetRect(Result, 0, Top - Result.Top); end; end; function TdxCustomLayoutControl.CanMultiSelect: Boolean; begin Result := dxLayoutDesigner.GetDesigner(Self) <> nil; end; function TdxCustomLayoutControl.CanShowSelection: Boolean; begin Result := {$IFDEF DELPHI6}True{$ELSE}CanMultiSelect{$ENDIF}; end; procedure TdxCustomLayoutControl.CheckLeftPos(var Value: Integer); begin if Value > ViewInfo.ContentWidth - ViewInfo.ClientWidth then Value := ViewInfo.ContentWidth - ViewInfo.ClientWidth; if Value < 0 then Value := 0; end; procedure TdxCustomLayoutControl.CheckPositions; begin LeftPos := LeftPos; TopPos := TopPos; end; procedure TdxCustomLayoutControl.CheckTopPos(var Value: Integer); begin if Value > ViewInfo.ContentHeight - ViewInfo.ClientHeight then Value := ViewInfo.ContentHeight - ViewInfo.ClientHeight; if Value < 0 then Value := 0; end; procedure TdxCustomLayoutControl.DoCustomization; begin if Assigned(FOnCustomization) then FOnCustomization(Self); end; procedure TdxCustomLayoutControl.DragAndDropBegan; begin if FCustomization then TLayoutCustomizeForm(FCustomizeForm).DragAndDropBegan; end; function TdxCustomLayoutControl.GetAlignmentConstraintClass: TdxLayoutAlignmentConstraintClass; begin Result := TdxLayoutAlignmentConstraint; end; function TdxCustomLayoutControl.GetDefaultGroupClass: TdxLayoutGroupClass; begin Result := TdxLayoutGroup; end; function TdxCustomLayoutControl.GetDefaultItemClass: TdxLayoutItemClass; begin Result := TdxLayoutItem; end; function TdxCustomLayoutControl.IsCustomization: Boolean; begin Result := Customization or IsDesigning; end; function TdxCustomLayoutControl.IsUpdateLocked: Boolean; begin Result := FUpdateLockCount <> 0; end; procedure TdxCustomLayoutControl.LayoutChanged; begin if FItems <> nil then FItems.Changed; end; {procedure TdxCustomLayoutControl.PostFree(AObject: TObject); begin if HandleAllocated then PostMessage(Handle, CM_FREEITEM, WParam(AObject), 0); end;} procedure TdxCustomLayoutControl.ScrollContent(APrevPos, ACurPos: Integer; AHorzScrolling: Boolean); var ADelta: Integer; AScrollBounds: TRect; begin if not HandleAllocated then Exit; ADelta := -(ACurPos - APrevPos); AScrollBounds := ViewInfo.ClientBounds; //ValidateRect(Handle, @AScrollBounds); ScrollWindowEx(Handle, Ord(AHorzScrolling) * ADelta, Ord(not AHorzScrolling) * ADelta, @AScrollBounds, nil, 0, nil, SW_INVALIDATE or SW_ERASE{ or SW_SCROLLCHILDREN bug in WinAPI}); UpdateWindow(Handle); end; procedure TdxCustomLayoutControl.UpdateLookAndFeelSkinName; var ASkinName: string; begin if LookAndFeel = nil then ASkinName := '' else ASkinName := LookAndFeel.InternalName; with inherited LookAndFeel do begin NativeStyle := ASkinName = ''; SkinName := ASkinName; end; end; type PdxLayoutItemPosition = ^TdxLayoutItemPosition; TdxLayoutItemPosition = record Item: TdxCustomLayoutItem; ParentName: string; Index: Integer; end; function ComparePositions(Item1, Item2: Pointer): Integer; begin Result := PdxLayoutItemPosition(Item1).Index - PdxLayoutItemPosition(Item2).Index; end; procedure TdxCustomLayoutControl.LoadFromCustomIniFile(AIniFile: TCustomIniFile; const ARootSection: string); var AItems: TList; APositions: TList; AItemCount, I: Integer; function CreateItemsList: TList; begin Result := TList.Create; Result.Count := AbsoluteItemCount; Move(FAbsoluteItems.List^, Result.List^, Result.Count * SizeOf(Pointer)); end; procedure PrepareItems; var I: Integer; begin for I := 0 to AbsoluteItemCount - 1 do AbsoluteItems[I].Parent := nil; end; function GetItemSection(AIndex: Integer): string; begin Result := 'Item' + IntToStr(AIndex); if ARootSection <> '' then Result := ARootSection + '\' + Result; end; procedure AddPosition(AItem: TdxCustomLayoutItem; const AParentName: string; AIndex: Integer); var APosition: PdxLayoutItemPosition; begin New(APosition); with APosition^ do begin Item := AItem; ParentName := AParentName; Index := AIndex; end; APositions.Add(APosition); end; procedure LoadItem(const ASection: string); var AName, AParentName: string; AItem: TdxCustomLayoutItem; AIndex: Integer; AGroup: TdxLayoutGroup; begin AName := AIniFile.ReadString(ASection, 'Name', ''); if AName = '' then Exit; AItem := FindItem(AName); AItems.Remove(AItem); if AItem = nil then begin AItem := CreateGroup; AItem.Name := AName; end; AParentName := AIniFile.ReadString(ASection, 'ParentName', ''); AIndex := AIniFile.ReadInteger(ASection, 'Index', -1); AddPosition(AItem, AParentName, AIndex); if AItem is TdxLayoutGroup then begin AGroup := TdxLayoutGroup(AItem); AGroup.Hidden := AIniFile.ReadBool(ASection, 'Hidden', False); AGroup.LayoutDirection := TdxLayoutDirection(AIniFile.ReadInteger(ASection, 'LayoutDirection', 0)); if AGroup.IsUserDefined and not AGroup.Hidden then AGroup.Caption := AIniFile.ReadString(ASection, 'Caption', ''); end; end; procedure DestroyNonLoadedItems; var I: Integer; function CanDestroy(AItem: TdxCustomLayoutItem): Boolean; function ItemExists(AItem: Pointer): Boolean; var I: Integer; begin for I := 0 to AbsoluteItemCount - 1 do begin Result := AbsoluteItems[I] = AItem; if Result then Exit; end; Result := False; end; begin Result := ItemExists(AItem) and (AItem is TdxLayoutGroup) and TdxLayoutGroup(AItem).CanDestroy; end; begin for I := 0 to AItems.Count - 1 do if CanDestroy(AItems[I]) then TObject(AItems[I]).Free; end; procedure UpdatePositions; var I: Integer; APosition: PdxLayoutItemPosition; begin APositions.Sort(ComparePositions); for I := 0 to APositions.Count - 1 do begin APosition := PdxLayoutItemPosition(APositions[I]); with APosition^ do begin Item.Parent := FindItem(ParentName) as TdxLayoutGroup; Item.Index := Index; end; end; end; begin AItems := CreateItemsList; APositions := TList.Create; try AItemCount := AIniFile.ReadInteger(ARootSection, 'ItemCount', -1); if AItemCount = -1 then Exit; BeginUpdate; try MayPack := False; try PrepareItems; for I := 0 to AItemCount - 1 do LoadItem(GetItemSection(I)); DestroyNonLoadedItems; UpdatePositions; finally MayPack := True; Items.Pack; end; finally EndUpdate; end; finally for I := 0 to APositions.Count - 1 do Dispose(PdxLayoutItemPosition(APositions[I])); APositions.Free; AItems.Free; end; end; function CompareItemsByIsUserDefined(Item1, Item2: Pointer): Integer; var AItem1, AItem2: TdxCustomLayoutItem; begin AItem1 := TdxCustomLayoutItem(Item1); AItem2 := TdxCustomLayoutItem(Item2); if (AItem1 is TdxLayoutGroup) and (AItem2 is TdxLayoutGroup) then Result := Ord(TdxLayoutGroup(AItem2).IsUserDefined) - Ord(TdxLayoutGroup(AItem1).IsUserDefined) else Result := Ord(AItem2 is TdxLayoutGroup) - Ord(AItem1 is TdxLayoutGroup); if Result = 0 then Result := Integer(Item1) - Integer(Item2); end; procedure TdxCustomLayoutControl.SaveToCustomIniFile(AIniFile: TCustomIniFile; const ARootSection: string); var AItems: TList; I: Integer; function CreateItemsList: TList; begin Result := TList.Create; Result.Count := AbsoluteItemCount; Move(FAbsoluteItems.List^, Result.List^, Result.Count * SizeOf(Pointer)); Result.Sort(CompareItemsByIsUserDefined); Result.Insert(0, Items); end; function GetItemSection(AIndex: Integer): string; begin Result := 'Item' + IntToStr(AIndex); if ARootSection <> '' then Result := ARootSection + '\' + Result; end; procedure DeletePrevSettings; var ABaseSectionName: string; ASections: TStringList; I: Integer; begin ABaseSectionName := ARootSection; if ABaseSectionName <> '' then ABaseSectionName := ABaseSectionName + '\'; ASections := TStringList.Create; try AIniFile.ReadSections(ASections); for I := 0 to ASections.Count - 1 do if Copy(ASections[I], 1, Length(ABaseSectionName)) = ABaseSectionName then AIniFile.EraseSection(ASections[I]); finally ASections.Free; end; end; procedure SaveItem(const ASection: string; AItem: TdxCustomLayoutItem); var AGroup: TdxLayoutGroup; function GetParentName: string; begin if AItem.Parent <> nil then Result := AItem.Parent.Name else Result := ''; end; begin AIniFile.WriteString(ASection, 'Name', AItem.Name); AIniFile.WriteString(ASection, 'ParentName', GetParentName); AIniFile.WriteInteger(ASection, 'Index', AItem.Index); if AItem is TdxLayoutGroup then begin AGroup := TdxLayoutGroup(AItem); AIniFile.WriteBool(ASection, 'Hidden', AGroup.Hidden); AIniFile.WriteInteger(ASection, 'LayoutDirection', Integer(AGroup.LayoutDirection)); if AGroup.IsUserDefined and not AGroup.Hidden then AIniFile.WriteString(ASection, 'Caption', AItem.Caption); end; end; begin DeletePrevSettings; AItems := CreateItemsList; try AIniFile.WriteInteger(ARootSection, 'ItemCount', AItems.Count); for I := 0 to AItems.Count - 1 do SaveItem(GetItemSection(I), AItems[I]); finally AItems.Free; end; end; procedure TdxCustomLayoutControl.Clear; var I: Integer; AItem: TdxCustomLayoutItem; begin MayPack := False; BeginUpdate; try for I := AbsoluteItemCount - 1 downto 0 do begin AItem := AbsoluteItems[I]; if (AItem is TdxLayoutItem) and (TdxLayoutItem(AItem).Control <> nil) then TdxLayoutItem(AItem).Control.Free; end; while AbsoluteItemCount <> 0 do AbsoluteItems[0].Free; finally EndUpdate; MayPack := True; end; end; function TdxCustomLayoutControl.CreateAlignmentConstraint: TdxLayoutAlignmentConstraint; begin Result := GetAlignmentConstraintClass.Create(Owner); AddAlignmentConstraint(Result); end; function TdxCustomLayoutControl.FindItem(AControl: TControl): TdxLayoutItem; var I: Integer; AItem: TdxCustomLayoutItem; begin for I := 0 to AbsoluteItemCount - 1 do begin AItem := AbsoluteItems[I]; if AItem is TdxLayoutItem then begin Result := TdxLayoutItem(AItem); if Result.Control = AControl then Exit; end; end; Result := nil; end; function TdxCustomLayoutControl.FindItem(const AName: string): TdxCustomLayoutItem; var I: Integer; begin if AName <> '' then begin Result := Items; if SameText(Result.Name, AName) then Exit; for I := 0 to AbsoluteItemCount - 1 do begin Result := AbsoluteItems[I]; if SameText(Result.Name, AName) then Exit; end; end; Result := nil; end; function TdxCustomLayoutControl.GetHitTest(const P: TPoint): TdxCustomLayoutHitTest; begin Result := ViewInfo.GetHitTest(P); end; function TdxCustomLayoutControl.GetHitTest(X, Y: Integer): TdxCustomLayoutHitTest; begin Result := ViewInfo.GetHitTest(X, Y); end; procedure TdxCustomLayoutControl.BeginUpdate; begin Inc(FUpdateLockCount); if (FUpdateLockCount = 1) and (FViewInfo <> nil) then FViewInfo.DestroyViewInfos; end; procedure TdxCustomLayoutControl.EndUpdate; begin if FUpdateLockCount <> 0 then begin Dec(FUpdateLockCount); if not IsUpdateLocked then begin if FViewInfo <> nil then FViewInfo.CreateViewInfos; LookAndFeelChanged; //LayoutChanged; end; end; end; function TdxCustomLayoutControl.CreateGroup(AGroupClass: TdxLayoutGroupClass = nil; AParent: TdxLayoutGroup = nil): TdxLayoutGroup; begin if AGroupClass = nil then AGroupClass := GetDefaultGroupClass; Result := TdxLayoutGroup(CreateItem(AGroupClass, AParent)); end; function TdxCustomLayoutControl.CreateItem(AItemClass: TdxCustomLayoutItemClass = nil; AParent: TdxLayoutGroup = nil): TdxCustomLayoutItem; begin if AItemClass = nil then AItemClass := GetDefaultItemClass; Result := AItemClass.Create(Owner); AddAvailableItem(Result); Result.Parent := AParent; Modified; if IsDesigning then dxLayoutDesigner.ItemsChanged(Self); end; function TdxCustomLayoutControl.CreateItemForControl(AControl: TControl; AParent: TdxLayoutGroup = nil): TdxLayoutItem; begin Result := TdxLayoutItem(CreateItem(GetDefaultItemClass, AParent)); Result.Control := AControl; end; procedure TdxCustomLayoutControl.LoadFromIniFile(const AFileName: string); var AIniFile: TMemIniFile; begin if AFileName = '' then Exit; AIniFile := TMemIniFile.Create(AFileName); try LoadFromCustomIniFile(AIniFile, Name); finally AIniFile.Free; end; end; procedure TdxCustomLayoutControl.LoadFromRegistry(const ARegistryPath: string); var AIniFile: TRegistryIniFile; begin if ARegistryPath = '' then Exit; AIniFile := TRegistryIniFile.Create(ARegistryPath); try LoadFromCustomIniFile(AIniFile, ''); finally AIniFile.Free; end; end; procedure TdxCustomLayoutControl.LoadFromStream(AStream: TStream); var AIniFile: TMemIniFile; AStrings: TStringList; begin AIniFile := TMemIniFile.Create(''); AStrings := TStringList.Create; try AStrings.LoadFromStream(AStream); AIniFile.SetStrings(AStrings); LoadFromCustomIniFile(AIniFile, ''); finally AStrings.Free; AIniFile.Free; end; end; procedure TdxCustomLayoutControl.SaveToIniFile(const AFileName: string); var AIniFile: TMemIniFile; begin if AFileName = '' then Exit; AIniFile := TMemIniFile.Create(AFileName); try SaveToCustomIniFile(AIniFile, Name); AIniFile.UpdateFile; finally AIniFile.Free; end; end; procedure TdxCustomLayoutControl.SaveToRegistry(const ARegistryPath: string); var AIniFile: TRegistryIniFile; begin if ARegistryPath = '' then Exit; AIniFile := TRegistryIniFile.Create(ARegistryPath); try SaveToCustomIniFile(AIniFile, ''); finally AIniFile.Free; end; end; procedure TdxCustomLayoutControl.SaveToStream(AStream: TStream); var AIniFile: TMemIniFile; AStrings: TStringList; begin AIniFile := TMemIniFile.Create(''); AStrings := TStringList.Create; try SaveToCustomIniFile(AIniFile, ''); AIniFile.GetStrings(AStrings); AStrings.SaveToStream(AStream); finally AStrings.Free; AIniFile.Free; end; end; { THitTests } type THitTests = class private FItems: TList; function GetCount: Integer; function GetInstance(AClass: TdxCustomLayoutHitTestClass): TdxCustomLayoutHitTest; function GetItem(Index: Integer): TdxCustomLayoutHitTest; protected function GetObjectByClass(AClass: TdxCustomLayoutHitTestClass): TdxCustomLayoutHitTest; property Count: Integer read GetCount; property Items[Index: Integer]: TdxCustomLayoutHitTest read GetItem; public constructor Create; destructor Destroy; override; property Instances[AClass: TdxCustomLayoutHitTestClass]: TdxCustomLayoutHitTest read GetInstance; default; end; var HitTests: THitTests; constructor THitTests.Create; begin inherited; FItems := TList.Create; end; destructor THitTests.Destroy; var I: Integer; begin for I := 0 to Count - 1 do Items[I].Free; FItems.Free; inherited; end; function THitTests.GetCount: Integer; begin Result := FItems.Count; end; function THitTests.GetInstance(AClass: TdxCustomLayoutHitTestClass): TdxCustomLayoutHitTest; begin Result := GetObjectByClass(AClass); if Result = nil then begin Result := AClass.Create; FItems.Add(Result); end; end; function THitTests.GetItem(Index: Integer): TdxCustomLayoutHitTest; begin Result := FItems[Index]; end; function THitTests.GetObjectByClass(AClass: TdxCustomLayoutHitTestClass): TdxCustomLayoutHitTest; var I: Integer; begin for I := 0 to Count - 1 do begin Result := Items[I]; if Result.ClassType = AClass then Exit; end; Result := nil; end; { TdxCustomLayoutHitTest } function TdxCustomLayoutHitTest.Cursor: TCursor; begin Result := crDefault; end; class function TdxCustomLayoutHitTest.HitTestCode: Integer; begin Result := htError; end; class function TdxCustomLayoutHitTest.Instance: TdxCustomLayoutHitTest; begin Result := HitTests.Instances[Self]; end; { TdxLayoutNoneHitTest } class function TdxLayoutNoneHitTest.HitTestCode: Integer; begin Result := htNone; end; { TdxLayoutItemHitTest } function TdxLayoutItemHitTest.GetItem: TdxLayoutItem; begin Result := TdxLayoutItem(inherited Item); end; procedure TdxLayoutItemHitTest.SetItem(Value: TdxLayoutItem); begin inherited Item := Value; end; class function TdxLayoutItemHitTest.HitTestCode: Integer; begin Result := htItem; end; { TdxLayoutGroupHitTest } function TdxLayoutGroupHitTest.GetItem: TdxLayoutGroup; begin Result := TdxLayoutGroup(inherited Item); end; procedure TdxLayoutGroupHitTest.SetItem(Value: TdxLayoutGroup); begin inherited Item := Value; end; class function TdxLayoutGroupHitTest.HitTestCode: Integer; begin Result := htGroup; end; { TdxLayoutCustomizeFormHitTest } class function TdxLayoutCustomizeFormHitTest.HitTestCode: Integer; begin Result := htCustomizeForm; end; { TdxLayoutClientAreaHitTest } class function TdxLayoutClientAreaHitTest.HitTestCode: Integer; begin Result := htClientArea; end; { TdxCustomLayoutControlHandler } constructor TdxCustomLayoutControlHandler.Create(AControl: TdxCustomLayoutControl); begin inherited Create; FControl := AControl; end; function TdxCustomLayoutControlHandler.GetViewInfo: TdxLayoutControlViewInfo; begin Result := FControl.ViewInfo; end; { TdxCustomLayoutItemElementPainter } constructor TdxCustomLayoutItemElementPainter.Create(ACanvas: TcxCanvas; AViewInfo: TdxCustomLayoutItemElementViewInfo); begin inherited Create; FCanvas := ACanvas; FViewInfo := AViewInfo; end; function TdxCustomLayoutItemElementPainter.GetLookAndFeel: TdxCustomLayoutLookAndFeel; begin Result := FViewInfo.LookAndFeel; end; { TdxCustomLayoutItemCaptionPainter } function TdxCustomLayoutItemCaptionPainter.GetViewInfo: TdxCustomLayoutItemCaptionViewInfo; begin Result := TdxCustomLayoutItemCaptionViewInfo(inherited ViewInfo); end; procedure TdxCustomLayoutItemCaptionPainter.AfterDrawText; begin {$IFDEF DELPHI7} with Canvas do Brush.Style := bsSolid; {$ENDIF} end; procedure TdxCustomLayoutItemCaptionPainter.BeforeDrawText; {$IFDEF DELPHI7} var R: TRect; {$ENDIF} begin with Canvas do begin {$IFDEF DELPHI7} if ViewInfo.IsTransparent then begin R := ViewInfo.TextAreaBounds; ThemeServices.DrawParentBackground(ViewInfo.Item.Container.Handle, Handle, nil, True, @R); Brush.Style := bsClear; end else Brush.Color := ViewInfo.Color; {$ELSE} Brush.Color := ViewInfo.Color; {$ENDIF} Font := ViewInfo.Font; Font.Color := ViewInfo.TextColor; if ViewInfo.IsTextUnderlined then Font.Style := Font.Style + [fsUnderline]; end; end; procedure TdxCustomLayoutItemCaptionPainter.DrawBackground; begin if not ViewInfo.IsTransparent then with Canvas do begin Brush.Color := ViewInfo.Color; FillRect(ViewInfo.Bounds); end; end; procedure TdxCustomLayoutItemCaptionPainter.DrawText; begin with ViewInfo do Canvas.DrawText(Text, TextAreaBounds, CalculateTextFlags, Enabled); end; procedure TdxCustomLayoutItemCaptionPainter.Paint; begin DrawBackground; if ViewInfo.Text <> '' then begin BeforeDrawText; DrawText; AfterDrawText; end; end; { TdxCustomLayoutItemPainter } constructor TdxCustomLayoutItemPainter.Create(ACanvas: TcxCanvas; AViewInfo: TdxCustomLayoutItemViewInfo); begin inherited Create; FCanvas := ACanvas; FViewInfo := AViewInfo; end; function TdxCustomLayoutItemPainter.GetLookAndFeel: TdxCustomLayoutLookAndFeel; begin Result := FViewInfo.LookAndFeel; end; procedure TdxCustomLayoutItemPainter.DrawCaption; begin with GetCaptionPainterClass.Create(Canvas, ViewInfo.CaptionViewInfo) do try Paint; finally Free; end; end; procedure TdxCustomLayoutItemPainter.DrawSelection; begin with ViewInfo.Item.Container.Painter.GetCustomizationCanvas do try Brush.Style := bsClear; Pen.Color := clHighlight; Pen.Style := psDot; with ViewInfo.Bounds do Polyline([TopLeft, Point(Right - 1, Top), Point(Right - 1, Bottom - 1), Point(Left, Bottom - 1), TopLeft]); Pen.Style := psSolid; Brush.Style := bsSolid; finally Free; end; end; procedure TdxCustomLayoutItemPainter.InternalDrawSelection; begin if ViewInfo.Selected and ViewInfo.Item.Container.CanShowSelection then DrawSelection; end; procedure TdxCustomLayoutItemPainter.DrawSelections; begin InternalDrawSelection; end; procedure TdxCustomLayoutItemPainter.Paint; begin if ViewInfo.HasCaption then DrawCaption; InternalDrawSelection; Canvas.ExcludeClipRect(ViewInfo.Bounds); end; { TdxLayoutItemControlPainter } function TdxLayoutItemControlPainter.GetViewInfo: TdxLayoutItemControlViewInfo; begin Result := TdxLayoutItemControlViewInfo(inherited ViewInfo); end; procedure TdxLayoutItemControlPainter.DrawBorders; var R: TRect; procedure DrawSingleBorder; begin Canvas.FrameRect(ViewInfo.Bounds, ViewInfo.BorderColor); end; procedure DrawStandardBorder; begin Canvas.DrawEdge(R, True, True); InflateRect(R, -1, -1); Canvas.DrawEdge(R, True, False); end; procedure DrawFlatBorder; begin Canvas.DrawEdge(R, True, True); InflateRect(R, -1, -1); Canvas.FrameRect(R, clBtnFace); end; begin R := ViewInfo.Bounds; case ViewInfo.BorderStyle of lbsSingle: DrawSingleBorder; lbsFlat: DrawFlatBorder; lbsStandard: DrawStandardBorder; end; end; procedure TdxLayoutItemControlPainter.Paint; begin if ViewInfo.HasBorder then DrawBorders; end; { TdxLayoutItemPainter } function TdxLayoutItemPainter.GetViewInfo: TdxLayoutItemViewInfo; begin Result := TdxLayoutItemViewInfo(inherited ViewInfo); end; function TdxLayoutItemPainter.GetCaptionPainterClass: TdxCustomLayoutItemCaptionPainterClass; begin Result := TdxLayoutItemCaptionPainter; end; function TdxLayoutItemPainter.GetControlPainterClass: TdxLayoutItemControlPainterClass; begin Result := TdxLayoutItemControlPainter; end; procedure TdxLayoutItemPainter.DrawControl; begin with GetControlPainterClass.Create(Canvas, ViewInfo.ControlViewInfo) do try Paint; finally Free; end; end; procedure TdxLayoutItemPainter.Paint; begin if ViewInfo.HasControl and ViewInfo.ControlViewInfo.OpaqueControl then Canvas.ExcludeClipRect(ViewInfo.ControlViewInfo.ControlBounds); if not ViewInfo.IsTransparent then with Canvas do begin Brush.Color := ViewInfo.Color; FillRect(ViewInfo.Bounds); end; if ViewInfo.HasControl then DrawControl; inherited; end; { TdxLayoutGroupPainter } function TdxLayoutGroupPainter.GetViewInfo: TdxLayoutGroupViewInfo; begin Result := TdxLayoutGroupViewInfo(inherited ViewInfo); end; function TdxLayoutGroupPainter.GetCaptionPainterClass: TdxCustomLayoutItemCaptionPainterClass; begin Result := TdxLayoutGroupCaptionPainter; end; procedure TdxLayoutGroupPainter.DrawBorders; var ASide: TdxLayoutSide; begin if not ViewInfo.IsTransparent then with Canvas do begin Brush.Color := ViewInfo.Color; for ASide := Low(ASide) to High(ASide) do FillRect(ViewInfo.BorderRestSpaceBounds[ASide]); end; end; procedure TdxLayoutGroupPainter.DrawBoundsFrame; var R: TRect; ARgn1, ARgn2: HRGN; begin Canvas.Pen.Style := psDashDot; Canvas.Pen.Color := ViewInfo.CaptionViewInfo.TextColor; Canvas.Brush.Style := bsClear; with ViewInfo.ClientBounds do begin R := ViewInfo.ClientBounds; ARgn1 := CreateRectRgnIndirect(R); InflateRect(R, -1, -1); ARgn2 := CreateRectRgnIndirect(R); CombineRgn(ARgn1, ARgn1, ARgn2, RGN_DIFF); DeleteObject(ARgn2); ExtSelectClipRgn(Canvas.Handle, ARgn1, RGN_OR); Canvas.Polyline([Point(Left, Top), Point(Right - 1, Top), Point(Right - 1, Bottom - 1), Point(Left, Bottom - 1), Point(Left, Top)]); ExtSelectClipRgn(Canvas.Handle, ARgn1, RGN_DIFF); DeleteObject(ARgn1); end; Canvas.Brush.Style := bsSolid; end; procedure TdxLayoutGroupPainter.DrawItems; var I: Integer; AItemViewInfo: TdxCustomLayoutItemViewInfo; begin for I := 0 to ViewInfo.ItemViewInfoCount - 1 do begin AItemViewInfo := ViewInfo.ItemViewInfos[I]; with AItemViewInfo.GetPainterClass.Create(Canvas, AItemViewInfo) do try Paint; finally Free; end; end; end; procedure TdxLayoutGroupPainter.DrawItemsArea; begin if not ViewInfo.IsTransparent then with Canvas do begin Brush.Color := ViewInfo.Color; FillRect(ViewInfo.ClientBounds); end; end; procedure TdxLayoutGroupPainter.DrawSelections; var I: Integer; AItemViewInfo: TdxCustomLayoutItemViewInfo; begin inherited; for I := 0 to ViewInfo.ItemViewInfoCount - 1 do begin AItemViewInfo := ViewInfo.ItemViewInfos[I]; with AItemViewInfo.GetPainterClass.Create(Canvas, AItemViewInfo) do try DrawSelections; finally Free; end; end; end; procedure TdxLayoutGroupPainter.Paint; begin if ViewInfo.HasBorder then DrawBorders; DrawItems; DrawItemsArea; if ViewInfo.HasBoundsFrame then DrawBoundsFrame; inherited; end; { TdxLayoutGroupCaptionStandardPainter } procedure TdxLayoutGroupCaptionStandardPainter.DrawText; {$IFDEF DELPHI7} const Enableds: array[Boolean] of Integer = (DTT_GRAYED, 0); {$ENDIF} begin {$IFDEF DELPHI7} if ThemeServices.ThemesEnabled then with ViewInfo do ThemeServices.DrawText(Canvas.Handle, ThemeServices.GetElementDetails(tbGroupBoxNormal), Text, TextAreaBounds, cxFlagsToDTFlags(CalculateTextFlags), Enableds[Enabled]) else inherited; {$ELSE} inherited; {$ENDIF} end; { TdxLayoutGroupStandardPainter } function TdxLayoutGroupStandardPainter.GetViewInfo: TdxLayoutGroupStandardViewInfo; begin Result := TdxLayoutGroupStandardViewInfo(inherited ViewInfo); end; function TdxLayoutGroupStandardPainter.GetCaptionPainterClass: TdxCustomLayoutItemCaptionPainterClass; begin Result := TdxLayoutGroupCaptionStandardPainter; end; procedure TdxLayoutGroupStandardPainter.DrawBorders; begin inherited; DrawFrame; end; procedure TdxLayoutGroupStandardPainter.DrawFrame; var R: TRect; begin {$IFDEF DELPHI7} if ThemeServices.ThemesEnabled then begin ThemeServices.DrawElement(Canvas.Handle, ThemeServices.GetElementDetails(tbGroupBoxNormal), ViewInfo.FrameBounds); Exit; end; {$ENDIF} R := ViewInfo.FrameBounds; with Canvas do begin DrawEdge(R, True, True); InflateRect(R, -1, -1); DrawEdge(R, False, False); end; end; { TdxLayoutGroupOfficePainter } function TdxLayoutGroupOfficePainter.GetCaptionPainterClass: TdxCustomLayoutItemCaptionPainterClass; begin Result := TdxLayoutGroupCaptionPainter; end; procedure TdxLayoutGroupOfficePainter.DrawFrame; var R: TRect; begin R := ViewInfo.FrameBounds; with Canvas do begin DrawEdge(R, True, True, [bTop]); Inc(R.Top); DrawEdge(R, False, False, [bTop]); end; end; { TdxLayoutGroupWebPainter } function TdxLayoutGroupWebPainter.GetLookAndFeel: TdxLayoutWebLookAndFeel; begin Result := TdxLayoutWebLookAndFeel(inherited LookAndFeel); end; function TdxLayoutGroupWebPainter.GetViewInfo: TdxLayoutGroupWebViewInfo; begin Result := TdxLayoutGroupWebViewInfo(inherited ViewInfo); end; procedure TdxLayoutGroupWebPainter.DrawBorders; begin DrawFrame; DrawCaptionSeparator; inherited; end; procedure TdxLayoutGroupWebPainter.DrawCaptionSeparator; begin with Canvas do begin Brush.Color := ViewInfo.Color; FillRect(ViewInfo.CaptionSeparatorAreaBounds); Brush.Color := ViewInfo.Options.GetFrameColor; FillRect(ViewInfo.CaptionSeparatorBounds); end; end; procedure TdxLayoutGroupWebPainter.DrawFrame; var R: TRect; I: Integer; begin R := ViewInfo.Bounds; for I := 1 to ViewInfo.Options.FrameWidth do begin Canvas.FrameRect(R, ViewInfo.Options.GetFrameColor); InflateRect(R, -1, -1); end; end; { TdxLayoutControlPainter } function TdxLayoutControlPainter.GetInternalCanvas: TcxCanvas; begin Result := FControl.Canvas; end; procedure TdxLayoutControlPainter.MakeCanvasClipped(ACanvas: TcxCanvas); begin ACanvas.IntersectClipRect(ViewInfo.ClientBounds); end; procedure TdxLayoutControlPainter.DrawEmptyArea; var AContentR, AClientR: TRect; begin if not ViewInfo.IsTransparent then with Canvas do begin Brush.Color := ViewInfo.LookAndFeel.GetEmptyAreaColor; AContentR := ViewInfo.ContentBounds; AClientR := ViewInfo.ClientBounds; FillRect(Rect(AContentR.Right, AClientR.Top, AClientR.Right, AClientR.Bottom)); FillRect(Rect(AClientR.Left, AContentR.Bottom, AContentR.Right, AClientR.Bottom)); end; end; procedure TdxLayoutControlPainter.DrawItems; var AItemsViewInfo: TdxLayoutGroupViewInfo; begin AItemsViewInfo := ViewInfo.ItemsViewInfo; with AItemsViewInfo.GetPainterClass.Create(Canvas, AItemsViewInfo) do try Paint; finally Free; end; end; procedure TdxLayoutControlPainter.PlaceControls; var AControlViewInfos, AWinControlViewInfos: TList; procedure RetrieveControlViewInfos(AItemViewInfo: TdxCustomLayoutItemViewInfo); var I: Integer; AControlViewInfo: TdxLayoutItemControlViewInfo; begin if AItemViewInfo is TdxLayoutGroupViewInfo then with TdxLayoutGroupViewInfo(AItemViewInfo) do for I := 0 to ItemViewInfoCount - 1 do RetrieveControlViewInfos(ItemViewInfos[I]) else begin AControlViewInfo := TdxLayoutItemViewInfo(AItemViewInfo).ControlViewInfo; if AControlViewInfo.Control <> nil then if AControlViewInfo.Control is TWinControl then AWinControlViewInfos.Add(AControlViewInfo) else AControlViewInfos.Add(AControlViewInfo); end; end; procedure ProcessControls; var I: Integer; begin for I := 0 to AControlViewInfos.Count - 1 do with TdxLayoutItemControlViewInfo(AControlViewInfos[I]) do begin Control.BoundsRect := ControlBounds; //ValidateRect(Self.Control.Handle, @ControlBounds); end; end; procedure ProcessWinControls; var AWindowsStruct: HDWP; I: Integer; begin AWindowsStruct := BeginDeferWindowPos(AWinControlViewInfos.Count); try for I := 0 to AWinControlViewInfos.Count - 1 do with TdxLayoutItemControlViewInfo(AWinControlViewInfos[I]), ControlBounds do DeferWindowPos(AWindowsStruct, (Control as TWinControl).Handle, 0, Left, Top, Right - Left, Bottom - Top, SWP_NOZORDER or SWP_NOACTIVATE); finally EndDeferWindowPos(AWindowsStruct); end; end; function CheckControlSizes(AControlViewInfos: TList): Boolean; var I: Integer; begin Result := True; for I := 0 to AControlViewInfos.Count - 1 do with TdxLayoutItemControlViewInfo(AControlViewInfos[I]) do begin Result := ((ItemViewInfo.AlignHorz = ahClient) or (Control.Width = ControlBounds.Right - ControlBounds.Left)) and ((ItemViewInfo.AlignVert = avClient) or (Control.Height = ControlBounds.Bottom - ControlBounds.Top)); if not Result then begin Item.SaveOriginalControlSize; Break; end; end; end; begin AControlViewInfos := TList.Create; AWinControlViewInfos := TList.Create; try Control.FIsPlacingControls := True; try RetrieveControlViewInfos(ViewInfo.ItemsViewInfo); ProcessControls; ProcessWinControls; finally Control.FIsPlacingControls := False; end; if not CheckControlSizes(AControlViewInfos) or not CheckControlSizes(AWinControlViewInfos) then Control.LayoutChanged; finally AWinControlViewInfos.Free; AControlViewInfos.Free; end; end; function TdxLayoutControlPainter.GetCanvas: TcxCanvas; begin Result := InternalCanvas; MakeCanvasClipped(Result); end; function TdxLayoutControlPainter.GetCustomizationCanvas: TcxCanvas; begin Result := TcxCustomizationCanvas.Create(Control); MakeCanvasClipped(Result); end; procedure TdxLayoutControlPainter.DrawSelections; var AItemsViewInfo: TdxLayoutGroupViewInfo; begin if Control.IsUpdateLocked then Exit; AItemsViewInfo := ViewInfo.ItemsViewInfo; with AItemsViewInfo.GetPainterClass.Create(Canvas, AItemsViewInfo) do try DrawSelections; finally Free; end; end; procedure TdxLayoutControlPainter.Paint; var APrevClipRegion: TcxRegion; begin FCanvas := GetCanvas; APrevClipRegion := FCanvas.GetClipRegion; { moved to TdxLayoutControlViewInfo.Calculate }//PlaceControls; // because of selection drawing DrawItems; DrawEmptyArea; // PlaceControls; FCanvas.SetClipRegion(APrevClipRegion, roSet); end; { TdxCustomLayoutItemElementViewInfo } constructor TdxCustomLayoutItemElementViewInfo.Create(AItemViewInfo: TdxCustomLayoutItemViewInfo); begin inherited Create; FItemViewInfo := AItemViewInfo; end; function TdxCustomLayoutItemElementViewInfo.GetHeight: Integer; begin Result := FHeight; if Result = 0 then begin Result := Bounds.Bottom - Bounds.Top; if Result = 0 then Result := CalculateHeight; end; end; function TdxCustomLayoutItemElementViewInfo.GetItem: TdxCustomLayoutItem; begin Result := FItemViewInfo.Item; end; function TdxCustomLayoutItemElementViewInfo.GetLookAndFeel: TdxCustomLayoutLookAndFeel; begin Result := FItemViewInfo.LookAndFeel; end; function TdxCustomLayoutItemElementViewInfo.GetWidth: Integer; begin Result := FWidth; if Result = 0 then begin Result := Bounds.Right - Bounds.Left; if Result = 0 then Result := CalculateWidth; end; end; procedure TdxCustomLayoutItemElementViewInfo.SetHeight(Value: Integer); begin FHeight := Value; end; procedure TdxCustomLayoutItemElementViewInfo.SetWidth(Value: Integer); begin FWidth := Value; end; function TdxCustomLayoutItemElementViewInfo.GetEnabled: Boolean; begin Result := FItemViewInfo.Enabled; end; function TdxCustomLayoutItemElementViewInfo.GetEnabledForWork: Boolean; begin Result := FItemViewInfo.EnabledForWork; end; function TdxCustomLayoutItemElementViewInfo.GetCursor(X, Y: Integer): TCursor; begin Result := crDefault; end; function TdxCustomLayoutItemElementViewInfo.GetVisible: Boolean; begin Result := False; end; procedure TdxCustomLayoutItemElementViewInfo.Invalidate(const ABounds: TRect); begin Item.Container.InvalidateRect(ABounds, False); end; procedure TdxCustomLayoutItemElementViewInfo.MouseEnter; begin end; procedure TdxCustomLayoutItemElementViewInfo.MouseLeave; begin Pressed := False; end; procedure TdxCustomLayoutItemElementViewInfo.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin Pressed := True; end; procedure TdxCustomLayoutItemElementViewInfo.MouseMove(Shift: TShiftState; X, Y: Integer); begin end; procedure TdxCustomLayoutItemElementViewInfo.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin Pressed := False; end; function TdxCustomLayoutItemElementViewInfo.WantsMouse(X, Y: Integer): Boolean; begin Result := Visible and PtInRect(Bounds, Point(X, Y)); end; procedure TdxCustomLayoutItemElementViewInfo.Calculate(const ABounds: TRect); begin Bounds := ABounds; end; { TdxCustomLayoutItemCaptionViewInfo } function TdxCustomLayoutItemCaptionViewInfo.GetCanvas: TcxCanvas; begin Result := ItemViewInfo.ContainerViewInfo.Canvas; end; function TdxCustomLayoutItemCaptionViewInfo.GetIsCustomization: Boolean; begin Result := FItemViewInfo.IsCustomization; end; function TdxCustomLayoutItemCaptionViewInfo.GetTextHeight: Integer; var R: TRect; begin if Item.CachedTextHeight = 0 then begin PrepareCanvas; if MultiLine then begin R := Rect(0, 0, CalculateWidth - 1 {for disabling}, 0); Canvas.TextExtent(Text, R, CalculateTextFlags); Result := R.Bottom - R.Top; end else Result := Canvas.TextHeight(Text); Item.CachedTextHeight := Result; end else Result := Item.CachedTextHeight; if Text <> '' then Inc(Result); // for disabling end; function TdxCustomLayoutItemCaptionViewInfo.GetTextWidth: Integer; var AText: string; begin AText := VisibleText; PrepareCanvas; Result := Canvas.TextWidth(AText); if AText <> '' then Inc(Result); // for disabling end; procedure TdxCustomLayoutItemCaptionViewInfo.SetHotTracked(Value: Boolean); begin if FHotTracked <> Value then begin FHotTracked := Value; Invalidate(HotTrackBounds); end; end; function TdxCustomLayoutItemCaptionViewInfo.GetCursor(X, Y: Integer): TCursor; begin if HotTracked and (htsHandPoint in HotTrackStyles) then Result := crcxHandPoint else Result := inherited GetCursor(X, Y); end; function TdxCustomLayoutItemCaptionViewInfo.GetVisible: Boolean; begin Result := ItemViewInfo.HasCaption; end; procedure TdxCustomLayoutItemCaptionViewInfo.MouseLeave; begin inherited; HotTracked := False; end; procedure TdxCustomLayoutItemCaptionViewInfo.MouseMove(Shift: TShiftState; X, Y: Integer); begin inherited; if IsHotTrackable then HotTracked := IsPointInHotTrackBounds(Point(X, Y)); end; procedure TdxCustomLayoutItemCaptionViewInfo.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var APressed: Boolean; begin APressed := Pressed; inherited; if CanDoCaptionClick(X, Y) and APressed then Item.DoCaptionClick; end; function TdxCustomLayoutItemCaptionViewInfo.GetColor: TColor; begin Result := ItemViewInfo.Color; end; function TdxCustomLayoutItemCaptionViewInfo.GetFont: TFont; begin Result := Options.GetFont(Item.Container); end; function TdxCustomLayoutItemCaptionViewInfo.GetHotTrackBounds: TRect; begin Result := TextAreaBounds; end; function TdxCustomLayoutItemCaptionViewInfo.GetHotTrackStyles: TdxLayoutHotTrackStyles; begin Result := Options.HotTrackStyles; end; function TdxCustomLayoutItemCaptionViewInfo.GetIsDefaultColor: Boolean; begin Result := ItemViewInfo.IsDefaultColor; end; function TdxCustomLayoutItemCaptionViewInfo.GetIsHotTrackable: Boolean; begin Result := not IsCustomization and EnabledForWork and Options.HotTrack; end; function TdxCustomLayoutItemCaptionViewInfo.CalculateTextFlags: Integer; const MultiLines: array[Boolean] of Integer = (cxSingleLine, cxWordBreak); AlignsVert: array[TdxAlignmentVert] of Integer = (cxAlignTop, cxAlignVCenter, cxAlignBottom); begin Result := MultiLines[MultiLine] or cxAlignmentsHorz[AlignHorz] or AlignsVert[AlignVert]; if Item.CaptionOptions.ShowAccelChar then Inc(Result, cxShowPrefix); end; function TdxCustomLayoutItemCaptionViewInfo.CanDoCaptionClick(X, Y: Integer): Boolean; begin Result := EnabledForWork and IsPointInHotTrackBounds(Point(X, Y)); end; function TdxCustomLayoutItemCaptionViewInfo.GetAlignHorz: TAlignment; begin Result := Item.CaptionOptions.AlignHorz; end; function TdxCustomLayoutItemCaptionViewInfo.GetIsTextUnderlined: Boolean; begin Result := IsHotTrackable and not HotTracked and (htsUnderlineCold in HotTrackStyles) or HotTracked and (htsUnderlineHot in HotTrackStyles); end; function TdxCustomLayoutItemCaptionViewInfo.GetIsTransparent: Boolean; begin Result := ItemViewInfo.ContainerViewInfo.HasBackground and IsDefaultColor; end; function TdxCustomLayoutItemCaptionViewInfo.GetOptions: TdxLayoutLookAndFeelCaptionOptions; begin Result := ItemViewInfo.Options.CaptionOptions; end; function TdxCustomLayoutItemCaptionViewInfo.GetText: string; begin Result := Item.Caption; end; function TdxCustomLayoutItemCaptionViewInfo.GetTextAreaBounds: TRect; begin Result := Bounds; if Enabled and (Text <> '') then with Result do begin Dec(Right); Dec(Bottom); end; end; function TdxCustomLayoutItemCaptionViewInfo.GetTextColor: TColor; begin if HotTracked then Result := GetTextHotColor else Result := GetTextNormalColor; end; function TdxCustomLayoutItemCaptionViewInfo.GetTextHotColor: TColor; begin Result := Options.GetTextHotColor; end; function TdxCustomLayoutItemCaptionViewInfo.GetTextNormalColor: TColor; begin Result := Options.GetTextColor; end; function TdxCustomLayoutItemCaptionViewInfo.GetVisibleText: string; begin Result := Text; if Item.CaptionOptions.ShowAccelChar then Result := StripHotKey(Result); end; function TdxCustomLayoutItemCaptionViewInfo.IsPointInHotTrackBounds(const P: TPoint): Boolean; var ABounds: TRectArray; I: Integer; begin Result := False; PrepareCanvas; Canvas.GetTextStringsBounds(Text, TextAreaBounds, CalculateTextFlags, Enabled, ABounds); try for I := 0 to High(ABounds) do begin Result := PtInRect(ABounds[I], P); if Result then Break; end; finally ABounds := nil; end; end; procedure TdxCustomLayoutItemCaptionViewInfo.PrepareCanvas; begin Canvas.Font := Font; end; function TdxCustomLayoutItemCaptionViewInfo.CalculateHeight: Integer; begin if Visible then Result := TextHeight else Result := 0; end; function TdxCustomLayoutItemCaptionViewInfo.CalculateWidth: Integer; begin if Visible then Result := TextWidth else Result := 0; end; { TdxCustomLayoutItemViewInfo } constructor TdxCustomLayoutItemViewInfo.Create(AContainerViewInfo: TdxLayoutControlViewInfo; AParentViewInfo: TdxLayoutGroupViewInfo; AItem: TdxCustomLayoutItem); begin inherited Create; FContainerViewInfo := AContainerViewInfo; FParentViewInfo := AParentViewInfo; FItem := AItem; FItem.FViewInfo := Self; CreateViewInfos; end; destructor TdxCustomLayoutItemViewInfo.Destroy; begin DestroyViewInfos; FItem.FViewInfo := nil; inherited; end; function TdxCustomLayoutItemViewInfo.GetAlignHorz: TdxLayoutAlignHorz; begin Result := Item.AlignHorz; end; function TdxCustomLayoutItemViewInfo.GetAlignVert: TdxLayoutAlignVert; begin Result := Item.AlignVert; end; function TdxCustomLayoutItemViewInfo.GetIsCustomization: Boolean; begin Result := FItem.Container.IsCustomization; end; function TdxCustomLayoutItemViewInfo.GetIsParentLocked: Boolean; begin Result := (ParentViewInfo <> nil) and ParentViewInfo.IsLocked; end; function TdxCustomLayoutItemViewInfo.GetLookAndFeel: TdxCustomLayoutLookAndFeel; begin Result := Item.GetLookAndFeel; end; function TdxCustomLayoutItemViewInfo.GetMinHeight: Integer; begin if AlignVert = avClient then Result := CalculateMinHeight else Result := CalculateHeight; end; function TdxCustomLayoutItemViewInfo.GetMinWidth: Integer; begin if AlignHorz = ahClient then Result := CalculateMinWidth else Result := CalculateWidth; end; function TdxCustomLayoutItemViewInfo.GetOffset(ASide: TdxLayoutSide): Integer; begin Result := FOffsets[ASide]; if Result = 0 then Result := CalculateOffset(ASide); end; function TdxCustomLayoutItemViewInfo.GetOffsetsHeight: Integer; begin Result := Offsets[sdTop] + Offsets[sdBottom]; end; function TdxCustomLayoutItemViewInfo.GetOffsetsWidth: Integer; begin Result := Offsets[sdLeft] + Offsets[sdRight]; end; function TdxCustomLayoutItemViewInfo.GetSelected: Boolean; begin Result := Item.IsDesigning and dxLayoutDesigner.IsComponentSelected(Item.Container, Item); end; procedure TdxCustomLayoutItemViewInfo.SetElementWithMouse(Value: TdxCustomLayoutItemElementViewInfo); begin if FElementWithMouse <> Value then begin if FElementWithMouse <> nil then FElementWithMouse.MouseLeave; FElementWithMouse := Value; if FElementWithMouse <> nil then FElementWithMouse.MouseEnter; end; end; procedure TdxCustomLayoutItemViewInfo.SetOffset(ASide: TdxLayoutSide; Value: Integer); begin FOffsets[ASide] := Value; end; procedure TdxCustomLayoutItemViewInfo.CreateViewInfos; begin FCaptionViewInfo := GetCaptionViewInfoClass.Create(Self); end; procedure TdxCustomLayoutItemViewInfo.DestroyViewInfos; begin FreeAndNil(FCaptionViewInfo); end; function TdxCustomLayoutItemViewInfo.CalculateMinHeight: Integer; begin Result := DoCalculateHeight(True); end; function TdxCustomLayoutItemViewInfo.CalculateMinWidth: Integer; begin Result := DoCalculateWidth(True); end; function TdxCustomLayoutItemViewInfo.CalculateOffset(ASide: TdxLayoutSide): Integer; begin case ASide of sdLeft: Result := Item.Offsets.Left; sdRight: Result := Item.Offsets.Right; sdTop: Result := Item.Offsets.Top; sdBottom: Result := Item.Offsets.Bottom; else Result := 0; end; end; function TdxCustomLayoutItemViewInfo.DoCalculateHeight(AIsMinHeight: Boolean = False): Integer; begin Result := OffsetsHeight; end; function TdxCustomLayoutItemViewInfo.DoCalculateWidth(AIsMinWidth: Boolean = False): Integer; begin Result := OffsetsWidth; end; function TdxCustomLayoutItemViewInfo.GetCursor(X, Y: Integer): TCursor; var I: Integer; begin for I := 0 to ElementCount - 1 do if Elements[I].WantsMouse(X, Y) then begin Result := Elements[I].GetCursor(X, Y); Exit; end; Result := crDefault; end; function TdxCustomLayoutItemViewInfo.GetElement(Index: Integer): TdxCustomLayoutItemElementViewInfo; begin if Index = 0 then Result := CaptionViewInfo else Result := nil; end; function TdxCustomLayoutItemViewInfo.GetElementCount: Integer; begin Result := 1; end; function TdxCustomLayoutItemViewInfo.GetEnabled: Boolean; begin Result := Item.Enabled; end; function TdxCustomLayoutItemViewInfo.GetEnabledForWork: Boolean; begin Result := Item.EnabledForWork; end; function TdxCustomLayoutItemViewInfo.GetIsTransparent: Boolean; begin Result := ContainerViewInfo.HasBackground and IsDefaultColor; end; function TdxCustomLayoutItemViewInfo.GetSelectionAreaBounds(Index: Integer): TRect; const SelectionSize = 2;//1; begin with Bounds do case Index of 0: Result := Rect(Left, Top, Left + SelectionSize, Bottom); 1: Result := Rect(Left, Top, Right, Top + SelectionSize); 2: Result := Rect(Right - SelectionSize, Top, Right, Bottom); 3: Result := Rect(Left, Bottom - SelectionSize, Right, Bottom); end; end; function TdxCustomLayoutItemViewInfo.GetSelectionAreaCount: Integer; begin Result := 4; end; function TdxCustomLayoutItemViewInfo.HasCaption: Boolean; begin Result := Item.HasCaption; end; procedure TdxCustomLayoutItemViewInfo.MouseEnter; begin end; procedure TdxCustomLayoutItemViewInfo.MouseLeave; begin ElementWithMouse := nil; end; procedure TdxCustomLayoutItemViewInfo.MouseDown(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if ElementWithMouse <> nil then ElementWithMouse.MouseDown(Button, Shift, X, Y); end; procedure TdxCustomLayoutItemViewInfo.MouseMove(Shift: TShiftState; X, Y: Integer); var I: Integer; begin for I := 0 to ElementCount - 1 do if Elements[I].WantsMouse(X, Y) then begin ElementWithMouse := Elements[I]; Elements[I].MouseMove(Shift, X, Y); Exit; end; ElementWithMouse := nil; end; procedure TdxCustomLayoutItemViewInfo.MouseUp(Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if ElementWithMouse <> nil then ElementWithMouse.MouseUp(Button, Shift, X, Y); end; procedure TdxCustomLayoutItemViewInfo.Calculate(const ABounds: TRect); begin Bounds := ABounds; Inc(Bounds.Left, Offsets[sdLeft]); Inc(Bounds.Top, Offsets[sdTop]); Dec(Bounds.Right, Offsets[sdRight]); Dec(Bounds.Bottom, Offsets[sdBottom]); end; function TdxCustomLayoutItemViewInfo.CalculateHeight: Integer; begin Result := DoCalculateHeight; end; function TdxCustomLayoutItemViewInfo.CalculateWidth: Integer; begin Result := DoCalculateWidth; end; function TdxCustomLayoutItemViewInfo.GetHitTest(const P: TPoint): TdxCustomLayoutHitTest; begin if not IsParentLocked and PtInRect(Bounds, P) then begin Result := GetHitTestClass.Instance; TdxCustomLayoutItemHitTest(Result).Item := Item; end else Result := nil; end; procedure TdxCustomLayoutItemViewInfo.ResetOffset(ASide: TdxLayoutSide); begin FOffsets[ASide] := 0; end; { TdxLayoutItemCaptionViewInfo } function TdxLayoutItemCaptionViewInfo.GetItem: TdxLayoutItem; begin Result := TdxLayoutItem(inherited GetItem); end; function TdxLayoutItemCaptionViewInfo.GetItemViewInfo: TdxLayoutItemViewInfo; begin Result := TdxLayoutItemViewInfo(inherited ItemViewInfo); end; function TdxLayoutItemCaptionViewInfo.GetAlignVert: TdxAlignmentVert; begin Result := Item.CaptionOptions.AlignVert; end; function TdxLayoutItemCaptionViewInfo.GetIsFixedWidth: Boolean; begin Result := Item.CaptionOptions.Width <> 0; end; function TdxLayoutItemCaptionViewInfo.GetMinWidth: Integer; begin if FWidth = 0 then Result := CalculateWidth else Result := Width; end; function TdxLayoutItemCaptionViewInfo.GetMultiLine: Boolean; begin Result := IsFixedWidth; end; function TdxLayoutItemCaptionViewInfo.GetTextAreaBounds: TRect; var ADelta: Integer; begin Result := inherited GetTextAreaBounds; if IsFixedWidth then with Result do begin ADelta := Width - CalculateWidth; case AlignHorz of taLeftJustify: Dec(Right, ADelta); taRightJustify: Inc(Left, ADelta); taCenter: begin Inc(Left, ADelta div 2); Dec(Right, ADelta - ADelta div 2); end; end; end; end; function TdxLayoutItemCaptionViewInfo.CalculateWidth: Integer; begin if Visible and IsFixedWidth then Result := Item.CaptionOptions.Width else Result := inherited CalculateWidth; end; { TdxLayoutItemControlViewInfo } function TdxLayoutItemControlViewInfo.GetBorderColor: TColor; begin Result := ItemViewInfo.Options.GetControlBorderColor; end; function TdxLayoutItemControlViewInfo.GetBorderStyle: TdxLayoutBorderStyle; begin Result := ItemViewInfo.Options.ControlBorderStyle; end; function TdxLayoutItemControlViewInfo.GetControl: TControl; begin Result := Item.Control; end; function TdxLayoutItemControlViewInfo.GetHasBorder: Boolean; begin Result := Item.ControlOptions.ShowBorder; end; function TdxLayoutItemControlViewInfo.GetItem: TdxLayoutItem; begin Result := TdxLayoutItem(inherited Item); end; function TdxLayoutItemControlViewInfo.GetItemViewInfo: TdxLayoutItemViewInfo; begin Result := TdxLayoutItemViewInfo(inherited ItemViewInfo); end; function TdxLayoutItemControlViewInfo.GetOpaqueControl: Boolean; begin Result := Item.ControlOptions.Opaque; end; function TdxLayoutItemControlViewInfo.GetVisible: Boolean; begin Result := ItemViewInfo.HasControl; end; function TdxLayoutItemControlViewInfo.CalculateControlBounds: TRect; begin Result := Bounds; Inc(Result.Left, BorderWidths[sdLeft]); Dec(Result.Right, BorderWidths[sdRight]); Inc(Result.Top, BorderWidths[sdTop]); Dec(Result.Bottom, BorderWidths[sdBottom]); end; function TdxLayoutItemControlViewInfo.GetBorderWidth(ASide: TdxLayoutSide): Integer; begin if HasBorder then Result := LookAndFeel.ItemControlBorderWidths[ASide] else Result := 0 end; function TdxLayoutItemControlViewInfo.GetHeight(AControlHeight: Integer): Integer; begin Result := BorderWidths[sdTop] + AControlHeight + BorderWidths[sdBottom]; end; function TdxLayoutItemControlViewInfo.GetWidth(AControlWidth: Integer): Integer; begin Result := BorderWidths[sdLeft] + AControlWidth + BorderWidths[sdRight]; end; procedure TdxLayoutItemControlViewInfo.Calculate(const ABounds: TRect); begin inherited; FControlBounds := CalculateControlBounds; end; function TdxLayoutItemControlViewInfo.CalculateHeight: Integer; begin if Visible then Result := GetHeight(Item.OriginalControlSize.Y) else Result := 0; end; function TdxLayoutItemControlViewInfo.CalculateWidth: Integer; begin if Visible then Result := GetWidth(Item.OriginalControlSize.X) else Result := 0; end; function TdxLayoutItemControlViewInfo.CalculateMinHeight: Integer; begin if Item.ControlOptions.FixedSize then Result := CalculateHeight else if Visible then Result := GetHeight(Item.ControlOptions.MinHeight) else Result := 0; end; function TdxLayoutItemControlViewInfo.CalculateMinWidth: Integer; begin if Item.ControlOptions.FixedSize then Result := CalculateWidth else if Visible then Result := GetWidth(Item.ControlOptions.MinWidth) else Result := 0; end; procedure TdxLayoutItemControlViewInfo.CalculateTabOrder(var AAvailTabOrder: Integer); begin if Item.HasWinControl then begin TWinControl(Control).TabOrder := AAvailTabOrder; Inc(AAvailTabOrder); end; end; { TdxLayoutItemViewInfo } function TdxLayoutItemViewInfo.GetCaptionViewInfo: TdxLayoutItemCaptionViewInfo; begin Result := TdxLayoutItemCaptionViewInfo(inherited CaptionViewInfo); end; function TdxLayoutItemViewInfo.GetItem: TdxLayoutItem; begin Result := TdxLayoutItem(inherited Item); end; function TdxLayoutItemViewInfo.GetOptionsEx: TdxLayoutLookAndFeelItemOptions; begin Result := TdxLayoutLookAndFeelItemOptions(inherited Options); end; procedure TdxLayoutItemViewInfo.CreateViewInfos; begin inherited; FControlViewInfo := GetControlViewInfoClass.Create(Self); end; procedure TdxLayoutItemViewInfo.DestroyViewInfos; begin FreeAndNil(FControlViewInfo); inherited; end; function TdxLayoutItemViewInfo.GetCaptionViewInfoClass: TdxCustomLayoutItemCaptionViewInfoClass; begin Result := TdxLayoutItemCaptionViewInfo; end; function TdxLayoutItemViewInfo.GetControlViewInfoClass: TdxLayoutItemControlViewInfoClass; begin Result := TdxLayoutItemControlViewInfo; end; function TdxLayoutItemViewInfo.GetHitTestClass: TdxCustomLayoutItemHitTestClass; begin Result := TdxLayoutItemHitTest; end; function TdxLayoutItemViewInfo.GetPainterClass: TdxCustomLayoutItemPainterClass; begin Result := TdxCustomLayoutItemPainterClass(LookAndFeel.GetItemPainterClass); end; procedure TdxLayoutItemViewInfo.CalculateViewInfosBounds(var ACaptionBounds, AControlBounds: TRect); var ACaptionSize, AControlSize: TPoint; ACaptionVisible, AControlVisible: Boolean; procedure CalculateElementViewInfoSize(AElementViewInfo: TdxCustomLayoutItemElementViewInfo; var ASize: TPoint; var AVisible: Boolean); begin AVisible := AElementViewInfo.Visible; with ASize do if AVisible then begin X := AElementViewInfo.Width; Y := AElementViewInfo.Height; end else begin X := 0; Y := 0; end; AVisible := AVisible and ((ASize.X <> 0) or (ASize.Y <> 0)); //AVisible := AVisible and (ASize.X <> 0) and (ASize.Y <> 0); end; procedure CalculateMainBounds; procedure InitBounds(var ABounds: TRect; const ASize: TPoint; AVisible: Boolean); begin if AVisible then ABounds := ContentBounds else SetRectEmpty(ABounds); end; procedure CalculateWithFixedControl; begin case CaptionLayout of clLeft: begin AControlBounds.Left := AControlBounds.Right - AControlSize.X; ACaptionBounds.Right := AControlBounds.Left - ControlOffsetHorz; end; clTop: begin AControlBounds.Top := AControlBounds.Bottom - AControlSize.Y; ACaptionBounds.Bottom := AControlBounds.Top - ControlOffsetVert; end; clRight: begin AControlBounds.Right := AControlBounds.Left + AControlSize.X; ACaptionBounds.Left := AControlBounds.Right + ControlOffsetHorz; end; clBottom: begin AControlBounds.Bottom := AControlBounds.Top + AControlSize.Y; ACaptionBounds.Top := AControlBounds.Bottom + ControlOffsetVert; end; end end; procedure CalculateWithFixedCaption; begin case CaptionLayout of clLeft: begin ACaptionBounds.Right := ACaptionBounds.Left + ACaptionSize.X; AControlBounds.Left := ACaptionBounds.Right + ControlOffsetHorz; end; clTop: begin ACaptionBounds.Bottom := ACaptionBounds.Top + ACaptionSize.Y; AControlBounds.Top := ACaptionBounds.Bottom + ControlOffsetVert; end; clRight: begin ACaptionBounds.Left := ACaptionBounds.Right - ACaptionSize.X; AControlBounds.Right := ACaptionBounds.Left - ControlOffsetHorz; end; clBottom: begin ACaptionBounds.Top := ACaptionBounds.Bottom - ACaptionSize.Y; AControlBounds.Bottom := ACaptionBounds.Top - ControlOffsetVert; end; end; end; begin InitBounds(ACaptionBounds, ACaptionSize, ACaptionVisible); InitBounds(AControlBounds, AControlSize, AControlVisible); if ACaptionVisible and AControlVisible then if Item.ControlOptions.FixedSize then CalculateWithFixedControl else CalculateWithFixedCaption else if AControlVisible and Item.ControlOptions.FixedSize then with AControlBounds, AControlSize do begin Right := Left + X; Bottom := Top + Y; end; end; procedure CalculateRestBounds(var ABounds: TRect; const ASize: TPoint; AAlignHorz: TAlignment; AAlignVert: TdxAlignmentVert); begin with ABounds, ASize do case CaptionLayout of clLeft, clRight: case AAlignVert of tavTop: Bottom := Top + Y; tavCenter: begin Top := (Top + Bottom - Y) div 2; Bottom := Top + Y; end; tavBottom: Top := Bottom - Y; end; clTop, clBottom: case AAlignHorz of taLeftJustify: Right := Left + X; taCenter: begin Left := (Left + Right - X) div 2; Right := Left + X; end; taRightJustify: Left := Right - X; end; end; end; begin CalculateElementViewInfoSize(CaptionViewInfo, ACaptionSize, ACaptionVisible); CalculateElementViewInfoSize(ControlViewInfo, AControlSize, AControlVisible); CalculateMainBounds; if ACaptionVisible then begin CalculateRestBounds(ACaptionBounds, ACaptionSize, Item.CaptionOptions.AlignHorz, Item.CaptionOptions.AlignVert); if AControlVisible and ((AlignHorz <> ahClient) or (CaptionLayout in [clLeft, clRight])) and ((AlignVert <> avClient) or (CaptionLayout in [clTop, clBottom])) then CalculateRestBounds(AControlBounds, AControlSize, taLeftJustify, tavTop); end; end; function TdxLayoutItemViewInfo.DoCalculateHeight(AIsMinHeight: Boolean = False): Integer; var AHeight: Integer; begin Result := CaptionViewInfo.Height; if AIsMinHeight then AHeight := ControlViewInfo.CalculateMinHeight else AHeight := ControlViewInfo.CalculateHeight; case CaptionLayout of clLeft, clRight: if AHeight > Result then Result := AHeight; clTop, clBottom: begin if (Result <> 0) and ControlViewInfo.Visible{(AHeight <> 0)} then Inc(Result, ControlOffsetVert); Inc(Result, AHeight); end; else Result := 0; end; Inc(Result, inherited DoCalculateHeight(AIsMinHeight)); end; function TdxLayoutItemViewInfo.DoCalculateWidth(AIsMinWidth: Boolean = False): Integer; var AWidth: Integer; begin if AIsMinWidth then begin Result := CaptionViewInfo.MinWidth; AWidth := ControlViewInfo.CalculateMinWidth; end else begin Result := CaptionViewInfo.Width; AWidth := ControlViewInfo.CalculateWidth; end; case CaptionLayout of clLeft, clRight: begin if (Result <> 0) and ControlViewInfo.Visible{(AWidth <> 0)} then Inc(Result, ControlOffsetHorz); Inc(Result, AWidth); end; clTop, clBottom: if AWidth > Result then Result := AWidth; else Result := 0; end; Inc(Result, inherited DoCalculateWidth(AIsMinWidth)); end; function TdxLayoutItemViewInfo.GetAutoControlAlignment: Boolean; function AreAlignmentAndCaptionLayoutLinked: Boolean; begin case CaptionLayout of clLeft: Result := AlignHorz in [ahLeft, ahClient]; clTop: Result := AlignVert in [avTop, avClient]; clRight: Result := AlignHorz in [ahRight, ahClient]; clBottom: Result := AlignVert in [avBottom, avClient]; else Result := False; end; end; begin Result := Item.ControlOptions.AutoAlignment and HasCaption and HasControl and AreAlignmentAndCaptionLayoutLinked; end; function TdxLayoutItemViewInfo.GetCaptionLayout: TdxCaptionLayout; begin Result := Item.CaptionOptions.Layout; end; function TdxLayoutItemViewInfo.GetColor: TColor; begin Result := ParentViewInfo.GetColor; end; function TdxLayoutItemViewInfo.GetContentBounds: TRect; begin Result := Bounds; end; function TdxLayoutItemViewInfo.GetControlOffsetHorz: Integer; begin Result := LookAndFeel.GetControlOffsetHorz(Item.Container); end; function TdxLayoutItemViewInfo.GetControlOffsetVert: Integer; begin Result := LookAndFeel.GetControlOffsetVert(Item.Container); end; function TdxLayoutItemViewInfo.GetElement(Index: Integer): TdxCustomLayoutItemElementViewInfo; begin Result := inherited GetElement(Index); if Index - inherited GetElementCount = 0 then Result := FControlViewInfo; end; function TdxLayoutItemViewInfo.GetElementCount: Integer; begin Result := inherited GetElementCount + 1; end; function TdxLayoutItemViewInfo.GetIsDefaultColor: Boolean; begin Result := ParentViewInfo.IsDefaultColor; end; function TdxLayoutItemViewInfo.GetOptions: TdxCustomLayoutLookAndFeelOptions; begin Result := LookAndFeel.ItemOptions; end; function TdxLayoutItemViewInfo.HasControl: Boolean; begin Result := Item.HasControl; end; procedure TdxLayoutItemViewInfo.Calculate(const ABounds: TRect); var ACaptionViewInfoBounds, AControlViewInfoBounds: TRect; begin inherited; CalculateViewInfosBounds(ACaptionViewInfoBounds, AControlViewInfoBounds); CaptionViewInfo.Calculate(ACaptionViewInfoBounds); ControlViewInfo.Calculate(AControlViewInfoBounds); end; procedure TdxLayoutItemViewInfo.CalculateTabOrders(var AAvailTabOrder: Integer); begin ControlViewInfo.CalculateTabOrder(AAvailTabOrder); end; { TdxLayoutGroupCaptionViewInfo } function TdxLayoutGroupCaptionViewInfo.GetAlignVert: TdxAlignmentVert; begin Result := tavTop; end; function TdxLayoutGroupCaptionViewInfo.GetMultiLine: Boolean; begin Result := False; end; function TdxLayoutGroupCaptionViewInfo.GetMinWidth: Integer; begin Result := CalculateWidth; end; { TdxLayoutGroupViewInfoSpecific } constructor TdxLayoutGroupViewInfoSpecific.Create(AGroupViewInfo: TdxLayoutGroupViewInfo); begin inherited Create; FGroupViewInfo := AGroupViewInfo; end; function TdxLayoutGroupViewInfoSpecific.GetItemOffset: Integer; begin Result := FGroupViewInfo.ItemOffset; end; function TdxLayoutGroupViewInfoSpecific.GetItemViewInfo(Index: Integer): TdxCustomLayoutItemViewInfo; begin Result := FGroupViewInfo.ItemViewInfos[Index]; end; function TdxLayoutGroupViewInfoSpecific.GetItemViewInfoCount: Integer; begin Result := FGroupViewInfo.ItemViewInfoCount; end; function TdxLayoutGroupViewInfoSpecific.GetLayoutDirection: TdxLayoutDirection; begin Result := FGroupViewInfo.LayoutDirection; end; function TdxLayoutGroupViewInfoSpecific.DoCalculateHeight: Integer; begin Result := GetCustomHeight(GetItemHeight); end; function TdxLayoutGroupViewInfoSpecific.DoCalculateWidth: Integer; begin Result := GetCustomWidth(GetItemWidth); end; function TdxLayoutGroupViewInfoSpecific.DoCalculateMinHeight: Integer; begin Result := GetCustomHeight(GetItemMinHeight); end; function TdxLayoutGroupViewInfoSpecific.DoCalculateMinWidth: Integer; begin Result := GetCustomWidth(GetItemMinWidth); end; function TdxLayoutGroupViewInfoSpecific.GetCustomHeight(AGetItemCustomHeight: TdxLayoutGroupViewInfoGetItemSizeEvent): Integer; var I, AItemHeight: Integer; begin Result := 0; for I := 0 to ItemViewInfoCount - 1 do begin AItemHeight := AGetItemCustomHeight(ItemViewInfos[I]); if AItemHeight > Result then Result := AItemHeight; end; end; function TdxLayoutGroupViewInfoSpecific.GetCustomWidth(AGetItemCustomWidth: TdxLayoutGroupViewInfoGetItemSizeEvent): Integer; var AIsFirstItem: Boolean; I, AItemWidth: Integer; AItemViewInfo: TdxCustomLayoutItemViewInfo; begin Result := 0; AIsFirstItem := True; for I := 0 to ItemViewInfoCount - 1 do begin AItemViewInfo := ItemViewInfos[I]; if GetItemAlignHorz(AItemViewInfo) <> ahCenter then begin if not AIsFirstItem then Inc(Result, ItemOffset); AItemWidth := AGetItemCustomWidth(AItemViewInfo); Inc(Result, AItemWidth); AIsFirstItem := False; end; end; for I := 0 to ItemViewInfoCount - 1 do begin AItemViewInfo := ItemViewInfos[I]; if GetItemAlignHorz(AItemViewInfo) = ahCenter then begin AItemWidth := AGetItemCustomWidth(AItemViewInfo); if AItemWidth > Result then Result := AItemWidth; end; end; end; procedure TdxLayoutGroupViewInfoSpecific.ConvertCoords(var R: TRect); begin end; procedure TdxLayoutGroupViewInfoSpecific.CalculateItemsBounds(AItemsAreaBounds: TRect); type TItemInfo = record ViewInfo: TdxCustomLayoutItemViewInfo; AlignHorz: TdxLayoutAlignHorz; CalculatedWidth, MinWidth, Width, Height: Integer; Bounds: TRect; Calculated: Boolean; end; PItemInfos = ^TItemInfos; TItemInfos = array[0..MaxInt div SizeOf(TItemInfo) - 1] of TItemInfo; var AItemInfos: PItemInfos; procedure PrepareItemInfos; var I: Integer; begin for I := 0 to ItemViewInfoCount - 1 do with AItemInfos^[I] do begin ViewInfo := ItemViewInfos[I]; AlignHorz := GetItemAlignHorz(ViewInfo); CalculatedWidth := GetItemWidth(ViewInfo); Height := GetItemHeight(ViewInfo); MinWidth := GetItemMinWidth(ViewInfo); Calculated := False; end; end; procedure CalculateItemsHorizontalBounds; var ASpace, AAvailableSpace: Integer; procedure CalculateSpaces; var AItemOffsets, I: Integer; AIsFirstItem: Boolean; begin AItemOffsets := 0; ASpace := 0; AIsFirstItem := True; for I := 0 to ItemViewInfoCount - 1 do with AItemInfos^[I] do if AlignHorz <> ahCenter then begin if not AIsFirstItem then Inc(AItemOffsets, ItemOffset); Inc(ASpace, CalculatedWidth); AIsFirstItem := False; end; with AItemsAreaBounds do AAvailableSpace := Right - Left - AItemOffsets; end; procedure RemoveNonClientItemsFromCalculating; var I: Integer; begin for I := 0 to ItemViewInfoCount - 1 do with AItemInfos^[I] do if AlignHorz <> ahClient then begin Width := CalculatedWidth; if AlignHorz <> ahCenter then begin Dec(ASpace, Width); Dec(AAvailableSpace, Width); end; Calculated := True; end; end; procedure CalculateClientItemsVisibleSizes; var ANeedRecalculating: Boolean; ANextSpace, ANextAvailableSpace, AOffset, I: Integer; begin repeat ANeedRecalculating := False; ANextSpace := ASpace; ANextAvailableSpace := AAvailableSpace; AOffset := 0; for I := 0 to ItemViewInfoCount - 1 do with AItemInfos^[I] do if not Calculated then begin Width := MulDiv(AAvailableSpace, AOffset + CalculatedWidth, ASpace) - MulDiv(AAvailableSpace, AOffset, ASpace); if Width < MinWidth then begin Width := MinWidth; Dec(ANextSpace, CalculatedWidth); Dec(ANextAvailableSpace, Width); Calculated := True; ANeedRecalculating := True; end; end; ASpace := ANextSpace; AAvailableSpace := ANextAvailableSpace; until not ANeedRecalculating; end; procedure CalculateItemsBounds; procedure ProcessLeftAlignedItems; var AOffset, I: Integer; begin AOffset := AItemsAreaBounds.Left; for I := 0 to ItemViewInfoCount - 1 do with AItemInfos^[I] do case AlignHorz of ahLeft, ahClient: begin Bounds.Left := AOffset; Bounds.Right := AOffset + Width; Inc(AOffset, Width + ItemOffset); end; ahCenter: begin Bounds.Left := (AItemsAreaBounds.Left + AItemsAreaBounds.Right - Width) div 2; Bounds.Right := Bounds.Left + Width; end; end; end; procedure ProcessRightAlignedItems; var AOffset, I: Integer; begin AOffset := AItemsAreaBounds.Right; for I := ItemViewInfoCount - 1 downto 0 do with AItemInfos^[I] do if AlignHorz = ahRight then begin Bounds.Right := AOffset; Bounds.Left := AOffset - Width; Dec(AOffset, Width + ItemOffset); end; end; begin ProcessLeftAlignedItems; ProcessRightAlignedItems; end; begin CalculateSpaces; RemoveNonClientItemsFromCalculating; CalculateClientItemsVisibleSizes; CalculateItemsBounds; end; procedure CalculateItemsVerticalBounds; var I: Integer; begin for I := 0 to ItemViewInfoCount - 1 do with AItemInfos^[I] do case GetItemAlignVert(ViewInfo) of avTop: begin Bounds.Top := AItemsAreaBounds.Top; Bounds.Bottom := Bounds.Top + Height; end; avCenter: begin Bounds.Top := (AItemsAreaBounds.Top + AItemsAreaBounds.Bottom - Height) div 2; Bounds.Bottom := Bounds.Top + Height; end; avBottom: begin Bounds.Bottom := AItemsAreaBounds.Bottom; Bounds.Top := Bounds.Bottom - Height; end; avClient: begin Bounds.Top := AItemsAreaBounds.Top; Bounds.Bottom := AItemsAreaBounds.Bottom; end; end; end; procedure CalculateItemViewInfos; var I: Integer; begin for I := 0 to ItemViewInfoCount - 1 do with AItemInfos^[I] do begin ConvertCoords(Bounds); ViewInfo.Calculate(Bounds); end; end; begin GetMem(AItemInfos, ItemViewInfoCount * SizeOf(TItemInfo)); try ConvertCoords(AItemsAreaBounds); PrepareItemInfos; CalculateItemsHorizontalBounds; CalculateItemsVerticalBounds; CalculateItemViewInfos; finally FreeMem(AItemInfos); end; end; function TdxLayoutGroupViewInfoSpecific.CalculateHeight(AIsMinHeight: Boolean = False): Integer; begin if AIsMinHeight then Result := DoCalculateMinHeight else Result := DoCalculateHeight; end; function TdxLayoutGroupViewInfoSpecific.CalculateWidth(AIsMinWidth: Boolean = False): Integer; begin if AIsMinWidth then Result := DoCalculateMinWidth else Result := DoCalculateWidth; end; { TdxLayoutGroupHorizontalSpecific } function TdxLayoutGroupViewInfoHorizontalSpecific.GetItemAlignHorz(AViewInfo: TdxCustomLayoutItemViewInfo): TdxLayoutAlignHorz; begin Result := AViewInfo.AlignHorz; end; function TdxLayoutGroupViewInfoHorizontalSpecific.GetItemAlignVert(AViewInfo: TdxCustomLayoutItemViewInfo): TdxLayoutAlignVert; begin Result := AViewInfo.AlignVert; end; function TdxLayoutGroupViewInfoHorizontalSpecific.GetItemHeight(AViewInfo: TdxCustomLayoutItemViewInfo): Integer; begin Result := AViewInfo.CalculateHeight; end; function TdxLayoutGroupViewInfoHorizontalSpecific.GetItemMinHeight(AViewInfo: TdxCustomLayoutItemViewInfo): Integer; begin Result := AViewInfo.MinHeight; end; function TdxLayoutGroupViewInfoHorizontalSpecific.GetItemMinWidth(AViewInfo: TdxCustomLayoutItemViewInfo): Integer; begin Result := AViewInfo.MinWidth; end; function TdxLayoutGroupViewInfoHorizontalSpecific.GetItemWidth(AViewInfo: TdxCustomLayoutItemViewInfo): Integer; begin Result := AViewInfo.CalculateWidth; end; function TdxLayoutGroupViewInfoHorizontalSpecific.IsAtInsertionPos(const R: TRect; const P: TPoint): Boolean; begin Result := P.X < (R.Left + R.Right) div 2; end; { TdxLayoutGroupViewInfoVerticalSpecific } procedure TdxLayoutGroupViewInfoVerticalSpecific.ConvertCoords(var R: TRect); var Temp: Integer; begin with R do begin Temp := Left; Left := Top; Top := Temp; Temp := Right; Right := Bottom; Bottom := Temp; end; end; function TdxLayoutGroupViewInfoVerticalSpecific.GetItemAlignHorz(AViewInfo: TdxCustomLayoutItemViewInfo): TdxLayoutAlignHorz; begin Result := TdxLayoutAlignHorz(AViewInfo.AlignVert); end; function TdxLayoutGroupViewInfoVerticalSpecific.GetItemAlignVert(AViewInfo: TdxCustomLayoutItemViewInfo): TdxLayoutAlignVert; begin Result := TdxLayoutAlignVert(AViewInfo.AlignHorz); end; function TdxLayoutGroupViewInfoVerticalSpecific.GetItemHeight(AViewInfo: TdxCustomLayoutItemViewInfo): Integer; begin Result := AViewInfo.CalculateWidth; end; function TdxLayoutGroupViewInfoVerticalSpecific.GetItemMinHeight(AViewInfo: TdxCustomLayoutItemViewInfo): Integer; begin Result := AViewInfo.MinWidth; end; function TdxLayoutGroupViewInfoVerticalSpecific.GetItemMinWidth(AViewInfo: TdxCustomLayoutItemViewInfo): Integer; begin Result := AViewInfo.MinHeight; end; function TdxLayoutGroupViewInfoVerticalSpecific.GetItemWidth(AViewInfo: TdxCustomLayoutItemViewInfo): Integer; begin Result := AViewInfo.CalculateHeight; end; function TdxLayoutGroupViewInfoVerticalSpecific.CalculateHeight(AIsMinHeight: Boolean = False): Integer; begin Result := inherited CalculateWidth(AIsMinHeight); end; function TdxLayoutGroupViewInfoVerticalSpecific.CalculateWidth(AIsMinWidth: Boolean = False): Integer; begin Result := inherited CalculateHeight(AIsMinWidth); end; function TdxLayoutGroupViewInfoVerticalSpecific.IsAtInsertionPos(const R: TRect; const P: TPoint): Boolean; begin Result := P.Y < (R.Top + R.Bottom) div 2; end; { TdxLayoutGroupViewInfo } constructor TdxLayoutGroupViewInfo.Create(AControlViewInfo: TdxLayoutControlViewInfo; AParentViewInfo: TdxLayoutGroupViewInfo; AItem: TdxCustomLayoutItem); begin inherited; CreateSpecific; CreateItemViewInfos; end; destructor TdxLayoutGroupViewInfo.Destroy; begin DestroyItemViewInfos; DestroySpecific; inherited; end; function TdxLayoutGroupViewInfo.GetBorderBounds(ASide: TdxLayoutSide): TRect; begin Result := Bounds; with ClientBounds do case ASide of sdLeft: Result.Right := Left; sdTop: Result.Bottom := Top; sdRight: Result.Left := Right; sdBottom: Result.Top := Bottom; end; end; function TdxLayoutGroupViewInfo.GetBorderRestSpaceBounds(ASide: TdxLayoutSide): TRect; begin Result := RestSpaceBounds; with ClientBounds do case ASide of sdLeft: Result.Right := Left; sdTop: Result.Bottom := Top; sdRight: Result.Left := Right; sdBottom: Result.Top := Bottom; end; end; function TdxLayoutGroupViewInfo.GetBordersHeight: Integer; begin Result := BorderWidths[sdLeft] + BorderWidths[sdRight]; end; function TdxLayoutGroupViewInfo.GetBordersWidth: Integer; begin Result := BorderWidths[sdTop] + BorderWidths[sdBottom]; end; function TdxLayoutGroupViewInfo.GetCaptionViewInfo: TdxLayoutGroupCaptionViewInfo; begin Result := TdxLayoutGroupCaptionViewInfo(inherited CaptionViewInfo); end; function TdxLayoutGroupViewInfo.GetGroup: TdxLayoutGroup; begin Result := TdxLayoutGroup(inherited Item); end; function TdxLayoutGroupViewInfo.GetIsLocked: Boolean; begin Result := Group.Locked and IsCustomization or IsParentLocked; end; function TdxLayoutGroupViewInfo.GetItemViewInfo(Index: Integer): TdxCustomLayoutItemViewInfo; begin Result := TdxCustomLayoutItemViewInfo(FItemViewInfos[Index]); end; function TdxLayoutGroupViewInfo.GetItemViewInfoCount: Integer; begin Result := FItemViewInfos.Count; end; function TdxLayoutGroupViewInfo.GetLayoutDirection: TdxLayoutDirection; begin Result := Group.LayoutDirection; end; function TdxLayoutGroupViewInfo.GetOptionsEx: TdxLayoutLookAndFeelGroupOptions; begin Result := TdxLayoutLookAndFeelGroupOptions(inherited Options); end; procedure TdxLayoutGroupViewInfo.CreateItemViewInfos; var I: Integer; AItem: TdxCustomLayoutItem; AItemViewInfo: TdxCustomLayoutItemViewInfo; begin FItemViewInfos := TList.Create; for I := 0 to Group.VisibleCount - 1 do begin AItem := Group.VisibleItems[I]; AItemViewInfo := GetItemViewInfoClass(AItem).Create(FContainerViewInfo, Self, AItem); FItemViewInfos.Add(AItemViewInfo); end; end; procedure TdxLayoutGroupViewInfo.CreateSpecific; begin FSpecific := GetSpecificClass.Create(Self); end; procedure TdxLayoutGroupViewInfo.DestroyItemViewInfos; var I: Integer; begin for I := 0 to ItemViewInfoCount - 1 do ItemViewInfos[I].Free; FreeAndNil(FItemViewInfos); end; procedure TdxLayoutGroupViewInfo.DestroySpecific; begin FreeAndNil(FSpecific); end; function TdxLayoutGroupViewInfo.GetCaptionViewInfoClass: TdxCustomLayoutItemCaptionViewInfoClass; begin Result := TdxLayoutGroupCaptionViewInfo; end; function TdxLayoutGroupViewInfo.GetHitTestClass: TdxCustomLayoutItemHitTestClass; begin Result := TdxLayoutGroupHitTest; end; function TdxLayoutGroupViewInfo.GetPainterClass: TdxCustomLayoutItemPainterClass; begin Result := TdxCustomLayoutItemPainterClass(LookAndFeel.GetGroupPainterClass); end; function TdxLayoutGroupViewInfo.DoCalculateHeight(AIsMinHeight: Boolean = False): Integer; begin Result := inherited DoCalculateHeight(AIsMinHeight) + GetHeight(Specific.CalculateHeight(AIsMinHeight)); end; function TdxLayoutGroupViewInfo.DoCalculateWidth(AIsMinWidth: Boolean = False): Integer; begin Result := inherited DoCalculateWidth(AIsMinWidth) + GetWidth(Specific.CalculateWidth(AIsMinWidth)); end; function TdxLayoutGroupViewInfo.CalculateCaptionViewInfoBounds: TRect; begin Result := Rect(0, 0, 0, 0); end; function TdxLayoutGroupViewInfo.CalculateItemsAreaBounds: TRect; begin Result := Bounds; Inc(Result.Left, BorderWidths[sdLeft]); Inc(Result.Top, BorderWidths[sdTop]); Dec(Result.Right, BorderWidths[sdRight]); Dec(Result.Bottom, BorderWidths[sdBottom]); end; procedure TdxLayoutGroupViewInfo.CalculateConsts; begin if UseItemsAreaOffsets then if Group.IsRoot then begin ItemsAreaOffsetHorz := LookAndFeel.GetRootItemsAreaOffsetHorz(Item.Container); ItemsAreaOffsetVert := LookAndFeel.GetRootItemsAreaOffsetVert(Item.Container); end else begin ItemsAreaOffsetHorz := LookAndFeel.GetItemsAreaOffsetHorz(Item.Container); ItemsAreaOffsetVert := LookAndFeel.GetItemsAreaOffsetVert(Item.Container); end else begin ItemsAreaOffsetHorz := 0; ItemsAreaOffsetVert := 0; end; if UseItemOffset then ItemOffset := LookAndFeel.GetItemOffset(Item.Container) else ItemOffset := 0; end; function TdxLayoutGroupViewInfo.GetBorderWidth(ASide: TdxLayoutSide): Integer; begin case ASide of sdLeft, sdRight: Result := ItemsAreaOffsetHorz; sdTop, sdBottom: Result := ItemsAreaOffsetVert; else Result := 0; end; if HasBorder then Inc(Result, LookAndFeel.GetGroupBorderWidth(Item.Container, ASide, HasCaption)); end; function TdxLayoutGroupViewInfo.GetClientBounds: TRect; begin Result := Bounds; if HasBorder then with LookAndFeel, Result do begin Inc(Left, GetGroupBorderWidth(Item.Container, sdLeft, HasCaption)); Dec(Right, GetGroupBorderWidth(Item.Container, sdRight, HasCaption)); Inc(Top, GetGroupBorderWidth(Item.Container, sdTop, HasCaption)); Dec(Bottom, GetGroupBorderWidth(Item.Container, sdBottom, HasCaption)); end; end; function TdxLayoutGroupViewInfo.GetColor: TColor; begin Result := Options.GetColor; end; function TdxLayoutGroupViewInfo.GetConst(Index: Integer): Integer; begin if not FConstsCalculated then begin CalculateConsts; FConstsCalculated := True; end; case Index of 2: Result := FItemOffset; 3: Result := FItemsAreaOffsetHorz; 4: Result := FItemsAreaOffsetVert; else Result := -1; end; end; function TdxLayoutGroupViewInfo.GetHeight(AItemsAreaHeight: Integer): Integer; begin Result := BorderWidths[sdTop] + AItemsAreaHeight + BorderWidths[sdBottom]; end; function TdxLayoutGroupViewInfo.GetIsDefaultColor: Boolean; begin Result := Options.Color = clDefault; end; function TdxLayoutGroupViewInfo.GetItemViewInfoClass(AItem: TdxCustomLayoutItem): TdxCustomLayoutItemViewInfoClass; begin Result := AItem.GetViewInfoClass; end; function TdxLayoutGroupViewInfo.GetMinVisibleWidth: Integer; begin if HasCaption then Result := CaptionViewInfo.MinWidth else Result := 0; end; function TdxLayoutGroupViewInfo.GetOptions: TdxCustomLayoutLookAndFeelOptions; begin Result := LookAndFeel.GroupOptions; end; function TdxLayoutGroupViewInfo.GetRestSpaceBounds: TRect; begin Result := Bounds; end; function TdxLayoutGroupViewInfo.GetSpecificClass: TdxLayoutGroupViewInfoSpecificClass; begin case LayoutDirection of ldHorizontal: Result := TdxLayoutGroupViewInfoHorizontalSpecific; ldVertical: Result := TdxLayoutGroupViewInfoVerticalSpecific; else Result := nil; end; end; function TdxLayoutGroupViewInfo.GetWidth(AItemsAreaWidth: Integer): Integer; begin Result := BorderWidths[sdLeft] + AItemsAreaWidth + BorderWidths[sdRight]; if Result < MinVisibleWidth then Result := MinVisibleWidth; end; function TdxLayoutGroupViewInfo.HasBorder: Boolean; begin Result := Group.ShowBorder; end; function TdxLayoutGroupViewInfo.HasBoundsFrame: Boolean; begin Result := Group.Hidden and Group.Container.ShowHiddenGroupsBounds; end; function TdxLayoutGroupViewInfo.UseItemOffset: Boolean; begin Result := Group.UseIndent; end; function TdxLayoutGroupViewInfo.UseItemsAreaOffsets: Boolean; begin Result := Group.ShowBorder or Group.IsRoot; end; procedure TdxLayoutGroupViewInfo.Calculate(const ABounds: TRect); begin inherited; FItemsAreaBounds := CalculateItemsAreaBounds; CaptionViewInfo.Calculate(CalculateCaptionViewInfoBounds); Specific.CalculateItemsBounds(ItemsAreaBounds); end; procedure TdxLayoutGroupViewInfo.CalculateTabOrders(var AAvailTabOrder: Integer); var I: Integer; begin for I := 0 to ItemViewInfoCount - 1 do ItemViewInfos[I].CalculateTabOrders(AAvailTabOrder); end; function TdxLayoutGroupViewInfo.GetHitTest(const P: TPoint): TdxCustomLayoutHitTest; var I: Integer; begin for I := 0 to ItemViewInfoCount - 1 do begin Result := ItemViewInfos[I].GetHitTest(P); if Result <> nil then Exit; end; if ContainerViewInfo.HideHiddenGroupsFromHitTest and Group.Hidden and not IsLocked then Result := nil else Result := inherited GetHitTest(P); end; function TdxLayoutGroupViewInfo.GetInsertionPos(const P: TPoint): Integer; var R: TRect; begin if PtInRect(Bounds, P) then for Result := 0 to ItemViewInfoCount - 1 do begin R := ItemViewInfos[Result].Bounds; if Specific.IsAtInsertionPos(R, P) then Exit; end; Result := ItemViewInfoCount; end; { TdxLayoutGroupStandardCaptionViewInfo } function TdxLayoutGroupStandardCaptionViewInfo.GetItemViewInfo: TdxLayoutGroupStandardViewInfo; begin Result := TdxLayoutGroupStandardViewInfo(inherited ItemViewInfo); end; function TdxLayoutGroupStandardCaptionViewInfo.GetAlignHorz: TAlignment; begin Result := taCenter; end; function TdxLayoutGroupStandardCaptionViewInfo.CalculateWidth: Integer; begin Result := inherited CalculateWidth; if Visible then Inc(Result, 2 + 2); end; { TdxLayoutGroupStandardViewInfo } function TdxLayoutGroupStandardViewInfo.GetLookAndFeel: TdxLayoutStandardLookAndFeel; begin Result := TdxLayoutStandardLookAndFeel(inherited LookAndFeel); end; function TdxLayoutGroupStandardViewInfo.CalculateCaptionViewInfoBounds: TRect; var ACaptionWidth: Integer; begin Result := BorderBounds[sdTop]; ACaptionWidth := CaptionViewInfo.CalculateWidth; with Result do begin case Item.CaptionOptions.AlignHorz of taLeftJustify: begin Inc(Left, CaptionViewInfoOffset); Right := Left + ACaptionWidth; end; taRightJustify: begin Dec(Right, CaptionViewInfoOffset); Left := Right - ACaptionWidth; end; taCenter: begin Left := (Left + Right - ACaptionWidth) div 2; Right := Left + ACaptionWidth; end; end; Bottom := Top + CaptionViewInfo.CalculateHeight; end; end; function TdxLayoutGroupStandardViewInfo.GetCaptionViewInfoClass: TdxCustomLayoutItemCaptionViewInfoClass; begin Result := TdxLayoutGroupStandardCaptionViewInfo; end; function TdxLayoutGroupStandardViewInfo.GetMinVisibleWidth: Integer; begin Result := inherited GetMinVisibleWidth; if HasCaption then Inc(Result, 2 * CaptionViewInfoOffset); end; function TdxLayoutGroupStandardViewInfo.GetCaptionViewInfoOffset: Integer; begin Result := LookAndFeel.HDLUToPixels(CaptionViewInfo.Font, 7) - 2; end; function TdxLayoutGroupStandardViewInfo.GetFrameBounds: TRect; begin Result := Bounds; Inc(Result.Top, LookAndFeel.VDLUToPixels(CaptionViewInfo.Font, 4) - LookAndFeel.FrameWidths[sdTop] div 2); end; { TdxLayoutGroupOfficeCaptionViewInfo } function TdxLayoutGroupOfficeCaptionViewInfo.CalculateWidth: Integer; var AOffset: Integer; begin Result := inherited CalculateWidth; if Visible then begin AOffset := LookAndFeel.HDLUToPixels(Font, 5); if AlignHorz = taCenter then AOffset := 2 * AOffset; Inc(Result, AOffset); end; end; { TdxLayoutGroupOfficeViewInfo } function TdxLayoutGroupOfficeViewInfo.GetCaptionViewInfoClass: TdxCustomLayoutItemCaptionViewInfoClass; begin Result := TdxLayoutGroupOfficeCaptionViewInfo; end; function TdxLayoutGroupOfficeViewInfo.GetCaptionViewInfoOffset: Integer; begin Result := 0; end; function TdxLayoutGroupOfficeViewInfo.GetFrameBounds: TRect; begin Result := inherited GetFrameBounds; with Result do Bottom := Top + 2; end; function TdxLayoutGroupOfficeViewInfo.GetMinVisibleWidth: Integer; begin Result := inherited GetMinVisibleWidth; if HasCaption then Inc(Result, 20); end; { TdxLayoutGroupWebCaptionViewInfo } function TdxLayoutGroupWebCaptionViewInfo.GetItemViewInfo: TdxLayoutGroupWebViewInfo; begin Result := TdxLayoutGroupWebViewInfo(inherited ItemViewInfo); end; function TdxLayoutGroupWebCaptionViewInfo.GetLookAndFeel: TdxLayoutWebLookAndFeel; begin Result := TdxLayoutWebLookAndFeel(inherited LookAndFeel); end; function TdxLayoutGroupWebCaptionViewInfo.GetOptionsEx: TdxLayoutWebLookAndFeelGroupCaptionOptions; begin Result := TdxLayoutWebLookAndFeelGroupCaptionOptions(inherited Options); end; function TdxLayoutGroupWebCaptionViewInfo.GetSeparatorWidth: Integer; begin Result := Options.SeparatorWidth; end; function TdxLayoutGroupWebCaptionViewInfo.GetAlignVert: TdxAlignmentVert; begin Result := tavCenter; end; function TdxLayoutGroupWebCaptionViewInfo.GetColor: TColor; begin Result := Options.GetColor; end; function TdxLayoutGroupWebCaptionViewInfo.GetIsDefaultColor: Boolean; begin Result := Options.Color = clDefault; end; function TdxLayoutGroupWebCaptionViewInfo.GetMinWidth: Integer; begin Result := 2 * TextOffset + inherited GetMinWidth; end; function TdxLayoutGroupWebCaptionViewInfo.GetTextAreaBounds: TRect; begin Result := inherited GetTextAreaBounds; Inc(Result.Left, TextOffset); end; function TdxLayoutGroupWebCaptionViewInfo.GetTextOffset: Integer; begin if ItemViewInfo.Options.OffsetCaption then Result := LookAndFeel.VDLUToPixels(Font, 5) else Result := LookAndFeel.DLUToPixels(Font, 2); end; function TdxLayoutGroupWebCaptionViewInfo.CalculateHeight: Integer; begin if Visible then Result := LookAndFeel.VDLUToPixels(Font, 11{12}) else Result := inherited CalculateHeight; end; { TdxLayoutGroupWebViewInfo } function TdxLayoutGroupWebViewInfo.GetCaptionViewInfo: TdxLayoutGroupWebCaptionViewInfo; begin Result := TdxLayoutGroupWebCaptionViewInfo(inherited CaptionViewInfo); end; function TdxLayoutGroupWebViewInfo.GetInsideFrameBounds: TRect; begin Result := Bounds; with Options do InflateRect(Result, -FrameWidth, -FrameWidth); end; function TdxLayoutGroupWebViewInfo.GetLookAndFeel: TdxLayoutWebLookAndFeel; begin Result := TdxLayoutWebLookAndFeel(inherited LookAndFeel); end; function TdxLayoutGroupWebViewInfo.GetOptionsEx: TdxLayoutWebLookAndFeelGroupOptions; begin Result := TdxLayoutWebLookAndFeelGroupOptions(inherited Options); end; function TdxLayoutGroupWebViewInfo.CalculateCaptionViewInfoBounds: TRect; begin Result := InsideFrameBounds; Result.Bottom := Result.Top + CaptionViewInfo.CalculateHeight; end; function TdxLayoutGroupWebViewInfo.GetCaptionViewInfoClass: TdxCustomLayoutItemCaptionViewInfoClass; begin Result := TdxLayoutGroupWebCaptionViewInfo; end; function TdxLayoutGroupWebViewInfo.GetMinVisibleWidth: Integer; begin Result := inherited GetMinVisibleWidth; Inc(Result, 2 * Options.FrameWidth); end; function TdxLayoutGroupWebViewInfo.GetRestSpaceBounds: TRect; begin Result := inherited GetRestSpaceBounds; with Options do InflateRect(Result, -FrameWidth, -FrameWidth); if HasCaption then Result.Top := CaptionViewInfo.Bounds.Bottom; if Options.HasCaptionSeparator(HasCaption) then Inc(Result.Top, CaptionViewInfo.SeparatorWidth); end; function TdxLayoutGroupWebViewInfo.GetCaptionSeparatorAreaBounds: TRect; begin Result := RestSpaceBounds; Result.Bottom := Result.Top; Dec(Result.Top, CaptionViewInfo.SeparatorWidth); end; function TdxLayoutGroupWebViewInfo.GetCaptionSeparatorBounds: TRect; begin Result := CaptionSeparatorAreaBounds; if not Options.OffsetCaption and not Options.OffsetItems and (Options.FrameWidth = 0) and (CaptionViewInfo.Color = Color) then with ClientBounds do begin Result.Left := Left; Result.Right := Right; end; end; { TdxLayoutControlViewInfo } constructor TdxLayoutControlViewInfo.Create(AControl: TdxCustomLayoutControl); begin inherited; CreateViewInfos; end; destructor TdxLayoutControlViewInfo.Destroy; begin DestroyViewInfos; FCanvas.Free; inherited; end; function TdxLayoutControlViewInfo.GetClientHeight: Integer; begin with ClientBounds do Result := Bottom - Top; end; function TdxLayoutControlViewInfo.GetClientWidth: Integer; begin with ClientBounds do Result := Right - Left; end; function TdxLayoutControlViewInfo.GetContentHeight: Integer; begin with ContentBounds do Result := Bottom - Top; end; function TdxLayoutControlViewInfo.GetContentWidth: Integer; begin with ContentBounds do Result := Right - Left; end; function TdxLayoutControlViewInfo.GetLookAndFeel: TdxCustomLayoutLookAndFeel; begin Result := FControl.GetLookAndFeel; end; procedure TdxLayoutControlViewInfo.CreateViewInfos; begin if LookAndFeel <> nil then FItemsViewInfo := GetItemsViewInfoClass.Create(Self, nil, FControl.Items); end; procedure TdxLayoutControlViewInfo.DestroyViewInfos; begin FreeAndNil(FItemsViewInfo); end; function TdxLayoutControlViewInfo.GetItemsViewInfoClass: TdxLayoutGroupViewInfoClass; begin Result := TdxLayoutGroupViewInfoClass(FControl.Items.GetViewInfoClass); end; procedure TdxLayoutControlViewInfo.RecreateViewInfos; begin DestroyViewInfos; CreateViewInfos; end; procedure TdxLayoutControlViewInfo.AlignItems; var I: Integer; procedure ProcessConstraint(AConstraint: TdxLayoutAlignmentConstraint); var AItemViewInfos: TList; procedure RetrieveItemViewInfos; var I: Integer; AViewInfo: TdxCustomLayoutItemViewInfo; begin for I := 0 to AConstraint.Count - 1 do begin AViewInfo := AConstraint.Items[I].ViewInfo; if AViewInfo <> nil then AItemViewInfos.Add(AViewInfo); end; end; function GetSide: TdxLayoutSide; begin if AConstraint.Kind in [ackLeft, ackRight] then Result := sdLeft else Result := sdTop; end; function AlignItemViewInfos: Boolean; var AMaxBorderValue, I: Integer; function GetBorderValue(AItemViewInfoIndex: Integer): Integer; begin with TdxCustomLayoutItemViewInfo(AItemViewInfos[AItemViewInfoIndex]), Bounds do case AConstraint.Kind of ackLeft: Result := Left - CalculateOffset(sdLeft); ackTop: Result := Top - CalculateOffset(sdTop); ackRight: Result := Right + CalculateOffset(sdRight); ackBottom: Result := Bottom + CalculateOffset(sdBottom); else Result := 0; end; end; function FindMaxBorderValue: Integer; var I: Integer; begin Result := -MaxInt; for I := 0 to AItemViewInfos.Count - 1 do if Result < GetBorderValue(I) then Result := GetBorderValue(I); end; procedure ChangeOffset(AItemViewInfoIndex, ADelta: Integer); begin with TdxCustomLayoutItemViewInfo(AItemViewInfos[AItemViewInfoIndex]) do Offsets[GetSide] := Offsets[GetSide] + ADelta; end; function AreItemViewInfosAligned: Boolean; var I, ABorderValue: Integer; begin ABorderValue := 0; for I := 0 to AItemViewInfos.Count - 1 do if I = 0 then ABorderValue := GetBorderValue(I) else begin Result := GetBorderValue(I) = ABorderValue; if not Result then Exit; end; Result := True; end; begin AMaxBorderValue := FindMaxBorderValue; for I := 0 to AItemViewInfos.Count - 1 do ChangeOffset(I, AMaxBorderValue - GetBorderValue(I)); CalculateItemsViewInfo; Result := AreItemViewInfosAligned; end; procedure ResetOffsets; var I: Integer; begin for I := 0 to AItemViewInfos.Count - 1 do TdxCustomLayoutItemViewInfo(AItemViewInfos[I]).ResetOffset(GetSide); CalculateItemsViewInfo; end; begin AItemViewInfos := TList.Create; try RetrieveItemViewInfos; while not AlignItemViewInfos do //!!! to think about invisible items if items will be deleted begin ResetOffsets; if AItemViewInfos.Count > 2 then AItemViewInfos.Count := AItemViewInfos.Count - 1 else Break; end; finally AItemViewInfos.Free; end; end; begin for I := 0 to FControl.AlignmentConstraintCount - 1 do ProcessConstraint(FControl.AlignmentConstraints[I]); end; function CompareAllItemViewInfos(Item1, Item2: TdxLayoutItemViewInfo): Integer; begin Result := Ord(Item2.CaptionLayout) - Ord(Item1.CaptionLayout); end; function CompareItemViewInfos(Item1, Item2: TdxLayoutItemViewInfo): Integer; begin case Item1.CaptionLayout of clLeft: Result := Item1.Bounds.Left - Item2.Bounds.Left; clTop: Result := Item1.Bounds.Top - Item2.Bounds.Top; clRight: Result := Item1.Bounds.Right - Item2.Bounds.Right; clBottom: Result := Item1.Bounds.Bottom - Item2.Bounds.Bottom; else Result := 0; end; end; procedure TdxLayoutControlViewInfo.AutoAlignControls; var AAllItemViewInfos: TList; ACaptionLayout: TdxCaptionLayout; procedure FindAllItemViewInfos(ACustomItemViewInfo: TdxCustomLayoutItemViewInfo); var I: Integer; begin if ACustomItemViewInfo is TdxLayoutGroupViewInfo then with TdxLayoutGroupViewInfo(ACustomItemViewInfo) do for I := 0 to ItemViewInfoCount - 1 do FindAllItemViewInfos(ItemViewInfos[I]) else if TdxLayoutItemViewInfo(ACustomItemViewInfo).AutoControlAlignment then AAllItemViewInfos.Add(ACustomItemViewInfo); end; procedure SortAllItemViewInfos; begin AAllItemViewInfos.Sort(@CompareAllItemViewInfos); end; procedure ProcessItemViewInfos(ACaptionLayout: TdxCaptionLayout); var AItemViewInfos: TList; AGroupedCount: Integer; procedure ExtractItemViewInfos; var I, ACount: Integer; begin I := AAllItemViewInfos.Count - 1; while (I <> -1) and (TdxLayoutItemViewInfo(AAllItemViewInfos[I]).CaptionLayout = ACaptionLayout) do Dec(I); ACount := AAllItemViewInfos.Count - 1 - I; AItemViewInfos.Count := ACount; Move(AAllItemViewInfos.List^[I + 1], AItemViewInfos.List^[0], ACount * SizeOf(Pointer)); AAllItemViewInfos.Count := I + 1; end; procedure SortItemViewInfos; begin AItemViewInfos.Sort(@CompareItemViewInfos); end; function FindGroup: Boolean; var AItemViewInfo1, AItemViewInfo2: TdxLayoutItemViewInfo; begin AItemViewInfo1 := AItemViewInfos[0]; AGroupedCount := 1; while AGroupedCount < AItemViewInfos.Count do begin AItemViewInfo2 := AItemViewInfos[AGroupedCount]; if CompareItemViewInfos(AItemViewInfo1, AItemViewInfo2) <> 0 then Break; Inc(AGroupedCount); end; Result := AGroupedCount <> 1; end; procedure AlignControls; function IsCaptionLayoutHorizontal: Boolean; begin Result := ACaptionLayout in [clLeft, clRight]; end; function GetMaxCaptionSize: Integer; var I, ACaptionSize: Integer; begin Result := 0; for I := 0 to AGroupedCount - 1 do begin with TdxLayoutItemViewInfo(AItemViewInfos[I]).CaptionViewInfo do if IsCaptionLayoutHorizontal then ACaptionSize := Width else ACaptionSize := Height; if Result < ACaptionSize then Result := ACaptionSize; end; end; procedure AssignCaptionSizes(AMaxCaptionSize: Integer); var I: Integer; begin for I := 0 to AGroupedCount - 1 do with TdxLayoutItemViewInfo(AItemViewInfos[I]).CaptionViewInfo do if IsCaptionLayoutHorizontal then Width := AMaxCaptionSize else Height := AMaxCaptionSize; end; begin AssignCaptionSizes(GetMaxCaptionSize); CalculateItemsViewInfo; end; procedure RemoveProcessedItemViewInfos; begin Move(AItemViewInfos.List^[AGroupedCount], AItemViewInfos.List^[0], (AItemViewInfos.Count - AGroupedCount) * SizeOf(Pointer)); AItemViewInfos.Count := AItemViewInfos.Count - AGroupedCount; end; begin AItemViewInfos := TList.Create; try ExtractItemViewInfos; while AItemViewInfos.Count <> 0 do begin SortItemViewInfos; if FindGroup then AlignControls; RemoveProcessedItemViewInfos; end; finally AItemViewInfos.Free; end; end; begin AAllItemViewInfos := TList.Create; try FindAllItemViewInfos(ItemsViewInfo); SortAllItemViewInfos; for ACaptionLayout := Low(ACaptionLayout) to High(ACaptionLayout) do ProcessItemViewInfos(ACaptionLayout); finally AAllItemViewInfos.Free; end; end; procedure TdxLayoutControlViewInfo.CalculateItemsViewInfo; begin ResetContentBounds; ItemsViewInfo.Calculate(ContentBounds); end; procedure TdxLayoutControlViewInfo.CalculateTabOrders; var AAvailTabOrder: Integer; begin AAvailTabOrder := 0; ItemsViewInfo.CalculateTabOrders(AAvailTabOrder); end; function TdxLayoutControlViewInfo.GetIsTransparent: Boolean; begin Result := HasBackground; end; function TdxLayoutControlViewInfo.HasBackground: Boolean; begin Result := Control.HasBackground; end; procedure TdxLayoutControlViewInfo.PrepareData; begin RecreateViewInfos; end; procedure TdxLayoutControlViewInfo.ResetContentBounds; begin SetRectEmpty(FContentBounds); end; function TdxLayoutControlViewInfo.GetCanvas: TcxCanvas; begin if Control.HandleAllocated then begin if FCanvas <> nil then FreeAndNil(FCanvas); Result := Control.Canvas; end else begin if FCanvas = nil then FCanvas := TcxScreenCanvas.Create; Result := FCanvas; end; end; function TdxLayoutControlViewInfo.GetClientBounds: TRect; begin Result := FControl.ClientBounds; end; function TdxLayoutControlViewInfo.GetContentBounds: TRect; function CalculateContentWidth: Integer; var AMinWidth: Integer; begin if acsWidth in Control.AutoContentSizes then begin with ClientBounds do Result := Right - Left; AMinWidth := ItemsViewInfo.MinWidth; if Result < AMinWidth then Result := AMinWidth; end else Result := ItemsViewInfo.CalculateWidth; end; function CalculateContentHeight: Integer; var AMinHeight: Integer; begin if acsHeight in Control.AutoContentSizes then begin with ClientBounds do Result := Bottom - Top; AMinHeight := ItemsViewInfo.MinHeight; if Result < AMinHeight then Result := AMinHeight; end else Result := ItemsViewInfo.CalculateHeight; end; begin if IsRectEmpty(FContentBounds) then with FContentBounds do begin Left := -Control.LeftPos; Top := -Control.TopPos; Right := Left + CalculateContentWidth; Bottom := Top + CalculateContentHeight; end; Result := FContentBounds; end; procedure TdxLayoutControlViewInfo.Calculate; begin PrepareData; CalculateItemsViewInfo; AlignItems; if Control.AutoControlAlignment then begin AutoAlignControls; AlignItems; end; Control.CheckPositions; Control.UpdateScrollBars; DoCalculateTabOrders; if Control.HandleAllocated then Control.IsPlaceControlsNeeded := True; end; procedure TdxLayoutControlViewInfo.DoCalculateTabOrders; begin if Control.AutoControlTabOrders then CalculateTabOrders; end; function TdxLayoutControlViewInfo.GetHitTest(const P: TPoint): TdxCustomLayoutHitTest; var ADesigner: TCustomForm; begin if Control.IsDesigning then ADesigner := dxLayoutDesigner.GetDesigner(Control) else ADesigner := nil; if Control.Customization and PtInRect(Control.CustomizeForm.BoundsRect, Control.ClientToScreen(P)) or (ADesigner <> nil) and PtInRect(ADesigner.BoundsRect, Control.ClientToScreen(P)) then Result := TdxLayoutCustomizeFormHitTest.Instance else if PtInRect(ClientBounds, P) then begin Result := ItemsViewInfo.GetHitTest(P); if Result = nil then Result := TdxLayoutClientAreaHitTest.Instance; end else Result := nil; if Result = nil then Result := TdxLayoutNoneHitTest.Instance; end; function TdxLayoutControlViewInfo.GetHitTest(X, Y: Integer): TdxCustomLayoutHitTest; begin Result := GetHitTest(Point(X, Y)); end; { TdxLayoutCustomizeListBox } function TdxLayoutCustomizeListBox.GetDragAndDropItemObject: TdxCustomLayoutItem; begin Result := TdxCustomLayoutItem(inherited DragAndDropItemObject); end; procedure TdxLayoutCustomizeListBox.BeginDragAndDrop; begin inherited; with Control do if CanDragAndDrop then begin (DragAndDropObject as TdxLayoutControlDragAndDropObject).Init(dsCustomizeForm, Self.DragAndDropItemObject); BeginDragAndDrop; end; end; initialization Screen.Cursors[crdxLayoutControlDrag] := LoadCursor(HInstance, 'DXLAYOUTCONTROLDRAGCURSOR'); RegisterClasses([TdxLayoutItem, TdxLayoutGroup, TdxLayoutAlignmentConstraint]); HitTests := THitTests.Create; finalization FreeAndNil(HitTests); end.