diff --git a/js/ui/genericDisplay.js b/js/ui/genericDisplay.js index 56325c95f..3ce3fa5ee 100644 --- a/js/ui/genericDisplay.js +++ b/js/ui/genericDisplay.js @@ -351,7 +351,6 @@ GenericDisplay.prototype = { this._matchedItems = []; // map this._displayedItems = {}; - this._displayedItemsCount = 0; this._selectedIndex = -1; // These two are public - .actor is the normal "actor subclass" property, // but we also expose a .displayControl actor which is separate. @@ -397,10 +396,11 @@ GenericDisplay.prototype = { // to the bottom one. Returns true if the selection actually moved up, false if it wrapped // around to the bottom. selectUp: function() { + let count = this._list.displayedCount; let selectedUp = true; let prev = this._selectedIndex - 1; if (this._selectedIndex <= 0) { - prev = this._displayedItemsCount - 1; + prev = count - 1; selectedUp = false; } this._selectIndex(prev); @@ -411,9 +411,10 @@ GenericDisplay.prototype = { // to the top one. Returns true if the selection actually moved down, false if it wrapped // around to the top. selectDown: function() { + let count = this._list.displayedCount; let selectedDown = true; let next = this._selectedIndex + 1; - if (this._selectedIndex == this._displayedItemsCount - 1) { + if (this._selectedIndex == count - 1) { next = 0; selectedDown = false; } @@ -429,8 +430,9 @@ GenericDisplay.prototype = { // Selects the last item among the displayed items. selectLastItem: function() { + let count = this._list.displayedCount; if (this.hasItems()) - this._selectIndex(this._displayedItemsCount - 1); + this._selectIndex(count - 1); }, // Returns true if the display has some item selected. @@ -445,7 +447,7 @@ GenericDisplay.prototype = { // Returns true if the display has any displayed items. hasItems: function() { - return this._displayedItemsCount > 0; + return this._list.displayedCount > 0; }, // Updates the displayed items and makes the display actor visible. @@ -541,15 +543,15 @@ GenericDisplay.prototype = { })); this._list.add_actor(displayItem.actor); this._displayedItems[itemId] = displayItem; - this._displayedItemsCount++; }, // Removes an item identifed by the itemId from the displayed items. _removeDisplayItem: function(itemId) { + let count = this._list.displayedCount; let displayItem = this._displayedItems[itemId]; let displayItemIndex = this._getIndexOfDisplayedActor(displayItem.actor); - if (this.hasSelected() && (this._displayedItemsCount == 1 || !this._list.visible)) { + if (this.hasSelected() && (count == 1 || !this._list.visible)) { this.unsetSelected(); } else if (this.hasSelected() && displayItemIndex < this._selectedIndex) { this.selectUp(); @@ -558,7 +560,6 @@ GenericDisplay.prototype = { displayItem.destroy(); delete this._displayedItems[itemId]; - this._displayedItemsCount--; }, // Removes all displayed items. @@ -707,6 +708,7 @@ GenericDisplay.prototype = { */ _updateDisplayControl: function(resetDisplayControl) { if (resetDisplayControl) { + this._selectedIndex = -1; this.displayControl.remove_all(); let nPages = this._list.n_pages; let pageNumber = this._list.page; @@ -744,8 +746,7 @@ GenericDisplay.prototype = { // Returns a display item based on its index in the ordering of the // display children. _findDisplayedByIndex: function(index) { - let displayedActors = this._list.get_children(); - let actor = displayedActors[index]; + let actor = this._list.get_displayed_actor(index); return this._findDisplayedByActor(actor); }, @@ -775,7 +776,8 @@ GenericDisplay.prototype = { // Selects (e.g. highlights) a display item at the provided index, // updates this.selectedItemDetails actor, and emits 'selected' signal. _selectIndex: function(index) { - if (this._selectedIndex != -1) { + let count = this._list.displayedCount; + if (this._selectedIndex >= 0) { let prev = this._findDisplayedByIndex(this._selectedIndex); prev.markSelected(false); // Calling destroy() gets large image previews released as quickly as @@ -787,12 +789,15 @@ GenericDisplay.prototype = { this.selectedItemDetails.remove_all(); } - this._selectedIndex = index; - if (index != -1 && index < this._displayedItemsCount) { - let item = this._findDisplayedByIndex(index); - item.markSelected(true); - this.selectedItemDetails.append(item.createDetailsActor(this._availableWidthForItemDetails, this._availableHeightForItemDetails), Big.BoxPackFlags.NONE); - this.emit('selected'); + if (index < count) { + this._selectedIndex = index; + if (index >= 0) { + let item = this._findDisplayedByIndex(index); + item.markSelected(true); + this.selectedItemDetails.append(item.createDetailsActor(this._availableWidthForItemDetails, + this._availableHeightForItemDetails), Big.BoxPackFlags.NONE); + this.emit('selected'); + } } } }; diff --git a/js/ui/overlay.js b/js/ui/overlay.js index 999dd0538..3c8fb5384 100644 --- a/js/ui/overlay.js +++ b/js/ui/overlay.js @@ -332,6 +332,8 @@ Dash.prototype = { me.emit('activated'); return true; } else if (symbol == Clutter.Up) { + if (!me._resultsShowing()) + return true; // selectUp and selectDown wrap around in their respective displays // too, but there doesn't seem to be any flickering if we first select // something in one display, but then unset the selection, and move @@ -342,13 +344,17 @@ Dash.prototype = { me._resultsAppsSection.display.selectUp(); else me._resultsDocsSection.display.selectUp(); + return true; } else if (symbol == Clutter.Down) { + if (!me._resultsShowing()) + return true; if (me._resultsDocsSection.display.hasSelected()) me._resultsDocsSection.display.selectDown(); else if (me._resultsAppsSection.display.hasItems()) me._resultsAppsSection.display.selectDown(); else me._resultsDocsSection.display.selectDown(); + return true; } return false; }); diff --git a/src/shell-overflow-list.c b/src/shell-overflow-list.c index b1f418e19..8565a33c0 100644 --- a/src/shell-overflow-list.c +++ b/src/shell-overflow-list.c @@ -10,6 +10,7 @@ enum { PROP_0, PROP_SPACING, PROP_ITEM_HEIGHT, + PROP_DISPLAYED_COUNT, PROP_PAGE, PROP_N_PAGES }; @@ -20,8 +21,36 @@ struct _ShellOverflowListPrivate { guint page; guint n_pages; guint items_per_page; + guint displayed_count; }; +static void +recalc_displayed_count (ShellOverflowList *self) +{ + GList *children; + int n_children; + int displayed_count; + int page, n_pages; + + children = clutter_container_get_children (CLUTTER_CONTAINER (self)); + n_children = g_list_length (children); + g_list_free (children); + + page = self->priv->page; + n_pages = self->priv->n_pages; + if (page < n_pages-1) + displayed_count = self->priv->items_per_page; + else if (n_pages > 0) + displayed_count = n_children - (self->priv->items_per_page * (n_pages-1)); + else + displayed_count = 0; + if (displayed_count != self->priv->displayed_count) + { + self->priv->displayed_count = displayed_count; + g_object_notify (G_OBJECT (self), "displayed-count"); + } +} + static void shell_overflow_list_set_property(GObject *object, guint prop_id, @@ -43,6 +72,7 @@ shell_overflow_list_set_property(GObject *object, break; case PROP_PAGE: priv->page = g_value_get_uint (value); + recalc_displayed_count (self); clutter_actor_queue_redraw (CLUTTER_ACTOR (self)); break; default: @@ -68,6 +98,9 @@ shell_overflow_list_get_property(GObject *object, case PROP_ITEM_HEIGHT: g_value_set_float (value, priv->spacing); break; + case PROP_DISPLAYED_COUNT: + g_value_set_uint (value, priv->displayed_count); + break; case PROP_PAGE: g_value_set_uint (value, priv->page); break; @@ -135,12 +168,15 @@ shell_overflow_list_allocate (ClutterActor *actor, } priv->items_per_page = n_fits; + if (n_pages != priv->n_pages) { priv->n_pages = n_pages; g_object_notify (G_OBJECT (self), "n-pages"); } + recalc_displayed_count (self); + g_list_free (children); } @@ -173,14 +209,9 @@ static void shell_overflow_list_pick (ClutterActor *actor, const ClutterColor *color) { - ShellOverflowList *self = SHELL_OVERFLOW_LIST (actor); - ShellOverflowListPrivate *priv = self->priv; - GList *children, *iter; - int i; - (CLUTTER_ACTOR_CLASS (g_type_class_peek (clutter_actor_get_type ())))->pick (actor, color); - shell_overflow_list_paint (self); + shell_overflow_list_paint (actor); } @@ -289,6 +320,14 @@ shell_overflow_list_class_init (ShellOverflowListClass *klass) 0.0, G_MAXFLOAT, 0.0, G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, + PROP_DISPLAYED_COUNT, + g_param_spec_uint ("displayed-count", + "Displayed count", + "Number of items displayed on current page", + 0, G_MAXUINT, 0, + G_PARAM_READWRITE)); + g_object_class_install_property (gobject_class, PROP_PAGE, g_param_spec_uint ("page", @@ -301,7 +340,7 @@ shell_overflow_list_class_init (ShellOverflowListClass *klass) PROP_N_PAGES, g_param_spec_uint ("n-pages", "Number of pages", - "Number of pagest", + "Number of pages", 0, G_MAXUINT, 0, G_PARAM_READABLE)); @@ -318,3 +357,31 @@ shell_overflow_list_init (ShellOverflowList *self) self->priv->n_pages = 1; self->priv->page = 0; } + +/** + * shell_overflow_list_get_displayed_actor: + * @self: + * @index: 0-based index for displayed list + * + * Returns the actor at the given index on the current page. + * + * Return value: (transfer none): #ClutterActor at index + */ +ClutterActor * +shell_overflow_list_get_displayed_actor (ShellOverflowList *self, + guint index) +{ + GList *children, *iter; + + children = clutter_container_get_children (CLUTTER_CONTAINER (self)); + + if (children == NULL) + return NULL; + + iter = g_list_nth (children, index + (self->priv->page * self->priv->items_per_page)); + + if (!iter) + return NULL; + + return iter->data; +} diff --git a/src/shell-overflow-list.h b/src/shell-overflow-list.h index 9d9ea8993..c8a912ed6 100644 --- a/src/shell-overflow-list.h +++ b/src/shell-overflow-list.h @@ -36,6 +36,8 @@ struct _ShellOverflowListClass GType shell_overflow_list_get_type (void) G_GNUC_CONST; +ClutterActor *shell_overflow_list_get_displayed_actor (ShellOverflowList *list, guint index); + G_END_DECLS #endif /* __SHELL_OVERFLOW_LIST_H__ */