Insert dragable and resizeable subgraphs into a graph window
This code provides a hook function which makes it possible to drag and resize subwindows in a graph with the mouse. To see how this works create a graph and execute the following:
TestAppendSubGraph(mainGraphName, plotThisWave)
This will insert a subpanel with a subgraph into the designated graph window, which can then be interacted with via the mouse. You can add as many subgraphs as you want. The subwindows are also prevented from disappearing outside the main graph area upon resizing the main graph. A minimum subwindow size is set by the subMinSize constant. The detection range for subwindow edge (i.e., where the dragging mode switches to resizing close to window edges) is controlled via the edgeDetect constant.
If you want to remove the hook and associated user data again, use:
TestRemoveHook(GraphName)
Here is the full code:
#pragma rtGlobals=3
#pragma DefaultTab={3,20,4}
function TestAppendSubGraph(string mainGName, wave plotThis)
GetWindow $mainGName, expand
variable gExpand = V_value; gExpand = gExpand == 0 ? 1 : gExpand // pixel conversion and expansion factor
variable pixConv = ScreenResolution/72*gExpand
GetWindow $mainGName psizeDC // define an initial size
variable size = max(min((V_bottom-V_top)/4,(V_right-V_left)/5),subMinSize)/pixConv
variable wL = (V_left+20)/pixConv, wT = (V_top+20)/pixConv, wR = wL+size*1.2, wB = wT+size
NewPanel/HOST=$mainGName/N=floatPanel/W=(wL,wT,wR,wB)
Display/HOST=#/FG=(FL,FT,FR,FB) plotThis
ModifyGraph frameStyle=1 // edges are easier to see with a frame
SetActiveSubwindow $mainGName
SetWindow $mainGName hook(DragUpdate)=DragHookFunction
end
function TestRemoveHook(string gName)
string subWinList = ChildWindowList(gName)
int i
for (i=0; i<ItemsInList(subWinList); i++)
SetWindow $gName userdata($StringFromList(i,subWinList))="" // remove user data from graph
endfor
SetWindow $gName userdata(dragInfo)=""
SetWindow $gName hook(DragUpdate)=$""
end
// ##################
static Constant subMinSize = 100
static Constant edgeDetect = 15
function DragHookFunction(STRUCT WMWinHookStruct &s)
string gName = StringFromList(0,s.winName,"#")
string sName = StringFromList(1,s.winName,"#")
string dragInfo = "", floatStruct = ""
int i, hookTakeOver = 0
GetWindow $gName, expand
variable gExpand = V_value; gExpand = gExpand == 0 ? 1 : gExpand // pixel conversion and expansion factor
variable pixConv = ScreenResolution/72*gExpand
variable winEdge = 0, dragEdge = 0
STRUCT DragStruct d
STRUCT rect tempRect
if (WhichListItem(s.eventName, "mousedown;mousemoved;mouseup;")>-1 && CmpStr(s.winName, gName)) // mouse events on the sub-graph
GetWindow $s.winName psizeDC
tempRect.top = v_top
tempRect.left = v_left
tempRect.right = v_right
tempRect.bottom = v_bottom
if (!CheckPointInRect(s.mouseLoc,tempRect)) // mouse is not in plot area
GetWindow $s.winName gsizeDC; winEdge = 1 // encode sub-window mouse edge detection into winEdge
winEdge = abs(s.mouseloc.h-v_left) <edgeDetect && abs(s.mouseloc.v-v_top) <edgeDetect ? 2 : winEdge // LT
winEdge = abs(s.mouseloc.h-v_right)<edgeDetect && abs(s.mouseloc.v-v_top) <edgeDetect ? 3 : winEdge // RT
winEdge = abs(s.mouseloc.h-v_left) <edgeDetect && abs(s.mouseloc.v-v_bottom)<edgeDetect ? 4 : winEdge // LB
winEdge = abs(s.mouseloc.h-v_right)<edgeDetect && abs(s.mouseloc.v-v_bottom)<edgeDetect ? 5 : winEdge // RB
endif
endif
StrSwitch(s.eventName)
case "mousedown":
if (CmpStr(s.winName, gName) && s.eventMod==1)
if (CheckPointInRect(s.mouseLoc,tempRect))
break
endif
GetWindow $gName gsizeDC
d.graphRect.top = v_top
d.graphRect.left = v_left
d.graphRect.bottom = v_bottom
d.graphRect.right = v_right
d.mouse_init = s.mouseloc
d.subwinRect = s.winrect
StructPut/S d, floatStruct
SetWindow $gName userdata($sName)=floatStruct // save info for the current subwindow
SetWindow $gName userdata(dragInfo)=num2str(winEdge)+";"+sName+";" // a list of the edge to drag and the dragged subwindow name
hookTakeOver = 1
endif
break
case "mouseup":
if (str2num(GetUserData(gName, "", "dragInfo")))
SetActiveSubwindow $gName
SetWindow $gName userdata(dragInfo)=""
endif
break
case "mousemoved":
if (winEdge)
s.cursorCode = str2num(StringFromList(winEdge,"0;8;4;11;10;7;"))
s.doSetCursor = 1 // change mouse cursor
endif
dragInfo = GetUserData(gName, "", "dragInfo")
dragEdge = str2num(StringFromList(0,dragInfo))
dragEdge = numtype(dragEdge) != 0 ? 0 : dragEdge
if (dragEdge)
GetMouse/W=$gName
if (!(V_flag & 1)) // mouse button released? => maybe we missed a mouse-up event?
SetWindow $gName userdata(dragInfo)=""
dragEdge = 0
endif
else
break
endif
sName = StringFromList(1,dragInfo)
StructGet/S d, GetUserData(gName, "", sName)
variable deltah = s.mouseloc.h - d.mouse_init.h
variable deltav = s.mouseloc.v - d.mouse_init.v
tempRect = d.subwinRect
tempRect.top += deltav * (dragEdge == 1 || dragEdge == 2 || dragEdge == 3)
tempRect.left += deltah * (dragEdge == 1 || dragEdge == 2 || dragEdge == 4)
tempRect.right += deltah * (dragEdge == 1 || dragEdge == 5 || dragEdge == 3)
tempRect.bottom += deltav * (dragEdge == 1 || dragEdge == 5 || dragEdge == 4)
string subWin = gName + "#" + sName
if (CheckRectPosAndSize(tempRect, d.graphRect) && WinType(subWin))
MoveSubwindow/W=$subWin fnum=(tempRect.left/pixConv, tempRect.top/pixConv, tempRect.right/pixConv, tempRect.bottom/pixConv)
d.subwinRect = tempRect
endif
d.mouse_init = s.mouseloc
StructPut/S d, floatStruct
SetWindow $gName userdata($sName)=floatStruct
break
case "resize":
string subWinList = ChildWindowList(gName)
if (!ItemsInList(subWinList))
break
endif
GetWindow $gName wsizeDC
int isHostMinW = abs(v_right-v_left) <= subMinSize
int isHostMinH = abs(v_bottom-v_top) <= subMinSize
for (i=0; i<ItemsInList(subWinList); i++)
sName = StringFromList(i, subWinList)
GetWindow $(gName+"#"+sName) wsizeDC
variable subW = abs(v_right-v_left)
variable subH = abs(v_bottom-v_top)
variable dW = isHostMinW ? 0 : subMinSize - subW // check if the panel width is smaller than the minimum
variable dH = isHostMinH ? 0 : subMinSize - subH
if (dW <= 0 && dH <= 0)
continue
endif
dragInfo = GetUserData(gName, "", sName)
if (strlen(dragInfo))
StructGet/S d, dragInfo
subW = abs(d.subwinRect.right -d.subwinRect.left)
subH = abs(d.subwinRect.bottom-d.subwinRect.top)
endif
tempRect.top = v_top - dH*(dH>0)
tempRect.bottom = v_top - dH*(dH>0) + subH
tempRect.left = v_left - dW*(dW>0)
tempRect.right = v_left - dW*(dW>0) + subW
MoveSubwindow/W=$(gName+"#"+sName) fnum=(tempRect.left/pixConv, tempRect.top/pixConv, tempRect.right/pixConv, tempRect.bottom/pixConv)
endfor
break
endswitch
return hookTakeOver
end
// ++++++++++++
static structure DragStruct
STRUCT point mouse_init
STRUCT Rect subwinRect
STRUCT Rect graphRect
endstructure
static function CheckRectPosAndSize(STRUCT rect &in, STRUCT rect &ref)
int isInside = (in.left>ref.left && in.top>ref.top && in.right<ref.right && in.bottom<ref.bottom)
int isMinSize = abs(in.right-in.left) >= subMinSize && abs(in.bottom-in.top) >= subMinSize
return isInside && isMinSize
end
static function CheckPointInRect(STRUCT point &pnt, STRUCT rect &ref)
return ( pnt.h>ref.left && pnt.h<ref.right && pnt.v>ref.top && pnt.v<ref.bottom )
end
Forum
Support
Gallery
Igor Pro 9
Learn More
Igor XOP Toolkit
Learn More
Igor NIDAQ Tools MX
Learn More