Skip to content

Instantly share code, notes, and snippets.

@swieder227 swieder227/.phoenix.js
Last active Nov 13, 2017

Embed
What would you like to do?
A config file for Phoenix
/***********************************************
Seth Wieder's Config file for Phoenix.js, an OS X window management tool
Last Tested with Version 2.5
https://github.com/kasper/phoenix/
***********************************************/
Phoenix.set({
daemon: false,
openAtLogin: true
});
/***********************************************
* Debugging
***********************************************/
const debugMode = false;
// Prints to Applications > Utilities > Console
function debug( message ) {
if ( debugMode ) Phoenix.log( message );
}
/***********************************************
* Functions
***********************************************/
function centerWindowInFrame( window, targetFrame ) {
var windowFrame = window.frame(),
targetFrameCenter = {x: targetFrame.x + targetFrame.width / 2, y: targetFrame.y + targetFrame.height / 2};
window.setTopLeft( {x: targetFrameCenter.x - windowFrame.width / 2, y: targetFrameCenter.y - windowFrame.height / 2} );
}
function getNextScreen( window ) {
return window.screen().next();
}
function getPreviousScreen( window ) {
return window.screen().previous();
}
function getCurrentWindow(){
return Window.focused();
}
function getCurrentScreenFrame(){
return getCurrentWindow().screen().flippedVisibleFrame();
}
/***********************************************
* BINDINGS
***********************************************/
const modCtrlAlt = ['ctrl','alt'];
const modCtrlAltCmd = ['ctrl','alt','cmd'];
const modShftCtrlAlt = ['shift','ctrl','alt'];
// Full/Center
Key.on( 'f', modCtrlAltCmd, function() {
debug( 'Maximizing current window' );
getCurrentWindow().maximize();
} );
Key.on( 'c', modCtrlAltCmd, function() {
debug( 'Centering in screen' );
var screenFrame = getCurrentScreenFrame();
centerWindowInFrame( getCurrentWindow(), screenFrame );
} );
// Halfs
Key.on( 'left', modCtrlAlt, function() {
debug( 'Moving to left-half' );
var screenFrame = getCurrentScreenFrame();
getCurrentWindow().setFrame( {x: screenFrame.x, y: screenFrame.y, width: screenFrame.width / 2, height: screenFrame.height} );
} );
Key.on( 'right', modCtrlAlt, function() {
debug( 'Moving to right-half' );
var screenFrame = getCurrentScreenFrame();
getCurrentWindow().setFrame( {x: screenFrame.x + screenFrame.width / 2, y: screenFrame.y, width: screenFrame.width / 2, height: screenFrame.height} );
} );
// Top/Bottom 80/20 - ideal for vertical monitors
Key.on( 'up', modCtrlAlt, function() {
debug( 'Moving to top 80' );
var screenFrame = getCurrentScreenFrame();
getCurrentWindow().setFrame( {x: screenFrame.x, y: screenFrame.y, width: screenFrame.width, height: screenFrame.height * 0.8} );
} );
Key.on( 'down', modCtrlAlt, function() {
debug( 'Moving to bottom 20' );
var screenFrame = getCurrentScreenFrame();
getCurrentWindow().setFrame( {x: screenFrame.x, y: screenFrame.y + screenFrame.height * 0.8, width: screenFrame.width, height: screenFrame.height * 0.2} );
} );
// Quarters
Key.on( 'keypad7', modShftCtrlAlt, function() {
debug( 'Moving to top-left 25%' );
var screenFrame = getCurrentScreenFrame();
getCurrentWindow().setFrame( {x: screenFrame.x, y: screenFrame.y, width: screenFrame.width / 2, height: screenFrame.height / 2} );
} );
Key.on( 'keypad1', modShftCtrlAlt, function() {
debug( 'Moving to bottom-left 25%' );
var screenFrame = getCurrentScreenFrame();
getCurrentWindow().setFrame( {x: screenFrame.x, y: screenFrame.y + screenFrame.height / 2, width: screenFrame.width / 2, height: screenFrame.height / 2} );
} );
Key.on( 'keypad3', modShftCtrlAlt, function() {
debug( 'Moving to bottom-right 25%' );
var screenFrame = getCurrentScreenFrame();
getCurrentWindow().setFrame( {x: screenFrame.x + screenFrame.width / 2, y: screenFrame.y + screenFrame.height / 2, width: screenFrame.width / 2, height: screenFrame.height / 2} );
} );
Key.on( 'keypad9', modShftCtrlAlt, function() {
debug( 'Moving to top-right 25%' );
var screenFrame = getCurrentScreenFrame();
getCurrentWindow().setFrame( {x: screenFrame.x + screenFrame.width / 2, y: screenFrame.y, width: screenFrame.width / 2, height: screenFrame.height / 2} );
} );
// Screen Switch
Key.on( 'left', modCtrlAltCmd, function() {
debug( 'Switch to Left Screen' );
if(Screen.all().length > 1){
var win = getCurrentWindow(),
targetWindow = getNextScreen(win);
getCurrentWindow().setFrame(targetWindow.flippedVisibleFrame());
}
} );
Key.on( 'right', modCtrlAltCmd, function() {
debug( 'Switch to Right Screen' );
if(Screen.all().length > 1){
var win = getCurrentWindow(),
targetWindow = getPreviousScreen(win);
getCurrentWindow().setFrame(targetWindow.flippedVisibleFrame());
}
} );
Key.on( 'right', modShftCtrlAlt, function(){
debug('Select screen to "east"');
getCurrentWindow().focusClosestNeighbour('east')
} );
Key.on('left', modShftCtrlAlt, function () {
debug('Select screen to "west"');
getCurrentWindow().focusClosestNeighbour('west')
});
/***********************************************
* Hints
***********************************************/
var HINT_APPEARANCE = "dark";
var HINT_BUTTON = "x";
var HINT_CANCEL = "escape";
var HINT_CHARS = "QWERTYASDFGHZXCVB";
var hintsActive = false;
var hintkeys = [];
var hints = {};
var escbind = null;
var bsbind = null;
function cancelHints () {
for (var activator in hints) {
hints[activator].modal.close();
};
Key.off(escbind);
Key.off(bsbind);
hintkeys.map(Key.off);
hints = {};
hintkeys = [];
hintsActive = false;
}
function showHints (windows, prefix) {
prefix = prefix || "";
if (windows.length > HINT_CHARS.length) {
var partitionSize = Math.floor(windows.length / HINT_CHARS.length);
var lists = _.toArray(_.groupBy(windows, function (win, k) {
return k % HINT_CHARS.length;
}));
for (var j = 0; j < HINT_CHARS.length; j++) {
showHints(lists[j], prefix + HINT_CHARS[j]);
}
return;
}
windows.forEach(function (win, i) {
var helper = "";
if (win.app().windows().length > 1) {
helper += " | " + win.title().substr(0, 15) + (win.title().length > 15 ? "" : "");
}
var hint = buildhint(prefix + HINT_CHARS[i] + helper, win);
var activators = Object.keys(hints);
for (var l = 0; l < activators.length; l++) {
var hint2 = hints[activators[l]].modal;
if (
hint.origin.x < hint2.origin.x + hint2.frame().width + 10
&& hint.origin.x + hint.frame().width > hint2.origin.x - 10
&& hint.origin.y < hint2.origin.y + hint2.frame().height + 10
&& hint.origin.y + hint.frame().width > hint2.origin.y - 10
) {
hint.origin = {
x: hint.origin.x,
y: hint2.origin.y + hint2.frame().height + 10
};
l = -1;
}
}
hints[prefix + HINT_CHARS[i]] = {
win: win,
modal: hint,
position: 0,
active: true
};
});
escbind = Key.on(HINT_CANCEL, [], cancelHints);
hintsActive = true;
}
Key.on(HINT_BUTTON, modCtrlAlt, function () {
if (hintsActive) {
cancelHints();
} else {
showHints(Window.all({
visible: true
}));
var sequence = "";
HINT_CHARS.split("").forEach(function (hintchar) {
hintkeys.push(Key.on(hintchar, [], function () {
sequence += hintchar;
for (var activator in hints) {
var hint = hints[activator];
if (!hint.active) continue;
if (activator[hint.position] === hintchar) {
hint.position++;
if (hint.position === activator.length) {
hint.win.focus();
Mouse.move({
x: hint.modal.origin.x + hint.modal.frame().width / 2,
y: Screen.all()[0].frame().height - hint.modal.origin.y - hint.modal.frame().height / 2
});
return cancelHints();
}
hint.modal.text = hint.modal.text.substr(1);
} else {
hint.modal.close();
hint.active = false;
}
}
}));
});
bsbind = Key.on("delete", [], function () {
if (!sequence.length) cancelHints();
var letter = sequence[sequence.length - 1];
sequence = sequence.substr(0, sequence.length - 1);
for (var activator in hints) {
var hint = hints[activator];
if (hint.active) {
hint.position--;
hint.modal.text = letter + hint.modal.text;
} else if (activator.substr(0, sequence.length) === sequence) {
hint.modal.show();
hint.active = true;
}
}
});
}
});
Event.on("mouseDidLeftClick", cancelHints);
function buildhint (msg, win) {
var wf = win.frame();
var wsf = win.screen().frame();
var modal = Modal.build({
text: msg,
appearance: HINT_APPEARANCE,
icon: win.app().icon(),
weight: 16
});
var mf = modal.frame();
modal.origin = {
x: Math.min(
Math.max(wf.x + wf.width / 2 - mf.width / 2, wsf.x),
wsf.x + wsf.width - mf.width
),
y: Math.min(
Math.max(Screen.all()[0].frame().height - (wf.y + wf.height / 2 + mf.height / 2), wsf.y),
wsf.y + wsf.height - mf.height
)
};
modal.show();
return modal;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.