{********************************************************************} { } { Developer Express Visual Component Library } { ExpressLayoutControl customize form } { } { 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 dxLayoutCustomizeForm; {$I cxVer.inc} interface uses Windows, Messages, SysUtils, Classes, Graphics, Contnrs, Controls, Forms, Dialogs, ComCtrls, ActnList, Menus, ToolWin, StdCtrls, ImgList, cxClasses, dxLayoutLookAndFeels, cxControls, cxGraphics, dxLayoutControl, dxLayoutDragAndDrop, cxLookAndFeelPainters, cxButtons, cxContainer, cxEdit, cxGroupBox, cxLookAndFeels, cxTreeView, cxCheckBox, dxLayoutcxEditAdapters; type TdxLayoutControlCustomizeForm = class(TdxLayoutControlCustomCustomizeForm) alMain: TActionList; acAddGroup: TAction; acAddItem: TAction; acClose: TAction; acTreeViewExpandAll: TAction; acTreeViewCollapseAll: TAction; acTreeViewItemsDelete: TAction; acAlignLeftSide: TAction; acAlignRightSide: TAction; acAlignTopSide: TAction; acAlignBottomSide: TAction; acAlignNone: TAction; ilActions: TcxImageList; ilItems: TcxImageList; pmTreeViewActions: TPopupMenu; miExpandAll: TMenuItem; miCallapseAll: TMenuItem; miSeparator1: TMenuItem; miTreeViewDelete: TMenuItem; miSeparator2: TMenuItem; miAlignBy: TMenuItem; pmAvailableItemsActions: TPopupMenu; AddGroup1: TMenuItem; AddItem1: TMenuItem; Delete1: TMenuItem; pmAlign: TPopupMenu; Left1: TMenuItem; Right1: TMenuItem; op1: TMenuItem; Bottom1: TMenuItem; miSeparator3: TMenuItem; miSeparator4: TMenuItem; None1: TMenuItem; lcMainGroup_Root: TdxLayoutGroup; lcMain: TdxLayoutControl; lcgTreeView: TdxLayoutGroup; lcgAvailableItems: TdxLayoutGroup; acAvailableItemsDelete: TAction; acAvailableItemsExpandAll: TAction; acAvailableItemsCollapseAll: TAction; acAvailableItemsViewAsList: TAction; acTabbedView: TAction; acHighlightRoot: TAction; lcMainGroup1: TdxLayoutGroup; acShowDesignSelectors: TAction; acStore: TAction; acRestore: TAction; ilHelper: TcxImageList; acTreeViewItemRename: TAction; Rename1: TMenuItem; Rename2: TMenuItem; acAvailableItemRename: TAction; acUndo: TAction; acRedo: TAction; N1: TMenuItem; Undo1: TMenuItem; Redo1: TMenuItem; N2: TMenuItem; Undo2: TMenuItem; Redo2: TMenuItem; acAlignBy: TAction; tvItems: TcxTreeView; lcMainItem6: TdxLayoutItem; tvAvailableItems: TcxTreeView; lcMainItem8: TdxLayoutItem; btnClose: TcxButton; lcMainItem1: TdxLayoutItem; lcMainGroup3: TdxLayoutGroup; cbTabbedView: TcxCheckBox; lcMainItem4: TdxLayoutItem; liShowDesignSelectors: TdxLayoutItem; btnShowDesignSelectors: TcxButton; liHighlightRoot: TdxLayoutItem; btnHighlightRoot: TcxButton; liRestore: TdxLayoutItem; btnRestore: TcxButton; liStore: TdxLayoutItem; btnStore: TcxButton; liRedo: TdxLayoutItem; btnRedo: TcxButton; liUndo: TdxLayoutItem; btnUndo: TcxButton; lcMainGroup2: TdxLayoutGroup; lgSeparator1: TdxLayoutGroup; lcMainItem2: TdxLayoutItem; btnAlignBy: TcxButton; lcMainItem7: TdxLayoutItem; btnTreeViewItemsDelete: TcxButton; lcMainItem9: TdxLayoutItem; btnTreeViewCollapseAll: TcxButton; lcMainItem10: TdxLayoutItem; btnTreeViewExpandAll: TcxButton; lgTreeView: TdxLayoutGroup; lgSeparator2: TdxLayoutGroup; lgSeparator3: TdxLayoutGroup; lgAvailableItems: TdxLayoutGroup; lcMainItem3: TdxLayoutItem; btnAvailableItemsViewAsList: TcxButton; lcMainItem11: TdxLayoutItem; btnAvailableItemsDelete: TcxButton; liAddItem: TdxLayoutItem; btnAddItem: TcxButton; lcMainItem13: TdxLayoutItem; btnAddGroup: TcxButton; lcMainItem14: TdxLayoutItem; btnAvailableItemsCollapseAll: TcxButton; lcMainItem15: TdxLayoutItem; btnAvailableItemsExpandAll: TcxButton; lgSeparator4: TdxLayoutGroup; lgSeparator5: TdxLayoutGroup; procedure acCloseExecute(Sender: TObject); procedure acAddGroupExecute(Sender: TObject); procedure acAddItemExecute(Sender: TObject); procedure tvItemsEdited(Sender: TObject; Node: TTreeNode; var S: String); procedure tvItemsMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure ItemsMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); procedure ItemsMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); procedure tvItemsChange(Sender: TObject; Node: TTreeNode); procedure tvItemsChanging(Sender: TObject; Node: TTreeNode; var AllowChange: Boolean); procedure AlignExecute(Sender: TObject); procedure acTreeViewItemsDeleteExecute(Sender: TObject); procedure FormClose(Sender: TObject; var Action: TCloseAction); procedure tvItemsContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean); procedure acAvailableItemsDeleteExecute(Sender: TObject); procedure tvItemsCustomDrawItem(Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean); procedure tvAvailableItemsContextPopup(Sender: TObject; MousePos: TPoint; var Handled: Boolean); procedure acAvailableItemsExpandAllExecute(Sender: TObject); procedure acAvailableItemsCollapseAllExecute(Sender: TObject); procedure acTreeViewExpandAllExecute(Sender: TObject); procedure acTreeViewCollapseAllExecute(Sender: TObject); procedure acAvailableItemsViewAsListExecute(Sender: TObject); procedure tvItemsEditing(Sender: TObject; Node: TTreeNode; var AllowEdit: Boolean); procedure FormShortCut(var Msg: TWMKey; var Handled: Boolean); procedure FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); procedure acTabbedViewExecute(Sender: TObject); procedure acHighlightRootExecute(Sender: TObject); procedure acShowDesignSelectorsExecute(Sender: TObject); procedure acStoreExecute(Sender: TObject); procedure acRestoreExecute(Sender: TObject); procedure acTreeViewItemRenameExecute(Sender: TObject); procedure acAvailableItemRenameExecute(Sender: TObject); procedure acUndoExecute(Sender: TObject); procedure acRedoExecute(Sender: TObject); procedure ToolBarsCustomDraw(Sender: TToolBar; const ARect: TRect; var DefaultDraw: Boolean); procedure acAlignByExecute(Sender: TObject); private FDragHelper: TdxLayoutDragAndDropHelper; FLockCount: Integer; FAvailableItemsWndProc: TWndMethod; FItemsWndProc: TWndMethod; procedure AddItemNode(ANodes: TTreeNodes; ANode: TTreeNode; AItem: TdxCustomLayoutItem; const ACustomName: string = ''); procedure AvailableItemsWndProc(var Message: TMessage); procedure DoAfterInsertionItem(AItem: TdxCustomLayoutItem); function GetImageIndex(AItem: TdxCustomLayoutItem): Integer; function GetIsLocked: Boolean; function GetNextToSelectItem(ATreeView: TcxTreeView): TdxCustomLayoutItem; procedure InitializePopupMenu; procedure ItemsWndProc(var Message: TMessage); procedure RefreshImages; procedure RefreshLists(ARefreshSelection: Boolean = False); procedure RefreshButtonStates; procedure RefreshView; procedure SelectItem(AItem: TdxCustomLayoutItem); procedure SetItemsSelections(AList: TList); procedure SetLayoutItemsSelections(ATreeView: TTreeView); function TreeViewWndProcHandler(ATreeView: TTreeView; var Message: TMessage): Boolean; protected procedure CreateWindowHandle(const Params: TCreateParams); override; procedure DestroyWindowHandle; override; procedure Loaded; override; procedure CalculateDeleteItemsActionStates; function CanDeleteItems(ATreeView: TcxTreeView): Boolean; procedure DeleteItems(AList: TComponentList; ASelectedItem: TdxCustomLayoutItem); procedure InitializeControl; override; procedure Localize; virtual; function NeedRefreshItemsAfterDeleting(AComponent: TPersistent): Boolean; procedure RefreshAvailableItems; procedure RefreshEnableds; procedure RefreshTreeView; procedure StoreTreeViewWndProc(ATreeView: TTreeView; var AStoredWndMethod: TWndMethod; ANewWndMethod: TWndMethod); procedure RestoreTreeViewWndProc(ATreeView: TTreeView; var AStoredWndMethod: TWndMethod); property DragHelper: TdxLayoutDragAndDropHelper read FDragHelper; property IsLocked: Boolean read GetIsLocked; property LockCount: Integer read FLockCount; public constructor Create(AOwner: TComponent); override; destructor Destroy; override; function GetHitTest(const P: TPoint): TdxCustomLayoutHitTest; override; // Updates procedure BeginUpdate; procedure CancelUpdate; procedure EndUpdate; procedure UpdateCaption; override; procedure UpdateContent; override; procedure UpdateSelection; override; procedure UpdateView; override; end; procedure cxTreeViewGetSelection(ATreeView: TTreeView; AList: TList); procedure cxTreeViewSyncSelection(ATreeView: TTreeView; AList: TList); implementation {$R *.DFM} uses Types, Math, CommCtrl, dxLayoutCommon, dxLayoutEditForm, cxGeometry, dxLayoutStrs, dxCore, dxOffice11, dxLayoutSelection; type TdxLayoutControlAccess = class(TdxCustomLayoutControl); TdxCustomLayoutItemAccess = class(TdxCustomLayoutItem); TdxCustomLayoutItemViewInfoAccess = class(TdxCustomLayoutItemViewInfo); TToolBarAccess = class(TToolBar); function CompareItemsByClass(Item1, Item2: Pointer): Integer; var AItem1, AItem2: TdxCustomLayoutItem; begin AItem1 := TdxCustomLayoutItem(Item1); AItem2 := TdxCustomLayoutItem(Item2); Result := Integer(AItem1.ClassType) - Integer(AItem2.ClassType); end; function CompareItemsByName(Item1, Item2: Pointer): Integer; procedure SplitNameByTrailingDigits(const AName: string; out ATrailingDigits: Integer; out ANameWithoutTrailingDigitals: string); var ACurrentLength: Integer; begin ANameWithoutTrailingDigitals := AName; ACurrentLength := Length(ANameWithoutTrailingDigitals); while (ACurrentLength > 0) and dxCharIsNumeric(ANameWithoutTrailingDigitals[ACurrentLength]) do begin ATrailingDigits := ATrailingDigits * 10 + StrToInt(ANameWithoutTrailingDigitals[ACurrentLength]); ANameWithoutTrailingDigitals := Copy(ANameWithoutTrailingDigitals, 1, ACurrentLength - 1); ACurrentLength := Length(ANameWithoutTrailingDigitals); end; if ACurrentLength = Length(AName) then ATrailingDigits := -1 else ATrailingDigits := StrToInt(Copy(AName, ACurrentLength + 1, Length(AName) - ACurrentLength)); end; var AName1, AName2: string; ANameWithoutLastDigitals1, ANameWithoutLastDigitals2: string; ANumber1, ANumber2: Integer; begin Result := CompareItemsByClass(Item1, Item2); if Result = 0 then begin AName1 := TdxCustomLayoutItem(Item1).CaptionForCustomizeForm; SplitNameByTrailingDigits(AName1, ANumber1, ANameWithoutLastDigitals1); AName2 := TdxCustomLayoutItem(Item2).CaptionForCustomizeForm; SplitNameByTrailingDigits(AName2, ANumber2, ANameWithoutLastDigitals2); Result := CompareText(ANameWithoutLastDigitals1, ANameWithoutLastDigitals2); if Result = 0 then Result := ANumber1 - ANumber2; end; end; function CompareItems(Item1, Item2: Pointer): Integer; begin Result := CompareItemsByClass(Item1, Item2); if (Result = 0) and (TObject(Item1) is TdxLayoutGroup) then Result := Integer(TdxLayoutGroup(Item1).Count > 0) - Integer(TdxLayoutGroup(Item2).Count > 0); if Result = 0 then Result := CompareItemsByName(Item1, Item2); end; procedure cxTreeViewGetSelection(ATreeView: TTreeView; AList: TList); var I: Integer; begin for I := 0 to ATreeView.SelectionCount - 1 do AList.Add(ATreeView.Selections[I].Data); end; procedure cxTreeViewSyncSelection(ATreeView: TTreeView; AList: TList); procedure InternalSyncSelection(ANode: TTreeNode); var I: Integer; begin if ANode = nil then Exit; if ANode.Selected xor (ANode.Data <> nil) and (AList.IndexOf(ANode.Data) >= 0) then if ANode.Selected then ATreeView.Deselect(ANode) else ATreeView.Select(ANode, [ssCtrl]); ANode.Focused := ANode.Selected; for I := 0 to ANode.Count - 1 do InternalSyncSelection(ANode[I]); end; var I: Integer; begin with ATreeView do begin if AList.Count > 0 then for I := 0 to Items.Count - 1 do InternalSyncSelection(Items[I]) else ATreeView.ClearSelection(False); end; if ATreeView.SelectionCount = 0 then ATreeView.Selected := nil; end; { TdxLayoutDesignForm } constructor TdxLayoutControlCustomizeForm.Create(AOwner: TComponent); begin inherited Create(AOwner); Localize; InitializePopupMenu; RefreshImages; tvItems.InnerTreeView.PopupMenu := pmTreeViewActions; tvAvailableItems.InnerTreeView.PopupMenu := pmAvailableItemsActions; end; destructor TdxLayoutControlCustomizeForm.Destroy; begin FreeAndNil(FDragHelper); inherited; end; function TdxLayoutControlCustomizeForm.GetHitTest(const P: TPoint): TdxCustomLayoutHitTest; const dxAreaPart: array [Boolean] of TdxLayoutAreaPart = (apAfterContent, apCenter); function GetHitNode(ATreeView: TcxTreeView): TTreeNode; begin with cxPointOffset(P, ATreeView.BoundsRect.TopLeft, False) do if htOnItem in ATreeView.GetHitTestInfoAt(X, Y) then Result := ATreeView.GetNodeAt(X, Y) else Result := nil; end; var AItem: TdxCustomLayoutItem; ANode: TTreeNode; begin ANode := nil; if tvItems.Visible and PtInRect(tvItems.BoundsRect, P) then begin Result := TdxLayoutCustomizeFormTreeViewItemsHitTest.Instance; ANode := GetHitNode(tvItems); end else if tvAvailableItems.Visible and PtInRect(tvAvailableItems.BoundsRect, P) then begin Result := TdxLayoutCustomizeFormAvailableItemsHitTest.Instance; ANode := GetHitNode(tvAvailableItems); end else Result := inherited GetHitTest(P); if ANode <> nil then begin AItem := TdxCustomLayoutItem(ANode.Data); TdxLayoutCustomizeFormHitTest(Result).HitItem := AItem; end else TdxLayoutCustomizeFormHitTest(Result).HitItem := nil; end; procedure TdxLayoutControlCustomizeForm.BeginUpdate; begin Inc(FLockCount); end; procedure TdxLayoutControlCustomizeForm.CancelUpdate; begin Dec(FLockCount); end; procedure TdxLayoutControlCustomizeForm.EndUpdate; begin Dec(FLockCount); if LockCount = 0 then RefreshLists(True); end; procedure TdxLayoutControlCustomizeForm.UpdateCaption; begin if Control.IsDesigning then Caption := Format(cxGetResourceString(@sdxLayoutControlDesignerCaptionFormat), [cxGetFullComponentName(Control)]) else Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormCaption); end; procedure TdxLayoutControlCustomizeForm.UpdateContent; begin RefreshLists; RefreshButtonStates; if (FDragHelper.DragItem <> nil) and (Control.DragAndDropState = ddsNone) then FDragHelper.Reset; end; procedure TdxLayoutControlCustomizeForm.UpdateSelection; var AList: TList; AIntf: IdxLayoutDesignerHelper; begin if IsLocked then Exit; AList := TList.Create; try if Supports(Control, IdxLayoutDesignerHelper, AIntf) then begin AIntf.GetSelection(AList); AIntf := nil; end; SetItemsSelections(AList); finally AList.Free; end; end; procedure TdxLayoutControlCustomizeForm.UpdateView; begin RefreshView; end; procedure TdxLayoutControlCustomizeForm.CreateWindowHandle(const Params: TCreateParams); begin inherited CreateWindowHandle(Params); StoreTreeViewWndProc(tvItems.InnerTreeView, FItemsWndProc, ItemsWndProc); StoreTreeViewWndProc(tvAvailableItems.InnerTreeView, FAvailableItemsWndProc, AvailableItemsWndProc); end; procedure TdxLayoutControlCustomizeForm.DestroyWindowHandle; begin inherited DestroyWindowHandle; RestoreTreeViewWndProc(tvItems.InnerTreeView, FItemsWndProc); RestoreTreeViewWndProc(tvAvailableItems.InnerTreeView, FAvailableItemsWndProc); end; procedure TdxLayoutControlCustomizeForm.Loaded; begin inherited Loaded; Constraints.MinHeight := Height div 2; Constraints.MinWidth := Width; end; procedure TdxLayoutControlCustomizeForm.CalculateDeleteItemsActionStates; begin acTreeViewItemsDelete.Enabled := CanDeleteItems(tvItems); acAvailableItemsDelete.Enabled := CanDeleteItems(tvAvailableItems); end; function TdxLayoutControlCustomizeForm.CanDeleteItems(ATreeView: TcxTreeView): Boolean; var AList: TList; I: Integer; AIntf: IdxLayoutDesignerHelper; begin Result := not ATreeView.IsEditing; if Result then begin AList := TList.Create; try cxTreeViewGetSelection(ATreeView.InnerTreeView, AList); Result := AList.Count > 0; if Result then for I := 0 to AList.Count - 1 do begin if Supports(Control, IdxLayoutDesignerHelper, AIntf) then begin Result := AIntf.CanDeleteComponent(TComponent(AList[I])); AIntf := nil; end; if not Result then Break; end; finally AList.Free; end; end; end; procedure TdxLayoutControlCustomizeForm.DeleteItems(AList: TComponentList; ASelectedItem: TdxCustomLayoutItem); begin if AList.Count = 0 then Exit; TdxLayoutControlAccess(Control).SaveToUndo; BeginUpdate; try SelectItem(ASelectedItem); Control.BeginUpdate; try while AList.Count > 0 do AList[0].Free; finally Control.EndUpdate; end; finally CancelUpdate; end; RefreshLists(True); end; procedure TdxLayoutControlCustomizeForm.InitializeControl; begin inherited; FDragHelper.Free; FDragHelper := TdxLayoutDragAndDropHelper.Create(Control); end; procedure TdxLayoutControlCustomizeForm.Localize; begin acAddGroup.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormAddGroup); acAddGroup.Hint := StripHotKey(acAddGroup.Caption); acAddItem.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormAddItem); acAddItem.Hint := StripHotKey(acAddItem.Caption); acAvailableItemsDelete.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormDelete); acAvailableItemsDelete.Hint := cxGetResourceString(@sdxLayoutControlCustomizeFormDeleteHint); acTreeViewItemsDelete.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormDelete); acTreeViewItemsDelete.Hint := cxGetResourceString(@sdxLayoutControlCustomizeFormDeleteHint); acAlignBy.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormAlignBy); acAlignBy.Hint := StripHotKey(acAlignBy.Caption); acClose.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormClose); acClose.Hint := StripHotKey(acClose.Caption); acTreeViewExpandAll.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormExpandAll); acTreeViewExpandAll.Hint := StripHotKey(acTreeViewExpandAll.Caption); acAvailableItemsExpandAll.Caption := acTreeViewExpandAll.Caption; acAvailableItemsExpandAll.Hint := acTreeViewExpandAll.Hint; acTreeViewCollapseAll.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormCollapseAll); acTreeViewCollapseAll.Hint := StripHotKey(acTreeViewCollapseAll.Caption); acAvailableItemsCollapseAll.Caption := acTreeViewCollapseAll.Caption; acAvailableItemsCollapseAll.Hint := StripHotKey(acTreeViewCollapseAll.Hint); acAlignLeftSide.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormAlignLeftSide); acAlignRightSide.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormAlignRightSide); acAlignTopSide.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormAlignTopSide); acAlignBottomSide.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormAlignBottomSide); acAlignNone.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormAlignNone); lcgTreeView.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormTreeViewGroup); lcgAvailableItems.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormListViewGroup); acTabbedView.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormTabbedView); acTabbedView.Hint := StripHotKey(acTabbedView.Caption); acAvailableItemsViewAsList.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormTreeView); acAvailableItemsViewAsList.Hint := StripHotKey(acAvailableItemsViewAsList.Caption); acStore.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormStore); acStore.Hint := StripHotKey(acStore.Caption); acRestore.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormRestore); acRestore.Hint := StripHotKey(acRestore.Caption); acTreeViewItemRename.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormRename); acTreeViewItemRename.Hint := acTreeViewItemRename.Caption; acAvailableItemRename.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormRename); acAvailableItemRename.Hint := acAvailableItemRename.Caption; acUndo.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormUndo); acUndo.Hint := acUndo.Caption; acRedo.Caption := cxGetResourceString(@sdxLayoutControlCustomizeFormRedo); acRedo.Hint := acRedo.Caption; btnUndo.Caption := ''; btnRedo.Caption := ''; btnStore.Caption := ''; btnRestore.Caption := ''; btnHighlightRoot.Caption := ''; btnShowDesignSelectors.Caption := ''; btnTreeViewExpandAll.Caption := ''; btnTreeViewCollapseAll.Caption := ''; btnTreeViewItemsDelete.Caption := ''; btnAlignBy.Caption := ''; btnAvailableItemsExpandAll.Caption := ''; btnAvailableItemsCollapseAll.Caption := ''; btnAddGroup.Caption := ''; btnAddItem.Caption := ''; btnAvailableItemsDelete.Caption := ''; btnAvailableItemsViewAsList.Caption := ''; end; function TdxLayoutControlCustomizeForm.NeedRefreshItemsAfterDeleting(AComponent: TPersistent): Boolean; begin Result := (AComponent is TdxCustomLayoutItem) and (TdxCustomLayoutItem(AComponent).Container = Control); end; procedure TdxLayoutControlCustomizeForm.RefreshAvailableItems; procedure PopulateItemChildren(AList: TList; AItem: TdxCustomLayoutItem); var I: Integer; begin if AItem is TdxLayoutGroup then begin for I := 0 to TdxLayoutGroup(AItem).Count - 1 do begin AList.Add(TdxLayoutGroup(AItem).Items[I]); PopulateItemChildren(AList, TdxLayoutGroup(AItem).Items[I]); end; end; end; procedure PopulateItems(AList: TList); var I: Integer; begin for I := 0 to Control.AvailableItemCount - 1 do begin AList.Add(Control.AvailableItems[I]); if Control.CustomizeAvailableItemsViewKind = oivkList then PopulateItemChildren(AList, Control.AvailableItems[I]); end; end; var AList: TList; I: Integer; begin with tvAvailableItems do begin Items.BeginUpdate; try Items.Clear; AList := TList.Create; try PopulateItems(AList); case Control.CustomizeAvailableItemsViewKind of oivkList: begin AList.Sort(CompareItemsByName); for I := 0 to AList.Count - 1 do with Items.AddObject(Items.GetFirstNode, TdxCustomLayoutItem(AList[I]).CaptionForCustomizeForm, AList[I]) do begin ImageIndex := GetImageIndex(AList[I]); SelectedIndex := ImageIndex; Selected := False; Focused := False; end; end; oivkTree: begin AList.Sort(CompareItems); for I := 0 to AList.Count - 1 do AddItemNode(Items, nil, TdxCustomLayoutItem(AList[I])); end; end; finally AList.Free; end; FullExpand; finally Items.EndUpdate; end; end; tvAvailableItems.ShowRoot := Control.CustomizeAvailableItemsViewKind = oivkTree; end; procedure TdxLayoutControlCustomizeForm.RefreshEnableds; begin if not IsLocked then begin acAlignBy.Enabled := (tvItems.SelectionCount > 1); acAvailableItemsExpandAll.Enabled := Control.CustomizeAvailableItemsViewKind = oivkTree; acAvailableItemsCollapseAll.Enabled := Control.CustomizeAvailableItemsViewKind = oivkTree; acRestore.Enabled := Control.CanRestore; CalculateDeleteItemsActionStates; acTreeViewItemRename.Enabled := (tvItems.Selected <> nil) and (tvItems.SelectionCount = 1) and not (TObject(tvItems.Selected.Data) as TdxCustomLayoutItem).IsRoot; acAvailableItemRename.Enabled := (tvAvailableItems.Selected <> nil) and (tvAvailableItems.SelectionCount = 1); acUndo.Enabled := Control.UndoRedoManager.CanUndo; acRedo.Enabled := Control.UndoRedoManager.CanRedo; acAddItem.Enabled := Control.IsDesigning; end; end; procedure TdxLayoutControlCustomizeForm.RefreshTreeView; begin with tvItems do begin Items.BeginUpdate; try Items.Clear; AddItemNode(Items, Items.GetFirstNode, Control.Items, cxGetResourceString(@sdxLayoutControlRoot)); FullExpand; finally Items.EndUpdate; end; end; end; procedure TdxLayoutControlCustomizeForm.StoreTreeViewWndProc(ATreeView: TTreeView; var AStoredWndMethod: TWndMethod; ANewWndMethod: TWndMethod); begin AStoredWndMethod := ATreeView.WindowProc; ATreeView.WindowProc := ANewWndMethod; end; procedure TdxLayoutControlCustomizeForm.RestoreTreeViewWndProc(ATreeView: TTreeView; var AStoredWndMethod: TWndMethod); begin if Assigned(AStoredWndMethod) then ATreeView.WindowProc := AStoredWndMethod; AStoredWndMethod := nil; end; procedure TdxLayoutControlCustomizeForm.AddItemNode(ANodes: TTreeNodes; ANode: TTreeNode; AItem: TdxCustomLayoutItem; const ACustomName: string = ''); var AName: string; I: Integer; AThisNode: TTreeNode; AGroup: TdxLayoutGroup; begin if ACustomName = '' then AName := AItem.CaptionForCustomizeForm else AName := ACustomName; if ANode = nil then AThisNode := ANodes.AddObject(ANodes.GetFirstNode, AName, AItem) else AThisNode := ANodes.AddChildObject(ANode, AName, AItem); if AItem is TdxLayoutGroup then begin AGroup := TdxLayoutGroup(AItem); for I := 0 to AGroup.Count - 1 do AddItemNode(ANodes, AThisNode, AGroup[I]); end; AThisNode.ImageIndex := GetImageIndex(AItem); AThisNode.SelectedIndex := AThisNode.ImageIndex; AThisNode.Selected := False; AThisNode.Focused := False; end; procedure TdxLayoutControlCustomizeForm.AvailableItemsWndProc(var Message: TMessage); begin if not TreeViewWndProcHandler(tvAvailableItems.InnerTreeView, Message) then begin FAvailableItemsWndProc(Message); case Message.Msg of WM_DESTROY: RestoreTreeViewWndProc(tvAvailableItems.InnerTreeView, FAvailableItemsWndProc); end; end; end; procedure TdxLayoutControlCustomizeForm.DoAfterInsertionItem(AItem: TdxCustomLayoutItem); var AIntf: IdxLayoutDesignerHelper; begin if Supports(Control, IdxLayoutDesignerHelper, AIntf) then begin AIntf.SelectComponent(AItem); AIntf := nil; end; end; function TdxLayoutControlCustomizeForm.GetImageIndex(AItem: TdxCustomLayoutItem): Integer; var AGroup: TdxLayoutGroup; begin if AItem is TdxLayoutGroup then begin AGroup := AItem as TdxLayoutGroup; Result := 1 + Integer(AGroup.LayoutDirection); if AGroup.Hidden and not AGroup.IsRoot then Inc(Result, 4); end else Result := 0; end; function TdxLayoutControlCustomizeForm.GetIsLocked: Boolean; begin Result := (LockCount > 0) or TdxLayoutControlAccess(Control).IsUpdateLocked; end; function TdxLayoutControlCustomizeForm.GetNextToSelectItem(ATreeView: TcxTreeView): TdxCustomLayoutItem; var ANode: TTreeNode; begin Result := nil; ANode := ATreeView.FindNextToSelect; if ANode <> nil then Result := TdxCustomLayoutItem(ANode.Data) else begin ANode := ATreeView.Selected; while (ANode <> nil) and ANode.Selected do ANode := ANode.GetPrev; if ANode <> nil then Result := TdxCustomLayoutItem(ANode.Data); end; end; procedure TdxLayoutControlCustomizeForm.InitializePopupMenu; var I: Integer; AMenuItem: TMenuItem; begin for I := 0 to pmAlign.Items.Count - 1 do begin AMenuItem := TMenuItem.Create(miAlignBy); AMenuItem.Caption := pmAlign.Items[I].Caption; AMenuItem.Action := pmAlign.Items[I].Action; miAlignBy.Add(AMenuItem); end; end; procedure TdxLayoutControlCustomizeForm.ItemsWndProc(var Message: TMessage); begin if not TreeViewWndProcHandler(tvItems.InnerTreeView, Message) then begin FItemsWndProc(Message); case Message.Msg of WM_DESTROY: RestoreTreeViewWndProc(tvItems.InnerTreeView, FItemsWndProc); end; end; end; procedure TdxLayoutControlCustomizeForm.RefreshImages; begin cxTransformImages(ilItems, ilHelper, clWindow, False); if not IsXPManifestEnabled then cxTransformImages(ilItems, clWindow); ilItems.AddImages(ilHelper); ilHelper.Clear; end; procedure TdxLayoutControlCustomizeForm.RefreshLists(ARefreshSelection: Boolean = False); begin if IsLocked then Exit; BeginUpdate; try RefreshAvailableItems; RefreshTreeView; finally CancelUpdate; end; if ARefreshSelection then UpdateSelection; end; procedure TdxLayoutControlCustomizeForm.RefreshButtonStates; begin acAvailableItemsViewAsList.Checked := Control.CustomizeAvailableItemsViewKind = oivkTree; acTabbedView.Checked := Control.CustomizeFormTabbedView; acHighlightRoot.Checked := Control.HighlightRoot; acShowDesignSelectors.Checked := Control.ShowDesignSelectors; RefreshEnableds; end; procedure TdxLayoutControlCustomizeForm.RefreshView; begin if Control.CustomizeFormTabbedView then lcMainGroup1.LayoutDirection := ldTabbed else lcMainGroup1.LayoutDirection := ldHorizontal; acShowDesignSelectors.Visible := Control.IsDesigning; liShowDesignSelectors.Visible := acShowDesignSelectors.Visible; acHighlightRoot.Visible := Control.IsDesigning; liHighlightRoot.Visible := acHighlightRoot.Visible; acStore.Visible := not Control.IsDesigning; liStore.Visible := acStore.Visible; acRestore.Visible := not Control.IsDesigning; liRestore.Visible := acRestore.Visible; acUndo.Visible := not Control.IsDesigning; liUndo.Visible := acUndo.Visible; acRedo.Visible := not Control.IsDesigning; liRedo.Visible := acRedo.Visible; lgSeparator1.Visible := acRedo.Visible; acAddItem.Visible := Control.IsDesigning; liAddItem.Visible := acAddItem.Visible; lcMain.LayoutLookAndFeel := TdxLayoutControlAccess(Control).GetLayoutLookAndFeel; end; procedure TdxLayoutControlCustomizeForm.SelectItem(AItem: TdxCustomLayoutItem); var AIntf: IdxLayoutDesignerHelper; begin if Supports(Control, IdxLayoutDesignerHelper, AIntf) then begin if AItem <> nil then AIntf.SelectComponent(AItem) else AIntf.SelectComponent(Control); AIntf := nil; end; RefreshEnableds; end; procedure TdxLayoutControlCustomizeForm.SetItemsSelections(AList: TList); procedure SetTreeViewAsActiveControl(ATreeView: TcxTreeView); begin if ATreeView.Visible then ActiveControl := ATreeView.InnerTreeView else ActiveControl := nil; end; var AItem: TdxCustomLayoutItemAccess; begin if IsLocked then Exit; BeginUpdate; try cxTreeViewSyncSelection(tvItems.InnerTreeView, AList); cxTreeViewSyncSelection(tvAvailableItems.InnerTreeView, AList); if (AList.Count > 0) and (TObject(AList.Last) is TdxCustomLayoutItem) then begin AItem := TdxCustomLayoutItemAccess(AList.Last); if AItem.IsAvailable then SetTreeViewAsActiveControl(tvAvailableItems) else SetTreeViewAsActiveControl(tvItems); end; finally CancelUpdate; end; RefreshEnableds; end; procedure TdxLayoutControlCustomizeForm.SetLayoutItemsSelections(ATreeView: TTreeView); var AList: TList; AIntf: IdxLayoutDesignerHelper; begin AList := TList.Create; try cxTreeViewGetSelection(ATreeView, AList); if Supports(Control, IdxLayoutDesignerHelper, AIntf) then begin AIntf.SetSelection(AList); AIntf := nil; end; finally AList.Free; end; end; function TdxLayoutControlCustomizeForm.TreeViewWndProcHandler(ATreeView: TTreeView; var Message: TMessage): Boolean; {$IFNDEF DELPHI12} procedure ShowContextMenu; var AHitTest: THitTests; begin AHitTest := ATreeView.GetHitTestInfoAt(Message.LParamLo, Message.LParamHi); if (htOnItem in AHitTest) then ATreeView.Perform(WM_CONTEXTMENU, ATreeView.Handle, Integer(PointToSmallPoint(GetMouseCursorPos))); end; {$ENDIF} var ANode: TTreeNode; AShift: TShiftState; begin Result := False; case Message.Msg of {$IFNDEF DELPHI12} CN_NOTIFY: case TWMNotify(Message).NMHdr^.code of NM_RCLICK: begin ShowContextMenu; Message.Result := 1; Result := True; end; end; {$ENDIF} WM_RBUTTONDOWN: begin ANode := ATreeView.GetNodeAt(Message.LParamLo, Message.LParamHi); if ANode <> nil then begin ANode.Focused := True; AShift := KeysToShiftState(Message.WParam); if not ANode.Selected then begin if [ssShift, ssCtrl] * AShift <> [] then AShift := []; BeginUpdate; try ATreeView.Select(ANode, AShift); finally CancelUpdate; end; SetLayoutItemsSelections(ATreeView); end; end; {$IFNDEF DELPHI12} Message.Result := 1; Result := True; {$ENDIF} end; WM_LBUTTONDOWN: begin ANode := ATreeView.GetNodeAt(Message.LParamLo, Message.LParamHi); if (ANode <> nil) and (ATreeView.SelectionCount > 1) then begin ANode.Focused := True; AShift := KeysToShiftState(Message.WParam); if ANode.Selected and ([ssCtrl, ssShift] * AShift = []) then begin BeginUpdate; try ATreeView.ClearSelection; finally CancelUpdate; end; end; end; end; end; end; procedure TdxLayoutControlCustomizeForm.acCloseExecute(Sender: TObject); begin Close; end; procedure TdxLayoutControlCustomizeForm.acAddGroupExecute(Sender: TObject); var AGroup: TdxLayoutGroup; begin TdxLayoutControlAccess(Control).SaveToUndo; Control.BeginUpdate; try AGroup := Control.CreateGroup; AGroup.Caption := cxGetResourceString(@sdxLayoutControlNewGroupCaption); finally Control.EndUpdate; end; DoAfterInsertionItem(AGroup); end; procedure TdxLayoutControlCustomizeForm.acAddItemExecute(Sender: TObject); var AItem: TdxCustomLayoutItem; begin Control.BeginUpdate; try AItem := Control.CreateItem; AItem.Caption := cxGetResourceString(@sdxLayoutControlNewItemCaption); finally Control.EndUpdate; end; DoAfterInsertionItem(AItem); end; procedure TdxLayoutControlCustomizeForm.tvItemsEdited(Sender: TObject; Node: TTreeNode; var S: String); begin if TdxCustomLayoutItem(Node.Data).IsRoot then Exit; TdxLayoutControlAccess(Control).SaveToUndo; BeginUpdate; try if Control.IsDesigning then TdxCustomLayoutItem(Node.Data).Name := S else TdxCustomLayoutItem(Node.Data).Caption := S; Node.Text := TdxCustomLayoutItem(Node.Data).CaptionForCustomizeForm; finally CancelUpdate; end; end; procedure TdxLayoutControlCustomizeForm.tvItemsMouseDown(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); var ANode: TTreeNode; ATreeView: TcxTreeView; AHitTests: THitTests; begin ATreeView := TcxTreeView(Sender); AHitTests := ATreeView.GetHitTestInfoAt(X, Y); if htOnItem in AHitTests then begin ANode := ATreeView.GetNodeAt(X, Y); if ANode = nil then Exit; ANode.Selected := True; if (Button = mbLeft) and ANode.Selected and (ANode = ATreeView.Selected) then DragHelper.InitializeDragItem(ATreeView.Selected.Data, X, Y); if (Button = mbRight) or (ssCtrl in Shift) then SetLayoutItemsSelections(ATreeView.InnerTreeView); end; end; procedure TdxLayoutControlCustomizeForm.ItemsMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer); var ASource: TdxLayoutDragSource; begin if Sender = tvItems then ASource := dsCustomizeFormTreeViewItems else ASource := dsCustomizeFormAvailableItems; if ssLeft in Shift then DragHelper.TryBeginDragAndDrop(X, Y, ASource); end; procedure TdxLayoutControlCustomizeForm.ItemsMouseUp(Sender: TObject; Button: TMouseButton; Shift: TShiftState; X, Y: Integer); begin if Button = mbLeft then DragHelper.Reset; end; procedure TdxLayoutControlCustomizeForm.tvItemsChange(Sender: TObject; Node: TTreeNode); begin if not IsLocked then SetLayoutItemsSelections(Sender as TTreeView); end; procedure TdxLayoutControlCustomizeForm.tvItemsChanging(Sender: TObject; Node: TTreeNode; var AllowChange: Boolean); begin AllowChange := (Node = nil) or (Node.Data <> nil); end; procedure TdxLayoutControlCustomizeForm.AlignExecute(Sender: TObject); var AList: TList; I: Integer; ATag: Integer; AIntf: IdxLayoutDesignerHelper; begin //todo: TdxLayoutControlAccess(Control).SaveToUndo; ATag := (Sender as TAction).Tag; AList := TList.Create; try if Supports(Control, IdxLayoutDesignerHelper, AIntf) then begin AIntf.GetSelection(AList); AIntf := nil; end; BeginUpdate; try Control.BeginUpdate; try if ATag = -1 then for I := 0 to AList.Count - 1 do TdxCustomLayoutItem(AList[I]).AlignmentConstraint := nil else with Control.CreateAlignmentConstraint do begin Kind := TdxLayoutAlignmentConstraintKind(ATag); for I := 0 to AList.Count - 1 do AddItem(TdxCustomLayoutItem(AList[I])); end; finally Control.EndUpdate; end; finally CancelUpdate; end; finally AList.Free; end; end; procedure TdxLayoutControlCustomizeForm.acTreeViewItemsDeleteExecute(Sender: TObject); procedure CheckSelectedParent(ANode: TTreeNode); var AParentNode: TTreeNode; AItem: TdxCustomLayoutItem; ANotSelectedChildCount: Integer; I: Integer; begin AParentNode := ANode.Parent; if AParentNode = nil then Exit; AItem := TdxCustomLayoutItem(AParentNode.Data); if not AParentNode.Selected and not AItem.IsRoot and (AItem is TdxLayoutGroup) and TdxLayoutGroup(AItem).Hidden then begin ANotSelectedChildCount := AParentNode.Count; for I := 0 to AParentNode.Count - 1 do if AParentNode[I].Selected then Dec(ANotSelectedChildCount); if ANotSelectedChildCount < 2 then tvItems.Select(AParentNode, [ssCtrl]); end; end; procedure SelectChildren(ANode: TTreeNode); var I: Integer; begin if ANode.Count > 0 then for I := 0 to ANode.Count - 1 do begin tvItems.Select(ANode[I], [ssCtrl]); SelectChildren(ANode[I]); end end; procedure CheckNeighbors(ANode: TTreeNode); var I: Integer; AParentNode: TTreeNode; ANeighborsSelectedCount: Integer; begin if (ANode.Parent = nil) or (ANode.Parent.Count = 0) then Exit; AParentNode := ANode.Parent; ANeighborsSelectedCount := 0; for I := 0 to AParentNode.Count - 1 do if AParentNode[I].Selected then Inc(ANeighborsSelectedCount); if AParentNode.Count - ANeighborsSelectedCount = 1 then for I := 0 to AParentNode.Count - 1 do if not AParentNode[I].Selected and (TObject(AParentNode[I].Data) is TdxLayoutGroup) and TdxLayoutGroup(AParentNode[I].Data).Hidden then tvItems.Select(AParentNode[I], [ssCtrl]); end; procedure AdjustSelectionForDeletion; var I: Integer; AList: TList; ASaveSelectedNode: TTreeNode; begin BeginUpdate; try AList := TList.Create; try ASaveSelectedNode := tvItems.GetSelections(AList); for I := 0 to AList.Count - 1 do begin SelectChildren(AList[I]); CheckNeighbors(AList[I]); CheckSelectedParent(AList[I]); end; with ASaveSelectedNode do TreeView_SelectItem(Handle, ItemId); finally AList.Free; end; finally CancelUpdate; end; end; var AList: TComponentList; begin if tvItems.IsEditing then Exit; AList := TComponentList.Create; try cxTreeViewGetSelection(tvItems.InnerTreeView, AList); AdjustSelectionForDeletion; DeleteItems(AList, GetNextToSelectItem(tvItems)); finally AList.Free; end; end; procedure TdxLayoutControlCustomizeForm.FormClose(Sender: TObject; var Action: TCloseAction); begin cxDialogsMetricsStore.StoreMetrics(Self); Action := caFree; end; procedure TdxLayoutControlCustomizeForm.tvItemsContextPopup( Sender: TObject; MousePos: TPoint; var Handled: Boolean); begin CalculateDeleteItemsActionStates; acAvailableItemsDelete.Enabled := False; end; procedure TdxLayoutControlCustomizeForm.acAvailableItemsDeleteExecute( Sender: TObject); var AList: TComponentList; begin if tvAvailableItems.IsEditing then Exit; AList := TComponentList.Create; try cxTreeViewGetSelection(tvAvailableItems.InnerTreeView, AList); DeleteItems(AList, GetNextToSelectItem(tvAvailableItems)); finally AList.Free; end; end; procedure TdxLayoutControlCustomizeForm.tvItemsCustomDrawItem( Sender: TCustomTreeView; Node: TTreeNode; State: TCustomDrawState; var DefaultDraw: Boolean); begin if (TObject(Node.Data) is TdxLayoutGroup) and TdxLayoutGroup(Node.Data).Hidden and not TdxLayoutGroup(Node.Data).IsRoot then Sender.Canvas.Font.Style := [fsItalic]; end; procedure TdxLayoutControlCustomizeForm.tvAvailableItemsContextPopup( Sender: TObject; MousePos: TPoint; var Handled: Boolean); begin CalculateDeleteItemsActionStates; acTreeViewItemsDelete.Enabled := False; end; procedure TdxLayoutControlCustomizeForm.acAvailableItemsExpandAllExecute( Sender: TObject); begin tvAvailableItems.FullExpand; end; procedure TdxLayoutControlCustomizeForm.acAvailableItemsCollapseAllExecute( Sender: TObject); begin tvAvailableItems.FullCollapse; end; procedure TdxLayoutControlCustomizeForm.acTreeViewExpandAllExecute( Sender: TObject); begin tvItems.FullExpand; end; procedure TdxLayoutControlCustomizeForm.acTreeViewCollapseAllExecute( Sender: TObject); begin tvItems.FullCollapse; end; procedure TdxLayoutControlCustomizeForm.acAvailableItemsViewAsListExecute( Sender: TObject); begin if acAvailableItemsViewAsList.Checked then Control.CustomizeAvailableItemsViewKind := oivkTree else Control.CustomizeAvailableItemsViewKind := oivkList; end; procedure TdxLayoutControlCustomizeForm.tvItemsEditing(Sender: TObject; Node: TTreeNode; var AllowEdit: Boolean); function IsKeyDown(AShift: TShiftState): Boolean; begin Result := (AShift * KeyboardStateToShiftState) <> []; end; begin AllowEdit := not (TdxCustomLayoutItem(Node.Data).IsRoot or (DragHelper.DragItem <> nil) or IsKeyDown([ssCtrl, ssShift])); if not AllowEdit or Control.IsDesigning then Exit; Node.Text := TdxCustomLayoutItem(Node.Data).Caption; RefreshEnableds; end; procedure TdxLayoutControlCustomizeForm.FormShortCut(var Msg: TWMKey; var Handled: Boolean); begin case Msg.CharCode of VK_ESCAPE: begin Handled := tvItems.IsEditing or tvAvailableItems.IsEditing; if Handled then if tvItems.Selected <> nil then tvItems.Selected.EndEdit(True) else if tvAvailableItems.Selected <> nil then tvAvailableItems.Selected.EndEdit(True); end; end; end; procedure TdxLayoutControlCustomizeForm.FormKeyDown(Sender: TObject; var Key: Word; Shift: TShiftState); begin if Key = VK_DELETE then begin if tvItems.Focused and not tvItems.IsEditing then acTreeViewItemsDelete.Execute; if tvAvailableItems.Focused and not tvAvailableItems.IsEditing then acAvailableItemsDelete.Execute; end; end; procedure TdxLayoutControlCustomizeForm.acTabbedViewExecute( Sender: TObject); begin Control.CustomizeFormTabbedView := acTabbedView.Checked; end; procedure TdxLayoutControlCustomizeForm.acHighlightRootExecute( Sender: TObject); begin Control.HighlightRoot := acHighlightRoot.Checked; end; procedure TdxLayoutControlCustomizeForm.acShowDesignSelectorsExecute( Sender: TObject); begin Control.ShowDesignSelectors := acShowDesignSelectors.Checked; end; procedure TdxLayoutControlCustomizeForm.acStoreExecute(Sender: TObject); begin Control.Store; RefreshEnableds; end; procedure TdxLayoutControlCustomizeForm.acRestoreExecute(Sender: TObject); begin TdxLayoutControlAccess(Control).SaveToUndo; Control.Restore; end; procedure TdxLayoutControlCustomizeForm.acTreeViewItemRenameExecute( Sender: TObject); begin tvItems.Selected.EditText; end; procedure TdxLayoutControlCustomizeForm.acAvailableItemRenameExecute( Sender: TObject); begin tvAvailableItems.Selected.EditText; end; procedure TdxLayoutControlCustomizeForm.acUndoExecute(Sender: TObject); begin Control.UndoRedoManager.Undo; RefreshButtonStates; end; procedure TdxLayoutControlCustomizeForm.acRedoExecute(Sender: TObject); begin Control.UndoRedoManager.Redo; RefreshButtonStates; end; procedure TdxLayoutControlCustomizeForm.ToolBarsCustomDraw( Sender: TToolBar; const ARect: TRect; var DefaultDraw: Boolean); begin cxDrawTransparentControlBackground(Sender, Sender.Canvas, Sender.ClientRect, False); end; procedure TdxLayoutControlCustomizeForm.acAlignByExecute(Sender: TObject); begin // for popup end; end.