Add text-visibility accessors for ClutterText

A ClutterText can be put in "password mode" by setting the
text as "invisible": every character inside the Text actor's
contents will be replaced when building the Pango layout with
a specific Unicode character.

The Unicode character is set to '*' by default, but the user
can be changed using the provided API.
This commit is contained in:
Emmanuele Bassi 2008-12-11 11:40:55 +00:00 committed by Emmanuele Bassi
parent 64af7bafe3
commit d5df1bebcf
2 changed files with 494 additions and 179 deletions

View File

@ -3,9 +3,10 @@
* *
* An OpenGL based 'interactive canvas' library. * An OpenGL based 'interactive canvas' library.
* *
* Copyright (C) 2006-2008 OpenedHand * Copyright (C) 2008 Intel Corporation.
* *
* Authored By Øyvind Kolås <pippin@o-hand.com> * Authored By: Øyvind Kolås <pippin@o-hand.com>
* Emmanuele Bassi <ebassi@linux.intel.com>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -18,9 +19,7 @@
* Lesser General Public License for more details. * Lesser General Public License for more details.
* *
* You should have received a copy of the GNU Lesser General Public * You should have received a copy of the GNU Lesser General Public
* License along with this library; if not, write to the * License along with this library. If not, see <http://www.gnu.org/licenses/>.
* Free Software Foundation, Inc., 59 Temple Place - Suite 330,
* Boston, MA 02111-1307, USA.
*/ */
/* TODO: undo/redo hooks? /* TODO: undo/redo hooks?
@ -112,6 +111,7 @@ struct _ClutterTextPrivate
guint selectable : 1; guint selectable : 1;
guint in_select_drag : 1; guint in_select_drag : 1;
guint cursor_color_set : 1; guint cursor_color_set : 1;
guint text_visible : 1;
/* current cursor position */ /* current cursor position */
gint position; gint position;
@ -124,17 +124,25 @@ struct _ClutterTextPrivate
*/ */
gint x_pos; gint x_pos;
/* the length of the text, in bytes */
gint n_bytes;
/* the length of the text, in characters */
gint n_chars;
/* Where to draw the cursor */ /* Where to draw the cursor */
ClutterGeometry cursor_pos; ClutterGeometry cursor_pos;
ClutterColor cursor_color; ClutterColor cursor_color;
ClutterColor selection_color;
GList *mappings; GList *mappings;
GList *commands; /* each instance has it's own set of commands GList *commands; /* each instance has it's own set of commands
so that actor specific actions can be added so that actor specific actions can be added
to single actor classes to single actor classes
*/ */
gint max_length;
gunichar priv_char;
}; };
enum enum
@ -158,7 +166,9 @@ enum
PROP_CURSOR_COLOR_SET, PROP_CURSOR_COLOR_SET,
PROP_EDITABLE, PROP_EDITABLE,
PROP_SELECTABLE, PROP_SELECTABLE,
PROP_ACTIVATABLE PROP_ACTIVATABLE,
PROP_TEXT_VISIBLE,
PROP_INVISIBLE_CHAR
}; };
enum enum
@ -258,7 +268,36 @@ clutter_text_create_layout_no_cache (ClutterText *text,
if (priv->text) if (priv->text)
{ {
if (!priv->use_markup) if (!priv->use_markup)
pango_layout_set_text (layout, priv->text, -1); {
if (priv->text_visible)
pango_layout_set_text (layout, priv->text, priv->n_bytes);
else
{
GString *str = g_string_sized_new (priv->n_bytes);
gunichar invisible_char;
gchar buf[7];
gint char_len, i;
if (priv->priv_char != 0)
invisible_char = priv->priv_char;
else
invisible_char = ' ';
/* we need to convert the string built of invisible
* characters into UTF-8 for it to be fed to the Pango
* layout
*/
memset (buf, 0, sizeof (buf));
char_len = g_unichar_to_utf8 (invisible_char, buf);
for (i = 0; i < priv->n_chars; i++)
g_string_append_len (str, buf, char_len);
pango_layout_set_text (layout, str->str, str->len);
g_string_free (str, TRUE);
}
}
else else
pango_layout_set_markup (layout, priv->text, -1); pango_layout_set_markup (layout, priv->text, -1);
} }
@ -423,20 +462,16 @@ clutter_text_position_to_coords (ClutterText *ttext,
priv = ttext->priv; priv = ttext->priv;
if (position == -1) if (position == -1)
{
index_ = strlen (text); index_ = strlen (text);
}
else else
{
index_ = offset_to_bytes (text, position); index_ = offset_to_bytes (text, position);
}
if (index_ > strlen (text)) if (index_ > strlen (text))
index_ = strlen (text); index_ = strlen (text);
pango_layout_get_cursor_pos ( pango_layout_get_cursor_pos (clutter_text_get_layout (ttext),
clutter_text_get_layout (ttext), index_,
index_, &rect, NULL); &rect, NULL);
if (x) if (x)
*x = rect.x / PANGO_SCALE; *x = rect.x / PANGO_SCALE;
@ -580,9 +615,16 @@ clutter_text_set_property (GObject *gobject,
clutter_text_set_selectable (self, g_value_get_boolean (value)); clutter_text_set_selectable (self, g_value_get_boolean (value));
break; break;
case PROP_TEXT_VISIBLE:
clutter_text_set_text_visible (self, g_value_get_boolean (value));
break;
case PROP_INVISIBLE_CHAR:
clutter_text_set_invisible_char (self, g_value_get_uint (value));
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
} }
} }
@ -636,9 +678,16 @@ clutter_text_get_property (GObject *gobject,
g_value_set_boolean (value, priv->activatable); g_value_set_boolean (value, priv->activatable);
break; break;
case PROP_TEXT_VISIBLE:
g_value_set_boolean (value, priv->text_visible);
break;
case PROP_INVISIBLE_CHAR:
g_value_set_uint (value, priv->priv_char);
break;
default: default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec); G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
break;
} }
} }
@ -674,12 +723,11 @@ clutter_text_finalize (GObject *gobject)
} }
static void static void
cursor_paint (ClutterText *ttext) cursor_paint (ClutterText *self)
{ {
ClutterTextPrivate *priv = ttext->priv; ClutterTextPrivate *priv = self->priv;
if (priv->editable && if (priv->editable && priv->cursor_visible)
priv->cursor_visible)
{ {
if (priv->cursor_color_set) if (priv->cursor_color_set)
{ {
@ -690,15 +738,13 @@ cursor_paint (ClutterText *ttext)
} }
else else
{ {
ClutterColor color; cogl_set_source_color4ub (priv->text_color.red,
clutter_text_get_color (ttext, &color); priv->text_color.green,
cogl_set_source_color4ub (color.red, priv->text_color.blue,
color.green, priv->text_color.alpha);
color.blue,
color.alpha);
} }
clutter_text_ensure_cursor_position (ttext); clutter_text_ensure_cursor_position (self);
if (priv->position == 0) if (priv->position == 0)
priv->cursor_pos.x -= 2; priv->cursor_pos.x -= 2;
@ -712,10 +758,12 @@ cursor_paint (ClutterText *ttext)
} }
else else
{ {
PangoLayout *layout = clutter_text_get_layout (self);
const gchar *utf8 = priv->text;
gint lines; gint lines;
gint start_index; gint start_index;
gint end_index; gint end_index;
const gchar *utf8 = clutter_text_get_text (ttext); gint line_no;
start_index = offset_to_bytes (utf8, priv->position); start_index = offset_to_bytes (utf8, priv->position);
end_index = offset_to_bytes (utf8, priv->selection_bound); end_index = offset_to_bytes (utf8, priv->selection_bound);
@ -727,9 +775,8 @@ cursor_paint (ClutterText *ttext)
end_index = temp; end_index = temp;
} }
PangoLayout *layout = clutter_text_get_layout (ttext);
lines = pango_layout_get_line_count (layout); lines = pango_layout_get_line_count (layout);
gint line_no;
for (line_no = 0; line_no < lines; line_no++) for (line_no = 0; line_no < lines; line_no++)
{ {
PangoLayoutLine *line; PangoLayoutLine *line;
@ -746,18 +793,21 @@ cursor_paint (ClutterText *ttext)
if (maxindex < start_index) if (maxindex < start_index)
continue; continue;
pango_layout_line_get_x_ranges (line, start_index, end_index, &ranges, &n_ranges); pango_layout_line_get_x_ranges (line, start_index, end_index,
&ranges,
&n_ranges);
pango_layout_line_x_to_index (line, 0, &index, NULL); pango_layout_line_x_to_index (line, 0, &index, NULL);
clutter_text_position_to_coords (ttext, bytes_to_offset (utf8, index), NULL, &y, &height); clutter_text_position_to_coords (self,
bytes_to_offset (utf8, index),
NULL, &y, &height);
for (i = 0; i < n_ranges; i++) for (i = 0; i < n_ranges; i++)
{
cogl_rectangle (ranges[i * 2 + 0] / PANGO_SCALE, cogl_rectangle (ranges[i * 2 + 0] / PANGO_SCALE,
y - height, y - height,
(ranges[i*2+1]-ranges[i*2+0])/PANGO_SCALE, ((ranges[i * 2 + 1] - ranges[i * 2 + 0])
/ PANGO_SCALE),
height); height);
}
g_free (ranges); g_free (ranges);
@ -772,32 +822,30 @@ static gboolean
clutter_text_button_press (ClutterActor *actor, clutter_text_button_press (ClutterActor *actor,
ClutterButtonEvent *bev) ClutterButtonEvent *bev)
{ {
ClutterText *ttext = CLUTTER_TEXT (actor); ClutterText *self = CLUTTER_TEXT (actor);
ClutterTextPrivate *priv = ttext->priv; ClutterTextPrivate *priv = self->priv;
ClutterUnit x, y; ClutterUnit x, y;
gint index_; gint index_;
const gchar *text;
text = clutter_text_get_text (ttext);
x = CLUTTER_UNITS_FROM_INT (bev->x); x = CLUTTER_UNITS_FROM_INT (bev->x);
y = CLUTTER_UNITS_FROM_INT (bev->y); y = CLUTTER_UNITS_FROM_INT (bev->y);
clutter_actor_transform_stage_point (actor, x, y, &x, &y); clutter_actor_transform_stage_point (actor, x, y, &x, &y);
index_ = clutter_text_coords_to_position (ttext, CLUTTER_UNITS_TO_INT (x), index_ = clutter_text_coords_to_position (self,
CLUTTER_UNITS_TO_INT (x),
CLUTTER_UNITS_TO_INT (y)); CLUTTER_UNITS_TO_INT (y));
clutter_text_set_cursor_position (ttext, bytes_to_offset (text, index_)); clutter_text_set_cursor_position (self, bytes_to_offset (priv->text, index_));
clutter_text_set_selection_bound (ttext, bytes_to_offset (text, index_) clutter_text_set_selection_bound (self, bytes_to_offset (priv->text, index_));
);
/* grab the pointer */
priv->in_select_drag = TRUE;
clutter_grab_pointer (actor);
/* we'll steal keyfocus if we do not have it */ /* we'll steal keyfocus if we do not have it */
clutter_actor_grab_key_focus (actor); clutter_actor_grab_key_focus (actor);
priv->in_select_drag = TRUE;
clutter_grab_pointer (actor);
return TRUE; return TRUE;
} }
@ -842,12 +890,15 @@ clutter_text_button_release (ClutterActor *actor,
{ {
ClutterText *ttext = CLUTTER_TEXT (actor); ClutterText *ttext = CLUTTER_TEXT (actor);
ClutterTextPrivate *priv = ttext->priv; ClutterTextPrivate *priv = ttext->priv;
if (priv->in_select_drag) if (priv->in_select_drag)
{ {
clutter_ungrab_pointer (); clutter_ungrab_pointer ();
priv->in_select_drag = FALSE; priv->in_select_drag = FALSE;
return TRUE; return TRUE;
} }
return FALSE; return FALSE;
} }
@ -898,7 +949,6 @@ clutter_text_key_press (ClutterActor *actor,
return FALSE; return FALSE;
} }
static void static void
clutter_text_paint (ClutterActor *self) clutter_text_paint (ClutterActor *self)
{ {
@ -1006,8 +1056,9 @@ clutter_text_allocate (ClutterActor *self,
ClutterText *text = CLUTTER_TEXT (self); ClutterText *text = CLUTTER_TEXT (self);
ClutterActorClass *parent_class; ClutterActorClass *parent_class;
/* Ensure that there is a cached layout with the right width so that /* Ensure that there is a cached layout with the right width so
we don't need to create the text during the paint run */ * that we don't need to create the text during the paint run
*/
clutter_text_create_layout (text, box->x2 - box->x1); clutter_text_create_layout (text, box->x2 - box->x1);
parent_class = CLUTTER_ACTOR_CLASS (clutter_text_parent_class); parent_class = CLUTTER_ACTOR_CLASS (clutter_text_parent_class);
@ -1023,6 +1074,8 @@ clutter_text_class_init (ClutterTextClass *klass)
_context = _clutter_context_create_pango_context (CLUTTER_CONTEXT ()); _context = _clutter_context_create_pango_context (CLUTTER_CONTEXT ());
g_type_class_add_private (klass, sizeof (ClutterTextPrivate));
gobject_class->set_property = clutter_text_set_property; gobject_class->set_property = clutter_text_set_property;
gobject_class->get_property = clutter_text_get_property; gobject_class->get_property = clutter_text_get_property;
gobject_class->dispose = clutter_text_dispose; gobject_class->dispose = clutter_text_dispose;
@ -1043,7 +1096,7 @@ clutter_text_class_init (ClutterTextClass *klass)
* The font to be used by the #ClutterText, as a string * The font to be used by the #ClutterText, as a string
* that can be parsed by pango_font_description_from_string(). * that can be parsed by pango_font_description_from_string().
* *
* Since: 0.2 * Since: 1.0
*/ */
pspec = g_param_spec_string ("font-name", pspec = g_param_spec_string ("font-name",
"Font Name", "Font Name",
@ -1110,22 +1163,19 @@ clutter_text_class_init (ClutterTextClass *klass)
* if both cursor-visible is set and editable is set at the same time, * if both cursor-visible is set and editable is set at the same time,
* the value defaults to TRUE. * the value defaults to TRUE.
*/ */
g_object_class_install_property pspec = g_param_spec_boolean ("cursor-visible",
(gobject_class, PROP_CURSOR_VISIBLE,
g_param_spec_boolean ("cursor-visible",
"Cursor Visible", "Cursor Visible",
"Whether the input cursor is visible", "Whether the input cursor is visible",
TRUE, TRUE,
G_PARAM_READWRITE)); CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_CURSOR_VISIBLE, pspec);
pspec = clutter_param_spec_color ("cursor-color",
g_object_class_install_property
(gobject_class, PROP_CURSOR_COLOR,
g_param_spec_boxed ("cursor-color",
"Cursor Colour", "Cursor Colour",
"Cursor Colour", "Cursor Colour",
CLUTTER_TYPE_COLOR, &default_cursor_color,
G_PARAM_READWRITE)); CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_CURSOR_COLOR, pspec);
/** /**
* ClutterText:position: * ClutterText:position:
@ -1137,7 +1187,7 @@ clutter_text_class_init (ClutterTextClass *klass)
"The cursor position", "The cursor position",
-1, G_MAXINT, -1, G_MAXINT,
-1, -1,
G_PARAM_READWRITE); CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_POSITION, pspec); g_object_class_install_property (gobject_class, PROP_POSITION, pspec);
/** /**
@ -1147,10 +1197,11 @@ clutter_text_class_init (ClutterTextClass *klass)
*/ */
pspec = g_param_spec_int ("selection-bound", pspec = g_param_spec_int ("selection-bound",
"Selection-bound", "Selection-bound",
"The cursor position of the other end of the selection.", "The cursor position of the other end "
"of the selection",
-1, G_MAXINT, -1, G_MAXINT,
-1, -1,
G_PARAM_READWRITE); CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_SELECTION_BOUND, pspec); g_object_class_install_property (gobject_class, PROP_SELECTION_BOUND, pspec);
pspec = g_param_spec_boxed ("attributes", pspec = g_param_spec_boxed ("attributes",
@ -1250,11 +1301,30 @@ clutter_text_class_init (ClutterTextClass *klass)
CLUTTER_PARAM_READWRITE); CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_JUSTIFY, pspec); g_object_class_install_property (gobject_class, PROP_JUSTIFY, pspec);
pspec = g_param_spec_boolean ("text-visible",
"Text Visible",
"Whether the text should be visible "
"or subsituted with an invisible "
"Unicode character",
FALSE,
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_TEXT_VISIBLE, pspec);
pspec = g_param_spec_unichar ("invisible-char",
"Invisible Character",
"The Unicode character used when the "
"text is set as not visible",
'*',
CLUTTER_PARAM_READWRITE);
g_object_class_install_property (gobject_class, PROP_INVISIBLE_CHAR, pspec);
/** /**
* ClutterText::text-changed: * ClutterText::text-changed:
* @actor: the actor which received the event * @actor: the actor which received the event
* *
* The ::text-changed signal is emitted after @entry's text changes * The ::text-changed signal is emitted after @actor's text changes
*
* Since: 1.0
*/ */
text_signals[TEXT_CHANGED] = text_signals[TEXT_CHANGED] =
g_signal_new ("text-changed", g_signal_new ("text-changed",
@ -1279,7 +1349,7 @@ clutter_text_class_init (ClutterTextClass *klass)
* ClutterText::activate * ClutterText::activate
* @actor: the actor which received the event * @actor: the actor which received the event
* *
* The ::activate signal is emitted each time the entry is 'activated' * The ::activate signal is emitted each time the actor is 'activated'
* by the user, normally by pressing the 'Enter' key. * by the user, normally by pressing the 'Enter' key.
* *
* Since: 1.0 * Since: 1.0
@ -1292,8 +1362,6 @@ clutter_text_class_init (ClutterTextClass *klass)
NULL, NULL, NULL, NULL,
g_cclosure_marshal_VOID__VOID, g_cclosure_marshal_VOID__VOID,
G_TYPE_NONE, 0); G_TYPE_NONE, 0);
g_type_class_add_private (klass, sizeof (ClutterTextPrivate));
} }
static void static void
@ -1326,9 +1394,13 @@ clutter_text_init (ClutterText *self)
priv->x_pos = -1; priv->x_pos = -1;
priv->cursor_visible = TRUE; priv->cursor_visible = TRUE;
priv->editable = FALSE; priv->editable = FALSE;
priv->selectable = TRUE;
priv->cursor_color_set = FALSE; priv->cursor_color_set = FALSE;
priv->text_visible = TRUE;
priv->priv_char = '*';
init_commands (self); /* FIXME: free */ init_commands (self); /* FIXME: free */
init_mappings (self); /* FIXME: free */ init_mappings (self); /* FIXME: free */
} }
@ -1355,98 +1427,133 @@ clutter_text_new_with_text (const gchar *font_name,
NULL); NULL);
} }
void void
clutter_text_set_editable (ClutterText *text, clutter_text_set_editable (ClutterText *self,
gboolean editable) gboolean editable)
{ {
ClutterTextPrivate *priv; ClutterTextPrivate *priv;
priv = text->priv; g_return_if_fail (CLUTTER_IS_TEXT (self));
priv = self->priv;
if (priv->editable != editable)
{
priv->editable = editable; priv->editable = editable;
clutter_actor_queue_redraw (CLUTTER_ACTOR (text));
if (CLUTTER_ACTOR_IS_VISIBLE (self))
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
g_object_notify (G_OBJECT (self), "editable");
}
} }
gboolean gboolean
clutter_text_get_editable (ClutterText *text) clutter_text_get_editable (ClutterText *self)
{ {
ClutterTextPrivate *priv; g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
priv = text->priv;
return priv->editable; return self->priv->editable;
} }
void void
clutter_text_set_selectable (ClutterText *text, clutter_text_set_selectable (ClutterText *self,
gboolean selectable) gboolean selectable)
{ {
ClutterTextPrivate *priv; ClutterTextPrivate *priv;
priv = text->priv; g_return_if_fail (CLUTTER_IS_TEXT (self));
priv = self->priv;
if (priv->selectable != selectable)
{
priv->selectable = selectable; priv->selectable = selectable;
clutter_actor_queue_redraw (CLUTTER_ACTOR (text));
if (CLUTTER_ACTOR_IS_VISIBLE (self))
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
g_object_notify (G_OBJECT (self), "selectable");
}
} }
gboolean gboolean
clutter_text_get_selectable (ClutterText *text) clutter_text_get_selectable (ClutterText *self)
{ {
ClutterTextPrivate *priv; g_return_val_if_fail (CLUTTER_IS_TEXT (self), TRUE);
priv = text->priv;
return priv->selectable; return self->priv->selectable;
} }
void void
clutter_text_set_activatable (ClutterText *text, clutter_text_set_activatable (ClutterText *self,
gboolean activatable) gboolean activatable)
{ {
ClutterTextPrivate *priv; ClutterTextPrivate *priv;
priv = text->priv; g_return_if_fail (CLUTTER_IS_TEXT (self));
priv = self->priv;
if (priv->activatable != activatable)
{
priv->activatable = activatable; priv->activatable = activatable;
clutter_actor_queue_redraw (CLUTTER_ACTOR (text));
if (CLUTTER_ACTOR_IS_VISIBLE (self))
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
g_object_notify (G_OBJECT (self), "activatable");
}
} }
gboolean gboolean
clutter_text_get_activatable (ClutterText *text) clutter_text_get_activatable (ClutterText *self)
{ {
ClutterTextPrivate *priv; g_return_val_if_fail (CLUTTER_IS_TEXT (self), TRUE);
priv = text->priv;
return priv->activatable; return self->priv->activatable;
} }
void void
clutter_text_set_cursor_visible (ClutterText *text, clutter_text_set_cursor_visible (ClutterText *self,
gboolean cursor_visible) gboolean cursor_visible)
{ {
ClutterTextPrivate *priv; ClutterTextPrivate *priv;
priv = text->priv; g_return_if_fail (CLUTTER_IS_TEXT (self));
priv = self->priv;
if (priv->cursor_visible != cursor_visible)
{
priv->cursor_visible = cursor_visible; priv->cursor_visible = cursor_visible;
clutter_actor_queue_redraw (CLUTTER_ACTOR (text));
if (CLUTTER_ACTOR_IS_VISIBLE (self))
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
g_object_notify (G_OBJECT (self), "cursor-visible");
}
} }
gboolean gboolean
clutter_text_get_cursor_visible (ClutterText *text) clutter_text_get_cursor_visible (ClutterText *self)
{ {
ClutterTextPrivate *priv; g_return_val_if_fail (CLUTTER_IS_TEXT (self), TRUE);
priv = text->priv;
return priv->cursor_visible; return self->priv->cursor_visible;
} }
void void
clutter_text_set_cursor_color (ClutterText *text, clutter_text_set_cursor_color (ClutterText *self,
const ClutterColor *color) const ClutterColor *color)
{ {
ClutterTextPrivate *priv; ClutterTextPrivate *priv;
g_return_if_fail (CLUTTER_IS_TEXT (text)); g_return_if_fail (CLUTTER_IS_TEXT (self));
g_return_if_fail (color != NULL);
priv = text->priv; priv = self->priv;
g_object_ref (text);
if (color) if (color)
{ {
@ -1454,22 +1561,26 @@ clutter_text_set_cursor_color (ClutterText *text,
priv->cursor_color_set = TRUE; priv->cursor_color_set = TRUE;
} }
else else
{
priv->cursor_color_set = FALSE; priv->cursor_color_set = FALSE;
}
if (CLUTTER_ACTOR_IS_VISIBLE (self))
clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
g_object_notify (G_OBJECT (self), "cursor-color");
g_object_notify (G_OBJECT (self), "cursor-color-set");
} }
void void
clutter_text_get_cursor_color (ClutterText *text, clutter_text_get_cursor_color (ClutterText *self,
ClutterColor *color) ClutterColor *color)
{ {
ClutterTextPrivate *priv; ClutterTextPrivate *priv;
g_return_if_fail (CLUTTER_IS_TEXT (text)); g_return_if_fail (CLUTTER_IS_TEXT (self));
g_return_if_fail (color != NULL); g_return_if_fail (color != NULL);
priv = text->priv; priv = self->priv;
*color = priv->cursor_color; *color = priv->cursor_color;
} }
@ -1478,7 +1589,6 @@ gchar *
clutter_text_get_selection (ClutterText *text) clutter_text_get_selection (ClutterText *text)
{ {
ClutterTextPrivate *priv; ClutterTextPrivate *priv;
const gchar *utf8 = clutter_text_get_text (text); const gchar *utf8 = clutter_text_get_text (text);
gchar *str; gchar *str;
gint len; gint len;
@ -1635,12 +1745,10 @@ clutter_text_action_move_up (ClutterText *ttext,
text = clutter_text_get_text (ttext); text = clutter_text_get_text (ttext);
pango_layout_index_to_line_x ( pango_layout_index_to_line_x (clutter_text_get_layout (ttext),
clutter_text_get_layout (ttext),
offset_to_bytes (text, priv->position), offset_to_bytes (text, priv->position),
0, 0,
&line_no, &line_no, &x);
&x);
if (priv->x_pos != -1) if (priv->x_pos != -1)
x = priv->x_pos; x = priv->x_pos;
@ -1711,8 +1819,10 @@ clutter_text_action_move_down (ClutterText *ttext,
{ {
gint pos = bytes_to_offset (text, index_); gint pos = bytes_to_offset (text, index_);
clutter_text_set_cursor_position (ttext, pos); clutter_text_set_cursor_position (ttext, pos);
} }
if (!(priv->selectable && event && if (!(priv->selectable && event &&
(event->key.modifier_state & CLUTTER_SHIFT_MASK))) (event->key.modifier_state & CLUTTER_SHIFT_MASK)))
clutter_text_clear_selection (ttext); clutter_text_clear_selection (ttext);
@ -1992,21 +2102,54 @@ clutter_text_get_text (ClutterText *text)
} }
void void
clutter_text_set_text (ClutterText *text, clutter_text_set_text (ClutterText *self,
const gchar *str) const gchar *text)
{ {
ClutterTextPrivate *priv; ClutterTextPrivate *priv;
g_return_if_fail (CLUTTER_IS_TEXT (text)); g_return_if_fail (CLUTTER_IS_TEXT (self));
priv = text->priv; priv = self->priv;
if (priv->max_length > 0)
{
gint len = g_utf8_strlen (text, -1);
if (len < priv->max_length)
{
g_free (priv->text);
priv->text = g_strdup (text);
priv->n_bytes = priv->text ? strlen (priv->text) : 0;
priv->n_chars = len;
}
else
{
gchar *n = g_malloc0 (priv->max_length + 1);
g_free (priv->text); g_free (priv->text);
priv->text = g_strdup (str);
clutter_text_dirty_cache (text); g_utf8_strncpy (n, text, priv->max_length);
clutter_actor_queue_relayout (CLUTTER_ACTOR (text)); priv->text = n;
priv->n_bytes = strlen (n);
priv->n_chars = priv->max_length;
}
}
else
{
g_free (priv->text);
priv->text = g_strdup (text);
priv->n_bytes = priv->text ? strlen (priv->text) : 0;
priv->n_chars = priv->text ? g_utf8_strlen (priv->text, -1) : 0;
}
clutter_text_dirty_cache (self);
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
g_signal_emit (self, text_signals[TEXT_CHANGED], 0);
g_object_notify (G_OBJECT (text), "text"); g_object_notify (G_OBJECT (text), "text");
} }
@ -2464,6 +2607,177 @@ clutter_text_set_cursor_position (ClutterText *self,
clutter_actor_queue_redraw (CLUTTER_ACTOR (self)); clutter_actor_queue_redraw (CLUTTER_ACTOR (self));
} }
/**
* clutter_text_set_text_visible:
* @self: a #ClutterText
* @visible: %TRUE if the contents of the actor are displayed as plain text.
*
* Sets whether the contents of the text actor are visible or not. When
* visibility is set to %FALSE, characters are displayed as the invisible
* char, and will also appear that way when the text in the text actor is
* copied elsewhere.
*
* The default invisible char is the asterisk '*', but it can be changed with
* clutter_text_set_invisible_char().
*
* Since: 1.0
*/
void
clutter_text_set_text_visible (ClutterText *self,
gboolean visible)
{
ClutterTextPrivate *priv;
g_return_if_fail (CLUTTER_IS_TEXT (self));
priv = self->priv;
if (priv->text_visible != visible)
{
priv->text_visible = visible;
clutter_text_dirty_cache (self);
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
g_object_notify (G_OBJECT (self), "text-visible");
}
}
/**
* clutter_text_get_text_visible:
* @self: a #ClutterText
*
* Retrieves the actor's text visibility.
*
* Return value: %TRUE if the contents of the actor are displayed as plaintext
*
* Since: 1.0
*/
gboolean
clutter_text_get_text_visible (ClutterText *self)
{
g_return_val_if_fail (CLUTTER_IS_TEXT (self), TRUE);
return self->priv->text_visible;
}
/**
* clutter_text_set_invisible_char:
* @self: a #ClutterText
* @wc: a Unicode character
*
* Sets the character to use in place of the actual text when
* clutter_text_set_text_visible() has been called to set text visibility
* to %FALSE. i.e. this is the character used in "password mode" to show the
* user how many characters have been typed. The default invisible char is an
* asterisk ('*'). If you set the invisible char to 0, then the user will get
* no feedback at all: there will be no text on the screen as they type.
*
* Since: 1.0
*/
void
clutter_text_set_invisible_char (ClutterText *self,
gunichar wc)
{
ClutterTextPrivate *priv;
g_return_if_fail (CLUTTER_IS_TEXT (self));
priv = self->priv;
priv->priv_char = wc;
if (priv->text_visible)
{
clutter_text_dirty_cache (self);
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
}
g_object_notify (G_OBJECT (self), "invisible-char");
}
/**
* clutter_text_get_invisible_char:
* @self: a #ClutterText
*
* Returns the character to use in place of the actual text when
* the #ClutterText:text-visibility property is set to %FALSE.
*
* Return value: a Unicode character
*
* Since: 1.0
*/
gunichar
clutter_text_get_invisible_char (ClutterText *self)
{
g_return_val_if_fail (CLUTTER_IS_TEXT (self), '*');
return self->priv->priv_char;
}
#if 0
/**
* clutter_text_set_max_length:
* @self: a #ClutterText
* @max: the maximum number of characters allowed in the text actor; 0
* to disable or -1 to set the length of the current string
*
* Sets the maximum allowed length of the contents of the actor. If the
* current contents are longer than the given length, then they will be
* truncated to fit.
*
* Since: 0.4
*/
void
clutter_text_set_max_length (ClutterText *self,
gint max)
{
ClutterTextPrivate *priv;
gchar *new = NULL;
g_return_if_fail (CLUTTER_IS_TEXT (entry));
priv = self->priv;
if (priv->max_length != max)
{
g_object_ref (entry);
if (max < 0)
max = g_utf8_strlen (priv->text, -1);
priv->max_length = max;
new = g_strdup (priv->text);
clutter_text_set_text (entry, new);
g_free (new);
g_object_notify (G_OBJECT (entry), "max-length");
g_object_unref (entry);
}
}
/**
* clutter_text_get_max_length:
* @entry: a #ClutterText
*
* Gets the maximum length of text that can be set into @entry.
* See clutter_text_set_max_length().
*
* Return value: the maximum number of characters.
*
* Since: 0.4
*/
gint
clutter_text_get_max_length (ClutterText *self)
{
g_return_val_if_fail (CLUTTER_IS_TEXT (entry), -1);
return self->priv->max_length;
}
#endif
void void
clutter_text_insert_unichar (ClutterText *self, clutter_text_insert_unichar (ClutterText *self,
gunichar wc) gunichar wc)
@ -2499,8 +2813,6 @@ clutter_text_insert_unichar (ClutterText *self,
g_string_free (new, TRUE); g_string_free (new, TRUE);
g_object_unref (self); g_object_unref (self);
g_signal_emit (G_OBJECT (self), text_signals[TEXT_CHANGED], 0);
} }
void void
@ -2531,13 +2843,11 @@ clutter_text_delete_text (ClutterText *ttext,
} }
new = g_string_new (text); new = g_string_new (text);
new = g_string_erase (new, start_bytes, end_bytes - start_bytes); new = g_string_erase (new, start_bytes, end_bytes - start_bytes);
clutter_text_set_text (ttext, new->str); clutter_text_set_text (ttext, new->str);
g_string_free (new, TRUE); g_string_free (new, TRUE);
g_signal_emit (G_OBJECT (ttext), text_signals[TEXT_CHANGED], 0);
} }

View File

@ -3,9 +3,10 @@
* *
* An OpenGL based 'interactive canvas' library. * An OpenGL based 'interactive canvas' library.
* *
* Copyright (C) 2006-2008 OpenedHand * Copyright (C) 2008 Intel Corporation.
* *
* Authored By Øyvind Kolås <pippin@o-hand.com> * Authored By: Øyvind Kolås <pippin@o-hand.com>
* Emmanuele Bassi <ebassi@linux.intel.com>
* *
* This library is free software; you can redistribute it and/or * This library is free software; you can redistribute it and/or
* modify it under the terms of the GNU Lesser General Public * modify it under the terms of the GNU Lesser General Public
@ -28,8 +29,8 @@
#ifndef __CLUTTER_TEXT_H__ #ifndef __CLUTTER_TEXT_H__
#define __CLUTTER_TEXT_H__ #define __CLUTTER_TEXT_H__
#include <clutter/clutter-label.h> #include <clutter/clutter-actor.h>
#include <clutter/clutter-types.h> #include <pango/pango.h>
G_BEGIN_DECLS G_BEGIN_DECLS
@ -54,13 +55,17 @@ struct _ClutterText
struct _ClutterTextClass struct _ClutterTextClass
{ {
/*< private >*/
ClutterActorClass parent_class; ClutterActorClass parent_class;
/*< public >*/
void (* text_changed) (ClutterText *self); void (* text_changed) (ClutterText *self);
void (* activate) (ClutterText *self); void (* activate) (ClutterText *self);
void (* cursor_event) (ClutterText *self, void (* cursor_event) (ClutterText *self,
ClutterGeometry *geometry); ClutterGeometry *geometry);
/*< private >*/
/* padding for future expansion */
void (* _clutter_reserved1) (void); void (* _clutter_reserved1) (void);
void (* _clutter_reserved2) (void); void (* _clutter_reserved2) (void);
void (* _clutter_reserved3) (void); void (* _clutter_reserved3) (void);
@ -151,9 +156,9 @@ void clutter_text_set_selection_bound (ClutterText *self
gint selection_bound); gint selection_bound);
gint clutter_text_get_selection_bound (ClutterText *self); gint clutter_text_get_selection_bound (ClutterText *self);
gchar * clutter_text_get_selection (ClutterText *self); gchar * clutter_text_get_selection (ClutterText *self);
void clutter_text_set_visibility (ClutterText *self, void clutter_text_set_text_visible (ClutterText *self,
gboolean visible); gboolean visible);
gboolean clutter_text_get_visibility (ClutterText *self); gboolean clutter_text_get_text_visible (ClutterText *self);
void clutter_text_set_invisible_char (ClutterText *self, void clutter_text_set_invisible_char (ClutterText *self,
gunichar wc); gunichar wc);
gunichar clutter_text_get_invisible_char (ClutterText *self); gunichar clutter_text_get_invisible_char (ClutterText *self);