lazarus/designer/anchoreditor.pas
2007-10-14 05:08:52 +00:00

915 lines
30 KiB
ObjectPascal

{ /***************************************************************************
AnchorEditor.pas - Lazarus IDE unit
-----------------------------------
***************************************************************************/
***************************************************************************
* *
* This source is free software; you can redistribute it and/or modify *
* it under the terms of the GNU General Public License as published by *
* the Free Software Foundation; either version 2 of the License, or *
* (at your option) any later version. *
* *
* This code is distributed in the hope that it will be useful, but *
* WITHOUT ANY WARRANTY; without even the implied warranty of *
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU *
* General Public License for more details. *
* *
* A copy of the GNU General Public License is available on the World *
* Wide Web at <http://www.gnu.org/copyleft/gpl.html>. You can also *
* obtain it by writing to the Free Software Foundation, *
* Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. *
* *
***************************************************************************
Author: Mattias Gaertner
Abstract:
Editor for editing Anchors, AnchorSide properties.
}
unit AnchorEditor;
{$mode objfpc}{$H+}
interface
uses
Classes, SysUtils, LCLProc, LResources, Forms, Controls, Graphics, Dialogs,
StdCtrls, Buttons, Spin,
IDECommands, PropEdits,
LazarusIDEStrConsts, EnvironmentOpts, IDEOptionDefs;
type
{ TAnchorDesignerSideValues }
TAnchorDesignerSideValues = class
private
FAmbiguousBorderSpace: boolean;
FAmbiguousEnabled: boolean;
FAmbiguousSide: boolean;
FAmbiguousSibling: boolean;
FAnchorKind: TAnchorKind;
FBorderSpace: integer;
FEnabled: boolean;
FSibling: string;
FSide: TAnchorSideReference;
public
constructor Create(TheKind: TAnchorKind);
procedure SetValues(AControl: TControl);
procedure MergeValues(AControl: TControl);
public
property AnchorKind: TAnchorKind read FAnchorKind;
property Enabled: boolean read FEnabled write FEnabled;
property AmbiguousEnabled: boolean read FAmbiguousEnabled write FAmbiguousEnabled;
property Sibling: string read FSibling write FSibling;
property AmbiguousSibling: boolean read FAmbiguousSibling write FAmbiguousSibling;
property Side: TAnchorSideReference read FSide write FSide;
property AmbiguousSide: boolean read FAmbiguousSide write FAmbiguousSide;
property BorderSpace: integer read FBorderSpace write FBorderSpace;
property AmbiguousBorderSpace: boolean read FAmbiguousBorderSpace write FAmbiguousBorderSpace;
end;
{ TAnchorDesignerValues }
TAnchorDesignerValues = class
private
FAmbiguousBorderspaceAround: boolean;
FBorderspaceAround: integer;
FSides: array[TAnchorKind] of TAnchorDesignerSideValues;
function GetSides(Kind: TAnchorKind): TAnchorDesignerSideValues;
procedure SetAmbiguousBorderspaceAround(const AValue: boolean);
procedure SetBorderspaceAround(const AValue: integer);
public
constructor Create;
destructor Destroy; override;
procedure SetValues(AControl: TControl);
procedure MergeValues(AControl: TControl);
public
property Sides[Kind: TAnchorKind]: TAnchorDesignerSideValues read GetSides;
property BorderspaceAround: integer read FBorderspaceAround write SetBorderspaceAround;
property AmbiguousBorderspaceAround: boolean read FAmbiguousBorderspaceAround write SetAmbiguousBorderspaceAround;
end;
{ TAnchorDesigner }
TAnchorDesigner = class(TForm)
AroundBorderSpaceSpinEdit: TSpinEdit;
BorderSpaceGroupBox: TGroupBox;
BottomAnchoredCheckBox: TCheckBox;
BottomBorderSpaceSpinEdit: TSpinEdit;
BottomGroupBox: TGroupBox;
BottomRefBottomSpeedButton: TSpeedButton;
BottomRefCenterSpeedButton: TSpeedButton;
BottomRefTopSpeedButton: TSpeedButton;
BottomSiblingComboBox: TComboBox;
BottomSiblingLabel: TLabel;
LeftAnchoredCheckBox: TCheckBox;
LeftBorderSpaceSpinEdit: TSpinEdit;
LeftGroupBox: TGroupBox;
LeftRefCenterSpeedButton: TSpeedButton;
LeftRefLeftSpeedButton: TSpeedButton;
LeftRefRightSpeedButton: TSpeedButton;
LeftSiblingComboBox: TComboBox;
LeftSiblingLabel: TLabel;
RightAnchoredCheckBox: TCheckBox;
RightBorderSpaceSpinEdit: TSpinEdit;
RightGroupBox: TGroupBox;
RightRefCenterSpeedButton: TSpeedButton;
RightRefLeftSpeedButton: TSpeedButton;
RightRefRightSpeedButton: TSpeedButton;
RightSiblingComboBox: TComboBox;
RightSiblingLabel: TLabel;
TopAnchoredCheckBox: TCheckBox;
TopBorderSpaceSpinEdit: TSpinEdit;
TopGroupBox: TGroupBox;
TopRefBottomSpeedButton: TSpeedButton;
TopRefCenterSpeedButton: TSpeedButton;
TopRefTopSpeedButton: TSpeedButton;
TopSiblingComboBox: TComboBox;
TopSiblingLabel: TLabel;
procedure AnchorDesignerClose(Sender: TObject; var CloseAction: TCloseAction
);
procedure AnchorDesignerCreate(Sender: TObject);
procedure AnchorDesignerDestroy(Sender: TObject);
procedure AnchorDesignerShow(Sender: TObject);
procedure AnchorEnabledCheckBoxChange(Sender: TObject);
procedure BorderSpaceSpinEditChange(Sender: TObject);
procedure SiblingComboBoxChange(Sender: TObject);
procedure ReferenceSideButtonClicked(Sender: TObject);
private
FSelection: TPersistentSelectionList;
FSelectedControlsList: TList;
FUpdating: Boolean;
protected
procedure KeyUp(var Key: Word; Shift: TShiftState); override;
procedure FillComboBoxWithSiblings(AComboBox: TComboBox);
function AnchorDesignerNoSiblingText: string;
public
Values: TAnchorDesignerValues;
destructor Destroy; override;
procedure Refresh(Force: boolean);
procedure OnRefreshPropertyValues;
function GetSelectedControls: TList;
function FindSibling(const Sibling: string): TControl;
class function ControlToStr(AControl: TControl): string;
procedure CollectValues(const ASelection: TList;
var TheValues: TAnchorDesignerValues;
var SelectedControlCount: integer);
procedure OnSetSelection(const ASelection: TPersistentSelectionList);
property Selection: TPersistentSelectionList read FSelection;
end;
{ TAnchorPropertyEditor }
TAnchorPropertyEditor = class(TSetPropertyEditor)
public
function GetAttributes: TPropertyAttributes; override;
procedure Edit; override;
end;
var
AnchorDesigner: TAnchorDesigner = nil;
ShowAnchorDesigner: TNotifyEvent = nil;
implementation
{ TAnchorDesigner }
procedure TAnchorDesigner.AnchorDesignerCreate(Sender: TObject);
procedure LoadGlyph(ASpeedButton: TSpeedButton; AImageName: String);
var
ABitmap: TBitmap;
begin
ABitmap := LoadBitmapFromLazarusResource(AImageName);
ASpeedButton.Glyph := ABitmap;
ABitmap.Free;
end;
var
AnchorEnabledHint: String;
begin
Name:=NonModalIDEWindowNames[nmiwAnchorEditor];
EnvironmentOptions.IDEWindowLayoutList.Apply(Self,Name);
KeyPreview:=true;
FSelection:=TPersistentSelectionList.Create;
FSelectedControlsList := TList.Create;
AnchorEnabledHint:=lisAnchorEnabledHint;
AroundBorderSpaceSpinEdit.Hint:=lisAroundBorderSpaceHint;
BorderSpaceGroupBox.Caption:=lisBorderSpace;
BottomAnchoredCheckBox.Caption:=lisEnabled;
BottomAnchoredCheckBox.Hint:=Format(AnchorEnabledHint,['akBottom']);
BottomBorderSpaceSpinEdit.Hint:=lisBottomBorderSpaceSpinEditHint;
BottomGroupBox.Caption:=lisBottomGroupBoxCaption;
BottomRefBottomSpeedButton.Hint:=lisAnchorToBottomSideKeepBorderSpace;
BottomRefCenterSpeedButton.Hint:=lisCenterControlVerticallyRelativeToSibling;
BottomRefTopSpeedButton.Hint:=lisAnchorToTopSideKeepBorderSpace;
BottomSiblingComboBox.Hint:=lisBottomSiblingComboBoxHint;
BottomSiblingLabel.Caption:=lisSibling;
LeftAnchoredCheckBox.Caption:=lisEnabled;
LeftAnchoredCheckBox.Hint:=Format(AnchorEnabledHint,['akLeft']);
LeftBorderSpaceSpinEdit.Hint:=lisLeftBorderSpaceSpinEditHint;
LeftGroupBox.Caption:=lisLeftGroupBoxCaption;
LeftRefCenterSpeedButton.Hint:=lisCenterControlHorizontallyRelativeToSibling;
LeftRefLeftSpeedButton.Hint:=lisAnchorToLeftSideKeepBorderSpace;
LeftRefRightSpeedButton.Hint:=lisAnchorToRightSideKeepBorderSpace;
LeftSiblingComboBox.Hint:=lisLeftSiblingComboBoxHint;
LeftSiblingLabel.Caption:=lisSibling;
RightAnchoredCheckBox.Caption:=lisEnabled;
RightAnchoredCheckBox.Hint:=Format(AnchorEnabledHint,['akRight']);
RightBorderSpaceSpinEdit.Hint:=lisRightBorderSpaceSpinEditHint;
RightGroupBox.Caption:=lisRightAnchoring;
RightRefCenterSpeedButton.Hint:=lisCenterControlHorizontallyRelativeToSibling;
RightRefLeftSpeedButton.Hint:=lisAnchorToLeftSideKeepBorderSpace;
RightRefRightSpeedButton.Hint:=lisAnchorToRightSideKeepBorderSpace;
RightSiblingComboBox.Hint:=lisRightSiblingComboBoxHint;
RightSiblingLabel.Caption:=lisSibling;
TopAnchoredCheckBox.Caption:=lisEnabled;
TopAnchoredCheckBox.Hint:=Format(AnchorEnabledHint,['akTop']);
TopBorderSpaceSpinEdit.Hint:=lisTopBorderSpaceSpinEditHint;
TopGroupBox.Caption:=lisTopAnchoring;
TopRefBottomSpeedButton.Hint:=lisAnchorToBottomSideKeepBorderSpace;
TopRefCenterSpeedButton.Hint:=lisCenterControlVerticallyRelativeToSibling;
TopRefTopSpeedButton.Hint:= lisAnchorToTopSideKeepBorderSpace;
TopSiblingComboBox.Hint:=lisTopSiblingComboBoxHint;
TopSiblingLabel.Caption:=lisSibling;
LoadGlyph(LeftRefLeftSpeedButton, 'anchor_left');
LoadGlyph(LeftRefCenterSpeedButton, 'anchor_center_horizontal');
LoadGlyph(LeftRefRightSpeedButton, 'anchor_left_right');
LoadGlyph(RightRefLeftSpeedButton, 'anchor_left_right');
LoadGlyph(RightRefCenterSpeedButton, 'anchor_center_horizontal');
LoadGlyph(RightRefRightSpeedButton, 'anchor_right');
LoadGlyph(TopRefTopSpeedButton, 'anchor_top');
LoadGlyph(TopRefCenterSpeedButton, 'anchor_center_vertical');
LoadGlyph(TopRefBottomSpeedButton, 'anchor_top_bottom');
LoadGlyph(BottomRefTopSpeedButton, 'anchor_top_bottom');
LoadGlyph(BottomRefCenterSpeedButton, 'anchor_center_vertical');
LoadGlyph(BottomRefBottomSpeedButton, 'anchor_bottom');
// autosizing
BottomSiblingLabel.AnchorToNeighbour(akLeft,10,BottomAnchoredCheckBox);
BottomSiblingComboBox.AnchorToNeighbour(akLeft,5,BottomSiblingLabel);
BottomSiblingLabel.AnchorVerticalCenterTo(BottomSiblingComboBox);
BottomAnchoredCheckBox.AnchorVerticalCenterTo(BottomSiblingComboBox);
TopSiblingLabel.AnchorToNeighbour(akLeft,10,TopAnchoredCheckBox);
TopSiblingComboBox.AnchorToNeighbour(akLeft,5,TopSiblingLabel);
TopSiblingLabel.AnchorVerticalCenterTo(TopSiblingComboBox);
TopAnchoredCheckBox.AnchorVerticalCenterTo(TopSiblingComboBox);
GlobalDesignHook.AddHandlerRefreshPropertyValues(@OnRefreshPropertyValues);
GlobalDesignHook.AddHandlerSetSelection(@OnSetSelection);
end;
procedure TAnchorDesigner.AnchorDesignerDestroy(Sender: TObject);
begin
FreeAndNil(Values);
GlobalDesignHook.RemoveAllHandlersForObject(Self);
FreeAndNil(FSelection);
FreeAndNil(FSelectedControlsList);
end;
procedure TAnchorDesigner.AnchorDesignerShow(Sender: TObject);
begin
Refresh(true);
end;
procedure TAnchorDesigner.AnchorEnabledCheckBoxChange(Sender: TObject);
var
Kind: TAnchorKind;
CurSide: TAnchorDesignerSideValues;
NewValue: Boolean;
SelectedControls: TList;
i: Integer;
CurControl: TControl;
begin
//debugln('TAnchorDesigner.AnchorEnabledCheckBoxChange ',DbgSName(Sender),' ',dbgs(TCheckBox(Sender).Checked));
if FUpdating or (Values=nil) then exit;
if Sender=LeftAnchoredCheckBox then
Kind:=akLeft
else if Sender=RightAnchoredCheckBox then
Kind:=akRight
else if Sender=TopAnchoredCheckBox then
Kind:=akTop
else if Sender=BottomAnchoredCheckBox then
Kind:=akBottom
else
exit;
NewValue:=TCheckBox(Sender).Checked;
CurSide:=Values.Sides[Kind];
//debugln('TAnchorDesigner.AnchorEnabledCheckBoxChange CurSide.AmbiguousEnabled=',dbgs(CurSide.AmbiguousEnabled),' CurSide.Enabled=',dbgs(CurSide.Enabled),' NewValue=',dbgs(NewValue));
if CurSide.AmbiguousEnabled or (CurSide.Enabled<>NewValue) then begin
//debugln('TAnchorDesigner.AnchorEnabledCheckBoxChange ',DbgSName(Sender),' NewValue=',dbgs(NewValue));
// user changed an anchor
SelectedControls:=GetSelectedControls;
if SelectedControls=nil then exit;
for i:=0 to SelectedControls.Count-1 do begin
CurControl:=TControl(SelectedControls[i]);
if NewValue then
CurControl.Anchors:=CurControl.Anchors+[Kind]
else
CurControl.Anchors:=CurControl.Anchors-[Kind];
end;
GlobalDesignHook.Modified(Self);
GlobalDesignHook.RefreshPropertyValues;
end;
end;
procedure TAnchorDesigner.BorderSpaceSpinEditChange(Sender: TObject);
var
Around: Boolean;
NewValue: LongInt;
CurSide: TAnchorDesignerSideValues;
SelectedControls: TList;
i: Integer;
CurControl: TControl;
Kind: TAnchorKind;
begin
//debugln('TAnchorDesigner.BorderSpaceSpinEditChange ',DbgSName(Sender),' ',dbgs(TSpinEdit(Sender).Value));
if FUpdating or (Values=nil) then exit;
Around:=false;
if Sender=LeftBorderSpaceSpinEdit then
Kind:=akLeft
else if Sender=RightBorderSpaceSpinEdit then
Kind:=akRight
else if Sender=TopBorderSpaceSpinEdit then
Kind:=akTop
else if Sender=BottomBorderSpaceSpinEdit then
Kind:=akBottom
else if Sender=AroundBorderSpaceSpinEdit then begin
Kind:=akLeft;
Around:=true;
end else
exit;
NewValue:=RoundToInt(TSpinEdit(Sender).Value);
CurSide:=Values.Sides[Kind];
if (Around and (Values.AmbiguousBorderspaceAround
or (Values.BorderspaceAround<>NewValue)))
or ((not Around) and (CurSide.AmbiguousBorderSpace
or (CurSide.BorderSpace<>NewValue)))
then begin
//debugln('TAnchorDesigner.BorderSpaceSpinEditChange ',DbgSName(Sender),' NewValue=',dbgs(NewValue));
// user changed a BorderSpace
SelectedControls:=GetSelectedControls;
if SelectedControls=nil then exit;
for i:=0 to SelectedControls.Count-1 do begin
CurControl:=TControl(SelectedControls[i]);
if Around then
CurControl.BorderSpacing.Around:=NewValue
else
CurControl.BorderSpacing.Space[Kind]:=NewValue;
end;
GlobalDesignHook.Modified(Self);
GlobalDesignHook.RefreshPropertyValues;
end;
end;
procedure TAnchorDesigner.SiblingComboBoxChange(Sender: TObject);
var
Kind: TAnchorKind;
NewSibling: TControl;
CurSide: TAnchorDesignerSideValues;
SelectedControls: TList;
i: Integer;
CurControl: TControl;
NewValue: String;
begin
//debugln('TAnchorDesigner.SiblingComboBoxChange ',DbgSName(Sender),' ',TComboBox(Sender).Text);
if FUpdating or (Values=nil) then exit;
if Sender=LeftSiblingComboBox then
Kind:=akLeft
else if Sender=RightSiblingComboBox then
Kind:=akRight
else if Sender=TopSiblingComboBox then
Kind:=akTop
else if Sender=BottomSiblingComboBox then
Kind:=akBottom
else
exit;
NewValue:=TComboBox(Sender).Caption;
CurSide:=Values.Sides[Kind];
if CurSide.AmbiguousSibling or (CompareText(CurSide.Sibling,NewValue)<>0) then
begin
if (NewValue<>AnchorDesignerNoSiblingText) then begin
NewSibling:=FindSibling(NewValue);
if NewSibling=nil then exit;
end else begin
NewSibling:=nil;
end;
//debugln('TAnchorDesigner.SiblingComboBoxChange ',DbgSName(Sender),' NewSibling=',DbgSName(NewSibling));
// user changed a sibling
SelectedControls:=GetSelectedControls;
if SelectedControls=nil then exit;
for i:=0 to SelectedControls.Count-1 do begin
CurControl:=TControl(SelectedControls[i]);
try
CurControl.AnchorSide[Kind].Control:=NewSibling;
except
on E: Exception do begin
MessageDlg('Error', lisUnableToSetAnchorSideControl+#13 +E.Message,
mtError,[mbCancel],0);
end;
end;
end;
GlobalDesignHook.Modified(Self);
GlobalDesignHook.RefreshPropertyValues;
end;
end;
procedure TAnchorDesigner.ReferenceSideButtonClicked(Sender: TObject);
var
CurSide: TAnchorDesignerSideValues;
Kind: TAnchorKind;
Side: TAnchorSideReference;
SelectedControls: TList;
i: Integer;
CurControl: TControl;
begin
//debugln('TAnchorDesigner.ReferenceSideButtonClicked ',DbgSName(Sender),' ',dbgs(TSpeedButton(Sender).Down));
if FUpdating or (Values=nil) then exit;
if Sender=LeftRefCenterSpeedButton then begin
Kind:=akLeft;
Side:=asrCenter;
end
else if Sender=LeftRefLeftSpeedButton then begin
Kind:=akLeft;
Side:=asrLeft;
end
else if Sender=LeftRefRightSpeedButton then begin
Kind:=akLeft;
Side:=asrRight;
end
else if Sender=RightRefCenterSpeedButton then begin
Kind:=akRight;
Side:=asrCenter;
end
else if Sender=RightRefLeftSpeedButton then begin
Kind:=akRight;
Side:=asrLeft;
end
else if Sender=RightRefRightSpeedButton then begin
Kind:=akRight;
Side:=asrRight;
end
else if Sender=TopRefCenterSpeedButton then begin
Kind:=akTop;
Side:=asrCenter;
end
else if Sender=TopRefTopSpeedButton then begin
Kind:=akTop;
Side:=asrTop;
end
else if Sender=TopRefBottomSpeedButton then begin
Kind:=akTop;
Side:=asrBottom;
end
else if Sender=BottomRefCenterSpeedButton then begin
Kind:=akBottom;
Side:=asrCenter;
end
else if Sender=BottomRefTopSpeedButton then begin
Kind:=akBottom;
Side:=asrTop;
end
else if Sender=BottomRefBottomSpeedButton then begin
Kind:=akBottom;
Side:=asrBottom;
end else
exit;
CurSide:=Values.Sides[Kind];
if CurSide.AmbiguousSide or (CurSide.Side<>Side) then
begin
//debugln('TAnchorDesigner.ReferenceSideButtonClicked ',DbgSName(Sender));
// user changed a sibling
SelectedControls:=GetSelectedControls;
if SelectedControls=nil then exit;
for i:=0 to SelectedControls.Count-1 do begin
CurControl:=TControl(SelectedControls[i]);
CurControl.AnchorSide[Kind].Side:=Side;
end;
GlobalDesignHook.Modified(Self);
GlobalDesignHook.RefreshPropertyValues;
end;
end;
procedure TAnchorDesigner.KeyUp(var Key: Word; Shift: TShiftState);
begin
inherited KeyUp(Key, Shift);
ExecuteIDEShortCut(Self,Key,Shift,nil);
end;
procedure TAnchorDesigner.FillComboBoxWithSiblings(AComboBox: TComboBox);
var
sl: TStringList;
i: Integer;
CurControl: TControl;
j: Integer;
Sibling: TControl;
SelectedControls: TList;
OldText: String;
procedure AddSibling(AControl: TControl);
var
NewControlStr: String;
begin
if AControl.Name='' then exit;
NewControlStr:=ControlToStr(AControl);
if sl.IndexOf(NewControlStr)>=0 then exit;
//debugln('TAnchorDesigner.FillComboBoxWithSiblings.AddSibling ',NewControlStr);
sl.Add(NewControlStr);
end;
begin
sl:=TStringList.Create;
sl.Add(AnchorDesignerNoSiblingText);
SelectedControls:=GetSelectedControls;
if SelectedControls<>nil then begin
for i:=0 to SelectedControls.Count-1 do begin
if TObject(SelectedControls[i]) is TControl then begin
CurControl:=TControl(SelectedControls[i]);
if (CurControl.Parent<>nil) then begin
AddSibling(CurControl.Parent);
for j:=0 to CurControl.Parent.ControlCount-1 do begin
Sibling:=CurControl.Parent.Controls[j];
if (Sibling<>CurControl) then
AddSibling(Sibling);
end;
end;
break;
end;
end;
end;
sl.Sort;
//debugln('TAnchorDesigner.FillComboBoxWithSiblings ',sl.Text);
OldText:=AComboBox.Text;
AComboBox.Items.Assign(sl);
AComboBox.Text:=OldText;
sl.Free;
end;
function TAnchorDesigner.AnchorDesignerNoSiblingText: string;
begin
Result:='(nil)';
end;
destructor TAnchorDesigner.Destroy;
begin
inherited Destroy;
if AnchorDesigner=Self then AnchorDesigner:=nil;
end;
procedure TAnchorDesigner.Refresh(Force: boolean);
var
SelectedControlCount: Integer;
CurSide: TAnchorDesignerSideValues;
Sibling: String;
CurSelection: TList;
begin
//debugln('TAnchorDesigner.Refresh A ');
if not Force then begin
// check if uddate is needed
if not Visible then exit;
end;
if FUpdating then exit;
FUpdating:=true;
try
FreeAndNil(Values);
CurSelection:=GetSelectedControls;
CollectValues(CurSelection,Values,SelectedControlCount);
//debugln('TAnchorDesigner.Refresh B ',dbgs(SelectedControlCount));
if (Values=nil) then begin
Caption:=lisAnchorEditorNoControlSelected;
BorderSpaceGroupBox.Enabled:=false;
TopGroupBox.Enabled:=false;
LeftGroupBox.Enabled:=false;
RightGroupBox.Enabled:=false;
BottomGroupBox.Enabled:=false;
end else begin
Caption:=lisAnchorsOfSelectedControls;
// all
BorderSpaceGroupBox.Enabled:=true;
if Values.AmbiguousBorderspaceAround then
AroundBorderSpaceSpinEdit.Value:=-1
else
AroundBorderSpaceSpinEdit.Value:=Values.BorderspaceAround;
// Top
TopGroupBox.Enabled:=true;
CurSide:=Values.Sides[akTop];
TopAnchoredCheckBox.AllowGrayed:=CurSide.AmbiguousEnabled;
if CurSide.AmbiguousEnabled then
TopAnchoredCheckBox.State:=cbGrayed
else
TopAnchoredCheckBox.Checked:=CurSide.Enabled;
if CurSide.AmbiguousBorderSpace then
TopBorderSpaceSpinEdit.Value:=-1
else
TopBorderSpaceSpinEdit.Value:=CurSide.BorderSpace;
TopBorderSpaceSpinEdit.ValueEmpty:=CurSide.AmbiguousBorderSpace;
Sibling:=CurSide.Sibling;
TopSiblingComboBox.Text:=Sibling;
//debugln('TAnchorDesigner.Refresh A TopSiblingComboBox.Text=',TopSiblingComboBox.Text,' Sibling=',Sibling);
FillComboBoxWithSiblings(TopSiblingComboBox);
//debugln('TAnchorDesigner.Refresh B TopSiblingComboBox.Text=',TopSiblingComboBox.Text,' Sibling=',Sibling);
TopRefBottomSpeedButton.Down:=(CurSide.Side=asrBottom);
TopRefCenterSpeedButton.Down:=(CurSide.Side=asrCenter);
TopRefTopSpeedButton.Down:=(CurSide.Side=asrTop);
// Bottom
BottomGroupBox.Enabled:=true;
CurSide:=Values.Sides[akBottom];
BottomAnchoredCheckBox.AllowGrayed:=CurSide.AmbiguousEnabled;
if CurSide.AmbiguousEnabled then
BottomAnchoredCheckBox.State:=cbGrayed
else
BottomAnchoredCheckBox.Checked:=CurSide.Enabled;
if CurSide.AmbiguousBorderSpace then
BottomBorderSpaceSpinEdit.Value:=-1
else
BottomBorderSpaceSpinEdit.Value:=CurSide.BorderSpace;
BottomBorderSpaceSpinEdit.ValueEmpty:=CurSide.AmbiguousBorderSpace;
Sibling:=CurSide.Sibling;
BottomSiblingComboBox.Text:=Sibling;
FillComboBoxWithSiblings(BottomSiblingComboBox);
BottomRefBottomSpeedButton.Down:=(CurSide.Side=asrBottom);
BottomRefCenterSpeedButton.Down:=(CurSide.Side=asrCenter);
BottomRefTopSpeedButton.Down:=(CurSide.Side=asrTop);
// Left
LeftGroupBox.Enabled:=true;
CurSide:=Values.Sides[akLeft];
LeftAnchoredCheckBox.AllowGrayed:=CurSide.AmbiguousEnabled;
if CurSide.AmbiguousEnabled then
LeftAnchoredCheckBox.State:=cbGrayed
else
LeftAnchoredCheckBox.Checked:=CurSide.Enabled;
if CurSide.AmbiguousBorderSpace then
LeftBorderSpaceSpinEdit.Value:=-1
else
LeftBorderSpaceSpinEdit.Value:=CurSide.BorderSpace;
LeftBorderSpaceSpinEdit.ValueEmpty:=CurSide.AmbiguousBorderSpace;
Sibling:=CurSide.Sibling;
LeftSiblingComboBox.Text:=Sibling;
FillComboBoxWithSiblings(LeftSiblingComboBox);
LeftRefRightSpeedButton.Down:=(CurSide.Side=asrBottom);
LeftRefCenterSpeedButton.Down:=(CurSide.Side=asrCenter);
LeftRefLeftSpeedButton.Down:=(CurSide.Side=asrTop);
// Right
RightGroupBox.Enabled:=true;
CurSide:=Values.Sides[akRight];
RightAnchoredCheckBox.AllowGrayed:=CurSide.AmbiguousEnabled;
if CurSide.AmbiguousEnabled then
RightAnchoredCheckBox.State:=cbGrayed
else
RightAnchoredCheckBox.Checked:=CurSide.Enabled;
if CurSide.AmbiguousBorderSpace then
RightBorderSpaceSpinEdit.Value:=-1
else
RightBorderSpaceSpinEdit.Value:=CurSide.BorderSpace;
RightBorderSpaceSpinEdit.ValueEmpty:=CurSide.AmbiguousBorderSpace;
Sibling:=CurSide.Sibling;
RightSiblingComboBox.Text:=Sibling;
FillComboBoxWithSiblings(RightSiblingComboBox);
RightRefRightSpeedButton.Down:=(CurSide.Side=asrBottom);
RightRefCenterSpeedButton.Down:=(CurSide.Side=asrCenter);
RightRefLeftSpeedButton.Down:=(CurSide.Side=asrTop);
end;
finally
FUpdating:=false;
end;
end;
procedure TAnchorDesigner.OnRefreshPropertyValues;
begin
Refresh(false);
end;
function TAnchorDesigner.GetSelectedControls: TList;
var
CurPersistent: TPersistent;
AControl: TControl;
i: Integer;
begin
Result:=nil;
GlobalDesignHook.GetSelection(FSelection);
if FSelection=nil then exit;
// collect values of selected controls
for i:=0 to FSelection.Count-1 do begin
CurPersistent:=FSelection[i];
if CurPersistent is TControl then begin
AControl:=TControl(CurPersistent);
if Result = nil then
begin
Result := FSelectedControlsList;
Result.Clear;
end;
Result.Add(AControl);
end;
end;
end;
function TAnchorDesigner.FindSibling(const Sibling: string): TControl;
var
Root: TPersistent;
RootComponent: TComponent;
i: Integer;
CurComponent: TComponent;
CurControl: TControl;
begin
Result:=nil;
Root:=GlobalDesignHook.LookupRoot;
if not (Root is TComponent) then exit;
RootComponent:=TComponent(Root);
if (RootComponent is TControl)
and (CompareText(Sibling,ControlToStr(TControl(RootComponent)))=0) then begin
Result:=TControl(RootComponent);
exit;
end;
for i:=0 to RootComponent.ComponentCount-1 do begin
CurComponent:=TComponent(RootComponent.Components[i]);
if CurComponent is TControl then begin
CurControl:=TControl(CurComponent);
if CompareText(Sibling,ControlToStr(CurControl))=0 then begin
Result:=CurControl;
exit;
end;
end;
end;
end;
class function TAnchorDesigner.ControlToStr(AControl: TControl): string;
begin
if AControl=nil then
Result:=''
else
Result:=AControl.Name+':'+AControl.ClassName;
end;
procedure TAnchorDesigner.CollectValues(
const ASelection: TList; var TheValues: TAnchorDesignerValues;
var SelectedControlCount: integer);
var
i: Integer;
AControl: TControl;
CurObject: TObject;
begin
TheValues:=nil;
SelectedControlCount:=0;
//debugln('TAnchorDesigner.CollectValues A ');
if ASelection=nil then exit;
// collect values of selected controls
for i:=0 to ASelection.Count-1 do begin
CurObject:=TObject(ASelection[i]);
//debugln('TAnchorDesigner.CollectValues B ',dbgs(i),' ',DbgSName(CurObject));
if CurObject is TControl then begin
AControl:=TControl(CurObject);
if SelectedControlCount=0 then begin
TheValues:=TAnchorDesignerValues.Create;
TheValues.SetValues(AControl);
end else begin
TheValues.MergeValues(AControl);
end;
inc(SelectedControlCount);
end;
end;
end;
procedure TAnchorDesigner.OnSetSelection(
const ASelection: TPersistentSelectionList);
begin
if FSelection.IsEqual(ASelection) then exit;
Refresh(false);
end;
procedure TAnchorDesigner.AnchorDesignerClose(Sender: TObject;
var CloseAction: TCloseAction);
begin
EnvironmentOptions.IDEWindowLayoutList.ItemByForm(Self).GetCurrentPosition;
end;
{ TAnchorDesignerValues }
function TAnchorDesignerValues.GetSides(Kind: TAnchorKind
): TAnchorDesignerSideValues;
begin
Result:=FSides[Kind];
end;
procedure TAnchorDesignerValues.SetAmbiguousBorderspaceAround(
const AValue: boolean);
begin
if FAmbiguousBorderspaceAround=AValue then exit;
FAmbiguousBorderspaceAround:=AValue;
end;
procedure TAnchorDesignerValues.SetBorderspaceAround(const AValue: integer);
begin
if FBorderspaceAround=AValue then exit;
FBorderspaceAround:=AValue;
end;
constructor TAnchorDesignerValues.Create;
var
a: TAnchorKind;
begin
for a:=Low(TAnchorKind) to High(TAnchorKind) do
FSides[a]:=TAnchorDesignerSideValues.Create(a);
end;
destructor TAnchorDesignerValues.Destroy;
var
a: TAnchorKind;
begin
for a:=Low(TAnchorKind) to High(TAnchorKind) do FSides[a].Free;
inherited Destroy;
end;
procedure TAnchorDesignerValues.SetValues(AControl: TControl);
var
a: TAnchorKind;
begin
BorderspaceAround:=AControl.BorderSpacing.Around;
AmbiguousBorderspaceAround:=false;
for a:=Low(TAnchorKind) to High(TAnchorKind) do
FSides[a].SetValues(AControl);
end;
procedure TAnchorDesignerValues.MergeValues(AControl: TControl);
var
a: TAnchorKind;
begin
FAmbiguousBorderspaceAround:=FAmbiguousBorderspaceAround
or (FBorderspaceAround<>AControl.BorderSpacing.Around);
for a:=Low(TAnchorKind) to High(TAnchorKind) do
FSides[a].MergeValues(AControl);
end;
{ TAnchorDesignerSideValues }
constructor TAnchorDesignerSideValues.Create(TheKind: TAnchorKind);
begin
FAnchorKind:=TheKind;
end;
procedure TAnchorDesignerSideValues.SetValues(AControl: TControl);
var
CurSide: TAnchorSide;
begin
FAmbiguousBorderSpace:=false;
FBorderSpace:=AControl.BorderSpacing.GetSideSpace(FAnchorKind);
FAmbiguousEnabled:=false;
FEnabled:=(FAnchorKind in AControl.Anchors);
CurSide:=AControl.AnchorSide[FAnchorKind];
FAmbiguousSide:=false;
FSide:=CurSide.Side;
FAmbiguousSibling:=false;
FSibling:=TAnchorDesigner.ControlToStr(CurSide.Control);
end;
procedure TAnchorDesignerSideValues.MergeValues(AControl: TControl);
var
CurSide: TAnchorSide;
begin
FAmbiguousBorderSpace:=FAmbiguousBorderSpace
or (FBorderSpace<>AControl.BorderSpacing.GetSideSpace(FAnchorKind));
FAmbiguousEnabled:=FAmbiguousEnabled
or (FEnabled<>(FAnchorKind in AControl.Anchors));
CurSide:=AControl.AnchorSide[FAnchorKind];
FAmbiguousSide:=FAmbiguousSide or (CurSide.Side<>FSide);
FAmbiguousSibling:=FAmbiguousSibling
or (TAnchorDesigner.ControlToStr(CurSide.Control)<>FSibling);
end;
{ TAnchorPropertyEditor }
function TAnchorPropertyEditor.GetAttributes: TPropertyAttributes;
begin
Result:=(inherited GetAttributes)+[paDialog];
end;
procedure TAnchorPropertyEditor.Edit;
begin
ShowAnchorDesigner(Self);
end;
initialization
RegisterPropertyEditor(TypeInfo(TAnchors), TControl, 'Anchors',
TAnchorPropertyEditor);
{$I anchoreditor.lrs}
end.