diff --git a/js/ui/appDisplay.js b/js/ui/appDisplay.js index 9d648c92e..6f67127c4 100644 --- a/js/ui/appDisplay.js +++ b/js/ui/appDisplay.js @@ -130,7 +130,7 @@ var BaseAppView = new Lang.Class({ this._childFocused(actor); }); // Standard hack for ClutterBinLayout - this._grid.actor.x_expand = true; + this._grid.x_expand = true; this._items = {}; this._allItems = []; @@ -203,7 +203,7 @@ var BaseAppView = new Lang.Class({ }, _doSpringAnimation(animationDirection) { - this._grid.actor.opacity = 255; + this._grid.opacity = 255; this._grid.animateSpring(animationDirection, Main.overview.getShowAppsButton()); }, @@ -217,8 +217,8 @@ var BaseAppView = new Lang.Class({ } if (animationDirection == IconGrid.AnimationDirection.IN) { - let id = this._grid.actor.connect('paint', () => { - this._grid.actor.disconnect(id); + let id = this._grid.connect('paint', () => { + this._grid.disconnect(id); this._doSpringAnimation(animationDirection); }); } else { @@ -228,7 +228,7 @@ var BaseAppView = new Lang.Class({ animateSwitch(animationDirection) { Tweener.removeTweens(this.actor); - Tweener.removeTweens(this._grid.actor); + Tweener.removeTweens(this._grid); let params = { time: VIEWS_SWITCH_TIME, transition: 'easeOutQuad' }; @@ -242,7 +242,7 @@ var BaseAppView = new Lang.Class({ params.onComplete = () => { this.actor.hide(); }; } - Tweener.addTween(this._grid.actor, params); + Tweener.addTween(this._grid, params); } }); Signals.addSignalMethods(BaseAppView.prototype); @@ -396,7 +396,7 @@ var AllView = new Lang.Class({ let box = new St.BoxLayout({ vertical: true }); this._grid.currentPage = 0; - this._stack.add_actor(this._grid.actor); + this._stack.add_actor(this._grid); this._eventBlocker = new St.Widget({ x_expand: true, y_expand: true }); this._stack.add_actor(this._eventBlocker); @@ -745,7 +745,7 @@ var AllView = new Lang.Class({ box.y2 = height; box = this.actor.get_theme_node().get_content_box(box); box = this._scrollView.get_theme_node().get_content_box(box); - box = this._grid.actor.get_theme_node().get_content_box(box); + box = this._grid.get_theme_node().get_content_box(box); let availWidth = box.x2 - box.x1; let availHeight = box.y2 - box.y1; let oldNPages = this._grid.nPages(); @@ -794,9 +794,9 @@ var FrequentView = new Lang.Class({ y_align: Clutter.ActorAlign.CENTER, y_expand: true }); - this._grid.actor.y_expand = true; + this._grid.y_expand = true; - this.actor.add_actor(this._grid.actor); + this.actor.add_actor(this._grid); this.actor.add_actor(this._noFrequentAppsLabel); this._noFrequentAppsLabel.hide(); @@ -843,7 +843,7 @@ var FrequentView = new Lang.Class({ box.x2 = width; box.y2 = height; box = this.actor.get_theme_node().get_content_box(box); - box = this._grid.actor.get_theme_node().get_content_box(box); + box = this._grid.get_theme_node().get_content_box(box); let availWidth = box.x2 - box.x1; let availHeight = box.y2 - box.y1; this._grid.adaptToSize(availWidth, availHeight); @@ -1141,12 +1141,12 @@ var FolderView = new Lang.Class({ this.parent(null, null); // If it not expand, the parent doesn't take into account its preferred_width when allocating // the second time it allocates, so we apply the "Standard hack for ClutterBinLayout" - this._grid.actor.x_expand = true; + this._grid.x_expand = true; this.actor = new St.ScrollView({ overlay_scrollbars: true }); this.actor.set_policy(Gtk.PolicyType.NEVER, Gtk.PolicyType.AUTOMATIC); let scrollableContainer = new St.BoxLayout({ vertical: true, reactive: true }); - scrollableContainer.add_actor(this._grid.actor); + scrollableContainer.add_actor(this._grid); this.actor.add_actor(scrollableContainer); let action = new Clutter.PanAction({ interpolate: true }); @@ -1369,7 +1369,7 @@ var FolderIcon = new Lang.Class({ _updatePopupSize() { // StWidget delays style calculation until needed, make sure we use the correct values - this.view._grid.actor.ensure_style(); + this.view._grid.ensure_style(); let offsetForEachSide = Math.ceil((this._popup.getOffset(St.Side.TOP) + this._popup.getOffset(St.Side.BOTTOM) - diff --git a/js/ui/iconGrid.js b/js/ui/iconGrid.js index a0d008386..cbfeb05f4 100644 --- a/js/ui/iconGrid.js +++ b/js/ui/iconGrid.js @@ -189,8 +189,16 @@ function zoomOutActor(actor) { var IconGrid = new Lang.Class({ Name: 'IconGrid', + Extends: St.Widget, + Signals: {'animation-done': {}, + 'child-focused': { param_types: [Clutter.Actor.$gtype]} }, _init(params) { + this.parent({ style_class: 'icon-grid', + y_align: Clutter.ActorAlign.START }); + + this.actor = this; + params = Params.parse(params, { rowLimit: null, columnLimit: null, minRows: 1, @@ -211,30 +219,23 @@ var IconGrid = new Lang.Class({ this.rightPadding = 0; this.leftPadding = 0; - this.actor = new St.BoxLayout({ style_class: 'icon-grid', - vertical: true }); this._items = []; this._clonesAnimating = []; // Pulled from CSS, but hardcode some defaults here this._spacing = 0; this._hItemSize = this._vItemSize = ICON_SIZE; this._fixedHItemSize = this._fixedVItemSize = undefined; - this._grid = new Shell.GenericContainer(); - this.actor.add(this._grid, { expand: true, y_align: St.Align.START }); - this.actor.connect('style-changed', this._onStyleChanged.bind(this)); + this.connect('style-changed', this._onStyleChanged.bind(this)); // Cancel animations when hiding the overview, to avoid icons // swarming into the void ... - this.actor.connect('notify::mapped', () => { - if (!this.actor.mapped) + this.connect('notify::mapped', () => { + if (!this.mapped) this._cancelAnimation(); }); - this._grid.connect('get-preferred-width', this._getPreferredWidth.bind(this)); - this._grid.connect('get-preferred-height', this._getPreferredHeight.bind(this)); - this._grid.connect('allocate', this._allocate.bind(this)); - this._grid.connect('actor-added', this._childAdded.bind(this)); - this._grid.connect('actor-removed', this._childRemoved.bind(this)); + this.connect('actor-added', this._childAdded.bind(this)); + this.connect('actor-removed', this._childRemoved.bind(this)); }, _keyFocusIn(actor) { @@ -249,13 +250,13 @@ var IconGrid = new Lang.Class({ child.disconnect(child._iconGridKeyFocusInId); }, - _getPreferredWidth(grid, forHeight, alloc) { + vfunc_get_preferred_width(forHeight) { if (this._fillParent) // Ignore all size requests of children and request a size of 0; // later we'll allocate as many children as fit the parent - return; + return [0, 0]; - let nChildren = this._grid.get_n_children(); + let nChildren = this.get_n_children(); let nColumns = this._colLimit ? Math.min(this._colLimit, nChildren) : nChildren; @@ -263,22 +264,28 @@ var IconGrid = new Lang.Class({ // Kind of a lie, but not really an issue right now. If // we wanted to support some sort of hidden/overflow that would // need higher level design - alloc.min_size = this._getHItemSize() + this.leftPadding + this.rightPadding; - alloc.natural_size = nColumns * this._getHItemSize() + totalSpacing + this.leftPadding + this.rightPadding; + let minSize = this._getHItemSize() + this.leftPadding + this.rightPadding; + let natSize = nColumns * this._getHItemSize() + totalSpacing + this.leftPadding + this.rightPadding; + + return this.get_theme_node().adjust_preferred_width(minSize, natSize); }, _getVisibleChildren() { - return this._grid.get_children().filter(actor => actor.visible); + return this.get_children().filter(actor => actor.visible); }, - _getPreferredHeight(grid, forWidth, alloc) { + vfunc_get_preferred_height(forWidth) { if (this._fillParent) // Ignore all size requests of children and request a size of 0; // later we'll allocate as many children as fit the parent - return; + return [0, 0]; + let themeNode = this.get_theme_node(); let children = this._getVisibleChildren(); let nColumns; + + forWidth = themeNode.adjust_for_width(forWidth); + if (forWidth < 0) nColumns = children.length; else @@ -293,16 +300,21 @@ var IconGrid = new Lang.Class({ nRows = Math.min(nRows, this._rowLimit); let totalSpacing = Math.max(0, nRows - 1) * this._getSpacing(); let height = nRows * this._getVItemSize() + totalSpacing + this.topPadding + this.bottomPadding; - alloc.min_size = height; - alloc.natural_size = height; + + return themeNode.adjust_preferred_height(height, height); }, - _allocate(grid, box, flags) { + vfunc_allocate(box, flags) { + this.set_allocation(box, flags); + + let themeNode = this.get_theme_node(); + box = themeNode.get_content_box(box); + if (this._fillParent) { // Reset the passed in box to fill the parent - let parentBox = this.actor.get_parent().allocation; - let gridBox = this.actor.get_theme_node().get_content_box(parentBox); - box = this._grid.get_theme_node().get_content_box(gridBox); + let parentBox = this.get_parent().allocation; + let gridBox = themeNode.get_content_box(parentBox); + box = themeNode.get_content_box(gridBox); } let children = this._getVisibleChildren(); @@ -332,10 +344,10 @@ var IconGrid = new Lang.Class({ if (this._rowLimit && rowIndex >= this._rowLimit || this._fillParent && childBox.y2 > availHeight - this.bottomPadding) { - this._grid.set_skip_paint(children[i], true); + children[i]._skipPaint = true; } else { children[i].allocate(childBox, flags); - this._grid.set_skip_paint(children[i], false); + children[i]._skipPaint = false; } columnIndex++; @@ -353,6 +365,66 @@ var IconGrid = new Lang.Class({ } }, + vfunc_paint() { + this.paint_background(); + + this.get_children().forEach(c => { + if (!c._skipPaint) + c.paint(); + }); + }, + + vfunc_pick(color) { + this.parent(color); + + this.get_children().forEach(c => { + if (!c._skipPaint) + c.paint(); + }); + }, + + vfunc_get_paint_volume(paintVolume) { + // Setting the paint volume does not make sense when we don't have + // any allocation + if (!this.has_allocation()) + return false; + + let themeNode = this.get_theme_node(); + let allocationBox = this.get_allocation_box(); + let paintBox = themeNode.get_paint_box(allocationBox); + + let origin = new Clutter.Vertex(); + origin.x = paintBox.x1 - allocationBox.x1; + origin.y = paintBox.y1 - allocationBox.y1; + origin.z = 0.0; + + paintVolume.set_origin(origin); + paintVolume.set_width(paintBox.x2 - paintBox.x1); + paintVolume.set_height(paintBox.y2 - paintBox.y1); + + if (this.get_clip_to_allocation()) + return true; + + for (let child = this.get_first_child(); + child != null; + child = child.get_next_sibling()) { + + if (!child.visible) + continue; + + if (child._skipPaint) + continue; + + let childVolume = child.get_transformed_paint_volume(this); + if (!childVolume) + return false + + paintVolume.union(childVolume); + } + + return true; + }, + /** * Intended to be override by subclasses if they need a different * set of items to be animated. @@ -589,11 +661,11 @@ var IconGrid = new Lang.Class({ }, _onStyleChanged() { - let themeNode = this.actor.get_theme_node(); + let themeNode = this.get_theme_node(); this._spacing = themeNode.get_length('spacing'); this._hItemSize = themeNode.get_length('-shell-grid-horizontal-item-size') || ICON_SIZE; this._vItemSize = themeNode.get_length('-shell-grid-vertical-item-size') || ICON_SIZE; - this._grid.queue_relayout(); + this.queue_relayout(); }, nRows(forWidth) { @@ -625,12 +697,12 @@ var IconGrid = new Lang.Class({ removeAll() { this._items = []; - this._grid.remove_all_children(); + this.remove_all_children(); }, destroyAll() { this._items = []; - this._grid.destroy_all_children(); + this.destroy_all_children(); }, addItem(item, index) { @@ -639,21 +711,21 @@ var IconGrid = new Lang.Class({ this._items.push(item); if (index !== undefined) - this._grid.insert_child_at_index(item.actor, index); + this.insert_child_at_index(item.actor, index); else - this._grid.add_actor(item.actor); + this.add_actor(item.actor); }, removeItem(item) { - this._grid.remove_child(item.actor); + this.remove_child(item.actor); }, getItemAtIndex(index) { - return this._grid.get_child_at_index(index); + return this.get_child_at_index(index); }, visibleItemsCount() { - return this._grid.get_n_children() - this._grid.get_n_skip_paint(); + return this.get_children().filter(c => !c._skipPaint).length; }, setSpacing(spacing) { @@ -739,11 +811,12 @@ var IconGrid = new Lang.Class({ } } }); -Signals.addSignalMethods(IconGrid.prototype); var PaginatedIconGrid = new Lang.Class({ Name: 'PaginatedIconGrid', Extends: IconGrid, + Signals: {'space-opened': {}, + 'space-closed': {} }, _init(params) { this.parent(params); @@ -754,20 +827,22 @@ var PaginatedIconGrid = new Lang.Class({ this._childrenPerPage = 0; }, - _getPreferredHeight(grid, forWidth, alloc) { - alloc.min_size = (this._availableHeightPerPageForItems() + this.bottomPadding + this.topPadding) * this._nPages + this._spaceBetweenPages * this._nPages; - alloc.natural_size = (this._availableHeightPerPageForItems() + this.bottomPadding + this.topPadding) * this._nPages + this._spaceBetweenPages * this._nPages; + vfunc_get_preferred_height(forWidth) { + let height = (this._availableHeightPerPageForItems() + this.bottomPadding + this.topPadding) * this._nPages + this._spaceBetweenPages * this._nPages; + return [height, height]; }, - _allocate(grid, box, flags) { + vfunc_allocate(box, flags) { if (this._childrenPerPage == 0) log('computePages() must be called before allocate(); pagination will not work.'); + this.set_allocation(box, flags); + if (this._fillParent) { // Reset the passed in box to fill the parent - let parentBox = this.actor.get_parent().allocation; - let gridBox = this.actor.get_theme_node().get_content_box(parentBox); - box = this._grid.get_theme_node().get_content_box(gridBox); + let parentBox = this.get_parent().allocation; + let gridBox = this.get_theme_node().get_content_box(parentBox); + box = this.get_theme_node().get_content_box(gridBox); } let children = this._getVisibleChildren(); let availWidth = box.x2 - box.x1; @@ -795,7 +870,7 @@ var PaginatedIconGrid = new Lang.Class({ for (let i = 0; i < children.length; i++) { let childBox = this._calculateChildBox(children[i], x, y, box); children[i].allocate(childBox, flags); - this._grid.set_skip_paint(children[i], false); + children[i]._skipPaint = false; columnIndex++; if (columnIndex == nColumns) { @@ -966,4 +1041,3 @@ var PaginatedIconGrid = new Lang.Class({ } } }); -Signals.addSignalMethods(PaginatedIconGrid.prototype); diff --git a/js/ui/search.js b/js/ui/search.js index 97e18c058..4adf50217 100644 --- a/js/ui/search.js +++ b/js/ui/search.js @@ -363,8 +363,9 @@ var GridSearchResults = new Lang.Class({ this._grid = new IconGrid.IconGrid({ rowLimit: MAX_GRID_SEARCH_RESULTS_ROWS, xAlign: St.Align.START }); + this._bin = new St.Bin({ x_align: St.Align.MIDDLE }); - this._bin.set_child(this._grid.actor); + this._bin.set_child(this._grid); this._resultDisplayBin.set_child(this._bin); },