mirror of
https://github.com/gosticks/PaperWM.git
synced 2026-08-12 12:10:27 +00:00
WIP:
- move most layout related function into separate file - restructure a bit - create cycleLayoutDir to allow explict control over which neighbour to use - add bindings for expandOrShrink (aka. "fit") right neighbour
This commit is contained in:
+2
-162
@@ -126,139 +126,6 @@ function cycleWorkspaceSettings(binding = "<Super>q") {
|
||||
);
|
||||
}
|
||||
|
||||
function expand(binding = "<Super><Shift>l") {
|
||||
var Tiling = Extension.imports.tiling;
|
||||
|
||||
function findNonVisibleIndex(space, metaWindow, dir=1, margin=1) {
|
||||
let k = space.indexOf(metaWindow) + dir;
|
||||
while (0 <= k && k < space.length && space.isFullyVisible(space[k][0], margin)) {
|
||||
k += dir;
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
||||
function action(metaWindow) {
|
||||
let space = Tiling.spaces.spaceOfWindow(metaWindow);
|
||||
|
||||
let a = findNonVisibleIndex(space, metaWindow, -1);
|
||||
let b = findNonVisibleIndex(space, metaWindow, 1);
|
||||
|
||||
let leftMost = space[a+1][0];
|
||||
let availableLeft = space.targetX + leftMost.clone.targetX;
|
||||
|
||||
let rightMost = space[b-1][0];
|
||||
let rightEdge = space.targetX + rightMost.clone.targetX + rightMost.clone.width;
|
||||
let availableRight = space.width - rightEdge;
|
||||
|
||||
let f = metaWindow.get_frame_rect();
|
||||
let available = f.width + availableRight + availableLeft - Tiling.prefs.horizontal_margin*2;
|
||||
|
||||
if (a+1 === b-1) {
|
||||
// We're the only window
|
||||
Tiling.toggleMaximizeHorizontally(metaWindow)
|
||||
} else {
|
||||
metaWindow.move_resize_frame(true, f.x, f.y, available, f.height);
|
||||
Tiling.move_to(space, space[a+1][0], { x: Tiling.prefs.horizontal_margin })
|
||||
}
|
||||
}
|
||||
|
||||
Keybindings.bindkey(binding, "expand-available-width", action, {activeInNavigator: true});
|
||||
}
|
||||
|
||||
function cycleLayouts(binding = "<Super>d") {
|
||||
var Tiling = Extension.imports.tiling;
|
||||
var Virt = Extension.imports.virtTiling;
|
||||
var Tweener = Extension.imports.utils.tweener;
|
||||
var Utils = Extension.imports.utils;
|
||||
var prefs = Tiling.prefs;
|
||||
|
||||
const splits = [
|
||||
[0.5, 0.5],
|
||||
[0.7, 0.3],
|
||||
[0.3, 0.7]
|
||||
];
|
||||
|
||||
function moveTo(space, metaWindow, target) {
|
||||
space.startAnimate();
|
||||
space.targetX = target;
|
||||
Tweener.addTween(space.cloneContainer,
|
||||
{ x: space.targetX,
|
||||
time: prefs.animation_time,
|
||||
onComplete: space.moveDone.bind(space)
|
||||
});
|
||||
|
||||
space.fixOverlays(metaWindow);
|
||||
}
|
||||
|
||||
function action(metaWindow, space, {navigator}={}) {
|
||||
const m = 50
|
||||
space = Tiling.spaces.spaceOfWindow(metaWindow);
|
||||
|
||||
prefs = {...prefs, minimum_margin: Tiling.minimumMargin()}
|
||||
|
||||
const tiling = Virt.layout(Virt.fromSpace(space), space.workArea(), prefs);
|
||||
|
||||
function resize(i, width) {
|
||||
for (let w of tiling[i]) {
|
||||
w.width = width;
|
||||
}
|
||||
}
|
||||
|
||||
let k = space.indexOf(metaWindow);
|
||||
let next = space.length > k+1 && space.isVisible(space[k+1][0], m) && space[k+1][0];
|
||||
let prev = k > 0 && space.isVisible(space[k-1][0], m) && space[k-1][0];
|
||||
|
||||
|
||||
let neighbour = next || prev;
|
||||
let f = metaWindow.get_frame_rect();
|
||||
let f2 = neighbour.get_frame_rect();
|
||||
|
||||
let neighbourK = space.indexOf(neighbour);
|
||||
|
||||
let available = space.width - Tiling.prefs.horizontal_margin*2 - Tiling.prefs.window_gap;
|
||||
|
||||
let s1 = f.width / available;
|
||||
let s2 = f2.width / available;
|
||||
|
||||
let state;
|
||||
if (!navigator["cycle-layouts"]) {
|
||||
navigator["cycle-layouts"] = {i: Utils.eq(s1, splits[0][0]) ? 1 : 0 }
|
||||
}
|
||||
state = navigator["cycle-layouts"];
|
||||
|
||||
let [a, b] = splits[(state.i++) % splits.length];
|
||||
|
||||
let metaWindowWidth = Math.round(available * a);;
|
||||
metaWindow.move_resize_frame(true, f.x, f.y, metaWindowWidth, f.height);
|
||||
resize(k, metaWindowWidth);
|
||||
|
||||
let neighbourWidth = Math.round(available * b);
|
||||
neighbour.move_resize_frame(true, f2.x, f2.y, neighbourWidth, f2.height);
|
||||
resize(neighbourK, neighbourWidth);
|
||||
|
||||
Virt.layout(tiling, space.workArea(), prefs);
|
||||
|
||||
let margin = Tiling.prefs.horizontal_margin;
|
||||
let width = f.width;
|
||||
let workarea = space.workArea();
|
||||
let wax = workarea.x - space.monitor.x;
|
||||
|
||||
let leftSnapPos = wax + margin;
|
||||
let rightSnapPos = wax + workarea.width - metaWindowWidth - margin;
|
||||
|
||||
if (neighbour == next) {
|
||||
print("next", metaWindow.title, leftSnapPos, tiling[k][0].x);
|
||||
moveTo(space, metaWindow, leftSnapPos - tiling[k][0].x);
|
||||
// Tiling.move_to(space, metaWindow, {x: leftSnapPos});
|
||||
} else {
|
||||
print("prev", neighbour.title, rightSnapPos, tiling[neighbourK][0].x);
|
||||
moveTo(space, neighbour, leftSnapPos - tiling[neighbourK][0].x);
|
||||
// Tiling.move_to(space, neighbour, {x: leftSnapPos});
|
||||
}
|
||||
}
|
||||
|
||||
Keybindings.bindkey(binding, "cycle-layouts", action, { opensNavigator: true })
|
||||
}
|
||||
|
||||
function showNavigator(binding = "<Super>j") {
|
||||
Keybindings.bindkey(binding, "show-minimap", () => null, { opensMinimap: true })
|
||||
@@ -341,37 +208,10 @@ function adjustWidth(incBinding="<Super>plus", decBinding="<Super>minus", increm
|
||||
Keybindings.bindkey(decBinding, "dec-width", adjuster(-increment));
|
||||
}
|
||||
|
||||
function tileInto(leftBinding="<Super>less", rightBinding="<Super><Shift>less") {
|
||||
// less: '<'
|
||||
let Tiling = Extension.imports.tiling;
|
||||
|
||||
const tileIntoDirection = (dir=-1) => (metaWindow) => {
|
||||
let space = Tiling.spaces.spaceOfWindow(metaWindow);
|
||||
let jFrom = space.indexOf(metaWindow);
|
||||
let jTo = jFrom + dir;
|
||||
if (jTo < 0 || jTo >= space.length)
|
||||
return;
|
||||
|
||||
space[jFrom].splice(space.rowOf(metaWindow), 1);
|
||||
space[jTo].push(metaWindow);
|
||||
|
||||
if (space[jFrom].length === 0) {
|
||||
space.splice(jFrom, 1);
|
||||
}
|
||||
space.layout(true, {
|
||||
customAllocators: { [space.indexOf(metaWindow)]: Tiling.allocateEqualHeight }
|
||||
});
|
||||
space.emit("full-layout");
|
||||
}
|
||||
|
||||
let options = { activeInNavigator: true };
|
||||
if (leftBinding)
|
||||
Keybindings.bindkey(leftBinding, "tile-into-left-column", tileIntoDirection(-1), options);
|
||||
if (rightBinding)
|
||||
Keybindings.bindkey(rightBinding, "tile-into-right-column", tileIntoDirection(1), options);
|
||||
function tileInto(leftBinding="<Super><Shift>less", rightBinding="<Super><Shift>less") {
|
||||
Extension.imports.examples.layouts.bindTileInto(leftBinding, rightBinding);
|
||||
}
|
||||
|
||||
|
||||
function cycleEdgeSnap(binding = "<Super>u") {
|
||||
var Tiling = Extension.imports.tiling;
|
||||
var Meta = imports.gi.Meta;
|
||||
|
||||
@@ -0,0 +1,260 @@
|
||||
var Extension;
|
||||
if (imports.misc.extensionUtils.extensions) {
|
||||
Extension = imports.misc.extensionUtils.extensions["paperwm@hedning:matrix.org"];
|
||||
} else {
|
||||
Extension = imports.ui.main.extensionManager.lookup("paperwm@hedning:matrix.org");
|
||||
}
|
||||
var Keybindings = Extension.imports.keybindings;
|
||||
var Main = imports.ui.main;
|
||||
var Tiling = Extension.imports.tiling;
|
||||
var Scratch = Extension.imports.scratch;
|
||||
var Virt = Extension.imports.virtTiling;
|
||||
var Tweener = Extension.imports.utils.tweener;
|
||||
var Utils = Extension.imports.utils;
|
||||
var prefs = Tiling.prefs;
|
||||
|
||||
|
||||
/** Adapts an action handler to operate on the neighbour in the given direction */
|
||||
function useNeigbour(dir, action) {
|
||||
return (metaWindow) => {
|
||||
let space = Tiling.spaces.spaceOfWindow(metaWindow)
|
||||
let i = space.indexOf(metaWindow)
|
||||
if (!space[i+dir])
|
||||
return action(undefined)
|
||||
|
||||
return action(space[i+dir][0])
|
||||
}
|
||||
}
|
||||
|
||||
/** Find the index of the first not fully visible column in the given direction */
|
||||
function findNonVisibleIndex(space, metaWindow, dir=1, margin=1) {
|
||||
let k = space.indexOf(metaWindow) + dir;
|
||||
while (0 <= k && k < space.length && space.isFullyVisible(space[k][0], margin)) {
|
||||
k += dir;
|
||||
}
|
||||
return k
|
||||
}
|
||||
|
||||
function moveTo(space, metaWindow, target) {
|
||||
space.startAnimate();
|
||||
space.targetX = target;
|
||||
Tweener.addTween(space.cloneContainer,
|
||||
{ x: space.targetX,
|
||||
time: prefs.animation_time,
|
||||
onComplete: space.moveDone.bind(space)
|
||||
});
|
||||
|
||||
space.fixOverlays();
|
||||
}
|
||||
|
||||
function getLeftSnapPosition(space) {
|
||||
let margin = Tiling.prefs.horizontal_margin;
|
||||
let workarea = space.workArea();
|
||||
let wax = workarea.x - space.monitor.x;
|
||||
|
||||
return wax + margin;
|
||||
}
|
||||
|
||||
function getSnapPositions(space, windowWidth) {
|
||||
let margin = Tiling.prefs.horizontal_margin;
|
||||
let workarea = space.workArea();
|
||||
let wax = workarea.x - space.monitor.x;
|
||||
|
||||
let leftSnapPos = wax + margin;
|
||||
let rightSnapPos = wax + workarea.width - windowWidth - margin;
|
||||
return [leftSnapPos, rightSnapPos]
|
||||
}
|
||||
|
||||
function mkVirtTiling(space) {
|
||||
return Virt.layout(Virt.fromSpace(space), space.workArea(), prefs);
|
||||
}
|
||||
|
||||
function moveToViewport(space, tiling, i, vx) {
|
||||
moveTo(space, null, vx - tiling[i][0].x);
|
||||
}
|
||||
|
||||
function resize(tiling, i, width) {
|
||||
for (let w of tiling[i]) {
|
||||
w.width = width;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////// Actions
|
||||
|
||||
|
||||
/**
|
||||
Expands or shrinks the window to fit the available viewport space.
|
||||
Available space is space not occupied by fully visible windows
|
||||
Will move the tiling as necessary.
|
||||
*/
|
||||
function fitAvailable(metaWindow) {
|
||||
// TERMINOLOGY: mold-into ?
|
||||
let space = Tiling.spaces.spaceOfWindow(metaWindow);
|
||||
|
||||
let a = findNonVisibleIndex(space, metaWindow, -1);
|
||||
let b = findNonVisibleIndex(space, metaWindow, 1);
|
||||
|
||||
let leftMost = space[a+1][0];
|
||||
let availableLeft = space.targetX + leftMost.clone.targetX;
|
||||
|
||||
let rightMost = space[b-1][0];
|
||||
let rightEdge = space.targetX + rightMost.clone.targetX + rightMost.clone.width;
|
||||
let availableRight = space.width - rightEdge;
|
||||
|
||||
let f = metaWindow.get_frame_rect();
|
||||
let available = f.width + availableRight + availableLeft - Tiling.prefs.horizontal_margin*2;
|
||||
|
||||
if (a+1 === b-1) {
|
||||
// We're the only window
|
||||
Tiling.toggleMaximizeHorizontally(metaWindow)
|
||||
} else {
|
||||
metaWindow.move_resize_frame(true, f.x, f.y, available, f.height);
|
||||
Tiling.move_to(space, space[a+1][0], { x: Tiling.prefs.horizontal_margin })
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
||||
function cycleLayoutDirection(dir) {
|
||||
|
||||
const splits = [
|
||||
[0.5, 0.5],
|
||||
[0.7, 0.3],
|
||||
[0.3, 0.7]
|
||||
];
|
||||
|
||||
return (metaWindow, space, {navigator}={}) => {
|
||||
let k = space.indexOf(metaWindow)
|
||||
let j = k+dir
|
||||
let neighbourCol = space[j]
|
||||
if (!neighbourCol)
|
||||
return
|
||||
|
||||
let neighbour = neighbourCol[0]
|
||||
|
||||
let tiling = mkVirtTiling(space)
|
||||
|
||||
let available = space.width - Tiling.prefs.horizontal_margin*2 - Tiling.prefs.window_gap;
|
||||
|
||||
let f1 = metaWindow.get_frame_rect();
|
||||
let f2 = neighbour.get_frame_rect();
|
||||
|
||||
let s1 = f1.width / available;
|
||||
let s2 = f2.width / available;
|
||||
|
||||
let state;
|
||||
if (!navigator["cycle-layouts"]) {
|
||||
navigator["cycle-layouts"] = {i: Utils.eq(s1, splits[0][0]) ? 1 : 0 }
|
||||
}
|
||||
state = navigator["cycle-layouts"];
|
||||
|
||||
let [a, b] = splits[state.i % splits.length];
|
||||
state.i++;
|
||||
|
||||
let metaWindowWidth = Math.round(available * a);;
|
||||
metaWindow.move_resize_frame(true, f1.x, f1.y, metaWindowWidth, f1.height);
|
||||
resize(tiling, k, metaWindowWidth);
|
||||
|
||||
let neighbourWidth = Math.round(available * b);
|
||||
neighbour.move_resize_frame(true, f2.x, f2.y, neighbourWidth, f2.height);
|
||||
resize(tiling, j, neighbourWidth);
|
||||
|
||||
Virt.layout(tiling, space.workArea(), prefs);
|
||||
|
||||
let snapLeft = getLeftSnapPosition(space)
|
||||
|
||||
if (dir === 1)
|
||||
moveToViewport(space, tiling, k, snapLeft);
|
||||
else
|
||||
moveToViewport(space, tiling, j, snapLeft);
|
||||
}
|
||||
}
|
||||
|
||||
function cycleLayouts(binding = "<Super>d") {
|
||||
function action(metaWindow, space, {navigator}={}) {
|
||||
const m = 50
|
||||
space = Tiling.spaces.spaceOfWindow(metaWindow);
|
||||
|
||||
let k = space.indexOf(metaWindow);
|
||||
let next = space.length > k+1 && space.isVisible(space[k+1][0], m) && space[k+1][0];
|
||||
let prev = k > 0 && space.isVisible(space[k-1][0], m) && space[k-1][0];
|
||||
|
||||
let neighbour = next || prev;
|
||||
|
||||
if (neighbour === next) {
|
||||
return cycleLayoutDirection(1)(metaWindow, space, {navigator})
|
||||
} else {
|
||||
return cycleLayoutDirection(-1)(metaWindow, space, {navigator})
|
||||
}
|
||||
}
|
||||
|
||||
Keybindings.bindkey(binding, "cycle-layouts", action, { opensNavigator: true });
|
||||
}
|
||||
|
||||
|
||||
function tileInto(dir=-1) {
|
||||
return (metaWindow, space) => {
|
||||
space = space || Tiling.spaces.spaceOfWindow(metaWindow);
|
||||
let jFrom = space.indexOf(metaWindow);
|
||||
if (space[jFrom].length > 1) {
|
||||
return tileOut(dir)(metaWindow, space);
|
||||
}
|
||||
let jTo = jFrom + dir;
|
||||
if (jTo < 0 || jTo >= space.length)
|
||||
return;
|
||||
|
||||
space[jFrom].splice(space.rowOf(metaWindow), 1);
|
||||
space[jTo].push(metaWindow);
|
||||
|
||||
if (space[jFrom].length === 0) {
|
||||
space.splice(jFrom, 1);
|
||||
}
|
||||
space.layout(true, {
|
||||
customAllocators: { [space.indexOf(metaWindow)]: Tiling.allocateEqualHeight }
|
||||
});
|
||||
space.emit("full-layout");
|
||||
}
|
||||
}
|
||||
|
||||
function tileOut(dir) {
|
||||
return (metaWindow, space) => {
|
||||
space = space || Tiling.spaces.spaceOfWindow(metaWindow);
|
||||
let [j, i] = space.positionOf(metaWindow);
|
||||
if (space[j].length === 0)
|
||||
return;
|
||||
|
||||
space[j].splice(i, 1);
|
||||
space.splice(j + (dir === 1 ? 1 : 0), 0, [metaWindow]);
|
||||
space.layout();
|
||||
space.emit("full-layout");
|
||||
space.fixOverlays();
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
////// Bindings
|
||||
|
||||
function bindTileInto(leftBinding="<Super><Alt>Left", rightBinding="<Super><Alt>Right") {
|
||||
let options = { activeInNavigator: true };
|
||||
if (leftBinding)
|
||||
Keybindings.bindkey(leftBinding, "tile-into-left-column", tileInto(-1), options);
|
||||
if (rightBinding)
|
||||
Keybindings.bindkey(rightBinding, "tile-into-right-column", tileInto(1), options);
|
||||
}
|
||||
|
||||
function bindTileOut(left="<Super><Ctrl>k", right="<Super><Ctrl>l") {
|
||||
Keybindings.bindkey(left, "tile-out-left", tileOut(-1), {activeInNavigator: true});
|
||||
Keybindings.bindkey(right, "tile-out-right", tileOut(1), {activeInNavigator: true});
|
||||
}
|
||||
|
||||
|
||||
function bindFitAvailable(focus = "<Super>l", right="<Super><Shift>l") {
|
||||
Keybindings.bindkey(focus, "fit-available-width", fitAvailable, {activeInNavigator: true});
|
||||
Keybindings.bindkey(right, "fit-available-width-right", useNeigbour(1, fitAvailable), {activeInNavigator: true});
|
||||
}
|
||||
|
||||
function bindCycleLayoutDirection(left="<Super><Shift>d", right="<Super>d") {
|
||||
Keybindings.bindkey(left, "cycle-layout-left", cycleLayoutDirection(-1), { opensNavigator: true });
|
||||
Keybindings.bindkey(right, "cycle-layout-right", cycleLayoutDirection(1), { opensNavigator: true });
|
||||
}
|
||||
@@ -36,9 +36,6 @@ function repl() {
|
||||
width: monitorWidth*3
|
||||
})
|
||||
|
||||
// let canvasStyle = `background-color: yellow;`
|
||||
canvasStyle = ""
|
||||
// let canvas = new St.Widget({name: "canvas", style: canvasStyle, x: 5, y: 5})
|
||||
let monitorStyle = `background-color: blue;`
|
||||
let monitor = new St.Widget({
|
||||
name: "monitor0",
|
||||
@@ -92,7 +89,6 @@ function repl() {
|
||||
Utils.printActorTree(virtStage, Utils.mkFmt({nameOnly: true}))
|
||||
|
||||
movecolumntoviewportposition(tilingContainer, monitor, columns[1][0], 30)
|
||||
// Utils.printA
|
||||
|
||||
virtStage.hide()
|
||||
virtStage.show()
|
||||
|
||||
Reference in New Issue
Block a user