gnome-shell/src/shell-slicer.c
Dan Winship 5331d3e360 [St] Make allocation handling more consistent
In StBin, StBoxLayout, and StTable, if a child has a potential
allocation that is larger than its preferred size, we give it its
preferred size instead. However, the corresponding
get_preferred_height/width methods were not making the same
assumption, which meant that if we had more width than the widget
wanted, we would allocate it its preferred width, but with the height
that corresponded to the larger width.

Fix this by defining new helpers _st_actor_get_preferred_width() and
_st_actor_get_preferred_height() and using them everywhere. Also, make
StBin and StTable use _st_allocate_fill() rather than having
nearly-identical duplicate copies of the code.

https://bugzilla.gnome.org/show_bug.cgi?id=609848
2010-02-16 14:06:39 -05:00

166 lines
4.5 KiB
C

/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/**
* SECTION:shell-slicer
* @short_description: Display only part of another actor
*
* A #StBin that has 0 minimum size, and will clip its child
* in the middle.
*/
#include "config.h"
#include "shell-slicer.h"
G_DEFINE_TYPE (ShellSlicer,
shell_slicer,
ST_TYPE_BIN);
static void
shell_slicer_get_preferred_width (ClutterActor *self,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
ClutterActor *child = st_bin_get_child (ST_BIN (self));
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (self));
st_theme_node_adjust_for_height (theme_node, &for_height);
if (min_width_p)
*min_width_p = 0;
if (child == NULL)
{
if (natural_width_p)
*natural_width_p = 0;
}
else
{
_st_actor_get_preferred_width (child, for_height, FALSE,
NULL,
natural_width_p);
}
st_theme_node_adjust_preferred_width (theme_node, min_width_p, natural_width_p);
}
static void
shell_slicer_get_preferred_height (ClutterActor *self,
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
ClutterActor *child = st_bin_get_child (ST_BIN (self));
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (self));
st_theme_node_adjust_for_width (theme_node, &for_width);
if (min_height_p)
*min_height_p = 0;
if (child == NULL)
{
if (natural_height_p)
*natural_height_p = 0;
}
else
{
_st_actor_get_preferred_height (child, for_width, FALSE,
NULL,
natural_height_p);
}
st_theme_node_adjust_preferred_height (theme_node, min_height_p, natural_height_p);
}
static void
shell_slicer_allocate (ClutterActor *self,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
ClutterActor *child;
/* Chain up directly to ClutterActor to set actor->allocation. We explicitly skip our parent class
* StBin here because we want to override the allocate function. */
CLUTTER_ACTOR_CLASS (g_type_class_peek (clutter_actor_get_type ()))->allocate (self, box, flags);
child = st_bin_get_child (ST_BIN (self));
if (child)
clutter_actor_allocate_preferred_size (child, flags);
}
static void
shell_slicer_paint_child (ShellSlicer *self)
{
ClutterActor *child;
ClutterActorBox self_box;
ClutterActorBox child_box;
float width, height, child_width, child_height;
StAlign x_align, y_align;
double x_align_factor, y_align_factor;
child = st_bin_get_child (ST_BIN (self));
if (!child)
return;
st_bin_get_alignment (ST_BIN (self), &x_align, &y_align);
_st_get_align_factors (ST_WIDGET (self), x_align, y_align,
&x_align_factor, &y_align_factor);
clutter_actor_get_allocation_box (CLUTTER_ACTOR (self), &self_box);
clutter_actor_get_allocation_box (child, &child_box);
width = self_box.x2 - self_box.x1;
height = self_box.y2 - self_box.y1;
child_width = child_box.x2 - child_box.x1;
child_height = child_box.y2 - child_box.y1;
cogl_push_matrix ();
cogl_clip_push (0, 0, width, height);
cogl_translate ((int)(0.5 + x_align_factor * (width - child_width)),
(int)(0.5 + y_align_factor * (height - child_height)),
0);
clutter_actor_paint (child);
cogl_clip_pop ();
cogl_pop_matrix ();
}
static void
shell_slicer_paint (ClutterActor *self)
{
/* StWidget paints CSS elements */
CLUTTER_ACTOR_CLASS (g_type_class_peek (st_widget_get_type ()))->paint (self);
shell_slicer_paint_child (SHELL_SLICER (self));
}
static void
shell_slicer_pick (ClutterActor *self,
const ClutterColor *pick_color)
{
shell_slicer_paint_child (SHELL_SLICER (self));
}
static void
shell_slicer_class_init (ShellSlicerClass *klass)
{
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
actor_class->get_preferred_width = shell_slicer_get_preferred_width;
actor_class->get_preferred_height = shell_slicer_get_preferred_height;
actor_class->allocate = shell_slicer_allocate;
actor_class->paint = shell_slicer_paint;
actor_class->pick = shell_slicer_pick;
}
static void
shell_slicer_init (ShellSlicer *actor)
{
}