gnome-shell/src/shell-overflow-list.c
Siegfried-Angel Gevatter Pujals 03e0fe1e95 Replace _getIndexOfDisplayedActor with a function in OverflowList
Said function in genericDisplay.js was returning the index of the
actor based upon its position in the entire list, while everywhere
else indexes relative to the currently displayed page were used.

This made actions in the details pane break (bug #590949), so I
replace it with a new function in shell-overflow-list.c,
shell_overflow_list_get_actor_index, which is page based.
2009-08-06 19:51:11 +02:00

426 lines
12 KiB
C

/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
#include "shell-overflow-list.h"
G_DEFINE_TYPE (ShellOverflowList,
shell_overflow_list,
CLUTTER_TYPE_GROUP);
enum {
PROP_0,
PROP_SPACING,
PROP_ITEM_HEIGHT,
PROP_DISPLAYED_COUNT,
PROP_PAGE,
PROP_N_PAGES
};
struct _ShellOverflowListPrivate {
guint item_height;
guint spacing;
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,
const GValue *value,
GParamSpec *pspec)
{
ShellOverflowList *self = SHELL_OVERFLOW_LIST (object);
ShellOverflowListPrivate *priv = self->priv;
switch (prop_id)
{
case PROP_SPACING:
priv->spacing = g_value_get_float (value);
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
break;
case PROP_ITEM_HEIGHT:
priv->item_height = g_value_get_float (value);
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
break;
case PROP_PAGE:
priv->page = g_value_get_uint (value);
recalc_displayed_count (self);
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
shell_overflow_list_get_property(GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
ShellOverflowList *self = SHELL_OVERFLOW_LIST (object);
ShellOverflowListPrivate *priv = self->priv;
switch (prop_id)
{
case PROP_SPACING:
g_value_set_float (value, priv->spacing);
break;
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;
case PROP_N_PAGES:
g_value_set_uint (value, priv->n_pages);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
}
}
static void
shell_overflow_list_allocate (ClutterActor *actor,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
ShellOverflowList *self = SHELL_OVERFLOW_LIST (actor);
ShellOverflowListPrivate *priv = self->priv;
GList *children, *iter;
int n_pages;
int n_children;
int n_fits;
float width;
float curheight;
float avail_height;
gboolean overflow;
/* chain up to set actor->allocation */
(CLUTTER_ACTOR_CLASS (g_type_class_peek (clutter_actor_get_type ())))->allocate (actor, box, flags);
width = box->x2 - box->x1;
curheight = 0;
avail_height = box->y2 - box->y1;
children = clutter_container_get_children (CLUTTER_CONTAINER (self));
n_children = g_list_length (children);
n_fits = 0;
n_pages = 1;
overflow = FALSE;
for (iter = children; iter; iter = iter->next)
{
ClutterActor *actor = CLUTTER_ACTOR (iter->data);
ClutterActorBox child_box;
if (iter != children)
curheight += priv->spacing;
if ((curheight + priv->item_height) > avail_height)
{
overflow = TRUE;
curheight = 0;
n_pages++;
}
else if (!overflow)
n_fits++;
child_box.x1 = 0;
child_box.x2 = width;
child_box.y1 = curheight;
child_box.y2 = child_box.y1 + priv->item_height;
clutter_actor_allocate (actor, &child_box, flags);
curheight += priv->item_height;
}
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);
}
void
shell_overflow_list_paint (ClutterActor *actor)
{
ShellOverflowList *self = SHELL_OVERFLOW_LIST (actor);
ShellOverflowListPrivate *priv = self->priv;
GList *children, *iter;
int i;
children = clutter_container_get_children (CLUTTER_CONTAINER (self));
if (children == NULL)
return;
iter = g_list_nth (children, (priv->page) * priv->items_per_page);
i = 0;
for (;iter && i < priv->items_per_page; iter = iter->next, i++)
{
ClutterActor *actor = CLUTTER_ACTOR (iter->data);
clutter_actor_paint (actor);
}
g_list_free (children);
}
static void
shell_overflow_list_pick (ClutterActor *actor,
const ClutterColor *color)
{
(CLUTTER_ACTOR_CLASS (g_type_class_peek (clutter_actor_get_type ())))->pick (actor, color);
shell_overflow_list_paint (actor);
}
static void
shell_overflow_list_get_preferred_height (ClutterActor *actor,
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
ShellOverflowList *self = SHELL_OVERFLOW_LIST (actor);
ShellOverflowListPrivate *priv = self->priv;
GList *children;
if (min_height_p)
*min_height_p = 0;
if (natural_height_p)
{
int n_children;
children = clutter_container_get_children (CLUTTER_CONTAINER (self));
n_children = g_list_length (children);
if (n_children == 0)
*natural_height_p = 0;
else
*natural_height_p = (n_children - 1) * (priv->item_height + priv->spacing) + priv->item_height;
g_list_free (children);
}
}
static void
shell_overflow_list_get_preferred_width (ClutterActor *actor,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
ShellOverflowList *self = SHELL_OVERFLOW_LIST (actor);
gboolean first = TRUE;
float min = 0, natural = 0;
GList *iter;
GList *children;
children = clutter_container_get_children (CLUTTER_CONTAINER (self));
for (iter = children; iter; iter = iter->next)
{
ClutterActor *child = iter->data;
float child_min, child_natural;
clutter_actor_get_preferred_width (child,
for_height,
&child_min,
&child_natural);
if (first)
{
first = FALSE;
min = child_min;
natural = child_natural;
}
else
{
if (child_min > min)
min = child_min;
if (child_natural > natural)
natural = child_natural;
}
}
if (min_width_p)
*min_width_p = min;
if (natural_width_p)
*natural_width_p = natural;
g_list_free (children);
}
static void
shell_overflow_list_class_init (ShellOverflowListClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
gobject_class->get_property = shell_overflow_list_get_property;
gobject_class->set_property = shell_overflow_list_set_property;
actor_class->get_preferred_width = shell_overflow_list_get_preferred_width;
actor_class->get_preferred_height = shell_overflow_list_get_preferred_height;
actor_class->allocate = shell_overflow_list_allocate;
actor_class->paint = shell_overflow_list_paint;
actor_class->pick = shell_overflow_list_pick;
g_object_class_install_property (gobject_class,
PROP_SPACING,
g_param_spec_float ("spacing",
"Spacing",
"Space between items",
0.0, G_MAXFLOAT, 0.0,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_ITEM_HEIGHT,
g_param_spec_float ("item-height",
"Item height",
"Fixed item height value",
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",
"Page number",
"Page number",
0, G_MAXUINT, 0,
G_PARAM_READWRITE));
g_object_class_install_property (gobject_class,
PROP_N_PAGES,
g_param_spec_uint ("n-pages",
"Number of pages",
"Number of pages",
0, G_MAXUINT, 0,
G_PARAM_READABLE));
g_type_class_add_private (gobject_class, sizeof (ShellOverflowListPrivate));
}
static void
shell_overflow_list_init (ShellOverflowList *self)
{
self->priv = G_TYPE_INSTANCE_GET_PRIVATE (self,
SHELL_TYPE_OVERFLOW_LIST,
ShellOverflowListPrivate);
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;
}
/**
* shell_overflow_list_get_actor_index:
* @self:
* @actor: a child of the list
*
* Returns the index on the current page of the given actor.
*
* Return value: index of @actor in
* the currently visible page
*/
int
shell_overflow_list_get_actor_index (ShellOverflowList *self,
ClutterActor *actor)
{
GList *children, *iter;
int i;
children = clutter_container_get_children (CLUTTER_CONTAINER (self));
if (children == NULL)
return NULL;
iter = g_list_nth (children, (self->priv->page) * self->priv->items_per_page);
int result = -1;
for (i = 0; iter; iter = iter->next, i++)
if (iter->data == actor)
{
result = i;
break;
}
g_list_free (children);
return result;
}