Reisze GUI Control using only the mouse

Post your working scripts, libraries and tools
MJs
Posts: 454
Joined: 23 Sep 2014, 03:29

Reisze GUI Control using only the mouse

13 Nov 2015, 10:32

simply put: most AHK GUI creators if not all (that I've seen) don't add a sizing and moving method with the mouse only without the need for Ctrl or Shift like resource editors, with blocks on the edges to resize the selected control, this is just a simple script that does just that.
this is not a GUI creator. there is a good one here http://autohotkey.com/boards/viewtopic.php?f=6&t=10157 by Alguimist. it's a full fledged one, and there are more, so there is no need to reinvent the wheel.

Code: Select all

#NoEnv
OnExit, Terminate

PicSize := 5 ; set the resing border size: width and height
ResizeColor		 := DllCall("User32.dll\GetSysColor", "Int", 13, "UInt") ; COLOR_HIGHLIGHT:=13
ResizeColorBrush := DllCall("Gdi32.dll\CreateSolidBrush", "UInt", ResizeColor, "UPtr")

OnMessage(0x138, "WM_CTLCOLORSTATIC")	; to set the resizing static control's color
OnMessage(0x020, "WM_SETCURSOR") 		; change the cursor
OnMessage(0x201, "WM_LBUTTONDOWN")		; set the resizing borders and moving the controls
OnMessage(0x204, "WM_RBUTTONDOWN")		; set the resizing borders on right click
OnMessage(0x007, "WM_SETFOCUS")			; no focus for our controls
OnMessage(0x200, "WM_MOUSEMOVE")		; in order not to change buttons style (state) or edit control when the mouse moves over them
OnMessage(0x100, "WM_KEYDOWN")			; no selecting child controls using TAB

SS_NOTIFY:=0x0100 ; static controls must have this style so that they get treated using WM_SETCURSOR, without this style, wParam=hWnd in WM_SETCURSOR func
WS_CLIPSIBLINGS:=0x04000000 ; Clips child windows relative to each other: combined with WinSet, Top; always the selected control is ontop off all  others
ControlsList :=[] ; added controls

Controls:="Text,Edit,UpDown,Picture,Button,Checkbox,Radio,DropDownList,ComboBox,ListBox,ListView,TreeView,Link,Hotkey,DateTime,MonthCal,Slider,Progress,GroupBox,Tab2,StatusBar"
Loop, Parse, Controls, csv
	Menu, Controls2Add, Add, %A_LoopField%, AddControl
Menu, FileMenu, Add, Copy`tCtrl+C, CopyControls
Menu, FileMenu, Add
Menu, FileMenu, Add, Exit`tCtrl+X, GuiClose

Gui, +resize +hWndhMainwin

Loop, 8
{
	Gui, Add, Text, x0 y20 w%PicSize% h%PicSize% vSResize%A_Index% hWndhSResize%A_Index% gOnMoveMakeThemMove Hidden
	SResizeHANDLES .= hSResize%A_Index% ","
}
SResizeHANDLES := trim(SResizeHANDLES, ",") ; for selecting controls using tab
;{ set the cursor for each control
 ; we need the next 5 cursors only
;IDC_SIZENWSE      = 32642  Double-pointed arrow pointing northwest and southeast
;IDC_SIZENS        = 32645  Double-pointed arrow pointing north and south
;IDC_SIZENESW      = 32643  Double-pointed arrow pointing northeast and southwest
;IDC_SIZEWE        = 32644  Double-pointed arrow pointing west and east
;IDC_SIZEALL       = 32646  Four-pointed arrow pointing north, south, east, and west

;IDC_APPSTARTING   = 32650  Standard arrow and small hourglass
;IDC_ARROW         = 32512  Standard arrow
;IDC_CROSS         = 32515  Crosshair
;IDC_HAND          = 32649  Hand
;IDC_HELP          = 32651  Arrow and question mark
;IDC_IBEAM         = 32513  I-beam
;IDC_ICON          = 32641  Obsolete for applications marked version  = 4.0 or later.
;IDC_NO            = 32648  Slashed circle
;IDC_SIZE          = 32640  Obsolete for applications marked version  = 4.0 or later. Use IDC_SIZEALL.
;IDC_UPARROW       = 32516  Vertical arrow
;IDC_WAIT          = 32514  Hourglass
;}
SizingCursor:={(hSResize1):32642, (hSResize2):32645, (hSResize3):32643, (hSResize4):32643, (hSResize5):32645, (hSResize6):32642,(hSResize7):32644, (hSResize8):32644}

Menu, ControlsMenu, Add, File, :FileMenu
Menu, ControlsMenu, Add, Controls, :Controls2Add
Gui, Menu, ControlsMenu
Gui, show, w400 h400, Resize Controls using Mouse
Return

OnMoveMakeThemMove: ;{
CoordMode, mouse, client
Gui, %A_Gui%:+LastFound
hWin:=WinExist("")
MouseGetPos, omx, omy ;, W_hWnd_Temp ; get the window under the mouse handle and position
GuiControlGet, oc, %A_Gui%:pos, %conUnderMouse%     ; the current window position
ncx:=ncy:=ncw:=nch:=0

Sizing:=true

VarSetCapacity(rect, 16, 0)
HDC := DllCall("User32.dll\GetDC", "Ptr", hWin, "UPtr")

	 if (A_GuiControl="SResize1") {		; x+y+w+h
	while GetKeyState("Lbutton", "P") {
		MouseGetPos, mx, my
		nch:=och-(my-ocy)
		ncw:=ocw-(mx-ocx)
		if (mx=omx) ; prevent flicker: redrawing the rect focus
			continue
		DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT)
		SetRect(rect, mx, my, ncw+mx, nch+my)
		DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT)
		omx:=mx
	}
	ncx:=mx, ncy:=my
}
else if (A_GuiControl="SResize2") {		; y+h
	
	while GetKeyState("Lbutton", "P") {
		MouseGetPos, mx, my
		nch:=och-(my-ocy)
		if (omy=my)
			continue
		DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT)
		SetRect(rect, ocx-1, my, ocw+ocx+1, my+nch+1)
		DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT)
		omy:=my
	    }
		ncx:=ocx, ncy:=my,  ncw:=ocw
}
else if (A_GuiControl="SResize3") {		; y+w+h
	while GetKeyState("Lbutton", "P") {
		MouseGetPos,mx,my
		nch:=och-(my-ocy)
        ncw:=mx-ocx+PicSize
		if (mx=omx) ; prevent flicker: redrawing the rect focus
			continue
		DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT)
		SetRect(rect, ocx-1, my-1, ncw+ocx+1, nch+my+1)
		DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT)
		omx:=mx
	    }
	ncx:=ocx, ncy:=my
}
else if (A_GuiControl="SResize4") {		; x+w+h
	while GetKeyState("Lbutton", "P") {
		MouseGetPos, mx, my
		nch:=ocy+(my-ocy)
		ncw:=ocw-(mx-ocx)
		if (mx=omx) ; prevent flicker: redrawing the rect focus
			continue
		DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT)
		SetRect(rect, mx, ocy, ncw+mx, nch)
		DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT)
		omx:=mx
	}
	ncx:=mx, ncy:=ocy, nch:=nch-ocy
}
else if (A_GuiControl="SResize5") {		; h
	while GetKeyState("Lbutton", "P") {
		MouseGetPos, mx, my
		nch:=ocy+(my-ocy)
		if (omy=my)
			continue
		DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT)
		SetRect(rect, ocx, ocy, ocw+ocx-2, nch)
		DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT)
		omy:=my		
	    }
		ncx:=ocx, ncy:=ocy,  ncw:=ocw, nch:=nch-ocy
}
else if (A_GuiControl="SResize6") {		; w+h
	while GetKeyState("Lbutton", "P") {
		MouseGetPos, mx, my
		nch:=ocy+(my-ocy)
		ncw:=ocx+(mx-ocx)
		if (nch=och) && (ncw=ocw) ; prevent flicker: redrawing the rect focus
			continue
		DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT)
		SetRect(rect, ocx, ocy, ncw, nch)
		DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT)
		och:=nch,ocw:=ncw
	}
	ncx:=ocx, ncy:=ocy, nch:=nch-ocy, ncw:=ncw-ocx
}
else if (A_GuiControl="SResize7") {		; x+w
	
	while GetKeyState("Lbutton", "P") {
        MouseGetPos, mx
        ncw:=ocw-(mx-ocx)
		if (mx=omx) ; prevent flicker: redrawing the rect focus
			continue
		DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT)
		SetRect(rect, mx, ocy, ncw+mx, och+ocy)
		DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT)
		omx:=mx
	}
	ncx:=mx, ncy:=ocy, nch:=och
}
else if (A_GuiControl="SResize8") {		; w
    while GetKeyState("Lbutton", "P") {
        MouseGetPos, mx
        ncw:=ocw - (omx-mx)
		if (ncw=oldncw) ; prevent flicker: redrawing the rect focus
			continue
		DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT)
		SetRect(rect, ocx,ocy,ncw+ocx, och+ocy)
		DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT)
		oldncw:=ncw
	    }
	ncx:=ocx, ncy:=ocy, nch:=och
}

DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT) ; Because DrawFocusRect is an XOR function, calling it a second time with the same rectangle removes the rectangle from the screen
DllCall("User32.dll\ReleaseDC", "Ptr", hWin, "Ptr", HDC)
Sizing:=false
MouseGetPos, mx, my
if (mx!=omx) || (my!=omy) ; eliminate sizing|moving the control if only click
{
	newpos := "x" ncx "y" ncy "w" ncw "h" nch
	GuiControl, MoveDraw, %conUnderMouse%, % newpos
	gosub, SetControlForSizing ; move the resizing borders to the new location of the control
}
return
;}
SetControlForSizing: ;{

GuiControlGet, con, pos,  %conUnderMouse%

GuiControl, movedraw, SResize1, % "x" conx-PicSize  "y" cony-PicSize
GuiControl, MoveDraw, SResize2, % "x" conx+((conw-PicSize)/2) " y" cony-PicSize
GuiControl, MoveDraw, SResize3, % "x" conx+conw " y" cony-PicSize

GuiControl, MoveDraw, SResize4, % "x" conx-PicSize "y" cony+conh
GuiControl, MoveDraw, SResize5, % "x" conx+((conw-PicSize)/2) " y"  cony+conh
GuiControl, MoveDraw, SResize6, % "x" conx+conw "y" cony+conh

GuiControl, MoveDraw, SResize7, % "x" conx-PicSize "y" cony+((conh-PicSize)/2)
GuiControl, MoveDraw, SResize8, % "x" conx+conw  "y" cony+((conh-PicSize)/2)

Loop, 8
	GuiControl, show, SResize%A_Index%
return
;}

WM_RBUTTONDOWN(wParam, lParam, Msg, hWnd) { ; select control if there is one
		global conUnderMouse
MouseGetPos,,,, c, 2 ; old mouse move x,y. and to eliminate our resizing controls
GuiControlGet, s, %A_Gui%:Name, %c%

if !c ; there is no control under the mouse
	Loop, 8
		GuiControl, hide, SResize%A_Index%
else if !(s~="i)SResize[1-8]"){
	conUnderMouse := c
	WinSet, Top,, ahk_id %conUnderMouse% ; the selected child widow on top of the z-order, to always be redrawn on top
	gosub, SetControlForSizing
	return, 0
}

}
WM_LBUTTONDOWN(wParam, lParam, Msg, hWnd) { ; select and move control on mouse move
	global conUnderMouse, hMainwin, onTheMove, PicSize
VarSetCapacity(rect, 16)
MouseGetPos, ommx ,ommy , win, c, 2 ; old mouse move x,y. and to eliminate our resizing controls
GuiControlGet, s, %A_Gui%:Name, %c%

if !c ; there is no control under the mouse
	Loop, 8
		GuiControl, hide, SResize%A_Index%

else if !(s~="i)SResize[1-8]"){ ; the control isn't one of our sizing ones
	conUnderMouse := c
	WinSet, Top,, ahk_id %conUnderMouse% ; the selected child widow on top of the z-order, to always be redrawn on top
	gosub, SetControlForSizing
	GuiControlGet, con, %A_Gui%:pos,  %conUnderMouse%
	GetClientSize(win, ww, wh) ; neede for out of client area pos
	onTheMove:=true
	VarSetCapacity(RECT, 16, 0)
	;GuiControl, %A_Gui%:-Redraw, %conUnderMouse% ; if moving create an undesired redrawing problems
	HDC := DllCall("User32.dll\GetDC", "Ptr", hMainwin, "UPtr")
	MouseGetPos, mmxx, mmyy ; to prevent non moving control from coming fully in client area even without use moving the mouse
	nx:=ny:=""
	while GetKeyState("Lbutton", "P") {
		MouseGetPos, mmx, mmy
		if !(mmx=mmxx && mmy=mmyy){ ; only if the mouse's moved, 
			; to NOT prevent controls from going out of the  client area ucomment the next line
			; nx:=conx+(mmx-ommx), ny:=cony+(mmy-ommy)
			
			; to prevent contols from going out of the client area
			; comment the next two lines if that's not desired
			nx := (nx:=conx+(mmx-ommx))<0 ? 0: (nx+conw)>ww ? ww-conw : nx
			ny := (ny:=cony+(mmy-ommy))<0 ? 0: (ny+conh)>wh ? wh-conh : ny
			
			; to keep all the resizing borders visible, instead of the previous two lines use the next two
			;nx := (nx:=conx+(mmx-ommx))<PicSize ? PicSize: (nx+conw)>ww ? ww-conw-PicSize : nx
			;ny := (ny:=cony+(mmy-ommy))<PicSize ? PicSize: (ny+conh)>wh ? wh-conh-PicSize : ny
			
			; or you can set based on the GUI Margins, MUST SET THE GuiMargin VARIABLE
			;nx := (nx:=conx+(mmx-ommx))<GuiMargin ? GuiMargin: (nx+conw)>ww ? ww-conw-GuiMargin : nx
			;ny := (ny:=cony+(mmy-ommy))<GuiMargin ? GuiMargin: (ny+conh)>wh ? wh-conh-GuiMargin : ny
			
			DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT)
			SetRect(RECT, nx, ny, nx+conw, ny+conh)
			DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT)
			mmxx:=mmx, mmyy:=mmy
		}
	}
	;GuiControl, %A_Gui%:+Redraw, %conUnderMouse%
	if !(nx="") ; explicitly an EMPTY STRING: we just clicked over the control, no drag
		GuiControl, MoveDraw, %conUnderMouse%, % "x" nx " y" ny
	onTheMove:=false
	DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT) ; Because DrawFocusRect is an XOR function, calling it a second time with the same rectangle removes the rectangle from the screen
	DllCall("User32.dll\ReleaseDC", "Ptr", hMainwin, "Ptr", HDC)
	gosub, SetControlForSizing
	return, 0
}

}
WM_SETCURSOR(wParam, lParam, Msg, hWnd) { ; set the cursor to indicate the state for moving resizing and what direction
; change the mouse to indicate a movable control
; wParam: handle to the window that contains the cursor, given that the mouse isn't captured
; if the mouse were to be captured, it's better using MouseGetPos
Global SizingCursor, Sizing, onTheMove
static CurrentCursorControl, hCursor

if Sizing{
	DllCall("SetCursor", "uint", hCursor)
	return, true
}

if SizingCursor[wParam]{ ; get the sizing cursor style
	hCursor := DllCall("LoadCursor", "uint", 0, "uint", SizingCursor[wParam]) ;IDC_SIZEWE=32644, IDC_SIZENS=32645
	DllCall("SetCursor", "uint", hCursor)
	CurrentCursorControl:=wParam
	return true
}
if (wParam!=hWnd)||onTheMove{ ; a control other than the window and the sizing borders, or we're moving a control
	hCursor := DllCall("LoadCursor", "uint", 0, "uint", 32646) ; IDC_SIZEALL:=32646 : Four-pointed arrow pointing north, south, east, and west
	DllCall("SetCursor", "uint", hCursor)
	CurrentCursorControl:=wParam
	return true
}
}
WM_CTLCOLORSTATIC(wParam, lParam) {
	global  StaticTextBackgroundColor, ResizeColorBrush
	Critical 50
	GuiControlGet, s, %A_Gui%:Name, %lParam%
	if (s~="i)SResize[1-8]"){ ; only our 8 static controls so we don't change other controls background
		DllCall("SetBkColor", UInt, wParam, UInt, StaticTextBackgroundColor)
		return ResizeColorBrush  ; Return the HBRUSH to notify the OS that we altered the HDC.
	}
}
WM_SETFOCUS(){
return, 0
}
WM_MOUSEMOVE() {
	return, 0 ; in order not to change controls state. button'ss style changes on mouse move, edit controls also, headers....
}
WM_KEYDOWN(wParam, lParam, Msg, hWnd) {
	global conUnderMouse, SResizeHANDLES, hSResize1
	;return, 0 ; no keys
if (wParam=9){ ; tab
	Loop, parse, SResizeHANDLES, csv
		WinSet, Top,, ahk_id %A_LoopField% ; set the resizing border to the top of the z-order, so that they donot  interfere with our window's added controls(real controls)
		
	if conUnderMouse is not integer
		ControlGet, conUnderMouse, hWnd,, %conUnderMouse%, ahk_id %hWnd%
	; one thing to notice is that the Z-Order changes based of the last control tha
	if !conUnderMouse:=DllCall("GetWindow", "Ptr", conUnderMouse, "uint", 2) ; GW_HWNDNEXT:=2 : get next control
		if !conUnderMouse := DllCall("GetWindow", "Ptr", hSResize1, "uint", 2) ; GW_HWNDNEXT:=2 : get the first control after our resizig
			return 0
	
	gosub, SetControlForSizing
}
return, 0 ; no keys
}

SetRect(byref rect, x,y,w,h){ ; just a simple helper function
DllCall("SetRect", "Ptr", &RECT, "UInt", x, "UInt", y, "UInt", w, "UInt", h)
}
GetClientSize(hwnd, ByRef wr, ByRef hr) { ;client area excludes the window's borders, title bar, and menu bar
    VarSetCapacity(rc, 16)
    DllCall("GetClientRect", "uint", hwnd, "uint", &rc)
    wr := NumGet(rc, 8, "int")
    hr := NumGet(rc, 12, "int")
}

AddControl:   ;{
c := A_ThisMenuItem
GetClientSize(hMainwin, ww, wh)
try  Gui, Add, %c%, hWndconUnderMouse Hidden %WS_CLIPSIBLINGS%, %c%
	catch e	{ ; might be error sometimes, (e.g second statusbar)
		MsgBox, 0, error, % "Error Adding the control:`n" e.Message
		return
	}

GuiControlGet, cpos, pos, %conUnderMouse%
ControlsList[conUnderMouse] :=  c

cposw := cposw<50 ? 50 : cposw
cposh := cposh<50 ? 50 : cposh
GuiControl, Move, %conUnderMouse%, % "x" (ww-cposw)//2 " y" (wh-cposh)//2 " w" cposw " h"  cposh
if (c~="i)Picture|Text")
	GuiControl, +%SS_NOTIFY%, %c%
GuiControl, Show, %conUnderMouse%
addedcontrol:=true
gosub, SetControlForSizing
return
;}
CopyControls: ;{
addedcontrol:=txt := ""
for hwnd, ctl in ControlsList
{
	GuiControlGet, c, pos, %hwnd%
	txt .= "Gui, Add, " ctl ", x" cx " y" cy " w" cw " h" ch ", " ctl "`r`n"
}
GetClientSize(hMainwin, ww, wh)
txt=
(
%txt%Gui, Show, w%ww% h%wh%, GUI Controls
return
GuiEscape:
GuiClose:
ExitApp
)
Clipboard := trim(txt, "`n")
return
;}
GuiClose:
GuiEscape:
ExitApp

Terminate: ;{
if addedcontrol{

MsgBox, 8227, save, you have added controls without saving`nwould you like to copy the gui?
IfMsgBox, Yes
	gosub, CopyControls
else IfMsgBox, Cancel
	return
}
ExitApp
return
;}
guest3456
Posts: 2941
Joined: 09 Oct 2013, 10:31

Re: Reisze GUI Control using only the mouse

14 Nov 2015, 03:38

the 'preview' rectangle when moving or resizing is not accurate for me on win8.1 at 125% scaling

but overall this is very well done

MJs
Posts: 454
Joined: 23 Sep 2014, 03:29

Re: Reisze GUI Control using only the mouse

15 Nov 2015, 16:35

first:
it's just a simple example or somewhat a concept for the Gui Creators that I'm more than happy for them to use it and integrate it to their code, I already asked Alguimist if he could implement it
Alguimist wrote:Let's see what can be done.
guest3456 wrote:the 'preview' rectangle when moving or resizing is not accurate for me on win8.1 at 125% scaling
thanks. And I didn't make a note of that in my OP but: no DPI based calculations or consideration.
but it shouldn't be so hard to add, I'll see about it

@TheDewd:
TheDewd wrote: You've probably already considered this, but try to incorporate a ToolTip to display the X & Y coordinates as well as Height and Width.
actually I didn't, as in my introduction and my intention: it's only for GUI Creators to consider using the code for adding a simple resizing and moving for their created controls.
for example: navigatin with tabulation, I added it in a hurry after I started writing the OP, even menu bar for adding controls. first it was a pre-added controls, just for demonstration

but you can add:

Code: Select all

ToolTip, % "x:" NumGet(RECT, 0)  " y:" NumGet(RECT, 4) " w:" NumGet(RECT, 8)-NumGet(RECT, 0) " h:" NumGet(RECT, 12)-NumGet(RECT, 4)
in OnMoveMakeThemMove after each DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT) that is after a SetRect(rect, in all 8 while GetKeyState("Lbutton", "P")
something like this

Code: Select all

	
SetRect(rect, .....) ; this changes based  on which part is being dragged
DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT)
ToolTip, % "x:" NumGet(RECT, 0)  " y:" NumGet(RECT, 4) " w:" NumGet(RECT, 8)-NumGet(RECT, 0) " h:" NumGet(RECT, 12)-NumGet(RECT, 4)
for WM_LBUTTONDOWN handler and since the Width and Height don't change.
change this:

Code: Select all

SetRect(RECT, nx, ny, nx+conw, ny+conh)
DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT)
to this:

Code: Select all

SetRect(RECT, nx, ny, nx+conw, ny+conh)
DllCall("User32.dll\DrawFocusRect", "Ptr", HDC, "Ptr", &RECT)
ToolTip, % "x:" NumGet(RECT, 0)  " y:" NumGet(RECT, 4) " w:" conw  " h:" conh
these are a simple hacks, even though I would advise using Alguimist AutoGUI since all this code presents is a way to resize and move controls in the gui client area, you'd notice more short comings than that. it's main objective is resizing moving with indicators of the control's state
elmo
Posts: 92
Joined: 09 Oct 2013, 09:08

Re: Reisze GUI Control using only the mouse

17 Jan 2017, 17:55

MJs,
First ... wow ... this is really well done and a great idea.

I am wondering whether you have continued to improve it since last year. If not, that is cool and your most excellent work has already put me way ahead of the curve.

If yes, I for one, am keenly interested in your latest and I would assume there are others.

Thank you in advance for your time and attention.

Return to “Scripts and Functions”

Who is online

Users browsing this forum: Kellyzkorner_NJ, Meow and 46 guests