diff --git a/ChangeLog b/ChangeLog index 982933977..b9c3cb607 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,3 +1,31 @@ +2007-05-31 Neil J Patel + + * clutter/Makefile.am: + * clutter/clutter-entry.c: (clutter_entry_set_property), + (clutter_entry_get_property), (clutter_entry_ensure_layout), + (clutter_entry_clear_layout), + (clutter_entry_ensure_cursor_position), (clutter_entry_paint), + (clutter_entry_request_coords), (clutter_entry_dispose), + (clutter_entry_finalize), (clutter_entry_class_init), + (clutter_entry_init), (clutter_entry_new_with_text), + (clutter_entry_new_full), (clutter_entry_new), + (clutter_entry_get_text), (clutter_entry_set_text), + (clutter_entry_get_font_name), (clutter_entry_set_font_name), + (clutter_entry_set_color), (clutter_entry_get_color), + (clutter_entry_get_layout), (clutter_entry_set_alignment), + (clutter_entry_get_alignment), (clutter_entry_set_position), + (clutter_entry_get_position), (clutter_entry_add), + (clutter_entry_remove), (clutter_entry_insert_text), + (clutter_entry_delete_text), (clutter_entry_set_visible_cursor), + (clutter_entry_get_visible_cursor): + * clutter/clutter-entry.h: + * clutter/clutter.h: + * examples/Makefile.am: + Initial import of ClutterEntry actor. + + * examples/test-entry.c: (on_key_release_cb), (main): + A basic test for ClutterEntry + 2007-05-31 Tomas Frydrych * clutter/clutter-actor.c: diff --git a/clutter/Makefile.am b/clutter/Makefile.am index 681b0b480..f59814845 100644 --- a/clutter/Makefile.am +++ b/clutter/Makefile.am @@ -48,6 +48,7 @@ source_h = \ $(srcdir)/clutter-clone-texture.h \ $(srcdir)/clutter-color.h \ $(srcdir)/clutter-event.h \ + $(srcdir)/clutter-entry.h \ $(srcdir)/clutter-feature.h \ $(srcdir)/clutter-fixed.h \ $(srcdir)/clutter-group.h \ @@ -137,6 +138,7 @@ source_c = \ clutter-clone-texture.c \ clutter-enum-types.c \ clutter-event.c \ + clutter-entry.c \ clutter-feature.c \ clutter-fixed.c \ clutter-group.c \ diff --git a/clutter/clutter-entry.c b/clutter/clutter-entry.c new file mode 100644 index 000000000..9ccaf6d58 --- /dev/null +++ b/clutter/clutter-entry.c @@ -0,0 +1,1015 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Authored By Matthew Allum + * Neil Jagdish Patel priv; + + switch (prop_id) + { + case PROP_FONT_NAME: + clutter_entry_set_font_name (entry, g_value_get_string (value)); + break; + case PROP_TEXT: + clutter_entry_set_text (entry, g_value_get_string (value)); + break; + case PROP_COLOR: + clutter_entry_set_color (entry, g_value_get_boxed (value)); + break; + case PROP_ALIGNMENT: + clutter_entry_set_alignment (entry, g_value_get_enum (value)); + break; + case PROP_POSITION: + clutter_entry_set_position (entry, g_value_get_int (value)); + break; + case PROP_CURSOR: + clutter_entry_set_visible_cursor (entry, g_value_get_boolean (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +clutter_entry_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + ClutterEntry *entry; + ClutterEntryPrivate *priv; + ClutterColor color; + + entry = CLUTTER_ENTRY(object); + priv = entry->priv; + + switch (prop_id) + { + case PROP_FONT_NAME: + g_value_set_string (value, priv->font_name); + break; + case PROP_TEXT: + g_value_set_string (value, priv->text); + break; + case PROP_COLOR: + clutter_entry_get_color (entry, &color); + g_value_set_boxed (value, &color); + break; + case PROP_ALIGNMENT: + g_value_set_enum (value, priv->alignment); + break; + case PROP_POSITION: + g_value_set_int (value, priv->position); + break; + case PROP_CURSOR: + g_value_set_boolean (value, priv->show_cursor); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +clutter_entry_ensure_layout (ClutterEntry *entry, gint width) +{ + ClutterEntryPrivate *priv; + + priv = entry->priv; + + if (!priv->layout) + { + priv->layout = pango_layout_new (_context); + + if (priv->effective_attrs) + pango_layout_set_attributes (priv->layout, priv->effective_attrs); + + pango_layout_set_alignment (priv->layout, priv->alignment); + pango_layout_set_ellipsize (priv->layout, priv->ellipsize); + pango_layout_set_single_paragraph_mode (priv->layout, + priv->single_line_mode); + + pango_layout_set_font_description (priv->layout, priv->desc); + + if (!priv->use_markup) + pango_layout_set_text (priv->layout, priv->text, -1); + else + pango_layout_set_markup (priv->layout, priv->text, -1); + + if (priv->wrap) + pango_layout_set_wrap (priv->layout, priv->wrap_mode); + + if (priv->wrap && width > 0) + { + pango_layout_set_width (priv->layout, width * PANGO_SCALE); + } + else + pango_layout_set_width (priv->layout, -1); + } +} + +static void +clutter_entry_clear_layout (ClutterEntry *entry) +{ + if (entry->priv->layout) + { + g_object_unref (entry->priv->layout); + entry->priv->layout = NULL; + } +} + +static void +clutter_entry_ensure_cursor_position (ClutterEntry *entry) +{ + ClutterEntryPrivate *priv; + gint index; + + priv = entry->priv; + + if (priv->position == -1) + index = g_utf8_strlen (priv->text, -1); + else + index = priv->position; + + pango_layout_get_cursor_pos (priv->layout, index, + &priv->cursor_pos, NULL); + + clutter_actor_set_size (CLUTTER_ACTOR (priv->cursor), + 1, priv->cursor_pos.height/ PANGO_SCALE); + + clutter_actor_set_position (priv->cursor, + priv->cursor_pos.x/ PANGO_SCALE, + priv->cursor_pos.y/ PANGO_SCALE); +} + +void +clutter_entry_paint (ClutterActor *self) +{ + ClutterEntry *entry; + ClutterEntryPrivate *priv; + + entry = CLUTTER_ENTRY(self); + priv = entry->priv; + + if (priv->desc == NULL || priv->text == NULL) + { + CLUTTER_NOTE (ACTOR, "layout: %p , desc: %p, text %p", + priv->layout, + priv->desc, + priv->text); + return; + } + + clutter_entry_ensure_layout (entry, clutter_actor_get_width(self)); + priv->fgcol.alpha = clutter_actor_get_opacity(self); + + pango_clutter_render_layout (priv->layout, 0, 0, &priv->fgcol, 0); + + if (priv->show_cursor) + { + clutter_entry_ensure_cursor_position (entry); + clutter_actor_paint (priv->cursor); + } +} + +static void +clutter_entry_request_coords (ClutterActor *self, + ClutterActorBox *box) +{ + /* do we need to do anything ? */ + clutter_entry_clear_layout (CLUTTER_ENTRY(self)); +} + +static void +clutter_entry_dispose (GObject *object) +{ + ClutterEntry *self = CLUTTER_ENTRY(object); + ClutterEntryPrivate *priv; + + priv = self->priv; + + if (priv->layout) + { + g_object_unref (priv->layout); + priv->layout = NULL; + } + + if (priv->desc) + { + pango_font_description_free (priv->desc); + priv->desc = NULL; + } + + g_free (priv->text); + priv->text = NULL; + + g_free (priv->font_name); + priv->font_name = NULL; + + if (priv->context) + { + g_object_unref (priv->context); + priv->context = NULL; + } + + G_OBJECT_CLASS (clutter_entry_parent_class)->dispose (object); +} + +static void +clutter_entry_finalize (GObject *object) +{ + G_OBJECT_CLASS (clutter_entry_parent_class)->finalize (object); +} + +static void +clutter_entry_class_init (ClutterEntryClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass); + + actor_class->paint = clutter_entry_paint; + actor_class->request_coords = clutter_entry_request_coords; + + gobject_class->finalize = clutter_entry_finalize; + gobject_class->dispose = clutter_entry_dispose; + gobject_class->set_property = clutter_entry_set_property; + gobject_class->get_property = clutter_entry_get_property; + + g_object_class_install_property + (gobject_class, PROP_FONT_NAME, + g_param_spec_string ("font-name", + "Font Name", + "Pango font description", + NULL, + G_PARAM_CONSTRUCT | CLUTTER_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, PROP_TEXT, + g_param_spec_string ("text", + "Text", + "Text to render", + NULL, + G_PARAM_CONSTRUCT | CLUTTER_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, PROP_COLOR, + g_param_spec_boxed ("color", + "Font Colour", + "Font Colour", + CLUTTER_TYPE_COLOR, + CLUTTER_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, PROP_ALIGNMENT, + g_param_spec_enum ( "alignment", + "Alignment", + "The preferred alignment for the string,", + PANGO_TYPE_ALIGNMENT, + PANGO_ALIGN_LEFT, + CLUTTER_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, PROP_POSITION, + g_param_spec_int ( "position", + "Position", + "The cursor position", + -1, G_MAXINT, + -1, + CLUTTER_PARAM_READWRITE)); + + g_object_class_install_property + (gobject_class, PROP_CURSOR, + g_param_spec_boolean ( "cursor-visible", + "Cursor Visible", + "Whether the input cursor is visible ", + TRUE, + CLUTTER_PARAM_READWRITE)); + + g_type_class_add_private (gobject_class, sizeof (ClutterEntryPrivate)); +} + +static void +clutter_entry_init (ClutterEntry *self) +{ + ClutterEntryPrivate *priv; + + self->priv = priv = CLUTTER_ENTRY_GET_PRIVATE (self); + + if (_context == NULL) + { + _font_map = PANGO_CLUTTER_FONT_MAP (pango_clutter_font_map_new ()); + /* pango_clutter_font_map_set_resolution (font_map, 96.0, 96.0); */ + _context = pango_clutter_font_map_create_context (_font_map); + } + + priv->alignment = PANGO_ALIGN_LEFT; + priv->wrap = FALSE; + priv->wrap_mode = PANGO_WRAP_WORD; + priv->ellipsize = PANGO_ELLIPSIZE_NONE; + priv->use_underline = FALSE; + priv->use_markup = FALSE; + priv->layout = NULL; + priv->text = NULL; + priv->attrs = NULL; + priv->position = -1; + + priv->fgcol.red = 0; + priv->fgcol.green = 0; + priv->fgcol.blue = 0; + priv->fgcol.alpha = 255; + + priv->font_name = g_strdup (DEFAULT_FONT_NAME); + priv->desc = pango_font_description_from_string (priv->font_name); + + priv->cursor = clutter_rectangle_new_with_color (&priv->fgcol); + clutter_actor_set_parent (priv->cursor, CLUTTER_ACTOR (self)); + priv->show_cursor = TRUE; + + CLUTTER_MARK(); +} + +/** + * clutter_entry_new_with_text: + * @font_name: the name (and size) of the font to be used + * @text: the text to be displayed + * + * Creates a new #ClutterEntry displaying @text using @font_name. + * + * Return value: a #ClutterEntry + */ +ClutterActor* +clutter_entry_new_with_text (const gchar *font_name, + const gchar *text) +{ + ClutterActor *entry; + + CLUTTER_MARK(); + + entry = clutter_entry_new (); + + clutter_entry_set_font_name (CLUTTER_ENTRY(entry), font_name); + clutter_entry_set_text (CLUTTER_ENTRY(entry), text); + + return entry; +} + +/** + * clutter_entry_new_full: + * @font_name: the name (and size) of the font to be used + * @text: the text to be displayed + * @color: #ClutterColor for text + * + * Creates a new #ClutterEntry displaying @text with color @color + * using @font_name. + * + * Return value: a #ClutterEntry + */ +ClutterActor* +clutter_entry_new_full (const gchar *font_name, + const gchar *text, + ClutterColor *color) +{ + /* FIXME: really new_with_text should take color argument... */ + ClutterActor *entry; + + entry = clutter_entry_new_with_text (font_name, text); + clutter_entry_set_color (CLUTTER_ENTRY(entry), color); + + return entry; +} + +/** + * clutter_entry_new: + * + * Creates a new, empty #ClutterEntry. + * + * Returns: the newly created #ClutterEntry + */ +ClutterActor * +clutter_entry_new (void) +{ + return g_object_new (CLUTTER_TYPE_ENTRY, NULL); +} + +/** + * clutter_entry_get_text: + * @entry: a #ClutterEntry + * + * Retrieves the text displayed by @entry + * + * Return value: the text of the entry. The returned string is + * owned by #ClutterEntry and should not be modified or freed. + */ +G_CONST_RETURN gchar * +clutter_entry_get_text (ClutterEntry *entry) +{ + g_return_val_if_fail (CLUTTER_IS_ENTRY (entry), NULL); + + return entry->priv->text; +} + +/** + * clutter_entry_set_text: + * @entry: a #ClutterEntry + * @text: the text to be displayed + * + * Sets @text as the text to be displayed by @entry. + */ +void +clutter_entry_set_text (ClutterEntry *entry, + const gchar *text) +{ + ClutterEntryPrivate *priv; + + g_return_if_fail (CLUTTER_IS_ENTRY (entry)); + + priv = entry->priv; + + g_object_ref (entry); + + g_free (priv->text); + priv->text = g_strdup (text); + + clutter_entry_clear_layout (entry); + + if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(entry))) + clutter_actor_queue_redraw (CLUTTER_ACTOR(entry)); + + g_object_notify (G_OBJECT (entry), "text"); + g_object_unref (entry); +} + +/** + * clutter_entry_get_font_name: + * @entry: a #ClutterEntry + * + * Retrieves the font used by @entry. + * + * Return value: a string containing the font name, in a format + * understandable by pango_font_description_from_string(). The + * string is owned by #ClutterEntry and should not be modified + * or freed. + */ +G_CONST_RETURN gchar * +clutter_entry_get_font_name (ClutterEntry *entry) +{ + g_return_val_if_fail (CLUTTER_IS_ENTRY (entry), NULL); + + return entry->priv->font_name; +} + +/** + * clutter_entry_set_font_name: + * @entry: a #ClutterEntry + * @font_name: a font name and size, or %NULL for the default font + * + * Sets @font_name as the font used by @entry. + * + * @font_name must be a string containing the font name and its + * size, similarly to what you would feed to the + * pango_font_description_from_string() function. + */ +void +clutter_entry_set_font_name (ClutterEntry *entry, + const gchar *font_name) +{ + ClutterEntryPrivate *priv; + PangoFontDescription *desc; + + g_return_if_fail (CLUTTER_IS_ENTRY (entry)); + + if (!font_name || font_name[0] == '\0') + font_name = DEFAULT_FONT_NAME; + + priv = entry->priv; + + if (strcmp (priv->font_name, font_name) == 0) + return; + + desc = pango_font_description_from_string (font_name); + if (!desc) + { + g_warning ("Attempting to create a PangoFontDescription for " + "font name `%s', but failed.", + font_name); + return; + } + + g_object_ref (entry); + + g_free (priv->font_name); + priv->font_name = g_strdup (font_name); + + if (priv->desc) + pango_font_description_free (priv->desc); + + priv->desc = desc; + + if (entry->priv->text && entry->priv->text[0] != '\0') + { + clutter_entry_clear_layout (entry); + + if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(entry))) + clutter_actor_queue_redraw (CLUTTER_ACTOR(entry)); + } + + g_object_notify (G_OBJECT (entry), "font-name"); + g_object_unref (entry); +} + + +/** + * clutter_entry_set_color: + * @entry: a #ClutterEntry + * @color: a #ClutterColor + * + * Sets the color of @entry. + */ +void +clutter_entry_set_color (ClutterEntry *entry, + const ClutterColor *color) +{ + ClutterActor *actor; + ClutterEntryPrivate *priv; + + g_return_if_fail (CLUTTER_IS_ENTRY (entry)); + g_return_if_fail (color != NULL); + + priv = entry->priv; + + g_object_ref (entry); + + priv->fgcol.red = color->red; + priv->fgcol.green = color->green; + priv->fgcol.blue = color->blue; + priv->fgcol.alpha = color->alpha; + + actor = CLUTTER_ACTOR (entry); + + clutter_actor_set_opacity (actor, priv->fgcol.alpha); + + clutter_rectangle_set_color (CLUTTER_RECTANGLE (priv->cursor), &priv->fgcol); + + if (CLUTTER_ACTOR_IS_VISIBLE (actor)) + clutter_actor_queue_redraw (actor); + + g_object_notify (G_OBJECT (entry), "color"); + g_object_unref (entry); +} + +/** + * clutter_entry_get_color: + * @entry: a #ClutterEntry + * @color: return location for a #ClutterColor + * + * Retrieves the color of @entry. + */ +void +clutter_entry_get_color (ClutterEntry *entry, + ClutterColor *color) +{ + ClutterEntryPrivate *priv; + + g_return_if_fail (CLUTTER_IS_ENTRY (entry)); + g_return_if_fail (color != NULL); + + priv = entry->priv; + + color->red = priv->fgcol.red; + color->green = priv->fgcol.green; + color->blue = priv->fgcol.blue; + color->alpha = priv->fgcol.alpha; +} + +/** + * clutter_entry_get_layout: + * @entry: a #ClutterEntry + * + * Gets the #PangoLayout used to display the entry. + * The layout is useful to e.g. convert text positions to + * pixel positions. + * The returned layout is owned by the entry so need not be + * freed by the caller. + * + * Return value: the #PangoLayout for this entry + * + * Since: 0.2 + **/ +PangoLayout* +clutter_entry_get_layout (ClutterEntry *entry) +{ + g_return_val_if_fail (CLUTTER_IS_ENTRY (entry), NULL); + + clutter_entry_ensure_layout (entry, -1); + + return entry->priv->layout; +} + +/** + * clutter_entry_set_alignment: + * @entry: a #ClutterEntry + * @alignment: A #PangoAlignment + * + * Sets text alignment of the entry. + **/ +void +clutter_entry_set_alignment (ClutterEntry *entry, + PangoAlignment alignment) +{ + ClutterEntryPrivate *priv; + + g_return_if_fail (CLUTTER_IS_ENTRY (entry)); + + priv = entry->priv; + + if (priv->alignment != alignment) + { + g_object_ref (entry); + + priv->alignment = alignment; + clutter_entry_clear_layout (entry); + + if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR (entry))) + clutter_actor_queue_redraw (CLUTTER_ACTOR (entry)); + + g_object_notify (G_OBJECT (entry), "alignment"); + g_object_unref (entry); + } +} + +/** + * clutter_entry_get_alignment: + * @entry: a #ClutterEntry + * + * Returns the entry's text alignment + * + * Return value: The entrys #PangoAlignment + * + * Since 0.2 + **/ +PangoAlignment +clutter_entry_get_alignment (ClutterEntry *entry) +{ + g_return_val_if_fail (CLUTTER_IS_ENTRY (entry), FALSE); + + return entry->priv->alignment; +} + +/** + * clutter_entry_set_position: + * @entry: a #ClutterEntry + * @position: the position of the cursor. The cursor is displayed before + * the character with the given (base 0) index. + * The value must be less than or equal to the number of + * characters in the entry. A value of -1 indicates that the position should + * be set after the last character in the entry. + * Note that this position is in characters, not in bytes. + * + **/ +void +clutter_entry_set_position (ClutterEntry *entry, gint position) +{ + ClutterEntryPrivate *priv; + gint len; + + g_return_if_fail (CLUTTER_IS_ENTRY (entry)); + + priv = entry->priv; + + if (priv->text == NULL) + return; + + len = g_utf8_strlen (priv->text, -1); + + if (position < 0 || position >= len) + priv->position = -1; + else + priv->position = position; + + if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(entry))) + clutter_actor_queue_redraw (CLUTTER_ACTOR(entry)); +} + +/** + * clutter_entry_get_position: + * @entry: a #ClutterEntry + * + * Returns the entry's text alignment + * + * Return value: the position of the cursor. + * The cursor is displayed before the character with the given (base 0) index + * in the widget. The value will be less than or equal to the number of + * characters in the widget. Note that this position is in characters, + * not in bytes. + * + **/ +gint +clutter_entry_get_position (ClutterEntry *entry) +{ + ClutterEntryPrivate *priv; + + g_return_val_if_fail (CLUTTER_IS_ENTRY (entry), 0); + + priv = entry->priv; + + return priv->position; +} + +/** + * clutter_entry_add: + * @entry: a #ClutterEntry + * @utf8: the character to add. + * + * Insert a character to the right of the current position of the cursor. + * + **/ +void +clutter_entry_add (ClutterEntry *entry, gunichar wc) +{ + ClutterEntryPrivate *priv; + GString *new = NULL; + + g_return_if_fail (CLUTTER_IS_ENTRY (entry)); + g_return_if_fail (g_unichar_validate (wc)); + + priv = entry->priv; + + g_object_ref (entry); + + new = g_string_new (priv->text); + + new = g_string_insert_unichar (new, priv->position, wc); + + clutter_entry_set_text (entry, new->str); + + if (priv->position > 0) + clutter_entry_set_position (entry, priv->position + 1); + + g_string_free (new, TRUE); + g_object_unref (entry); +} + +/** + * clutter_entry_remove: + * @entry: a #ClutterEntry + * @len: the number of characters to remove. + * + * Characters are removed from before the current postion of the cursor. + * + **/ +void +clutter_entry_remove (ClutterEntry *entry, guint num) +{ + ClutterEntryPrivate *priv; + GString *new = NULL; + gint len; + + g_return_if_fail (CLUTTER_IS_ENTRY (entry)); + + priv = entry->priv; + + g_object_ref (entry); + + if (priv->text == NULL) + { + g_object_unref (entry); + return; + } + len = g_utf8_strlen (priv->text, -1); + new = g_string_new (priv->text); + + if (priv->position == -1) + new = g_string_erase (new, len-num, num); + else + new = g_string_erase (new, priv->position-num, num); + + clutter_entry_set_text (entry, new->str); + + if (priv->position > 0) + clutter_entry_set_position (entry, priv->position-num); + + g_string_free (new, TRUE); + g_object_unref (entry); +} + +/** + * clutter_entry_insert_text: + * @entry: a #ClutterEntry + * @text: the text to insert + * @position: the position at which to insert the text. A value of 0 indicates + * that the text will be inserted before the first character in the entrys text, + * and a value of -1 indicates that the text will be inserted after the last + * character in the entrys text. + * + * Insert text at a specifc position. + **/ +void +clutter_entry_insert_text (ClutterEntry *entry, + const gchar *text, + gssize position) +{ + ClutterEntryPrivate *priv; + GString *new = NULL; + + g_return_if_fail (CLUTTER_IS_ENTRY (entry)); + + priv = entry->priv; + + g_object_ref (entry); + + new = g_string_new (priv->text); + new = g_string_insert (new, position, text); + + clutter_entry_set_text (entry, new->str); + + g_string_free (new, TRUE); + g_object_unref (entry); +} + +/** + * clutter_entry_delete_text + * @entry: a #ClutterEntry + * @start_pos: the starting position. + * @end_pos: the end position. + * + * Deletes a sequence of characters. The characters that are deleted are those + * characters at positions from start_pos up to, but not including end_pos. + * If end_pos is negative, then the the characters deleted will be those + * characters from start_pos to the end of the text. + **/ +void +clutter_entry_delete_text (ClutterEntry *entry, + gssize start_pos, + gssize end_pos) +{ + ClutterEntryPrivate *priv; + GString *new = NULL; + + g_return_if_fail (CLUTTER_IS_ENTRY (entry)); + + priv = entry->priv; + + g_object_ref (entry); + if (priv->text == NULL) + { + g_object_unref (entry); + return; + } + + new = g_string_new (priv->text); + new = g_string_erase (new, start_pos, end_pos-start_pos); + + clutter_entry_set_text (entry, new->str); + + g_string_free (new, TRUE); + g_object_unref (entry); +} + +/** + * clutter_entry_set_visible_cursor + * @entry: a #ClutterEntry + * @visible: whether the input cursor should be visible + * + * Sets the visibility of the input cursor. + **/ +void +clutter_entry_set_visible_cursor (ClutterEntry *entry, gboolean visible) +{ + ClutterEntryPrivate *priv; + + g_return_if_fail (CLUTTER_IS_ENTRY (entry)); + + priv = entry->priv; + priv->show_cursor = visible; + + if (CLUTTER_ACTOR_IS_VISIBLE (CLUTTER_ACTOR(entry))) + clutter_actor_queue_redraw (CLUTTER_ACTOR(entry)); +} + +/** + * clutter_entry_get_visible_cursor + * @entry: a #ClutterEntry + * + * Returns the input cursors visiblity + * + * Return value: whether the input cursor is visible + * + **/ +gboolean +clutter_entry_get_visible_cursor (ClutterEntry *entry) +{ + ClutterEntryPrivate *priv; + + g_return_val_if_fail (CLUTTER_IS_ENTRY (entry), FALSE); + + priv = entry->priv; + + return priv->show_cursor; +} + diff --git a/clutter/clutter-entry.h b/clutter/clutter-entry.h new file mode 100644 index 000000000..bdcd61396 --- /dev/null +++ b/clutter/clutter-entry.h @@ -0,0 +1,124 @@ +/* + * Clutter. + * + * An OpenGL based 'interactive canvas' library. + * + * Authored By Matthew Allum + * Neil Jagdish Patel +#include +#include + + +G_BEGIN_DECLS + +#define CLUTTER_TYPE_ENTRY (clutter_entry_get_type ()) + +#define CLUTTER_ENTRY(obj) \ + (G_TYPE_CHECK_INSTANCE_CAST ((obj), \ + CLUTTER_TYPE_ENTRY, ClutterEntry)) + +#define CLUTTER_ENTRY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_CAST ((klass), \ + CLUTTER_TYPE_ENTRY, ClutterEntryClass)) + +#define CLUTTER_IS_ENTRY(obj) \ + (G_TYPE_CHECK_INSTANCE_TYPE ((obj), \ + CLUTTER_TYPE_ENTRY)) + +#define CLUTTER_IS_ENTRY_CLASS(klass) \ + (G_TYPE_CHECK_CLASS_TYPE ((klass), \ + CLUTTER_TYPE_ENTRY)) + +#define CLUTTER_ENTRY_GET_CLASS(obj) \ + (G_TYPE_INSTANCE_GET_CLASS ((obj), \ + CLUTTER_TYPE_ENTRY, ClutterEntryClass)) + +typedef struct _ClutterEntry ClutterEntry; +typedef struct _ClutterEntryClass ClutterEntryClass; +typedef struct _ClutterEntryPrivate ClutterEntryPrivate; + +struct _ClutterEntry +{ + ClutterActor parent; + + /*< private >*/ + ClutterEntryPrivate *priv; +}; + +struct _ClutterEntryClass +{ + /*< private >*/ + ClutterActorClass parent_class; + + void (*_clutter_entry_1) (void); + void (*_clutter_entry_2) (void); + void (*_clutter_entry_3) (void); + void (*_clutter_entry_4) (void); +}; + +GType clutter_entry_get_type (void) G_GNUC_CONST; + +ClutterActor * clutter_entry_new (void); + +ClutterActor* clutter_entry_new_full (const gchar *font_name, + const gchar *text, + ClutterColor *color); + +ClutterActor * clutter_entry_new_with_text (const gchar *font_name, + const gchar *text); +void clutter_entry_set_text (ClutterEntry *entry, + const gchar *text); +G_CONST_RETURN gchar *clutter_entry_get_text (ClutterEntry *entry); +void clutter_entry_set_font_name (ClutterEntry *entry, + const gchar *font_name); +G_CONST_RETURN gchar *clutter_entry_get_font_name (ClutterEntry *entry); +void clutter_entry_set_color (ClutterEntry *entry, + const ClutterColor *color); +void clutter_entry_get_color (ClutterEntry *entry, + ClutterColor *color); +PangoLayout * clutter_entry_get_layout (ClutterEntry *entry); +void clutter_entry_set_alignment (ClutterEntry *entry, + PangoAlignment alignment); +PangoAlignment clutter_entry_get_alignment (ClutterEntry *entry); +void clutter_entry_set_position (ClutterEntry *entry, + gint position); +gint clutter_entry_get_position (ClutterEntry *entry); +void clutter_entry_add (ClutterEntry *entry, + gunichar wc); +void clutter_entry_remove (ClutterEntry *entry, + guint len); +void clutter_entry_insert_text (ClutterEntry *entry, + const gchar *text, + gssize position); +void clutter_entry_delete_text (ClutterEntry *entry, + gssize start_pos, + gssize end_pos); +void clutter_entry_set_visible_cursor (ClutterEntry *entry, + gboolean visible); +gboolean clutter_entry_get_visible_cursor (ClutterEntry *entry); +G_END_DECLS + +#endif /* _HAVE_CLUTTER_ENTRY_H */ diff --git a/clutter/clutter.h b/clutter/clutter.h index 3b0e956d5..6eb4a69f9 100644 --- a/clutter/clutter.h +++ b/clutter/clutter.h @@ -31,6 +31,7 @@ #include "clutter-color.h" #include "clutter-util.h" #include "clutter-event.h" +#include "clutter-entry.h" #include "clutter-timeline.h" #include "clutter-behaviour.h" #include "clutter-behaviour-bspline.h" diff --git a/doc/reference/ChangeLog b/doc/reference/ChangeLog index 764622969..29b0bf6c0 100644 --- a/doc/reference/ChangeLog +++ b/doc/reference/ChangeLog @@ -1,3 +1,10 @@ +2007-05-31 Neil J Patel + + * clutter-docs.sgml: + * clutter-sections.txt: + * tmpl/clutter-entry.sgml: + Added ClutterEntry + 2007-05-31 Tomas Frydrych * tmpl/clutter-behaviour-ellipse.sgml: diff --git a/doc/reference/clutter-docs.sgml b/doc/reference/clutter-docs.sgml index 7890cf0e0..b7d41a58a 100644 --- a/doc/reference/clutter-docs.sgml +++ b/doc/reference/clutter-docs.sgml @@ -74,6 +74,7 @@ + Clutter Behaviours diff --git a/doc/reference/clutter-sections.txt b/doc/reference/clutter-sections.txt index ce46c5219..1cd38ab93 100644 --- a/doc/reference/clutter-sections.txt +++ b/doc/reference/clutter-sections.txt @@ -756,3 +756,40 @@ CLUTTER_VERSION_HEX CLUTTER_CHECK_VERSION CLUTTER_FLAVOUR + +
+clutter-entry +ClutterEntry +ClutterEntry +ClutterEntryClass +clutter_entry_new +clutter_entry_new_with_text +clutter_entry_new_full +clutter_entry_set_text +clutter_entry_get_text +clutter_entry_set_font_name +clutter_entry_get_font_name +clutter_entry_set_color +clutter_entry_get_color +clutter_entry_get_layout +clutter_entry_set_alignment +clutter_entry_get_alignment +clutter_entry_set_position +clutter_entry_get_position +clutter_entry_add +clutter_entry_remove +clutter_entry_insert_text +clutter_entry_delete_text +clutter_entry_set_visible_cursor +clutter_entry_get_visible_cursor + +CLUTTER_ENTRY +CLUTTER_IS_ENTRY +CLUTTER_TYPE_ENTRY +CLUTTER_ENTRY_CLASS +CLUTTER_IS_ENTRY_CLASS +CLUTTER_ENTRY_GET_CLASS + +ClutterEntryPrivate +clutter_entry_get_type +
diff --git a/doc/reference/tmpl/clutter-entry.sgml b/doc/reference/tmpl/clutter-entry.sgml new file mode 100644 index 000000000..78a844aa1 --- /dev/null +++ b/doc/reference/tmpl/clutter-entry.sgml @@ -0,0 +1,216 @@ + +ClutterEntry + + + + + + + + + + + + + + + + + + + + + + +@parent: + + + + + + + + + + + + +@Returns: + + + + + + + +@font_name: +@text: +@Returns: + + + + + + + +@font_name: +@text: +@color: +@Returns: + + + + + + + +@entry: +@text: + + + + + + + +@entry: +@Returns: + + + + + + + +@entry: +@font_name: + + + + + + + +@entry: +@Returns: + + + + + + + +@entry: +@color: + + + + + + + +@entry: +@color: + + + + + + + +@entry: +@Returns: + + + + + + + +@entry: +@alignment: + + + + + + + +@entry: +@Returns: + + + + + + + +@entry: +@position: + + + + + + + +@entry: +@Returns: + + + + + + + +@entry: +@wc: + + + + + + + +@entry: +@len: + + + + + + + +@entry: +@text: +@position: + + + + + + + +@entry: +@start_pos: +@end_pos: + + + + + + + +@entry: +@visible: + + + + + + + +@entry: +@Returns: + + diff --git a/examples/Makefile.am b/examples/Makefile.am index f9f5e1a66..0f31c7f4c 100644 --- a/examples/Makefile.am +++ b/examples/Makefile.am @@ -1,4 +1,4 @@ -noinst_PROGRAMS = test super-oh behave test-text slider +noinst_PROGRAMS = test super-oh behave test-text slider test-entry INCLUDES = -I$(top_srcdir)/ LDADD = $(top_builddir)/clutter/libclutter-@CLUTTER_FLAVOUR@-@CLUTTER_MAJORMINOR@.la @@ -29,6 +29,12 @@ behave_LDFLAGS = \ test_text_SOURCES = test-text.c test_text_CFLAGS = $(CLUTTER_CFLAGS) $(GCONF_CFLAGS) test_text_LDFLAGS = \ + $(CLUTTER_LIBS) \ + $(GCONF_LIBS) + +test_entry_SOURCES = test-entry.c +test_entry_CFLAGS = $(CLUTTER_CFLAGS) $(GCONF_CFLAGS) +test_entry_LDFLAGS = \ $(CLUTTER_LIBS) \ $(GCONF_LIBS) diff --git a/examples/test-entry.c b/examples/test-entry.c new file mode 100644 index 000000000..d7faad6a5 --- /dev/null +++ b/examples/test-entry.c @@ -0,0 +1,90 @@ +#include + +void +on_key_release_cb (ClutterStage *stage, ClutterEvent *event, ClutterEntry *entry) +{ + if (event->type == CLUTTER_KEY_RELEASE) { + ClutterKeyEvent* kev = (ClutterKeyEvent *) event; + guint key = clutter_key_event_symbol (kev); + + gint pos = clutter_entry_get_position (entry); + gint len = g_utf8_strlen (clutter_entry_get_text (entry), -1); + + switch (key) + { + case CLUTTER_Return: + case CLUTTER_KP_Enter: + case CLUTTER_ISO_Enter: + break; + case CLUTTER_Escape: + clutter_main_quit (); + break; + case CLUTTER_BackSpace: + clutter_entry_remove (entry, 1); + break; + case CLUTTER_Left: + if (pos != 0) + { + if (pos == -1) + { + clutter_entry_set_position (entry, len-1); + } + else + clutter_entry_set_position (entry, pos - 1); + } + break; + case CLUTTER_Right: + if (pos != -1) + { + if (pos != len) + clutter_entry_set_position (entry, pos +1); + } + break; + case CLUTTER_Up: + clutter_entry_insert_text (entry, "insert", 5); + break; + case CLUTTER_Down: + clutter_entry_delete_text (entry, 5, 11); + default: + clutter_entry_add (entry, clutter_key_event_unicode (kev)); + break; + } + } +} + +int +main (int argc, char *argv[]) +{ + ClutterTimeline *timeline; + ClutterActor *entry; + ClutterActor *stage; + gchar *text; + gsize size; + ClutterColor stage_color = { 0x00, 0x00, 0x00, 0xff }; + ClutterColor entry_color = { 0x33, 0xdd, 0xff, 0xff }; + + clutter_init (&argc, &argv); + + stage = clutter_stage_get_default (); + + clutter_actor_set_size (stage, 800, 600); + clutter_stage_set_color (CLUTTER_STAGE (stage), &stage_color); + + entry = clutter_entry_new_with_text ("Sans 14", + "Type something, be sure to use the " + "left/right arrow keys to move the " + "cursor position."); + clutter_entry_set_color (CLUTTER_ENTRY (entry), &entry_color); + clutter_actor_set_size (entry, 600, 50); + clutter_actor_set_position (entry, 100, 100); + + clutter_group_add (CLUTTER_GROUP (stage), entry); + clutter_group_show_all (CLUTTER_GROUP (stage)); + + g_signal_connect (stage, "key-release-event", + G_CALLBACK (on_key_release_cb), (gpointer)entry); + + clutter_main(); + + return 0; +}