gnome-shell/src/st/st-label.c
Emmanuele Bassi 5bc042ba6f Remove override of map/unmap
Clutter, since version 1.8, does The Right Thing™ inside the default
implementation of ClutterActor::map and ClutterActor::unmap, even for
non-container actors: it will iterate over the list of children and
map, or unmap, each one of them, respectively.

This means that the requirement to override map and unmap for composite
actors to map and unmap the internal children has been dropped.

https://bugzilla.gnome.org/show_bug.cgi?id=669239
2012-02-06 23:36:43 +00:00

505 lines
14 KiB
C

/* -*- mode: C; c-file-style: "gnu"; indent-tabs-mode: nil; -*- */
/*
* st-label.c: Plain label actor
*
* Copyright 2008,2009 Intel Corporation
* Copyright 2009 Red Hat, Inc.
* Copyright 2010 Florian Müllner
*
* This program is free software; you can redistribute it and/or modify it
* under the terms and conditions of the GNU Lesser General Public License,
* version 2.1, as published by the Free Software Foundation.
*
* This program is distributed in the hope it will be useful, but WITHOUT ANY
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
* FOR A PARTICULAR PURPOSE. See the GNU Lesser General Public License for
* more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
/**
* SECTION:st-label
* @short_description: Widget for displaying text
*
* #StLabel is a simple widget for displaying text. It derives from
* #StWidget to add extra style and placement functionality over
* #ClutterText. The internal #ClutterText is publicly accessibly to allow
* applications to set further properties.
*/
#ifdef HAVE_CONFIG_H
#include "config.h"
#endif
#include <stdlib.h>
#include <string.h>
#include <glib.h>
#include <clutter/clutter.h>
#include "st-label.h"
#include "st-private.h"
#include "st-widget.h"
#include <st/st-widget-accessible.h>
enum
{
PROP_0,
PROP_CLUTTER_TEXT,
PROP_TEXT
};
#define ST_LABEL_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), ST_TYPE_LABEL, StLabelPrivate))
struct _StLabelPrivate
{
ClutterActor *label;
CoglHandle text_shadow_material;
float shadow_width;
float shadow_height;
};
G_DEFINE_TYPE (StLabel, st_label, ST_TYPE_WIDGET);
static GType st_label_accessible_get_type (void) G_GNUC_CONST;
static void
st_label_set_property (GObject *gobject,
guint prop_id,
const GValue *value,
GParamSpec *pspec)
{
StLabel *label = ST_LABEL (gobject);
switch (prop_id)
{
case PROP_TEXT:
st_label_set_text (label, g_value_get_string (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
st_label_get_property (GObject *gobject,
guint prop_id,
GValue *value,
GParamSpec *pspec)
{
StLabelPrivate *priv = ST_LABEL (gobject)->priv;
switch (prop_id)
{
case PROP_CLUTTER_TEXT:
g_value_set_object (value, priv->label);
break;
case PROP_TEXT:
g_value_set_string (value, clutter_text_get_text (CLUTTER_TEXT (priv->label)));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
}
}
static void
st_label_style_changed (StWidget *self)
{
StLabelPrivate *priv = ST_LABEL(self)->priv;
if (priv->text_shadow_material != COGL_INVALID_HANDLE)
{
cogl_handle_unref (priv->text_shadow_material);
priv->text_shadow_material = COGL_INVALID_HANDLE;
}
_st_set_text_from_style ((ClutterText *)priv->label, st_widget_get_theme_node (self));
ST_WIDGET_CLASS (st_label_parent_class)->style_changed (self);
}
static void
st_label_get_preferred_width (ClutterActor *actor,
gfloat for_height,
gfloat *min_width_p,
gfloat *natural_width_p)
{
StLabelPrivate *priv = ST_LABEL (actor)->priv;
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
st_theme_node_adjust_for_height (theme_node, &for_height);
clutter_actor_get_preferred_width (priv->label, for_height,
min_width_p,
natural_width_p);
st_theme_node_adjust_preferred_width (theme_node, min_width_p, natural_width_p);
}
static void
st_label_get_preferred_height (ClutterActor *actor,
gfloat for_width,
gfloat *min_height_p,
gfloat *natural_height_p)
{
StLabelPrivate *priv = ST_LABEL (actor)->priv;
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
st_theme_node_adjust_for_width (theme_node, &for_width);
clutter_actor_get_preferred_height (priv->label, for_width,
min_height_p,
natural_height_p);
st_theme_node_adjust_preferred_height (theme_node, min_height_p, natural_height_p);
}
static void
st_label_allocate (ClutterActor *actor,
const ClutterActorBox *box,
ClutterAllocationFlags flags)
{
StLabelPrivate *priv = ST_LABEL (actor)->priv;
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
ClutterActorClass *parent_class;
ClutterActorBox content_box;
st_theme_node_get_content_box (theme_node, box, &content_box);
parent_class = CLUTTER_ACTOR_CLASS (st_label_parent_class);
parent_class->allocate (actor, box, flags);
clutter_actor_allocate (priv->label, &content_box, flags);
}
static void
st_label_dispose (GObject *object)
{
StLabelPrivate *priv = ST_LABEL (object)->priv;
if (priv->label)
{
clutter_actor_destroy (priv->label);
priv->label = NULL;
}
if (priv->text_shadow_material != COGL_INVALID_HANDLE)
{
cogl_handle_unref (priv->text_shadow_material);
priv->text_shadow_material = COGL_INVALID_HANDLE;
}
G_OBJECT_CLASS (st_label_parent_class)->dispose (object);
}
static void
st_label_paint (ClutterActor *actor)
{
StLabelPrivate *priv = ST_LABEL (actor)->priv;
ClutterActorClass *parent_class;
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
StShadow *shadow_spec = st_theme_node_get_text_shadow (theme_node);
parent_class = CLUTTER_ACTOR_CLASS (st_label_parent_class);
parent_class->paint (actor);
if (shadow_spec)
{
ClutterActorBox allocation;
float width, height;
clutter_actor_get_allocation_box (priv->label, &allocation);
clutter_actor_box_get_size (&allocation, &width, &height);
allocation.x1 = allocation.y1 = 0;
allocation.x2 = width;
allocation.y2 = height;
if (priv->text_shadow_material == COGL_INVALID_HANDLE ||
width != priv->shadow_width ||
height != priv->shadow_height)
{
CoglHandle material;
if (priv->text_shadow_material != COGL_INVALID_HANDLE)
cogl_handle_unref (priv->text_shadow_material);
material = _st_create_shadow_material_from_actor (shadow_spec,
priv->label);
priv->shadow_width = width;
priv->shadow_height = height;
priv->text_shadow_material = material;
}
if (priv->text_shadow_material != COGL_INVALID_HANDLE)
_st_paint_shadow_with_opacity (shadow_spec,
priv->text_shadow_material,
&allocation,
clutter_actor_get_paint_opacity (priv->label));
}
clutter_actor_paint (priv->label);
}
static void
st_label_class_init (StLabelClass *klass)
{
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
StWidgetClass *widget_class = ST_WIDGET_CLASS (klass);
GParamSpec *pspec;
g_type_class_add_private (klass, sizeof (StLabelPrivate));
gobject_class->set_property = st_label_set_property;
gobject_class->get_property = st_label_get_property;
gobject_class->dispose = st_label_dispose;
actor_class->paint = st_label_paint;
actor_class->allocate = st_label_allocate;
actor_class->get_preferred_width = st_label_get_preferred_width;
actor_class->get_preferred_height = st_label_get_preferred_height;
widget_class->style_changed = st_label_style_changed;
widget_class->get_accessible_type = st_label_accessible_get_type;
pspec = g_param_spec_object ("clutter-text",
"Clutter Text",
"Internal ClutterText actor",
CLUTTER_TYPE_TEXT,
G_PARAM_READABLE);
g_object_class_install_property (gobject_class, PROP_CLUTTER_TEXT, pspec);
pspec = g_param_spec_string ("text",
"Text",
"Text of the label",
NULL, G_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_TEXT, pspec);
}
static void
st_label_init (StLabel *label)
{
StLabelPrivate *priv;
label->priv = priv = ST_LABEL_GET_PRIVATE (label);
label->priv->label = g_object_new (CLUTTER_TYPE_TEXT,
"ellipsize", PANGO_ELLIPSIZE_END,
NULL);
label->priv->text_shadow_material = COGL_INVALID_HANDLE;
label->priv->shadow_width = -1.;
label->priv->shadow_height = -1.;
clutter_actor_set_parent (priv->label, CLUTTER_ACTOR (label));
}
/**
* st_label_new:
* @text: text to set the label to
*
* Create a new #StLabel with the specified label
*
* Returns: a new #StLabel
*/
StWidget *
st_label_new (const gchar *text)
{
if (text == NULL || *text == '\0')
return g_object_new (ST_TYPE_LABEL, NULL);
else
return g_object_new (ST_TYPE_LABEL,
"text", text,
NULL);
}
/**
* st_label_get_text:
* @label: a #StLabel
*
* Get the text displayed on the label
*
* Returns: the text for the label. This must not be freed by the application
*/
const gchar *
st_label_get_text (StLabel *label)
{
g_return_val_if_fail (ST_IS_LABEL (label), NULL);
return clutter_text_get_text (CLUTTER_TEXT (label->priv->label));
}
/**
* st_label_set_text:
* @label: a #StLabel
* @text: text to set the label to
*
* Sets the text displayed on the label
*/
void
st_label_set_text (StLabel *label,
const gchar *text)
{
StLabelPrivate *priv;
ClutterText *ctext;
g_return_if_fail (ST_IS_LABEL (label));
g_return_if_fail (text != NULL);
priv = label->priv;
ctext = CLUTTER_TEXT (priv->label);
if (clutter_text_get_editable (ctext) ||
g_strcmp0 (clutter_text_get_text (ctext), text) != 0)
{
if (priv->text_shadow_material != COGL_INVALID_HANDLE)
{
cogl_handle_unref (priv->text_shadow_material);
priv->text_shadow_material = COGL_INVALID_HANDLE;
}
clutter_text_set_text (ctext, text);
g_object_notify (G_OBJECT (label), "text");
}
}
/**
* st_label_get_clutter_text:
* @label: a #StLabel
*
* Retrieve the internal #ClutterText so that extra parameters can be set
*
* Returns: (transfer none): ethe #ClutterText used by #StLabel. The label
* is owned by the #StLabel and should not be unref'ed by the application.
*/
ClutterActor*
st_label_get_clutter_text (StLabel *label)
{
g_return_val_if_fail (ST_LABEL (label), NULL);
return label->priv->label;
}
/******************************************************************************/
/*************************** ACCESSIBILITY SUPPORT ****************************/
/******************************************************************************/
#define ST_TYPE_LABEL_ACCESSIBLE st_label_accessible_get_type ()
#define ST_LABEL_ACCESSIBLE(obj) \
(G_TYPE_CHECK_INSTANCE_CAST ((obj), \
ST_TYPE_LABEL_ACCESSIBLE, StLabelAccessible))
#define ST_IS_LABEL_ACCESSIBLE(obj) \
(G_TYPE_CHECK_INSTANCE_TYPE ((obj), \
ST_TYPE_LABEL_ACCESSIBLE))
#define ST_LABEL_ACCESSIBLE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_CAST ((klass), \
ST_TYPE_LABEL_ACCESSIBLE, StLabelAccessibleClass))
#define ST_IS_LABEL_ACCESSIBLE_CLASS(klass) \
(G_TYPE_CHECK_CLASS_TYPE ((klass), \
ST_TYPE_LABEL_ACCESSIBLE))
#define ST_LABEL_ACCESSIBLE_GET_CLASS(obj) \
(G_TYPE_INSTANCE_GET_CLASS ((obj), \
ST_TYPE_LABEL_ACCESSIBLE, StLabelAccessibleClass))
typedef struct _StLabelAccessible StLabelAccessible;
typedef struct _StLabelAccessibleClass StLabelAccessibleClass;
struct _StLabelAccessible
{
StWidgetAccessible parent;
};
struct _StLabelAccessibleClass
{
StWidgetAccessibleClass parent_class;
};
static void st_label_accessible_class_init (StLabelAccessibleClass *klass);
static void st_label_accessible_init (StLabelAccessible *label);
/* AtkObject */
static void st_label_accessible_initialize (AtkObject *obj,
gpointer data);
static const gchar * st_label_accessible_get_name (AtkObject *obj);
G_DEFINE_TYPE (StLabelAccessible, st_label_accessible, ST_TYPE_WIDGET_ACCESSIBLE)
static void
st_label_accessible_class_init (StLabelAccessibleClass *klass)
{
AtkObjectClass *atk_class = ATK_OBJECT_CLASS (klass);
atk_class->initialize = st_label_accessible_initialize;
atk_class->get_name = st_label_accessible_get_name;
}
static void
st_label_accessible_init (StLabelAccessible *self)
{
/* initialization done on AtkObject->initialize */
}
static void
label_text_notify_cb (StLabel *label,
GParamSpec *pspec,
AtkObject *accessible)
{
g_object_notify (G_OBJECT (accessible), "accessible-name");
}
static void
st_label_accessible_initialize (AtkObject *obj,
gpointer data)
{
ATK_OBJECT_CLASS (st_label_accessible_parent_class)->initialize (obj, data);
g_signal_connect (data, "notify::text",
G_CALLBACK (label_text_notify_cb),
obj);
obj->role = ATK_ROLE_LABEL;
}
static const gchar *
st_label_accessible_get_name (AtkObject *obj)
{
const gchar *name = NULL;
g_return_val_if_fail (ST_IS_LABEL_ACCESSIBLE (obj), NULL);
name = ATK_OBJECT_CLASS (st_label_accessible_parent_class)->get_name (obj);
if (name == NULL)
{
ClutterActor *actor = NULL;
actor = CLUTTER_ACTOR (atk_gobject_accessible_get_object (ATK_GOBJECT_ACCESSIBLE (obj)));
if (actor == NULL) /* State is defunct */
name = NULL;
else
name = st_label_get_text (ST_LABEL (actor));
}
return name;
}