In my last post I talked about snapping windows to monitor halves and quadrants. I have been using that code for a few days and found it has a few shortcomings:
- If a window has size constraints, these will still be respected (which is good) but this will result in the window not being moved correctly. Snapping to the left and top half works fine, but snapping to the right or bottom half will move part of the window outside the active monitor.
- If a window has size constraints, moving from the left half of the right hand side monitor to the right half of left hand side monitor will not work. the same applies from the top half of the bottom monitor to the bottom half of the top monitor.
- It’s a bit inconvenient to move a window from a quadrant of one monitor to a quadrant of a different monitor. E.g. sometimes I want to move a window from the top right quadrant of the right hand side monitor to the top right quadrant of the left hand side monitor and vice versa. In order to do that I have to press Ctrl+Alt+Left (moves it to the left half of that monitor) Ctrl+Alt+Left (moves it to the right half of the other monitor) Ctrl+Alt+PgUp (finally moves it to the top right quadrant of that monitor). It would be nice to accomplish this
- with less key strokes
- without resizing the window
Currently I am leaning towards Ctrl+Alt+PgUp moving the window to the top right quadrant of the same monitor and pressing it again moving it to the same quadrant of the monitor to the right of that monitor, or if that doesn’t exist, to the monitor above. But I’m not yet sure about the order of monitors here. If you want to voice your opinion, use my corresponding Google+ post
The fix for the constraints issues isn’t that difficult: Just read the form’s constraints and adjust the position accordingly. Here is the new code:
procedure TForm_MoveTo(_frm: TCustomForm; _Position: TdzWindowPositions); procedure ToTop(var _Re: TRect; _MinHeight, _MaxHeight: Integer); begin _Re.Bottom := _Re.Top + TRect_Height(_Re) div 2; if TRect_Height(_Re) < _MinHeight then _Re.Bottom := _Re.Top + _MinHeight; if (_MaxHeight > 0) and (TRect_Height(_Re) > _MaxHeight) then _Re.Bottom := _Re.Top + _MaxHeight; end; procedure ToBottom(var _Re: TRect; _MinHeight, _MaxHeight: Integer); begin _Re.Top := _Re.Top + TRect_Height(_Re) div 2; if TRect_Height(_Re) < _MinHeight then _Re.Top := _Re.Bottom - _MinHeight; if (_MaxHeight > 0) and (TRect_Height(_Re) > _MaxHeight) then _Re.Top := _Re.Bottom - _MaxHeight; end; procedure ToLeft(var _Re: TRect; _MinWidth, _MaxWidth: Integer); begin _Re.Right := _Re.Left + TRect_Width(_Re) div 2; if TRect_Width(_Re) < _MinWidth then _Re.Right := _Re.Left + _MinWidth; if (_MaxWidth > 0) and (TRect_Width(_Re) > _MaxWidth) then _Re.Right := _Re.Left + _MaxWidth; end; procedure ToRight(var _Re: TRect; _MinWidth, _MaxWidth: Integer); begin _Re.Left := _Re.Left + TRect_Width(_Re) div 2; if TRect_Width(_Re) < _MinWidth then _Re.Left := _Re.Right - _MinWidth; if (_MaxWidth > 0) and (TRect_Width(_Re) > _MaxWidth) then _Re.Left := _Re.Right - _MaxWidth; end; function SamePoint(const _pnt1, _pnt2: TPoint): Boolean; begin Result := (_pnt1.X = _pnt2.X) and (_pnt1.Y = _pnt2.Y); end; function SameRect(const _re1, _re2: TRect): Boolean; begin Result := SamePoint(_re1.TopLeft, _re2.TopLeft) and SamePoint(_re1.BottomRight, _re2.BottomRight); end; var re: TRect; Bounds: TRect; NewMonitor: TMonitor; Constraints: TSizeConstraints; begin re := _frm.Monitor.WorkareaRect; Bounds := _frm.BoundsRect; Constraints := _frm.Constraints; case _Position of dwpTop: begin ToTop(re, Constraints.MinHeight, Constraints.MaxHeight); if SameRect(re, Bounds) then begin NewMonitor := MonitorFromPoint(Point((re.Left + re.Right) div 2, re.Top - TRect_Height(re) div 2)); if Assigned(NewMonitor) then begin re := NewMonitor.WorkareaRect; ToBottom(re, Constraints.MinHeight, Constraints.MaxHeight); end; end; end; dwpBottom: begin ToBottom(re, Constraints.MinHeight, Constraints.MaxHeight); if SameRect(re, Bounds) then begin NewMonitor := MonitorFromPoint(Point((re.Left + re.Right) div 2, re.Bottom + TRect_Height(re) div 2)); if Assigned(NewMonitor) then begin re := NewMonitor.WorkareaRect; ToTop(re, Constraints.MinHeight, Constraints.MaxHeight); end; end; end; dwpLeft: begin ToLeft(re, Constraints.MinWidth, Constraints.MaxWidth); if SameRect(re, Bounds) then begin NewMonitor := MonitorFromPoint(Point(re.Left - TRect_Width(re) div 2, (re.Top + re.Bottom) div 2)); if Assigned(NewMonitor) then begin re := NewMonitor.WorkareaRect; ToRight(re, Constraints.MinWidth, Constraints.MaxWidth); end; end; end; dwpRight: begin ToRight(re, Constraints.MinWidth, Constraints.MaxWidth); if SameRect(re, Bounds) then begin NewMonitor := MonitorFromPoint(Point(re.Right + TRect_Width(re) div 2, (re.Top + re.Bottom) div 2)); if Assigned(NewMonitor) then begin re := NewMonitor.WorkareaRect; ToLeft(re, Constraints.MinWidth, Constraints.MaxWidth); end; end; end; dwpTopLeft: begin ToTop(re, Constraints.MinHeight, Constraints.MaxHeight); ToLeft(re, Constraints.MinWidth, Constraints.MaxWidth); end; dwpTopRight: begin ToTop(re, Constraints.MinHeight, Constraints.MaxHeight); ToRight(re, Constraints.MinWidth, Constraints.MaxWidth); end; dwpBottomLeft: begin ToBottom(re, Constraints.MinHeight, Constraints.MaxHeight); ToLeft(re, Constraints.MinWidth, Constraints.MaxWidth); end; dwpBottomRight: begin ToBottom(re, Constraints.MinHeight, Constraints.MaxHeight); ToRight(re, Constraints.MinWidth, Constraints.MaxWidth); end; end; _frm.BoundsRect := re; end;
It’s already in the dzlib repository on sourceforge, unit u_dzVclUtils.