Scroll previews using mouse pointer

This commit is contained in:
Charles Gagnon
2019-06-07 20:02:51 -04:00
parent db309b3540
commit 3606cdff45
3 changed files with 95 additions and 86 deletions

View File

@@ -41,7 +41,6 @@ const IconGrid = imports.ui.iconGrid;
const Main = imports.ui.main;
const PopupMenu = imports.ui.popupMenu;
const Tweener = imports.ui.tweener;
const Util = imports.misc.util;
const Workspace = imports.ui.workspace;
const Me = imports.misc.extensionUtils.getCurrentExtension();
@@ -567,7 +566,7 @@ var taskbar = Utils.defineClass({
appIcon.actor.connect('notify::hover', Lang.bind(this, function() {
if (appIcon.actor.hover){
this._ensureAppIconVisibilityTimeoutId = Mainloop.timeout_add(100, Lang.bind(this, function(){
ensureActorVisibleInScrollView(this._scrollView, appIcon.actor);
Utils.ensureActorVisibleInScrollView(this._scrollView, appIcon.actor, this._scrollView._dtpFadeSize);
this._ensureAppIconVisibilityTimeoutId = 0;
return GLib.SOURCE_REMOVE;
}));
@@ -581,11 +580,11 @@ var taskbar = Utils.defineClass({
appIcon.actor.connect('clicked',
Lang.bind(this, function(actor) {
ensureActorVisibleInScrollView(this._scrollView, actor);
Utils.ensureActorVisibleInScrollView(this._scrollView, actor, this._scrollView._dtpFadeSize);
}));
appIcon.actor.connect('key-focus-in', Lang.bind(this, function(actor) {
let [x_shift, y_shift] = ensureActorVisibleInScrollView(this._scrollView, actor);
let [x_shift, y_shift] = Utils.ensureActorVisibleInScrollView(this._scrollView, actor, this._scrollView._dtpFadeSize);
// This signal is triggered also by mouse click. The popup menu is opened at the original
// coordinates. Thus correct for the shift which is going to be applied to the scrollview.
@@ -960,9 +959,9 @@ var taskbar = Utils.defineClass({
// Ensure the next and previous icon are visible when moving the icon
// (I assume there's room for both of them)
if (hoveredIndex > 1)
ensureActorVisibleInScrollView(this._scrollView, this._box.get_children()[hoveredIndex-1]);
ensureActorVisibleInScrollView(this._scrollView, this._box.get_children()[hoveredIndex-1], this._scrollView._dtpFadeSize);
if (hoveredIndex < this._box.get_children().length-1)
ensureActorVisibleInScrollView(this._scrollView, this._box.get_children()[hoveredIndex+1]);
ensureActorVisibleInScrollView(this._scrollView, this._box.get_children()[hoveredIndex+1], this._scrollView._dtpFadeSize);
}
}
@@ -1217,68 +1216,4 @@ function sortWindowsCompareFunction(windowA, windowB) {
function getWindowStableSequence(window) {
return ('_dtpPosition' in window ? window._dtpPosition : window.get_stable_sequence());
}
/*
* This is a copy of the same function in utils.js, but also adjust horizontal scrolling
* and perform few further cheks on the current value to avoid changing the values when
* it would be clamp to the current one in any case.
* Return the amount of shift applied
*/
function ensureActorVisibleInScrollView(scrollView, actor) {
let adjust_v = true;
let adjust_h = true;
let vadjustment = scrollView.vscroll.adjustment;
let hadjustment = scrollView.hscroll.adjustment;
let [vvalue, vlower, vupper, vstepIncrement, vpageIncrement, vpageSize] = vadjustment.get_values();
let [hvalue, hlower, hupper, hstepIncrement, hpageIncrement, hpageSize] = hadjustment.get_values();
let [hvalue0, vvalue0] = [hvalue, vvalue];
let voffset = 0;
let hoffset = scrollView._dtpFadeSize;
let box = actor.get_allocation_box();
let y1 = box.y1, y2 = box.y2, x1 = box.x1, x2 = box.x2;
let parent = actor.get_parent();
while (parent != scrollView) {
if (!parent)
throw new Error("actor not in scroll view");
let box = parent.get_allocation_box();
y1 += box.y1;
y2 += box.y1;
x1 += box.x1;
x2 += box.x1;
parent = parent.get_parent();
}
if (y1 < vvalue + voffset)
vvalue = Math.max(0, y1 - voffset);
else if (vvalue < vupper - vpageSize && y2 > vvalue + vpageSize - voffset)
vvalue = Math.min(vupper -vpageSize, y2 + voffset - vpageSize);
if (x1 < hvalue + hoffset)
hvalue = Math.max(0, x1 - hoffset);
else if (hvalue < hupper - hpageSize && x2 > hvalue + hpageSize - hoffset)
hvalue = Math.min(hupper - hpageSize, x2 + hoffset - hpageSize);
if (vvalue !== vvalue0) {
Tweener.addTween(vadjustment,
{ value: vvalue,
time: Util.SCROLL_TIME,
transition: 'easeOutQuad' });
}
if (hvalue !== hvalue0) {
Tweener.addTween(hadjustment,
{ value: hvalue,
time: Util.SCROLL_TIME,
transition: 'easeOutQuad' });
}
return [hvalue- hvalue0, vvalue - vvalue0];
}
}

View File

@@ -32,6 +32,8 @@ const Shell = imports.gi.Shell;
const St = imports.gi.St;
const Mainloop = imports.mainloop;
const Main = imports.ui.main;
const Tweener = imports.ui.tweener;
const Util = imports.misc.util;
var TRANSLATION_DOMAIN = imports.misc.extensionUtils.getCurrentExtension().metadata['gettext-domain'];
@@ -371,6 +373,66 @@ var getrgbaColor = function(color, alpha, offset) {
return 'rgba(' + rgb.red + ',' + rgb.green + ',' + rgb.blue + ',' + (Math.floor(alpha * 100) * 0.01) + '); ' ;
};
/*
* This is a copy of the same function in utils.js, but also adjust horizontal scrolling
* and perform few further cheks on the current value to avoid changing the values when
* it would be clamp to the current one in any case.
* Return the amount of shift applied
*/
var ensureActorVisibleInScrollView = function(scrollView, actor, fadeSize) {
let vadjustment = scrollView.vscroll.adjustment;
let hadjustment = scrollView.hscroll.adjustment;
let [vvalue, vlower, vupper, vstepIncrement, vpageIncrement, vpageSize] = vadjustment.get_values();
let [hvalue, hlower, hupper, hstepIncrement, hpageIncrement, hpageSize] = hadjustment.get_values();
let [hvalue0, vvalue0] = [hvalue, vvalue];
let voffset = fadeSize;
let hoffset = fadeSize;
let box = actor.get_allocation_box();
let y1 = box.y1, y2 = box.y2, x1 = box.x1, x2 = box.x2;
let parent = actor.get_parent();
while (parent != scrollView) {
if (!parent)
throw new Error("actor not in scroll view");
let box = parent.get_allocation_box();
y1 += box.y1;
y2 += box.y1;
x1 += box.x1;
x2 += box.x1;
parent = parent.get_parent();
}
if (y1 < vvalue + voffset)
vvalue = Math.max(0, y1 - voffset);
else if (vvalue < vupper - vpageSize && y2 > vvalue + vpageSize - voffset)
vvalue = Math.min(vupper -vpageSize, y2 + voffset - vpageSize);
if (x1 < hvalue + hoffset)
hvalue = Math.max(0, x1 - hoffset);
else if (hvalue < hupper - hpageSize && x2 > hvalue + hpageSize - hoffset)
hvalue = Math.min(hupper - hpageSize, x2 + hoffset - hpageSize);
if (vvalue !== vvalue0) {
Tweener.addTween(vadjustment,
{ value: vvalue,
time: Util.SCROLL_TIME,
transition: 'easeOutQuad' });
}
if (hvalue !== hvalue0) {
Tweener.addTween(hadjustment,
{ value: hvalue,
time: Util.SCROLL_TIME,
transition: 'easeOutQuad' });
}
return [hvalue- hvalue0, vvalue - vvalue0];
}
/**
* ColorUtils is adapted from https://github.com/micheleg/dash-to-dock

View File

@@ -33,10 +33,14 @@ const Me = imports.misc.extensionUtils.getCurrentExtension();
const Taskbar = Me.imports.taskbar;
const Utils = Me.imports.utils;
//timeout intervals
const ENSURE_VISIBLE_MS = 200;
//timeout names
const T1 = 'openMenuTimeout';
const T2 = 'closeMenuTimeout';
const T3 = 'peekTimeout';
const T4 = 'ensureVisibleTimeout';
const MAX_TRANSLATION = 40;
const HEADER_HEIGHT = 38;
@@ -69,8 +73,8 @@ var PreviewMenu = Utils.defineClass({
this.peekInitialWorkspaceIndex = -1;
this.opened = false;
this._position = Taskbar.getPosition();
let isLeftOrRight = this._checkIfLeftOrRight();
this._translationProp = 'translation_' + (isLeftOrRight ? 'x' : 'y');
this.isLeftOrRight = this._position == St.Side.LEFT || this._position == St.Side.RIGHT;
this._translationProp = 'translation_' + (this.isLeftOrRight ? 'x' : 'y');
this._translationDirection = (this._position == St.Side.TOP || this._position == St.Side.LEFT ? -1 : 1);
this._translationOffset = Math.min(this._dtpSettings.get_int('panel-size'), MAX_TRANSLATION) * this._translationDirection;
@@ -82,14 +86,12 @@ var PreviewMenu = Utils.defineClass({
y_expand: true,
y_align: Clutter.ActorAlign[this._translationDirection > 0 ? 'END' : 'START']
});
this._box = new St.BoxLayout({ vertical: isLeftOrRight });
this._box = new St.BoxLayout({ vertical: this.isLeftOrRight });
this._scrollView = new St.ScrollView({
name: 'dashtopanelPreviewScrollview',
hscrollbar_policy: Gtk.PolicyType.NEVER,
vscrollbar_policy: Gtk.PolicyType.NEVER,
enable_mouse_scrolling: true,
y_expand: !isLeftOrRight,
x_expand: isLeftOrRight
enable_mouse_scrolling: true
});
this._scrollView.add_actor(this._box);
@@ -251,6 +253,18 @@ var PreviewMenu = Utils.defineClass({
this._endPeek(true);
},
ensureVisible: function(preview) {
let [ , , upper, , , pageSize] = this._scrollView[this.isLeftOrRight ? 'v' : 'h' + 'scroll'].adjustment.get_values();
if (upper > pageSize) {
this._timeoutsHandler.add([
T4,
ENSURE_VISIBLE_MS,
() => Utils.ensureActorVisibleInScrollView(this._scrollView, preview, MIN_DIMENSION)
]);
}
},
_setReactive: function(reactive) { 
this._box.get_children().forEach(c => c.reactive = reactive);
this.menu.reactive = reactive;
@@ -337,7 +351,7 @@ var PreviewMenu = Utils.defineClass({
_onScrollEvent: function(actor, event) {
if (!event.is_pointer_emulated()) {
let vOrh = this._checkIfLeftOrRight() ? 'v' : 'h';
let vOrh = this.isLeftOrRight ? 'v' : 'h';
let adjustment = this._scrollView['get_' + vOrh + 'scroll_bar']().get_adjustment();
let increment = adjustment.step_increment;
let delta = increment;
@@ -362,6 +376,7 @@ var PreviewMenu = Utils.defineClass({
_endOpenCloseTimeouts: function() {
this._timeoutsHandler.remove(T1);
this._timeoutsHandler.remove(T2);
this._timeoutsHandler.remove(T4);
},
_refreshGlobals: function() {
@@ -401,7 +416,7 @@ var PreviewMenu = Utils.defineClass({
let previewSize = (this._dtpSettings.get_int('window-preview-size') +
this._dtpSettings.get_int('window-preview-padding') * 2) * scaleFactor;
if (this._checkIfLeftOrRight()) {
if (this.isLeftOrRight) {
w = previewSize;
h = this._panelWrapper.monitor.height;
y = this._panelWrapper.monitor.y;
@@ -437,7 +452,7 @@ var PreviewMenu = Utils.defineClass({
previewsWidth = Math.min(previewsWidth, this._panelWrapper.monitor.width);
previewsHeight = Math.min(previewsHeight, this._panelWrapper.monitor.height) + headerHeight;
if (this._checkIfLeftOrRight()) {
if (this.isLeftOrRight) {
y = sourceAllocation.y1 + appIconMargin - this._panelWrapper.monitor.y + (sourceContentBox.y2 - sourceContentBox.y1 - previewsHeight) * .5;
y = Math.max(y, 0);
y = Math.min(y, this._panelWrapper.monitor.height - previewsHeight);
@@ -463,7 +478,7 @@ var PreviewMenu = Utils.defineClass({
if (!c.animatingOut) {
let [width, height] = c.getSize();
if (this._checkIfLeftOrRight()) {
if (this.isLeftOrRight) {
previewsWidth = Math.max(width, previewsWidth);
previewsHeight += height;
} else {
@@ -495,10 +510,6 @@ var PreviewMenu = Utils.defineClass({
Tweener.addTween(this.menu, getTweenOpts(tweenOpts));
},
_checkIfLeftOrRight: function() {
return this._position == St.Side.LEFT || this._position == St.Side.RIGHT;
},
_peek: function(window) {
let currentWorkspace = Utils.getCurrentWorkspace();
let windowWorkspace = window.get_workspace();
@@ -746,6 +757,7 @@ var Preview = Utils.defineClass({
this.set_style(this._getBackgroundColor(FOCUSED_COLOR_OFFSET, focused ? '-' : 0));
if (focused) {
this._previewMenu.ensureVisible(this);
this._previewMenu.requestPeek(this.window);
}
},
@@ -954,7 +966,7 @@ var Preview = Utils.defineClass({
let size = this._previewMenu._dtpSettings.get_int('window-preview-size') * scaleFactor;
let w, h;
if (this._previewMenu._checkIfLeftOrRight()) {
if (this._previewMenu.isLeftOrRight) {
w = size;
h = w * aspectRatio.y.size / aspectRatio.x.size;
} else {