Cycle Send Plugins
This is a variation of the brilliant script by @samuel_henriques to open the plugins of a send. This modified script cycles through the sends on a track. Because the target windows of the plugins are disabled, cycling will leave the plugins open on the screen. It skips inactive sends.
sf.ui.proTools.appActivate();
sf.ui.proTools.invalidate();
function getSelectedSendIndex() {
sf.ui.proTools.invalidate();
const outputWin = sf.ui.proTools.mainTrackOutputWindow;
const outputViewSelector = outputWin.buttons.whoseTitle.is("Output View selector").first;
// Check if a send is currently open and convert letter to a numeric index
if (outputWin.exists && outputViewSelector.value.invalidate().value.startsWith("send")) {
const sendLetter = outputViewSelector.value.value.replace("send ", "").toLowerCase();
const sendIndex = sendLetter.charCodeAt(0) - 96; // Convert 'a' to 1, 'b' to 2, ..., 'j' to 10
return sendIndex;
} else {
// Start from the first send if no send is open
return 0; // Return 0 to indicate no send is currently open
}
}
try {
let origTrack = sf.ui.proTools.selectedTrack.normalizedTrackName;
// Determine the current or next send slot to open
let currentSendSlot = getSelectedSendIndex();
let nextSendSlot = (currentSendSlot === 0) ? 1 : (currentSendSlot < 10 ? currentSendSlot + 1 : 1);
// Find the next active or assigned send, looping if necessary
let foundActiveSend = false;
for (let i = 0; i < 10; i++) { // Limit to 10 iterations
const sendButton = sf.ui.proTools.selectedTrack.sendSelectorButtons[nextSendSlot - 1];
if (sendButton.value.value !== "unassigned" && !sendButton.invalidate().value.value.startsWith("inactive")) {
foundActiveSend = true;
break;
}
// Increment send slot and wrap around if necessary
nextSendSlot = nextSendSlot < 10 ? nextSendSlot + 1 : 1;
}
if (foundActiveSend) {
// Toggle send to show it
sf.ui.proTools.selectedTrack.trackSendToggleShow({
sendNumber: nextSendSlot,
});
// Navigate to the return track for the active send slot
sf.ui.proTools.selectedTrack.trackSendGotoReturn({
sendNumber: nextSendSlot,
});
const returnTrack = sf.ui.proTools.selectedTrackHeaders[0];
// Open insert plugins on the aux return track
openInsertWin(returnTrack, ["a", "b", "c", "d", "e", "f", "g", "h", "i", "j"]);
// Return to the original track
sf.app.proTools.selectTracksByName({
trackNames: [origTrack],
});
} else {
sf.interaction.notify({
title: "No Active Sends",
message: "No active or assigned sends were found.",
});
}
} catch (error) {
sf.interaction.notify({
title: "Error processing sends",
message: error.message,
});
}
function getInsertWin(track, insertChar) {
const trackName = track.normalizedTrackName;
return sf.ui.proTools.windows.whoseTitle.startsWith('Plug-in:').filter(w => {
if (w.popupButtons.whoseTitle.is('Track Selector').first.value.value !== trackName) return false;
if (w.popupButtons.whoseTitle.is('Insert Position selector').first.value.value !== insertChar) return false;
return true;
})[0];
}
function openInsertWin(track, inserts) {
const insertChars = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j'];
for (let i = 0; i < inserts.length; i++) {
const insertN = insertChars.indexOf(inserts[i]);
if (!track.insertButtons[insertN].invalidate().exists) continue;
if (track.insertButtons[insertN].value.value === "unassigned" || track.insertSelectorButtons[insertN].invalidate().value.value.startsWith("inactive")) continue;
let pluginWin = getInsertWin(track, inserts[i]);
if (!pluginWin) {
track.insertButtons[insertN].elementClick();
while (true) {
pluginWin = getInsertWin(track, inserts[i]);
if (pluginWin) break;
sf.wait({ intervalMs: 100 });
}
const targetBtn = pluginWin.buttons.whoseTitle.is('Target button').first;
targetBtn.elementClick(); // Disable target mode
}
}
}
Linked from:
- AAdam Lilienfeldt @Adam_Lilienfeldt
Stumbled upon this post and thought I'd share my version of a similar thing.
I've tried to build it as robust as possible to deal with any edge cases (multiple send windows open, return tracks hidden inside a closed folder track etc).I suspect this can be done a bit simpler, but writing this script has been an exciting learning curve for me!
It's probably a bit overkill, but I do find it very useful to my workflow.The script is referencing two helper scripts:
- one to arrange the windows it opens
- one to close all floating and docked windows).
I'll post those below as well.
Hopefully it's still easy enough to piece together - they could easily be integrated into the main script. I've just done it this way because I use these functions repeatedly in many of my scripts.
sf.ui.useSfx(); // Debug configuration const DEBUG_MODE = false; function debugLog(message) { if (DEBUG_MODE) { log(message); } } const INSERT_CHARS = ['a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j']; // Global state to remember the last used send for each track if (!globalState["lastUsedSends"]) { globalState["lastUsedSends"] = {}; } // Plugin window caching let pluginWindowCache = null; let cacheTimestamp = 0; const CACHE_DURATION = 500; // Track which folder we opened so we can close it later let openedFolderName = null; // ===== TRACK EXISTENCE & VISIBILITY FUNCTIONS ===== /** * Check if a track exists in the session (works even when hidden in folders) */ function trackExists(trackName) { try { const allTracks = sf.app.proTools.tracks.invalidate().allItems.map(track => track.name); return allTracks.includes(trackName); } catch (error) { debugLog("trackExists error: " + error.message); return false; } } /** * Check if a track is visible in the current view */ function isTrackVisible(trackName) { const visibleNames = sf.ui.proTools.sfx.visibleTrackHeaders.map(t => t.normalizedTrackName); return visibleNames.includes(trackName); } /** * Try to open a folder track */ function tryOpenFolder(folderTrack) { try { folderTrack.folderTrackSetOpen({ targetValue: "Enable" }); return true; } catch (e) { return false; } } /** * Try to close a folder track by name */ function closeFolderByName(folderName) { if (!folderName) return false; try { const folderTrack = sf.ui.proTools.sfx.visibleTrackHeaders.filter(t => t.normalizedTrackName === folderName )[0]; if (folderTrack) { folderTrack.folderTrackSetOpen({ targetValue: "Disable" }); debugLog(`Closed folder: ${folderName}`); return true; } } catch (e) { debugLog(`Error closing folder ${folderName}: ${e.message}`); } return false; } /** * Attempt to make a track visible by opening its parent folder * Sets openedFolderName if a folder was opened */ function ensureTrackVisible(trackName) { if (!trackExists(trackName)) { return { success: false, reason: 'track_not_exists' }; } if (isTrackVisible(trackName)) { return { success: true, reason: 'already_visible' }; } debugLog(`Track "${trackName}" exists but not visible - searching folders...`); const visibleHeaders = sf.ui.proTools.sfx.visibleTrackHeaders; const folderTracks = visibleHeaders.filter(t => { const titleMatch = t.title.value.match(/ - (.*)$/); const trackType = titleMatch ? titleMatch[1].trim().toLowerCase() : ''; return trackType.includes('folder'); }); for (const folder of folderTracks) { const folderName = folder.normalizedTrackName; if (tryOpenFolder(folder)) { sf.ui.proTools.sfx.invalidate(); if (isTrackVisible(trackName)) { debugLog(`Found "${trackName}" inside folder "${folderName}"`); openedFolderName = folderName; // Track which folder we opened return { success: true, reason: 'folder_opened', folderName: folderName }; } } } return { success: false, reason: 'not_found_in_folders' }; } /** * Navigate to a send's return track, handling hidden folders and sidechains */ function goToSendReturn(track, sendNumber) { const origTrackName = track.normalizedTrackName; // First attempt try { track.trackSendGotoReturn({ sendNumber: sendNumber }); const returnTrack = sf.ui.proTools.sfx.selectedTrack; const returnTrackName = returnTrack.normalizedTrackName; if (returnTrackName !== origTrackName) { debugLog(`Direct navigation successful: ${returnTrackName}`); return { success: true, reason: 'direct', returnTrack: returnTrack, returnTrackName: returnTrackName }; } } catch (e) { debugLog(`First attempt failed: ${e.message}`); } // Get the send destination name from the send button const sendButton = track.sendButtons[sendNumber - 1]; const sendDestination = sendButton.value.value; debugLog(`Send ${sendNumber} destination: "${sendDestination}"`); if (!sendDestination || sendDestination === "unassigned") { return { success: false, reason: 'unassigned' }; } // Check if a track with this name exists if (!trackExists(sendDestination)) { debugLog(`No track named "${sendDestination}" - this is a sidechain`); return { success: false, reason: 'sidechain' }; } // Track exists - try to make it visible debugLog(`Track "${sendDestination}" exists - ensuring visibility...`); const visibilityResult = ensureTrackVisible(sendDestination); if (!visibilityResult.success) { debugLog(`Could not make "${sendDestination}" visible: ${visibilityResult.reason}`); return { success: false, reason: 'could_not_reveal', trackName: sendDestination }; } // Now try again - re-select original track first try { sf.app.proTools.selectTracksByName({ trackNames: [origTrackName] }); track = sf.ui.proTools.sfx.selectedTrack; track.trackSendGotoReturn({ sendNumber: sendNumber }); const returnTrack = sf.ui.proTools.sfx.selectedTrack; const returnTrackName = returnTrack.normalizedTrackName; if (returnTrackName !== origTrackName) { debugLog(`Navigation successful after opening folder: ${returnTrackName}`); return { success: true, reason: 'after_folder_open', returnTrack: returnTrack, returnTrackName: returnTrackName }; } } catch (e) { debugLog(`Second attempt failed: ${e.message}`); } // Still failed - select it manually try { sf.app.proTools.selectTracksByName({ trackNames: [sendDestination] }); const returnTrack = sf.ui.proTools.sfx.selectedTrack; debugLog(`Manually selected: ${sendDestination}`); return { success: true, reason: 'manual_select', returnTrack: returnTrack, returnTrackName: sendDestination }; } catch (e) { debugLog(`Manual selection failed: ${e.message}`); return { success: false, reason: 'all_attempts_failed' }; } } // ===== TRACK HEIGHT FUNCTIONS ===== function getCurrentTrackHeightName(track) { try { const trackOptionsPopup = track.getFirstWithTitle("Track Options"); const popupMenuItems = trackOptionsPopup.popupMenuFetchAllItems().menuItems; const currentHeight = popupMenuItems.find(mi => mi.element.isMenuChecked); return currentHeight ? currentHeight.path.slice(-1)[0] : null; } catch (error) { debugLog("Error getting current track height: " + error.message); return null; } } function setTrackHeight(track, heightName) { try { const trackOptionsPopup = track.getFirstWithTitle("Track Options"); const popupMenuItems = trackOptionsPopup.popupMenuFetchAllItems().menuItems; const targetMenuItem = popupMenuItems.find(mi => mi.path[mi.path.length - 1] === heightName); if (targetMenuItem) { trackOptionsPopup.popupMenuSelect({ menuPath: targetMenuItem.path }); return true; } else { debugLog(`Warning: Height "${heightName}" not found in menu`); return false; } } catch (error) { debugLog("Error setting track height: " + error.message); return false; } } function isTrackTooSmall(heightName) { if (!heightName) return false; const smallHeights = ["micro", "mini", "small"]; return smallHeights.includes(heightName.toLowerCase()); } function expandTrackIfNeeded(track) { try { const trackOptionsPopup = track.getFirstWithTitle("Track Options"); const popupMenuItems = trackOptionsPopup.popupMenuFetchAllItems().menuItems; // Find current height const currentHeight = popupMenuItems.find(mi => mi.element.isMenuChecked); const currentHeightName = currentHeight ? currentHeight.path.slice(-1)[0] : null; if (!currentHeightName) { debugLog("Could not determine current track height"); return null; } debugLog(`Track height is "${currentHeightName}"`); // Check if too small const smallHeights = ["micro", "mini", "small"]; if (!smallHeights.includes(currentHeightName.toLowerCase())) { debugLog("No expansion needed"); return null; } // Need to expand - find medium in the SAME menu structure debugLog(`Expanding from "${currentHeightName}" to medium`); const targetMenuItem = popupMenuItems.find(mi => mi.path[mi.path.length - 1] === "medium"); if (targetMenuItem) { trackOptionsPopup.popupMenuSelect({ menuPath: targetMenuItem.path }); // Return both the original height name AND the menu items for restoration return { heightName: currentHeightName, menuItems: popupMenuItems, popup: trackOptionsPopup }; } else { debugLog('Warning: "medium" height not found in menu'); return null; } } catch (error) { debugLog("Error in expandTrackIfNeeded: " + error.message); return null; } } // ===== WINDOW MANAGEMENT FUNCTIONS ===== function closeAllSendWindows() { let closedCount = 0; try { while (sf.ui.proTools.sfx.sendMixerWindow.invalidate().exists) { sf.ui.proTools.sfx.sendMixerWindow.windowClose(); closedCount++; } debugLog(`Closed ${closedCount} send windows`); } catch (error) { log("Error closing send window: " + error.message); } } function closeAllPluginWindows() { try { let closedCount = 0; while (sf.ui.proTools.sfx.getFloatingWindowWithTitleStartingWith("Plug-in").invalidate().exists) { const frontPluginWin = sf.ui.proTools.sfx.getFloatingWindowWithTitleStartingWith("Plug-in"); frontPluginWin.windowClose(); closedCount++; } debugLog(`Closed ${closedCount} plugin windows`); return closedCount; } catch (error) { log("General error in closeAllPluginWindows: " + error.message); return 0; } } // ===== PLUGIN ANALYSIS FUNCTIONS ===== function getPluginWindowInfo() { const now = Date.now(); if (pluginWindowCache && (now - cacheTimestamp) < CACHE_DURATION) { return pluginWindowCache; } try { const pluginWindows = sf.ui.proTools.sfx.windows.filter(w => { return w.title && w.title.value && w.title.value.startsWith("Plug-in:"); }); const windowInfo = { count: pluginWindows.length, trackNames: [] }; for (let i = 0; i < pluginWindows.length; i++) { try { const win = pluginWindows[i]; if (win.popupButtons && win.popupButtons.whoseTitle.is('Track Selector').first) { const trackName = win.popupButtons.whoseTitle.is('Track Selector').first.value.value; if (trackName && !windowInfo.trackNames.includes(trackName)) { windowInfo.trackNames.push(trackName); } } } catch (e) { continue; } } pluginWindowCache = windowInfo; cacheTimestamp = now; return windowInfo; } catch (error) { debugLog("Error getting plugin window info: " + error.message); return { count: 0, trackNames: [] }; } } function doPluginsBelongToCurrentSendReturn(track, sendNumber) { try { const origTrackName = track.normalizedTrackName; const pluginInfo = getPluginWindowInfo(); if (pluginInfo.count === 0) return false; const gotoResult = goToSendReturn(track, sendNumber); if (!gotoResult.success) return false; const returnTrackName = gotoResult.returnTrackName; sf.app.proTools.selectTracksByName({ trackNames: [origTrackName] }); return pluginInfo.trackNames.includes(returnTrackName); } catch (error) { debugLog("Error checking plugin ownership: " + error.message); try { sf.app.proTools.selectTracksByName({ trackNames: [track.normalizedTrackName] }); } catch (e) { } return false; } } // ===== SEND MANAGEMENT FUNCTIONS ===== function findAvailableSends(track) { const availableSends = []; const maxSends = 10; for (let i = 0; i < maxSends; i++) { try { const sendButton = track.sendButtons[i].invalidate(); if (sendButton.exists) { const sendValue = sendButton.value; if (sendValue && sendValue.value !== "unassigned") { const sendSelectorBtn = track.sendSelectorButtons[i].invalidate(); if (sendSelectorBtn && sendSelectorBtn.exists) { const sendStatus = sendSelectorBtn.value.value.trim().toLowerCase(); if (sendStatus.includes("inactive") || sendStatus.includes("bypassed")) { debugLog("Send " + String.fromCharCode(96 + i + 1) + " is " + sendStatus + ", skipping"); continue; } } availableSends.push(i + 1); } } } catch (error) { debugLog("Error checking send " + (i + 1) + ": " + error.message); } } return availableSends; } /** * Find available sends that have return tracks (excludes sidechains) */ function findAvailableSendsWithReturns(track) { const allSends = findAvailableSends(track); const sendsWithReturns = []; for (const sendNum of allSends) { const sendButton = track.sendButtons[sendNum - 1]; const sendDestination = sendButton.value.value; // Check if a track with this destination name exists if (trackExists(sendDestination)) { sendsWithReturns.push(sendNum); } else { debugLog(`Send ${sendNum} (${sendDestination}) is a sidechain - excluding from cycle`); } } return sendsWithReturns; } function getCurrentSendIndex() { const outputWin = sf.ui.proTools.sfx.sendMixerWindow.invalidate(); if (!outputWin || !outputWin.exists) return 0; const outputViewSelector = outputWin.buttons.whoseTitle.is("Output View selector").first; if (!outputViewSelector || !outputViewSelector.exists) return 0; if (outputViewSelector.value && outputViewSelector.value.value && outputViewSelector.value.value.startsWith("send")) { const sendLetter = outputViewSelector.value.value.replace("send ", "").toLowerCase(); return sendLetter.charCodeAt(0) - 96; } return 0; } // ===== GET TRACK FROM SEND WINDOW ===== function getTrackNameFromSendWindow() { try { const sendWindow = sf.ui.proTools.sfx.sendMixerWindow.invalidate(); if (!sendWindow || !sendWindow.exists) { return null; } // Try to find track selector button const trackSelector = sendWindow.buttons.whoseTitle.startsWith("Track selector").first; if (trackSelector && trackSelector.exists && trackSelector.title && trackSelector.title.value) { const titleParts = trackSelector.title.value.split('\n'); if (titleParts.length > 1) { debugLog(`Found track from send window: ${titleParts[1]}`); return titleParts[1]; } } return null; } catch (error) { debugLog("Error getting track from send window: " + error.message); return null; } } // ===== IMPROVED INSERT FUNCTIONS ===== function getInsertWin(track, insertIndex) { const insertChar = INSERT_CHARS[insertIndex]; const trackName = track.normalizedTrackName; return sf.ui.proTools.sfx.windows.whoseTitle.contains('Plug').filter(w => { const trackSelector = w.popupButtons.whoseTitle.is('Track Selector').first; if (!trackSelector || !trackSelector.value) return false; if (trackSelector.value.value !== trackName) return false; const insertSelector = w.popupButtons.whoseTitle.is('Insert Position selector').first; if (!insertSelector || !insertSelector.value) return false; if (insertSelector.value.value !== insertChar) return false; return true; })[0]; } function openActiveInserts(track) { let openedCount = 0; let newlyOpenedCount = 0; let lastPluginName = null; debugLog(`=== OPENING ACTIVE INSERTS for ${track.normalizedTrackName} ===`); track.invalidate(); const expansionInfo = expandTrackIfNeeded(track); for (let i = track.insertSelectorButtons.length - 1; i >= 0; i--) { try { let button = track.insertSelectorButtons[i]; if (!button.exists) { debugLog(`Insert ${i}: Button doesn't exist`); continue; } const statusValue = button.value.value; debugLog(`Insert ${i}: Status = "${statusValue}"`); if (statusValue.startsWith("inactive") || statusValue.startsWith("bypassed")) { debugLog(`Insert ${i}: Skipping (${statusValue})`); continue; } const insertButton = track.insertButtons[i].invalidate(); if (!insertButton.exists || insertButton.value.value === "unassigned") { debugLog(`Insert ${i}: Unassigned`); continue; } const pluginName = insertButton.value.value; debugLog(`Insert ${i}: ACTIVE - Plugin: "${pluginName}"`); let pluginWin = getInsertWin(track, i); if (!pluginWin) { insertButton.elementClick(); lastPluginName = pluginName; try { sf.ui.proTools.sfx.windows.whoseTitle.is(`Plug-in: ${pluginName}`).first.elementWaitFor(); pluginWin = getInsertWin(track, i); } catch (waitError) { debugLog(`Insert ${i}: Failed to open window - ${waitError.message}`); } if (pluginWin) { try { const targetBtn = pluginWin.buttons.whoseTitle.is('Target button').first; if (targetBtn && targetBtn.exists) { targetBtn.elementClick(); } } catch (e) { debugLog(`Insert ${i}: Could not find Target button`); } openedCount++; newlyOpenedCount++; debugLog(`Insert ${i}: Successfully opened (NEW)`); } else { debugLog(`Insert ${i}: Failed to open window`); } } else { try { const targetBtn = pluginWin.buttons.whoseTitle.is('Target button').first; if (targetBtn && targetBtn.exists) { targetBtn.elementClick(); } } catch (e) { } openedCount++; debugLog(`Insert ${i}: Already open`); } } catch (error) { debugLog(`Insert ${i}: Error - ${error.message}`); continue; } } if (expansionInfo) { try { const targetMenuItem = expansionInfo.menuItems.find( mi => mi.path[mi.path.length - 1] === expansionInfo.heightName ); if (targetMenuItem) { expansionInfo.popup.popupMenuSelect({ menuPath: targetMenuItem.path }); debugLog(`Restored height to "${expansionInfo.heightName}"`); } } catch (error) { debugLog("Error restoring track height: " + error.message); } } debugLog(`=== Total plugins: ${openedCount} (${newlyOpenedCount} newly opened) ===`); if (newlyOpenedCount > 0) { if (lastPluginName) { try { debugLog(`Waiting for last plugin window: "Plug-in: ${lastPluginName}"`); sf.ui.proTools.sfx.windows.whoseTitle.is(`Plug-in: ${lastPluginName}`).first.elementWaitFor(); } catch (waitError) { debugLog(`elementWaitFor failed for last plugin, using fallback delay`); } } debugLog(`Calling window arrange script`); sf.soundflow.runCommand({ commandId: 'user:default:cmidhshut00031wcuezl45598', }); } return openedCount; } // ===== MAIN SCRIPT EXECUTION ===== const isOptionPressed = event.keyboardState.hasAlt; const isCommandPressed = event.keyboardState.hasCommand; const isControlPressed = event.keyboardState.hasControl; // Command+Option: Close everything and exit if (isCommandPressed && isOptionPressed && !isControlPressed) { closeAllPluginWindows(); closeAllSendWindows(); sf.soundflow.runCommand({ commandId: "package:cme9qennt0000d510wgmtlehf" }); return; } try { let origTrack; let origTrackName; // PRIORITY: Always check send window first and use its track const trackFromSendWindow = getTrackNameFromSendWindow(); if (trackFromSendWindow) { // Send window is open - ALWAYS use its track, regardless of selection debugLog(`Using track from send window: ${trackFromSendWindow}`); sf.app.proTools.selectTracksByName({ trackNames: [trackFromSendWindow] }); origTrack = sf.ui.proTools.sfx.selectedTrack; origTrackName = trackFromSendWindow; } else { // No send window - fall back to selected track try { origTrack = sf.ui.proTools.sfx.selectedTrack; if (!origTrack || !origTrack.exists) { sf.interaction.notify({ title: "No Track Available", message: "Please select a track or have a send window open.", }); return; } origTrackName = origTrack.normalizedTrackName; debugLog(`Using selected track: ${origTrackName}`); } catch (selectedTrackError) { sf.interaction.notify({ title: "No Track Available", message: "Please select a track or have a send window open.", }); return; } } // Check for available sends WITH RETURN TRACKS (excludes sidechains) const availableSends = findAvailableSendsWithReturns(origTrack); if (availableSends.length === 0) { sf.interaction.notify({ title: "No Sends Available", message: "The selected track doesn't have any sends with return tracks.", }); return; } // Determine cycling logic let currentOpenSendSlot = getCurrentSendIndex(); const pluginInfo = getPluginWindowInfo(); let shouldCycle = false; let nextSendSlot; let userManuallyChangedSend = false; debugLog(`=== CYCLING DEBUG ===`); debugLog(`Current open send slot: ${currentOpenSendSlot}`); debugLog(`Available sends (with returns): ${availableSends.join(", ")}`); debugLog(`Plugin windows open: ${pluginInfo.count}`); // Early exit: If only one send exists and it's already open with plugins, just notify and keep everything open if (availableSends.length === 1 && currentOpenSendSlot === availableSends[0] && pluginInfo.count > 0) { if (doPluginsBelongToCurrentSendReturn(origTrack, currentOpenSendSlot)) { sf.interaction.notify({ title: "Send Already Open", message: `Send ${String.fromCharCode(96 + availableSends[0]).toUpperCase()} is the only send on this track and is already open.`, }); return; } } // Detect manual send changes if (currentOpenSendSlot > 0 && globalState["lastUsedSends"][origTrackName] !== undefined) { const storedIndex = globalState["lastUsedSends"][origTrackName]; const expectedSend = availableSends[storedIndex]; if (currentOpenSendSlot !== expectedSend) { userManuallyChangedSend = true; const currentIndex = availableSends.indexOf(currentOpenSendSlot); if (currentIndex !== -1) { globalState["lastUsedSends"][origTrackName] = currentIndex; } } } if (!isOptionPressed && currentOpenSendSlot > 0 && pluginInfo.count > 0) { if (doPluginsBelongToCurrentSendReturn(origTrack, currentOpenSendSlot)) { shouldCycle = true; closeAllPluginWindows(); closeAllSendWindows(); } else { closeAllPluginWindows(); shouldCycle = false; } } if (!isOptionPressed && globalState["lastUsedSends"][origTrackName] !== undefined && currentOpenSendSlot > 0) { const storedIndex = globalState["lastUsedSends"][origTrackName]; const currentSendInList = availableSends[storedIndex]; if (currentOpenSendSlot === currentSendInList) { closeAllPluginWindows(); } } // Cycling logic if (currentOpenSendSlot === 0) { nextSendSlot = availableSends[0]; globalState["lastUsedSends"][origTrackName] = 0; } else if (isOptionPressed && !isCommandPressed && !isControlPressed) { nextSendSlot = currentOpenSendSlot; } else if (userManuallyChangedSend) { nextSendSlot = currentOpenSendSlot; } else if (globalState["lastUsedSends"][origTrackName] !== undefined) { const storedIndex = globalState["lastUsedSends"][origTrackName]; let nextIndex; closeAllPluginWindows(); if (isControlPressed && isCommandPressed && isOptionPressed) { nextIndex = (storedIndex - 1 + availableSends.length) % availableSends.length; } else { nextIndex = (storedIndex + 1) % availableSends.length; } nextSendSlot = availableSends[nextIndex]; globalState["lastUsedSends"][origTrackName] = nextIndex; } else { nextSendSlot = currentOpenSendSlot; const currentIndex = availableSends.indexOf(currentOpenSendSlot); if (currentIndex !== -1) { globalState["lastUsedSends"][origTrackName] = currentIndex; } else { nextSendSlot = availableSends[0]; globalState["lastUsedSends"][origTrackName] = 0; } } // Handle send window try { const outputWindow = sf.ui.proTools.sfx.sendMixerWindow.invalidate(); const outputWinExists = outputWindow.exists; const needToOpenSend = shouldCycle || !outputWinExists || (currentOpenSendSlot !== nextSendSlot); if (needToOpenSend) { if (outputWinExists && currentOpenSendSlot !== nextSendSlot) { outputWindow.windowClose(); } const sendButtonIndex = nextSendSlot - 1; origTrack.sendButtons[sendButtonIndex].invalidate().elementClick(); try { debugLog(`Waiting for send window to open`); sf.ui.proTools.sfx.sendMixerWindow.invalidate().elementWaitFor(); } catch (waitError) { debugLog(`elementWaitFor failed for send window: ${waitError.message}`); } } } catch (error) { sf.interaction.notify({ title: "Error Managing Send Window", message: error.message, }); return; } // Handle return track and plugins try { if (isOptionPressed && !isControlPressed) { const gotoResult = goToSendReturn(origTrack, nextSendSlot); if (gotoResult.success) { sf.ui.proTools.sfx.dawCommands.getByUniquePersistedName("ScrollSelectedTracksIntoView").run(); } // Don't close folder when using Option (navigating to return track) return; } // Normal flow: navigate to return track and open plugins const gotoResult = goToSendReturn(origTrack, nextSendSlot); if (!gotoResult.success) { sf.interaction.notify({ title: "Could Not Access Return Track", message: `Send ${nextSendSlot}: ${gotoResult.reason}`, }); sf.app.proTools.selectTracksByName({ trackNames: [origTrackName] }); // Close folder if we opened one if (openedFolderName) { closeFolderByName(openedFolderName); openedFolderName = null; } return; } const returnTrack = gotoResult.returnTrack; let pluginsOpened = 0; try { pluginsOpened = openActiveInserts(returnTrack); } catch (pluginError) { debugLog("Error opening plugins: " + pluginError.message); } if (pluginsOpened === 0) { sf.interaction.notify({ title: "No Active Plugins", message: `No active plugins found on send ${nextSendSlot}.`, }); } // Return to original track try { sf.app.proTools.selectTracksByName({ trackNames: [origTrackName] }); sf.ui.proTools.sfx.selectedTrack.trackScrollToView(); } catch (returnError) { debugLog("Error returning to original track: " + returnError.message); } // Close folder if we opened one if (openedFolderName) { closeFolderByName(openedFolderName); openedFolderName = null; } } catch (error) { sf.interaction.notify({ title: "Error with return track", message: error.message, }); debugLog("Error with return track: " + error.message); try { sf.app.proTools.selectTracksByName({ trackNames: [origTrackName] }); origTrack.trackScrollToView(); } catch (e) { } // Close folder if we opened one (even on error) if (openedFolderName) { closeFolderByName(openedFolderName); openedFolderName = null; } } } catch (error) { sf.interaction.notify({ title: "Error processing send", message: error.message, }); debugLog("Main error: " + error.message); // Close folder if we opened one (even on error) if (openedFolderName) { closeFolderByName(openedFolderName); openedFolderName = null; } }The close all floating and docked window script:
sf.ui.useSfx(); sf.ui.proTools.invalidate(); //sf.ui.proTools.appActivate(); // Configuration array for windows and their corresponding buttons const windowConfigs = [ { name: "Melodyne", button: sf.ui.proTools.sfx.mainWindow.melodyneTabButton, window: sf.ui.proTools.sfx.windows.whoseTitle.is("Melodyne").first }, { name: "MIDI Editor", button: sf.ui.proTools.sfx.mainWindow.midiEditorTabButton, window: sf.ui.proTools.sfx.midiEditorWindow }, { name: "Clip Effects", button: sf.ui.proTools.sfx.mainWindow.clipEffectsTabButton, window: sf.ui.proTools.sfx.windows.whoseTitle.is("Clip Effects").first }, { name: "Auto-Align", button: sf.ui.proTools.sfx.mainWindow.radioButtons.whoseTitle.startsWith("AUTO-ALIGN").first, window: sf.ui.proTools.sfx.windows.whoseTitle.startsWith("Auto-Align 2").first }, { name: "RX Spectral Editor", button: sf.ui.proTools.sfx.mainWindow.rxSpectralEditorTabButton, window: sf.ui.proTools.sfx.windows.whoseTitle.startsWith("RX Spectral Editor").first }, { name: "Repitch Elements", button: sf.ui.proTools.sfx.mainWindow.radioButtons.whoseTitle.startsWith("REPITCH ELEMENTS").first, window: sf.ui.proTools.sfx.windows.whoseTitle.startsWith("RePitch Elements").first, }, { name: "Spectralayers", button: sf.ui.proTools.sfx.mainWindow.radioButtons.whoseTitle.startsWith("SPECTRALAYERS").first, window: sf.ui.proTools.sfx.windows.whoseTitle.startsWith("SpectraLayers").first, }, { name: "Wavelab", button: sf.ui.proTools.sfx.mainWindow.radioButtons.whoseTitle.startsWith("WAVELAB").first, window: sf.ui.proTools.sfx.windows.whoseTitle.startsWith("WaveLab").first, }, { name: "Acoustica", button: sf.ui.proTools.sfx.mainWindow.radioButtons.whoseTitle.startsWith("ACOUSTICA").first, window: sf.ui.proTools.sfx.windows.whoseTitle.startsWith("Acoustica").first, }, { name: "Dynassist", button: sf.ui.proTools.sfx.mainWindow.radioButtons.whoseTitle.startsWith("Dynassist").first, window: sf.ui.proTools.sfx.windows.whoseTitle.startsWith("Dynassist").first, }, ]; // Close floating windows first windowConfigs.forEach(config => { if (config.window.exists) { //log(`${config.name} window open - closing floating window`); config.window.windowClose(); } }); // Close docked windows by clicking their buttons windowConfigs.forEach(config => { if (!config.button.exists) { return; } const buttonValue = config.button.value.intValue; if (buttonValue === 1) { config.button.elementClick(); //log(`Closed ${config.name} window`); } }); sf.ui.proTools.sfx.floatingWindows.allItems.forEach(function (win) { try { win.windowClose(); // Tries to close the window } catch (err) { // Ignores errors, which can happen if a window isn't in a closable state } });The window arrange script:
sf.ui.useSfx(); const DEBUG_MODE = false; function debugLog(message) { if (DEBUG_MODE) { log(message); } } // --- Configuration --- const ARRANGE_TYPES = ['All']; const WINDOW_GAP = 8; const START_X = 50; const START_Y = 50; const CASCADE_OFFSET = 30; const MIN_WINDOW_WIDTH = 350; const FALLBACK_HEIGHT = 300; const OVERFLOW_TOLERANCE = 100; const PREFER_RIGHT_ALIGNMENT = true; // NEW: Prefer right-aligned layouts // --------------------- // --- MaxRects Packer with Multiple Heuristics --- const MaxRectsPacker = function(w, h, overflowTolerance = 0, heuristic = 'contact', preferRight = false) { this.binWidth = w + overflowTolerance; this.binHeight = h + overflowTolerance; this.actualWidth = w; this.actualHeight = h; this.freeRectangles = [{ x: 0, y: 0, w: this.binWidth, h: this.binHeight }]; this.usedRectangles = []; this.heuristic = heuristic; this.preferRight = preferRight; }; MaxRectsPacker.prototype = { fit: function(blocks) { for (let i = 0; i < blocks.length; i++) { const block = blocks[i]; let bestNode = this.findPositionForNewNode(block.w, block.h); if (bestNode.score < Infinity) { block.fit = { x: bestNode.x, y: bestNode.y }; this.placeRectangle({ x: bestNode.x, y: bestNode.y, w: block.w, h: block.h }); } else { block.fit = null; } } }, findPositionForNewNode: function(width, height) { switch(this.heuristic) { case 'contact': return this.findPositionContact(width, height); case 'bssf': return this.findPositionBSSF(width, height); case 'bl': return this.preferRight ? this.findPositionBottomRight(width, height) : this.findPositionBottomLeft(width, height); case 'baf': return this.findPositionBestAreaFit(width, height); default: return this.findPositionContact(width, height); } }, // Contact Point heuristic - prefers corners and edges findPositionContact: function(width, height) { let bestNode = { score: Infinity, x: 0, y: 0 }; let bestContactScore = -1; let bestRightScore = this.preferRight ? -Infinity : 0; for (let i = 0; i < this.freeRectangles.length; i++) { const freeRect = this.freeRectangles[i]; if (freeRect.w >= width && freeRect.h >= height) { const contactScore = this.calculateContactScore(freeRect.x, freeRect.y, width, height); const leftoverHoriz = freeRect.w - width; const leftoverVert = freeRect.h - height; const shortSideFit = Math.min(leftoverHoriz, leftoverVert); const rightScore = this.preferRight ? (freeRect.x + width) : 0; let isBetter = false; if (contactScore > bestContactScore) { isBetter = true; } else if (contactScore === bestContactScore) { if (this.preferRight && rightScore > bestRightScore) { isBetter = true; } else if ((!this.preferRight || rightScore === bestRightScore) && shortSideFit < bestNode.score) { isBetter = true; } } if (isBetter) { bestNode = { x: freeRect.x, y: freeRect.y, w: width, h: height, score: shortSideFit }; bestContactScore = contactScore; bestRightScore = rightScore; } } } return bestNode; }, // Best Short Side Fit - minimizes leftover space findPositionBSSF: function(width, height) { let bestNode = { score: Infinity, x: 0, y: 0 }; let bestLongSideFit = Infinity; let bestRightScore = this.preferRight ? -Infinity : 0; for (let i = 0; i < this.freeRectangles.length; i++) { const freeRect = this.freeRectangles[i]; if (freeRect.w >= width && freeRect.h >= height) { const leftoverHoriz = freeRect.w - width; const leftoverVert = freeRect.h - height; const shortSideFit = Math.min(leftoverHoriz, leftoverVert); const longSideFit = Math.max(leftoverHoriz, leftoverVert); const rightScore = this.preferRight ? (freeRect.x + width) : 0; let isBetter = false; if (shortSideFit < bestNode.score) { isBetter = true; } else if (shortSideFit === bestNode.score) { if (this.preferRight && rightScore > bestRightScore) { isBetter = true; } else if ((!this.preferRight || rightScore === bestRightScore) && longSideFit < bestLongSideFit) { isBetter = true; } } if (isBetter) { bestNode = { x: freeRect.x, y: freeRect.y, w: width, h: height, score: shortSideFit }; bestLongSideFit = longSideFit; bestRightScore = rightScore; } } } return bestNode; }, // Bottom-Left - prefers lower positions, then leftmost findPositionBottomLeft: function(width, height) { let bestNode = { score: Infinity, x: 0, y: Infinity }; for (let i = 0; i < this.freeRectangles.length; i++) { const freeRect = this.freeRectangles[i]; if (freeRect.w >= width && freeRect.h >= height) { const topSideY = freeRect.y + height; if (topSideY < bestNode.y || (topSideY === bestNode.y && freeRect.x < bestNode.x)) { bestNode = { x: freeRect.x, y: freeRect.y, w: width, h: height, score: topSideY }; } } } if (bestNode.y === Infinity) { bestNode.score = Infinity; } return bestNode; }, // Bottom-Right - prefers lower positions, then rightmost findPositionBottomRight: function(width, height) { let bestNode = { score: Infinity, x: -Infinity, y: Infinity }; for (let i = 0; i < this.freeRectangles.length; i++) { const freeRect = this.freeRectangles[i]; if (freeRect.w >= width && freeRect.h >= height) { const topSideY = freeRect.y + height; const rightSideX = freeRect.x + width; if (topSideY < bestNode.y || (topSideY === bestNode.y && rightSideX > bestNode.x)) { bestNode = { x: freeRect.x, y: freeRect.y, w: width, h: height, score: topSideY }; } } } if (bestNode.y === Infinity) { bestNode.score = Infinity; } return bestNode; }, // Best Area Fit - minimizes area of the free rectangle findPositionBestAreaFit: function(width, height) { let bestNode = { score: Infinity, x: 0, y: 0 }; let bestShortSideFit = Infinity; let bestRightScore = this.preferRight ? -Infinity : 0; for (let i = 0; i < this.freeRectangles.length; i++) { const freeRect = this.freeRectangles[i]; if (freeRect.w >= width && freeRect.h >= height) { const areaFit = freeRect.w * freeRect.h - width * height; const leftoverHoriz = freeRect.w - width; const leftoverVert = freeRect.h - height; const shortSideFit = Math.min(leftoverHoriz, leftoverVert); const rightScore = this.preferRight ? (freeRect.x + width) : 0; let isBetter = false; if (areaFit < bestNode.score) { isBetter = true; } else if (areaFit === bestNode.score) { if (this.preferRight && rightScore > bestRightScore) { isBetter = true; } else if ((!this.preferRight || rightScore === bestRightScore) && shortSideFit < bestShortSideFit) { isBetter = true; } } if (isBetter) { bestNode = { x: freeRect.x, y: freeRect.y, w: width, h: height, score: areaFit }; bestShortSideFit = shortSideFit; bestRightScore = rightScore; } } } return bestNode; }, calculateContactScore: function(x, y, w, h) { let score = 0; if (x === 0) score++; if (y === 0) score++; if (x + w >= this.actualWidth) score++; if (y + h >= this.actualHeight) score++; for (let i = 0; i < this.usedRectangles.length; i++) { const rect = this.usedRectangles[i]; if (x === rect.x + rect.w || x + w === rect.x) { if (y < rect.y + rect.h && y + h > rect.y) { score++; } } if (y === rect.y + rect.h || y + h === rect.y) { if (x < rect.x + rect.w && x + w > rect.x) { score++; } } } return score; }, placeRectangle: function(node) { let numRectanglesToProcess = this.freeRectangles.length; for (let i = 0; i < numRectanglesToProcess; i++) { if (this.splitFreeNode(this.freeRectangles[i], node)) { this.freeRectangles.splice(i, 1); i--; numRectanglesToProcess--; } } this.pruneFreeList(); this.usedRectangles.push(node); }, splitFreeNode: function(freeNode, usedNode) { if (usedNode.x >= freeNode.x + freeNode.w || usedNode.x + usedNode.w <= freeNode.x || usedNode.y >= freeNode.y + freeNode.h || usedNode.y + usedNode.h <= freeNode.y) { return false; } if (usedNode.x < freeNode.x + freeNode.w && usedNode.x + usedNode.w > freeNode.x) { if (usedNode.y > freeNode.y && usedNode.y < freeNode.y + freeNode.h) { const newNode = { ...freeNode }; newNode.h = usedNode.y - newNode.y; this.freeRectangles.push(newNode); } if (usedNode.y + usedNode.h < freeNode.y + freeNode.h) { const newNode = { ...freeNode }; newNode.y = usedNode.y + usedNode.h; newNode.h = freeNode.y + freeNode.h - (usedNode.y + usedNode.h); this.freeRectangles.push(newNode); } } if (usedNode.y < freeNode.y + freeNode.h && usedNode.y + usedNode.h > freeNode.y) { if (usedNode.x > freeNode.x && usedNode.x < freeNode.x + freeNode.w) { const newNode = { ...freeNode }; newNode.w = usedNode.x - newNode.x; this.freeRectangles.push(newNode); } if (usedNode.x + usedNode.w < freeNode.x + freeNode.w) { const newNode = { ...freeNode }; newNode.x = usedNode.x + usedNode.w; newNode.w = freeNode.x + freeNode.w - (usedNode.x + usedNode.w); this.freeRectangles.push(newNode); } } return true; }, pruneFreeList: function() { for (let i = 0; i < this.freeRectangles.length; i++) { for (let j = i + 1; j < this.freeRectangles.length; j++) { if (this.isContainedIn(this.freeRectangles[i], this.freeRectangles[j])) { this.freeRectangles.splice(i, 1); i--; break; } if (this.isContainedIn(this.freeRectangles[j], this.freeRectangles[i])) { this.freeRectangles.splice(j, 1); j--; } } } }, isContainedIn: function(a, b) { return a.x >= b.x && a.y >= b.y && a.x + a.w <= b.x + b.w && a.y + a.h <= b.y + b.h; } }; // --- Evaluation Functions --- function calculateOverlap(blocks) { let totalOverlap = 0; let maxOverlap = 0; for (let i = 0; i < blocks.length; i++) { if (!blocks[i].fit) continue; for (let j = i + 1; j < blocks.length; j++) { if (!blocks[j].fit) continue; const overlapX = Math.max(0, Math.min(blocks[i].fit.x + blocks[i].w, blocks[j].fit.x + blocks[j].w) - Math.max(blocks[i].fit.x, blocks[j].fit.x) ); const overlapY = Math.max(0, Math.min(blocks[i].fit.y + blocks[i].h, blocks[j].fit.y + blocks[j].h) - Math.max(blocks[i].fit.y, blocks[j].fit.y) ); const overlap = overlapX * overlapY; totalOverlap += overlap; maxOverlap = Math.max(maxOverlap, overlap); } } return { total: totalOverlap, max: maxOverlap }; } function calculateWastedSpace(blocks, screenWidth, screenHeight) { if (blocks.length === 0) return screenWidth * screenHeight; let maxX = 0, maxY = 0; blocks.forEach(block => { if (block.fit) { maxX = Math.max(maxX, block.fit.x + block.w); maxY = Math.max(maxY, block.fit.y + block.h); } }); const usedArea = maxX * maxY; const actualWindowArea = blocks.reduce((sum, b) => sum + (b.w * b.h), 0); return usedArea - actualWindowArea; } function calculateRightAlignment(blocks, screenWidth) { if (blocks.length === 0) return 0; // Calculate average X position (higher = more right-aligned) let totalX = 0; let count = 0; blocks.forEach(block => { if (block.fit) { totalX += block.fit.x + block.w / 2; // Use center of window count++; } }); return count > 0 ? totalX / count : 0; } function evaluateLayout(blocks, screenWidth, screenHeight, preferRight) { const fittedCount = blocks.filter(b => b.fit !== null).length; const overlap = calculateOverlap(blocks); const waste = calculateWastedSpace(blocks, screenWidth, screenHeight); const rightAlignment = preferRight ? calculateRightAlignment(blocks, screenWidth) : 0; // Scoring: prioritize fitting all windows, then minimize overlap, then right alignment (if preferred), then minimize waste const score = (fittedCount * 1000000) - (overlap.total * 1000) + (rightAlignment * 10) - waste; return { score: score, fittedCount: fittedCount, overlapTotal: overlap.total, overlapMax: overlap.max, waste: waste, rightAlignment: rightAlignment }; } // --- Multi-Strategy Packer --- function tryMultipleStrategies(blocks, screenWidth, screenHeight, preferRight) { const strategies = [ { heuristic: 'contact', sorts: ['maxdim', 'area', 'width', 'height'] }, { heuristic: 'bssf', sorts: ['maxdim', 'area', 'perimeter'] }, { heuristic: 'bl', sorts: ['height', 'width', 'area'] }, { heuristic: 'baf', sorts: ['area', 'maxdim'] } ]; let bestResult = null; let bestEval = { score: -Infinity }; debugLog("=== TRYING MULTIPLE STRATEGIES ==="); debugLog(`Right alignment preference: ${preferRight ? "YES" : "NO"}`); strategies.forEach(strategy => { strategy.sorts.forEach(sortType => { const blocksCopy = blocks.map(b => ({ ...b, fit: null })); // Apply sort switch(sortType) { case 'maxdim': blocksCopy.sort((a, b) => { const maxA = Math.max(a.w, a.h); const maxB = Math.max(b.w, b.h); return maxB !== maxA ? maxB - maxA : b.area - a.area; }); break; case 'area': blocksCopy.sort((a, b) => b.area - a.area); break; case 'width': blocksCopy.sort((a, b) => b.w !== a.w ? b.w - a.w : b.h - a.h); break; case 'height': blocksCopy.sort((a, b) => b.h !== a.h ? b.h - a.h : b.w - a.w); break; case 'perimeter': blocksCopy.sort((a, b) => { const perimA = 2 * (a.w + a.h); const perimB = 2 * (b.w + b.h); return perimB - perimA; }); break; } const packer = new MaxRectsPacker(screenWidth, screenHeight, OVERFLOW_TOLERANCE, strategy.heuristic, preferRight); packer.fit(blocksCopy); const evaluation = evaluateLayout(blocksCopy, screenWidth, screenHeight, preferRight); debugLog(`${strategy.heuristic} + ${sortType}: fitted=${evaluation.fittedCount}, overlap=${evaluation.overlapTotal}, rightAlign=${Math.round(evaluation.rightAlignment)}, score=${evaluation.score}`); if (evaluation.score > bestEval.score) { bestEval = evaluation; bestResult = blocksCopy; } }); }); debugLog(`\n=== BEST STRATEGY ===`); debugLog(`Fitted: ${bestEval.fittedCount}/${blocks.length}`); debugLog(`Total overlap: ${bestEval.overlapTotal}px²`); debugLog(`Max single overlap: ${bestEval.overlapMax}px²`); debugLog(`Wasted space: ${bestEval.waste}px²`); debugLog(`Right alignment score: ${Math.round(bestEval.rightAlignment)}`); return bestResult; } // ------------------------------------------- sf.ui.proTools.sfx.invalidate(); const SCREEN_WIDTH = sf.ui.screens.mainScreen.size.x - START_X; const SCREEN_HEIGHT = sf.ui.screens.mainScreen.size.y - START_Y; const allFloatingWindows = sf.ui.proTools.sfx.floatingWindows.invalidate(); let windowsToArrange = allFloatingWindows.filter(win => { if (ARRANGE_TYPES.includes('All')) return true; const isPlugin = win.buttons.whoseTitle.is("Targeted").exists; const isSendOrOutput = win.buttons.whoseTitle.is("Target button").exists || win.popupButtons.whoseTitle.is('Insert Position selector').exists; if (ARRANGE_TYPES.includes('Plugins') && isPlugin) return true; if (ARRANGE_TYPES.includes('Sends') && isSendOrOutput) return true; return false; }); if (!windowsToArrange || windowsToArrange.length === 0) { throw 0; } let blocks = windowsToArrange.map(win => { try { let frame = win.frame; if (!frame || frame.w === 0) { win.invalidate(); frame = win.frame; } const frameH = (frame && frame.h) || FALLBACK_HEIGHT; const frameW = (frame && frame.w) || MIN_WINDOW_WIDTH; return { w: frameW + WINDOW_GAP, h: frameH + WINDOW_GAP, windowElement: win, originalW: frameW, originalH: frameH, fit: null, isValid: true, area: frameW * frameH }; } catch (e) { return { isValid: false }; } }).filter(b => b.isValid); const bestBlocks = tryMultipleStrategies(blocks, SCREEN_WIDTH, SCREEN_HEIGHT, PREFER_RIGHT_ALIGNMENT); let fittedBlocks = bestBlocks.filter(b => b.fit !== null); let unfittedBlocks = bestBlocks.filter(b => b.fit === null); fittedBlocks.forEach(block => { const finalX = START_X + block.fit.x; const finalY = START_Y + block.fit.y; try { block.windowElement.windowMove({ position: { x: Math.round(finalX), y: Math.round(finalY) } }); } catch (e) { log(`Error moving window: ${e.message}`); } }); if (unfittedBlocks.length > 0) { let maxX = 0, maxY = 0; fittedBlocks.forEach(block => { const rightEdge = block.fit.x + block.w; const bottomEdge = block.fit.y + block.h; maxX = Math.max(maxX, rightEdge); maxY = Math.max(maxY, bottomEdge); }); unfittedBlocks.forEach((block, i) => { const offset = i * CASCADE_OFFSET; let finalX, finalY; if (maxX + block.w < SCREEN_WIDTH + OVERFLOW_TOLERANCE) { finalX = START_X + maxX + offset; finalY = START_Y + offset; } else { finalX = START_X + offset; finalY = START_Y + offset; } try { block.windowElement.windowMove({ position: { x: Math.round(finalX), y: Math.round(finalY) } }); block.windowElement.elementRaise(); } catch (e) { log(`Error moving unfitted window: ${e.message}`); } }); } debugLog(`\nPacked: ${fittedBlocks.length} | Cascaded: ${unfittedBlocks.length}`);