[text] Add single-line-mode to ClutterText

Allow using ClutterText as a single line text field. This is useful for
text fields that accept just a single line of contents by default, and
respond to the Enter key press to execute some action.

The :single-line-mode property enables this behaviour inside ClutterText
by clipping and scrolling the contents of the PangoLayout if they do
not fit the allocated width of the Text actor.
This commit is contained in:
Emmanuele Bassi 2009-01-07 00:25:24 +00:00
parent 8182b354b1
commit 43f82332dd
2 changed files with 172 additions and 7 deletions

View File

@ -135,6 +135,8 @@ struct _ClutterTextPrivate
*/
gint x_pos;
gint text_x;
/* the length of the text, in bytes */
gint n_bytes;
@ -175,7 +177,8 @@ enum
PROP_SELECTABLE,
PROP_ACTIVATABLE,
PROP_PASSWORD_CHAR,
PROP_MAX_LENGTH
PROP_MAX_LENGTH,
PROP_SINGLE_LINE_MODE
};
enum
@ -635,6 +638,10 @@ clutter_text_set_property (GObject *gobject,
clutter_text_set_max_length (self, g_value_get_int (value));
break;
case PROP_SINGLE_LINE_MODE:
clutter_text_set_single_line_mode (self, g_value_get_boolean (value));
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
}
@ -706,6 +713,10 @@ clutter_text_get_property (GObject *gobject,
g_value_set_int (value, priv->max_length);
break;
case PROP_SINGLE_LINE_MODE:
g_value_set_boolean (value, priv->single_line_mode);
break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
}
@ -769,8 +780,6 @@ cursor_paint (ClutterText *self)
real_opacity);
}
clutter_text_ensure_cursor_position (self);
if (priv->position == 0)
priv->cursor_pos.x -= 2;
@ -997,6 +1006,8 @@ clutter_text_key_press (ClutterActor *actor,
return FALSE;
}
#define TEXT_PADDING 2
static void
clutter_text_paint (ClutterActor *self)
{
@ -1006,6 +1017,8 @@ clutter_text_paint (ClutterActor *self)
ClutterActorBox alloc = { 0, };
CoglColor color = { 0, };
guint8 real_opacity;
gint text_x = priv->text_x;
gboolean clip_set = FALSE;
if (priv->font_desc == NULL || priv->text == NULL)
{
@ -1015,23 +1028,81 @@ clutter_text_paint (ClutterActor *self)
return;
}
cursor_paint (text);
CLUTTER_NOTE (PAINT, "painting text (text:`%s')", priv->text);
clutter_text_ensure_cursor_position (text);
clutter_actor_get_allocation_box (self, &alloc);
layout = clutter_text_create_layout (text, alloc.x2 - alloc.x1);
if (priv->single_line_mode)
{
PangoRectangle logical_rect = { 0, };
gint actor_width, text_width;
pango_layout_get_extents (layout, NULL, &logical_rect);
cogl_clip_set (0, 0,
CLUTTER_UNITS_TO_FIXED (alloc.x2 - alloc.x1),
CLUTTER_UNITS_TO_FIXED (alloc.y2 - alloc.y1));
clip_set = TRUE;
actor_width = (CLUTTER_UNITS_TO_DEVICE (alloc.x2 - alloc.x1))
- 2 * TEXT_PADDING;
text_width = logical_rect.width / PANGO_SCALE;
if (actor_width < text_width)
{
gint cursor_x = priv->cursor_pos.x;
if (priv->position == -1)
{
text_x = actor_width - text_width;
priv->cursor_pos.x += text_x + TEXT_PADDING;
}
else if (priv->position == 0)
{
text_x = 0;
}
else
{
if (text_x <= 0)
{
gint diff = -1 * text_x;
if (cursor_x < diff)
text_x += diff - cursor_x;
else if (cursor_x > (diff + actor_width))
text_x -= cursor_x - (diff - actor_width);
}
}
}
else
{
text_x = 0;
priv->cursor_pos.x += text_x + TEXT_PADDING;
}
}
else
text_x = 0;
cursor_paint (text);
real_opacity = clutter_actor_get_paint_opacity (self)
* priv->text_color.alpha
/ 255;
CLUTTER_NOTE (PAINT, "painting text (text:`%s')", priv->text);
cogl_color_set_from_4ub (&color,
priv->text_color.red,
priv->text_color.green,
priv->text_color.blue,
real_opacity);
cogl_pango_render_layout (layout, 0, 0, &color, 0);
cogl_pango_render_layout (layout, text_x, 0, &color, 0);
if (clip_set)
cogl_clip_unset ();
priv->text_x = text_x;
}
static void
@ -1801,6 +1872,26 @@ clutter_text_class_init (ClutterTextClass *klass)
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_MAX_LENGTH, pspec);
/**
* ClutterText:single-line-mode:
*
* Whether the #ClutterText actor should be in single line mode
* or not. A single line #ClutterText actor will only contain a
* single line of text, scrolling it in case its length is bigger
* than the allocated size.
*
* Setting this property will also set the #ClutterText:activatable
* property as a side-effect.
*
* Since: 1.0
*/
pspec = g_param_spec_boolean ("single-line-mode",
"Single Line Mode",
"Whether the text should be a single line",
FALSE,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_SINGLE_LINE_MODE, pspec);
/**
* ClutterText::text-changed:
* @self: the #ClutterText that emitted the signal
@ -3588,3 +3679,73 @@ clutter_text_get_chars (ClutterText *self,
return g_strndup (priv->text + start_index, end_index - start_index);
}
/**
* clutter_text_set_single_line_mode:
* @self: a #ClutterText
* @single_line: whether to enable single line mode
*
* Sets whether a #ClutterText actor should be in single line mode
* or not.
*
* A text actor in single line mode will not wrap text and will clip
* the the visible area to the predefined size. The contents of the
* text actor will scroll to display the end of the text if its length
* is bigger than the allocated width.
*
* When setting the single line mode the #ClutterText:activatable
* property is also set as a side effect. Instead of entering a new
* line character, the text actor will emit the #ClutterText::activate
* signal.
*
* Since: 1.0
*/
void
clutter_text_set_single_line_mode (ClutterText *self,
gboolean single_line)
{
ClutterTextPrivate *priv;
g_return_if_fail (CLUTTER_IS_TEXT (self));
priv = self->priv;
if (priv->single_line_mode != single_line)
{
g_object_freeze_notify (G_OBJECT (self));
priv->single_line_mode = single_line;
if (priv->single_line_mode)
{
priv->activatable = TRUE;
g_object_notify (G_OBJECT (self), "activatable");
}
clutter_text_dirty_cache (self);
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
g_object_notify (G_OBJECT (self), "single-line-mode");
g_object_thaw_notify (G_OBJECT (self));
}
}
/**
* clutter_text_get_single_line_mode:
* @self: a #ClutterText
*
* Retrieves whether the #ClutterText actor is in single line mode.
*
* Return value: %TRUE if the #ClutterText actor is in single line mode
*
* Since: 1.0
*/
gboolean
clutter_text_get_single_line_mode (ClutterText *self)
{
g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
return self->priv->single_line_mode;
}

View File

@ -187,6 +187,10 @@ gunichar clutter_text_get_password_char (ClutterText *self
void clutter_text_set_max_length (ClutterText *self,
gint max);
gint clutter_text_get_max_length (ClutterText *self);
void clutter_text_set_single_line_mode (ClutterText *self,
gboolean single_line);
gboolean clutter_text_get_single_line_mode (ClutterText *self);
gboolean clutter_text_activate (ClutterText *self);
G_END_DECLS