mirror of
https://gitlab.com/freepascal.org/lazarus/lazarus.git
synced 2025-08-16 00:19:32 +02:00
anchordocking: page tab position
git-svn-id: trunk@26058 -
This commit is contained in:
parent
0ee2f904ac
commit
448ae99fb8
@ -183,6 +183,7 @@ type
|
|||||||
procedure MoveLeftMostButtonClick(Sender: TObject); virtual;
|
procedure MoveLeftMostButtonClick(Sender: TObject); virtual;
|
||||||
procedure MoveRightButtonClick(Sender: TObject); virtual;
|
procedure MoveRightButtonClick(Sender: TObject); virtual;
|
||||||
procedure MoveRightMostButtonClick(Sender: TObject); virtual;
|
procedure MoveRightMostButtonClick(Sender: TObject); virtual;
|
||||||
|
procedure TabPositionClick(Sender: TObject); virtual;
|
||||||
public
|
public
|
||||||
constructor Create(TheOwner: TComponent); override;
|
constructor Create(TheOwner: TComponent); override;
|
||||||
procedure UpdateDockCaption(Exclude: TControl = nil); override;
|
procedure UpdateDockCaption(Exclude: TControl = nil); override;
|
||||||
@ -352,6 +353,8 @@ type
|
|||||||
fDisabledAutosizing: TFPList; // list of TControl
|
fDisabledAutosizing: TFPList; // list of TControl
|
||||||
fTreeNameToDocker: TADNameToControl;
|
fTreeNameToDocker: TADNameToControl;
|
||||||
fPopupMenu: TPopupMenu;
|
fPopupMenu: TPopupMenu;
|
||||||
|
fCloseBtnReferenceCount: integer;
|
||||||
|
fCloseBtnBitmap: TBitmap;
|
||||||
function GetControls(Index: integer): TControl;
|
function GetControls(Index: integer): TControl;
|
||||||
procedure SetHeaderAlignLeft(const AValue: integer);
|
procedure SetHeaderAlignLeft(const AValue: integer);
|
||||||
procedure SetHeaderAlignTop(const AValue: integer);
|
procedure SetHeaderAlignTop(const AValue: integer);
|
||||||
@ -439,11 +442,26 @@ procedure AnchorAndChangeBounds(AControl: TControl; Side: TAnchorKind;
|
|||||||
Target: TControl);
|
Target: TControl);
|
||||||
function ControlsLeftTopOnScreen(AControl: TControl): TPoint;
|
function ControlsLeftTopOnScreen(AControl: TControl): TPoint;
|
||||||
|
|
||||||
implementation
|
type
|
||||||
|
TAnchorControlsRect = array[TAnchorKind] of TControl;
|
||||||
|
|
||||||
var
|
function GetDockSplitter(Control: TControl; Side: TAnchorKind;
|
||||||
CloseBtnReferenceCount: integer = 0;
|
out Splitter: TAnchorDockSplitter): boolean;
|
||||||
CloseBtnBitmap: TBitmap = nil;
|
function GetDockSplitterOrParent(Control: TControl; Side: TAnchorKind;
|
||||||
|
out AnchorControl: TControl): boolean;
|
||||||
|
function CountAnchoredControls(Control: TControl; Side: TAnchorKind
|
||||||
|
): Integer;
|
||||||
|
function NeighbourCanBeShrinked(EnlargeControl, Neighbour: TControl;
|
||||||
|
Side: TAnchorKind): boolean;
|
||||||
|
function ControlIsAnchoredIndirectly(StartControl: TControl; Side: TAnchorKind;
|
||||||
|
DestControl: TControl): boolean;
|
||||||
|
procedure GetAnchorControlsRect(Control: TControl;
|
||||||
|
out ARect: TAnchorControlsRect);
|
||||||
|
function GetEnclosingControlRect(ControlList: TFPlist;
|
||||||
|
out ARect: TAnchorControlsRect): boolean;
|
||||||
|
function GetEnclosedControls(const ARect: TAnchorControlsRect): TFPList;
|
||||||
|
|
||||||
|
implementation
|
||||||
|
|
||||||
function dbgs(SiteType: TAnchorDockHostSiteType): string; overload;
|
function dbgs(SiteType: TAnchorDockHostSiteType): string; overload;
|
||||||
begin
|
begin
|
||||||
@ -506,6 +524,323 @@ begin
|
|||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function GetDockSplitter(Control: TControl; Side: TAnchorKind; out
|
||||||
|
Splitter: TAnchorDockSplitter): boolean;
|
||||||
|
begin
|
||||||
|
Result:=false;
|
||||||
|
Splitter:=nil;
|
||||||
|
if not (Side in Control.Anchors) then exit;
|
||||||
|
Splitter:=TAnchorDockSplitter(Control.AnchorSide[Side].Control);
|
||||||
|
if not (Splitter is TAnchorDockSplitter) then begin
|
||||||
|
Splitter:=nil;
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
if Splitter.Parent<>Control.Parent then exit;
|
||||||
|
Result:=true;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetDockSplitterOrParent(Control: TControl; Side: TAnchorKind; out
|
||||||
|
AnchorControl: TControl): boolean;
|
||||||
|
begin
|
||||||
|
Result:=false;
|
||||||
|
AnchorControl:=nil;
|
||||||
|
if not (Side in Control.Anchors) then exit;
|
||||||
|
AnchorControl:=Control.AnchorSide[Side].Control;
|
||||||
|
if (AnchorControl is TAnchorDockSplitter)
|
||||||
|
and (AnchorControl.Parent=Control.Parent)
|
||||||
|
then
|
||||||
|
Result:=true
|
||||||
|
else if AnchorControl=Control.Parent then
|
||||||
|
Result:=true;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function CountAnchoredControls(Control: TControl; Side: TAnchorKind): Integer;
|
||||||
|
{ return the number of siblings, that are anchored on Side of Control
|
||||||
|
For example: if Side=akLeft it will return the number of controls, which
|
||||||
|
right side is anchored to the left of Control }
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
Neighbour: TControl;
|
||||||
|
begin
|
||||||
|
Result:=0;
|
||||||
|
for i:=0 to Control.AnchoredControlCount-1 do begin
|
||||||
|
Neighbour:=Control.AnchoredControls[i];
|
||||||
|
if (OppositeAnchor[Side] in Neighbour.Anchors)
|
||||||
|
and (Neighbour.AnchorSide[OppositeAnchor[Side]].Control=Control) then
|
||||||
|
inc(Result);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function NeighbourCanBeShrinked(EnlargeControl, Neighbour: TControl;
|
||||||
|
Side: TAnchorKind): boolean;
|
||||||
|
{ returns true if Neighbour can be shrinked on the opposite side of Side
|
||||||
|
}
|
||||||
|
const
|
||||||
|
MinControlSize = 20;
|
||||||
|
var
|
||||||
|
Splitter: TAnchorDockSplitter;
|
||||||
|
begin
|
||||||
|
Result:=false;
|
||||||
|
if not GetDockSplitter(EnlargeControl,OppositeAnchor[Side],Splitter) then
|
||||||
|
exit;
|
||||||
|
case Side of
|
||||||
|
akLeft: // check if left side of Neighbour can be moved
|
||||||
|
Result:=Neighbour.Left+Neighbour.Width
|
||||||
|
>EnlargeControl.Left+EnlargeControl.Width+Splitter.Width+MinControlSize;
|
||||||
|
akRight: // check if right side of Neighbour can be moved
|
||||||
|
Result:=Neighbour.Left+MinControlSize+Splitter.Width<EnlargeControl.Left;
|
||||||
|
akTop: // check if top side of Neighbour can be moved
|
||||||
|
Result:=Neighbour.Top+Neighbour.Height
|
||||||
|
>EnlargeControl.Top+EnlargeControl.Height+Splitter.Height+MinControlSize;
|
||||||
|
akBottom: // check if bottom side of Neighbour can be moved
|
||||||
|
Result:=Neighbour.Top+MinControlSize+Splitter.Height<EnlargeControl.Top;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function ControlIsAnchoredIndirectly(StartControl: TControl; Side: TAnchorKind;
|
||||||
|
DestControl: TControl): boolean;
|
||||||
|
{ true if there is an Anchor way from StartControl to DestControl over Side.
|
||||||
|
For example:
|
||||||
|
|
||||||
|
+-+|+-+
|
||||||
|
|A|||B|
|
||||||
|
+-+|+-+
|
||||||
|
|
||||||
|
A is akLeft to B.
|
||||||
|
B is akRight to A.
|
||||||
|
The splitter is akLeft to B.
|
||||||
|
The splitter is akRight to A.
|
||||||
|
All other are false.
|
||||||
|
}
|
||||||
|
var
|
||||||
|
Checked: array of Boolean;
|
||||||
|
Parent: TWinControl;
|
||||||
|
|
||||||
|
function Check(ControlIndex: integer): boolean;
|
||||||
|
var
|
||||||
|
AControl: TControl;
|
||||||
|
SideControl: TControl;
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
if Checked[ControlIndex] then
|
||||||
|
exit(false);
|
||||||
|
Checked[ControlIndex]:=true;
|
||||||
|
AControl:=Parent.Controls[ControlIndex];
|
||||||
|
if AControl=DestControl then exit(true);
|
||||||
|
|
||||||
|
if (Side in AControl.Anchors) then begin
|
||||||
|
SideControl:=AControl.AnchorSide[Side].Control;
|
||||||
|
if (SideControl<>nil) and Check(Parent.GetControlIndex(SideControl)) then
|
||||||
|
exit(true);
|
||||||
|
end;
|
||||||
|
for i:=0 to AControl.AnchoredControlCount-1 do begin
|
||||||
|
if Checked[i] then continue;
|
||||||
|
SideControl:=AControl.AnchoredControls[i];
|
||||||
|
if OppositeAnchor[Side] in SideControl.Anchors then begin
|
||||||
|
if (SideControl.AnchorSide[OppositeAnchor[Side]].Control=AControl)
|
||||||
|
and Check(i) then
|
||||||
|
exit(true);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
Result:=false;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
if (StartControl=nil) or (DestControl=nil)
|
||||||
|
or (StartControl.Parent=nil)
|
||||||
|
or (StartControl.Parent<>DestControl.Parent)
|
||||||
|
or (StartControl=DestControl) then
|
||||||
|
exit(false);
|
||||||
|
Parent:=StartControl.Parent;
|
||||||
|
SetLength(Checked,Parent.ControlCount);
|
||||||
|
for i:=0 to length(Checked)-1 do Checked[i]:=false;
|
||||||
|
Result:=Check(Parent.GetControlIndex(StartControl));
|
||||||
|
end;
|
||||||
|
|
||||||
|
procedure GetAnchorControlsRect(Control: TControl; out
|
||||||
|
ARect: TAnchorControlsRect);
|
||||||
|
var
|
||||||
|
a: TAnchorKind;
|
||||||
|
begin
|
||||||
|
for a:=Low(TAnchorKind) to High(TAnchorKind) do
|
||||||
|
ARect[a]:=Control.AnchorSide[a].Control;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetEnclosingControlRect(ControlList: TFPlist; out
|
||||||
|
ARect: TAnchorControlsRect): boolean;
|
||||||
|
{ ARect will be the minimum TAnchorControlsRect around the controls in the list
|
||||||
|
returns true, if there is such a TAnchorControlsRect.
|
||||||
|
|
||||||
|
The controls in ARect will either be the Parent or a TLazDockSplitter
|
||||||
|
}
|
||||||
|
var
|
||||||
|
Parent: TWinControl;
|
||||||
|
|
||||||
|
function ControlIsValidAnchor(Control: TControl; Side: TAnchorKind): boolean;
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
Result:=false;
|
||||||
|
if (Control=ARect[Side]) then exit(true);// this allows Parent at the beginning
|
||||||
|
|
||||||
|
if not (Control is TAnchorDockSplitter) then
|
||||||
|
exit;// not a splitter
|
||||||
|
if (TAnchorDockSplitter(Control).ResizeAnchor in [akLeft,akRight])
|
||||||
|
<>(Side in [akLeft,akRight]) then
|
||||||
|
exit;// wrong alignment
|
||||||
|
if ControlList.IndexOf(Control)>=0 then
|
||||||
|
exit;// is an inner control
|
||||||
|
if ControlIsAnchoredIndirectly(Control,Side,ARect[Side]) then
|
||||||
|
exit; // this anchor would be worse than the current maximum
|
||||||
|
for i:=0 to ControlList.Count-1 do begin
|
||||||
|
if not ControlIsAnchoredIndirectly(Control,Side,TControl(ControlList[i]))
|
||||||
|
then begin
|
||||||
|
// this anchor is not above (below, ...) the inner controls
|
||||||
|
exit;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
Result:=true;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
TopIndex: Integer;
|
||||||
|
TopControl: TControl;
|
||||||
|
RightIndex: Integer;
|
||||||
|
RightControl: TControl;
|
||||||
|
BottomIndex: Integer;
|
||||||
|
BottomControl: TControl;
|
||||||
|
LeftIndex: Integer;
|
||||||
|
LeftControl: TControl;
|
||||||
|
Candidates: TFPList;
|
||||||
|
i: Integer;
|
||||||
|
a: TAnchorKind;
|
||||||
|
begin
|
||||||
|
Result:=false;
|
||||||
|
if (ControlList=nil) or (ControlList.Count=0) then exit;
|
||||||
|
|
||||||
|
// get Parent
|
||||||
|
Parent:=TControl(ControlList[0]).Parent;
|
||||||
|
if Parent=nil then exit;
|
||||||
|
for i:=0 to ControlList.Count-1 do
|
||||||
|
if TControl(ControlList[i]).Parent<>Parent then exit;
|
||||||
|
|
||||||
|
// set the default rect: the Parent
|
||||||
|
Result:=true;
|
||||||
|
for a:=Low(TAnchorKind) to High(TAnchorKind) do
|
||||||
|
ARect[a]:=Parent;
|
||||||
|
|
||||||
|
// find all possible Candidates
|
||||||
|
Candidates:=TFPList.Create;
|
||||||
|
try
|
||||||
|
Candidates.Add(Parent);
|
||||||
|
for i:=0 to Parent.ControlCount-1 do
|
||||||
|
if Parent.Controls[i] is TAnchorDockSplitter then
|
||||||
|
Candidates.Add(Parent.Controls[i]);
|
||||||
|
|
||||||
|
// now check every possible rectangle
|
||||||
|
// Note: four loops seems to be dog slow, but the checks
|
||||||
|
// avoid most possibilities early
|
||||||
|
for TopIndex:=0 to Candidates.Count-1 do begin
|
||||||
|
TopControl:=TControl(Candidates[TopIndex]);
|
||||||
|
if not ControlIsValidAnchor(TopControl,akTop) then continue;
|
||||||
|
|
||||||
|
for RightIndex:=0 to Candidates.Count-1 do begin
|
||||||
|
RightControl:=TControl(Candidates[RightIndex]);
|
||||||
|
if (TopControl.AnchorSide[akRight].Control<>RightControl)
|
||||||
|
and (RightControl.AnchorSide[akTop].Control<>TopControl) then
|
||||||
|
continue; // not touching / not a corner
|
||||||
|
if not ControlIsValidAnchor(RightControl,akRight) then continue;
|
||||||
|
|
||||||
|
for BottomIndex:=0 to Candidates.Count-1 do begin
|
||||||
|
BottomControl:=TControl(Candidates[BottomIndex]);
|
||||||
|
if (RightControl.AnchorSide[akBottom].Control<>BottomControl)
|
||||||
|
and (BottomControl.AnchorSide[akRight].Control<>RightControl) then
|
||||||
|
continue; // not touching / not a corner
|
||||||
|
if not ControlIsValidAnchor(BottomControl,akBottom) then continue;
|
||||||
|
|
||||||
|
for LeftIndex:=0 to Candidates.Count-1 do begin
|
||||||
|
LeftControl:=TControl(Candidates[LeftIndex]);
|
||||||
|
if (BottomControl.AnchorSide[akLeft].Control<>LeftControl)
|
||||||
|
and (LeftControl.AnchorSide[akBottom].Control<>BottomControl) then
|
||||||
|
continue; // not touching / not a corner
|
||||||
|
if (TopControl.AnchorSide[akLeft].Control<>LeftControl)
|
||||||
|
and (LeftControl.AnchorSide[akTop].Control<>LeftControl) then
|
||||||
|
continue; // not touching / not a corner
|
||||||
|
if not ControlIsValidAnchor(LeftControl,akLeft) then continue;
|
||||||
|
|
||||||
|
// found a better rectangle
|
||||||
|
ARect[akLeft] :=LeftControl;
|
||||||
|
ARect[akRight] :=RightControl;
|
||||||
|
ARect[akTop] :=TopControl;
|
||||||
|
ARect[akBottom]:=BottomControl;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
finally
|
||||||
|
Candidates.Free;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
function GetEnclosedControls(const ARect: TAnchorControlsRect): TFPList;
|
||||||
|
{ return a list of all controls bounded by the anchors in ARect }
|
||||||
|
var
|
||||||
|
Parent: TWinControl;
|
||||||
|
|
||||||
|
procedure Fill(AControl: TControl);
|
||||||
|
var
|
||||||
|
a: TAnchorKind;
|
||||||
|
SideControl: TControl;
|
||||||
|
i: Integer;
|
||||||
|
begin
|
||||||
|
if AControl=nil then exit;
|
||||||
|
if AControl=Parent then exit;// do not add Parent
|
||||||
|
for a:=Low(TAnchorKind) to High(TAnchorKind) do
|
||||||
|
if ARect[a]=AControl then exit;// do not add boundary
|
||||||
|
|
||||||
|
if Result.IndexOf(AControl)>=0 then exit;// already added
|
||||||
|
Result.Add(AControl);
|
||||||
|
|
||||||
|
for a:=Low(TAnchorKind) to High(TAnchorKind) do
|
||||||
|
Fill(AControl.AnchorSide[a].Control);
|
||||||
|
for i:=0 to Parent.ControlCount-1 do begin
|
||||||
|
SideControl:=Parent.Controls[i];
|
||||||
|
for a:=Low(TAnchorKind) to High(TAnchorKind) do
|
||||||
|
if SideControl.AnchorSide[a].Control=AControl then
|
||||||
|
Fill(SideControl);
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
|
||||||
|
var
|
||||||
|
i: Integer;
|
||||||
|
AControl: TControl;
|
||||||
|
LeftTopControl: TControl;
|
||||||
|
begin
|
||||||
|
Result:=TFPList.Create;
|
||||||
|
|
||||||
|
// find the Parent
|
||||||
|
if (ARect[akLeft]=ARect[akRight]) and (ARect[akLeft] is TWinControl) then
|
||||||
|
Parent:=TWinControl(ARect[akLeft])
|
||||||
|
else
|
||||||
|
Parent:=ARect[akLeft].Parent;
|
||||||
|
|
||||||
|
// find the left, top most control
|
||||||
|
for i:=0 to Parent.ControlCount-1 do begin
|
||||||
|
AControl:=Parent.Controls[i];
|
||||||
|
if (AControl.AnchorSide[akLeft].Control=ARect[akLeft])
|
||||||
|
and (AControl.AnchorSide[akTop].Control=ARect[akTop]) then begin
|
||||||
|
LeftTopControl:=AControl;
|
||||||
|
break;
|
||||||
|
end;
|
||||||
|
end;
|
||||||
|
if Result.Count=0 then exit;
|
||||||
|
|
||||||
|
// use flood fill to find the rest
|
||||||
|
Fill(LeftTopControl);
|
||||||
|
end;
|
||||||
|
|
||||||
{ TAnchorDockMaster }
|
{ TAnchorDockMaster }
|
||||||
|
|
||||||
function TAnchorDockMaster.GetControls(Index: integer): TControl;
|
function TAnchorDockMaster.GetControls(Index: integer): TControl;
|
||||||
@ -3371,7 +3706,7 @@ constructor TAnchorDockCloseButton.Create(AOwner: TComponent);
|
|||||||
begin
|
begin
|
||||||
inherited Create(AOwner);
|
inherited Create(AOwner);
|
||||||
GetCloseGlyph;
|
GetCloseGlyph;
|
||||||
Glyph:=CloseBtnBitmap;
|
Glyph:=DockMaster.fCloseBtnBitmap;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
destructor TAnchorDockCloseButton.Destroy;
|
destructor TAnchorDockCloseButton.Destroy;
|
||||||
@ -3385,36 +3720,38 @@ var
|
|||||||
BitmapHandle,MaskHandle: HBITMAP;
|
BitmapHandle,MaskHandle: HBITMAP;
|
||||||
OrigBitmap: TBitmap;
|
OrigBitmap: TBitmap;
|
||||||
begin
|
begin
|
||||||
inc(CloseBtnReferenceCount);
|
inc(DockMaster.fCloseBtnReferenceCount);
|
||||||
if CloseBtnReferenceCount=1 then begin
|
if DockMaster.fCloseBtnReferenceCount=1 then begin
|
||||||
ThemeServices.GetStockImage(idButtonClose,BitmapHandle,MaskHandle);
|
ThemeServices.GetStockImage(idButtonClose,BitmapHandle,MaskHandle);
|
||||||
OrigBitmap:=TBitmap.Create;
|
OrigBitmap:=TBitmap.Create;
|
||||||
OrigBitmap.Handle:=BitmapHandle;
|
OrigBitmap.Handle:=BitmapHandle;
|
||||||
if MaskHandle<>0 then
|
if MaskHandle<>0 then
|
||||||
OrigBitmap.MaskHandle:=MaskHandle;
|
OrigBitmap.MaskHandle:=MaskHandle;
|
||||||
CloseBtnBitmap:=TBitmap.Create;
|
DockMaster.fCloseBtnBitmap:=TBitmap.Create;
|
||||||
CloseBtnBitmap.SetSize(12,12);
|
with DockMaster.fCloseBtnBitmap do begin
|
||||||
CloseBtnBitmap.Canvas.Brush.Color:=clWhite;
|
SetSize(12,12);
|
||||||
CloseBtnBitmap.Canvas.FillRect(Rect(0,0,CloseBtnBitmap.Width,CloseBtnBitmap.Height));
|
Canvas.Brush.Color:=clWhite;
|
||||||
CloseBtnBitmap.Canvas.StretchDraw(Rect(0,0,CloseBtnBitmap.Width,CloseBtnBitmap.Height),OrigBitmap);
|
Canvas.FillRect(Rect(0,0,Width,Height));
|
||||||
CloseBtnBitmap.Transparent:=true;
|
Canvas.StretchDraw(Rect(0,0,Width,Height),OrigBitmap);
|
||||||
CloseBtnBitmap.TransparentColor:=clWhite;
|
Transparent:=true;
|
||||||
|
TransparentColor:=clWhite;
|
||||||
|
end;
|
||||||
OrigBitmap.Free;
|
OrigBitmap.Free;
|
||||||
end;
|
end;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
procedure TAnchorDockCloseButton.ReleaseCloseGlyph;
|
procedure TAnchorDockCloseButton.ReleaseCloseGlyph;
|
||||||
begin
|
begin
|
||||||
dec(CloseBtnReferenceCount);
|
dec(DockMaster.fCloseBtnReferenceCount);
|
||||||
if CloseBtnReferenceCount=0 then
|
if DockMaster.fCloseBtnReferenceCount=0 then
|
||||||
FreeAndNil(CloseBtnBitmap);
|
FreeAndNil(DockMaster.fCloseBtnBitmap);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TAnchorDockCloseButton.GetGlyphSize(PaintRect: TRect): TSize;
|
function TAnchorDockCloseButton.GetGlyphSize(PaintRect: TRect): TSize;
|
||||||
begin
|
begin
|
||||||
if PaintRect.Left=0 then ;
|
if PaintRect.Left=0 then ;
|
||||||
Result.cx:=CloseBtnBitmap.Width;
|
Result.cx:=DockMaster.fCloseBtnBitmap.Width;
|
||||||
Result.cy:=CloseBtnBitmap.Height;
|
Result.cy:=DockMaster.fCloseBtnBitmap.Height;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
function TAnchorDockCloseButton.DrawGlyph(ACanvas: TCanvas;
|
function TAnchorDockCloseButton.DrawGlyph(ACanvas: TCanvas;
|
||||||
@ -3424,9 +3761,9 @@ begin
|
|||||||
if BiDiFlags=0 then ;
|
if BiDiFlags=0 then ;
|
||||||
if ATransparent then ;
|
if ATransparent then ;
|
||||||
if AState=bsDisabled then ;
|
if AState=bsDisabled then ;
|
||||||
Result:=Rect(0,0,CloseBtnBitmap.Width,CloseBtnBitmap.Height);
|
Result:=Rect(0,0,DockMaster.fCloseBtnBitmap.Width,DockMaster.fCloseBtnBitmap.Height);
|
||||||
OffsetRect(Result,AClient.Left+AOffset.X,AClient.Top+AOffset.Y);
|
OffsetRect(Result,AClient.Left+AOffset.X,AClient.Top+AOffset.Y);
|
||||||
ACanvas.Draw(Result.Left,Result.Top,CloseBtnBitmap);
|
ACanvas.Draw(Result.Left,Result.Top,DockMaster.fCloseBtnBitmap);
|
||||||
end;
|
end;
|
||||||
|
|
||||||
{ TAnchorDockManager }
|
{ TAnchorDockManager }
|
||||||
@ -3860,17 +4197,12 @@ end;
|
|||||||
procedure TAnchorDockPageControl.PopupMenuPopup(Sender: TObject);
|
procedure TAnchorDockPageControl.PopupMenuPopup(Sender: TObject);
|
||||||
var
|
var
|
||||||
ChangeLockItem: TMenuItem;
|
ChangeLockItem: TMenuItem;
|
||||||
ParentSite: TAnchorDockHostSite;
|
|
||||||
Side: TAnchorKind;
|
|
||||||
SideCaptions: array[TAnchorKind] of string;
|
|
||||||
ContainsMainForm: Boolean;
|
ContainsMainForm: Boolean;
|
||||||
s: String;
|
s: String;
|
||||||
|
TabPositionSection: TMenuItem;
|
||||||
|
Item: TMenuItem;
|
||||||
|
tp: TTabPosition;
|
||||||
begin
|
begin
|
||||||
ParentSite:=TAnchorDockHostSite(Parent);
|
|
||||||
SideCaptions[akLeft]:=adrsLeft;
|
|
||||||
SideCaptions[akTop]:=adrsTop;
|
|
||||||
SideCaptions[akRight]:=adrsRight;
|
|
||||||
SideCaptions[akBottom]:=adrsBottom;
|
|
||||||
PopupMenu.Items.Clear;
|
PopupMenu.Items.Clear;
|
||||||
|
|
||||||
// top popup menu item can be clicked by accident, so use something simple:
|
// top popup menu item can be clicked by accident, so use something simple:
|
||||||
@ -3880,6 +4212,7 @@ begin
|
|||||||
ChangeLockItem.Checked:=not DockMaster.AllowDragging;
|
ChangeLockItem.Checked:=not DockMaster.AllowDragging;
|
||||||
ChangeLockItem.ShowAlwaysCheckable:=true;
|
ChangeLockItem.ShowAlwaysCheckable:=true;
|
||||||
|
|
||||||
|
// movement
|
||||||
if PageIndex>0 then
|
if PageIndex>0 then
|
||||||
DockMaster.AddPopupMenuItem('MoveLeftMenuItem', adrsMovePageLeft,
|
DockMaster.AddPopupMenuItem('MoveLeftMenuItem', adrsMovePageLeft,
|
||||||
@MoveLeftButtonClick);
|
@MoveLeftButtonClick);
|
||||||
@ -3894,6 +4227,22 @@ begin
|
|||||||
DockMaster.AddPopupMenuItem('MoveRightMostMenuItem', adrsMovePageRightmost,
|
DockMaster.AddPopupMenuItem('MoveRightMostMenuItem', adrsMovePageRightmost,
|
||||||
@MoveRightMostButtonClick);
|
@MoveRightMostButtonClick);
|
||||||
|
|
||||||
|
// tab position
|
||||||
|
TabPositionSection:=DockMaster.AddPopupMenuItem('TabPositionMenuItem',
|
||||||
|
adrsTabPosition,nil);
|
||||||
|
for tp:=Low(TTabPosition) to high(TTabPosition) do begin
|
||||||
|
case tp of
|
||||||
|
tpTop: s:=adrsTop;
|
||||||
|
tpBottom: s:=adrsBottom;
|
||||||
|
tpLeft: s:=adrsLeft;
|
||||||
|
tpRight: s:=adrsRight;
|
||||||
|
end;
|
||||||
|
Item:=DockMaster.AddPopupMenuItem('TabPos'+ADLTabPostionNames[tp]+'MenuItem',
|
||||||
|
s,@TabPositionClick,TabPositionSection);
|
||||||
|
Item.ShowAlwaysCheckable:=true;
|
||||||
|
Item.Checked:=TabPosition=tp;
|
||||||
|
Item.Tag:=ord(tp);
|
||||||
|
end;
|
||||||
|
|
||||||
// close
|
// close
|
||||||
ContainsMainForm:=IsParentOf(Application.MainForm);
|
ContainsMainForm:=IsParentOf(Application.MainForm);
|
||||||
@ -3943,6 +4292,15 @@ begin
|
|||||||
Page[PageIndex].PageIndex:=PageCount-1;
|
Page[PageIndex].PageIndex:=PageCount-1;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TAnchorDockPageControl.TabPositionClick(Sender: TObject);
|
||||||
|
var
|
||||||
|
Item: TMenuItem;
|
||||||
|
begin
|
||||||
|
if not (Sender is TMenuItem) then exit;
|
||||||
|
Item:=TMenuItem(Sender);
|
||||||
|
TabPosition:=TTabPosition(Item.Tag);
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TAnchorDockPageControl.UpdateDockCaption(Exclude: TControl);
|
procedure TAnchorDockPageControl.UpdateDockCaption(Exclude: TControl);
|
||||||
begin
|
begin
|
||||||
if Exclude=nil then ;
|
if Exclude=nil then ;
|
||||||
|
@ -76,6 +76,7 @@ type
|
|||||||
FNodes: TFPList; // list of TAnchorDockLayoutTreeNode
|
FNodes: TFPList; // list of TAnchorDockLayoutTreeNode
|
||||||
FNodeType: TADLTreeNodeType;
|
FNodeType: TADLTreeNodeType;
|
||||||
FParent: TAnchorDockLayoutTreeNode;
|
FParent: TAnchorDockLayoutTreeNode;
|
||||||
|
FTabPosition: TTabPosition;
|
||||||
FWindowState: TWindowState;
|
FWindowState: TWindowState;
|
||||||
function GetAnchors(Site: TAnchorKind): string;
|
function GetAnchors(Site: TAnchorKind): string;
|
||||||
function GetBottom: integer;
|
function GetBottom: integer;
|
||||||
@ -97,6 +98,7 @@ type
|
|||||||
procedure SetNodeType(const AValue: TADLTreeNodeType);
|
procedure SetNodeType(const AValue: TADLTreeNodeType);
|
||||||
procedure SetParent(const AValue: TAnchorDockLayoutTreeNode);
|
procedure SetParent(const AValue: TAnchorDockLayoutTreeNode);
|
||||||
procedure SetRight(const AValue: integer);
|
procedure SetRight(const AValue: integer);
|
||||||
|
procedure SetTabPosition(const AValue: TTabPosition);
|
||||||
procedure SetTop(const AValue: integer);
|
procedure SetTop(const AValue: integer);
|
||||||
procedure SetWidth(const AValue: integer);
|
procedure SetWidth(const AValue: integer);
|
||||||
procedure SetWindowState(const AValue: TWindowState);
|
procedure SetWindowState(const AValue: TWindowState);
|
||||||
@ -140,6 +142,7 @@ type
|
|||||||
property WindowState: TWindowState read FWindowState write SetWindowState;
|
property WindowState: TWindowState read FWindowState write SetWindowState;
|
||||||
property Monitor: integer read FMonitor write SetMonitor;
|
property Monitor: integer read FMonitor write SetMonitor;
|
||||||
property HeaderPosition: TADLHeaderPosition read FHeaderPosition write SetHeaderPosition;
|
property HeaderPosition: TADLHeaderPosition read FHeaderPosition write SetHeaderPosition;
|
||||||
|
property TabPosition: TTabPosition read FTabPosition write SetTabPosition;
|
||||||
function Count: integer;
|
function Count: integer;
|
||||||
function IsSplitter: boolean;
|
function IsSplitter: boolean;
|
||||||
function IsRootWindow: boolean;
|
function IsRootWindow: boolean;
|
||||||
@ -219,6 +222,12 @@ const
|
|||||||
'right',
|
'right',
|
||||||
'bottom'
|
'bottom'
|
||||||
);
|
);
|
||||||
|
ADLTabPostionNames: array[TTabPosition] of string = (
|
||||||
|
'Top',
|
||||||
|
'Bottom',
|
||||||
|
'Left',
|
||||||
|
'Right'
|
||||||
|
);
|
||||||
ADLAlignNames: array[TAlign] of string = (
|
ADLAlignNames: array[TAlign] of string = (
|
||||||
'None',
|
'None',
|
||||||
'Top',
|
'Top',
|
||||||
@ -232,6 +241,7 @@ const
|
|||||||
function NameToADLTreeNodeType(s: string): TADLTreeNodeType;
|
function NameToADLTreeNodeType(s: string): TADLTreeNodeType;
|
||||||
function NameToADLWindowState(s: string): TWindowState;
|
function NameToADLWindowState(s: string): TWindowState;
|
||||||
function NameToADLHeaderPosition(s: string): TADLHeaderPosition;
|
function NameToADLHeaderPosition(s: string): TADLHeaderPosition;
|
||||||
|
function NameToADLTabPosition(s: string): TTabPosition;
|
||||||
function NameToADLAlign(s: string): TAlign;
|
function NameToADLAlign(s: string): TAlign;
|
||||||
function dbgs(const NodeType: TADLTreeNodeType): string; overload;
|
function dbgs(const NodeType: TADLTreeNodeType): string; overload;
|
||||||
|
|
||||||
@ -264,6 +274,13 @@ begin
|
|||||||
Result:=adlhpAuto;
|
Result:=adlhpAuto;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
function NameToADLTabPosition(s: string): TTabPosition;
|
||||||
|
begin
|
||||||
|
for Result:=low(TTabPosition) to high(TTabPosition) do
|
||||||
|
if s=ADLTabPostionNames[Result] then exit;
|
||||||
|
Result:=tpTop;
|
||||||
|
end;
|
||||||
|
|
||||||
function NameToADLAlign(s: string): TAlign;
|
function NameToADLAlign(s: string): TAlign;
|
||||||
begin
|
begin
|
||||||
for Result:=low(TAlign) to high(TAlign) do
|
for Result:=low(TAlign) to high(TAlign) do
|
||||||
@ -898,6 +915,13 @@ begin
|
|||||||
IncreaseChangeStamp;
|
IncreaseChangeStamp;
|
||||||
end;
|
end;
|
||||||
|
|
||||||
|
procedure TAnchorDockLayoutTreeNode.SetTabPosition(const AValue: TTabPosition);
|
||||||
|
begin
|
||||||
|
if FTabPosition=AValue then exit;
|
||||||
|
FTabPosition:=AValue;
|
||||||
|
IncreaseChangeStamp;
|
||||||
|
end;
|
||||||
|
|
||||||
procedure TAnchorDockLayoutTreeNode.SetTop(const AValue: integer);
|
procedure TAnchorDockLayoutTreeNode.SetTop(const AValue: integer);
|
||||||
begin
|
begin
|
||||||
if Top=AValue then exit;
|
if Top=AValue then exit;
|
||||||
@ -960,6 +984,7 @@ begin
|
|||||||
or (Align<>Node.Align)
|
or (Align<>Node.Align)
|
||||||
or (WindowState<>Node.WindowState)
|
or (WindowState<>Node.WindowState)
|
||||||
or (HeaderPosition<>Node.HeaderPosition)
|
or (HeaderPosition<>Node.HeaderPosition)
|
||||||
|
or (TabPosition<>Node.TabPosition)
|
||||||
then
|
then
|
||||||
exit;
|
exit;
|
||||||
for a:=low(TAnchorKind) to high(TAnchorKind) do
|
for a:=low(TAnchorKind) to high(TAnchorKind) do
|
||||||
@ -981,6 +1006,7 @@ begin
|
|||||||
Align:=Node.Align;
|
Align:=Node.Align;
|
||||||
WindowState:=Node.WindowState;
|
WindowState:=Node.WindowState;
|
||||||
HeaderPosition:=Node.HeaderPosition;
|
HeaderPosition:=Node.HeaderPosition;
|
||||||
|
TabPosition:=Node.TabPosition;
|
||||||
for a:=low(TAnchorKind) to high(TAnchorKind) do
|
for a:=low(TAnchorKind) to high(TAnchorKind) do
|
||||||
Anchors[a]:=Node.Anchors[a];
|
Anchors[a]:=Node.Anchors[a];
|
||||||
while Count>Node.Count do Nodes[Count-1].Free;
|
while Count>Node.Count do Nodes[Count-1].Free;
|
||||||
@ -1008,6 +1034,10 @@ begin
|
|||||||
Monitor:=TCustomForm(AControl).Monitor.MonitorNum;
|
Monitor:=TCustomForm(AControl).Monitor.MonitorNum;
|
||||||
end else
|
end else
|
||||||
WindowState:=wsNormal;
|
WindowState:=wsNormal;
|
||||||
|
if AControl is TCustomNotebook then
|
||||||
|
TabPosition:=TCustomNotebook(AControl).TabPosition
|
||||||
|
else
|
||||||
|
TabPosition:=tpTop;
|
||||||
for a:=low(TAnchorKind) to high(TAnchorKind) do begin
|
for a:=low(TAnchorKind) to high(TAnchorKind) do begin
|
||||||
AnchorControl:=AControl.AnchorSide[a].Control;
|
AnchorControl:=AControl.AnchorSide[a].Control;
|
||||||
if (AnchorControl=nil) or (AnchorControl=AControl.Parent) then
|
if (AnchorControl=nil) or (AnchorControl=AControl.Parent) then
|
||||||
@ -1037,6 +1067,7 @@ begin
|
|||||||
Align:=NameToADLAlign(Config.GetValue('Anchors/Align',AlignNames[alNone]));
|
Align:=NameToADLAlign(Config.GetValue('Anchors/Align',AlignNames[alNone]));
|
||||||
WindowState:=NameToADLWindowState(Config.GetValue('WindowState',ADLWindowStateNames[wsNormal]));
|
WindowState:=NameToADLWindowState(Config.GetValue('WindowState',ADLWindowStateNames[wsNormal]));
|
||||||
HeaderPosition:=NameToADLHeaderPosition(Config.GetValue('Header/Position',ADLHeaderPositionNames[adlhpAuto]));
|
HeaderPosition:=NameToADLHeaderPosition(Config.GetValue('Header/Position',ADLHeaderPositionNames[adlhpAuto]));
|
||||||
|
TabPosition:=NameToADLTabPosition(Config.GetValue('Header/TabPosition',ADLTabPostionNames[tpTop]));
|
||||||
Monitor:=Config.GetValue('Monitor',0);
|
Monitor:=Config.GetValue('Monitor',0);
|
||||||
NewCount:=Config.GetValue('ChildCount',0);
|
NewCount:=Config.GetValue('ChildCount',0);
|
||||||
for i:=1 to NewCount do begin
|
for i:=1 to NewCount do begin
|
||||||
@ -1067,7 +1098,9 @@ begin
|
|||||||
Config.SetDeleteValue('WindowState',ADLWindowStateNames[WindowState],
|
Config.SetDeleteValue('WindowState',ADLWindowStateNames[WindowState],
|
||||||
ADLWindowStateNames[wsNormal]);
|
ADLWindowStateNames[wsNormal]);
|
||||||
Config.SetDeleteValue('Header/Position',ADLHeaderPositionNames[HeaderPosition],
|
Config.SetDeleteValue('Header/Position',ADLHeaderPositionNames[HeaderPosition],
|
||||||
ADLHeaderPositionNames[adlhpAuto]);
|
ADLHeaderPositionNames[adlhpAuto]);
|
||||||
|
Config.SetDeleteValue('Header/TabPosition',ADLTabPostionNames[TabPosition],
|
||||||
|
ADLTabPostionNames[tpTop]);
|
||||||
Config.SetDeleteValue('Monitor',Monitor,0);
|
Config.SetDeleteValue('Monitor',Monitor,0);
|
||||||
Config.SetDeleteValue('ChildCount',Count,0);
|
Config.SetDeleteValue('ChildCount',Count,0);
|
||||||
for i:=1 to Count do begin
|
for i:=1 to Count do begin
|
||||||
|
@ -36,6 +36,7 @@ interface
|
|||||||
resourcestring
|
resourcestring
|
||||||
adrsClose = 'Close';
|
adrsClose = 'Close';
|
||||||
adrsQuit = 'Quit %s';
|
adrsQuit = 'Quit %s';
|
||||||
|
adrsTabPosition = 'Tab position';
|
||||||
adrsMovePageRight = 'Move page right';
|
adrsMovePageRight = 'Move page right';
|
||||||
adrsMovePageRightmost = 'Move page rightmost';
|
adrsMovePageRightmost = 'Move page rightmost';
|
||||||
adrsUndock = 'Undock';
|
adrsUndock = 'Undock';
|
||||||
|
Loading…
Reference in New Issue
Block a user