unit SnapTo;

interface

uses Forms, Messages, engine;

Var
 SnapRange: Integer = 20;
 OffsetX: Integer = 0;
 OffsetY: Integer = 2;

  procedure WMWindowPosChanging(var Message: TWMWindowPosChanging; Self: TForm);
  procedure SnapToGrid(Var Message: TWMWindowPosChanging; Self: TFormPanel);
  procedure VisSnapToGrip(Var Message: TWMWindowPosChanging; Self: TVisualPanel);
  function OkToSnapY(SelfForm: TForm; SnapTo: TForm): boolean;
  Function OkToSnapX(SelfForm: TForm; SnapTo: TForm): Boolean;
  Function MouseIsOnForm(Form: TForm): boolean;

implementation

Uses Main, controls, ProcsAndTypes;

Function MouseIsOnForm(Form: TForm): boolean;
begin
 Result := false;
 If (Mouse.CursorPos.X >= form.left) and (Mouse.CursorPos.X <= form.left+form.width) then begin
  If (Mouse.CursorPos.Y >= form.top) and (Mouse.CursorPos.Y <= form.top+form.height) then begin
   Result := true;
  end;
 end;
end;

procedure SnapToGrid(Var Message: TWMWindowPosChanging; Self: TFormPanel);
begin
 Message.WindowPos^.x := Message.WindowPos^.x - (Message.WindowPos^.x mod Options.Visual.GridSpacingX);
 Message.WindowPos^.y := Message.WindowPos^.y - (Message.WindowPos^.y mod Options.Visual.GridSpacingY);
 if ((Message.WindowPos^.cx + Message.WindowPos^.x) mod Options.Visual.GridSpacingX) <= (Options.Visual.GridSpacingX div 2) then begin
  // shorten
  Message.WindowPos^.cx := Message.WindowPos^.cx - ((Message.WindowPos^.cx + Message.WindowPos^.x) mod Options.Visual.GridSpacingX) + 1;
 end
  else
 begin
  // extend
  Message.WindowPos^.cx := Message.WindowPos^.cx + (Options.Visual.GridSpacingX - (Message.WindowPos^.cx + Message.WindowPos^.x) mod Options.Visual.GridSpacingX) + 1;
 end;
 if ((Message.WindowPos^.cy + Message.WindowPos^.y) mod Options.Visual.GridSpacingY) <= (Options.Visual.GridSpacingY div 2) then begin
  // shorten
  Message.WindowPos^.cy := Message.WindowPos^.cy - ((Message.WindowPos^.cy + Message.WindowPos^.y) mod Options.Visual.GridSpacingY) + 1;
 end
  else
 begin
  // extend
  Message.WindowPos^.cy := Message.WindowPos^.cy + (Options.Visual.GridSpacingY - (Message.WindowPos^.cy + Message.WindowPos^.y) mod Options.Visual.GridSpacingY) + 1;
 end;
end;

procedure VisSnapToGrip(Var Message: TWMWindowPosChanging; Self: TVisualPanel);
begin
 Message.WindowPos^.x := Message.WindowPos^.x - (Message.WindowPos^.x mod Options.Visual.FormPanelOptions.GridSpacingX);
 Message.WindowPos^.y := Message.WindowPos^.y - (Message.WindowPos^.y mod Options.Visual.FormPanelOptions.GridSpacingY);
 if ((Message.WindowPos^.cx + Message.WindowPos^.x) mod Options.Visual.FormPanelOptions.GridSpacingX) <= (Options.Visual.FormPanelOptions.GridSpacingX div 2) then begin
  // shorten
  Message.WindowPos^.cx := Message.WindowPos^.cx - ((Message.WindowPos^.cx + Message.WindowPos^.x) mod Options.Visual.FormPanelOptions.GridSpacingX) + 1;
 end
  else
 begin
  // extend
  Message.WindowPos^.cx := Message.WindowPos^.cx + (Options.Visual.FormPanelOptions.GridSpacingY - (Message.WindowPos^.cx + Message.WindowPos^.x) mod Options.Visual.FormPanelOptions.GridSpacingY) + 1;
 end;
 if ((Message.WindowPos^.cy + Message.WindowPos^.y) mod Options.Visual.FormPanelOptions.GridSpacingY) <= (Options.Visual.FormPanelOptions.GridSpacingY div 2) then begin
  // shorten
  Message.WindowPos^.cy := Message.WindowPos^.cy - ((Message.WindowPos^.cy + Message.WindowPos^.y) mod Options.Visual.FormPanelOptions.GridSpacingY) + 1;
 end
  else
 begin
  // extend
  Message.WindowPos^.cy := Message.WindowPos^.cy + (Options.Visual.FormPanelOptions.GridSpacingY - (Message.WindowPos^.cy + Message.WindowPos^.y) mod Options.Visual.FormPanelOptions.GridSpacingY) + 1;
 end;
end;

procedure WMWindowPosChanging(var Message: TWMWindowPosChanging; Self: TForm);
Var
 I: Integer;
begin
 If Self.Tag = 0 then exit;
 For I := 0 to application.ComponentCount - 1 do begin
  If (application.Components[I] is TForm) then begin
   If ((Application.Components[I] as TForm) <> self) and ((Application.Components[I] as TForm).Tag = 999) then begin
    with (application.Components[I] as TForm) do begin
     If visible then begin
      // Snap on right?
      If ((Message.WindowPos^.x < (left + width + SnapRange)) and (Message.WindowPos^.x > (left + width - snaprange)))
       and OkToSnapY(Self, Application.Components[I] as TForm) then Message.WindowPos^.x := Left + Width - OffsetX;
      // Snap on Left?
      If (((Message.WindowPos^.x + Self.width - SnapRange) < left) and ((Message.WindowPos^.x + Self.Width + SnapRange) > left))
       and OkToSnapY(Self, Application.Components[I] as TForm) then Message.WindowPos^.x := Left - Message.WindowPos^.cx + OffsetX;
      // Snap on Buttom?
      If ((Message.WindowPos^.y < (top + height + SnapRange)) and (Message.WindowPos^.y > (top + height - snaprange)))
       and OkToSnapX(Self, Application.Components[I] as TForm) then Message.WindowPos^.y := Top + Height - OffsetY;
      // Snap on Top?
      If (((Message.WindowPos^.y + Self.height - SnapRange) < top) and ((Message.WindowPos^.y + Self.height + SnapRange) > top))
       and OkToSnapX(Self, Application.Components[I] as TForm) then Message.WindowPos^.y := Top - Message.WindowPos^.cy + OffsetY;
     end;
    end;
   end;
  end;
 end;
end;

function OkToSnapY(SelfForm, SnapTo: TForm): boolean;
begin
 Result := false;
 If ((SelfForm.Top > SnapTo.Top) and (SelfForm.Top < (SnapTo.Top + SnapTo.Height))) or
  (((SelfForm.Top + SelfForm.Height) > SnapTo.Top) and ((SelfForm.Top + SelfForm.Height) < (SnapTo.Top + SnapTo.Height))) then Result := true;
 If ((SnapTo.Top > SelfForm.Top) and ((SnapTo.Top + SnapTo.Height) < (SelfForm.Top + SelfForm.Height))) Then Result := true;
end;

function OkToSnapX(SelfForm, SnapTo: TForm): Boolean;
begin
 Result := False;
 If ((SelfForm.Left > SnapTo.Left) and (SelfForm.Left < (SnapTo.Left + SnapTo.Width))) or
  (((SelfForm.Left + SelfForm.Width) > SnapTo.Left) and ((SelfForm.Left + SelfForm.Width) < (SnapTo.Left + SnapTo.Width))) Then Result := true;
 If ((SnapTo.Left > SelfForm.Left) and ((SnapTo.Left + SnapTo.Width) < (SelfForm.Left + SelfForm.Width))) Then Result := true;
end;

end.
 