Tile all open KM palettes horizontally or vertically

A custom action which aligns all open KM palettes with the last palette to be moved
(either manually, or by any action or script which has brought the moved palette to the front).

The tiling can be vertical or horizontal, aligned to left or right edges, or to top or bottom edges.

If, for example, a palette has just been moved to a second display using Ver. 0.2 of the related Move a palette plugin, then this plugin will cause any other open palettes to follow it to the other display, and line up with it.

Tile all open KM palettes.zip (6.2 KB)

Custom Keyboard Maestro Plug-in

NAME

  • Tile all open KM palettes

VERSION

  • 0.1

SYNOPSIS

  • Lines up all open KM palettes with the last one to be moved
    • ( Either manually, or by any action or script which makes it the front palette )
  • For example, if one palette is moved to a position on a second display, this action will cause any other open palettes to follow it to the other display and align vertically or horizontally with it.

REQUIREMENTS

  • Yosemite
    • The core script movePalette.sh is mainly written in Javascript for Applications

OPTIONS

  • Direction of tiling

    • Down (top to bottom)
    • Right (left to right)
    • Up (bottom to top)
    • Left (right to left)
  • Alignment of tiling

    • Left aligned
    • Top aligned
    • Right aligned
    • Bottom aligned

INSTALLATION

  • Drag the .zip file onto the Keyboard Maestro icon in the OS X toolbar.
  • (if updating a previous version of the action, first manually remove the previous copy from the custom actions folder)
    • ~/Library/Application Support/Keyboard Maestro/Keyboard Maestro Actions

CONTACT


Uncompressed version of the .js code

// RobTrew  Twitter: @ComplexPoint June 2015
(function (strDirn, strAlign) {

	strDirn = strDirn ? strDirn.toLowerCase() : 'down';
	if (['down', 'up', 'left', 'right'].indexOf(strDirn) === -1)
		strDirn = 'down';

	var blnVertical = ['down', 'up'].indexOf(strDirn) !== -1,
		blnAZ = ['down', 'right'].indexOf(strDirn) !== -1,
		blnAlign = (['bottom', 'right'].indexOf(strAlign.toLowerCase()) !== -1);

	// Place a window, and return a position for the next one
	// lstPrevXY --> oWin --> lstNewXY
	function tileWin(lstPosn, oWin) {
		var lstSize = oWin.size(),
			lstAligned = blnAlign ? fnAlign(
				lstPosn, lstSize
			) : lstPosn;

		oWin.position = blnAZ ? lstAligned :
			(blnVertical ? [
				lstAligned[0],
				lstAligned[1] - lstSize[1]
			] : [
				lstAligned[0] - lstSize[0],
				lstAligned[1]
			])

		// and return an adjacent position for any successor.
		return [
			lstPosn[0] + (blnVertical ?
				0 : (blnAZ ? lstSize[0] : -lstSize[0])
			),
			lstPosn[1] + (blnVertical ?
				(blnAZ ? lstSize[1] : -lstSize[1]) : 0
			)
		];
	}

	// Derive a special alignment ( right | bottom )
	// lstPosn --> lstSize --> lstAlignedPosn
	function fnAlign(lstPosn, lstSize) {
		return blnVertical ? [
			lngMaxH - lstSize[0],
			lstPosn[1]
		] : [
			lstPosn[0],
			lngMaxY - lstSize[1]
		];
	}

	/************************************************************************/

	var appSE = Application("System Events"),
		lstProcs = appSE.applicationProcesses.whose({
			name: "Keyboard Maestro Engine"
		}),
		procKME = (lstProcs && lstProcs.length) ? lstProcs[0] : null;

	var lstWins = procKME ? procKME.windows() : [],
		lngWins = lstWins.length,
		oWin, lstStartPosn, lstPosn, lstSize,
		lngMaxH, lngMaxY;
		
	if (lngWins) {
		oWin = lstWins[0]; // Most recently moved ( manually | AXRaise )
		lstStartPosn = oWin.position();
		lstSize = oWin.size();
		
		if (blnAlign) { // marked alignments: to right or bottom
			lngMaxH = lstStartPosn[0] + lstSize[0];
			lngMaxY = lstStartPosn[1] + lstSize[1];
		}
		
		if (!blnAZ) { // marked directions: upwards or to right
			if (blnVertical) lstStartPosn[1] = (lstStartPosn[1] + lstSize[1]);
			else lstStartPosn[0] = (lstStartPosn[0] + lstSize[0]);
		}
		
		// NOW PLACE EACH TILE, DERIVING A POSITION FOR ITS SUCCESSOR
		lstWins.reduce(tileWin, lstStartPosn);
	}

	return 0;
})("down", "left");
2 Likes