/* 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 . */ /* CoverflowAltTab::TimelineSwitcher: * * Extends CoverflowAltTab::Switcher, switching tabs using a timeline */ import {Switcher} from './switcher.js'; import {Preview, Placement, findUpperLeftFromCenter} from './preview.js' let TRANSITION_TYPE; let IN_BOUNDS_TRANSITION_TYPE; const TILT_ANGLE = 45; export class TimelineSwitcher extends Switcher { constructor(...args) { super(...args); TRANSITION_TYPE = 'userChoice'; IN_BOUNDS_TRANSITION_TYPE = 'easeInOutQuint'; } _createPreviews() { 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 }; 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 { let preferred_size_ok; [preferred_size_ok, width, height] = texture.get_preferred_size(); } let previewScale = this._settings.preview_to_monitor_ratio; let scale = 1.0; 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, { opacity: (!metaWin.minimized && metaWin.get_workspace() == currentWorkspace || metaWin.is_on_all_workspaces()) ? 255: 0, source: texture.get_size ? texture : compositor, reactive: true, name: metaWin.title, x: (metaWin.minimized ? -(compositor.x + compositor.width / 2) : compositor.x) - monitor.x, y: (metaWin.minimized ? -(compositor.y + compositor.height / 2) : compositor.y) - monitor.y, rotation_angle_y: 0, width: width, height: height, }); preview.scale = scale; preview.target_x = findUpperLeftFromCenter(preview.width * preview.scale, this._previewsCenterPosition.x); preview.target_y = findUpperLeftFromCenter(preview.height, this._previewsCenterPosition.y); preview.set_pivot_point_placement(Placement.LEFT); if (this._windows.includes(metaWin)) { this._previews[this._windows.indexOf(metaWin)] = preview; } this._allPreviews.push(preview); this.previewActor.add_child(preview); preview.make_bottom_layer(this.previewActor); } } } _previewNext() { this._setCurrentIndex((this._currentIndex + 1) % this._windows.length); this._updatePreviews(false, 1); } _previewPrevious() { this._setCurrentIndex((this._windows.length + this._currentIndex - 1) % this._windows.length); this._updatePreviews(false, -1); } _updatePreviews(reorder_only=false, direction=0) { if (this._previews == null || this._previews.length == 0) return; let animation_time = this._settings.animation_time * (this._settings.randomize_animation_times ? this._getRandomArbitrary(0.25, 1) : 1); if (this._previews.length == 1) { if (reorder_only) return; let preview = this._previews[0]; this._manager.platform.tween(preview, { x: preview.target_x, y: preview.target_y, scale_x: preview.scale, scale_y: preview.scale, scale_z: preview.scale, time: animation_time / 2, transition: TRANSITION_TYPE, rotation_angle_y: TILT_ANGLE, }); this._manager.platform.tween(preview, { opacity: 255, time: animation_time / 2, transition: IN_BOUNDS_TRANSITION_TYPE, onComplete: () => { preview.set_reactive(true); } }); return; } for (let i = this._currentIndex; i < this._currentIndex + this._previews.length; i++) { this._previews[i%this._previews.length].make_bottom_layer(this.previewActor); } if (reorder_only) return; // preview windows for (let [i, preview] of this._previews.entries()) { animation_time = this._settings.animation_time * (this._settings.randomize_animation_times ? this._getRandomArbitrary(0.0001, 1) : 1); let distance = (this._currentIndex > i) ? this._previews.length - this._currentIndex + i : i - this._currentIndex; if (distance === this._previews.length - 1 && direction > 0) { preview.__looping = true; animation_time = this._settings.animation_time; preview.make_top_layer(this.previewActor); this._raiseIcons(); let scale = preview.scale * Math.pow(this._settings.preview_scaling_factor, -1); this._manager.platform.tween(preview, { x: preview.target_x + 150, y: preview.target_y + 100, time: animation_time / 2, transition: TRANSITION_TYPE, rotation_angle_y: TILT_ANGLE, onCompleteParams: [preview, distance, animation_time], onComplete: this._onFadeForwardComplete, onCompleteScope: this, }); this._manager.platform.tween(preview, { opacity: 0, scale_x: scale, scale_y: scale, scale_z: scale, time: animation_time / 2, transition: IN_BOUNDS_TRANSITION_TYPE, }); } else if (distance === 0 && direction < 0) { preview.__looping = true; animation_time = this._settings.animation_time; let scale = preview.scale * Math.pow(this._settings.preview_scaling_factor, this._previews.length); preview.make_bottom_layer(this.previewActor); this._manager.platform.tween(preview, { time: animation_time / 2, x: preview.target_x - Math.sqrt(this._previews.length) * 150, y: preview.target_y - Math.sqrt(this._previews.length) * 100, transition: TRANSITION_TYPE, rotation_angle_y: TILT_ANGLE, onCompleteParams: [preview, distance, animation_time], onComplete: this._onFadeBackwardsComplete, onCompleteScope: this, }); this._manager.platform.tween(preview, { time: animation_time / 2, transition: IN_BOUNDS_TRANSITION_TYPE, scale_x: scale, scale_y: scale, scale_x: scale, opacity: 0, }); } else { let scale = preview.scale * Math.pow(this._settings.preview_scaling_factor, distance);//Math.max(preview.scale * ((20 - 2 * distance) / 20), 0); let tweenparams = { x: preview.target_x - Math.sqrt(distance) * 150, y: preview.target_y - Math.sqrt(distance) * 100, scale_x: scale, scale_y: scale, scale_z: scale, time: animation_time, rotation_angle_y: TILT_ANGLE, transition: TRANSITION_TYPE, onComplete: () => { preview.set_reactive(true); }, }; let opacitytweenparams = { opacity: 255, time: animation_time, transition: IN_BOUNDS_TRANSITION_TYPE, }; if (preview.__looping || preview.__finalTween) preview.__finalTween = [tweenparams, opacitytweenparams]; else this._manager.platform.tween(preview, tweenparams); this._manager.platform.tween(preview, opacitytweenparams); } } } _onFadeBackwardsComplete(preview, distance, animation_time) { preview.__looping = false; preview.make_top_layer(this.previewActor); this._raiseIcons(); preview.x = preview.target_x + 150; preview.y = preview.target_y + 100; let scale_start = preview.scale * Math.pow(this._settings.preview_scaling_factor, -1); preview.scale_x = scale_start; preview.scale_y = scale_start; preview.scale_z = scale_start; this._manager.platform.tween(preview, { x: preview.target_x, y: preview.target_y, time: animation_time / 2, transition: TRANSITION_TYPE, onCompleteParams: [preview], onComplete: this._onFinishMove, onCompleteScope: this, }); this._manager.platform.tween(preview, { opacity: 255, scale_x: preview.scale, scale_y: preview.scale, scale_z: preview.scale, time: animation_time / 2, transition: IN_BOUNDS_TRANSITION_TYPE, }); } _onFadeForwardComplete(preview, distance, animation_time) { preview.__looping = false; preview.make_bottom_layer(this.previewActor); log(distance); preview.x = preview.target_x - Math.sqrt(distance + 1) * 150; preview.y = preview.target_y - Math.sqrt(distance + 1) * 100; let scale_start = preview.scale * Math.pow(this._settings.preview_scaling_factor, distance + 1); preview.scale_x = scale_start; preview.scale_y = scale_start; preview.scale_z = scale_start; this._manager.platform.tween(preview, { x: preview.target_x - Math.sqrt(distance) * 150, y: preview.target_y - Math.sqrt(distance) * 100, time: animation_time / 2, transition: TRANSITION_TYPE, onCompleteParams: [preview], onComplete: this._onFinishMove, onCompleteScope: this, }); let scale_end = preview.scale * Math.pow(this._settings.preview_scaling_factor, distance); this._manager.platform.tween(preview, { opacity: 255, scale_x: scale_end, scale_y: scale_end, scale_z: scale_end, time: animation_time / 2, transition: IN_BOUNDS_TRANSITION_TYPE, }); } _onFinishMove(preview) { this._updatePreviews(true) if (preview.__finalTween) { for (let tween of preview.__finalTween) { this._manager.platform.tween(preview, tween); } preview.__finalTween = null; } } };