Custom Command ShowMulti (Launch multiple viewers)

This add-in creates the custom command ShowMulti. It complements the built-in command Show by being able to launch more than one viewer at once.

JScript
function OnInit(initData) {
    initData.name = 'CommandShowMulti';
    initData.version = '2022-05-18';
    initData.url = 'https://resource.dopus.com/t/custom-command-showmulti-launch-multiple-viewers/41266';
    initData.desc = 'Launch multiple viewers at once';
    initData.default_enable = true;
    initData.min_version = '12.0';
}

function OnAddCommands(addCmdData) {
    var cmd = addCmdData.AddCommand();
    cmd.name = 'ShowMulti';
    cmd.method = 'OnShowMulti';
    cmd.desc = 'ShowMulti';
    cmd.label = 'ShowMulti';
    cmd.template = 'MODE/K,DISPLAY/N';
    cmd.hide = false;
    cmd.icon = 'script';

    var cmd = addCmdData.AddCommand();
    cmd.name = 'MenuBarMulti';
    cmd.method = 'OnMenuBarMulti';
    cmd.desc = 'Toggle Menu Bar in all open viewers';
    cmd.label = 'MenuBarMulti';
    cmd.hide = false;
    cmd.icon = 'script';

    var cmd = addCmdData.AddCommand();
    cmd.name = 'StatusBarMulti';
    cmd.method = 'OnStatusBarMulti';
    cmd.desc = 'Toggle Status Bar in all open viewers';
    cmd.label = 'StatusBarMulti';
    cmd.hide = false;
    cmd.icon = 'script';

    var cmd = addCmdData.AddCommand();
    cmd.name = 'ControlBarMulti';
    cmd.method = 'OnControlBarMulti';
    cmd.desc = 'Toggle Control Bar in all open viewers';
    cmd.label = 'ControlBarMulti';
    cmd.hide = false;
    cmd.icon = 'script';

    var cmd = addCmdData.AddCommand();
    cmd.name = 'FullScreenMulti';
    cmd.method = 'OnFullScreenMulti';
    cmd.desc = 'Set all viewers to Full Screen';
    cmd.label = 'FullScreenMulti';
    cmd.hide = false;
    cmd.icon = 'script';

    var cmd = addCmdData.AddCommand();
    cmd.name = 'OriginalSizeMulti';
    cmd.method = 'OnOriginalSizeMulti';
    cmd.desc = 'Set images in all viewers to original size';
    cmd.label = 'OriginalSizeMulti';
    cmd.hide = false;
    cmd.icon = 'script';

    var cmd = addCmdData.AddCommand();
    cmd.name = 'FitToPageMulti';
    cmd.method = 'OnFitToPageMulti';
    cmd.desc = 'Zoom images in all viewers to fit';
    cmd.label = 'FitToPageMulti';
    cmd.hide = false;
    cmd.icon = 'script';

    var cmd = addCmdData.AddCommand();
    cmd.name = 'NextImageMulti';
    cmd.method = 'OnNextImageMulti';
    cmd.desc = 'Jump forward by count of open viewers (Shift to jump by 1)';
    cmd.label = 'NextImageMulti';
    cmd.hide = false;
    cmd.icon = 'script';

    var cmd = addCmdData.AddCommand();
    cmd.name = 'PreviousImageMulti';
    cmd.method = 'OnPreviousImageMulti';
    cmd.desc = 'Jump backward by count of open viewers (Shift to jump by 1)';
    cmd.label = 'PreviousImageMulti';
    cmd.hide = false;
    cmd.icon = 'script';
}

function OnShowMulti(scriptCmdData) {
    var cmd = scriptCmdData.func.command;
    var tab = scriptCmdData.func.sourcetab;
    var args = scriptCmdData.func.args;
    var si = DOpus.Create().SysInfo();

    cmd.deselect = false;

    if (tab.selected_files.count < 2) cmd.SetFiles(tab.files);

    var curDisp = si.MouseMonitor();
    var maxDisp = si.Monitors().count;

    var d = args.display;
    if (typeof d != 'number' || d < 0 || d >= maxDisp) d = curDisp; // if display is missing or out-of-range, use current monitor

    var targetDisp = si.WorkAreas(d);

    var posX = targetDisp.left;
    var posY = targetDisp.top;

    var imgW = targetDisp.width;
    var imgW2 = imgW / 2;
    var imgH = targetDisp.height;
    var imgH2 = imgH / 2;

    var m = args.got_arg.mode ? args.mode.toLowerCase() : ((imgW > imgH) ? 'vert' : 'horiz');

    cmd.Clear();

    cmd.AddLine('Close ALLVIEWERS');

    if (m == 'quad') {
        cmd.AddLine('Show POS=' + (posX + 0 * imgW2) + ',' + (posY + 0 * imgH2) + ' SIZE=' + imgW2 + ',' + imgH2 + ' NOUSEEXISTING');
        cmd.AddLine('Show POS=' + (posX + 1 * imgW2) + ',' + (posY + 0 * imgH2) + ' SIZE=' + imgW2 + ',' + imgH2 + ' NOUSEEXISTING');
        cmd.AddLine('Show POS=' + (posX + 0 * imgW2) + ',' + (posY + 1 * imgH2) + ' SIZE=' + imgW2 + ',' + imgH2 + ' NOUSEEXISTING');
        cmd.AddLine('Show POS=' + (posX + 1 * imgW2) + ',' + (posY + 1 * imgH2) + ' SIZE=' + imgW2 + ',' + imgH2 + ' NOUSEEXISTING');
    } else if (m == 'horiz') {
        cmd.AddLine('Show POS=' + (posX + 0 * imgW2) + ',' + (posY + 0 * imgH2) + ' SIZE=' + imgW + ',' + imgH2 + ' NOUSEEXISTING');
        cmd.AddLine('Show POS=' + (posX + 0 * imgW2) + ',' + (posY + 1 * imgH2) + ' SIZE=' + imgW + ',' + imgH2 + ' NOUSEEXISTING');
    } else {
        cmd.AddLine('Show POS=' + (posX + 0 * imgW2) + ',' + (posY + 0 * imgH2) + ' SIZE=' + imgW2 + ',' + imgH + ' NOUSEEXISTING');
        cmd.AddLine('Show POS=' + (posX + 1 * imgW2) + ',' + (posY + 0 * imgH2) + ' SIZE=' + imgW2 + ',' + imgH + ' NOUSEEXISTING');
    }

    cmd.Run();

    var newVwrs = cmd.results.newviewers;
    for (var i = 1; i < newVwrs.count; i++) {
        newVwrs(i).Command('goto,+' + i);
    }
}

function OnMenuBarMulti(scriptCmdData) {
    var cmd = scriptCmdData.func.command;
    cmd.deselect = false;

    if (DOpus.viewers.count == 0) return;

    for (var e = new Enumerator(DOpus.viewers); !e.atEnd(); e.moveNext()) {
        e.item().Command('toolbar');
    }
}

function OnStatusBarMulti(scriptCmdData) {
    var cmd = scriptCmdData.func.command;
    cmd.deselect = false;

    if (DOpus.viewers.count == 0) return;

    for (var e = new Enumerator(DOpus.viewers); !e.atEnd(); e.moveNext()) {
        e.item().Command('statusbar');
    }
}

function OnControlBarMulti(scriptCmdData) {
    var cmd = scriptCmdData.func.command;
    cmd.deselect = false;

    if (DOpus.viewers.count == 0) return;

    for (var e = new Enumerator(DOpus.viewers); !e.atEnd(); e.moveNext()) {
        e.item().Command('toolbar');
    }
}

function OnFullScreenMulti(scriptCmdData) {
    var cmd = scriptCmdData.func.command;
    cmd.deselect = false;

    if (DOpus.viewers.count == 0) return;

    for (var e = new Enumerator(DOpus.viewers); !e.atEnd(); e.moveNext()) {
        e.item().Command('fullscreen');
    }
}

function OnOriginalSizeMulti(scriptCmdData) {
    var cmd = scriptCmdData.func.command;
    cmd.deselect = false;

    if (DOpus.viewers.count == 0) return;

    for (var e = new Enumerator(DOpus.viewers); !e.atEnd(); e.moveNext()) {
        e.item().Command('zoom,reset');
    }
}

function OnFitToPageMulti(scriptCmdData) {
    var cmd = scriptCmdData.func.command;
    cmd.deselect = false;

    if (DOpus.viewers.count == 0) return;

    for (var e = new Enumerator(DOpus.viewers); !e.atEnd(); e.moveNext()) {
        e.item().Command('zoom,fit');
    }
}

function OnNextImageMulti(scriptCmdData) {
    var cmd = scriptCmdData.func.command;
    cmd.deselect = false;

    if (DOpus.viewers.count == 0) return;

    var jump = scriptCmdData.func.qualifiers.indexOf('shift') < 0 ? DOpus.viewers.count : 1;

    cmd.ClearFiles();

    for (var e = new Enumerator(DOpus.viewers); !e.atEnd(); e.moveNext()) {
        var vwr = e.item();
        var n = vwr.index + jump;
        if (n >= vwr.files.count) n = n - vwr.files.count;
        vwr.Command('goto,' + n);
        cmd.AddFile(vwr.current);
    }

    cmd.RunCommand('Select NONE');
    cmd.RunCommand('Select FROMSCRIPT SETFOCUS');
    cmd.RunCommand('Select SHOWFOCUS');
}

function OnPreviousImageMulti(scriptCmdData) {
    var cmd = scriptCmdData.func.command;
    cmd.deselect = false;

    if (DOpus.viewers.count == 0) return;

    var jump = scriptCmdData.func.qualifiers.indexOf('shift') < 0 ? DOpus.viewers.count : 1;

    cmd.ClearFiles();

    for (var e = new Enumerator(DOpus.viewers); !e.atEnd(); e.moveNext()) {
        var vwr = e.item();
        var n = vwr.index - jump;
        if (n < 0) n = n + vwr.files.count;
        vwr.Command('goto,' + n);
        cmd.AddFile(vwr.current);
    }

    cmd.RunCommand('Select NONE');
    cmd.RunCommand('Select FROMSCRIPT SETFOCUS');
    cmd.RunCommand('Select SHOWFOCUS');
}

Usage

By default,

ShowMulti

launches two viewers side-by-side on the current monitor and places the first two of the selected items in them. If fewer than two files are selected, all the files in the source will be used. On a monitor in landscape mode the viewers will be left and right, on a monitor in portrait mode top and bottom. All previously opened viewers will be closed.

To open the viewers on a specific monitor, use the DISPLAY=n parameter. n is the zero-based index of your monitors. It's determined by Windows and your hardware and does not necessarily count from left to right. You'll need to try it out.

ShowMulti DISPLAY=0

To force the left/right resp. top/bottom layout, use the MODE parameter. Allowed values are horiz, vert, and quad. The latter will launch four viewers as quadrants.

ShowMulti MODE=quad

The two parameters can be combined:

ShowMulti DISPLAY=2 MODE=vert

The add-in also provides some additional commands to make handling the avalanche of viewers a bit easier. You can place the commands anywhere you like (viewer, lister, floating toolbar, hotkey). They will work with all open viewers.

  • To quickly browse through your gallery, use NextImageMulti and PreviousImageMulti. They will jump forward (backward) by the number of open viewers. Press Shift to jump by only one image.

  • To toggle the toolbars in the viewers, use MenuBarMulti, StatusBarMulti, and ControlBarMulti.

  • To toggle full screen mode for all viewers, use FullScreenMulti.

  • To zoom the images in all viewers to their original size, use OriginalSizeMulti.

  • To fit the images into the viewers, use FitToPageMulti.

Your favorite viewer commands are not on this list? Let me know, "Multi-nizing" them is rather simple :slight_smile:

Installation

  • Save CommandShowMulti.js.txt to /scripts (What are aliases?).

  • Copy the main button and menu to convenient places (usually your lister toolbar and viewer toolbar). The menu contains all buttons from above, already with some hotkeys. Please check if they clash with your existing hotkey system.

The main button:

// ShowMulti DISPLAY=0 MODE=horiz
// ShowMulti DISPLAY=1 MODE=vert
// ShowMulti DISPLAY=2 MODE=quad
ShowMulti 
Button as XML
<?xml version="1.0"?>
<button backcol="none" display="both" label_pos="right" textcol="none">
	<label>Show Multi</label>
	<tip>Launch multiple viewers at once</tip>
	<icon1>#slideshow</icon1>
	<function type="normal">
		<instruction>// ShowMulti DISPLAY=0 MODE=horiz</instruction>
		<instruction>// ShowMulti DISPLAY=1 MODE=vert</instruction>
		<instruction>// ShowMulti DISPLAY=2 MODE=quad</instruction>
		<instruction>ShowMulti </instruction>
	</function>
</button>

The menu:

image

Menu as XML
<?xml version="1.0"?>
<button backcol="none" display="label" label_pos="right" textcol="none" type="menu">
	<label>Multi</label>
	<icon1>#newmenu</icon1>
	<button backcol="none" display="both" hotkey="ctrl+shift+N" label_pos="right" textcol="none">
		<label>Menu Bar Multi\tCtrl+Shift+N</label>
		<tip>Toggle Menu Bar in all open viewers</tip>
		<icon1>#empty</icon1>
		<function type="normal">
			<instruction>MenuBarMulti </instruction>
		</function>
	</button>
	<button backcol="none" display="both" hotkey="ctrl+shift+B" label_pos="right" textcol="none">
		<label>Status Bar Multi\tCtrl+Shift+B</label>
		<tip>Toggle Status Bar in all open viewers</tip>
		<icon1>#empty</icon1>
		<function type="normal">
			<instruction>StatusBarMulti </instruction>
		</function>
	</button>
	<button backcol="none" display="both" hotkey="ctrl+shift+L" label_pos="right" textcol="none">
		<label>Control Bar Multi\tCtrl+Shift+L</label>
		<tip>Toggle Control Bar in all open viewers</tip>
		<icon1>#empty</icon1>
		<function type="normal">
			<instruction>ControlBarMulti </instruction>
		</function>
	</button>
	<button backcol="none" display="both" hotkey="shift+alt+enter" label_pos="right" separate="yes" textcol="none">
		<label>Full Screen Multi\tAlt+Shift+Enter</label>
		<tip>Set all viewers to Full Screen</tip>
		<icon1>#empty</icon1>
		<function type="normal">
			<instruction>FullScreenMulti </instruction>
		</function>
	</button>
	<button backcol="none" display="both" hotkey="ctrl+shift+O" label_pos="right" textcol="none">
		<label>Original Size Multi\tCtrl+Shift+O</label>
		<tip>Set images in all viewers to original size</tip>
		<icon1>#empty</icon1>
		<function type="normal">
			<instruction>OriginalSizeMulti </instruction>
		</function>
	</button>
	<button backcol="none" display="both" hotkey="ctrl+shift+F" label_pos="right" textcol="none">
		<label>Fit To Page Multi\tCtrl+Shift+F</label>
		<tip>Zoom images in all viewers to fit</tip>
		<icon1>#empty</icon1>
		<function type="normal">
			<instruction>FitToPageMulti </instruction>
		</function>
	</button>
	<button backcol="none" display="both" label_pos="right" textcol="none">
		<label>Previous Image Multi\tJ / Shift+J</label>
		<tip>Jump backward by count of open viewers (Shift to jump by 1)</tip>
		<hotkeys>
			<key>J</key>
			<key>shift+J</key>
		</hotkeys>
		<icon1>#media_back</icon1>
		<function type="normal">
			<instruction>PreviousImageMulti </instruction>
		</function>
	</button>
	<button backcol="none" display="both" label_pos="right" textcol="none">
		<label>Next Image Multi\tK / Shift+K</label>
		<tip>Jump forward by count of open viewers (Shift to jump by 1)</tip>
		<hotkeys>
			<key>K</key>
			<key>shift+K</key>
		</hotkeys>
		<icon1>#media_forward</icon1>
		<function type="normal">
			<instruction>NextImageMulti </instruction>
		</function>
	</button>
</button>

And finally, if you haven't already, treat yourself to a button/hotkey like

Close ALLVIEWERS

You'll need it :wink:


You might enjoy reading

6 Likes