Fixes for GenericDisplay

GenericDisplay wasn't quite completely converted to the ShellOverflowList
model.  Since the list now holds all actors, the indexing/wrapping
was incorrect.

Add a property which lets us keep track of how many items are displayed,
use this in genericDisplay.

Avoid setting selectedIndex to -2 when going up with no items.

If we're not displaying any results at all, don't attempt keynav (for now).
This commit is contained in:
Colin Walters 2009-07-11 12:26:36 -04:00
parent f7a82d6400
commit 2161e90cda
4 changed files with 104 additions and 24 deletions

View File

@ -351,7 +351,6 @@ GenericDisplay.prototype = {
this._matchedItems = []; this._matchedItems = [];
// map<itemId, GenericDisplayItem> // map<itemId, GenericDisplayItem>
this._displayedItems = {}; this._displayedItems = {};
this._displayedItemsCount = 0;
this._selectedIndex = -1; this._selectedIndex = -1;
// These two are public - .actor is the normal "actor subclass" property, // These two are public - .actor is the normal "actor subclass" property,
// but we also expose a .displayControl actor which is separate. // 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 // to the bottom one. Returns true if the selection actually moved up, false if it wrapped
// around to the bottom. // around to the bottom.
selectUp: function() { selectUp: function() {
let count = this._list.displayedCount;
let selectedUp = true; let selectedUp = true;
let prev = this._selectedIndex - 1; let prev = this._selectedIndex - 1;
if (this._selectedIndex <= 0) { if (this._selectedIndex <= 0) {
prev = this._displayedItemsCount - 1; prev = count - 1;
selectedUp = false; selectedUp = false;
} }
this._selectIndex(prev); 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 // to the top one. Returns true if the selection actually moved down, false if it wrapped
// around to the top. // around to the top.
selectDown: function() { selectDown: function() {
let count = this._list.displayedCount;
let selectedDown = true; let selectedDown = true;
let next = this._selectedIndex + 1; let next = this._selectedIndex + 1;
if (this._selectedIndex == this._displayedItemsCount - 1) { if (this._selectedIndex == count - 1) {
next = 0; next = 0;
selectedDown = false; selectedDown = false;
} }
@ -429,8 +430,9 @@ GenericDisplay.prototype = {
// Selects the last item among the displayed items. // Selects the last item among the displayed items.
selectLastItem: function() { selectLastItem: function() {
let count = this._list.displayedCount;
if (this.hasItems()) if (this.hasItems())
this._selectIndex(this._displayedItemsCount - 1); this._selectIndex(count - 1);
}, },
// Returns true if the display has some item selected. // Returns true if the display has some item selected.
@ -445,7 +447,7 @@ GenericDisplay.prototype = {
// Returns true if the display has any displayed items. // Returns true if the display has any displayed items.
hasItems: function() { hasItems: function() {
return this._displayedItemsCount > 0; return this._list.displayedCount > 0;
}, },
// Updates the displayed items and makes the display actor visible. // Updates the displayed items and makes the display actor visible.
@ -541,15 +543,15 @@ GenericDisplay.prototype = {
})); }));
this._list.add_actor(displayItem.actor); this._list.add_actor(displayItem.actor);
this._displayedItems[itemId] = displayItem; this._displayedItems[itemId] = displayItem;
this._displayedItemsCount++;
}, },
// Removes an item identifed by the itemId from the displayed items. // Removes an item identifed by the itemId from the displayed items.
_removeDisplayItem: function(itemId) { _removeDisplayItem: function(itemId) {
let count = this._list.displayedCount;
let displayItem = this._displayedItems[itemId]; let displayItem = this._displayedItems[itemId];
let displayItemIndex = this._getIndexOfDisplayedActor(displayItem.actor); 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(); this.unsetSelected();
} else if (this.hasSelected() && displayItemIndex < this._selectedIndex) { } else if (this.hasSelected() && displayItemIndex < this._selectedIndex) {
this.selectUp(); this.selectUp();
@ -558,7 +560,6 @@ GenericDisplay.prototype = {
displayItem.destroy(); displayItem.destroy();
delete this._displayedItems[itemId]; delete this._displayedItems[itemId];
this._displayedItemsCount--;
}, },
// Removes all displayed items. // Removes all displayed items.
@ -707,6 +708,7 @@ GenericDisplay.prototype = {
*/ */
_updateDisplayControl: function(resetDisplayControl) { _updateDisplayControl: function(resetDisplayControl) {
if (resetDisplayControl) { if (resetDisplayControl) {
this._selectedIndex = -1;
this.displayControl.remove_all(); this.displayControl.remove_all();
let nPages = this._list.n_pages; let nPages = this._list.n_pages;
let pageNumber = this._list.page; let pageNumber = this._list.page;
@ -744,8 +746,7 @@ GenericDisplay.prototype = {
// Returns a display item based on its index in the ordering of the // Returns a display item based on its index in the ordering of the
// display children. // display children.
_findDisplayedByIndex: function(index) { _findDisplayedByIndex: function(index) {
let displayedActors = this._list.get_children(); let actor = this._list.get_displayed_actor(index);
let actor = displayedActors[index];
return this._findDisplayedByActor(actor); return this._findDisplayedByActor(actor);
}, },
@ -775,7 +776,8 @@ GenericDisplay.prototype = {
// Selects (e.g. highlights) a display item at the provided index, // Selects (e.g. highlights) a display item at the provided index,
// updates this.selectedItemDetails actor, and emits 'selected' signal. // updates this.selectedItemDetails actor, and emits 'selected' signal.
_selectIndex: function(index) { _selectIndex: function(index) {
if (this._selectedIndex != -1) { let count = this._list.displayedCount;
if (this._selectedIndex >= 0) {
let prev = this._findDisplayedByIndex(this._selectedIndex); let prev = this._findDisplayedByIndex(this._selectedIndex);
prev.markSelected(false); prev.markSelected(false);
// Calling destroy() gets large image previews released as quickly as // Calling destroy() gets large image previews released as quickly as
@ -787,12 +789,15 @@ GenericDisplay.prototype = {
this.selectedItemDetails.remove_all(); this.selectedItemDetails.remove_all();
} }
this._selectedIndex = index; if (index < count) {
if (index != -1 && index < this._displayedItemsCount) { this._selectedIndex = index;
let item = this._findDisplayedByIndex(index); if (index >= 0) {
item.markSelected(true); let item = this._findDisplayedByIndex(index);
this.selectedItemDetails.append(item.createDetailsActor(this._availableWidthForItemDetails, this._availableHeightForItemDetails), Big.BoxPackFlags.NONE); item.markSelected(true);
this.emit('selected'); this.selectedItemDetails.append(item.createDetailsActor(this._availableWidthForItemDetails,
this._availableHeightForItemDetails), Big.BoxPackFlags.NONE);
this.emit('selected');
}
} }
} }
}; };

View File

@ -332,6 +332,8 @@ Dash.prototype = {
me.emit('activated'); me.emit('activated');
return true; return true;
} else if (symbol == Clutter.Up) { } else if (symbol == Clutter.Up) {
if (!me._resultsShowing())
return true;
// selectUp and selectDown wrap around in their respective displays // selectUp and selectDown wrap around in their respective displays
// too, but there doesn't seem to be any flickering if we first select // 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 // something in one display, but then unset the selection, and move
@ -342,13 +344,17 @@ Dash.prototype = {
me._resultsAppsSection.display.selectUp(); me._resultsAppsSection.display.selectUp();
else else
me._resultsDocsSection.display.selectUp(); me._resultsDocsSection.display.selectUp();
return true;
} else if (symbol == Clutter.Down) { } else if (symbol == Clutter.Down) {
if (!me._resultsShowing())
return true;
if (me._resultsDocsSection.display.hasSelected()) if (me._resultsDocsSection.display.hasSelected())
me._resultsDocsSection.display.selectDown(); me._resultsDocsSection.display.selectDown();
else if (me._resultsAppsSection.display.hasItems()) else if (me._resultsAppsSection.display.hasItems())
me._resultsAppsSection.display.selectDown(); me._resultsAppsSection.display.selectDown();
else else
me._resultsDocsSection.display.selectDown(); me._resultsDocsSection.display.selectDown();
return true;
} }
return false; return false;
}); });

View File

@ -10,6 +10,7 @@ enum {
PROP_0, PROP_0,
PROP_SPACING, PROP_SPACING,
PROP_ITEM_HEIGHT, PROP_ITEM_HEIGHT,
PROP_DISPLAYED_COUNT,
PROP_PAGE, PROP_PAGE,
PROP_N_PAGES PROP_N_PAGES
}; };
@ -20,8 +21,36 @@ struct _ShellOverflowListPrivate {
guint page; guint page;
guint n_pages; guint n_pages;
guint items_per_page; 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 static void
shell_overflow_list_set_property(GObject *object, shell_overflow_list_set_property(GObject *object,
guint prop_id, guint prop_id,
@ -43,6 +72,7 @@ shell_overflow_list_set_property(GObject *object,
break; break;
case PROP_PAGE: case PROP_PAGE:
priv->page = g_value_get_uint (value); priv->page = g_value_get_uint (value);
recalc_displayed_count (self);
clutter_actor_queue_redraw (CLUTTER_ACTOR (self)); clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
break; break;
default: default:
@ -68,6 +98,9 @@ shell_overflow_list_get_property(GObject *object,
case PROP_ITEM_HEIGHT: case PROP_ITEM_HEIGHT:
g_value_set_float (value, priv->spacing); g_value_set_float (value, priv->spacing);
break; break;
case PROP_DISPLAYED_COUNT:
g_value_set_uint (value, priv->displayed_count);
break;
case PROP_PAGE: case PROP_PAGE:
g_value_set_uint (value, priv->page); g_value_set_uint (value, priv->page);
break; break;
@ -135,12 +168,15 @@ shell_overflow_list_allocate (ClutterActor *actor,
} }
priv->items_per_page = n_fits; priv->items_per_page = n_fits;
if (n_pages != priv->n_pages) if (n_pages != priv->n_pages)
{ {
priv->n_pages = n_pages; priv->n_pages = n_pages;
g_object_notify (G_OBJECT (self), "n-pages"); g_object_notify (G_OBJECT (self), "n-pages");
} }
recalc_displayed_count (self);
g_list_free (children); g_list_free (children);
} }
@ -173,14 +209,9 @@ static void
shell_overflow_list_pick (ClutterActor *actor, shell_overflow_list_pick (ClutterActor *actor,
const ClutterColor *color) 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); (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, 0.0, G_MAXFLOAT, 0.0,
G_PARAM_READWRITE)); 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, g_object_class_install_property (gobject_class,
PROP_PAGE, PROP_PAGE,
g_param_spec_uint ("page", g_param_spec_uint ("page",
@ -301,7 +340,7 @@ shell_overflow_list_class_init (ShellOverflowListClass *klass)
PROP_N_PAGES, PROP_N_PAGES,
g_param_spec_uint ("n-pages", g_param_spec_uint ("n-pages",
"Number of pages", "Number of pages",
"Number of pagest", "Number of pages",
0, G_MAXUINT, 0, 0, G_MAXUINT, 0,
G_PARAM_READABLE)); G_PARAM_READABLE));
@ -318,3 +357,31 @@ shell_overflow_list_init (ShellOverflowList *self)
self->priv->n_pages = 1; self->priv->n_pages = 1;
self->priv->page = 0; 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;
}

View File

@ -36,6 +36,8 @@ struct _ShellOverflowListClass
GType shell_overflow_list_get_type (void) G_GNUC_CONST; GType shell_overflow_list_get_type (void) G_GNUC_CONST;
ClutterActor *shell_overflow_list_get_displayed_actor (ShellOverflowList *list, guint index);
G_END_DECLS G_END_DECLS
#endif /* __SHELL_OVERFLOW_LIST_H__ */ #endif /* __SHELL_OVERFLOW_LIST_H__ */