linux-presets/gui/gnome/autocustom-gnome-macos/res/extensions/CoverflowAltTab@palatis.blo.../coverflowSwitcher.js

367 lines
15 KiB
JavaScript
Raw Normal View History

2024-07-08 22:46:35 +02:00
/*
This file is part of CoverflowAltTab.
CoverflowAltTab is free software: you can redistribute it and/or modify
it under the terms of the GNU General Public License as published by
the Free Software Foundation, either version 3 of the License, or
(at your option) any later version.
CoverflowAltTab is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
GNU General Public License for more details.
You should have received a copy of the GNU General Public License
along with CoverflowAltTab. If not, see <http://www.gnu.org/licenses/>.
*/
/* CoverflowAltTab::CoverflowSwitcher:
*
* Extends CoverflowAltTab::Switcher, switching tabs using a cover flow.
*/
import Graphene from 'gi://Graphene';
import {Switcher} from './switcher.js';
const BaseSwitcher = Switcher;
import {Preview, Placement, Direction, findUpperLeftFromCenter} from './preview.js'
const SIDE_ANGLE = 90;
const BLEND_OUT_ANGLE = 30;
const ALPHA = 1;
function appendParams(base, extra) {
for (let key in extra) {
base[key] = extra[key];
}
}
export class CoverflowSwitcher extends BaseSwitcher {
constructor(...args) {
super(...args);
}
_createPreviews() {
// TODO: Shouldn't monitor be set once per coverflow state?
let monitor = this._updateActiveMonitor();
let currentWorkspace = this._manager.workspace_manager.get_active_workspace();
this._previewsCenterPosition = {
x: this.actor.width / 2,
y: this.actor.height / 2 + this._settings.offset
};
let ratio = this._settings.preview_to_monitor_ratio;
this._xOffsetLeft = this.actor.width * (0.5 * (1 - ratio) - 0.1 * ratio)
this._xOffsetRight = this.actor.width - this._xOffsetLeft;
for (let windowActor of global.get_window_actors()) {
let metaWin = windowActor.get_meta_window();
let compositor = metaWin.get_compositor_private();
if (compositor) {
let texture = compositor.get_texture();
let width, height;
if (texture.get_size) {
[width, height] = texture.get_size();
} else {
// TODO: Check this OK!
let preferred_size_ok;
[preferred_size_ok, width, height] = texture.get_preferred_size();
}
let scale = 1.0;
let previewScale = this._settings.preview_to_monitor_ratio;
let previewWidth = this.actor.width * previewScale;
let previewHeight = this.actor.height * previewScale;
if (width > previewWidth || height > previewHeight)
scale = Math.min(previewWidth / width, previewHeight / height);
let preview = new Preview(metaWin, this, {
name: metaWin.title,
opacity: ALPHA * (!metaWin.minimized && metaWin.get_workspace() == currentWorkspace || metaWin.is_on_all_workspaces()) ? 255 : 0,
source: texture.get_size ? texture : compositor,
reactive: true,
x: metaWin.minimized ? 0 :
compositor.x - monitor.x,
y: metaWin.minimized ? 0 :
compositor.y - monitor.y,
translation_x: 0,
width: width,
height: height,
scale_x: metaWin.minimized ? 0 : 1,
scale_y: metaWin.minimized ? 0 : 1,
scale_z: metaWin.minimized ? 0 : 1,
rotation_angle_y: 0,
});
preview.scale = scale;
preview.set_pivot_point_placement(Placement.CENTER);
preview.center_position = {
x: findUpperLeftFromCenter(width,
this._previewsCenterPosition.x),
y: findUpperLeftFromCenter(height,
this._previewsCenterPosition.y)
};
if (this._windows.includes(metaWin)) {
this._previews[this._windows.indexOf(metaWin)] = preview;
}
this._allPreviews.push(preview);
this.previewActor.add_child(preview);
}
}
}
_usingCarousel() {
return (this._parent === null && this._settings.switcher_looping_method == "Carousel");
}
_previewNext() {
if (this._currentIndex == this._windows.length - 1) {
this._setCurrentIndex(0);
if (this._usingCarousel()) {
this._updatePreviews(false)
} else {
this._flipStack(Direction.TO_LEFT);
}
} else {
this._setCurrentIndex(this._currentIndex + 1);
this._updatePreviews(false);
}
}
_previewPrevious() {
if (this._currentIndex == 0) {
this._setCurrentIndex(this._windows.length-1);
if (this._usingCarousel()) {
this._updatePreviews(false)
} else {
this._flipStack(Direction.TO_RIGHT);
}
} else {
this._setCurrentIndex(this._currentIndex - 1);
this._updatePreviews(false);
}
}
_flipStack(direction) {
//this._looping = true;
let xOffset, angle;
this._updateActiveMonitor();
if (direction === Direction.TO_LEFT) {
xOffset = -this._xOffsetLeft;
angle = BLEND_OUT_ANGLE;
} else {
xOffset = this._activeMonitor.width + this._xOffsetLeft;
angle = -BLEND_OUT_ANGLE;
}
let animation_time = this._settings.animation_time * 2/3;
for (let [i, preview] of this._previews.entries()) {
this._onFlipIn(preview, i, direction);
}
}
_onFlipIn(preview, index, direction) {
let xOffsetStart, xOffsetEnd, angleStart, angleEnd;
let zeroIndexPreview = null;
this._updateActiveMonitor();
if (direction === Direction.TO_LEFT) {
xOffsetStart = this.actor.width + this._xOffsetLeft;
xOffsetEnd = this._xOffsetRight;
angleStart = -BLEND_OUT_ANGLE;
angleEnd = -SIDE_ANGLE + this._getPerspectiveCorrectionAngle(1);
} else {
xOffsetStart = -this._xOffsetLeft;
xOffsetEnd = this._xOffsetLeft;
angleStart = BLEND_OUT_ANGLE;
angleEnd = SIDE_ANGLE + this._getPerspectiveCorrectionAngle(0);
}
//let animation_time = this._settings.animation_time * 2;
let animation_time = this._settings.animation_time * 2 * (direction === Direction.TO_RIGHT ? ((index + 1) / this._previews.length) : (1 - index / this._previews.length));
this._updatePreview(index, zeroIndexPreview, preview, index, false, animation_time);
let translation_x;
if (direction === Direction.TO_RIGHT) {
translation_x = xOffsetStart - (this._previewsCenterPosition.x
- preview.width / 2) + 50 * (index - this._currentIndex);
} else {
translation_x = xOffsetStart - (this._previewsCenterPosition.x
+ preview.width / 2) + 50 * (index - this._currentIndex);
}
let lastExtraParams = {
transition: 'userChoice',
onCompleteParams: [direction],
onComplete: this._onFlipComplete,
onCompleteScope: this
};
this._manager.platform.tween(preview, {
transition: 'easeInOutQuint',
opacity: ALPHA * 255,
time: animation_time,
});
this._raiseIcons();
return;
}
_onFlipComplete(direction) {
this._looping = false;
this._updatePreviews(false);
}
// TODO: Remove unused direction variable
_animatePreviewToMid(preview, animation_time, extraParams = []) {
let pivot_point = preview.get_pivot_point_placement(Placement.CENTER);
let tweenParams = {
x: findUpperLeftFromCenter(preview.width, this._previewsCenterPosition.x),
y: findUpperLeftFromCenter(preview.height, this._previewsCenterPosition.y),
scale_x: preview.scale,
scale_y: preview.scale,
scale_z: preview.scale,
pivot_point: pivot_point,
translation_x: 0,
rotation_angle_y: 0,
time: animation_time,
transition: 'userChoice',
};
appendParams(tweenParams, extraParams);
this._manager.platform.tween(preview, tweenParams);
}
_animatePreviewToSide(preview, index, xOffset, extraParams, toChangePivotPoint = true) {
let [x, y] = preview.get_pivot_point();
let pivot_point = new Graphene.Point({ x: x, y: y });
let half_length = Math.floor(this._previews.length / 2);
let pivot_index = (this._usingCarousel()) ?
half_length : this._currentIndex;
if (toChangePivotPoint) {
if (index < pivot_index) {
let progress = pivot_index - index < 1 ? pivot_index - index : 1;
pivot_point = new Graphene.Point({ x: 0.5 - 0.5 * progress, y: 0.5});
} else {
let progress = index - pivot_index < 1 ? index - pivot_index : 1;
pivot_point = new Graphene.Point({ x: 0.5 + 0.5 * progress, y: 0.5});
}
}
let scale = Math.pow(this._settings.preview_scaling_factor, Math.abs(index - pivot_index));
scale = scale * preview.scale;
let tweenParams = {
x: findUpperLeftFromCenter(preview.width, this._previewsCenterPosition.x),
y: findUpperLeftFromCenter(preview.height, this._previewsCenterPosition.y),
scale_x: scale,
scale_y: scale,
scale_z: scale,
pivot_point: pivot_point,
};
if (index < pivot_index) {
tweenParams.translation_x = xOffset - (this._previewsCenterPosition.x
- preview.width / 2) + 50 * (index - pivot_index);
} else {
tweenParams.translation_x = xOffset - (this._previewsCenterPosition.x
+ preview.width / 2) + 50 * (index - pivot_index);
}
appendParams(tweenParams, extraParams);
this._manager.platform.tween(preview, tweenParams);
}
_getPerspectiveCorrectionAngle(side) {
if (this._settings.perspective_correction_method != "Adjust Angles") return 0;
if (this.num_monitors == 1) {
return 0;
} else if (this.num_monitors == 2) {
if (this.monitor_number == this.monitors_ltr[0].index) {
if (side == 0) return 508/1000 * 90;
else return 508/1000 *90;
} else {
if (side == 0) return -508/1000 * 90;
else return -508/1000 * 90;
}
} else if (this.num_monitors == 3) {
if (this.monitor_number == this.monitors_ltr[0].index) {
if (side == 0) return (666)/1000 * 90;
else return 750/1000 * 90;
} else if (this.monitor_number == this.monitors_ltr[1].index) {
return 0;
} else {
if (side == 0) return (-750)/1000 * 90;
else return -666/1000 * 90;
}
}
}
_updatePreviews(reorder_only=false) {
if (this._previews == null) return;
let half_length = Math.floor(this._previews.length / 2);
let previews = [];
for (let [i, preview] of this._previews.entries()) {
let idx = (this._usingCarousel()) ?
(i - this._currentIndex + half_length + this._previews.length) % this._previews.length :
i;
previews.push([i, idx, preview]);
}
previews.sort((a, b) => a[1] - b[1]);
let zeroIndexPreview = null;
for (let item of previews) {
let preview = item[2];
let i = item[0];
let idx = item[1];
let animation_time = this._settings.animation_time * (this._settings.randomize_animation_times ? this._getRandomArbitrary(0.0001, 1) : 1);
zeroIndexPreview = this._updatePreview(idx, zeroIndexPreview, preview, i, reorder_only, animation_time);
this._manager.platform.tween(preview, {
opacity: ALPHA * 255,
time: this._settings.animation_time,
transition: 'easeInOutQuint',
onComplete: () => {
preview.set_reactive(true);
}
});
}
if (zeroIndexPreview != null) zeroIndexPreview.make_bottom_layer(this.previewActor);
this._raiseIcons();
}
_updatePreview(idx, zeroIndexPreview, preview, i, reorder_only, animation_time) {
let half_length = Math.floor(this._previews.length / 2);
let pivot_index = (this._usingCarousel()) ?
half_length : this._currentIndex;
if (this._usingCarousel() && idx == 0) {
zeroIndexPreview = preview;
}
if (i == this._currentIndex) {
preview.make_top_layer(this.previewActor);
if (!reorder_only) {
this._animatePreviewToMid(preview, this._settings.animation_time);
}
} else if (idx < pivot_index) {
preview.make_top_layer(this.previewActor);
if (!reorder_only) {
let final_angle = SIDE_ANGLE + this._getPerspectiveCorrectionAngle(0);
let progress = pivot_index - idx < 1 ? pivot_index - idx : 1;
let center_offset = (this._xOffsetLeft + this._xOffsetRight) / 2;
this._animatePreviewToSide(preview, idx, center_offset - preview.width / 2 - progress * (center_offset - preview.width / 2 - this._xOffsetLeft), {
rotation_angle_y: progress * final_angle,
time: this.gestureInProgress ? 0 : animation_time,
transition: 'userChoice',
});
}
} else /* i > this._currentIndex */ {
preview.make_bottom_layer(this.previewActor);
if (!reorder_only) {
let final_angle = -SIDE_ANGLE + this._getPerspectiveCorrectionAngle(1);
let progress = idx - pivot_index < 1 ? idx - pivot_index : 1;
let center_offset = (this._xOffsetLeft + this._xOffsetRight) / 2;
this._animatePreviewToSide(preview, idx, center_offset + preview.width / 2 + progress * (this._xOffsetRight - center_offset - preview.width / 2), {
rotation_angle_y: progress * final_angle,
time: this.gestureInProgress ? 0 : animation_time,
transition: 'userChoice',
});
}
}
return zeroIndexPreview;
}
};