; "Screen Magnifier" - IntelliPoint clone? {{{

#SingleInstance ignore          ; ignore script if already-running
#MaxHotkeysPerInterval 200      ; need that with the scrollwheel
Process, Priority, , High       ; tell that to Windows Task Manager
OnExit GuiClose                 ; some clean up before leaving

hotkey, Shift,  toggle_resize   ; Script hotkey: resize by corner
hotkey, Alt,    toggle_aliasing ; Script hotkey: antialiasing
hotkey, Space,  toggle_follow   ; Script hotkey: stick window
hotkey, Ctrl,   toggle_pindown  ; Script hotkey: stick area
hotkey, Escape, GuiClose        ; Script hotkey: terminate script

;=============================================================== }}}
; Initialization: Global Variables {{{

  ; Execution parameters - - - - - - - - - - - - - - - - - - - - - -
  delay     := 10               ; display update intervals (ms)

  follow    := true             ; follow mouse pointer - or not
  pindown   := 0                ; keep current zoom area coordinates
  antialize := 0                ; less starcase

  ; Zoom parameters- - - - - - - - - - - - - - - - - - - - - - - - -
  zoom      := 2                ; initial zoom factor
  ZOOMFX    := 1.189207115      ; zoom factor (square square of 2)
  ZOOMFXMAX := 8                ; zoom factor max
  zooming   := false

  ; Action resources - - - - - - - - - - - - - - - - - - - - - - - -
  resizing  := false            ; zoom window resize in progress
  dragFromX := 0                ; resizing corner reference point
  dragFromY := 0                ; ...
  stickX    := 0                ; stuck window reference point
  stickY    := 0                ; ...
  pinX      := 0                ; stuck zoome area reference point

  ; Window coordinates - - - - - - - - - - - - - - - - - - - - - - -
  wox       := 0                ; zoom window origin x
  wwMax     := A_ScreenWidth    ; max width
  ww        := 480              ; initial
  wwMin     := 32               ; min

  woy       := 0                ; zoom window origin y
  whMax     := A_ScreenHeight   ; max height
  wh        := 200              ; initial ...
  whMin     := 16               ; min     ...

  wwD       := 0                ; window Delta (mouse wheel)
  whD       := 0                ; ...

  ; Mouse pointer coordinates - - - - - - - - - - - - - - - - - - - 
  mx        := 0                ; mouse x current position
  my        := 0                ; ...
  mxp       := mx               ; previous
  myp       := my               ; ...

; }}}
; Initialization: Zoom Window handles {{{

  MouseGetPos, mx, my

  ; Zoom window always on top and starts way off screen
  Gui, +AlwaysOnTop  +Owner -Resize -ToolWindow +E0x00000020
  Gui, Show, NoActivate W%ww% H%wh% X-1000 Y-1000, MagWindow

  WinSet, Transparent, 254, MagWindow
  Gui, -Caption
  Gui, +Border











  WinGet, src_id, id
  src_frame := DllCall("GetDC", UInt, src_id)




  WinGet, dst_id, id, MagWindow
  dst_frame := DllCall("GetDC", UInt, dst_id)

  DllCall( "gdi32.dll\SetStretchBltMode"
         , "uint", dst_frame
         , "int", 4*antialize)

; First Zoom Window display
  SetTimer, repaint , %delay%       ; schedule next repaint ;Gosub, repaint
  Gosub, repaint

return
;=================================================================== }}}

; Event handlers: Mouse Wheel {{{

WheelUp::               ; zoom in
    if zoom < %ZOOMFXMAX%
        zoom *= %ZOOMFX%
    zooming := true     ; triggers update
return

WheelDown::             ; zoom out
    if zoom > %ZOOMFX%
        zoom /= %ZOOMFX%
    zooming := true     ; triggers update
return

+WheelDown::            ; larger
    wwD =  32
    whD =  32
return

+WheelUp::              ; smaller
    wwD = -32
    whD = -32
return

;=================================================================== }}}
; Hotkey handlers: follow, aliasing, GuiClose {{{
toggle_follow:          ; follow or stick
    if resizing OR pindown
        return
    if follow {
        if(stickX != 0) OR (stickY != 0)
            MouseMove, stickX, stickY
        stickX := wox + ww/2
        stickY := woy + wh/2
        follow := false
    }
    else {
        follow := true
        MouseGetPos, stickX, stickY
        MouseMove, wox + ww/2, woy + wh/2
    }

return

toggle_aliasing:        ; aliasing
    antialize := 1-antialize
    DllCall( "gdi32.dll\SetStretchBltMode"
           , "uint", dst_frame
           , "int", 4*antialize)



return

toggle_pindown:         ; keep current zoomed area coordinates
    if resizing
        return
    pindown := !pindown
return

toggle_resize:          ; enter or leave resize by corner
    if pindown
        return
    if !resizing
    {
        resizing  := true
        if follow {
            ; Move pointer to Zoom Window center
            MouseMove, wox + ww/2, woy + wh/2
            ; Remember Zoom Window center
            MouseGetPos, dragFromX, dragFromY
            ; Move to Zoom Window corner
            MouseMove, dragFromX + ww/2, dragFromY + wh/2
        }
        else {
            ; Remember Zoom Area center
            MouseGetPos, dragFromX, dragFromY
            ; Move pointer to Zoom Area corner
            MouseMove, mx + ww/2/zoom, my + wh/2/zoom
        }

    }
    else {
        resizing := false
        ; Restore pointer position
        MouseMove, dragFromX, dragFromY
    }
return

GuiClose:       ; clean up and terminate
   DllCall("gdi32.dll\DeleteDC", UInt,dst_frame)
   DllCall("gdi32.dll\DeleteDC", UInt,src_frame)

Process, Priority, , Normal
ExitApp
;=================================================================== }}}

; repaint: Zoom, follow, rescale and resize {{{
repaint:
    CoordMode,   Mouse, Screen


    if !pindown {
        MouseGetPos, mx, my
        WinGetPos,   wx, wy, ww, wh, MagWindow

        ; Resize by corner -----------------------------------------
        if resizing
        {
            ww  := 2 * (mx - dragFromX)
            wh  := 2 * (my - dragFromY)
            if !follow {            ; resizze area instead of window
                ww *= zoom
                wh *= zoom
            }
            ; Make it look like pointer is still centered
            mx  := dragFromX
            my  := dragFromY
            zooming := true         ; triggers update
        }
        ; Resize with mouse wheel ----------------------------------
        else if (wwD != 0) OR (whD != 0)
        {
            ww  += wwD
            wh  += whD
            wwD := 0
            whD := 0
            zooming := true         ; triggers update
        }

        clip_on_screen()            ; keep zoom area on screen
    }
    ; Update -------------------------------------------------------
    if pindown OR zooming OR (mx != mxp) OR (my != myp)
    {
        clip_size()                 ; Keep Window min-max
        clip_pos()                  ; Keep Window on screen

        WinMove, MagWindow, ,wox, woy, %ww%, %wh%

        DllCall( "gdi32.dll\StretchBlt"
               , UInt, dst_frame          ; destination frame
               ,  Int, 2                  ; ...x
               ,  Int, 2                  ; ...y
               ,  Int, ww-6               ; ...width
               ,  Int, wh-6               ; ...height
               , UInt, src_frame          ; source frame
               ,  Int, mx - (ww/2 / zoom) ; ...x
               ,  Int, my - (wh/2 / zoom) ; ...y
               ,  Int,       ww   / zoom  ; ...width
               ,  Int,       wh   / zoom  ; ...height
               , UInt, 0xCC0020)          ; dwRop (raster operation)
    }
    ; Remember and schedule update ---------------------------------
    mxp := mx
    myp := my
return

;=================================================================== }}}





clip_on_screen() ; Keep zoom window area on screen {{{
{
    global

    if(mx   < ww/2/zoom)
        mx := ww/2/zoom
    if(mx   > A_ScreenWidth-(ww/2/zoom))
        mx := A_ScreenWidth-(ww/2/zoom)

    if(my   < wh/2/zoom)
        my := wh/2/zoom
    if(my   > A_ScreenHeight-(wh/2/zoom))
        my := A_ScreenHeight-(wh/2/zoom)
}
; }}}
clip_size() ; Keep Zoom Window size within min-max limits {{{
{
    global


    if( ww < 0 )
       ww *= -1
    if( ww < wwMin )
       ww := wwMin
    if( ww > wwMax )
       ww := wwMax

    if( wh < 0 )
       wh *= -1
    if( wh < whMin )
       wh := whMin
    if( wh > whMax )
       wh := whMax
}
; }}}
clip_pos() ; Keep Zoom Window on screen {{{
{
    global

    if follow {                 ; Window near mouse
        wox := mx-ww/2
        woy := my-wh/2
    }
    else {                      ; Window position fixed
        wox := stickX-ww/2
        woy := stickY-wh/2
    }

    if(wox < 0)                 ; window inside screen
        wox = 0
    if(wox >  (A_ScreenWidth-ww))
        wox := A_ScreenWidth-ww
    if(woy < 0)
        woy = 0
    if(woy >  (A_ScreenHeight-wh))
        woy := A_ScreenHeight-wh
}
; }}}

RemoveToolTip: ; hide tooltips {{{
SetTimer, RemoveToolTip, Off
ToolTip

return
;=================================================================== }}}

; vim: syntax=ahk foldmethod=marker