mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-05-20 11:22:30 +02:00
746 lines
20 KiB
ObjectPascal
746 lines
20 KiB
ObjectPascal
{
|
|
*****************************************************************************
|
|
See the file COPYING.modifiedLGPL.txt, included in this distribution,
|
|
for details about the license.
|
|
*****************************************************************************
|
|
|
|
Author: Michael W. Vogel
|
|
}
|
|
|
|
unit DockedAnchorControl;
|
|
|
|
{$mode objfpc}{$H+}
|
|
{$modeswitch advancedrecords}
|
|
{$modeswitch typehelpers}
|
|
|
|
interface
|
|
|
|
uses
|
|
// RTL, FCL
|
|
Classes, SysUtils, fgl, FPCanvas,
|
|
// LCL
|
|
Controls, ExtCtrls, Graphics, LCLProc, Dialogs, PairSplitter, ComCtrls,
|
|
LCLType, IDEDialogs,
|
|
// DockedFormEditor
|
|
DockedOptionsIDE, DockedStrConsts, DockedTools;
|
|
|
|
type
|
|
|
|
{ TAnchorsHelper }
|
|
|
|
TAnchorsHelper = type helper for TAnchors
|
|
function ToString: String;
|
|
end;
|
|
|
|
const
|
|
AnchorSideReferenceStr: array[TAnchorSideReference] of String =
|
|
('Top', 'Bottom', 'Center');
|
|
|
|
type
|
|
TAttachDetach = (adAttachControl, adDetachControl, adAttachPoint, adDetachPoint, adAttachSide, adDetachSide);
|
|
|
|
const
|
|
AttachDetachStr: array[TAttachDetach] of String =
|
|
(SAttachControl, SDetachControl, SAttachPoint, SDetachPoint, SAttachSide, SDetachSide);
|
|
|
|
type
|
|
|
|
TAnchorControlState = (acsNone, acsInvalid, acsSelected, acsUpdating);
|
|
TAnchorControlStates = set of TAnchorControlState;
|
|
TAnchorState = (asMouseDown, asMoving, asAnchorLeft, asAnchorTop, asAnchorRight,
|
|
asAnchorBottom, asBordering);
|
|
TAnchorStates = set of TAnchorState;
|
|
|
|
{ TAnchorStatesHelper }
|
|
|
|
TAnchorStatesHelper = type helper for TAnchorStates
|
|
function IsAnchoring: Boolean;
|
|
function IsAnchoringBottom: Boolean;
|
|
function IsAnchoringHorz: Boolean;
|
|
function IsAnchoringLeft: Boolean;
|
|
function IsAnchoringRight: Boolean;
|
|
function IsAnchoringTop: Boolean;
|
|
function IsAnchoringVert: Boolean;
|
|
function IsBordering: Boolean;
|
|
function IsMouseDown: Boolean;
|
|
function IsMoving: Boolean;
|
|
end;
|
|
|
|
{ TTargetAnchorSide }
|
|
|
|
TTargetAnchorSide = record
|
|
Kind: TAnchorKind;
|
|
Side: TAnchorSideReference;
|
|
class operator = (Item1, Item2: TTargetAnchorSide): Boolean;
|
|
end;
|
|
|
|
{ TTargetAnchorSides }
|
|
|
|
TTargetAnchorSides = class(specialize TFPGList<TTargetAnchorSide>)
|
|
public
|
|
procedure Add(AKind: TAnchorKind; ASide: TAnchorSideReference); overload;
|
|
end;
|
|
|
|
{ TAnchorControl }
|
|
|
|
TAnchorControl = class(TPanel)
|
|
private
|
|
FIsChildControl: Boolean;
|
|
FRootControl: TControl;
|
|
FState: TAnchorControlStates;
|
|
FTargetAnchorSides: TTargetAnchorSides;
|
|
procedure AnchorControlShowHint(Sender: TObject; HintInfo: PHintInfo);
|
|
function BorderSpacingStr: String;
|
|
function BoundsString: String;
|
|
procedure CheckIsChildControl;
|
|
procedure CreateCaption;
|
|
public
|
|
constructor Create(AParent: TWinControl; ARootControl: TControl); reintroduce;
|
|
destructor Destroy; override;
|
|
function AnchorSideStr(AKind: TAnchorKind): String;
|
|
function AnchorsString: String;
|
|
function AnchorValid(AKind: TAnchorKind; AControl: TControl; ASide: TAnchorSideReference): Boolean;
|
|
function AnchorsValid: Boolean;
|
|
procedure AssignAnchor(ASource: TAnchorControl; AKind: TAnchorKind);
|
|
procedure AssignAnchors(ASource: TAnchorControl);
|
|
procedure AssignBounds(ASource: TAnchorControl);
|
|
procedure AssignFull(ASource: TAnchorControl);
|
|
procedure AssignToRoot_Anchor(AKind: TAnchorKind);
|
|
procedure AssignToRoot_Anchors;
|
|
procedure AssignToRoot_Bounds;
|
|
procedure AssignToRoot_ControlsBounds(SelfBoundsToRoot: Boolean);
|
|
procedure AssignToRoot_Full;
|
|
procedure Invalid;
|
|
function IsInvalid: Boolean;
|
|
procedure Paint; override;
|
|
procedure RemoveAnchorSide(AAnchorKind: TAnchorKind);
|
|
procedure RemoveAnchorSides;
|
|
procedure SetNewParent(AParent: TWinControl);
|
|
procedure TargetAnchorSidesGet(AAnchorControl: TAnchorControl);
|
|
procedure Validate;
|
|
public
|
|
property IsChildControl: Boolean read FIsChildControl;
|
|
property RootControl: TControl read FRootControl;
|
|
property State: TAnchorControlStates read FState write FState;
|
|
end;
|
|
|
|
{ TAnchorControls }
|
|
|
|
TAnchorControls = class(specialize TFPGObjectList<TAnchorControl>)
|
|
// on Index[0], there is FBackGround
|
|
public
|
|
destructor Destroy; override;
|
|
procedure BeginUpdate;
|
|
procedure EndUpdate;
|
|
procedure CheckAnchors;
|
|
procedure CheckParents;
|
|
procedure CheckProperties;
|
|
procedure DeleteIndexAndAbove(AIndex: Integer);
|
|
function IndexOf(AControl: TControl): Integer; overload;
|
|
procedure Invalid;
|
|
function RemoveInvalid: Boolean;
|
|
end;
|
|
|
|
{ TBorderControl }
|
|
|
|
TBorderControl = class(TPanel)
|
|
FBitmap: TBitmap;
|
|
public
|
|
constructor Create(TheOwner: TComponent); override;
|
|
destructor Destroy; override;
|
|
procedure Paint; override;
|
|
end;
|
|
|
|
implementation
|
|
|
|
{ TAnchorsHelper }
|
|
|
|
function TAnchorsHelper.ToString: String;
|
|
begin
|
|
Result := EmptyStr;
|
|
if akLeft in Self then Result := EnumerationString(Result, STabPositionLeft);
|
|
if akTop in Self then Result := EnumerationString(Result, STabPositionTop);
|
|
if akRight in Self then Result := EnumerationString(Result, STabPositionRight);
|
|
if akBottom in Self then Result := EnumerationString(Result, STabPositionBottom);
|
|
Result := '[' + Result + ']';
|
|
end;
|
|
|
|
{ TAnchorStatesHelper }
|
|
|
|
function TAnchorStatesHelper.IsAnchoring: Boolean;
|
|
begin
|
|
Result := Self * [asAnchorLeft, asAnchorRight, asAnchorTop, asAnchorBottom] <> [];
|
|
end;
|
|
|
|
function TAnchorStatesHelper.IsAnchoringBottom: Boolean;
|
|
begin
|
|
Result := asAnchorBottom in Self;
|
|
end;
|
|
|
|
function TAnchorStatesHelper.IsAnchoringHorz: Boolean;
|
|
begin
|
|
Result := Self * [asAnchorLeft, asAnchorRight] <> [];
|
|
end;
|
|
|
|
function TAnchorStatesHelper.IsAnchoringLeft: Boolean;
|
|
begin
|
|
Result := asAnchorLeft in Self;
|
|
end;
|
|
|
|
function TAnchorStatesHelper.IsAnchoringRight: Boolean;
|
|
begin
|
|
Result := asAnchorRight in Self;
|
|
end;
|
|
|
|
function TAnchorStatesHelper.IsAnchoringTop: Boolean;
|
|
begin
|
|
Result := asAnchorTop in Self;
|
|
end;
|
|
|
|
function TAnchorStatesHelper.IsAnchoringVert: Boolean;
|
|
begin
|
|
Result := Self * [asAnchorTop, asAnchorBottom] <> [];
|
|
end;
|
|
|
|
function TAnchorStatesHelper.IsBordering: Boolean;
|
|
begin
|
|
Result := asBordering in Self;
|
|
end;
|
|
|
|
function TAnchorStatesHelper.IsMouseDown: Boolean;
|
|
begin
|
|
Result := asMouseDown in Self;
|
|
end;
|
|
|
|
function TAnchorStatesHelper.IsMoving: Boolean;
|
|
begin
|
|
Result := asMoving in Self;
|
|
end;
|
|
|
|
{ TTargetAnchorSide }
|
|
|
|
class operator TTargetAnchorSide. = (Item1, Item2: TTargetAnchorSide): Boolean;
|
|
begin
|
|
Result := (Item1.Kind = Item2.Kind) and
|
|
(Item1.Side = Item2.Side);
|
|
end;
|
|
|
|
{ TTargetAnchorSides }
|
|
|
|
procedure TTargetAnchorSides.Add(AKind: TAnchorKind; ASide: TAnchorSideReference);
|
|
var
|
|
LTargetAnchorSide: TTargetAnchorSide;
|
|
begin
|
|
LTargetAnchorSide.Kind := AKind;
|
|
LTargetAnchorSide.Side := ASide;
|
|
Add(LTargetAnchorSide);
|
|
end;
|
|
|
|
{ TAnchorControl }
|
|
|
|
procedure TAnchorControl.AnchorControlShowHint(Sender: TObject; HintInfo: PHintInfo);
|
|
begin
|
|
HintInfo^.HintStr := 'Name [' + DbgSName(RootControl) + ']' + LineEnding +
|
|
'Bounds [' + BoundsString + ']' + LineEnding +
|
|
'Align [' + DbgS(Align) + ']' + LineEnding +
|
|
AnchorsString +
|
|
'Borderspacing [' + BorderSpacingStr + ']';
|
|
HintInfo^.HideTimeout := 5000;
|
|
end;
|
|
|
|
function TAnchorControl.BorderSpacingStr: String;
|
|
begin
|
|
Result := 'Around: ' + BorderSpacing.Around.ToString +
|
|
', Left: ' + BorderSpacing.Left.ToString +
|
|
', Top: ' + BorderSpacing.Top.ToString +
|
|
', Right: ' + BorderSpacing.Right.ToString +
|
|
', Bottom: ' + BorderSpacing.Bottom.ToString;
|
|
end;
|
|
|
|
function TAnchorControl.BoundsString: String;
|
|
begin
|
|
Result := 'Left: ' + Left.ToString +
|
|
', Top: ' + Top.ToString +
|
|
', Width: ' + Width.ToString +
|
|
', Height: ' + Height.ToString;
|
|
end;
|
|
|
|
procedure TAnchorControl.CheckIsChildControl;
|
|
begin
|
|
FIsChildControl :=
|
|
(FRootControl is TPairSplitterSide) or
|
|
((FRootControl is TSplitter) and (FRootControl.Parent is TPairSplitter)) or
|
|
(FRootControl is TToolButton) or
|
|
(FRootControl is TPage) or
|
|
(FRootControl is TTabSheet);
|
|
end;
|
|
|
|
procedure TAnchorControl.CreateCaption;
|
|
begin
|
|
if not FRootControl.Name.IsEmpty then
|
|
Caption := FRootControl.Name
|
|
else
|
|
Caption := FRootControl.ClassName;
|
|
end;
|
|
|
|
constructor TAnchorControl.Create(AParent: TWinControl; ARootControl: TControl);
|
|
begin
|
|
inherited Create(nil);
|
|
FTargetAnchorSides := TTargetAnchorSides.Create;
|
|
FRootControl := ARootControl;
|
|
CreateCaption;
|
|
CheckIsChildControl;
|
|
SetBounds(ARootControl.Left, ARootControl.Top, ARootControl.Width, ARootControl.Height);
|
|
BorderSpacing := ARootControl.BorderSpacing;
|
|
Align := ARootControl.Align;
|
|
Parent := AParent;
|
|
Color := DockedOptions.AnchorControlColor;
|
|
ParentColor := False;
|
|
FState := [acsNone];
|
|
ParentShowHint := False;
|
|
ShowHint := True;
|
|
OnShowHint := @AnchorControlShowHint;
|
|
end;
|
|
|
|
destructor TAnchorControl.Destroy;
|
|
begin
|
|
FTargetAnchorSides.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
function TAnchorControl.AnchorSideStr(AKind: TAnchorKind): String;
|
|
begin
|
|
case AKind of
|
|
akLeft: Result := 'Anchor Left [';
|
|
akTop: Result := 'Anchor Top [';
|
|
akRight: Result := 'Anchor Right [';
|
|
akBottom: Result := 'Anchor Bottom [';
|
|
end;
|
|
if not Assigned(AnchorSide[AKind].Control) or not (AnchorSide[AKind].Control is TAnchorControl) then
|
|
Result := Result +
|
|
'Control: nil]'
|
|
else
|
|
Result := Result +
|
|
'Control: ' + TAnchorControl(AnchorSide[AKind].Control).Caption +
|
|
', Side: ' + AnchorSideReferenceStr[AnchorSide[AKind].Side] + ']';
|
|
end;
|
|
|
|
function TAnchorControl.AnchorsString: String;
|
|
var
|
|
LKind: TAnchorKind;
|
|
begin
|
|
Result := '';
|
|
for LKind := akTop to akBottom do
|
|
if LKind in Anchors then
|
|
Result := LinedString(Result, AnchorSideStr(LKind));
|
|
if not Result.IsEmpty then
|
|
Result := Result + LineEnding;
|
|
end;
|
|
|
|
function TAnchorControl.AnchorValid(AKind: TAnchorKind; AControl: TControl; ASide: TAnchorSideReference): Boolean;
|
|
var
|
|
LReferenceControl: TControl;
|
|
LReferenceSide: TAnchorSideReference;
|
|
LPosition: Integer;
|
|
begin
|
|
Result := AnchorSide[AKind].CheckSidePosition(AControl,
|
|
ASide,
|
|
LReferenceControl,
|
|
LReferenceSide,
|
|
LPosition);
|
|
end;
|
|
|
|
function TAnchorControl.AnchorsValid: Boolean;
|
|
var
|
|
LKind: TAnchorKind;
|
|
begin
|
|
for LKind := akTop to akBottom do
|
|
begin
|
|
if not (LKind in Anchors) then Continue;
|
|
if not AnchorValid(LKind,
|
|
AnchorSide[LKind].Control,
|
|
AnchorSide[LKind].Side)
|
|
then
|
|
if IDEMessageDialog(
|
|
SWarningCaption,
|
|
SCircularDependency,
|
|
mtWarning,
|
|
[mbIgnore, mbCancel]) = mrIgnore
|
|
then Exit(True)
|
|
else Exit(False);
|
|
end;
|
|
Result := True;
|
|
end;
|
|
|
|
procedure TAnchorControl.AssignAnchor(ASource: TAnchorControl; AKind: TAnchorKind);
|
|
begin
|
|
AnchorSide[AKind].Control := ASource.AnchorSide[AKind].Control;
|
|
AnchorSide[AKind].Side := ASource.AnchorSide[AKind].Side;
|
|
if AKind in ASource.Anchors then
|
|
Anchors := Anchors + [AKind]
|
|
else
|
|
Anchors := Anchors - [AKind];
|
|
|
|
if not DockedOptions.TreatAlign then Exit;
|
|
case ASource.Align of
|
|
alNone, alCustom: Exit;
|
|
alTop: if AKind = akBottom then Exit;
|
|
alLeft: if AKind = akRight then Exit;
|
|
alRight: if AKind = akLeft then Exit;
|
|
alBottom: if AKind = akTop then Exit;
|
|
end;
|
|
AnchorSide[AKind].Control := ASource.Parent;
|
|
case AKind of
|
|
akTop: AnchorSide[AKind].Side := asrTop;
|
|
akLeft: AnchorSide[AKind].Side := asrTop;
|
|
akRight: AnchorSide[AKind].Side := asrBottom;
|
|
akBottom: AnchorSide[AKind].Side := asrBottom;
|
|
end;
|
|
end;
|
|
|
|
procedure TAnchorControl.AssignAnchors(ASource: TAnchorControl);
|
|
var
|
|
LKind: TAnchorKind;
|
|
begin
|
|
for LKind := akTop to akBottom do
|
|
AssignAnchor(ASource, LKind);
|
|
Anchors := ASource.Anchors;
|
|
end;
|
|
|
|
procedure TAnchorControl.AssignBounds(ASource: TAnchorControl);
|
|
var
|
|
LRect: TRect;
|
|
begin
|
|
LRect := ASource.BoundsRect;
|
|
SetBounds(LRect.Left, LRect.Top, LRect.Width, LRect.Height);
|
|
BorderSpacing := ASource.BorderSpacing;
|
|
end;
|
|
|
|
procedure TAnchorControl.AssignFull(ASource: TAnchorControl);
|
|
begin
|
|
Align := ASource.Align;
|
|
AssignAnchors(ASource);
|
|
AssignBounds(ASource);
|
|
end;
|
|
|
|
procedure TAnchorControl.AssignToRoot_Anchor(AKind: TAnchorKind);
|
|
var
|
|
LAnchorSideControl: TControl;
|
|
begin
|
|
LAnchorSideControl := AnchorSide[AKind].Control;
|
|
if LAnchorSideControl is TAnchorControl then
|
|
RootControl.AnchorSide[AKind].Control := TAnchorControl(LAnchorSideControl).RootControl
|
|
else
|
|
RootControl.AnchorSide[AKind].Control := nil;
|
|
RootControl.AnchorSide[AKind].Side := AnchorSide[AKind].Side;
|
|
end;
|
|
|
|
procedure TAnchorControl.AssignToRoot_Anchors;
|
|
var
|
|
LKind: TAnchorKind;
|
|
begin
|
|
if DockedOptions.TreatAlign then
|
|
RootControl.Align := alNone;
|
|
for LKind := akTop to akBottom do
|
|
AssignToRoot_Anchor(LKind);
|
|
RootControl.Anchors := Anchors;
|
|
end;
|
|
|
|
procedure TAnchorControl.AssignToRoot_Bounds;
|
|
var
|
|
LRect: TRect;
|
|
begin
|
|
LRect := BoundsRect;
|
|
RootControl.SetBounds(LRect.Left, LRect.Top, LRect.Width, LRect.Height);
|
|
RootControl.BorderSpacing := BorderSpacing;
|
|
end;
|
|
|
|
procedure TAnchorControl.AssignToRoot_ControlsBounds(SelfBoundsToRoot: Boolean);
|
|
var
|
|
i: Integer;
|
|
begin
|
|
if SelfBoundsToRoot then
|
|
AssignToRoot_Bounds;
|
|
|
|
for i := 0 to ControlCount - 1 do
|
|
if Controls[i] is TAnchorControl then
|
|
TAnchorControl(Controls[i]).AssignToRoot_ControlsBounds(True);
|
|
end;
|
|
|
|
procedure TAnchorControl.AssignToRoot_Full;
|
|
begin
|
|
AssignToRoot_Anchors;
|
|
AssignToRoot_Bounds;
|
|
end;
|
|
|
|
procedure TAnchorControl.Invalid;
|
|
begin
|
|
FState := [acsInvalid];
|
|
end;
|
|
|
|
function TAnchorControl.IsInvalid: Boolean;
|
|
begin
|
|
Result := acsInvalid in State;
|
|
end;
|
|
|
|
procedure TAnchorControl.Paint;
|
|
var
|
|
LKind: TAnchorKind;
|
|
LColor: TColor;
|
|
LTargetAnchorSide: TTargetAnchorSide;
|
|
begin
|
|
inherited Paint;
|
|
if acsInvalid in State then Exit;
|
|
if acsUpdating in State then Exit;
|
|
|
|
for LTargetAnchorSide in FTargetAnchorSides do
|
|
begin
|
|
case LTargetAnchorSide.Kind of
|
|
akBottom: Canvas.Pen.Color := DockedOptions.AnchorBottomColor;
|
|
akLeft: Canvas.Pen.Color := DockedOptions.AnchorLeftColor;
|
|
akRight: Canvas.Pen.Color := DockedOptions.AnchorRightColor;
|
|
akTop: Canvas.Pen.Color := DockedOptions.AnchorTopColor;
|
|
end;
|
|
if LTargetAnchorSide.Kind in [akLeft, akRight] then
|
|
case LTargetAnchorSide.Side of
|
|
asrLeft: Canvas.Line(0, 0, 0, Height - 1);
|
|
asrCenter: Canvas.Line((Width - 1) div 2, 0, (Width - 1) div 2, Height - 1);
|
|
asrRight: Canvas.Line(Width - 1, 0, Width - 1, Height - 1);
|
|
end
|
|
else
|
|
case LTargetAnchorSide.Side of
|
|
asrTop: Canvas.Line(0, 0, Width - 1, 0);
|
|
asrCenter: Canvas.Line(0, (Height - 1) div 2, Width - 1, (Height - 1) div 2);
|
|
asrBottom: Canvas.Line(0, Height - 1, Width - 1, Height - 1);
|
|
end;
|
|
end;
|
|
|
|
if acsSelected in State then
|
|
for LKind := akTop to akBottom do
|
|
begin
|
|
LColor := clBlack;
|
|
if (LKind in Anchors) and Assigned(AnchorSide[LKind].Control) then
|
|
case LKind of
|
|
akBottom: LColor := DockedOptions.AnchorBottomColor;
|
|
akLeft: LColor := DockedOptions.AnchorLeftColor;
|
|
akRight: LColor := DockedOptions.AnchorRightColor;
|
|
akTop: LColor := DockedOptions.AnchorTopColor;
|
|
end;
|
|
Canvas.Pen.Color := LColor;
|
|
case LKind of
|
|
akBottom: Canvas.Line(0, Height - 1, Width - 1, Height - 1);
|
|
akLeft: Canvas.Line(0, 0, 0, Height - 1);
|
|
akRight: Canvas.Line(Width - 1, 0, Width - 1, Height - 1);
|
|
akTop: Canvas.Line(0, 0, Width - 1, 0);
|
|
end;
|
|
end;
|
|
end;
|
|
|
|
procedure TAnchorControl.RemoveAnchorSide(AAnchorKind: TAnchorKind);
|
|
begin
|
|
AnchorSide[AAnchorKind].Control := nil;
|
|
AnchorSide[AAnchorKind].Side := asrTop;
|
|
Anchors := Anchors - [AAnchorKind];
|
|
end;
|
|
|
|
procedure TAnchorControl.RemoveAnchorSides;
|
|
var
|
|
LKind: TAnchorKind;
|
|
begin
|
|
if DockedOptions.TreatAlign then
|
|
Align := alNone;
|
|
for LKind := akTop to akBottom do
|
|
RemoveAnchorSide(LKind);
|
|
end;
|
|
|
|
procedure TAnchorControl.SetNewParent(AParent: TWinControl);
|
|
begin
|
|
Parent := AParent;
|
|
end;
|
|
|
|
procedure TAnchorControl.TargetAnchorSidesGet(AAnchorControl: TAnchorControl);
|
|
var
|
|
LKind: TAnchorKind;
|
|
begin
|
|
FTargetAnchorSides.Clear;
|
|
if not Assigned(AAnchorControl) then Exit;
|
|
for LKind := akTop to akBottom do
|
|
if (LKind in AAnchorControl.Anchors) and (AAnchorControl.AnchorSide[LKind].Control = Self) then
|
|
FTargetAnchorSides.Add(LKind, AAnchorControl.AnchorSide[LKind].Side);
|
|
end;
|
|
|
|
procedure TAnchorControl.Validate;
|
|
begin
|
|
FState := [acsNone];
|
|
end;
|
|
|
|
{ TAnchorControls }
|
|
|
|
destructor TAnchorControls.Destroy;
|
|
begin
|
|
while Count > 0 do
|
|
Delete(Count - 1);
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TAnchorControls.BeginUpdate;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 1 to Count - 1 do
|
|
if Self[i].IsInvalid then
|
|
Continue
|
|
else
|
|
Self[i].State := Self[i].State + [acsUpdating];
|
|
end;
|
|
|
|
procedure TAnchorControls.EndUpdate;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 1 to Count - 1 do
|
|
if Self[i].IsInvalid then
|
|
Continue
|
|
else
|
|
Self[i].State := Self[i].State - [acsUpdating];
|
|
end;
|
|
|
|
procedure TAnchorControls.CheckAnchors;
|
|
var
|
|
i: Integer;
|
|
LKind: TAnchorKind;
|
|
LIndex: Integer;
|
|
begin
|
|
for i := 1 to Count - 1 do
|
|
if Self[i].IsInvalid then
|
|
Continue
|
|
else
|
|
begin
|
|
for LKind := akTop to akBottom do
|
|
begin
|
|
Self[i].AnchorSide[LKind].Side := Self[i].RootControl.AnchorSide[LKind].Side;
|
|
if Self[i].RootControl.AnchorSide[LKind].Control = nil then
|
|
begin
|
|
Self[i].AnchorSide[LKind].Control := nil;
|
|
Continue;
|
|
end;
|
|
LIndex := IndexOf(Self[i].RootControl.AnchorSide[LKind].Control);
|
|
if LIndex >= 0 then
|
|
Self[i].AnchorSide[LKind].Control := Self[LIndex]
|
|
else
|
|
Self[i].AnchorSide[LKind].Control := nil;
|
|
end;
|
|
Self[i].Anchors := Self[i].RootControl.Anchors;
|
|
end;
|
|
end;
|
|
|
|
procedure TAnchorControls.CheckParents;
|
|
var
|
|
LIndex, i: Integer;
|
|
begin
|
|
for i := 1 to Count - 1 do
|
|
if Self[i].IsInvalid then
|
|
Continue
|
|
else
|
|
begin
|
|
LIndex := IndexOf(Self[i].RootControl.Parent);
|
|
if LIndex >= 0 then
|
|
Self[i].SetNewParent(Self[LIndex])
|
|
else
|
|
// use BackGround
|
|
Self[i].SetNewParent(Self[0]);
|
|
end;
|
|
end;
|
|
|
|
procedure TAnchorControls.CheckProperties;
|
|
var
|
|
i, LLeft, LTop, LWidth, LHeight: Integer;
|
|
begin
|
|
for i := 1 to Count - 1 do
|
|
if Self[i].IsInvalid or Self[i].IsChildControl then
|
|
Continue
|
|
else
|
|
begin
|
|
LLeft := Self[i].RootControl.Left;
|
|
LTop := Self[i].RootControl.Top;
|
|
LWidth := Self[i].RootControl.Width;
|
|
LHeight := Self[i].RootControl.Height;
|
|
if (LLeft <> Self[i].Left)
|
|
or (LTop <> Self[i].Top)
|
|
or (LWidth <> Self[i].Width)
|
|
or (LHeight <> Self[i].Height) then
|
|
Self[i].SetBounds(LLeft, LTop, LWidth, LHeight);
|
|
|
|
Self[i].Align := Self[i].RootControl.Align;
|
|
Self[i].BorderSpacing := Self[i].RootControl.BorderSpacing;
|
|
Self[i].CreateCaption;
|
|
end;
|
|
end;
|
|
|
|
procedure TAnchorControls.DeleteIndexAndAbove(AIndex: Integer);
|
|
begin
|
|
while Count > AIndex do
|
|
Delete(Count - 1);
|
|
end;
|
|
|
|
function TAnchorControls.IndexOf(AControl: TControl): Integer;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := - 1;
|
|
for i := 0 to Count - 1 do
|
|
if Self[i].RootControl = AControl then
|
|
Exit(i);
|
|
end;
|
|
|
|
procedure TAnchorControls.Invalid;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
for i := 1 to Count - 1 do
|
|
Self[i].Invalid;
|
|
end;
|
|
|
|
function TAnchorControls.RemoveInvalid: Boolean;
|
|
var
|
|
i: Integer;
|
|
begin
|
|
Result := False;
|
|
for i := Count - 1 downto 1 do
|
|
if Self[i].IsInvalid then
|
|
begin
|
|
Delete(i);
|
|
Result := True;
|
|
end;
|
|
end;
|
|
|
|
{ TBorderControl }
|
|
|
|
constructor TBorderControl.Create(TheOwner: TComponent);
|
|
begin
|
|
inherited Create(TheOwner);
|
|
FBitmap := TBitmap.Create;
|
|
FBitmap.SetSize(2, 2);
|
|
FBitmap.Canvas.Pixels[0, 0] := DockedOptions.AnchorBorderColor;
|
|
FBitmap.Canvas.Pixels[0, 1] := DockedOptions.AnchorControlColor;
|
|
FBitmap.Canvas.Pixels[1, 0] := DockedOptions.AnchorControlColor;
|
|
FBitmap.Canvas.Pixels[1, 1] := DockedOptions.AnchorBorderColor;
|
|
BevelOuter := bvNone;
|
|
end;
|
|
|
|
destructor TBorderControl.Destroy;
|
|
begin
|
|
FBitmap.Free;
|
|
inherited Destroy;
|
|
end;
|
|
|
|
procedure TBorderControl.Paint;
|
|
begin
|
|
Canvas.Brush.Style := bsImage;
|
|
Canvas.Brush.Bitmap := FBitmap;
|
|
Canvas.FillRect(0, 0, ClientWidth, ClientHeight);
|
|
end;
|
|
|
|
end.
|
|
|