TCustomForm: rewrite MoveToDefaultPosition and fix regression after 5d1e0bb8e9

This commit is contained in:
Ondrej Pokorny 2021-11-19 08:31:09 +01:00
parent c187dc8f26
commit cbafa07331

View File

@ -1217,59 +1217,13 @@ begin
end; end;
procedure TCustomForm.MoveToDefaultPosition; procedure TCustomForm.MoveToDefaultPosition;
var
RealWidth, RealHeight: Integer;
procedure MoveToDefaultMonitor(var X, Y: Integer);
var
Source, Target: TMonitor;
ABounds: TRect;
begin
// delphi compatibility: if no main form then DefaultMonitor has no effect
if Application.MainForm = nil then Exit;
// find the monitor of the center of the form (the boundaries might be on another monitor)
Source := Screen.MonitorFromRect(Rect(X,Y,X+RealWidth,Y+RealHeight));
case DefaultMonitor of
dmDesktop:
Target := Source; // no need to move
dmPrimary:
Target := Screen.PrimaryMonitor;
dmMainForm:
Target := Application.MainForm.Monitor;
dmActiveForm:
if Screen.ActiveCustomForm <> nil then
Target := Screen.ActiveCustomForm.Monitor
else
Target := Source;
end;
if Source = Target then Exit; // no move
if Position in [poMainFormCenter, poOwnerFormCenter] then
begin
ABounds := Target.BoundsRect;
// shift X and Y from Source to Target monitor
X := (X - Source.Left) + ABounds.Left;
Y := (Y - Source.Top) + ABounds.Top;
// check that we are still in the desired monitor
X:= Max(ABounds.Left, Min(ABounds.Right-RealWidth, X));
Y:= Max(ABounds.Top, Min(ABounds.Bottom-RealHeight, Y));
end
else // poWorkAreaCenter, poScreenCenter
begin
if Position = poWorkAreaCenter then
ABounds := Target.WorkareaRect
else
ABounds := Target.BoundsRect;
X := (ABounds.Left + ABounds.Right - RealWidth) div 2;
Y := (ABounds.Top + ABounds.Bottom - RealHeight) div 2;
end;
end;
var var
X, Y: integer; X, Y: integer;
p: TPosition; p: TPosition;
AForm: TCustomForm; BuddyForm: TCustomForm;
RealRect, AFormRealRect: TRect; RealRect, CenterToRect, MonitorRect: TRect;
AFormRealWidth, AFormRealHeight: Integer; m: TMonitor;
CheckWorkArea: Boolean;
begin begin
if (Parent <> nil) or (ParentWindow <> 0) then exit; if (Parent <> nil) or (ParentWindow <> 0) then exit;
@ -1278,73 +1232,104 @@ begin
// first make sure X and Y are assigned // first make sure X and Y are assigned
X := Left; X := Left;
Y := Top; Y := Top;
if HandleAllocated and (GetWindowRect(Handle, RealRect) <> 0) then if not (HandleAllocated and (GetWindowRect(Handle, RealRect) <> 0)) then
begin // success RealRect := BoundsRect;
RealWidth := RealRect.Right-RealRect.Left;
RealHeight := RealRect.Bottom-RealRect.Top; // process DefaultMonitor
end else case DefaultMonitor of
begin // error dmDesktop: m := nil; // no need to move
RealWidth := Width; dmPrimary: m := Screen.PrimaryMonitor;
RealHeight := Height; dmMainForm:
if Application.MainForm <> nil then
m := Application.MainForm.Monitor
else
m := nil;
dmActiveForm:
if Screen.ActiveCustomForm <> nil then
m := Screen.ActiveCustomForm.Monitor
else
m := nil;
end; end;
p := Position; p := Position;
if (Position = poMainFormCenter) and (Application.Mainform=nil) then BuddyForm := nil;
p := poScreenCenter; if p = poOwnerFormCenter then
case P of
poDesktopCenter:
begin begin
X := Screen.DesktopLeft + (Screen.DesktopWidth - RealWidth) div 2; if Owner is TCustomForm then
Y := Screen.DesktopTop +(Screen.DesktopHeight - RealHeight) div 2; BuddyForm := TCustomForm(Owner)
end;
poScreenCenter:
begin
X := (Screen.Width - RealWidth) div 2;
Y := (Screen.Height - RealHeight) div 2;
end;
poWorkAreaCenter:
begin
X := Screen.WorkAreaLeft + (Screen.WorkAreaWidth - RealWidth) div 2;
Y := Screen.WorkAreaTop + (Screen.WorkAreaHeight - RealHeight) div 2;
end;
poMainFormCenter,
poOwnerFormCenter:
begin
if (P = poOwnerFormCenter) and (Owner is TCustomForm) then
AForm := TCustomForm(Owner)
else else
AForm := Application.MainForm; p := poMainFormCenter;
if (Self <> AForm) and Assigned(AForm) then end;
if p = poMainFormCenter then
begin begin
if Assigned(Application.MainForm) then
BuddyForm := Application.MainForm
else
p := poScreenCenter;
end;
case Position of
poScreenCenter..poWorkAreaCenter:
begin
CheckWorkArea := True;
// decide about the rect to center to
CenterToRect := Screen.PrimaryMonitor.BoundsRect; // center by default to primary monitor
case p of
poScreenCenter:
if Screen.MonitorCount=1 then
CenterToRect := Rect(0, 0, Screen.Width, Screen.Height)
else
if Assigned(m) then
CenterToRect := m.BoundsRect;
poDesktopCenter:
if Screen.MonitorCount=1 then
CenterToRect := Screen.DesktopRect
else
if Assigned(m) then
CenterToRect := m.BoundsRect;
poWorkAreaCenter:
if Assigned(m) then // WorkArea is always on one monitor - there is no workarea for the whole screen (Screen.WorkAreaRect=PrimaryMonitor.WorkAreaRect)
CenterToRect := m.WorkareaRect
else
CenterToRect := Screen.PrimaryMonitor.WorkareaRect;
poMainFormCenter, poOwnerFormCenter:
begin
if Assigned(m) and (m<>BuddyForm.Monitor) then // DefaultMonitor has precendence before Position
CenterToRect := m.BoundsRect
else
if FormStyle = fsMDIChild then if FormStyle = fsMDIChild then
begin begin
X := (AForm.ClientWidth - RealWidth) div 2; CenterToRect := BuddyForm.ClientRect;
Y := (AForm.ClientHeight - RealHeight) div 2; CheckWorkArea := False;
end else end else
if not (BuddyForm.HandleAllocated and (GetWindowRect(BuddyForm.Handle, CenterToRect) <> 0)) then
CenterToRect := Screen.PrimaryMonitor.BoundsRect; // CenterToRect may be zeroed, need to reassign to default value
end;
poDesigned..poDefaultSizeOnly: ;
end;
// center the form
X := CenterToRect.Left + (CenterToRect.Width - RealRect.Width) div 2;
Y := CenterToRect.Top + (CenterToRect.Height - RealRect.Height) div 2;
if CheckWorkArea then
begin begin
if AForm.HandleAllocated and (GetWindowRect(AForm.Handle, AFormRealRect) <> 0) then if not Assigned(m) then
begin // success m := Screen.MonitorFromPoint(Point(X+RealRect.Width div 2, Y+RealRect.Height div 2));
AFormRealWidth := AFormRealRect.Right-AFormRealRect.Left; if Assigned(m) then
AFormRealHeight := AFormRealRect.Bottom-AFormRealRect.Top; MonitorRect := m.WorkareaRect
end else else
begin // error MonitorRect := Screen.WorkAreaRect;
AFormRealWidth := AForm.Width;
AFormRealHeight := AForm.Height; X:= Max(MonitorRect.Left, Min(MonitorRect.Right-RealRect.Width, X));
end; Y:= Max(MonitorRect.Top, Min(MonitorRect.Bottom-RealRect.Height, Y));
X := ((AFormRealWidth - RealWidth) div 2) + AForm.Left;
Y := ((AFormRealHeight - RealHeight) div 2) + AForm.Top;
end; end;
end; end;
// check that we are still in the viewarea poDefault, poDefaultPosOnly:
X:= Max(Screen.WorkAreaLeft, Min((Screen.WorkAreaLeft+Screen.WorkAreaWidth)-RealWidth, X)); if HandleAllocated then // get current widgetset position
Y:= Max(Screen.WorkAreaTop, Min((Screen.WorkAreaTop+Screen.WorkAreaHeight)-RealHeight, Y));
end;
end;
// get current widgetset position
if (p in [poDefault, poDefaultPosOnly]) and HandleAllocated then
GetWindowRelativePosition(Handle,X,Y); GetWindowRelativePosition(Handle,X,Y);
if (Position in [poScreenCenter, poMainFormCenter, poOwnerFormCenter, poWorkAreaCenter]) then poDesigned, poDefaultSizeOnly: ;
MoveToDefaultMonitor(X, Y); end;
SetBounds(X, Y, Width, Height); SetBounds(X, Y, Width, Height);
end; end;