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 begin
poDesktopCenter: if Owner is TCustomForm then
begin BuddyForm := TCustomForm(Owner)
X := Screen.DesktopLeft + (Screen.DesktopWidth - RealWidth) div 2; else
Y := Screen.DesktopTop +(Screen.DesktopHeight - RealHeight) div 2; p := poMainFormCenter;
end; end;
poScreenCenter: if p = poMainFormCenter then
begin begin
X := (Screen.Width - RealWidth) div 2; if Assigned(Application.MainForm) then
Y := (Screen.Height - RealHeight) div 2; BuddyForm := Application.MainForm
end; else
poWorkAreaCenter: p := poScreenCenter;
begin end;
X := Screen.WorkAreaLeft + (Screen.WorkAreaWidth - RealWidth) div 2;
Y := Screen.WorkAreaTop + (Screen.WorkAreaHeight - RealHeight) div 2; case Position of
end; poScreenCenter..poWorkAreaCenter:
poMainFormCenter, begin
poOwnerFormCenter: CheckWorkArea := True;
begin // decide about the rect to center to
if (P = poOwnerFormCenter) and (Owner is TCustomForm) then CenterToRect := Screen.PrimaryMonitor.BoundsRect; // center by default to primary monitor
AForm := TCustomForm(Owner) case p of
else poScreenCenter:
AForm := Application.MainForm; if Screen.MonitorCount=1 then
if (Self <> AForm) and Assigned(AForm) 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 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
begin if not (BuddyForm.HandleAllocated and (GetWindowRect(BuddyForm.Handle, CenterToRect) <> 0)) then
if AForm.HandleAllocated and (GetWindowRect(AForm.Handle, AFormRealRect) <> 0) then CenterToRect := Screen.PrimaryMonitor.BoundsRect; // CenterToRect may be zeroed, need to reassign to default value
begin // success
AFormRealWidth := AFormRealRect.Right-AFormRealRect.Left;
AFormRealHeight := AFormRealRect.Bottom-AFormRealRect.Top;
end else
begin // error
AFormRealWidth := AForm.Width;
AFormRealHeight := AForm.Height;
end;
X := ((AFormRealWidth - RealWidth) div 2) + AForm.Left;
Y := ((AFormRealHeight - RealHeight) div 2) + AForm.Top;
end;
end; end;
// check that we are still in the viewarea poDesigned..poDefaultSizeOnly: ;
X:= Max(Screen.WorkAreaLeft, Min((Screen.WorkAreaLeft+Screen.WorkAreaWidth)-RealWidth, X));
Y:= Max(Screen.WorkAreaTop, Min((Screen.WorkAreaTop+Screen.WorkAreaHeight)-RealHeight, Y));
end; 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
if not Assigned(m) then
m := Screen.MonitorFromPoint(Point(X+RealRect.Width div 2, Y+RealRect.Height div 2));
if Assigned(m) then
MonitorRect := m.WorkareaRect
else
MonitorRect := Screen.WorkAreaRect;
X:= Max(MonitorRect.Left, Min(MonitorRect.Right-RealRect.Width, X));
Y:= Max(MonitorRect.Top, Min(MonitorRect.Bottom-RealRect.Height, Y));
end;
end;
poDefault, poDefaultPosOnly:
if HandleAllocated then // get current widgetset position
GetWindowRelativePosition(Handle,X,Y);
poDesigned, poDefaultSizeOnly: ;
end; end;
// get current widgetset position
if (p in [poDefault, poDefaultPosOnly]) and HandleAllocated then
GetWindowRelativePosition(Handle,X,Y);
if (Position in [poScreenCenter, poMainFormCenter, poOwnerFormCenter, poWorkAreaCenter]) then
MoveToDefaultMonitor(X, Y);
SetBounds(X, Y, Width, Height); SetBounds(X, Y, Width, Height);
end; end;