- workaround fpc linker bug (in ldockctrl)
- move things related to header drawing to separate class TDockHeader
- use 'Control.Dock' instead of 'Control.Parent :=' in anchor-docking (now anchordocking demo looks much better under win32)

git-svn-id: trunk@14025 -
This commit is contained in:
paul 2008-02-08 02:51:59 +00:00
parent 0bd4b1c1ab
commit 0230315a7c
2 changed files with 225 additions and 227 deletions

View File

@ -2742,8 +2742,7 @@ var
Result:=Check(Root); Result:=Check(Root);
end; end;
function FindNearestControlNode: TLazDockConfigNode; // FPC bug: when this function is internal of FindNearestControlNode then get win32 linker error
function FindOwnSplitterSiblingWithControl(Node: TLazDockConfigNode function FindOwnSplitterSiblingWithControl(Node: TLazDockConfigNode
): TLazDockConfigNode; ): TLazDockConfigNode;
{ find a sibling, that is a direct neighbour behind a splitter, and the { find a sibling, that is a direct neighbour behind a splitter, and the
@ -2771,6 +2770,8 @@ var
Result:=nil; Result:=nil;
end; end;
function FindNearestControlNode: TLazDockConfigNode;
function FindSiblingWithControl(Node: TLazDockConfigNode function FindSiblingWithControl(Node: TLazDockConfigNode
): TLazDockConfigNode; ): TLazDockConfigNode;
var var

View File

@ -88,6 +88,13 @@ type
property AutoFreeDockSite: boolean read FAutoFreeDockSite write FAutoFreeDockSite; property AutoFreeDockSite: boolean read FAutoFreeDockSite write FAutoFreeDockSite;
end; end;
TLazDockHeaderPart =
(
ldhpAll, // total header rect
ldhpCaption, // header caption
ldhpRestoreButton, // header restore button
ldhpCloseButton // header close button
);
{ TLazDockForm { TLazDockForm
The default DockSite for a TLazDockTree The default DockSite for a TLazDockTree
@ -104,13 +111,6 @@ type
Child control is a TLazDockPages Child control is a TLazDockPages
} }
TLazDockHeaderPart = (
ldhpAll,
ldhpCaption,
ldhpRestoreButton,
ldhpCloseButton
);
TLazDockForm = class(TCustomForm) TLazDockForm = class(TCustomForm)
private private
FDockZone: TDockZone; FDockZone: TDockZone;
@ -128,7 +128,8 @@ type
function FindHeader(x, y: integer; out Part: TLazDockHeaderPart): TControl; function FindHeader(x, y: integer; out Part: TLazDockHeaderPart): TControl;
function IsDockedControl(Control: TControl): boolean; function IsDockedControl(Control: TControl): boolean;
function ControlHasTitle(Control: TControl): boolean; function ControlHasTitle(Control: TControl): boolean;
procedure GetTitleRect(Control: TControl; Part: TLazDockHeaderPart; out ARect: TRect); function GetTitleRect(Control: TControl): TRect;
function GetTitleOrientation(Control: TControl): TDockOrientation;
property DockZone: TDockZone read FDockZone; property DockZone: TDockZone read FDockZone;
property PageControl: TLazDockPages read FPageControl; property PageControl: TLazDockPages read FPageControl;
property MainControl: TControl read FMainControl write SetMainControl; property MainControl: TControl read FMainControl write SetMainControl;
@ -228,7 +229,8 @@ type
const const
DockAlignOrientations: array[TAlign] of TDockOrientation = ( DockAlignOrientations: array[TAlign] of TDockOrientation =
(
doPages, //alNone, doPages, //alNone,
doVertical, //alTop, doVertical, //alTop,
doVertical, //alBottom, doVertical, //alBottom,
@ -260,6 +262,124 @@ function GetEnclosedControls(const ARect: TAnchorControlsRect): TFPList;
implementation implementation
type
{ TDockHeader }
// maybe once it will be control, so now better to move all related to header things to class
TDockHeader = class
class function GetRectOfPart(AHeaderRect: TRect; AOrientation: TDockOrientation; APart: TLazDockHeaderPart): TRect;
class procedure Draw(ACanvas: TCanvas; ACaption: String; AOrientation: TDockOrientation; const ARect: TRect);
end;
class function TDockHeader.GetRectOfPart(AHeaderRect: TRect; AOrientation: TDockOrientation;
APart: TLazDockHeaderPart): TRect;
var
d: Integer;
begin
Result := AHeaderRect;
if APart = ldhpAll then
Exit;
InflateRect(Result, -2, -2);
case AOrientation of
doHorizontal:
begin
d := Result.Bottom - Result.Top;
if APart = ldhpCloseButton then
begin
Result.Left := Max(Result.Left, Result.Right - d);
Exit;
end;
Result.Right := Max(Result.Left, Result.Right - d - 1);
if APart = ldhpRestoreButton then
begin
Result.Left := Max(Result.Left, Result.Right - d);
Exit;
end;
Result.Right := Max(Result.Left, Result.Right - d - 1);
InflateRect(Result, -4, 0);
end;
doVertical:
begin
d := Result.Right - Result.Left;
if APart = ldhpCloseButton then
begin
Result.Bottom := Min(Result.Bottom, Result.Top + d);
Exit;
end;
Result.Top := Min(Result.Bottom, Result.Top + d + 1);
if APart = ldhpRestoreButton then
begin
Result.Bottom := Min(Result.Bottom, Result.Top + d);
Exit;
end;
Result.Top := Min(Result.Bottom, Result.Top + d + 1);
InflateRect(Result, 0, -4);
end;
end;
end;
class procedure TDockHeader.Draw(ACanvas: TCanvas; ACaption: String; AOrientation: TDockOrientation; const ARect: TRect);
var
Details: TThemedElementDetails;
BtnRect: TRect;
DrawRect: TRect;
TextStyle: TTextStyle;
// LCL dont handle orientation in TFont
OldFont, RotatedFont: HFONT;
ALogFont: TLogFont;
begin
TextStyle.Alignment := taLeftJustify;
TextStyle.SingleLine := True;
TextStyle.Clipping := False;
TextStyle.Opaque := False;
TextStyle.Wordbreak := False;
TextStyle.SystemFont := False;
TextStyle.RightToLeft := False;
DrawRect := ARect;
InflateRect(DrawRect, -1, -1);
ACanvas.Brush.Color := clBtnShadow;
ACanvas.FrameRect(DrawRect);
InflateRect(DrawRect, -1, -1);
// draw close button
BtnRect := GetRectOfPart(ARect, AOrientation, ldhpCloseButton);
Details := ThemeServices.GetElementDetails(twMDICloseButtonNormal);
ThemeServices.DrawElement(ACanvas.Handle, Details, BtnRect);
// draw restore button
BtnRect := GetRectOfPart(ARect, AOrientation, ldhpRestoreButton);
Details := ThemeServices.GetElementDetails(twMDIRestoreButtonNormal);
ThemeServices.DrawElement(ACanvas.Handle, Details, BtnRect);
// draw caption
DrawRect := GetRectOfPart(ARect, AOrientation, ldhpCaption);
case AOrientation of
doHorizontal:
begin
TextStyle.Layout := tlCenter;
ACanvas.TextRect(DrawRect, DrawRect.Left, DrawRect.Top, ACaption, TextStyle);
end;
doVertical:
begin
TextStyle.Layout := tlBottom;
OldFont := 0;
if GetObject(ACanvas.Font.Reference.Handle, SizeOf(ALogFont), @ALogFont) <> 0 then
begin
ALogFont.lfEscapement := 900;
RotatedFont := CreateFontIndirect(ALogFont);
if RotatedFont <> 0 then
OldFont := SelectObject(ACanvas.Handle, RotatedFont);
end;
ACanvas.TextRect(DrawRect, DrawRect.Left, DrawRect.Bottom, ACaption, TextStyle);
if OldFont <> 0 then
DeleteObject(SelectObject(ACanvas.Handle, OldFont));
end;
end;
end;
function GetLazDockSplitter(Control: TControl; Side: TAnchorKind; out function GetLazDockSplitter(Control: TControl; Side: TAnchorKind; out
Splitter: TLazDockSplitter): boolean; Splitter: TLazDockSplitter): boolean;
@ -654,87 +774,9 @@ begin
BreakAnchors(Zone.NextSibling); BreakAnchors(Zone.NextSibling);
end; end;
procedure TLazDockTree.PaintDockFrame(ACanvas: TCanvas; AControl: TControl; procedure TLazDockTree.PaintDockFrame(ACanvas: TCanvas; AControl: TControl; const ARect: TRect);
const ARect: TRect);
var
Details: TThemedElementDetails;
BtnRect: TRect;
DrawRect: TRect;
d: integer;
DockCaption: String;
TextStyle: TTextStyle;
// LCL dont handle orientation in TFont
OldFont, RotatedFont: HFONT;
ALogFont: TLogFont;
begin begin
DockCaption := DockSite.GetDockCaption(AControl); TDockHeader.Draw(ACanvas, DockSite.GetDockCaption(AControl), AControl.DockOrientation, ARect);
TextStyle.Alignment := taLeftJustify;
TextStyle.SingleLine := True;
TextStyle.Clipping := False;
TextStyle.Opaque := False;
TextStyle.Wordbreak := False;
TextStyle.SystemFont := False;
TextStyle.RightToLeft := AControl.UseRightToLeftAlignment;
DrawRect := ARect;
InflateRect(DrawRect, -1, -1);
ACanvas.Brush.Color := clBtnShadow;
ACanvas.FrameRect(DrawRect);
InflateRect(DrawRect, -1, -1);
case AControl.DockOrientation of
doHorizontal:
begin
TextStyle.Layout := tlCenter;
d := DrawRect.Bottom - DrawRect.Top;
BtnRect := DrawRect;
BtnRect.Left := BtnRect.Right - d;
Details := ThemeServices.GetElementDetails(twMDICloseButtonNormal);
ThemeServices.DrawElement(ACanvas.Handle, Details, BtnRect);
DrawRect.Right := BtnRect.Left;
BtnRect := DrawRect;
Dec(BtnRect.Right);
BtnRect.Left := BtnRect.Right - d;
Details := ThemeServices.GetElementDetails(twMDIRestoreButtonNormal);
ThemeServices.DrawElement(ACanvas.Handle, Details, BtnRect);
DrawRect.Right := BtnRect.Left;
InflateRect(DrawRect, -4, 0);
ACanvas.TextRect(DrawRect, DrawRect.Left, DrawRect.Top, DockCaption, TextStyle);
end;
doVertical:
begin
TextStyle.Layout := tlBottom;
d := DrawRect.Right - DrawRect.Left;
BtnRect := DrawRect;
BtnRect.Bottom := BtnRect.Top + d;
Details := ThemeServices.GetElementDetails(twMDICloseButtonNormal);
ThemeServices.DrawElement(ACanvas.Handle, Details, BtnRect);
DrawRect.Top := BtnRect.Bottom;
BtnRect := DrawRect;
Inc(BtnRect.Top);
BtnRect.Bottom := BtnRect.Top + d;
Details := ThemeServices.GetElementDetails(twMDIRestoreButtonNormal);
ThemeServices.DrawElement(ACanvas.Handle, Details, BtnRect);
DrawRect.Top := BtnRect.Bottom;
InflateRect(DrawRect, 0, -4);
OldFont := 0;
if GetObject(ACanvas.Font.Reference.Handle, SizeOf(ALogFont), @ALogFont) <> 0 then
begin
ALogFont.lfEscapement := 900;
RotatedFont := CreateFontIndirect(ALogFont);
if RotatedFont <> 0 then
OldFont := SelectObject(ACanvas.Handle, RotatedFont);
end;
ACanvas.TextRect(DrawRect, DrawRect.Left, DrawRect.Bottom, DockCaption, TextStyle);
if OldFont <> 0 then
DeleteObject(SelectObject(ACanvas.Handle, OldFont));
end;
end;
end; end;
procedure TLazDockTree.CreateDockLayoutHelperControls(Zone: TLazDockZone); procedure TLazDockTree.CreateDockLayoutHelperControls(Zone: TLazDockZone);
@ -1739,7 +1781,7 @@ begin
Control.AnchorSide[akRight].Assign(DropCtl.AnchorSide[akRight]); Control.AnchorSide[akRight].Assign(DropCtl.AnchorSide[akRight]);
end; end;
Control.Anchors:=[akLeft,akTop,akRight,akBottom]; Control.Anchors:=[akLeft,akTop,akRight,akBottom];
Control.Parent:=DropCtl.Parent; Control.Dock(DropCtl.Parent, Rect(0, 0, 0, 0));
Control.Visible:=true; Control.Visible:=true;
// position DropCtl // position DropCtl
@ -1796,9 +1838,12 @@ begin
DebugLn(['TCustomAnchoredDockManager.DockControl NewPage=',NewPage.Caption,' Control=',Control.Caption,',',DbgSName(Control)]); DebugLn(['TCustomAnchoredDockManager.DockControl NewPage=',NewPage.Caption,' Control=',Control.Caption,',',DbgSName(Control)]);
NewPage.DisableAlign; NewPage.DisableAlign;
try try
Control.Parent:=NewPage; if DropCtl is TCustomForm then
if Control is TCustomForm then begin
TCustomForm(Control).WindowState:=wsNormal; TCustomForm(DropCtl).WindowState:=wsNormal;
TCustomForm(DropCtl).BorderStyle:=bsNone;
end;
Control.Dock(NewPage, Rect(0, 0, 0, 0));
Control.AnchorClient(0); Control.AnchorClient(0);
finally finally
NewPage.EnableAlign; NewPage.EnableAlign;
@ -2422,11 +2467,6 @@ end;
procedure TLazDockForm.PaintWindow(DC: HDC); procedure TLazDockForm.PaintWindow(DC: HDC);
var var
Details: TThemedElementDetails;
BtnRect: TRect;
DrawRect: TRect;
DockCaption: String;
TextStyle: TTextStyle;
i: Integer; i: Integer;
Control: TControl; Control: TControl;
ACanvas: TCanvas; ACanvas: TCanvas;
@ -2434,49 +2474,18 @@ begin
inherited PaintWindow(DC); inherited PaintWindow(DC);
ACanvas:=nil; ACanvas:=nil;
try try
for i:=0 to ControlCount-1 do begin for i := 0 to ControlCount-1 do
Control:=Controls[i]; begin
if not ControlHasTitle(Control) then continue; Control := Controls[i];
if not ControlHasTitle(Control) then
continue;
if ACanvas=nil then begin if ACanvas = nil then
ACanvas:=TCanvas.Create; begin
ACanvas.Handle:=DC; ACanvas := TCanvas.Create;
end; ACanvas.Handle := DC;
DockCaption := Control.Caption;
TextStyle.Alignment := taLeftJustify;
TextStyle.Layout := tlCenter;
TextStyle.SingleLine := True;
TextStyle.Clipping := True;
TextStyle.Opaque := False;
TextStyle.Wordbreak := False;
TextStyle.SystemFont := False;
TextStyle.RightToLeft := Control.UseRightToLeftAlignment;
// draw frame
GetTitleRect(Control,ldhpAll,DrawRect);
InflateRect(DrawRect, -1, -1);
ACanvas.Brush.Color := clBtnShadow;
ACanvas.FrameRect(DrawRect);
// draw close button
GetTitleRect(Control,ldhpCloseButton,BtnRect);
Details := ThemeServices.GetElementDetails(twMDICloseButtonNormal);
ThemeServices.DrawElement(ACanvas.Handle, Details, BtnRect);
// draw restore button
GetTitleRect(Control,ldhpRestoreButton,BtnRect);
Details := ThemeServices.GetElementDetails(twMDIRestoreButtonNormal);
ThemeServices.DrawElement(ACanvas.Handle, Details, BtnRect);
// draw caption
GetTitleRect(Control,ldhpCaption,DrawRect);
if Control.BorderSpacing.Top>0 then begin
ACanvas.TextRect(DrawRect, DrawRect.Left, DrawRect.Top,
DockCaption, TextStyle);
end else begin
ACanvas.TextRect(DrawRect, DrawRect.Left, DrawRect.Bottom,
DockCaption, TextStyle);
end; end;
TDockHeader.Draw(ACanvas, Control.Caption, GetTitleOrientation(Control), GetTitleRect(Control));
end; end;
finally finally
ACanvas.Free; ACanvas.Free;
@ -2590,36 +2599,43 @@ begin
FindCandidate(Self,0); FindCandidate(Self,0);
end; end;
function TLazDockForm.FindHeader(x, y: integer; out Part: TLazDockHeaderPart function TLazDockForm.FindHeader(x, y: integer; out Part: TLazDockHeaderPart): TControl;
): TControl;
var var
i: Integer; i: Integer;
Control: TControl; Control: TControl;
TitleRect: TRect; TitleRect, SubRect: TRect;
p: TPoint; p: TPoint;
CurPart: TLazDockHeaderPart; CurPart: TLazDockHeaderPart;
Orientation: TDockOrientation;
begin begin
for i:=0 to ControlCount-1 do begin for i := 0 to ControlCount-1 do
Control:=Controls[i]; begin
if not ControlHasTitle(Control) then continue; Control := Controls[i];
GetTitleRect(Control,ldhpAll,TitleRect); if not ControlHasTitle(Control) then
p:=Point(X,Y); Continue;
if not PtInRect(TitleRect,p) then continue; TitleRect := GetTitleRect(Control);
p := Point(X,Y);
if not PtInRect(TitleRect, p) then
Continue;
// on header // on header
// => check sub parts // => check sub parts
Result:=Control; Result := Control;
for CurPart:=low(TLazDockHeaderPart) to high(TLazDockHeaderPart) do begin Orientation := GetTitleOrientation(Control);
if CurPart=ldhpAll then continue; for CurPart := low(TLazDockHeaderPart) to high(TLazDockHeaderPart) do
GetTitleRect(Control,CurPart,TitleRect); begin
if PtInRect(TitleRect,p) then begin if CurPart = ldhpAll then
Part:=CurPart; Continue;
exit; SubRect := TDockHeader.GetRectOfPart(TitleRect, Orientation, CurPart);
if PtInRect(SubRect, p) then
begin
Part := CurPart;
Exit;
end; end;
end; end;
Part:=ldhpAll; Part := ldhpAll;
exit; Exit;
end; end;
Result:=nil; Result := nil;
end; end;
function TLazDockForm.IsDockedControl(Control: TControl): boolean; function TLazDockForm.IsDockedControl(Control: TControl): boolean;
@ -2648,50 +2664,31 @@ begin
and ((Control.BorderSpacing.Left>0) or (Control.BorderSpacing.Top>0)); and ((Control.BorderSpacing.Left>0) or (Control.BorderSpacing.Top>0));
end; end;
procedure TLazDockForm.GetTitleRect(Control: TControl; Part: TLazDockHeaderPart; function TLazDockForm.GetTitleRect(Control: TControl): TRect;
out ARect: TRect);
var
d: Integer;
begin begin
ARect := Control.BoundsRect; Result := Control.BoundsRect;
if Control.BorderSpacing.Top>0 then begin if Control.BorderSpacing.Top > 0 then
ARect.Top:=Control.Top-Control.BorderSpacing.Top; begin
ARect.Bottom:=Control.Top; Result.Top := Control.Top - Control.BorderSpacing.Top;
end else begin Result.Bottom := Control.Top;
ARect.Left:=Control.Left-Control.BorderSpacing.Left; end else
ARect.Right:=Control.Left; begin
end; Result.Left := Control.Left - Control.BorderSpacing.Left;
if Part=ldhpAll then exit; Result.Right := Control.Left;
InflateRect(ARect, -2, -2);
if Control.BorderSpacing.Top>0 then begin
d:=ARect.Bottom-ARect.Top;
if Part=ldhpCloseButton then begin
ARect.Left:=Max(ARect.Left,ARect.Right-d);
exit;
end;
ARect.Right:=Max(ARect.Left,ARect.Right-d-1);
if Part=ldhpRestoreButton then begin
ARect.Left:=Max(ARect.Left,ARect.Right-d);
exit;
end;
ARect.Right:=Max(ARect.Left,ARect.Right-d-1);
InflateRect(ARect, -4, 0);
end else begin
d:=ARect.Right-ARect.Left;
if Part=ldhpCloseButton then begin
ARect.Bottom:=Min(ARect.Bottom,ARect.Top+d);
exit;
end;
ARect.Top:=Min(ARect.Bottom,ARect.Top+d+1);
if Part=ldhpRestoreButton then begin
ARect.Bottom:=Min(ARect.Bottom,ARect.Top+d);
exit;
end;
ARect.Top:=Min(ARect.Bottom,ARect.Top+d+1);
InflateRect(ARect, 0, -4);
end; end;
end; end;
function TLazDockForm.GetTitleOrientation(Control: TControl): TDockOrientation;
begin
if Control.BorderSpacing.Top > 0 then
Result := doHorizontal
else
if Control.BorderSpacing.Left > 0 then
Result := doVertical
else
Result := doNoOrient;
end;
initialization initialization
DefaultDockTreeClass := TLazDockTree; DefaultDockTreeClass := TLazDockTree;