#pragma rtGlobals=1 // Use modern global access method. // Igor supports exterior panels that stick to the target window, but only for graphs and panels. // SyncWin extends this idea to any pair of target windows (also tables, layouts, notebooks). // To use, create two windows and install the link between them using SyncWinInstall() // To use the following example, copy+paste to virgin procedure, then decommentize (edit menu) // function SyncWinExample() // // string myPanel = "Panel0", myTable = "Table0" // Edit /N=$myTable /W=(100,50,300,150) // NewPanel /N=$myPanel /W=(150,60,350,160) // SyncWinInstall(myPanel, mainWin = myTable, anchor = "LB", killmode = 1) // // string myLayout = "Layout0", myNB = "NB0" // NewLayout /N=$myLayout /W=(200,70,400,170) // NewNotebook /F=1 /N=$myNB /W=(250,80,450,180) // SyncWinInstall(myNB, mainWin = myLayout, anchor = "TC", killmode = 2) // // string myGraph = "MyOtherGraph" // Display /N=$myGraph /W=(300,90,500,190) // Display /N=MyFirstGraph /W=(350,100,550,200) // SyncWinInstall(myGraph) // // end strconstant ksSyncWinAnchors = "LT;LC;LB;TL;TC;TR;RT;RC;RB;BL;BC;BR;" strconstant ksSyncWinDefaultAnchor = "RT" // sync will be glued to Right of main, Tops are aligned // this function just sets hooks and userdata, you need to create the sync window yourself beforehand ! // call with uninstall = 1 to kill sync window now (implies decoupling) // call with uninstall = 2 to only decouple main and sync window // call with killmode = 1 to kill sync window whenever main is killed (sync is slave to main) // call with killmode = 2 to kill main window whenever sync is killed (main is slave to sync) // call with killmode = 3 to kill either window whenever the other one is killed function SyncWinInstall(syncWin, [mainWin, anchor, uninstall, killmode]) string syncWin // name of sync window that is to move with the main window string mainWin // name of main window; if empty or missing, uses top target window string anchor // should be one of the codes in ksSyncWinAnchors (case insensitive) variable uninstall // 0 (default): install; 1: kill sync window now; 2: only decouple windows variable killmode // 0 (default): no slave-killing; 1: sync is slave; 2: main is slave; 3: both are slaves DoWindow $syncWin variable syncExists = V_Flag if( ParamIsDefault(mainWin) || strlen(mainWin) == 0 ) mainWin = StringFromList(0, WinList("*", ";", "WIN:87" )) endif DoWindow $mainWin if( syncExists && V_Flag ) uninstall = ParamIsDefault(uninstall) ? 0 : uninstall switch( uninstall ) case 0: // get proper anchor code anchor = SelectString(ParamIsDefault(anchor), anchor, ksSyncWinDefaultAnchor) variable anchorCode = WhichListItem(anchor, ksSyncWinAnchors, ";", 0, 0) anchorCode = anchorCode < 0 ? 6 : anchorCode // set dependencies in main win SetWindow $mainWin, hook(SyncWinHook) = SyncWinHook, userdata(SyncWinName) = syncWin SetWindow $mainWin, userdata(SyncWinAnchor) = StringFromList(anchorCode, ksSyncWinAnchors) if( !ParamIsDefault(killmode) && (killmode & 1) ) SetWindow $mainWin, userdata(SyncWinKill) = "1" else SetWindow $mainWin, userdata(SyncWinKill) = "0" endif // set dependencies in sync win SetWindow $syncWin, hook(SyncWinHook) = SyncWinHook, userdata(SyncWinName) = mainWin SetWindow $syncWin, userdata(SyncWinAnchor) = StringFromList(mod(anchorCode+6,12), ksSyncWinAnchors) if( !ParamIsDefault(killmode) && (killmode & 2) ) SetWindow $syncWin, userdata(SyncWinKill) = "1" else SetWindow $syncWin, userdata(SyncWinKill) = "0" endif // do the initial sync move manually SyncWinMove(mainWin, syncWin, anchor) break case 1: // kill sync window now // variable killMain = str2num(GetUserData(syncWin, "", "SyncWinKill")) DoWindow /K $syncWin // if( killMain ) // shouldn't this be done by the hook function? what if it is? // DoWindow /K $mainWin // endif break case 2: // only decouple sync from main and vice versa SyncWinDecouple(mainWin) SyncWinDecouple(syncWin) endswitch endif end // auxiliary function to make window "normal" again function SyncWinDecouple(win) string win SetWindow $win, hook(SyncWinHook) = $"" SetWindow $win, userdata(SyncWinName) = "" SetWindow $win, userdata(SyncWinAnchor) = "" SetWindow $win, userdata(SyncWinKill) = "" SetWindow $win, userdata(SyncWinMoved)= "" end // this hook will be installed by SyncWinInstall(); it is used for both, main and sync windows function SyncWinHook(s) struct WMWinHookStruct &s variable rVal = 0 string mainWin = s.winName string syncWin = GetUserData(mainWin, "", "SyncWinName") switch( s.eventCode ) case 2: // main window is about to be killed DoWindow $syncWin // check sync's existence if( V_Flag ) variable killSync = str2num(GetUserData(mainWin, "", "SyncWinKill")) if( killSync ) // kill sync window if so instructed upon install DoWindow /K $syncWin else // remove dependencies in sync window SyncWinDecouple(syncWin) endif endif break case 6: // "resize" case 12: // "moved" variable induced = strlen(GetUserData(mainWin, "", "SyncWinMoved")) if( induced ) // called because the sync window was sync-moved, avoid recursion! SetWindow $mainWin, userdata(SyncWinMoved) = "" else // called due to genuine user move SyncWinMove(mainWin, syncWin, GetUserData(mainWin, "", "SyncWinAnchor")) SetWindow $syncWin, userdata(SyncWinMoved) = "yes" DoWindow/F $syncWin // make sync win visible endif break endswitch return rVal end // this keeps the windows aligned, will be called by SyncWinHook() function SyncWinMove(mainWin, syncWin, anchor) string mainWin, syncWin, anchor DoWindow $syncWin // check sync's existence variable syncExists = V_Flag DoWindow $mainWin // check main's existence if( V_Flag && syncExists && WhichListItem(anchor, ksSyncWinAnchors, ";", 0, 0) >= 0 ) GetWindow $mainWin, wsize // coords of main window without titlebar and frames variable mL = V_left, mT = V_top, mR = V_right, mB = V_bottom GetWindow $mainWin, wsizeOuter // coords of main window including titlebar and frames variable horFrame = V_right - V_left + mL - mR, vertFrame = V_bottom - V_top + mT - mB GetWindow $syncWin, wsize // without titlebar and frame variable width = V_right - V_left, height = V_bottom - V_top variable left, top strswitch( UpperStr(anchor[0]) ) case "L": left = mL - horFrame - width // fall through case "R": strswitch( UpperStr(anchor[1]) ) case "T": top = mT break case "C": top = (mT + mB - height) / 2 break case "B": top = mB - height endswitch if( !cmpstr(anchor[0], "R") ) // stop fall through left = mR + horFrame endif break case "T": top = mT - vertFrame - height // fall through case "B": strswitch( UpperStr(anchor[1]) ) case "L": left = mL break case "C": left = (mL + mR - width) / 2 break case "R": left = mR - width endswitch if( !cmpstr(anchor[0], "B") ) // stop fall through top = mB + vertFrame endif endswitch endif MoveWindow /W=$syncWin left, top, left + width, top + height end