mirror of
https://github.com/gosticks/PaperWM.git
synced 2026-10-06 11:56:54 +00:00
horizontal swipe: Rework target window logic
Not the prettiest code, but it works fairly well. Selecting the target window works like this (when gliding is finished): - if the tiling is outside the monitor select the first/last window and snap - if there's any fully visible windows select the closest one - if there's no visible window choose the window with highest visible width ratio This is all calculated the moment we release the swipe, so instead of showing any potential overshoot we simply adjust the travel so it doesn't overshoot.
This commit is contained in:
+69
-65
@@ -105,6 +105,7 @@ function disable() {
|
||||
Handle scrolling horizontally in a space. The handler is meant to be
|
||||
connected from each space.background and bound to the space.
|
||||
*/
|
||||
let start;
|
||||
function horizontalScroll(actor, event) {
|
||||
if (event.type() !== Clutter.EventType.TOUCHPAD_SWIPE ||
|
||||
event.get_touchpad_gesture_finger_count() > 3) {
|
||||
@@ -117,6 +118,7 @@ function horizontalScroll(actor, event) {
|
||||
if (direction === undefined) {
|
||||
this.vx = 0;
|
||||
this.hState = phase;
|
||||
start = this.targetX;
|
||||
Tweener.removeTweens(this.cloneContainer);
|
||||
direction = DIRECTIONS.Horizontal;
|
||||
}
|
||||
@@ -141,69 +143,63 @@ function update(space, dx, t) {
|
||||
}
|
||||
|
||||
function done(space) {
|
||||
if (!Number.isFinite(space.vx)) {
|
||||
if (!Number.isFinite(space.vx) || space.length === 0) {
|
||||
navigator.finish();
|
||||
space.hState = -1;
|
||||
return Clutter.EVENT_STOP;
|
||||
}
|
||||
|
||||
// Only snap to the edges if we started gliding when the viewport is fully covered
|
||||
let snap = !(0 <= space.cloneContainer.x ||
|
||||
space.targetX + space.cloneContainer.width <= space.width);
|
||||
let startGlide = space.targetX;
|
||||
|
||||
let start = space.targetX;
|
||||
let accel = .3/16; // ms/s^2
|
||||
// timetravel
|
||||
let accel = .3/16; // px/ms^2
|
||||
accel = space.vx > 0 ? -accel : accel;
|
||||
let t = -space.vx/accel;
|
||||
let d = space.vx*t + .5*accel*t**2;
|
||||
let target = Math.round(space.targetX - d);
|
||||
|
||||
// timetravel
|
||||
let mode = Clutter.AnimationMode.EASE_OUT;
|
||||
let first = space[0][0];
|
||||
let last = space[space.length-1][0];
|
||||
let mode = Clutter.AnimationMode.EASE_OUT_QUAD;
|
||||
let first;
|
||||
let last;
|
||||
|
||||
if (snap && target > 0) {
|
||||
target = 0; // snap to left edge
|
||||
let full = space.cloneContainer.width > space.width;
|
||||
// Only snap to the edges if we started gliding when the viewport is fully covered
|
||||
let snap = !(0 <= space.targetX ||
|
||||
space.targetX + space.cloneContainer.width <= space.width);
|
||||
if ((snap && target > 0)
|
||||
|| (full && target > space.width*2)) {
|
||||
// Snap to left edge
|
||||
first = space[0][0];
|
||||
target = 0;
|
||||
mode = Clutter.AnimationMode.EASE_OUT_BACK;
|
||||
} else if (snap && target + space.cloneContainer.width < space.width) {
|
||||
} else if ((snap && target + space.cloneContainer.width < space.width)
|
||||
|| (full && target + space.cloneContainer.width < -space.width)) {
|
||||
// Snap to right edge
|
||||
last = space[space.length-1][0];
|
||||
target = space.width - space.cloneContainer.width;
|
||||
mode = Clutter.AnimationMode.EASE_OUT_BACK;
|
||||
} else if (target + first.clone.width > space.width) {
|
||||
target = space.width - first.clone.width;
|
||||
mode = Clutter.AnimationMode.EASE_OUT_BACK;
|
||||
} else if (target + space.cloneContainer.width - first.clone.width < 0) {
|
||||
target = last.clone.width - space.cloneContainer.width;
|
||||
mode = Clutter.AnimationMode.EASE_OUT_BACK;
|
||||
}
|
||||
|
||||
|
||||
log(`2. tweeen from ${space.targetX} to ${space.targetX + d} in ${t}`);
|
||||
// Adjust for target window
|
||||
let selected;
|
||||
// adjust for window
|
||||
space.targetX = Math.round(target);
|
||||
selected = focusWindowAtPointer(space, snap, start - target > 0 );
|
||||
delete selected.lastFrame;
|
||||
selected = last || first || findTargetWindow(space, start - target > 0 );
|
||||
delete selected.lastFrame; // Invalidate frame information
|
||||
let x = Tiling.ensuredX(selected, space);
|
||||
target = x - selected.clone.targetX;
|
||||
|
||||
let newD = Math.abs(start - target);
|
||||
// Scale down travel time if we've cut down the discance to travel
|
||||
let newD = Math.abs(startGlide - target);
|
||||
if (newD < Math.abs(d))
|
||||
t = t*Math.abs(newD/d);
|
||||
|
||||
if (target !== space.targetX) {
|
||||
space.targetX = target;
|
||||
t = Math.max(t, 200);
|
||||
log(`min duration`)
|
||||
}
|
||||
if (mode !== Clutter.AnimationMode.EASE_OUT) {
|
||||
log(`min duration`)
|
||||
// Use a minimum duration if we've adjusted travel
|
||||
if (target !== space.targetX || mode === Clutter.AnimationMode.EASE_OUT_BACK) {
|
||||
t = Math.max(t, 200);
|
||||
}
|
||||
space.targetX = target;
|
||||
|
||||
// Main.activateWindow(selected);
|
||||
Tiling.updateSelection(space, selected);
|
||||
// Tweener.removeTweens(space.cloneContainer);
|
||||
Tweener.addTween(space.cloneContainer, {
|
||||
x: space.targetX,
|
||||
duration: t,
|
||||
@@ -220,46 +216,54 @@ function done(space) {
|
||||
}
|
||||
|
||||
|
||||
function focusWindowAtPointer(space, snap) {
|
||||
let [aX, aY, mask] = global.get_pointer();
|
||||
let [ok, x, y] = space.actor.transform_stage_point(aX, aY);
|
||||
space.targetX = Math.round(space.targetX);
|
||||
// space.cloneContainer.x = space.targetX;
|
||||
|
||||
function findTargetWindow(space, direction) {
|
||||
let selected = space.selectedWindow.clone;
|
||||
if (!(selected.x + space.targetX >= 0 &&
|
||||
selected.x + selected.width + space.targetX <= space.width)) {
|
||||
selected = false;
|
||||
if (selected.x + space.targetX >= 0 &&
|
||||
selected.x + selected.width + space.targetX <= space.width) {
|
||||
return selected.meta_window;
|
||||
}
|
||||
selected = selected && space.selectedWindow;
|
||||
|
||||
let pointerAt;
|
||||
let gap = prefs.window_gap/2;
|
||||
for (let w of space.getWindows()) {
|
||||
let windows = space.getWindows().filter(space.isPlaceable.bind(space));
|
||||
if (!direction) // scroll left
|
||||
windows.reverse();
|
||||
let visible = windows.filter(w => {
|
||||
let clone = w.clone;
|
||||
if (clone.x + space.targetX - gap <= x
|
||||
&& x <= clone.x + space.targetX + clone.width + gap) {
|
||||
pointerAt = w;
|
||||
break;
|
||||
return clone.x + space.targetX >= 0 &&
|
||||
clone.x + clone.width + space.targetX <= space.width;
|
||||
});
|
||||
if (visible.length > 0) {
|
||||
return visible[0];
|
||||
}
|
||||
|
||||
if (windows.length === 0) {
|
||||
let first = space.getWindow(0, 0);
|
||||
let last = space.getWindow(space.length - 1, 0);
|
||||
if (direction) {
|
||||
return last;
|
||||
} else {
|
||||
return first;
|
||||
}
|
||||
}
|
||||
|
||||
let first, last;
|
||||
if (space.cloneContainer.width < space.width) {
|
||||
// space.layout();
|
||||
} else if (0 <= space.cloneContainer.x && snap) {
|
||||
first = space[0][0];
|
||||
// Tiling.move_to(space, first, {x: 0});
|
||||
} else if (space.targetX + space.cloneContainer.width <= space.width && snap) {
|
||||
last = space[space.length-1][0];
|
||||
// Tiling.move_to(space, last, {x: space.width - last.clone.width});
|
||||
}
|
||||
if (windows.length === 1)
|
||||
return windows[0];
|
||||
|
||||
let target = selected || pointerAt || last || first;
|
||||
return target;
|
||||
// Tiling.ensureViewport(target, space);
|
||||
// if (!Tiling.inPreview)
|
||||
// Navigator.getNavigator().finish();
|
||||
let closest = windows[0].clone;
|
||||
let next = windows[1].clone;
|
||||
let r1, r2;
|
||||
if (direction) { // ->
|
||||
r1 = Math.abs(closest.targetX + closest.width + space.targetX)/closest.width;
|
||||
r2 = Math.abs(next.targetX + space.targetX - space.width)/next.width;
|
||||
} else {
|
||||
r1 = Math.abs(closest.targetX + space.targetX - space.width)/closest.width;
|
||||
r2 = Math.abs(next.targetX + next.width + space.targetX)/next.width;
|
||||
}
|
||||
// Choose the window the most visible width (as a ratio)
|
||||
if (r1 > r2)
|
||||
return closest.meta_window;
|
||||
else
|
||||
return next.meta_window;
|
||||
}
|
||||
|
||||
var transition = 'easeOutQuad';
|
||||
|
||||
Reference in New Issue
Block a user