03e0fe1e95
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.
426 lines
12 KiB
C
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;
|
|
}
|