unit UnitFrmTriggerWindow;

interface

uses
  Windows, Messages, SysUtils, Variants, Classes, Graphics, Controls, Forms,
  Dialogs, ExtCtrls, UnitKeyboardQuery, StdCtrls, Buttons;

type
  TFrmTriggerWindow = class(TForm)
    Image2: TImage;
    btnGestures: TSpeedButton;
    Image1: TImage;
    TimCloser: TTimer;
    TimDelay: TTimer;
    timCursor: TTimer;

    procedure FormCreate(Sender: TObject);
    procedure FormMouseLeave(Sender: TObject);
    procedure TimCloserTimer(Sender: TObject);
    procedure btnHelpClick(Sender: TObject);
    procedure btnHelpMouseEnter(Sender: TObject);
    procedure btnHelpMouseLeave(Sender: TObject);
    procedure FormActivate(Sender: TObject);
    procedure btnGesturesClick(Sender: TObject);
    procedure TimDelayTimer(Sender: TObject);
    procedure btnGesturesMouseUp(Sender: TObject; Button: TMouseButton;
      Shift: TShiftState; X, Y: Integer);

    procedure WMNCHitTest(VAR Msg: TWMNcHitTest);  message WM_NCHITTEST;
    procedure WMSetCursor(Var M: TWMSetCursor); message WM_SETCURSOR;
    procedure FormPaint(Sender: TObject);
    procedure timCursorTimer(Sender: TObject);
    procedure FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);

  private
    { Private declarations }
    storedWidth : integer;
    //p : TPanel;
    FirstDown : boolean;
    showingfull : boolean;
    ForceHide : boolean;
    forwin : THandle;
    crit : Windows.RTL_CRITICAL_SECTION;
    procedure HidePad;
    procedure ShowPad(nowidth : boolean = false);
    procedure SetWidth(w : integer; fudge : integer = 0);
    function GetInterval: integer;
    procedure SetInverval(const Value: integer);
    procedure SetEnable(const Value: boolean);

  protected

    procedure CreateParams(var Params: TCreateParams); override;
  public
    { Public declarations }
    procedure hide;
    procedure ReportPoint(p : TPoint);
    procedure ReportMouseButton(down : boolean);
    function RemoveSelfFromFocus(NoFocus : boolean = false) : THandle;

    property prFadeTime : integer read GetInterval write SetInverval;
    property prEnable : boolean write SetEnable;


  end;

var
  FrmTriggerWindow: TFrmTriggerWindow;

implementation

uses UnitMisc, UnitFrmSysTrayMenu, UnitFrmAbout, UnitFrmConfig,
  UnitPopupGenerate, UnitPaste, UnitThreadAttach;


{$R *.dfm}

function TFrmTriggerWindow.GetInterval: integer;
begin
    result := TimCloser.Interval;
end;
procedure TFrmTriggerWindow.SetEnable(const Value: boolean);
begin
    if not value then
        self.Hide
    else begin
        self.show;
        self.HidePad;
    end;
end;
procedure TFrmTriggerWindow.SetInverval(const Value: integer);
begin
    TimCloser.Interval := value;
end;
procedure TFrmTriggerWindow.hide;
begin
    self.Visible := false;
    ShowWindow(self.Handle, SW_HIDE);
    self.Close;
end;
function TFrmTriggerWindow.RemoveSelfFromFocus(NoFocus : boolean) : thandle;
var h : THandle;
    name : string;
    i : integer;
    ta : TThreadAttach;
const exename = 'arsclip.exe';
begin
    h := GetForegroundWindow;
    name := WindowHandleToEXEName(h);
    i := 0;

    while (lowercase(name) = exename) and (i<10) do begin
        h := UnitMisc.GetNextWindow(h);
        name := WindowHandleToEXEName(h);

        inc(i);
    end;

    if not NoFocus then begin
        if lowercase(name) = exename then begin
            ta := TThreadAttach.Create(h);
        end else begin
            ta := TThreadAttach.Create(GetForegroundWindow);
        end;
        Windows.SetForegroundWindow(h);
        myfree(ta);
    end;

    result := h;
end;




procedure TFrmTriggerWindow.CreateParams(var Params: TCreateParams);
begin
	inherited CreateParams(Params);

    // styles copied from HintWindow class, some may do nothing
    with Params do begin

        style := WS_POPUP or WS_BORDER {or WS_TABSTOP};
        ExStyle := WS_EX_TOOLWINDOW or WS_EX_TOPMOST or WS_EX_NOACTIVATE;


        //WindowClass.style := {WindowClass.style or CS_DROPSHADOW or CS_SAVEBITS;
        WndParent := GetDesktopWindow;
    end;
end;
procedure TFrmTriggerWindow.FormActivate(Sender: TObject);
begin
	if not KeyboardQuery.IsClicked(leftButton)  then begin
	    self.RemoveSelfFromFocus(false);
    end;
end;
procedure TFrmTriggerWindow.FormCreate(Sender: TObject);
begin
    storedWidth := self.Width;



    ClientHeight := Height;
    ClientWidth := Width;


    // (dirty, filth tricks because nothing worked to hide just this window)
    // Hide the entire application from the taskbar, remove the caption and border
    // Only hidden windows are affected
    // Any form needing to show on the taskbar must manually toggle WS_EX_TOOLWINDOW off and WS_EX_APPWINDOW on
    //ShowWindow(Application.Handle, SW_HIDE);
    {SetWindowLong(Application.Handle, GWL_EXSTYLE,
        GetWindowLong(Application.Handle, GWL_EXSTYLE) or WS_EX_TOOLWINDOW or WS_EX_TOPMOST);}
    {SetWindowLong(self.Handle, GWL_EXSTYLE,
        GetWindowLong(self.Handle, GWL_EXSTYLE) or WS_EX_TOOLWINDOW);}
    //ShowWindow(FrmGestures.Handle,SW_HIDE);


    //pnlTop.Align := alTop;
    //imgScratch.Align := alClient;
    //imgScratch.Width := width;

    FirstDown := true;
    self.showingfull := true;


    self.ShowPad(true);
    self.HidePad;


    image1.Visible := false;
    image2.Visible := false;

    self.Width := 10;
    self.Height := 10;

    Windows.InitializeCriticalSection(crit);
end;

procedure TFrmTriggerWindow.HidePad;
var m : TMonitor;
    r : TRect;
    thickness : integer;


begin
    self.TimCloser.Enabled := false;
    m := Screen.PrimaryMonitor;

    if (not assigned(frmconfig)) then EXIT;


    thickness := frmConfig.tbTriggerThickness.Position;
    self.Height := 200;

    if assigned(FrmConfig) then begin
        if FrmConfig.cbUseVirtualDesktop.Checked then begin
            r := screen.DesktopRect;
        end else begin
            r := m.WorkareaRect;
        end;

    end;

    with r do begin
    if (frmconfig.sbleft.down or frmconfig.sbright.down) then begin
        self.Top := r.Top + trunc((r.bottom-r.top)/2) - trunc(self.Height/2);
    end;

    if (frmconfig.sbTop.down or frmconfig.sbtopleft.down or frmconfig.sbtopright.down) then begin
        self.top := r.Top;
    end;
    if (frmconfig.sbBottom.down) then begin
        self.Top := r.top + (r.bottom-r.top) - thickness;
    end;

    if (frmconfig.sbbottomleft.down or frmconfig.sbbottomright.down) then begin
        self.top := r.Top + (r.bottom-r.top) - self.height;
    end;

    if (frmconfig.sbleft.down or frmconfig.sbright.down) or
        (frmconfig.sbtopleft.down or frmconfig.sbtopright.down) or
        (frmconfig.sbbottomleft.down or frmconfig.sbbottomright.down) then begin
        SetWidth(thickness);

    end else begin
        SetWidth(200);
        self.Left := trunc((r.Right-r.left)  / 2) - (self.Width div 2);
        self.Height := thickness;
    end;
    if (frmconfig.sbLeft.down or frmconfig.sbtopleft.down or frmconfig.sbbottomleft.down) then begin
        self.Left := r.Left;
    end;

    if (frmconfig.sbright.down or frmconfig.sbtopright.down or frmconfig.sbbottomright.down) then begin
        self.Left := r.left + (r.right-r.left) - thickness;
    end;

    self.showingfull := false;
    end;
end;



procedure TFrmTriggerWindow.FormMouseLeave(Sender: TObject);
begin
    TimDelay.Enabled := false;
    screen.Cursor := crArrow;
{    FrmMainPopup.Hide;
    TimDelay.Enabled := false;
    TimCloser.Enabled := true;

    screen.Cursor := crArrow;
}
end;

procedure TFrmTriggerWindow.FormPaint(Sender: TObject);
var
	pa : Array of TPoint;
    r : TRect;
const wd = 8;

begin
    canvas.CopyRect(Image1.ClientRect, image1.Canvas, image1.ClientRect);
	canvas.CopyRect(Image2.ClientRect, image2.canvas, image2.ClientRect);


	with Canvas do begin
        brush.Color := clActiveCaption;
        pen.color := clBtnText;
        r := self.ClientRect;
        InflateRect(r,-1,-1);
        setlength(pa,3);
        pa[0] := point(r.Right-wd,r.bottom);
        pa[1] := point(r.Right, r.bottom-wd);
        pa[2] := point(r.Right, r.Bottom);
        polygon(pa);
    end;
end;

procedure TFrmTriggerWindow.ShowPad(nowidth : boolean = false);
begin
    forwin := self.RemoveSelfFromFocus(true);
    self.showingfull := true;
end;


procedure TFrmTriggerWindow.SetWidth(w: integer; fudge : integer);
var m : TMonitor;
begin
    self.Width := w;
    m := Screen.PrimaryMonitor;

    self.Left := m.Left+m.width - (self.Width + fudge);
end;






procedure TFrmTriggerWindow.ReportMouseButton(down : boolean);
begin
    if self.showingfull  then begin
        if down then begin
            if FirstDown then begin
                ReportPoint(mouse.cursorpos);
                FirstDown := false;
            end else begin
            end;
        end else begin
            if not firstdown then begin
                ForceHide := true;
            end;

            FirstDown := true;
        end;
    end else begin
        FirstDown := true;
    end;
end;

procedure TFrmTriggerWindow.ReportPoint(p: TPoint);
begin
end;




procedure TFrmTriggerWindow.TimCloserTimer(Sender: TObject);
begin
    TimCloser.Enabled := false;
    self.ForceHide := false;
end;

procedure TFrmTriggerWindow.timCursorTimer(Sender: TObject);
begin
    if Assigned(screen) then begin
        timCursor.Enabled := false;
        screen.Cursor := crDefault;
    end;
end;

procedure TFrmTriggerWindow.TimDelayTimer(Sender: TObject);
begin
	EnterCriticalSection(crit);
	TimDelay.Enabled := false;

    forwin := Windows.GetForegroundWindow;
    forwin := self.RemoveSelfFromFocus(true);

    self.ShowPad;

    self.RemoveSelfFromFocus(true);
    FrmMainPopup.ShowOnScratchPad(true);

    if not ForceHide  then begin
        self.timcloser.enabled := false;
    end;


    LeaveCriticalSection(crit);
end;


procedure TFrmTriggerWindow.FormMouseMove(Sender: TObject; Shift: TShiftState; X, Y: Integer);
var
	pt : TPoint;

const THRESHOLD = 15;
begin
    pt := point(x, y);
    if (pt.x >= self.width-THRESHOLD) and (pt.Y >= self.height-THRESHOLD)  then begin
    	TimDelay.Enabled := false;
    end else begin
    	screen.Cursor := crDefault;
    	if not PtInRect(btnGestures.ClientRect, pt) then begin
            if TimDelay.Enabled = false then begin
            	TimDelay.Interval := frmconfig.tbDelay.Position;
	            TimDelay.Enabled := true;
            end;
    	end;
    end;

end;

procedure TFrmTriggerWindow.WMNCHitTest(var Msg: TWMNcHitTest);
var
	pt : TPoint;

const THRESHOLD = 15;
begin
	inherited;

    msg.result := HTCLIENT;
    //windows.GetWindowRect(self.Handle, r);

    pt := point(msg.XPos, msg.YPos);
    pt := self.ScreenToClient(pt);

    if (pt.x >= self.width-THRESHOLD) and (pt.Y >= self.height-THRESHOLD)  then begin
        msg.Result := HTCAPTION;
        TimDelay.Enabled := false;
        EXIT;
    end else begin
    	if not PtInRect(btnGestures.ClientRect, pt) then begin
            if TimDelay.Enabled = false then begin
            	TimDelay.Interval := frmconfig.tbDelay.Position;
	            TimDelay.Enabled := true;
            end;
    	end;
    end;
end;

procedure TFrmTriggerWindow.WMSetCursor(var M: TWMSetCursor);
begin
	if m.CursorWnd = self.Handle then begin
        if m.HitTest = HTCAPTION then begin
            screen.Cursor := crSizeAll;
            timCursor.Enabled := true;
            m.Result := 1;
        end else begin
            screen.Cursor := crDefault;
            m.result := 1;
        end;
    end;
end;




procedure TFrmTriggerWindow.btnGesturesClick(Sender: TObject);
begin
    self.HidePad;
    self.TimCloser.Enabled := false;
end;
procedure TFrmTriggerWindow.btnGesturesMouseUp(Sender: TObject;
  Button: TMouseButton; Shift: TShiftState; X, Y: Integer);
begin
    Windows.SetForegroundWindow(frmConfig.Handle);
    frmConfig.pcPanels.ActivePageIndex := frmconfig.tsTriggerWindow.PageIndex;
    frmConfig.Show;
end;
procedure TFrmTriggerWindow.btnHelpClick(Sender: TObject);
begin
    self.HidePad;
    self.TimCloser.Enabled := false;
end;
procedure TFrmTriggerWindow.btnHelpMouseEnter(Sender: TObject);
begin
    TimDelay.Enabled := false;
end;
procedure TFrmTriggerWindow.btnHelpMouseLeave(Sender: TObject);
begin
    FormMouseLeave(sender);
end;

end.



