dash: Wrap items in a scale-aware container
Clutter containers only take their children's size into account, but not their scale. As we want the dash to change its size smoothly when zooming items in/out, we wrap each item in a custom container which does consider the child's scale. https://bugzilla.gnome.org/show_bug.cgi?id=636156
This commit is contained in:
parent
2b84554d91
commit
29e97a5f88
@ -316,6 +316,7 @@ StTooltip StLabel {
|
|||||||
.dash-placeholder {
|
.dash-placeholder {
|
||||||
background-image: url("dash-placeholder.svg");
|
background-image: url("dash-placeholder.svg");
|
||||||
height: 27px;
|
height: 27px;
|
||||||
|
width: 48px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#viewSelector {
|
#viewSelector {
|
||||||
@ -478,7 +479,7 @@ StTooltip StLabel {
|
|||||||
background-position: 190px 10px;
|
background-position: 190px 10px;
|
||||||
}
|
}
|
||||||
|
|
||||||
#dash > .app-well-app {
|
.dash-item-container > .app-well-app {
|
||||||
padding: 6px 12px;
|
padding: 6px 12px;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
146
js/ui/dash.js
146
js/ui/dash.js
@ -1,5 +1,6 @@
|
|||||||
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
/* -*- mode: js2; js2-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||||
|
|
||||||
|
const Clutter = imports.gi.Clutter;
|
||||||
const Signals = imports.signals;
|
const Signals = imports.signals;
|
||||||
const Lang = imports.lang;
|
const Lang = imports.lang;
|
||||||
const Meta = imports.gi.Meta;
|
const Meta = imports.gi.Meta;
|
||||||
@ -15,21 +16,103 @@ const IconGrid = imports.ui.iconGrid;
|
|||||||
const Main = imports.ui.main;
|
const Main = imports.ui.main;
|
||||||
const Workspace = imports.ui.workspace;
|
const Workspace = imports.ui.workspace;
|
||||||
|
|
||||||
|
// A container like StBin, but taking the child's scale into account
|
||||||
|
// when requesting a size
|
||||||
|
function DashItemContainer() {
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
DashItemContainer.prototype = {
|
||||||
|
_init: function() {
|
||||||
|
this.actor = new Shell.GenericContainer({ style_class: 'dash-item-container' });
|
||||||
|
this.actor.connect('get-preferred-width',
|
||||||
|
Lang.bind(this, this._getPreferredWidth));
|
||||||
|
this.actor.connect('get-preferred-height',
|
||||||
|
Lang.bind(this, this._getPreferredHeight));
|
||||||
|
this.actor.connect('allocate',
|
||||||
|
Lang.bind(this, this._allocate));
|
||||||
|
this.actor._delegate = this;
|
||||||
|
|
||||||
|
this.child = null;
|
||||||
|
},
|
||||||
|
|
||||||
|
_allocate: function(actor, box, flags) {
|
||||||
|
if (this.child == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let availWidth = box.x2 - box.x1;
|
||||||
|
let availHeight = box.y2 - box.y1;
|
||||||
|
let [minChildWidth, minChildHeight, natChildWidth, natChildHeight] =
|
||||||
|
this.child.get_preferred_size();
|
||||||
|
let [childScaleX, childScaleY] = this.child.get_scale();
|
||||||
|
|
||||||
|
let childWidth = Math.min(natChildWidth * childScaleX, availWidth);
|
||||||
|
let childHeight = Math.min(natChildHeight * childScaleY, availHeight);
|
||||||
|
|
||||||
|
let childBox = new Clutter.ActorBox();
|
||||||
|
childBox.x1 = (availWidth - childWidth) / 2;
|
||||||
|
childBox.y1 = (availHeight - childHeight) / 2;
|
||||||
|
childBox.x2 = childBox.x1 + childWidth;
|
||||||
|
childBox.y2 = childBox.y1 + childHeight;
|
||||||
|
|
||||||
|
this.child.allocate(childBox, flags);
|
||||||
|
},
|
||||||
|
|
||||||
|
_getPreferredHeight: function(actor, forWidth, alloc) {
|
||||||
|
alloc.min_size = 0;
|
||||||
|
alloc.natural_size = 0;
|
||||||
|
|
||||||
|
if (this.child == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let [minHeight, natHeight] = this.child.get_preferred_height(forWidth);
|
||||||
|
alloc.min_size += minHeight * this.child.scale_y;
|
||||||
|
alloc.natural_size += natHeight * this.child.scale_y;
|
||||||
|
},
|
||||||
|
|
||||||
|
_getPreferredWidth: function(actor, forHeight, alloc) {
|
||||||
|
alloc.min_size = 0;
|
||||||
|
alloc.natural_size = 0;
|
||||||
|
|
||||||
|
if (this.child == null)
|
||||||
|
return;
|
||||||
|
|
||||||
|
let [minWidth, natWidth] = this.child.get_preferred_width(forHeight);
|
||||||
|
alloc.min_size = minWidth * this.child.scale_y;
|
||||||
|
alloc.natural_size = natWidth * this.child.scale_y;
|
||||||
|
},
|
||||||
|
|
||||||
|
setChild: function(actor) {
|
||||||
|
if (this.child == actor)
|
||||||
|
return;
|
||||||
|
|
||||||
|
this.actor.destroy_children();
|
||||||
|
|
||||||
|
this.child = actor;
|
||||||
|
this.actor.add_actor(this.child);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
function RemoveFavoriteIcon() {
|
function RemoveFavoriteIcon() {
|
||||||
this._init();
|
this._init();
|
||||||
}
|
}
|
||||||
|
|
||||||
RemoveFavoriteIcon.prototype = {
|
RemoveFavoriteIcon.prototype = {
|
||||||
|
__proto__: DashItemContainer.prototype,
|
||||||
|
|
||||||
_init: function() {
|
_init: function() {
|
||||||
this.actor = new St.Bin({ style_class: 'remove-favorite' });
|
DashItemContainer.prototype._init.call(this);
|
||||||
|
|
||||||
|
this._iconBin = new St.Bin({ style_class: 'remove-favorite' });
|
||||||
this._iconActor = null;
|
this._iconActor = null;
|
||||||
this.icon = new IconGrid.BaseIcon(_("Remove"),
|
this.icon = new IconGrid.BaseIcon(_("Remove"),
|
||||||
{ setSizeManually: true,
|
{ setSizeManually: true,
|
||||||
showLabel: false,
|
showLabel: false,
|
||||||
createIcon: Lang.bind(this, this._createIcon) });
|
createIcon: Lang.bind(this, this._createIcon) });
|
||||||
this.actor.set_child(this.icon.actor);
|
this._iconBin.set_child(this.icon.actor);
|
||||||
this.actor._delegate = this;
|
this._iconBin._delegate = this;
|
||||||
|
|
||||||
|
this.setChild(this._iconBin);
|
||||||
},
|
},
|
||||||
|
|
||||||
_createIcon: function(size) {
|
_createIcon: function(size) {
|
||||||
@ -40,7 +123,7 @@ RemoveFavoriteIcon.prototype = {
|
|||||||
},
|
},
|
||||||
|
|
||||||
setHover: function(hovered) {
|
setHover: function(hovered) {
|
||||||
this.actor.set_hover(hovered);
|
this._iconBin.set_hover(hovered);
|
||||||
if (this._iconActor)
|
if (this._iconActor)
|
||||||
this._iconActor.set_hover(hovered);
|
this._iconActor.set_hover(hovered);
|
||||||
},
|
},
|
||||||
@ -73,6 +156,20 @@ RemoveFavoriteIcon.prototype = {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
function DragPlaceholderItem() {
|
||||||
|
this._init();
|
||||||
|
}
|
||||||
|
|
||||||
|
DragPlaceholderItem.prototype = {
|
||||||
|
__proto__: DashItemContainer.prototype,
|
||||||
|
|
||||||
|
_init: function() {
|
||||||
|
DashItemContainer.prototype._init.call(this);
|
||||||
|
this.setChild(new St.Bin({ style_class: 'dash-placeholder' }));
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
function Dash() {
|
function Dash() {
|
||||||
this._init();
|
this._init();
|
||||||
}
|
}
|
||||||
@ -191,7 +288,7 @@ Dash.prototype = {
|
|||||||
Main.queueDeferredWork(this._workId);
|
Main.queueDeferredWork(this._workId);
|
||||||
},
|
},
|
||||||
|
|
||||||
_addApp: function(app, pos) {
|
_createAppItem: function(app) {
|
||||||
let display = new AppDisplay.AppWellIcon(app,
|
let display = new AppDisplay.AppWellIcon(app,
|
||||||
{ setSizeManually: true,
|
{ setSizeManually: true,
|
||||||
showLabel: false });
|
showLabel: false });
|
||||||
@ -203,9 +300,12 @@ Dash.prototype = {
|
|||||||
Lang.bind(this, function() {
|
Lang.bind(this, function() {
|
||||||
display.actor.opacity = 255;
|
display.actor.opacity = 255;
|
||||||
}));
|
}));
|
||||||
|
let item = new DashItemContainer();
|
||||||
|
item.setChild(display.actor);
|
||||||
|
|
||||||
display.icon.setIconSize(this._iconSize);
|
display.icon.setIconSize(this._iconSize);
|
||||||
|
|
||||||
this._box.insert_actor(display.actor, pos);
|
return item;
|
||||||
},
|
},
|
||||||
|
|
||||||
_adjustIconSize: function() {
|
_adjustIconSize: function() {
|
||||||
@ -221,7 +321,10 @@ Dash.prototype = {
|
|||||||
return;
|
return;
|
||||||
|
|
||||||
let iconChildren = children.filter(function(actor) {
|
let iconChildren = children.filter(function(actor) {
|
||||||
return actor.visible && actor._delegate && actor._delegate.icon;
|
return actor.visible &&
|
||||||
|
actor._delegate.child &&
|
||||||
|
actor._delegate.child._delegate &&
|
||||||
|
actor._delegate.child._delegate.icon;
|
||||||
});
|
});
|
||||||
|
|
||||||
// Compute the amount of extra space (or missing space) we have
|
// Compute the amount of extra space (or missing space) we have
|
||||||
@ -243,7 +346,7 @@ Dash.prototype = {
|
|||||||
this._iconSize = newIconSize;
|
this._iconSize = newIconSize;
|
||||||
|
|
||||||
for (let i = 0; i < iconChildren.length; i++) {
|
for (let i = 0; i < iconChildren.length; i++) {
|
||||||
let icon = iconChildren[i]._delegate.icon;
|
let icon = iconChildren[i]._delegate.child._delegate.icon;
|
||||||
icon.setIconSize(this._iconSize);
|
icon.setIconSize(this._iconSize);
|
||||||
}
|
}
|
||||||
},
|
},
|
||||||
@ -257,11 +360,13 @@ Dash.prototype = {
|
|||||||
let running = this._tracker.get_running_apps(contextId);
|
let running = this._tracker.get_running_apps(contextId);
|
||||||
|
|
||||||
let children = this._box.get_children().filter(function(actor) {
|
let children = this._box.get_children().filter(function(actor) {
|
||||||
return actor._delegate && actor._delegate.app;
|
return actor._delegate.child &&
|
||||||
|
actor._delegate.child._delegate &&
|
||||||
|
actor._delegate.child._delegate.app;
|
||||||
});
|
});
|
||||||
// Apps currently in the dash
|
// Apps currently in the dash
|
||||||
let oldApps = children.map(function(actor) {
|
let oldApps = children.map(function(actor) {
|
||||||
return actor._delegate.app;
|
return actor._delegate.child._delegate.app;
|
||||||
});
|
});
|
||||||
// Apps supposed to be in the dash
|
// Apps supposed to be in the dash
|
||||||
let newApps = [];
|
let newApps = [];
|
||||||
@ -317,6 +422,7 @@ Dash.prototype = {
|
|||||||
if (newApps[newIndex] &&
|
if (newApps[newIndex] &&
|
||||||
oldApps.indexOf(newApps[newIndex]) == -1) {
|
oldApps.indexOf(newApps[newIndex]) == -1) {
|
||||||
addedItems.push({ app: newApps[newIndex],
|
addedItems.push({ app: newApps[newIndex],
|
||||||
|
item: this._createAppItem(newApps[newIndex]),
|
||||||
pos: newIndex });
|
pos: newIndex });
|
||||||
newIndex++;
|
newIndex++;
|
||||||
continue;
|
continue;
|
||||||
@ -326,12 +432,14 @@ Dash.prototype = {
|
|||||||
let insertHere = newApps[newIndex + 1] &&
|
let insertHere = newApps[newIndex + 1] &&
|
||||||
newApps[newIndex + 1] == oldApps[oldIndex];
|
newApps[newIndex + 1] == oldApps[oldIndex];
|
||||||
let alreadyRemoved = removedActors.reduce(function(result, actor) {
|
let alreadyRemoved = removedActors.reduce(function(result, actor) {
|
||||||
let removedApp = actor._delegate.app;
|
let removedApp = actor._delegate.child._delegate.app;
|
||||||
return result || removedApp == newApps[newIndex];
|
return result || removedApp == newApps[newIndex];
|
||||||
}, false);
|
}, false);
|
||||||
|
|
||||||
if (insertHere || alreadyRemoved) {
|
if (insertHere || alreadyRemoved) {
|
||||||
|
let newItem = this._createAppItem(newApps[newIndex]);
|
||||||
addedItems.push({ app: newApps[newIndex],
|
addedItems.push({ app: newApps[newIndex],
|
||||||
|
item: newItem,
|
||||||
pos: newIndex + removedActors.length });
|
pos: newIndex + removedActors.length });
|
||||||
newIndex++;
|
newIndex++;
|
||||||
} else {
|
} else {
|
||||||
@ -341,7 +449,8 @@ Dash.prototype = {
|
|||||||
}
|
}
|
||||||
|
|
||||||
for (let i = 0; i < addedItems.length; i++)
|
for (let i = 0; i < addedItems.length; i++)
|
||||||
this._addApp(addedItems[i].app, addedItems[i].pos);
|
this._box.insert_actor(addedItems[i].item.actor,
|
||||||
|
addedItems[i].pos);
|
||||||
|
|
||||||
for (let i = 0; i < removedActors.length; i++)
|
for (let i = 0; i < removedActors.length; i++)
|
||||||
removedActors[i].destroy();
|
removedActors[i].destroy();
|
||||||
@ -351,7 +460,7 @@ Dash.prototype = {
|
|||||||
|
|
||||||
_clearDragPlaceholder: function() {
|
_clearDragPlaceholder: function() {
|
||||||
if (this._dragPlaceholder) {
|
if (this._dragPlaceholder) {
|
||||||
this._dragPlaceholder.destroy();
|
this._dragPlaceholder.actor.destroy();
|
||||||
this._dragPlaceholder = null;
|
this._dragPlaceholder = null;
|
||||||
this._dragPlaceholderPos = -1;
|
this._dragPlaceholderPos = -1;
|
||||||
}
|
}
|
||||||
@ -380,7 +489,7 @@ Dash.prototype = {
|
|||||||
// the remove target has the same size as "normal" items, we don't
|
// the remove target has the same size as "normal" items, we don't
|
||||||
// need to do the same adjustment there.
|
// need to do the same adjustment there.
|
||||||
if (this._dragPlaceholder) {
|
if (this._dragPlaceholder) {
|
||||||
boxHeight -= this._dragPlaceholder.height;
|
boxHeight -= this._dragPlaceholder.actor.height;
|
||||||
numChildren--;
|
numChildren--;
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -389,14 +498,15 @@ Dash.prototype = {
|
|||||||
if (pos != this._dragPlaceholderPos && pos <= numFavorites) {
|
if (pos != this._dragPlaceholderPos && pos <= numFavorites) {
|
||||||
this._dragPlaceholderPos = pos;
|
this._dragPlaceholderPos = pos;
|
||||||
if (this._dragPlaceholder)
|
if (this._dragPlaceholder)
|
||||||
this._dragPlaceholder.destroy();
|
this._dragPlaceholder.actor.destroy();
|
||||||
|
|
||||||
// Don't allow positioning before or after self
|
// Don't allow positioning before or after self
|
||||||
if (favPos != -1 && (pos == favPos || pos == favPos + 1))
|
if (favPos != -1 && (pos == favPos || pos == favPos + 1))
|
||||||
return DND.DragMotionResult.CONTINUE;
|
return DND.DragMotionResult.CONTINUE;
|
||||||
|
|
||||||
this._dragPlaceholder = new St.Bin({ style_class: 'dash-placeholder' });
|
this._dragPlaceholder = new DragPlaceholderItem();
|
||||||
this._box.insert_actor(this._dragPlaceholder, pos);
|
this._box.insert_actor(this._dragPlaceholder.actor,
|
||||||
|
this._dragPlaceholderPos);
|
||||||
}
|
}
|
||||||
|
|
||||||
let srcIsFavorite = (favPos != -1);
|
let srcIsFavorite = (favPos != -1);
|
||||||
@ -430,7 +540,7 @@ Dash.prototype = {
|
|||||||
let favPos = 0;
|
let favPos = 0;
|
||||||
let children = this._box.get_children();
|
let children = this._box.get_children();
|
||||||
for (let i = 0; i < this._dragPlaceholderPos; i++) {
|
for (let i = 0; i < this._dragPlaceholderPos; i++) {
|
||||||
let childId = children[i]._delegate.app.get_id();
|
let childId = children[i]._delegate.child._delegate.app.get_id();
|
||||||
if (childId == id)
|
if (childId == id)
|
||||||
continue;
|
continue;
|
||||||
if (childId in favorites)
|
if (childId in favorites)
|
||||||
|
Loading…
Reference in New Issue
Block a user