2008-12-11 11:12:48 +00:00
|
|
|
/*
|
|
|
|
* Clutter.
|
|
|
|
*
|
|
|
|
* An OpenGL based 'interactive canvas' library.
|
|
|
|
*
|
2008-12-11 11:40:55 +00:00
|
|
|
* Copyright (C) 2008 Intel Corporation.
|
2008-12-11 11:12:48 +00:00
|
|
|
*
|
2008-12-11 11:40:55 +00:00
|
|
|
* Authored By: Øyvind Kolås <pippin@o-hand.com>
|
|
|
|
* Emmanuele Bassi <ebassi@linux.intel.com>
|
2008-12-11 11:12:48 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that 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
|
2008-12-11 11:40:55 +00:00
|
|
|
* License along with this library. If not, see <http://www.gnu.org/licenses/>.
|
2008-12-11 11:12:48 +00:00
|
|
|
*/
|
|
|
|
|
2008-12-11 15:00:22 +00:00
|
|
|
/**
|
|
|
|
* SECTION:clutter-text
|
|
|
|
* @short_description: An actor for displaying and editing text
|
|
|
|
*
|
|
|
|
* #ClutterText is an actor that displays custom text using Pango
|
|
|
|
* as the text rendering engine.
|
|
|
|
*
|
|
|
|
* #ClutterText also allows inline editing of the text if the
|
|
|
|
* actor is set editable using clutter_text_set_editable().
|
|
|
|
*
|
|
|
|
* Selection using keyboard or pointers can be enabled using
|
|
|
|
* clutter_text_set_selectable().
|
|
|
|
*
|
|
|
|
* #ClutterText is available since Clutter 1.0
|
|
|
|
*/
|
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
#ifdef HAVE_CONFIG_H
|
|
|
|
#include "config.h"
|
|
|
|
#endif
|
|
|
|
|
|
|
|
#include <string.h>
|
2010-10-21 11:16:05 +00:00
|
|
|
#include <math.h>
|
2008-12-11 11:12:48 +00:00
|
|
|
|
|
|
|
#include "clutter-text.h"
|
2008-12-11 11:15:11 +00:00
|
|
|
|
2010-10-21 11:16:05 +00:00
|
|
|
#include "clutter-actor-private.h"
|
2012-05-28 12:02:25 +00:00
|
|
|
#include "clutter-animatable.h"
|
2008-12-11 12:03:17 +00:00
|
|
|
#include "clutter-binding-pool.h"
|
2012-02-23 17:21:57 +00:00
|
|
|
#include "clutter-color.h"
|
2008-12-11 12:03:17 +00:00
|
|
|
#include "clutter-debug.h"
|
|
|
|
#include "clutter-enum-types.h"
|
2008-12-11 11:15:56 +00:00
|
|
|
#include "clutter-keysyms.h"
|
2008-12-11 11:15:11 +00:00
|
|
|
#include "clutter-main.h"
|
2010-04-22 16:54:05 +00:00
|
|
|
#include "clutter-marshal.h"
|
2011-05-16 15:04:27 +00:00
|
|
|
#include "clutter-private.h" /* includes <cogl-pango/cogl-pango.h> */
|
2010-04-22 16:54:05 +00:00
|
|
|
#include "clutter-profile.h"
|
2012-05-28 12:02:25 +00:00
|
|
|
#include "clutter-property-transition.h"
|
2011-06-15 09:06:31 +00:00
|
|
|
#include "clutter-text-buffer.h"
|
2008-12-11 11:15:11 +00:00
|
|
|
#include "clutter-units.h"
|
2011-03-07 18:53:07 +00:00
|
|
|
#include "clutter-paint-volume-private.h"
|
2011-08-16 16:31:42 +00:00
|
|
|
#include "clutter-scriptable.h"
|
2008-12-11 11:15:11 +00:00
|
|
|
|
2008-12-15 18:24:42 +00:00
|
|
|
/* cursor width in pixels */
|
|
|
|
#define DEFAULT_CURSOR_SIZE 2
|
|
|
|
|
2013-03-26 22:03:19 +00:00
|
|
|
/* vertical padding for the cursor */
|
|
|
|
#define CURSOR_Y_PADDING 2
|
|
|
|
|
2008-12-11 11:17:26 +00:00
|
|
|
/* We need at least three cached layouts to run the allocation without
|
2008-12-11 11:33:10 +00:00
|
|
|
* regenerating a new layout. First the layout will be generated at
|
|
|
|
* full width to get the preferred width, then it will be generated at
|
|
|
|
* the preferred width to get the preferred height and then it might
|
|
|
|
* be regenerated at a different width to get the height for the
|
|
|
|
* actual allocated width
|
2010-04-16 10:11:50 +00:00
|
|
|
*
|
|
|
|
* since we might get multiple queries from layout managers doing a
|
|
|
|
* double-pass allocations, like tabular ones, we should use 6 slots
|
2008-12-11 11:33:10 +00:00
|
|
|
*/
|
2010-04-16 10:11:50 +00:00
|
|
|
#define N_CACHED_LAYOUTS 6
|
2008-12-11 11:17:26 +00:00
|
|
|
|
|
|
|
#define CLUTTER_TEXT_GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), CLUTTER_TYPE_TEXT, ClutterTextPrivate))
|
|
|
|
|
|
|
|
typedef struct _LayoutCache LayoutCache;
|
|
|
|
|
2009-04-06 14:22:31 +00:00
|
|
|
static const ClutterColor default_cursor_color = { 0, 0, 0, 255 };
|
|
|
|
static const ClutterColor default_selection_color = { 0, 0, 0, 255 };
|
|
|
|
static const ClutterColor default_text_color = { 0, 0, 0, 255 };
|
2011-03-02 17:02:56 +00:00
|
|
|
static const ClutterColor default_selected_text_color = { 0, 0, 0, 255 };
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2012-05-28 12:02:25 +00:00
|
|
|
static ClutterAnimatableIface *parent_animatable_iface = NULL;
|
2012-06-08 13:13:36 +00:00
|
|
|
static ClutterScriptableIface *parent_scriptable_iface = NULL;
|
2012-05-28 12:02:25 +00:00
|
|
|
|
2011-08-16 16:31:42 +00:00
|
|
|
static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
|
2012-05-28 12:02:25 +00:00
|
|
|
static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
|
2011-08-16 16:31:42 +00:00
|
|
|
|
|
|
|
G_DEFINE_TYPE_WITH_CODE (ClutterText,
|
|
|
|
clutter_text,
|
|
|
|
CLUTTER_TYPE_ACTOR,
|
|
|
|
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
|
2012-05-28 12:02:25 +00:00
|
|
|
clutter_scriptable_iface_init)
|
|
|
|
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
|
|
|
|
clutter_animatable_iface_init));
|
2008-12-11 11:17:26 +00:00
|
|
|
|
|
|
|
struct _LayoutCache
|
|
|
|
{
|
2008-12-11 11:33:10 +00:00
|
|
|
/* Cached layout. Pango internally caches the computed extents
|
|
|
|
* when they are requested so there is no need to cache that as
|
|
|
|
* well
|
|
|
|
*/
|
2008-12-11 11:17:26 +00:00
|
|
|
PangoLayout *layout;
|
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
/* A number representing the age of this cache (so that when a
|
|
|
|
* new layout is needed the last used cache is replaced)
|
|
|
|
*/
|
2008-12-16 14:02:05 +00:00
|
|
|
guint age;
|
2008-12-11 11:17:26 +00:00
|
|
|
};
|
2008-12-11 11:12:48 +00:00
|
|
|
|
|
|
|
struct _ClutterTextPrivate
|
|
|
|
{
|
2008-12-11 11:17:26 +00:00
|
|
|
PangoFontDescription *font_desc;
|
|
|
|
|
2010-08-06 16:04:37 +00:00
|
|
|
/* the displayed text */
|
2011-06-15 09:06:31 +00:00
|
|
|
ClutterTextBuffer *buffer;
|
2010-08-06 16:04:37 +00:00
|
|
|
|
2008-12-11 11:17:26 +00:00
|
|
|
gchar *font_name;
|
2010-08-06 16:04:37 +00:00
|
|
|
|
2009-09-09 11:15:23 +00:00
|
|
|
gchar *preedit_str;
|
2008-12-11 11:17:26 +00:00
|
|
|
|
|
|
|
ClutterColor text_color;
|
|
|
|
|
|
|
|
LayoutCache cached_layouts[N_CACHED_LAYOUTS];
|
|
|
|
guint cache_age;
|
|
|
|
|
2010-01-05 11:58:12 +00:00
|
|
|
/* These are the attributes set by the attributes property */
|
2008-12-11 11:33:10 +00:00
|
|
|
PangoAttrList *attrs;
|
2010-01-05 11:58:12 +00:00
|
|
|
/* These are the attributes derived from the text when the
|
|
|
|
use-markup property is set */
|
|
|
|
PangoAttrList *markup_attrs;
|
|
|
|
/* This is the combination of the above two lists. It is set to NULL
|
|
|
|
whenever either of them changes and then regenerated by merging
|
|
|
|
the two lists whenever a layout is needed */
|
2008-12-11 11:33:10 +00:00
|
|
|
PangoAttrList *effective_attrs;
|
2010-01-05 11:58:12 +00:00
|
|
|
/* These are the attributes for the preedit string. These are merged
|
|
|
|
with the effective attributes into a temporary list before
|
|
|
|
creating a layout */
|
2009-09-09 11:15:23 +00:00
|
|
|
PangoAttrList *preedit_attrs;
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
/* current cursor position */
|
|
|
|
gint position;
|
|
|
|
|
|
|
|
/* current 'other end of selection' position */
|
|
|
|
gint selection_bound;
|
|
|
|
|
2009-01-07 00:43:24 +00:00
|
|
|
/* the x position in the PangoLayout, used to
|
2008-12-11 11:33:10 +00:00
|
|
|
* avoid drifting when repeatedly moving up|down
|
|
|
|
*/
|
2008-12-11 11:35:52 +00:00
|
|
|
gint x_pos;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2009-01-07 00:43:24 +00:00
|
|
|
/* the x position of the PangoLayout when in
|
|
|
|
* single line mode, to scroll the contents of the
|
|
|
|
* text actor
|
|
|
|
*/
|
2009-01-07 00:25:24 +00:00
|
|
|
gint text_x;
|
|
|
|
|
2011-02-04 11:33:53 +00:00
|
|
|
/* the y position of the PangoLayout, fixed to 0 by
|
|
|
|
* default for now */
|
|
|
|
gint text_y;
|
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
/* Where to draw the cursor */
|
2013-03-26 22:03:19 +00:00
|
|
|
ClutterRect cursor_rect;
|
2008-12-11 11:33:10 +00:00
|
|
|
ClutterColor cursor_color;
|
2008-12-16 10:37:45 +00:00
|
|
|
guint cursor_size;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2011-03-07 18:53:07 +00:00
|
|
|
/* Box representing the paint volume. The box is lazily calculated
|
|
|
|
and cached */
|
|
|
|
ClutterPaintVolume paint_volume;
|
|
|
|
|
2009-09-09 11:15:23 +00:00
|
|
|
guint preedit_cursor_pos;
|
|
|
|
gint preedit_n_chars;
|
|
|
|
|
2009-04-06 14:22:31 +00:00
|
|
|
ClutterColor selection_color;
|
|
|
|
|
2011-03-02 17:02:56 +00:00
|
|
|
ClutterColor selected_text_color;
|
|
|
|
|
2009-01-06 15:22:31 +00:00
|
|
|
gunichar password_char;
|
2009-01-27 16:47:20 +00:00
|
|
|
|
2011-09-19 15:44:22 +00:00
|
|
|
guint password_hint_id;
|
|
|
|
guint password_hint_timeout;
|
|
|
|
|
2009-01-27 16:47:20 +00:00
|
|
|
/* Signal handler for when the backend changes its font settings */
|
2011-09-19 15:44:22 +00:00
|
|
|
guint settings_changed_id;
|
2009-11-10 12:18:32 +00:00
|
|
|
|
|
|
|
/* Signal handler for when the :text-direction changes */
|
|
|
|
guint direction_changed_id;
|
2011-09-07 14:20:42 +00:00
|
|
|
|
|
|
|
/* bitfields */
|
|
|
|
guint alignment : 2;
|
|
|
|
guint wrap : 1;
|
|
|
|
guint use_underline : 1;
|
|
|
|
guint use_markup : 1;
|
|
|
|
guint ellipsize : 3;
|
|
|
|
guint single_line_mode : 1;
|
|
|
|
guint wrap_mode : 3;
|
|
|
|
guint justify : 1;
|
|
|
|
guint editable : 1;
|
|
|
|
guint cursor_visible : 1;
|
|
|
|
guint activatable : 1;
|
|
|
|
guint selectable : 1;
|
|
|
|
guint selection_color_set : 1;
|
|
|
|
guint in_select_drag : 1;
|
2012-06-18 01:03:58 +00:00
|
|
|
guint in_select_touch : 1;
|
2011-09-07 14:20:42 +00:00
|
|
|
guint cursor_color_set : 1;
|
|
|
|
guint preedit_set : 1;
|
|
|
|
guint is_default_font : 1;
|
|
|
|
guint has_focus : 1;
|
|
|
|
guint selected_text_color_set : 1;
|
|
|
|
guint paint_volume_valid : 1;
|
2011-09-19 15:44:22 +00:00
|
|
|
guint show_password_hint : 1;
|
|
|
|
guint password_hint_visible : 1;
|
2008-12-11 11:12:48 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
PROP_0,
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
PROP_BUFFER,
|
2008-12-11 11:17:26 +00:00
|
|
|
PROP_FONT_NAME,
|
2010-02-03 14:35:45 +00:00
|
|
|
PROP_FONT_DESCRIPTION,
|
2008-12-11 11:17:26 +00:00
|
|
|
PROP_TEXT,
|
|
|
|
PROP_COLOR,
|
|
|
|
PROP_USE_MARKUP,
|
2008-12-11 11:33:10 +00:00
|
|
|
PROP_ATTRIBUTES,
|
2009-02-02 23:55:30 +00:00
|
|
|
PROP_LINE_ALIGNMENT,
|
2008-12-11 11:33:10 +00:00
|
|
|
PROP_LINE_WRAP,
|
|
|
|
PROP_LINE_WRAP_MODE,
|
2008-12-11 11:17:26 +00:00
|
|
|
PROP_JUSTIFY,
|
|
|
|
PROP_ELLIPSIZE,
|
2008-12-11 11:12:48 +00:00
|
|
|
PROP_SELECTION_BOUND,
|
2009-04-06 14:22:31 +00:00
|
|
|
PROP_SELECTION_COLOR,
|
|
|
|
PROP_SELECTION_COLOR_SET,
|
2008-12-11 11:12:48 +00:00
|
|
|
PROP_CURSOR_VISIBLE,
|
|
|
|
PROP_CURSOR_COLOR,
|
|
|
|
PROP_CURSOR_COLOR_SET,
|
2008-12-16 10:37:45 +00:00
|
|
|
PROP_CURSOR_SIZE,
|
2012-07-05 15:23:52 +00:00
|
|
|
PROP_CURSOR_POSITION,
|
2008-12-11 11:12:48 +00:00
|
|
|
PROP_EDITABLE,
|
|
|
|
PROP_SELECTABLE,
|
2008-12-11 11:40:55 +00:00
|
|
|
PROP_ACTIVATABLE,
|
2009-01-06 15:22:31 +00:00
|
|
|
PROP_PASSWORD_CHAR,
|
2009-01-07 00:25:24 +00:00
|
|
|
PROP_MAX_LENGTH,
|
2010-06-21 09:20:32 +00:00
|
|
|
PROP_SINGLE_LINE_MODE,
|
2011-03-02 17:02:56 +00:00
|
|
|
PROP_SELECTED_TEXT_COLOR,
|
|
|
|
PROP_SELECTED_TEXT_COLOR_SET,
|
2010-06-21 09:20:32 +00:00
|
|
|
|
|
|
|
PROP_LAST
|
2008-12-11 11:12:48 +00:00
|
|
|
};
|
|
|
|
|
2010-06-21 09:20:32 +00:00
|
|
|
static GParamSpec *obj_props[PROP_LAST];
|
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
enum
|
|
|
|
{
|
|
|
|
TEXT_CHANGED,
|
|
|
|
ACTIVATE,
|
2009-11-20 14:17:41 +00:00
|
|
|
INSERT_TEXT,
|
|
|
|
DELETE_TEXT,
|
2013-03-26 22:03:19 +00:00
|
|
|
CURSOR_CHANGED,
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
LAST_SIGNAL
|
|
|
|
};
|
|
|
|
|
2008-12-11 11:17:26 +00:00
|
|
|
static guint text_signals[LAST_SIGNAL] = { 0, };
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2011-09-19 15:44:22 +00:00
|
|
|
static void clutter_text_settings_changed_cb (ClutterText *text);
|
2011-06-15 09:06:31 +00:00
|
|
|
static void buffer_connect_signals (ClutterText *self);
|
|
|
|
static void buffer_disconnect_signals (ClutterText *self);
|
|
|
|
static ClutterTextBuffer *get_buffer (ClutterText *self);
|
2009-01-27 16:47:20 +00:00
|
|
|
|
2012-02-07 11:31:28 +00:00
|
|
|
static inline void
|
2011-03-07 18:53:07 +00:00
|
|
|
clutter_text_dirty_paint_volume (ClutterText *text)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = text->priv;
|
|
|
|
|
|
|
|
if (priv->paint_volume_valid)
|
|
|
|
{
|
|
|
|
clutter_paint_volume_free (&priv->paint_volume);
|
|
|
|
priv->paint_volume_valid = FALSE;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-07 11:31:28 +00:00
|
|
|
static inline void
|
2011-03-07 18:53:07 +00:00
|
|
|
clutter_text_queue_redraw (ClutterActor *self)
|
|
|
|
{
|
|
|
|
/* This is a wrapper for clutter_actor_queue_redraw that also
|
|
|
|
dirties the cached paint volume. It would be nice if we could
|
|
|
|
just override the default implementation of the queue redraw
|
|
|
|
signal to do this instead but that doesn't work because the
|
|
|
|
signal isn't immediately emitted when queue_redraw is called.
|
|
|
|
Clutter will however immediately call get_paint_volume when
|
|
|
|
queue_redraw is called so we do need to dirty it immediately. */
|
|
|
|
|
|
|
|
clutter_text_dirty_paint_volume (CLUTTER_TEXT (self));
|
|
|
|
|
|
|
|
clutter_actor_queue_redraw (self);
|
|
|
|
}
|
|
|
|
|
|
|
|
#define clutter_actor_queue_redraw \
|
|
|
|
Please_use_clutter_text_queue_redraw_instead
|
|
|
|
|
2009-01-07 00:43:24 +00:00
|
|
|
#define offset_real(t,p) ((p) == -1 ? g_utf8_strlen ((t), -1) : (p))
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2008-12-11 11:47:06 +00:00
|
|
|
static gint
|
|
|
|
offset_to_bytes (const gchar *text,
|
|
|
|
gint pos)
|
|
|
|
{
|
2009-01-13 18:42:50 +00:00
|
|
|
const gchar *ptr;
|
2008-12-11 11:47:06 +00:00
|
|
|
|
|
|
|
if (pos < 0)
|
|
|
|
return strlen (text);
|
|
|
|
|
2009-01-13 18:42:50 +00:00
|
|
|
/* Loop over each character in the string until we either reach the
|
|
|
|
end or the requested position */
|
|
|
|
for (ptr = text; *ptr && pos-- > 0; ptr = g_utf8_next_char (ptr));
|
|
|
|
|
|
|
|
return ptr - text;
|
2008-12-11 11:47:06 +00:00
|
|
|
}
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2009-01-07 00:43:24 +00:00
|
|
|
#define bytes_to_offset(t,p) (g_utf8_pointer_to_offset ((t), (t) + (p)))
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2008-12-11 12:03:17 +00:00
|
|
|
static inline void
|
|
|
|
clutter_text_clear_selection (ClutterText *self)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
2008-12-11 11:33:10 +00:00
|
|
|
ClutterTextPrivate *priv = self->priv;
|
|
|
|
|
2009-07-23 17:21:10 +00:00
|
|
|
if (priv->selection_bound != priv->position)
|
|
|
|
{
|
|
|
|
priv->selection_bound = priv->position;
|
2011-03-03 11:35:46 +00:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SELECTION_BOUND]);
|
2011-03-07 18:53:07 +00:00
|
|
|
clutter_text_queue_redraw (CLUTTER_ACTOR (self));
|
2009-07-23 17:21:10 +00:00
|
|
|
}
|
2008-12-11 11:12:48 +00:00
|
|
|
}
|
|
|
|
|
2009-09-09 11:15:23 +00:00
|
|
|
static gchar *
|
|
|
|
clutter_text_get_display_text (ClutterText *self)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
2011-06-15 09:06:31 +00:00
|
|
|
ClutterTextBuffer *buffer;
|
|
|
|
const gchar *text;
|
|
|
|
|
|
|
|
buffer = get_buffer (self);
|
|
|
|
text = clutter_text_buffer_get_text (buffer);
|
2009-09-09 11:15:23 +00:00
|
|
|
|
2011-09-07 12:28:15 +00:00
|
|
|
/* simple short-circuit to avoid going through GString
|
|
|
|
* with an empty text and a password char set
|
|
|
|
*/
|
2011-06-15 09:06:31 +00:00
|
|
|
if (text[0] == '\0')
|
2009-09-09 11:15:23 +00:00
|
|
|
return g_strdup ("");
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
if (G_LIKELY (priv->password_char == 0))
|
|
|
|
return g_strdup (text);
|
2009-09-09 11:15:23 +00:00
|
|
|
else
|
|
|
|
{
|
2011-06-15 09:06:31 +00:00
|
|
|
GString *str;
|
2009-09-09 11:15:23 +00:00
|
|
|
gunichar invisible_char;
|
|
|
|
gchar buf[7];
|
|
|
|
gint char_len, i;
|
2011-06-15 09:06:31 +00:00
|
|
|
guint n_chars;
|
2009-09-09 11:15:23 +00:00
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
n_chars = clutter_text_buffer_get_length (buffer);
|
|
|
|
str = g_string_sized_new (clutter_text_buffer_get_bytes (buffer));
|
2009-09-09 11:15:23 +00:00
|
|
|
invisible_char = priv->password_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);
|
|
|
|
|
2011-09-19 15:44:22 +00:00
|
|
|
if (priv->show_password_hint && priv->password_hint_visible)
|
|
|
|
{
|
|
|
|
char *last_char;
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
for (i = 0; i < n_chars - 1; i++)
|
2011-09-19 15:44:22 +00:00
|
|
|
g_string_append_len (str, buf, char_len);
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
last_char = g_utf8_offset_to_pointer (text, n_chars - 1);
|
2011-09-19 15:44:22 +00:00
|
|
|
g_string_append (str, last_char);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-06-15 09:06:31 +00:00
|
|
|
for (i = 0; i < n_chars; i++)
|
2011-09-19 15:44:22 +00:00
|
|
|
g_string_append_len (str, buf, char_len);
|
|
|
|
}
|
2009-09-09 11:15:23 +00:00
|
|
|
|
|
|
|
return g_string_free (str, FALSE);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-02-07 11:31:28 +00:00
|
|
|
static inline void
|
2010-01-05 11:58:12 +00:00
|
|
|
clutter_text_ensure_effective_attributes (ClutterText *self)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
|
|
|
|
|
|
|
/* If we already have the effective attributes then we don't need to
|
|
|
|
do anything */
|
2012-02-07 11:31:28 +00:00
|
|
|
if (priv->effective_attrs != NULL)
|
|
|
|
return;
|
|
|
|
|
2012-12-17 18:56:57 +00:00
|
|
|
/* Same as if we don't have any attribute at all.
|
|
|
|
* We also ignore markup attributes for editable. */
|
|
|
|
if (priv->attrs == NULL && (priv->editable || priv->markup_attrs == NULL))
|
2012-02-07 11:31:28 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (priv->attrs != NULL)
|
2010-01-05 11:58:12 +00:00
|
|
|
{
|
2012-12-17 18:56:57 +00:00
|
|
|
/* If there are no markup attributes, or if this is editable (in which
|
|
|
|
* case we ignore markup), then we can just use these attrs directly */
|
|
|
|
if (priv->editable || priv->markup_attrs == NULL)
|
2012-02-07 11:31:28 +00:00
|
|
|
priv->effective_attrs = pango_attr_list_ref (priv->attrs);
|
|
|
|
else
|
2010-01-05 11:58:12 +00:00
|
|
|
{
|
2012-02-07 11:31:28 +00:00
|
|
|
/* Otherwise we need to merge the two lists */
|
|
|
|
PangoAttrIterator *iter;
|
|
|
|
GSList *attributes, *l;
|
2010-01-05 11:58:12 +00:00
|
|
|
|
2012-02-07 11:31:28 +00:00
|
|
|
priv->effective_attrs = pango_attr_list_copy (priv->markup_attrs);
|
2010-01-05 11:58:12 +00:00
|
|
|
|
2012-02-07 11:31:28 +00:00
|
|
|
iter = pango_attr_list_get_iterator (priv->attrs);
|
|
|
|
do
|
|
|
|
{
|
|
|
|
attributes = pango_attr_iterator_get_attrs (iter);
|
2010-01-05 11:58:12 +00:00
|
|
|
|
2012-02-07 11:31:28 +00:00
|
|
|
for (l = attributes; l != NULL; l = l->next)
|
|
|
|
{
|
|
|
|
PangoAttribute *attr = l->data;
|
2010-01-05 11:58:12 +00:00
|
|
|
|
2012-02-07 11:31:28 +00:00
|
|
|
pango_attr_list_insert (priv->effective_attrs, attr);
|
2010-01-05 11:58:12 +00:00
|
|
|
}
|
2011-12-19 04:20:04 +00:00
|
|
|
|
2012-02-07 11:31:28 +00:00
|
|
|
g_slist_free (attributes);
|
2010-01-05 11:58:12 +00:00
|
|
|
}
|
2012-02-07 11:31:28 +00:00
|
|
|
while (pango_attr_iterator_next (iter));
|
|
|
|
|
|
|
|
pango_attr_iterator_destroy (iter);
|
2010-01-05 11:58:12 +00:00
|
|
|
}
|
2012-02-07 11:31:28 +00:00
|
|
|
}
|
|
|
|
else if (priv->markup_attrs != NULL)
|
|
|
|
{
|
|
|
|
/* We can just use the markup attributes directly */
|
|
|
|
priv->effective_attrs = pango_attr_list_ref (priv->markup_attrs);
|
2010-01-05 11:58:12 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-11 11:17:26 +00:00
|
|
|
static PangoLayout *
|
2010-05-08 17:38:37 +00:00
|
|
|
clutter_text_create_layout_no_cache (ClutterText *text,
|
|
|
|
gint width,
|
|
|
|
gint height,
|
|
|
|
PangoEllipsizeMode ellipsize)
|
2008-12-11 11:17:26 +00:00
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = text->priv;
|
|
|
|
PangoLayout *layout;
|
2009-09-09 11:15:23 +00:00
|
|
|
gchar *contents;
|
|
|
|
gsize contents_len;
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2010-04-22 16:54:05 +00:00
|
|
|
CLUTTER_STATIC_TIMER (text_layout_timer,
|
|
|
|
"Mainloop",
|
|
|
|
"Text Layout",
|
|
|
|
"Layout creation",
|
|
|
|
0);
|
|
|
|
|
|
|
|
CLUTTER_TIMER_START (_clutter_uprof_context, text_layout_timer);
|
|
|
|
|
2009-02-02 12:04:34 +00:00
|
|
|
layout = clutter_actor_create_pango_layout (CLUTTER_ACTOR (text), NULL);
|
2008-12-11 11:17:26 +00:00
|
|
|
pango_layout_set_font_description (layout, priv->font_desc);
|
|
|
|
|
2009-09-09 11:15:23 +00:00
|
|
|
contents = clutter_text_get_display_text (text);
|
|
|
|
contents_len = strlen (contents);
|
|
|
|
|
|
|
|
if (priv->editable && priv->preedit_set)
|
2008-12-11 11:17:26 +00:00
|
|
|
{
|
2009-09-09 11:15:23 +00:00
|
|
|
GString *tmp = g_string_new (contents);
|
|
|
|
PangoAttrList *tmp_attrs = pango_attr_list_new ();
|
|
|
|
gint cursor_index;
|
|
|
|
|
|
|
|
if (priv->position == 0)
|
|
|
|
cursor_index = 0;
|
2009-01-07 13:48:45 +00:00
|
|
|
else
|
2009-09-09 11:15:23 +00:00
|
|
|
cursor_index = offset_to_bytes (contents, priv->position);
|
2008-12-11 11:40:55 +00:00
|
|
|
|
2009-09-09 11:15:23 +00:00
|
|
|
g_string_insert (tmp, cursor_index, priv->preedit_str);
|
2008-12-11 11:40:55 +00:00
|
|
|
|
2009-09-09 11:15:23 +00:00
|
|
|
pango_layout_set_text (layout, tmp->str, tmp->len);
|
2008-12-11 11:40:55 +00:00
|
|
|
|
2009-09-19 08:18:06 +00:00
|
|
|
if (priv->preedit_attrs != NULL)
|
|
|
|
{
|
|
|
|
pango_attr_list_splice (tmp_attrs, priv->preedit_attrs,
|
|
|
|
cursor_index,
|
|
|
|
strlen (priv->preedit_str));
|
|
|
|
|
|
|
|
pango_layout_set_attributes (layout, tmp_attrs);
|
|
|
|
}
|
2008-12-11 11:40:55 +00:00
|
|
|
|
2009-09-09 11:15:23 +00:00
|
|
|
g_string_free (tmp, TRUE);
|
|
|
|
pango_attr_list_unref (tmp_attrs);
|
2008-12-11 11:17:26 +00:00
|
|
|
}
|
2009-09-09 11:15:23 +00:00
|
|
|
else
|
|
|
|
pango_layout_set_text (layout, contents, contents_len);
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2012-12-17 18:56:57 +00:00
|
|
|
/* This will merge the markup attributes and the attributes
|
|
|
|
* property if needed */
|
|
|
|
clutter_text_ensure_effective_attributes (text);
|
2010-01-05 11:58:12 +00:00
|
|
|
|
2012-12-17 18:56:57 +00:00
|
|
|
if (priv->effective_attrs != NULL)
|
|
|
|
pango_layout_set_attributes (layout, priv->effective_attrs);
|
2009-01-29 13:18:57 +00:00
|
|
|
|
|
|
|
pango_layout_set_alignment (layout, priv->alignment);
|
|
|
|
pango_layout_set_single_paragraph_mode (layout, priv->single_line_mode);
|
|
|
|
pango_layout_set_justify (layout, priv->justify);
|
2009-04-21 13:15:19 +00:00
|
|
|
pango_layout_set_wrap (layout, priv->wrap_mode);
|
2009-01-29 13:18:57 +00:00
|
|
|
|
2010-05-08 17:38:37 +00:00
|
|
|
pango_layout_set_ellipsize (layout, ellipsize);
|
|
|
|
pango_layout_set_width (layout, width);
|
|
|
|
pango_layout_set_height (layout, height);
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2009-09-09 11:15:23 +00:00
|
|
|
g_free (contents);
|
|
|
|
|
2010-04-22 16:54:05 +00:00
|
|
|
CLUTTER_TIMER_STOP (_clutter_uprof_context, text_layout_timer);
|
|
|
|
|
2008-12-11 11:17:26 +00:00
|
|
|
return layout;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clutter_text_dirty_cache (ClutterText *text)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = text->priv;
|
|
|
|
int i;
|
|
|
|
|
|
|
|
/* Delete the cached layouts so they will be recreated the next time
|
|
|
|
they are needed */
|
|
|
|
for (i = 0; i < N_CACHED_LAYOUTS; i++)
|
|
|
|
if (priv->cached_layouts[i].layout)
|
|
|
|
{
|
|
|
|
g_object_unref (priv->cached_layouts[i].layout);
|
|
|
|
priv->cached_layouts[i].layout = NULL;
|
|
|
|
}
|
2011-03-07 18:53:07 +00:00
|
|
|
|
|
|
|
clutter_text_dirty_paint_volume (text);
|
2008-12-11 11:17:26 +00:00
|
|
|
}
|
|
|
|
|
2010-06-26 14:49:15 +00:00
|
|
|
/*
|
|
|
|
* clutter_text_set_font_description_internal:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @desc: a #PangoFontDescription
|
|
|
|
*
|
|
|
|
* Sets @desc as the font description to be used by the #ClutterText
|
2013-03-04 13:02:44 +00:00
|
|
|
* actor. The #PangoFontDescription is copied.
|
2010-06-26 14:49:15 +00:00
|
|
|
*
|
|
|
|
* This function will also set the :font-name field as a side-effect
|
|
|
|
*
|
|
|
|
* This function will evict the layout cache, and queue a relayout if
|
|
|
|
* the #ClutterText actor has contents.
|
|
|
|
*/
|
|
|
|
static inline void
|
|
|
|
clutter_text_set_font_description_internal (ClutterText *self,
|
|
|
|
PangoFontDescription *desc)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
|
|
|
|
2012-12-01 01:21:23 +00:00
|
|
|
if (priv->font_desc == desc ||
|
|
|
|
pango_font_description_equal (priv->font_desc, desc))
|
2010-06-26 14:49:15 +00:00
|
|
|
return;
|
|
|
|
|
|
|
|
if (priv->font_desc != NULL)
|
|
|
|
pango_font_description_free (priv->font_desc);
|
|
|
|
|
2013-03-04 13:02:44 +00:00
|
|
|
priv->font_desc = pango_font_description_copy (desc);
|
2010-06-26 14:49:15 +00:00
|
|
|
|
|
|
|
/* update the font name string we use */
|
|
|
|
g_free (priv->font_name);
|
|
|
|
priv->font_name = pango_font_description_to_string (priv->font_desc);
|
|
|
|
|
|
|
|
clutter_text_dirty_cache (self);
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
if (clutter_text_buffer_get_length (get_buffer (self)) != 0)
|
2010-06-26 14:49:15 +00:00
|
|
|
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
|
|
|
|
|
2011-03-03 11:35:46 +00:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FONT_DESCRIPTION]);
|
2010-06-26 14:49:15 +00:00
|
|
|
}
|
|
|
|
|
2009-01-27 16:47:20 +00:00
|
|
|
static void
|
2011-09-19 15:44:22 +00:00
|
|
|
clutter_text_settings_changed_cb (ClutterText *text)
|
2009-01-27 16:47:20 +00:00
|
|
|
{
|
2011-09-19 15:44:22 +00:00
|
|
|
ClutterTextPrivate *priv = text->priv;
|
|
|
|
guint password_hint_time = 0;
|
|
|
|
ClutterSettings *settings;
|
|
|
|
|
|
|
|
settings = clutter_settings_get_default ();
|
|
|
|
|
|
|
|
g_object_get (settings, "password-hint-time", &password_hint_time, NULL);
|
|
|
|
|
|
|
|
priv->show_password_hint = password_hint_time > 0;
|
|
|
|
priv->password_hint_timeout = password_hint_time;
|
|
|
|
|
|
|
|
if (priv->is_default_font)
|
2010-06-26 14:49:15 +00:00
|
|
|
{
|
|
|
|
PangoFontDescription *font_desc;
|
2010-09-10 13:27:37 +00:00
|
|
|
gchar *font_name = NULL;
|
|
|
|
|
|
|
|
g_object_get (settings, "font-name", &font_name, NULL);
|
2010-06-26 14:49:15 +00:00
|
|
|
|
|
|
|
CLUTTER_NOTE (ACTOR, "Text[%p]: default font changed to '%s'",
|
|
|
|
text,
|
|
|
|
font_name);
|
|
|
|
|
|
|
|
font_desc = pango_font_description_from_string (font_name);
|
|
|
|
clutter_text_set_font_description_internal (text, font_desc);
|
2010-09-10 13:27:37 +00:00
|
|
|
|
2013-03-04 13:02:44 +00:00
|
|
|
pango_font_description_free (font_desc);
|
2010-09-10 13:27:37 +00:00
|
|
|
g_free (font_name);
|
2010-06-26 14:49:15 +00:00
|
|
|
}
|
|
|
|
|
2009-01-27 16:47:20 +00:00
|
|
|
clutter_text_dirty_cache (text);
|
|
|
|
clutter_actor_queue_relayout (CLUTTER_ACTOR (text));
|
|
|
|
}
|
|
|
|
|
2009-11-10 12:18:32 +00:00
|
|
|
static void
|
|
|
|
clutter_text_direction_changed_cb (GObject *gobject,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
|
|
|
clutter_text_dirty_cache (CLUTTER_TEXT (gobject));
|
|
|
|
|
|
|
|
/* no need to queue a relayout: set_text_direction() will do that for us */
|
|
|
|
}
|
|
|
|
|
2008-12-11 11:17:26 +00:00
|
|
|
/*
|
|
|
|
* clutter_text_create_layout:
|
|
|
|
* @text: a #ClutterText
|
|
|
|
* @allocation_width: the allocation width
|
2008-12-16 14:02:05 +00:00
|
|
|
* @allocation_height: the allocation height
|
2008-12-11 11:17:26 +00:00
|
|
|
*
|
|
|
|
* Like clutter_text_create_layout_no_cache(), but will also ensure
|
|
|
|
* the glyphs cache. If a previously cached layout generated using the
|
|
|
|
* same width is available then that will be used instead of
|
|
|
|
* generating a new one.
|
|
|
|
*/
|
|
|
|
static PangoLayout *
|
|
|
|
clutter_text_create_layout (ClutterText *text,
|
Remove Units from the public API
With the recent change to internal floating point values, ClutterUnit
has become a redundant type, defined to be a float. All integer entry
points are being internally converted to floating point values to be
passed to the GL pipeline with the least amount of conversion.
ClutterUnit is thus exposed as just a "pixel with fractionary bits",
and not -- as users might think -- as generic, resolution and device
independent units. not that it was the case, but a definitive amount
of people was convinced it did provide this "feature", and was flummoxed
about the mere existence of this type.
So, having ClutterUnit exposed in the public API doubles the entry
points and has the following disadvantages:
- we have to maintain twice the amount of entry points in ClutterActor
- we still do an integer-to-float implicit conversion
- we introduce a weird impedance between pixels and "pixels with
fractionary bits"
- language bindings will have to choose what to bind, and resort
to manually overriding the API
+ *except* for language bindings based on GObject-Introspection, as
they cannot do manual overrides, thus will replicate the entire
set of entry points
For these reason, we should coalesces every Actor entry point for
pixels and for ClutterUnit into a single entry point taking a float,
like:
void clutter_actor_set_x (ClutterActor *self,
gfloat x);
void clutter_actor_get_size (ClutterActor *self,
gfloat *width,
gfloat *height);
gfloat clutter_actor_get_height (ClutterActor *self);
etc.
The issues I have identified are:
- we'll have a two cases of compiler warnings:
- printf() format of the return values from %d to %f
- clutter_actor_get_size() taking floats instead of unsigned ints
- we'll have a problem with varargs when passing an integer instead
of a floating point value, except on 64bit platforms where the
size of a float is the same as the size of an int
To be clear: the *intent* of the API should not change -- we still use
pixels everywhere -- but:
- we remove ambiguity in the API with regard to pixels and units
- we remove entry points we get to maintain for the whole 1.0
version of the API
- we make things simpler to bind for both manual language bindings
and automatic (gobject-introspection based) ones
- we have the simplest API possible while still exposing the
capabilities of the underlying GL implementation
2009-05-06 15:44:47 +00:00
|
|
|
gfloat allocation_width,
|
|
|
|
gfloat allocation_height)
|
2008-12-11 11:17:26 +00:00
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = text->priv;
|
|
|
|
LayoutCache *oldest_cache = priv->cached_layouts;
|
|
|
|
gboolean found_free_cache = FALSE;
|
2010-05-08 17:38:37 +00:00
|
|
|
gint width = -1;
|
|
|
|
gint height = -1;
|
|
|
|
PangoEllipsizeMode ellipsize = PANGO_ELLIPSIZE_NONE;
|
2008-12-11 11:17:26 +00:00
|
|
|
int i;
|
|
|
|
|
2010-04-22 16:54:05 +00:00
|
|
|
CLUTTER_STATIC_COUNTER (text_cache_hit_counter,
|
|
|
|
"Text layout cache hit counter",
|
|
|
|
"Increments for each layout cache hit",
|
|
|
|
0);
|
|
|
|
CLUTTER_STATIC_COUNTER (text_cache_miss_counter,
|
|
|
|
"Text layout cache miss counter",
|
|
|
|
"Increments for each layout cache miss",
|
|
|
|
0);
|
|
|
|
|
2010-05-08 17:38:37 +00:00
|
|
|
/* First determine the width, height, and ellipsize mode that
|
|
|
|
* we need for the layout. The ellipsize mode depends on
|
|
|
|
* allocation_width/allocation_size as follows:
|
|
|
|
*
|
|
|
|
* Cases, assuming ellipsize != NONE on actor:
|
|
|
|
*
|
|
|
|
* Width request: ellipsization can be set or not on layout,
|
|
|
|
* doesn't matter.
|
|
|
|
*
|
|
|
|
* Height request: ellipsization must never be set on layout
|
|
|
|
* if wrap=true, because we need to measure the wrapped
|
|
|
|
* height. It must always be set if wrap=false.
|
|
|
|
*
|
|
|
|
* Allocate: ellipsization must always be set.
|
|
|
|
*
|
|
|
|
* See http://bugzilla.gnome.org/show_bug.cgi?id=560931
|
|
|
|
*/
|
|
|
|
|
2010-05-13 14:51:42 +00:00
|
|
|
if (priv->ellipsize != PANGO_ELLIPSIZE_NONE)
|
2010-05-08 17:38:37 +00:00
|
|
|
{
|
|
|
|
if (allocation_height < 0 && priv->wrap)
|
|
|
|
; /* must not set ellipsization on wrap=true height request */
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (!priv->editable)
|
|
|
|
ellipsize = priv->ellipsize;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* When painting, we always need to set the width, since
|
|
|
|
* we might need to align to the right. When getting the
|
|
|
|
* height, however, there are some cases where we know that
|
|
|
|
* the width won't affect the width.
|
|
|
|
*
|
|
|
|
* - editable, single-line text actors, since those can
|
|
|
|
* scroll the layout.
|
|
|
|
* - non-wrapping, non-ellipsizing actors.
|
|
|
|
*/
|
|
|
|
if (allocation_width >= 0 &&
|
|
|
|
(allocation_height >= 0 ||
|
|
|
|
!((priv->editable && priv->single_line_mode) ||
|
|
|
|
(priv->ellipsize == PANGO_ELLIPSIZE_NONE && !priv->wrap))))
|
|
|
|
{
|
2010-06-14 10:59:33 +00:00
|
|
|
width = allocation_width * 1024 + 0.5f;
|
2010-05-08 17:38:37 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/* Pango only uses height if ellipsization is enabled, so don't set
|
|
|
|
* height if ellipsize isn't set. Pango implicitly enables wrapping
|
|
|
|
* if height is set, so don't set height if wrapping is disabled.
|
|
|
|
* In other words, only set height if we want to both wrap then
|
|
|
|
* ellipsize and we're not in single line mode.
|
|
|
|
*
|
|
|
|
* See http://bugzilla.gnome.org/show_bug.cgi?id=560931 if this
|
|
|
|
* seems odd.
|
|
|
|
*/
|
|
|
|
if (allocation_height >= 0 &&
|
|
|
|
priv->wrap &&
|
|
|
|
priv->ellipsize != PANGO_ELLIPSIZE_NONE &&
|
|
|
|
!priv->single_line_mode)
|
|
|
|
{
|
2010-06-14 10:59:33 +00:00
|
|
|
height = allocation_height * 1024 + 0.5f;
|
2010-05-08 17:38:37 +00:00
|
|
|
}
|
|
|
|
|
2008-12-16 14:02:05 +00:00
|
|
|
/* Search for a cached layout with the same width and keep
|
|
|
|
* track of the oldest one
|
|
|
|
*/
|
2008-12-11 11:17:26 +00:00
|
|
|
for (i = 0; i < N_CACHED_LAYOUTS; i++)
|
|
|
|
{
|
|
|
|
if (priv->cached_layouts[i].layout == NULL)
|
|
|
|
{
|
|
|
|
/* Always prefer free cache spaces */
|
|
|
|
found_free_cache = TRUE;
|
|
|
|
oldest_cache = priv->cached_layouts + i;
|
|
|
|
}
|
2010-04-13 23:12:02 +00:00
|
|
|
else
|
2008-12-11 11:17:26 +00:00
|
|
|
{
|
2010-05-08 17:38:37 +00:00
|
|
|
PangoLayout *cached = priv->cached_layouts[i].layout;
|
|
|
|
gint cached_width = pango_layout_get_width (cached);
|
|
|
|
gint cached_height = pango_layout_get_height (cached);
|
|
|
|
gint cached_ellipsize = pango_layout_get_ellipsize (cached);
|
|
|
|
|
|
|
|
if (cached_width == width &&
|
|
|
|
cached_height == height &&
|
|
|
|
cached_ellipsize == ellipsize)
|
|
|
|
{
|
|
|
|
/* If this cached layout is using the same size then we can
|
|
|
|
* just return that directly
|
2010-04-22 16:54:05 +00:00
|
|
|
*/
|
2010-05-08 17:38:37 +00:00
|
|
|
CLUTTER_NOTE (ACTOR,
|
|
|
|
"ClutterText: %p: cache hit for size %.2fx%.2f",
|
|
|
|
text,
|
|
|
|
allocation_width,
|
|
|
|
allocation_height);
|
|
|
|
|
|
|
|
CLUTTER_COUNTER_INC (_clutter_uprof_context,
|
|
|
|
text_cache_hit_counter);
|
|
|
|
|
|
|
|
return priv->cached_layouts[i].layout;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* When getting the preferred height for a specific width,
|
|
|
|
* we might be able to reuse the layout from getting the
|
|
|
|
* preferred width. If the width that the layout gives
|
|
|
|
* unconstrained is less than the width that we are using
|
|
|
|
* than the height will be unaffected by that width.
|
|
|
|
*/
|
|
|
|
if (allocation_height < 0 &&
|
|
|
|
cached_width == -1 &&
|
|
|
|
cached_ellipsize == ellipsize)
|
|
|
|
{
|
|
|
|
PangoRectangle logical_rect;
|
|
|
|
|
|
|
|
pango_layout_get_extents (priv->cached_layouts[i].layout,
|
|
|
|
NULL,
|
|
|
|
&logical_rect);
|
|
|
|
|
|
|
|
if (logical_rect.width <= width)
|
|
|
|
{
|
|
|
|
/* We've been asked for our height for the width we gave as a result
|
|
|
|
* of a _get_preferred_width call
|
|
|
|
*/
|
|
|
|
CLUTTER_NOTE (ACTOR,
|
|
|
|
"ClutterText: %p: cache hit for size %.2fx%.2f "
|
|
|
|
"(unwrapped width narrower than given width)",
|
|
|
|
text,
|
|
|
|
allocation_width,
|
|
|
|
allocation_height);
|
|
|
|
|
|
|
|
CLUTTER_COUNTER_INC (_clutter_uprof_context,
|
|
|
|
text_cache_hit_counter);
|
|
|
|
|
|
|
|
return priv->cached_layouts[i].layout;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (!found_free_cache &&
|
|
|
|
(priv->cached_layouts[i].age < oldest_cache->age))
|
|
|
|
{
|
|
|
|
oldest_cache = priv->cached_layouts + i;
|
|
|
|
}
|
2008-12-11 11:17:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-05-06 16:08:25 +00:00
|
|
|
CLUTTER_NOTE (ACTOR, "ClutterText: %p: cache miss for size %.2fx%.2f",
|
2008-12-11 11:17:26 +00:00
|
|
|
text,
|
2009-05-06 16:08:25 +00:00
|
|
|
allocation_width,
|
|
|
|
allocation_height);
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2010-04-22 16:54:05 +00:00
|
|
|
CLUTTER_COUNTER_INC (_clutter_uprof_context, text_cache_miss_counter);
|
|
|
|
|
2008-12-11 11:17:26 +00:00
|
|
|
/* If we make it here then we didn't have a cached version so we
|
|
|
|
need to recreate the layout */
|
|
|
|
if (oldest_cache->layout)
|
|
|
|
g_object_unref (oldest_cache->layout);
|
|
|
|
|
|
|
|
oldest_cache->layout =
|
2010-05-08 17:38:37 +00:00
|
|
|
clutter_text_create_layout_no_cache (text, width, height, ellipsize);
|
2008-12-11 11:17:26 +00:00
|
|
|
|
|
|
|
cogl_pango_ensure_glyph_cache_for_layout (oldest_cache->layout);
|
|
|
|
|
|
|
|
/* Mark the 'time' this cache was created and advance the time */
|
|
|
|
oldest_cache->age = priv->cache_age++;
|
|
|
|
return oldest_cache->layout;
|
|
|
|
}
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2012-02-06 18:23:21 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_coords_to_position:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @x: the X coordinate, relative to the actor
|
|
|
|
* @y: the Y coordinate, relative to the actor
|
|
|
|
*
|
|
|
|
* Retrieves the position of the character at the given coordinates.
|
|
|
|
*
|
|
|
|
* Return: the position of the character
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2012-02-06 18:23:21 +00:00
|
|
|
*/
|
|
|
|
gint
|
|
|
|
clutter_text_coords_to_position (ClutterText *self,
|
2009-06-02 17:44:30 +00:00
|
|
|
gfloat x,
|
|
|
|
gfloat y)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
|
|
|
gint index_;
|
|
|
|
gint px, py;
|
|
|
|
gint trailing;
|
|
|
|
|
2012-02-06 18:23:21 +00:00
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), 0);
|
2009-05-14 09:51:58 +00:00
|
|
|
|
2012-02-06 18:23:21 +00:00
|
|
|
/* Take any offset due to scrolling into account, and normalize
|
|
|
|
* the coordinates to PangoScale units
|
|
|
|
*/
|
|
|
|
px = (x - self->priv->text_x) * PANGO_SCALE;
|
|
|
|
py = (y - self->priv->text_y) * PANGO_SCALE;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2012-02-06 18:23:21 +00:00
|
|
|
pango_layout_xy_to_index (clutter_text_get_layout (self),
|
2008-12-15 18:24:42 +00:00
|
|
|
px, py,
|
|
|
|
&index_, &trailing);
|
2008-12-11 11:12:48 +00:00
|
|
|
|
|
|
|
return index_ + trailing;
|
|
|
|
}
|
|
|
|
|
2009-05-06 16:18:12 +00:00
|
|
|
/**
|
2008-12-15 18:24:42 +00:00
|
|
|
* clutter_text_position_to_coords:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @position: position in characters
|
2010-09-08 14:37:58 +00:00
|
|
|
* @x: (out): return location for the X coordinate, or %NULL
|
|
|
|
* @y: (out): return location for the Y coordinate, or %NULL
|
|
|
|
* @line_height: (out): return location for the line height, or %NULL
|
2008-12-15 18:24:42 +00:00
|
|
|
*
|
|
|
|
* Retrieves the coordinates of the given @position.
|
|
|
|
*
|
|
|
|
* Return value: %TRUE if the conversion was successful
|
2009-05-06 16:18:12 +00:00
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-15 18:24:42 +00:00
|
|
|
*/
|
2009-05-06 16:18:12 +00:00
|
|
|
gboolean
|
2008-12-11 11:48:17 +00:00
|
|
|
clutter_text_position_to_coords (ClutterText *self,
|
|
|
|
gint position,
|
Remove Units from the public API
With the recent change to internal floating point values, ClutterUnit
has become a redundant type, defined to be a float. All integer entry
points are being internally converted to floating point values to be
passed to the GL pipeline with the least amount of conversion.
ClutterUnit is thus exposed as just a "pixel with fractionary bits",
and not -- as users might think -- as generic, resolution and device
independent units. not that it was the case, but a definitive amount
of people was convinced it did provide this "feature", and was flummoxed
about the mere existence of this type.
So, having ClutterUnit exposed in the public API doubles the entry
points and has the following disadvantages:
- we have to maintain twice the amount of entry points in ClutterActor
- we still do an integer-to-float implicit conversion
- we introduce a weird impedance between pixels and "pixels with
fractionary bits"
- language bindings will have to choose what to bind, and resort
to manually overriding the API
+ *except* for language bindings based on GObject-Introspection, as
they cannot do manual overrides, thus will replicate the entire
set of entry points
For these reason, we should coalesces every Actor entry point for
pixels and for ClutterUnit into a single entry point taking a float,
like:
void clutter_actor_set_x (ClutterActor *self,
gfloat x);
void clutter_actor_get_size (ClutterActor *self,
gfloat *width,
gfloat *height);
gfloat clutter_actor_get_height (ClutterActor *self);
etc.
The issues I have identified are:
- we'll have a two cases of compiler warnings:
- printf() format of the return values from %d to %f
- clutter_actor_get_size() taking floats instead of unsigned ints
- we'll have a problem with varargs when passing an integer instead
of a floating point value, except on 64bit platforms where the
size of a float is the same as the size of an int
To be clear: the *intent* of the API should not change -- we still use
pixels everywhere -- but:
- we remove ambiguity in the API with regard to pixels and units
- we remove entry points we get to maintain for the whole 1.0
version of the API
- we make things simpler to bind for both manual language bindings
and automatic (gobject-introspection based) ones
- we have the simplest API possible while still exposing the
capabilities of the underlying GL implementation
2009-05-06 15:44:47 +00:00
|
|
|
gfloat *x,
|
|
|
|
gfloat *y,
|
|
|
|
gfloat *line_height)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
2009-05-06 16:18:12 +00:00
|
|
|
ClutterTextPrivate *priv;
|
2008-12-11 11:48:17 +00:00
|
|
|
PangoRectangle rect;
|
2009-09-09 11:15:23 +00:00
|
|
|
gint n_chars;
|
2009-01-06 15:22:31 +00:00
|
|
|
gint password_char_bytes = 1;
|
2008-12-11 11:48:17 +00:00
|
|
|
gint index_;
|
2011-06-15 09:06:31 +00:00
|
|
|
gsize n_bytes;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2009-05-06 16:18:12 +00:00
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
n_chars = clutter_text_buffer_get_length (get_buffer (self));
|
2009-09-09 11:15:23 +00:00
|
|
|
if (priv->preedit_set)
|
2011-06-15 09:06:31 +00:00
|
|
|
n_chars += priv->preedit_n_chars;
|
2009-09-09 11:15:23 +00:00
|
|
|
|
|
|
|
if (position < -1 || position > n_chars)
|
2009-05-06 16:18:12 +00:00
|
|
|
return FALSE;
|
|
|
|
|
2009-01-06 15:22:31 +00:00
|
|
|
if (priv->password_char != 0)
|
|
|
|
password_char_bytes = g_unichar_to_utf8 (priv->password_char, NULL);
|
2008-12-11 11:12:48 +00:00
|
|
|
|
|
|
|
if (position == -1)
|
2008-12-11 11:48:17 +00:00
|
|
|
{
|
2009-01-06 15:22:31 +00:00
|
|
|
if (priv->password_char == 0)
|
2009-10-19 14:31:29 +00:00
|
|
|
{
|
2011-06-15 09:06:31 +00:00
|
|
|
n_bytes = clutter_text_buffer_get_bytes (get_buffer (self));
|
2009-10-19 14:31:29 +00:00
|
|
|
if (priv->editable && priv->preedit_set)
|
2011-06-15 09:06:31 +00:00
|
|
|
index_ = n_bytes + strlen (priv->preedit_str);
|
2009-10-19 14:31:29 +00:00
|
|
|
else
|
2011-06-15 09:06:31 +00:00
|
|
|
index_ = n_bytes;
|
2009-10-19 14:31:29 +00:00
|
|
|
}
|
2008-12-11 11:48:17 +00:00
|
|
|
else
|
2009-09-09 11:15:23 +00:00
|
|
|
index_ = n_chars * password_char_bytes;
|
2008-12-11 11:48:17 +00:00
|
|
|
}
|
2008-12-15 18:24:42 +00:00
|
|
|
else if (position == 0)
|
|
|
|
{
|
|
|
|
index_ = 0;
|
|
|
|
}
|
2008-12-11 11:12:48 +00:00
|
|
|
else
|
2008-12-11 11:48:17 +00:00
|
|
|
{
|
2009-10-19 14:31:29 +00:00
|
|
|
gchar *text = clutter_text_get_display_text (self);
|
2009-11-09 08:42:15 +00:00
|
|
|
GString *tmp = g_string_new (text);
|
|
|
|
gint cursor_index;
|
|
|
|
|
|
|
|
cursor_index = offset_to_bytes (text, priv->position);
|
2009-11-09 11:07:27 +00:00
|
|
|
|
|
|
|
if (priv->preedit_str != NULL)
|
|
|
|
g_string_insert (tmp, cursor_index, priv->preedit_str);
|
2009-10-19 14:31:29 +00:00
|
|
|
|
2009-01-06 15:22:31 +00:00
|
|
|
if (priv->password_char == 0)
|
2009-11-09 08:42:15 +00:00
|
|
|
index_ = offset_to_bytes (tmp->str, position);
|
2008-12-11 11:48:17 +00:00
|
|
|
else
|
2009-09-09 11:15:23 +00:00
|
|
|
index_ = position * password_char_bytes;
|
2009-10-19 14:31:29 +00:00
|
|
|
|
|
|
|
g_free (text);
|
2009-11-09 08:42:15 +00:00
|
|
|
g_string_free (tmp, TRUE);
|
2008-12-11 11:48:17 +00:00
|
|
|
}
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2009-09-09 11:15:23 +00:00
|
|
|
pango_layout_get_cursor_pos (clutter_text_get_layout (self),
|
|
|
|
index_,
|
2008-12-11 11:40:55 +00:00
|
|
|
&rect, NULL);
|
2008-12-11 11:12:48 +00:00
|
|
|
|
|
|
|
if (x)
|
2009-05-06 16:18:12 +00:00
|
|
|
{
|
2009-06-02 17:44:30 +00:00
|
|
|
*x = (gfloat) rect.x / 1024.0f;
|
2009-05-06 16:18:12 +00:00
|
|
|
|
|
|
|
/* Take any offset due to scrolling into account */
|
|
|
|
if (priv->single_line_mode)
|
|
|
|
*x += priv->text_x;
|
|
|
|
}
|
2008-12-11 11:48:17 +00:00
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
if (y)
|
2009-06-02 17:44:30 +00:00
|
|
|
*y = (gfloat) rect.y / 1024.0f;
|
2008-12-11 11:48:17 +00:00
|
|
|
|
2008-12-15 18:24:42 +00:00
|
|
|
if (line_height)
|
2009-06-02 17:44:30 +00:00
|
|
|
*line_height = (gfloat) rect.height / 1024.0f;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2008-12-15 18:24:42 +00:00
|
|
|
return TRUE;
|
2008-12-11 11:12:48 +00:00
|
|
|
}
|
|
|
|
|
2008-12-11 11:48:17 +00:00
|
|
|
static inline void
|
|
|
|
clutter_text_ensure_cursor_position (ClutterText *self)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
2008-12-11 11:48:17 +00:00
|
|
|
ClutterTextPrivate *priv = self->priv;
|
Remove Units from the public API
With the recent change to internal floating point values, ClutterUnit
has become a redundant type, defined to be a float. All integer entry
points are being internally converted to floating point values to be
passed to the GL pipeline with the least amount of conversion.
ClutterUnit is thus exposed as just a "pixel with fractionary bits",
and not -- as users might think -- as generic, resolution and device
independent units. not that it was the case, but a definitive amount
of people was convinced it did provide this "feature", and was flummoxed
about the mere existence of this type.
So, having ClutterUnit exposed in the public API doubles the entry
points and has the following disadvantages:
- we have to maintain twice the amount of entry points in ClutterActor
- we still do an integer-to-float implicit conversion
- we introduce a weird impedance between pixels and "pixels with
fractionary bits"
- language bindings will have to choose what to bind, and resort
to manually overriding the API
+ *except* for language bindings based on GObject-Introspection, as
they cannot do manual overrides, thus will replicate the entire
set of entry points
For these reason, we should coalesces every Actor entry point for
pixels and for ClutterUnit into a single entry point taking a float,
like:
void clutter_actor_set_x (ClutterActor *self,
gfloat x);
void clutter_actor_get_size (ClutterActor *self,
gfloat *width,
gfloat *height);
gfloat clutter_actor_get_height (ClutterActor *self);
etc.
The issues I have identified are:
- we'll have a two cases of compiler warnings:
- printf() format of the return values from %d to %f
- clutter_actor_get_size() taking floats instead of unsigned ints
- we'll have a problem with varargs when passing an integer instead
of a floating point value, except on 64bit platforms where the
size of a float is the same as the size of an int
To be clear: the *intent* of the API should not change -- we still use
pixels everywhere -- but:
- we remove ambiguity in the API with regard to pixels and units
- we remove entry points we get to maintain for the whole 1.0
version of the API
- we make things simpler to bind for both manual language bindings
and automatic (gobject-introspection based) ones
- we have the simplest API possible while still exposing the
capabilities of the underlying GL implementation
2009-05-06 15:44:47 +00:00
|
|
|
gfloat x, y, cursor_height;
|
2013-03-26 22:03:19 +00:00
|
|
|
ClutterRect cursor_rect = CLUTTER_RECT_INIT_ZERO;
|
2009-09-09 11:15:23 +00:00
|
|
|
gint position;
|
|
|
|
|
|
|
|
position = priv->position;
|
|
|
|
|
2009-10-19 14:31:29 +00:00
|
|
|
if (priv->editable && priv->preedit_set)
|
2009-11-09 08:42:15 +00:00
|
|
|
{
|
|
|
|
if (position == -1)
|
2011-06-15 09:06:31 +00:00
|
|
|
position = clutter_text_buffer_get_length (get_buffer (self));
|
2013-03-26 22:03:19 +00:00
|
|
|
|
2009-11-09 08:42:15 +00:00
|
|
|
position += priv->preedit_cursor_pos;
|
|
|
|
}
|
2009-10-19 14:31:29 +00:00
|
|
|
|
2009-09-09 11:15:23 +00:00
|
|
|
CLUTTER_NOTE (MISC, "Cursor at %d (preedit %s at pos: %d)",
|
|
|
|
position,
|
|
|
|
priv->preedit_set ? "set" : "unset",
|
|
|
|
priv->preedit_set ? priv->preedit_cursor_pos : 0);
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2008-12-15 18:24:42 +00:00
|
|
|
x = y = cursor_height = 0;
|
2009-09-09 11:15:23 +00:00
|
|
|
clutter_text_position_to_coords (self, position,
|
2008-12-11 11:48:17 +00:00
|
|
|
&x, &y,
|
|
|
|
&cursor_height);
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2013-03-26 22:03:19 +00:00
|
|
|
clutter_rect_init (&cursor_rect,
|
|
|
|
x,
|
|
|
|
y + CURSOR_Y_PADDING,
|
|
|
|
priv->cursor_size,
|
|
|
|
cursor_height - 2 * CURSOR_Y_PADDING);
|
2009-04-21 11:06:14 +00:00
|
|
|
|
2013-03-26 22:03:19 +00:00
|
|
|
if (!clutter_rect_equals (&priv->cursor_rect, &cursor_rect))
|
2009-04-21 11:06:14 +00:00
|
|
|
{
|
2013-03-26 22:03:19 +00:00
|
|
|
priv->cursor_rect = cursor_rect;
|
|
|
|
|
|
|
|
g_signal_emit (self, text_signals[CURSOR_CHANGED], 0);
|
2009-04-21 11:06:14 +00:00
|
|
|
}
|
2008-12-11 11:12:48 +00:00
|
|
|
}
|
|
|
|
|
2009-05-06 16:08:25 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_delete_selection:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
|
|
|
* Deletes the currently selected text
|
|
|
|
*
|
|
|
|
* This function is only useful in subclasses of #ClutterText
|
|
|
|
*
|
|
|
|
* Return value: %TRUE if text was deleted or if the text actor
|
|
|
|
* is empty, and %FALSE otherwise
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2009-05-06 16:08:25 +00:00
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
clutter_text_delete_selection (ClutterText *self)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
2009-05-06 16:08:25 +00:00
|
|
|
ClutterTextPrivate *priv;
|
2008-12-11 11:33:10 +00:00
|
|
|
gint start_index;
|
|
|
|
gint end_index;
|
2009-10-16 13:22:15 +00:00
|
|
|
gint old_position, old_selection;
|
2011-06-15 09:06:31 +00:00
|
|
|
guint n_chars;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2009-05-06 16:08:25 +00:00
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
n_chars = clutter_text_buffer_get_length (get_buffer (self));
|
|
|
|
if (n_chars == 0)
|
2008-12-11 11:48:17 +00:00
|
|
|
return TRUE;
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
start_index = priv->position == -1 ? n_chars : priv->position;
|
|
|
|
end_index = priv->selection_bound == -1 ? n_chars : priv->selection_bound;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
|
|
|
if (end_index == start_index)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (end_index < start_index)
|
|
|
|
{
|
|
|
|
gint temp = start_index;
|
|
|
|
start_index = end_index;
|
|
|
|
end_index = temp;
|
|
|
|
}
|
|
|
|
|
2009-10-16 13:22:15 +00:00
|
|
|
old_position = priv->position;
|
|
|
|
old_selection = priv->selection_bound;
|
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
clutter_text_delete_text (self, start_index, end_index);
|
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
priv->position = start_index;
|
|
|
|
priv->selection_bound = start_index;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2010-01-25 15:13:58 +00:00
|
|
|
/* Not required to be guarded by g_object_freeze/thaw_notify */
|
2009-10-16 13:22:15 +00:00
|
|
|
if (priv->position != old_position)
|
2012-08-24 09:43:29 +00:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CURSOR_POSITION]);
|
2009-10-16 13:22:15 +00:00
|
|
|
|
|
|
|
if (priv->selection_bound != old_selection)
|
2011-03-03 11:35:46 +00:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SELECTION_BOUND]);
|
2009-10-16 13:22:15 +00:00
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2010-01-25 15:13:58 +00:00
|
|
|
/*
|
|
|
|
* Utility function to update both cursor position and selection bound
|
|
|
|
* at once
|
|
|
|
*/
|
|
|
|
static inline void
|
|
|
|
clutter_text_set_positions (ClutterText *self,
|
|
|
|
gint new_pos,
|
|
|
|
gint new_bound)
|
|
|
|
{
|
|
|
|
g_object_freeze_notify (G_OBJECT (self));
|
|
|
|
clutter_text_set_cursor_position (self, new_pos);
|
|
|
|
clutter_text_set_selection_bound (self, new_bound);
|
|
|
|
g_object_thaw_notify (G_OBJECT (self));
|
|
|
|
}
|
|
|
|
|
2009-10-07 20:44:17 +00:00
|
|
|
static inline void
|
|
|
|
clutter_text_set_markup_internal (ClutterText *self,
|
|
|
|
const gchar *str)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
|
|
|
GError *error;
|
|
|
|
gchar *text = NULL;
|
|
|
|
PangoAttrList *attrs = NULL;
|
|
|
|
gboolean res;
|
|
|
|
|
2011-09-07 12:28:15 +00:00
|
|
|
g_assert (str != NULL);
|
|
|
|
|
2009-10-07 20:44:17 +00:00
|
|
|
error = NULL;
|
|
|
|
res = pango_parse_markup (str, -1, 0,
|
|
|
|
&attrs,
|
|
|
|
&text,
|
|
|
|
NULL,
|
|
|
|
&error);
|
2011-09-07 12:28:15 +00:00
|
|
|
|
2009-10-07 20:44:17 +00:00
|
|
|
if (!res)
|
|
|
|
{
|
2011-09-07 12:28:15 +00:00
|
|
|
if (G_LIKELY (error != NULL))
|
2009-10-07 20:44:17 +00:00
|
|
|
{
|
2011-09-07 12:28:15 +00:00
|
|
|
g_warning ("Failed to set the markup of the actor '%s': %s",
|
|
|
|
_clutter_actor_get_debug_name (CLUTTER_ACTOR (self)),
|
2009-10-07 20:44:17 +00:00
|
|
|
error->message);
|
|
|
|
g_error_free (error);
|
|
|
|
}
|
|
|
|
else
|
2011-09-07 12:28:15 +00:00
|
|
|
g_warning ("Failed to set the markup of the actor '%s'",
|
|
|
|
_clutter_actor_get_debug_name (CLUTTER_ACTOR (self)));
|
2009-10-07 20:44:17 +00:00
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
if (text)
|
|
|
|
{
|
2012-04-09 16:09:59 +00:00
|
|
|
clutter_text_buffer_set_text (get_buffer (self), text, -1);
|
2011-06-15 09:06:31 +00:00
|
|
|
g_free (text);
|
|
|
|
}
|
2009-10-07 20:44:17 +00:00
|
|
|
|
2010-01-05 11:58:12 +00:00
|
|
|
/* Store the new markup attributes */
|
2010-08-06 16:04:37 +00:00
|
|
|
if (priv->markup_attrs != NULL)
|
2010-01-05 11:58:12 +00:00
|
|
|
pango_attr_list_unref (priv->markup_attrs);
|
2010-08-06 16:04:37 +00:00
|
|
|
|
2010-01-05 11:58:12 +00:00
|
|
|
priv->markup_attrs = attrs;
|
2009-10-07 20:44:17 +00:00
|
|
|
|
2010-01-05 11:58:12 +00:00
|
|
|
/* Clear the effective attributes so they will be regenerated when a
|
|
|
|
layout is created */
|
2010-08-06 16:04:37 +00:00
|
|
|
if (priv->effective_attrs != NULL)
|
2010-01-05 11:58:12 +00:00
|
|
|
{
|
|
|
|
pango_attr_list_unref (priv->effective_attrs);
|
|
|
|
priv->effective_attrs = NULL;
|
2009-10-07 20:44:17 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
static void
|
|
|
|
clutter_text_set_property (GObject *gobject,
|
|
|
|
guint prop_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
2008-12-11 11:33:10 +00:00
|
|
|
ClutterText *self = CLUTTER_TEXT (gobject);
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
switch (prop_id)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
2011-06-15 09:06:31 +00:00
|
|
|
case PROP_BUFFER:
|
|
|
|
clutter_text_set_buffer (self, g_value_get_object (value));
|
|
|
|
break;
|
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
case PROP_TEXT:
|
text: Make :use-markup set idempotent
Setting :use-markup and :text is currently not idempotent, and it
depends on the ordering, e.g.:
g_object_set (actor, "use-markup", TRUE, "text", value, NULL);
does not yield the same results as:
g_object_set (actor, "text", value, "use-markup", TRUE, NULL);
This is particularly jarring when using ClutterText from ClutterScript,
but in general GObject properties should not rely on the order when used
from g_object_set().
The fix is to store the contents of the ClutterText as a separate string
from the displayed text, and use the contents, instead of the displayed
text, when toggling the :use-markup property.
Let's also add a unit test for good measure, to try and catch
regressions.
https://bugzilla.gnome.org/show_bug.cgi?id=651940
2011-09-06 11:45:41 +00:00
|
|
|
{
|
|
|
|
const char *str = g_value_get_string (value);
|
|
|
|
if (self->priv->use_markup)
|
2011-09-07 12:08:22 +00:00
|
|
|
clutter_text_set_markup_internal (self, str ? str : "");
|
text: Make :use-markup set idempotent
Setting :use-markup and :text is currently not idempotent, and it
depends on the ordering, e.g.:
g_object_set (actor, "use-markup", TRUE, "text", value, NULL);
does not yield the same results as:
g_object_set (actor, "text", value, "use-markup", TRUE, NULL);
This is particularly jarring when using ClutterText from ClutterScript,
but in general GObject properties should not rely on the order when used
from g_object_set().
The fix is to store the contents of the ClutterText as a separate string
from the displayed text, and use the contents, instead of the displayed
text, when toggling the :use-markup property.
Let's also add a unit test for good measure, to try and catch
regressions.
https://bugzilla.gnome.org/show_bug.cgi?id=651940
2011-09-06 11:45:41 +00:00
|
|
|
else
|
2011-06-15 09:06:31 +00:00
|
|
|
clutter_text_buffer_set_text (get_buffer (self), str ? str : "", -1);
|
text: Make :use-markup set idempotent
Setting :use-markup and :text is currently not idempotent, and it
depends on the ordering, e.g.:
g_object_set (actor, "use-markup", TRUE, "text", value, NULL);
does not yield the same results as:
g_object_set (actor, "text", value, "use-markup", TRUE, NULL);
This is particularly jarring when using ClutterText from ClutterScript,
but in general GObject properties should not rely on the order when used
from g_object_set().
The fix is to store the contents of the ClutterText as a separate string
from the displayed text, and use the contents, instead of the displayed
text, when toggling the :use-markup property.
Let's also add a unit test for good measure, to try and catch
regressions.
https://bugzilla.gnome.org/show_bug.cgi?id=651940
2011-09-06 11:45:41 +00:00
|
|
|
}
|
2008-12-11 11:33:10 +00:00
|
|
|
break;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
case PROP_COLOR:
|
|
|
|
clutter_text_set_color (self, clutter_value_get_color (value));
|
|
|
|
break;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
case PROP_FONT_NAME:
|
|
|
|
clutter_text_set_font_name (self, g_value_get_string (value));
|
|
|
|
break;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2010-02-03 14:35:45 +00:00
|
|
|
case PROP_FONT_DESCRIPTION:
|
|
|
|
clutter_text_set_font_description (self, g_value_get_boxed (value));
|
|
|
|
break;
|
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
case PROP_USE_MARKUP:
|
|
|
|
clutter_text_set_use_markup (self, g_value_get_boolean (value));
|
|
|
|
break;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
case PROP_ATTRIBUTES:
|
|
|
|
clutter_text_set_attributes (self, g_value_get_boxed (value));
|
|
|
|
break;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2009-02-02 23:55:30 +00:00
|
|
|
case PROP_LINE_ALIGNMENT:
|
|
|
|
clutter_text_set_line_alignment (self, g_value_get_enum (value));
|
2008-12-11 11:33:10 +00:00
|
|
|
break;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
case PROP_LINE_WRAP:
|
|
|
|
clutter_text_set_line_wrap (self, g_value_get_boolean (value));
|
|
|
|
break;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
case PROP_LINE_WRAP_MODE:
|
|
|
|
clutter_text_set_line_wrap_mode (self, g_value_get_enum (value));
|
2008-12-11 11:17:26 +00:00
|
|
|
break;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
|
|
|
case PROP_JUSTIFY:
|
|
|
|
clutter_text_set_justify (self, g_value_get_boolean (value));
|
2008-12-11 11:17:26 +00:00
|
|
|
break;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
|
|
|
case PROP_ELLIPSIZE:
|
|
|
|
clutter_text_set_ellipsize (self, g_value_get_enum (value));
|
2008-12-11 11:17:26 +00:00
|
|
|
break;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2012-07-05 15:23:52 +00:00
|
|
|
case PROP_CURSOR_POSITION:
|
2008-12-11 11:33:10 +00:00
|
|
|
clutter_text_set_cursor_position (self, g_value_get_int (value));
|
2008-12-11 11:12:48 +00:00
|
|
|
break;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
case PROP_SELECTION_BOUND:
|
2008-12-11 11:33:10 +00:00
|
|
|
clutter_text_set_selection_bound (self, g_value_get_int (value));
|
2008-12-11 11:12:48 +00:00
|
|
|
break;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2009-04-06 14:22:31 +00:00
|
|
|
case PROP_SELECTION_COLOR:
|
|
|
|
clutter_text_set_selection_color (self, g_value_get_boxed (value));
|
|
|
|
break;
|
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
case PROP_CURSOR_VISIBLE:
|
2008-12-11 11:33:10 +00:00
|
|
|
clutter_text_set_cursor_visible (self, g_value_get_boolean (value));
|
2008-12-11 11:12:48 +00:00
|
|
|
break;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
case PROP_CURSOR_COLOR:
|
2008-12-11 11:33:10 +00:00
|
|
|
clutter_text_set_cursor_color (self, g_value_get_boxed (value));
|
2008-12-11 11:12:48 +00:00
|
|
|
break;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2008-12-16 10:37:45 +00:00
|
|
|
case PROP_CURSOR_SIZE:
|
|
|
|
clutter_text_set_cursor_size (self, g_value_get_int (value));
|
|
|
|
break;
|
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
case PROP_EDITABLE:
|
2008-12-11 11:33:10 +00:00
|
|
|
clutter_text_set_editable (self, g_value_get_boolean (value));
|
2008-12-11 11:12:48 +00:00
|
|
|
break;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
case PROP_ACTIVATABLE:
|
2008-12-11 11:33:10 +00:00
|
|
|
clutter_text_set_activatable (self, g_value_get_boolean (value));
|
2008-12-11 11:12:48 +00:00
|
|
|
break;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
case PROP_SELECTABLE:
|
2008-12-11 11:33:10 +00:00
|
|
|
clutter_text_set_selectable (self, g_value_get_boolean (value));
|
2008-12-11 11:12:48 +00:00
|
|
|
break;
|
|
|
|
|
2009-01-06 15:22:31 +00:00
|
|
|
case PROP_PASSWORD_CHAR:
|
|
|
|
clutter_text_set_password_char (self, g_value_get_uint (value));
|
2008-12-11 11:40:55 +00:00
|
|
|
break;
|
|
|
|
|
2008-12-11 11:54:07 +00:00
|
|
|
case PROP_MAX_LENGTH:
|
|
|
|
clutter_text_set_max_length (self, g_value_get_int (value));
|
|
|
|
break;
|
|
|
|
|
2009-01-07 00:25:24 +00:00
|
|
|
case PROP_SINGLE_LINE_MODE:
|
|
|
|
clutter_text_set_single_line_mode (self, g_value_get_boolean (value));
|
|
|
|
break;
|
|
|
|
|
2011-03-02 17:02:56 +00:00
|
|
|
case PROP_SELECTED_TEXT_COLOR:
|
|
|
|
clutter_text_set_selected_text_color (self, clutter_value_get_color (value));
|
|
|
|
break;
|
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clutter_text_get_property (GObject *gobject,
|
2008-12-11 11:40:55 +00:00
|
|
|
guint prop_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
2011-06-15 09:06:31 +00:00
|
|
|
ClutterText *self = CLUTTER_TEXT (gobject);
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
2011-06-15 09:06:31 +00:00
|
|
|
case PROP_BUFFER:
|
|
|
|
g_value_set_object (value, clutter_text_get_buffer (self));
|
|
|
|
break;
|
|
|
|
|
2008-12-11 11:17:26 +00:00
|
|
|
case PROP_TEXT:
|
2011-06-15 09:06:31 +00:00
|
|
|
g_value_set_string (value, clutter_text_buffer_get_text (get_buffer (self)));
|
2008-12-11 11:17:26 +00:00
|
|
|
break;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2008-12-11 11:17:26 +00:00
|
|
|
case PROP_FONT_NAME:
|
|
|
|
g_value_set_string (value, priv->font_name);
|
|
|
|
break;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2010-02-03 14:35:45 +00:00
|
|
|
case PROP_FONT_DESCRIPTION:
|
|
|
|
g_value_set_boxed (value, priv->font_desc);
|
|
|
|
break;
|
|
|
|
|
2009-09-08 12:06:51 +00:00
|
|
|
case PROP_USE_MARKUP:
|
|
|
|
g_value_set_boolean (value, priv->use_markup);
|
|
|
|
break;
|
|
|
|
|
2008-12-11 11:17:26 +00:00
|
|
|
case PROP_COLOR:
|
|
|
|
clutter_value_set_color (value, &priv->text_color);
|
|
|
|
break;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
case PROP_CURSOR_VISIBLE:
|
|
|
|
g_value_set_boolean (value, priv->cursor_visible);
|
|
|
|
break;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
case PROP_CURSOR_COLOR:
|
2008-12-11 11:17:26 +00:00
|
|
|
clutter_value_set_color (value, &priv->cursor_color);
|
2008-12-11 11:12:48 +00:00
|
|
|
break;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2008-12-11 11:49:14 +00:00
|
|
|
case PROP_CURSOR_COLOR_SET:
|
|
|
|
g_value_set_boolean (value, priv->cursor_color_set);
|
|
|
|
break;
|
|
|
|
|
2008-12-16 10:37:45 +00:00
|
|
|
case PROP_CURSOR_SIZE:
|
|
|
|
g_value_set_int (value, priv->cursor_size);
|
|
|
|
break;
|
|
|
|
|
2012-07-05 15:23:52 +00:00
|
|
|
case PROP_CURSOR_POSITION:
|
2009-01-08 17:06:04 +00:00
|
|
|
g_value_set_int (value, priv->position);
|
2008-12-11 11:12:48 +00:00
|
|
|
break;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
case PROP_SELECTION_BOUND:
|
2009-01-08 17:06:04 +00:00
|
|
|
g_value_set_int (value, priv->selection_bound);
|
2008-12-11 11:12:48 +00:00
|
|
|
break;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
case PROP_EDITABLE:
|
|
|
|
g_value_set_boolean (value, priv->editable);
|
|
|
|
break;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
case PROP_SELECTABLE:
|
|
|
|
g_value_set_boolean (value, priv->selectable);
|
|
|
|
break;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2009-04-06 14:22:31 +00:00
|
|
|
case PROP_SELECTION_COLOR:
|
|
|
|
clutter_value_set_color (value, &priv->selection_color);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_SELECTION_COLOR_SET:
|
|
|
|
g_value_set_boolean (value, priv->selection_color_set);
|
|
|
|
break;
|
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
case PROP_ACTIVATABLE:
|
|
|
|
g_value_set_boolean (value, priv->activatable);
|
|
|
|
break;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2009-01-06 15:22:31 +00:00
|
|
|
case PROP_PASSWORD_CHAR:
|
|
|
|
g_value_set_uint (value, priv->password_char);
|
2008-12-11 11:40:55 +00:00
|
|
|
break;
|
|
|
|
|
2008-12-11 11:54:07 +00:00
|
|
|
case PROP_MAX_LENGTH:
|
2011-06-15 09:06:31 +00:00
|
|
|
g_value_set_int (value, clutter_text_buffer_get_max_length (get_buffer (self)));
|
2008-12-11 11:54:07 +00:00
|
|
|
break;
|
|
|
|
|
2009-01-07 00:25:24 +00:00
|
|
|
case PROP_SINGLE_LINE_MODE:
|
|
|
|
g_value_set_boolean (value, priv->single_line_mode);
|
|
|
|
break;
|
|
|
|
|
2009-01-08 17:06:04 +00:00
|
|
|
case PROP_ELLIPSIZE:
|
|
|
|
g_value_set_enum (value, priv->ellipsize);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_LINE_WRAP:
|
|
|
|
g_value_set_boolean (value, priv->wrap);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_LINE_WRAP_MODE:
|
|
|
|
g_value_set_enum (value, priv->wrap_mode);
|
|
|
|
break;
|
|
|
|
|
2009-02-02 23:55:30 +00:00
|
|
|
case PROP_LINE_ALIGNMENT:
|
2009-01-08 17:06:04 +00:00
|
|
|
g_value_set_enum (value, priv->alignment);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_JUSTIFY:
|
|
|
|
g_value_set_boolean (value, priv->justify);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_ATTRIBUTES:
|
|
|
|
g_value_set_boxed (value, priv->attrs);
|
|
|
|
break;
|
|
|
|
|
2011-03-02 17:02:56 +00:00
|
|
|
case PROP_SELECTED_TEXT_COLOR:
|
|
|
|
clutter_value_set_color (value, &priv->selected_text_color);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_SELECTED_TEXT_COLOR_SET:
|
|
|
|
g_value_set_boolean (value, priv->selected_text_color_set);
|
|
|
|
break;
|
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (gobject, prop_id, pspec);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
static void
|
|
|
|
clutter_text_dispose (GObject *gobject)
|
|
|
|
{
|
|
|
|
ClutterText *self = CLUTTER_TEXT (gobject);
|
2009-01-27 16:47:20 +00:00
|
|
|
ClutterTextPrivate *priv = self->priv;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
|
|
|
/* get rid of the entire cache */
|
|
|
|
clutter_text_dirty_cache (self);
|
|
|
|
|
2009-11-10 12:18:32 +00:00
|
|
|
if (priv->direction_changed_id)
|
|
|
|
{
|
|
|
|
g_signal_handler_disconnect (self, priv->direction_changed_id);
|
|
|
|
priv->direction_changed_id = 0;
|
|
|
|
}
|
|
|
|
|
2011-09-19 15:44:22 +00:00
|
|
|
if (priv->settings_changed_id)
|
2009-01-27 16:47:20 +00:00
|
|
|
{
|
|
|
|
g_signal_handler_disconnect (clutter_get_default_backend (),
|
2011-09-19 15:44:22 +00:00
|
|
|
priv->settings_changed_id);
|
|
|
|
priv->settings_changed_id = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (priv->password_hint_id)
|
|
|
|
{
|
|
|
|
g_source_remove (priv->password_hint_id);
|
|
|
|
priv->password_hint_id = 0;
|
2009-01-27 16:47:20 +00:00
|
|
|
}
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
clutter_text_set_buffer (self, NULL);
|
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
G_OBJECT_CLASS (clutter_text_parent_class)->dispose (gobject);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clutter_text_finalize (GObject *gobject)
|
|
|
|
{
|
|
|
|
ClutterText *self = CLUTTER_TEXT (gobject);
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
|
|
|
|
|
|
|
if (priv->font_desc)
|
|
|
|
pango_font_description_free (priv->font_desc);
|
|
|
|
|
2010-01-05 11:44:17 +00:00
|
|
|
if (priv->attrs)
|
|
|
|
pango_attr_list_unref (priv->attrs);
|
2010-01-05 11:58:12 +00:00
|
|
|
if (priv->markup_attrs)
|
|
|
|
pango_attr_list_unref (priv->markup_attrs);
|
2010-01-05 11:44:17 +00:00
|
|
|
if (priv->effective_attrs)
|
|
|
|
pango_attr_list_unref (priv->effective_attrs);
|
|
|
|
if (priv->preedit_attrs)
|
|
|
|
pango_attr_list_unref (priv->preedit_attrs);
|
|
|
|
|
2011-03-07 18:53:07 +00:00
|
|
|
clutter_text_dirty_paint_volume (self);
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
clutter_text_set_buffer (self, NULL);
|
2008-12-11 11:33:10 +00:00
|
|
|
g_free (priv->font_name);
|
|
|
|
|
|
|
|
G_OBJECT_CLASS (clutter_text_parent_class)->finalize (gobject);
|
|
|
|
}
|
|
|
|
|
2011-03-07 18:53:07 +00:00
|
|
|
typedef void (* ClutterTextSelectionFunc) (ClutterText *text,
|
|
|
|
const ClutterActorBox *box,
|
|
|
|
gpointer user_data);
|
|
|
|
|
|
|
|
static void
|
|
|
|
clutter_text_foreach_selection_rectangle (ClutterText *self,
|
|
|
|
ClutterTextSelectionFunc func,
|
|
|
|
gpointer user_data)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
|
|
|
PangoLayout *layout = clutter_text_get_layout (self);
|
|
|
|
gchar *utf8 = clutter_text_get_display_text (self);
|
|
|
|
gint lines;
|
|
|
|
gint start_index;
|
|
|
|
gint end_index;
|
|
|
|
gint line_no;
|
|
|
|
|
|
|
|
if (priv->position == 0)
|
|
|
|
start_index = 0;
|
|
|
|
else
|
|
|
|
start_index = offset_to_bytes (utf8, priv->position);
|
|
|
|
|
|
|
|
if (priv->selection_bound == 0)
|
|
|
|
end_index = 0;
|
|
|
|
else
|
|
|
|
end_index = offset_to_bytes (utf8, priv->selection_bound);
|
|
|
|
|
|
|
|
if (start_index > end_index)
|
|
|
|
{
|
|
|
|
gint temp = start_index;
|
|
|
|
start_index = end_index;
|
|
|
|
end_index = temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
lines = pango_layout_get_line_count (layout);
|
|
|
|
|
|
|
|
for (line_no = 0; line_no < lines; line_no++)
|
|
|
|
{
|
|
|
|
PangoLayoutLine *line;
|
|
|
|
gint n_ranges;
|
|
|
|
gint *ranges;
|
|
|
|
gint i;
|
|
|
|
gint index_;
|
|
|
|
gint maxindex;
|
|
|
|
ClutterActorBox box;
|
|
|
|
gfloat y, height;
|
|
|
|
|
|
|
|
line = pango_layout_get_line_readonly (layout, line_no);
|
|
|
|
pango_layout_line_x_to_index (line, G_MAXINT, &maxindex, NULL);
|
|
|
|
if (maxindex < start_index)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
pango_layout_line_get_x_ranges (line, start_index, end_index,
|
|
|
|
&ranges,
|
|
|
|
&n_ranges);
|
|
|
|
pango_layout_line_x_to_index (line, 0, &index_, NULL);
|
|
|
|
|
|
|
|
clutter_text_position_to_coords (self,
|
|
|
|
bytes_to_offset (utf8, index_),
|
|
|
|
NULL, &y, &height);
|
|
|
|
|
|
|
|
box.y1 = y;
|
|
|
|
box.y2 = y + height;
|
|
|
|
|
|
|
|
for (i = 0; i < n_ranges; i++)
|
|
|
|
{
|
2011-07-10 09:24:40 +00:00
|
|
|
gfloat range_x;
|
|
|
|
gfloat range_width;
|
2011-03-07 18:53:07 +00:00
|
|
|
|
|
|
|
range_x = ranges[i * 2] / PANGO_SCALE;
|
|
|
|
|
|
|
|
/* Account for any scrolling in single line mode */
|
|
|
|
if (priv->single_line_mode)
|
|
|
|
range_x += priv->text_x;
|
|
|
|
|
|
|
|
|
2011-07-10 09:24:40 +00:00
|
|
|
range_width = ((gfloat) ranges[i * 2 + 1] - (gfloat) ranges[i * 2])
|
|
|
|
/ PANGO_SCALE;
|
2011-03-07 18:53:07 +00:00
|
|
|
|
|
|
|
box.x1 = range_x;
|
2011-07-10 09:24:40 +00:00
|
|
|
box.x2 = ceilf (range_x + range_width + .5f);
|
2011-03-07 18:53:07 +00:00
|
|
|
|
|
|
|
func (self, &box, user_data);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (ranges);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_free (utf8);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2011-07-10 09:24:40 +00:00
|
|
|
add_selection_rectangle_to_path (ClutterText *text,
|
|
|
|
const ClutterActorBox *box,
|
|
|
|
gpointer user_data)
|
2011-03-07 18:53:07 +00:00
|
|
|
{
|
|
|
|
cogl_path_rectangle (user_data, box->x1, box->y1, box->x2, box->y2);
|
|
|
|
}
|
|
|
|
|
2011-03-02 17:02:56 +00:00
|
|
|
/* Draws the selected text, its background, and the cursor */
|
2008-12-11 11:12:48 +00:00
|
|
|
static void
|
2011-03-02 17:02:56 +00:00
|
|
|
selection_paint (ClutterText *self)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
2008-12-11 11:40:55 +00:00
|
|
|
ClutterTextPrivate *priv = self->priv;
|
2008-12-11 12:18:26 +00:00
|
|
|
ClutterActor *actor = CLUTTER_ACTOR (self);
|
2011-03-02 17:02:56 +00:00
|
|
|
guint8 paint_opacity = clutter_actor_get_paint_opacity (actor);
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2011-05-13 13:26:22 +00:00
|
|
|
if (!priv->has_focus)
|
|
|
|
return;
|
|
|
|
|
2008-12-11 11:40:55 +00:00
|
|
|
if (priv->editable && priv->cursor_visible)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
2009-04-06 14:22:31 +00:00
|
|
|
const ClutterColor *color;
|
2009-09-09 11:15:23 +00:00
|
|
|
gint position;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2009-09-09 11:15:23 +00:00
|
|
|
position = priv->position;
|
|
|
|
|
|
|
|
if (position == priv->selection_bound)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
2011-03-02 17:02:56 +00:00
|
|
|
/* No selection, just draw the cursor */
|
2009-04-06 14:22:31 +00:00
|
|
|
if (priv->cursor_color_set)
|
|
|
|
color = &priv->cursor_color;
|
|
|
|
else
|
|
|
|
color = &priv->text_color;
|
|
|
|
|
|
|
|
cogl_set_source_color4ub (color->red,
|
|
|
|
color->green,
|
|
|
|
color->blue,
|
2013-03-26 22:03:19 +00:00
|
|
|
paint_opacity * color->alpha / 255);
|
|
|
|
|
|
|
|
cogl_rectangle (priv->cursor_rect.origin.x,
|
|
|
|
priv->cursor_rect.origin.y,
|
|
|
|
priv->cursor_rect.origin.x + priv->cursor_rect.size.width,
|
|
|
|
priv->cursor_rect.origin.y + priv->cursor_rect.size.height);
|
2008-12-11 11:12:48 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-03-02 17:02:56 +00:00
|
|
|
/* Paint selection background first */
|
2011-03-07 18:53:07 +00:00
|
|
|
PangoLayout *layout = clutter_text_get_layout (self);
|
2011-03-02 17:02:56 +00:00
|
|
|
CoglPath *selection_path = cogl_path_new ();
|
|
|
|
CoglColor cogl_color = { 0, };
|
2009-09-09 11:15:23 +00:00
|
|
|
|
2011-03-02 17:02:56 +00:00
|
|
|
/* Paint selection background */
|
|
|
|
if (priv->selection_color_set)
|
|
|
|
color = &priv->selection_color;
|
|
|
|
else if (priv->cursor_color_set)
|
|
|
|
color = &priv->cursor_color;
|
|
|
|
else
|
|
|
|
color = &priv->text_color;
|
|
|
|
|
|
|
|
cogl_set_source_color4ub (color->red,
|
|
|
|
color->green,
|
|
|
|
color->blue,
|
|
|
|
paint_opacity * color->alpha / 255);
|
|
|
|
|
2011-07-10 09:24:40 +00:00
|
|
|
clutter_text_foreach_selection_rectangle (self,
|
|
|
|
add_selection_rectangle_to_path,
|
|
|
|
selection_path);
|
2011-03-07 18:53:07 +00:00
|
|
|
|
2011-03-02 17:02:56 +00:00
|
|
|
cogl_path_fill (selection_path);
|
|
|
|
|
|
|
|
/* Paint selected text */
|
2012-03-08 14:07:15 +00:00
|
|
|
cogl_framebuffer_push_path_clip (cogl_get_draw_framebuffer (),
|
|
|
|
selection_path);
|
2011-03-02 17:02:56 +00:00
|
|
|
cogl_object_unref (selection_path);
|
|
|
|
|
|
|
|
if (priv->selected_text_color_set)
|
|
|
|
color = &priv->selected_text_color;
|
|
|
|
else
|
|
|
|
color = &priv->text_color;
|
|
|
|
|
|
|
|
cogl_color_init_from_4ub (&cogl_color,
|
|
|
|
color->red,
|
|
|
|
color->green,
|
|
|
|
color->blue,
|
|
|
|
paint_opacity * color->alpha / 255);
|
|
|
|
|
|
|
|
cogl_pango_render_layout (layout, priv->text_x, 0, &cogl_color, 0);
|
|
|
|
|
|
|
|
cogl_clip_pop ();
|
2008-12-11 11:40:55 +00:00
|
|
|
}
|
2008-12-11 11:12:48 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2009-03-30 15:46:57 +00:00
|
|
|
static gint
|
|
|
|
clutter_text_move_word_backward (ClutterText *self,
|
|
|
|
gint start)
|
|
|
|
{
|
|
|
|
gint retval = start;
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
if (clutter_text_buffer_get_length (get_buffer (self)) > 0 && start > 0)
|
2009-03-30 15:46:57 +00:00
|
|
|
{
|
|
|
|
PangoLayout *layout = clutter_text_get_layout (self);
|
|
|
|
PangoLogAttr *log_attrs = NULL;
|
|
|
|
gint n_attrs = 0;
|
|
|
|
|
|
|
|
pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
|
|
|
|
|
|
|
|
retval = start - 1;
|
|
|
|
while (retval > 0 && !log_attrs[retval].is_word_start)
|
|
|
|
retval -= 1;
|
|
|
|
|
|
|
|
g_free (log_attrs);
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gint
|
|
|
|
clutter_text_move_word_forward (ClutterText *self,
|
|
|
|
gint start)
|
|
|
|
{
|
|
|
|
gint retval = start;
|
2011-06-15 09:06:31 +00:00
|
|
|
guint n_chars;
|
2009-03-30 15:46:57 +00:00
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
n_chars = clutter_text_buffer_get_length (get_buffer (self));
|
|
|
|
if (n_chars > 0 && start < n_chars)
|
2009-03-30 15:46:57 +00:00
|
|
|
{
|
|
|
|
PangoLayout *layout = clutter_text_get_layout (self);
|
|
|
|
PangoLogAttr *log_attrs = NULL;
|
|
|
|
gint n_attrs = 0;
|
|
|
|
|
|
|
|
pango_layout_get_log_attrs (layout, &log_attrs, &n_attrs);
|
|
|
|
|
2009-08-16 21:00:35 +00:00
|
|
|
retval = start + 1;
|
2011-06-15 09:06:31 +00:00
|
|
|
while (retval < n_chars && !log_attrs[retval].is_word_end)
|
2009-03-30 15:46:57 +00:00
|
|
|
retval += 1;
|
|
|
|
|
|
|
|
g_free (log_attrs);
|
|
|
|
}
|
|
|
|
|
|
|
|
return retval;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gint
|
|
|
|
clutter_text_move_line_start (ClutterText *self,
|
|
|
|
gint start)
|
|
|
|
{
|
|
|
|
PangoLayoutLine *layout_line;
|
|
|
|
PangoLayout *layout;
|
|
|
|
gint line_no;
|
|
|
|
gint index_;
|
|
|
|
gint position;
|
2011-06-15 09:06:31 +00:00
|
|
|
const gchar *text;
|
2009-03-30 15:46:57 +00:00
|
|
|
|
|
|
|
layout = clutter_text_get_layout (self);
|
2011-06-15 09:06:31 +00:00
|
|
|
text = clutter_text_buffer_get_text (get_buffer (self));
|
2009-03-30 15:46:57 +00:00
|
|
|
|
|
|
|
if (start == 0)
|
|
|
|
index_ = 0;
|
|
|
|
else
|
2011-06-15 09:06:31 +00:00
|
|
|
index_ = offset_to_bytes (text, start);
|
2009-03-30 15:46:57 +00:00
|
|
|
|
|
|
|
pango_layout_index_to_line_x (layout, index_,
|
|
|
|
0,
|
|
|
|
&line_no, NULL);
|
|
|
|
|
|
|
|
layout_line = pango_layout_get_line_readonly (layout, line_no);
|
|
|
|
if (!layout_line)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
pango_layout_line_x_to_index (layout_line, 0, &index_, NULL);
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
position = bytes_to_offset (text, index_);
|
2009-03-30 15:46:57 +00:00
|
|
|
|
|
|
|
return position;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gint
|
|
|
|
clutter_text_move_line_end (ClutterText *self,
|
|
|
|
gint start)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
|
|
|
PangoLayoutLine *layout_line;
|
|
|
|
PangoLayout *layout;
|
|
|
|
gint line_no;
|
|
|
|
gint index_;
|
|
|
|
gint trailing;
|
|
|
|
gint position;
|
2011-06-15 09:06:31 +00:00
|
|
|
const gchar *text;
|
2009-03-30 15:46:57 +00:00
|
|
|
|
|
|
|
layout = clutter_text_get_layout (self);
|
2011-06-15 09:06:31 +00:00
|
|
|
text = clutter_text_buffer_get_text (get_buffer (self));
|
2009-03-30 15:46:57 +00:00
|
|
|
|
|
|
|
if (start == 0)
|
|
|
|
index_ = 0;
|
|
|
|
else
|
2011-06-15 09:06:31 +00:00
|
|
|
index_ = offset_to_bytes (text, priv->position);
|
2009-03-30 15:46:57 +00:00
|
|
|
|
|
|
|
pango_layout_index_to_line_x (layout, index_,
|
|
|
|
0,
|
|
|
|
&line_no, NULL);
|
|
|
|
|
|
|
|
layout_line = pango_layout_get_line_readonly (layout, line_no);
|
|
|
|
if (!layout_line)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
pango_layout_line_x_to_index (layout_line, G_MAXINT, &index_, &trailing);
|
|
|
|
index_ += trailing;
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
position = bytes_to_offset (text, index_);
|
2009-03-30 15:46:57 +00:00
|
|
|
|
|
|
|
return position;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clutter_text_select_word (ClutterText *self)
|
|
|
|
{
|
|
|
|
gint cursor_pos = self->priv->position;
|
|
|
|
gint start_pos, end_pos;
|
|
|
|
|
|
|
|
start_pos = clutter_text_move_word_backward (self, cursor_pos);
|
|
|
|
end_pos = clutter_text_move_word_forward (self, cursor_pos);
|
|
|
|
|
|
|
|
clutter_text_set_selection (self, start_pos, end_pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clutter_text_select_line (ClutterText *self)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
|
|
|
gint cursor_pos = priv->position;
|
|
|
|
gint start_pos, end_pos;
|
|
|
|
|
|
|
|
if (priv->single_line_mode)
|
|
|
|
{
|
|
|
|
start_pos = 0;
|
|
|
|
end_pos = -1;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
start_pos = clutter_text_move_line_start (self, cursor_pos);
|
|
|
|
end_pos = clutter_text_move_line_end (self, cursor_pos);
|
|
|
|
}
|
|
|
|
|
|
|
|
clutter_text_set_selection (self, start_pos, end_pos);
|
|
|
|
}
|
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
static gboolean
|
2012-06-18 01:03:58 +00:00
|
|
|
clutter_text_press (ClutterActor *actor,
|
|
|
|
ClutterEvent *event)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
2008-12-11 11:40:55 +00:00
|
|
|
ClutterText *self = CLUTTER_TEXT (actor);
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
2012-06-18 01:03:58 +00:00
|
|
|
ClutterEventType type = clutter_event_type (event);
|
2009-03-30 06:54:42 +00:00
|
|
|
gboolean res = FALSE;
|
Remove Units from the public API
With the recent change to internal floating point values, ClutterUnit
has become a redundant type, defined to be a float. All integer entry
points are being internally converted to floating point values to be
passed to the GL pipeline with the least amount of conversion.
ClutterUnit is thus exposed as just a "pixel with fractionary bits",
and not -- as users might think -- as generic, resolution and device
independent units. not that it was the case, but a definitive amount
of people was convinced it did provide this "feature", and was flummoxed
about the mere existence of this type.
So, having ClutterUnit exposed in the public API doubles the entry
points and has the following disadvantages:
- we have to maintain twice the amount of entry points in ClutterActor
- we still do an integer-to-float implicit conversion
- we introduce a weird impedance between pixels and "pixels with
fractionary bits"
- language bindings will have to choose what to bind, and resort
to manually overriding the API
+ *except* for language bindings based on GObject-Introspection, as
they cannot do manual overrides, thus will replicate the entire
set of entry points
For these reason, we should coalesces every Actor entry point for
pixels and for ClutterUnit into a single entry point taking a float,
like:
void clutter_actor_set_x (ClutterActor *self,
gfloat x);
void clutter_actor_get_size (ClutterActor *self,
gfloat *width,
gfloat *height);
gfloat clutter_actor_get_height (ClutterActor *self);
etc.
The issues I have identified are:
- we'll have a two cases of compiler warnings:
- printf() format of the return values from %d to %f
- clutter_actor_get_size() taking floats instead of unsigned ints
- we'll have a problem with varargs when passing an integer instead
of a floating point value, except on 64bit platforms where the
size of a float is the same as the size of an int
To be clear: the *intent* of the API should not change -- we still use
pixels everywhere -- but:
- we remove ambiguity in the API with regard to pixels and units
- we remove entry points we get to maintain for the whole 1.0
version of the API
- we make things simpler to bind for both manual language bindings
and automatic (gobject-introspection based) ones
- we have the simplest API possible while still exposing the
capabilities of the underlying GL implementation
2009-05-06 15:44:47 +00:00
|
|
|
gfloat x, y;
|
2008-12-11 11:40:55 +00:00
|
|
|
gint index_;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2012-08-17 18:52:56 +00:00
|
|
|
/* if a ClutterText is just used for display purposes, then we
|
|
|
|
* should ignore the events we receive
|
|
|
|
*/
|
|
|
|
if (!priv->editable)
|
2012-03-30 15:19:02 +00:00
|
|
|
return CLUTTER_EVENT_PROPAGATE;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2012-08-17 18:52:56 +00:00
|
|
|
clutter_actor_grab_key_focus (actor);
|
|
|
|
|
2009-03-30 06:54:42 +00:00
|
|
|
/* if the actor is empty we just reset everything and not
|
|
|
|
* set up the dragging of the selection since there's nothing
|
|
|
|
* to select
|
|
|
|
*/
|
2011-06-15 09:06:31 +00:00
|
|
|
if (clutter_text_buffer_get_length (get_buffer (self)) == 0)
|
2009-03-30 06:54:42 +00:00
|
|
|
{
|
2010-01-25 15:13:58 +00:00
|
|
|
clutter_text_set_positions (self, -1, -1);
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2012-01-12 10:40:38 +00:00
|
|
|
return CLUTTER_EVENT_STOP;
|
2009-03-30 06:54:42 +00:00
|
|
|
}
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2012-06-18 01:03:58 +00:00
|
|
|
clutter_event_get_coords (event, &x, &y);
|
|
|
|
|
|
|
|
res = clutter_actor_transform_stage_point (actor, x, y, &x, &y);
|
2009-03-30 06:54:42 +00:00
|
|
|
if (res)
|
|
|
|
{
|
2011-06-15 09:06:31 +00:00
|
|
|
const char *text;
|
2012-08-17 18:52:56 +00:00
|
|
|
int offset;
|
2009-03-30 15:46:57 +00:00
|
|
|
|
2009-06-02 17:44:30 +00:00
|
|
|
index_ = clutter_text_coords_to_position (self, x, y);
|
2011-06-15 09:06:31 +00:00
|
|
|
text = clutter_text_buffer_get_text (get_buffer (self));
|
|
|
|
offset = bytes_to_offset (text, index_);
|
2009-03-30 15:46:57 +00:00
|
|
|
|
|
|
|
/* what we select depends on the number of button clicks we
|
2012-08-17 18:52:56 +00:00
|
|
|
* receive, and whether we are selectable:
|
2009-03-30 15:46:57 +00:00
|
|
|
*
|
|
|
|
* 1: just position the cursor and the selection
|
|
|
|
* 2: select the current word
|
|
|
|
* 3: select the contents of the whole actor
|
|
|
|
*/
|
2012-06-18 01:03:58 +00:00
|
|
|
if (type == CLUTTER_BUTTON_PRESS)
|
2009-03-30 15:46:57 +00:00
|
|
|
{
|
2012-06-18 01:03:58 +00:00
|
|
|
gint click_count = clutter_event_get_click_count (event);
|
|
|
|
|
|
|
|
if (click_count == 1)
|
|
|
|
{
|
|
|
|
clutter_text_set_positions (self, offset, offset);
|
|
|
|
}
|
2012-08-17 18:52:56 +00:00
|
|
|
else if (priv->selectable && click_count == 2)
|
2012-06-18 01:03:58 +00:00
|
|
|
{
|
|
|
|
clutter_text_select_word (self);
|
|
|
|
}
|
2012-08-17 18:52:56 +00:00
|
|
|
else if (priv->selectable && click_count == 3)
|
2012-06-18 01:03:58 +00:00
|
|
|
{
|
|
|
|
clutter_text_select_line (self);
|
|
|
|
}
|
2009-03-30 15:46:57 +00:00
|
|
|
}
|
2012-06-18 01:03:58 +00:00
|
|
|
else
|
2012-08-17 18:52:56 +00:00
|
|
|
{
|
|
|
|
/* touch events do not have click count */
|
|
|
|
clutter_text_set_positions (self, offset, offset);
|
|
|
|
}
|
2009-03-30 06:54:42 +00:00
|
|
|
}
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2012-08-17 18:52:56 +00:00
|
|
|
/* we don't need to go any further if we're not selectable */
|
|
|
|
if (!priv->selectable)
|
|
|
|
return CLUTTER_EVENT_STOP;
|
|
|
|
|
2008-12-11 11:40:55 +00:00
|
|
|
/* grab the pointer */
|
2008-12-11 11:12:48 +00:00
|
|
|
priv->in_select_drag = TRUE;
|
2012-06-18 01:03:58 +00:00
|
|
|
|
|
|
|
if (type == CLUTTER_BUTTON_PRESS)
|
|
|
|
clutter_grab_pointer (actor);
|
|
|
|
else
|
|
|
|
{
|
|
|
|
clutter_input_device_sequence_grab (clutter_event_get_device (event),
|
|
|
|
clutter_event_get_event_sequence (event),
|
|
|
|
actor);
|
|
|
|
priv->in_select_touch = TRUE;
|
|
|
|
}
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2012-01-12 10:40:38 +00:00
|
|
|
return CLUTTER_EVENT_STOP;
|
2008-12-11 11:12:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2012-06-18 01:03:58 +00:00
|
|
|
clutter_text_move (ClutterActor *actor,
|
|
|
|
ClutterEvent *event)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
2009-06-02 17:44:30 +00:00
|
|
|
ClutterText *self = CLUTTER_TEXT (actor);
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
Remove Units from the public API
With the recent change to internal floating point values, ClutterUnit
has become a redundant type, defined to be a float. All integer entry
points are being internally converted to floating point values to be
passed to the GL pipeline with the least amount of conversion.
ClutterUnit is thus exposed as just a "pixel with fractionary bits",
and not -- as users might think -- as generic, resolution and device
independent units. not that it was the case, but a definitive amount
of people was convinced it did provide this "feature", and was flummoxed
about the mere existence of this type.
So, having ClutterUnit exposed in the public API doubles the entry
points and has the following disadvantages:
- we have to maintain twice the amount of entry points in ClutterActor
- we still do an integer-to-float implicit conversion
- we introduce a weird impedance between pixels and "pixels with
fractionary bits"
- language bindings will have to choose what to bind, and resort
to manually overriding the API
+ *except* for language bindings based on GObject-Introspection, as
they cannot do manual overrides, thus will replicate the entire
set of entry points
For these reason, we should coalesces every Actor entry point for
pixels and for ClutterUnit into a single entry point taking a float,
like:
void clutter_actor_set_x (ClutterActor *self,
gfloat x);
void clutter_actor_get_size (ClutterActor *self,
gfloat *width,
gfloat *height);
gfloat clutter_actor_get_height (ClutterActor *self);
etc.
The issues I have identified are:
- we'll have a two cases of compiler warnings:
- printf() format of the return values from %d to %f
- clutter_actor_get_size() taking floats instead of unsigned ints
- we'll have a problem with varargs when passing an integer instead
of a floating point value, except on 64bit platforms where the
size of a float is the same as the size of an int
To be clear: the *intent* of the API should not change -- we still use
pixels everywhere -- but:
- we remove ambiguity in the API with regard to pixels and units
- we remove entry points we get to maintain for the whole 1.0
version of the API
- we make things simpler to bind for both manual language bindings
and automatic (gobject-introspection based) ones
- we have the simplest API possible while still exposing the
capabilities of the underlying GL implementation
2009-05-06 15:44:47 +00:00
|
|
|
gfloat x, y;
|
2009-06-02 17:44:30 +00:00
|
|
|
gint index_, offset;
|
|
|
|
gboolean res;
|
2011-06-15 09:06:31 +00:00
|
|
|
const gchar *text;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
|
|
|
if (!priv->in_select_drag)
|
2012-01-12 10:40:38 +00:00
|
|
|
return CLUTTER_EVENT_PROPAGATE;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2012-06-18 01:03:58 +00:00
|
|
|
clutter_event_get_coords (event, &x, &y);
|
|
|
|
|
|
|
|
res = clutter_actor_transform_stage_point (actor, x, y, &x, &y);
|
2009-06-02 17:44:30 +00:00
|
|
|
if (!res)
|
2012-01-12 10:40:38 +00:00
|
|
|
return CLUTTER_EVENT_PROPAGATE;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2009-06-02 17:44:30 +00:00
|
|
|
index_ = clutter_text_coords_to_position (self, x, y);
|
2011-06-15 09:06:31 +00:00
|
|
|
text = clutter_text_buffer_get_text (get_buffer (self));
|
|
|
|
offset = bytes_to_offset (text, index_);
|
2008-12-11 11:12:48 +00:00
|
|
|
|
|
|
|
if (priv->selectable)
|
2009-06-02 17:44:30 +00:00
|
|
|
clutter_text_set_cursor_position (self, offset);
|
2008-12-11 11:12:48 +00:00
|
|
|
else
|
2010-02-02 17:07:22 +00:00
|
|
|
clutter_text_set_positions (self, offset, offset);
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2012-01-12 10:40:38 +00:00
|
|
|
return CLUTTER_EVENT_STOP;
|
2008-12-11 11:12:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2012-06-18 01:03:58 +00:00
|
|
|
clutter_text_release (ClutterActor *actor,
|
|
|
|
ClutterEvent *event)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
2009-06-02 17:44:30 +00:00
|
|
|
ClutterText *self = CLUTTER_TEXT (actor);
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
2012-06-18 01:03:58 +00:00
|
|
|
ClutterEventType type = clutter_event_type (event);
|
2008-12-11 11:40:55 +00:00
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
if (priv->in_select_drag)
|
|
|
|
{
|
2012-06-18 01:03:58 +00:00
|
|
|
if (type == CLUTTER_BUTTON_RELEASE)
|
|
|
|
{
|
|
|
|
if (!priv->in_select_touch)
|
|
|
|
{
|
|
|
|
clutter_ungrab_pointer ();
|
|
|
|
priv->in_select_drag = FALSE;
|
2008-12-11 11:40:55 +00:00
|
|
|
|
2012-06-18 01:03:58 +00:00
|
|
|
return CLUTTER_EVENT_STOP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (priv->in_select_touch)
|
|
|
|
{
|
|
|
|
ClutterInputDevice *device = clutter_event_get_device (event);
|
|
|
|
ClutterEventSequence *sequence =
|
|
|
|
clutter_event_get_event_sequence (event);
|
|
|
|
|
|
|
|
clutter_input_device_sequence_ungrab (device, sequence);
|
|
|
|
priv->in_select_touch = FALSE;
|
|
|
|
priv->in_select_drag = FALSE;
|
|
|
|
|
|
|
|
return CLUTTER_EVENT_STOP;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return CLUTTER_EVENT_PROPAGATE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
clutter_text_button_press (ClutterActor *actor,
|
|
|
|
ClutterButtonEvent *event)
|
|
|
|
{
|
|
|
|
return clutter_text_press (actor, (ClutterEvent *) event);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
clutter_text_motion (ClutterActor *actor,
|
|
|
|
ClutterMotionEvent *event)
|
|
|
|
{
|
|
|
|
return clutter_text_move (actor, (ClutterEvent *) event);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
clutter_text_button_release (ClutterActor *actor,
|
|
|
|
ClutterButtonEvent *event)
|
|
|
|
{
|
|
|
|
return clutter_text_release (actor, (ClutterEvent *) event);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
clutter_text_touch_event (ClutterActor *actor,
|
|
|
|
ClutterTouchEvent *event)
|
|
|
|
{
|
|
|
|
switch (event->type)
|
|
|
|
{
|
|
|
|
case CLUTTER_TOUCH_BEGIN:
|
|
|
|
return clutter_text_press (actor, (ClutterEvent *) event);
|
|
|
|
|
|
|
|
case CLUTTER_TOUCH_END:
|
|
|
|
case CLUTTER_TOUCH_CANCEL:
|
|
|
|
/* TODO: the cancel case probably need a special handler */
|
|
|
|
return clutter_text_release (actor, (ClutterEvent *) event);
|
|
|
|
|
|
|
|
case CLUTTER_TOUCH_UPDATE:
|
|
|
|
return clutter_text_move (actor, (ClutterEvent *) event);
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
2008-12-11 11:12:48 +00:00
|
|
|
}
|
2008-12-11 11:40:55 +00:00
|
|
|
|
2012-01-12 10:40:38 +00:00
|
|
|
return CLUTTER_EVENT_PROPAGATE;
|
2008-12-11 11:12:48 +00:00
|
|
|
}
|
|
|
|
|
2011-09-19 15:44:22 +00:00
|
|
|
static gboolean
|
|
|
|
clutter_text_remove_password_hint (gpointer data)
|
|
|
|
{
|
|
|
|
ClutterText *self = data;
|
|
|
|
|
|
|
|
self->priv->password_hint_visible = FALSE;
|
|
|
|
self->priv->password_hint_id = 0;
|
|
|
|
|
|
|
|
clutter_text_dirty_cache (data);
|
|
|
|
clutter_text_queue_redraw (data);
|
|
|
|
|
2012-01-12 10:40:38 +00:00
|
|
|
return G_SOURCE_REMOVE;
|
2011-09-19 15:44:22 +00:00
|
|
|
}
|
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
static gboolean
|
|
|
|
clutter_text_key_press (ClutterActor *actor,
|
2008-12-11 12:03:17 +00:00
|
|
|
ClutterKeyEvent *event)
|
2008-12-11 11:17:26 +00:00
|
|
|
{
|
2008-12-11 12:10:46 +00:00
|
|
|
ClutterText *self = CLUTTER_TEXT (actor);
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
2008-12-11 12:03:17 +00:00
|
|
|
ClutterBindingPool *pool;
|
|
|
|
gboolean res;
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
if (!priv->editable)
|
2012-01-12 10:40:38 +00:00
|
|
|
return CLUTTER_EVENT_PROPAGATE;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2009-03-30 15:57:11 +00:00
|
|
|
/* we need to use the ClutterText type name to find our own
|
|
|
|
* key bindings; subclasses will override or chain up this
|
|
|
|
* event handler, so they can do whatever they want there
|
|
|
|
*/
|
|
|
|
pool = clutter_binding_pool_find (g_type_name (CLUTTER_TYPE_TEXT));
|
2008-12-11 12:03:17 +00:00
|
|
|
g_assert (pool != NULL);
|
|
|
|
|
2008-12-11 12:24:45 +00:00
|
|
|
/* we allow passing synthetic events that only contain
|
|
|
|
* the Unicode value and not the key symbol
|
|
|
|
*/
|
2009-06-06 14:27:37 +00:00
|
|
|
if (event->keyval == 0 && (event->flags & CLUTTER_EVENT_FLAG_SYNTHETIC))
|
2008-12-11 12:24:45 +00:00
|
|
|
res = FALSE;
|
|
|
|
else
|
2009-06-06 14:27:37 +00:00
|
|
|
res = clutter_binding_pool_activate (pool, event->keyval,
|
2008-12-11 12:24:45 +00:00
|
|
|
event->modifier_state,
|
|
|
|
G_OBJECT (actor));
|
|
|
|
|
|
|
|
/* if the key binding has handled the event we bail out
|
|
|
|
* as fast as we can; otherwise, we try to insert the
|
|
|
|
* Unicode character inside the key event into the text
|
|
|
|
* actor
|
|
|
|
*/
|
2008-12-11 12:03:17 +00:00
|
|
|
if (res)
|
2012-01-12 10:40:38 +00:00
|
|
|
return CLUTTER_EVENT_STOP;
|
2009-08-17 16:43:42 +00:00
|
|
|
else if ((event->modifier_state & CLUTTER_CONTROL_MASK) == 0)
|
2008-12-11 11:33:10 +00:00
|
|
|
{
|
2009-06-06 14:27:37 +00:00
|
|
|
gunichar key_unichar;
|
|
|
|
|
2012-01-12 10:40:38 +00:00
|
|
|
/* Skip keys when control is pressed */
|
2009-06-06 14:27:37 +00:00
|
|
|
key_unichar = clutter_event_get_key_unicode ((ClutterEvent *) event);
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2008-12-11 12:24:45 +00:00
|
|
|
/* return is reported as CR, but we want LF */
|
|
|
|
if (key_unichar == '\r')
|
2008-12-11 11:33:10 +00:00
|
|
|
key_unichar = '\n';
|
|
|
|
|
2012-09-09 18:44:43 +00:00
|
|
|
if ((key_unichar == '\n' && !priv->single_line_mode) ||
|
2009-01-13 17:52:38 +00:00
|
|
|
(g_unichar_validate (key_unichar) &&
|
|
|
|
!g_unichar_iscntrl (key_unichar)))
|
2008-12-11 11:33:10 +00:00
|
|
|
{
|
2008-12-11 12:24:45 +00:00
|
|
|
/* truncate the eventual selection so that the
|
|
|
|
* Unicode character can replace it
|
|
|
|
*/
|
2009-05-06 16:08:25 +00:00
|
|
|
clutter_text_delete_selection (self);
|
2008-12-11 12:10:46 +00:00
|
|
|
clutter_text_insert_unichar (self, key_unichar);
|
2008-12-11 12:03:17 +00:00
|
|
|
|
2011-09-19 15:44:22 +00:00
|
|
|
if (priv->show_password_hint)
|
|
|
|
{
|
|
|
|
if (priv->password_hint_id != 0)
|
|
|
|
g_source_remove (priv->password_hint_id);
|
|
|
|
|
|
|
|
priv->password_hint_visible = TRUE;
|
|
|
|
priv->password_hint_id =
|
2012-01-12 10:40:38 +00:00
|
|
|
clutter_threads_add_timeout (priv->password_hint_timeout,
|
|
|
|
clutter_text_remove_password_hint,
|
|
|
|
self);
|
2011-09-19 15:44:22 +00:00
|
|
|
}
|
|
|
|
|
2012-01-12 10:40:38 +00:00
|
|
|
return CLUTTER_EVENT_STOP;
|
2008-12-11 11:33:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2012-01-12 10:40:38 +00:00
|
|
|
return CLUTTER_EVENT_PROPAGATE;
|
2008-12-11 11:33:10 +00:00
|
|
|
}
|
|
|
|
|
2012-06-07 15:14:21 +00:00
|
|
|
static void
|
|
|
|
clutter_text_compute_layout_offsets (ClutterText *self,
|
|
|
|
PangoLayout *layout,
|
|
|
|
const ClutterActorBox *alloc,
|
|
|
|
int *text_x,
|
|
|
|
int *text_y)
|
|
|
|
{
|
|
|
|
ClutterActor *actor = CLUTTER_ACTOR (self);
|
|
|
|
ClutterActorAlign x_align, y_align;
|
|
|
|
PangoRectangle logical_rect;
|
|
|
|
float alloc_width, alloc_height;
|
|
|
|
float x, y;
|
|
|
|
|
|
|
|
clutter_actor_box_get_size (alloc, &alloc_width, &alloc_height);
|
|
|
|
pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
|
|
|
|
|
|
|
|
if (clutter_actor_needs_expand (actor, CLUTTER_ORIENTATION_HORIZONTAL))
|
|
|
|
x_align = _clutter_actor_get_effective_x_align (actor);
|
|
|
|
else
|
|
|
|
x_align = CLUTTER_ACTOR_ALIGN_FILL;
|
|
|
|
|
|
|
|
if (clutter_actor_needs_expand (actor, CLUTTER_ORIENTATION_VERTICAL))
|
|
|
|
y_align = clutter_actor_get_y_align (actor);
|
|
|
|
else
|
|
|
|
y_align = CLUTTER_ACTOR_ALIGN_FILL;
|
|
|
|
|
|
|
|
x = 0.f;
|
|
|
|
switch (x_align)
|
|
|
|
{
|
|
|
|
case CLUTTER_ACTOR_ALIGN_FILL:
|
|
|
|
case CLUTTER_ACTOR_ALIGN_START:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CLUTTER_ACTOR_ALIGN_END:
|
|
|
|
if (alloc_width > logical_rect.width)
|
|
|
|
x = alloc_width - logical_rect.width;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CLUTTER_ACTOR_ALIGN_CENTER:
|
|
|
|
if (alloc_width > logical_rect.width)
|
|
|
|
x = (alloc_width - logical_rect.width) / 2.f;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
y = 0.f;
|
|
|
|
switch (y_align)
|
|
|
|
{
|
|
|
|
case CLUTTER_ACTOR_ALIGN_FILL:
|
|
|
|
case CLUTTER_ACTOR_ALIGN_START:
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CLUTTER_ACTOR_ALIGN_END:
|
|
|
|
if (alloc_height > logical_rect.height)
|
|
|
|
y = alloc_height - logical_rect.height;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case CLUTTER_ACTOR_ALIGN_CENTER:
|
|
|
|
if (alloc_height > logical_rect.height)
|
|
|
|
y = (alloc_height - logical_rect.height) / 2.f;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (text_x != NULL)
|
|
|
|
*text_x = floorf (x);
|
|
|
|
|
|
|
|
if (text_y != NULL)
|
|
|
|
*text_y = floorf (y);
|
|
|
|
}
|
|
|
|
|
2009-01-07 00:25:24 +00:00
|
|
|
#define TEXT_PADDING 2
|
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
static void
|
|
|
|
clutter_text_paint (ClutterActor *self)
|
|
|
|
{
|
|
|
|
ClutterText *text = CLUTTER_TEXT (self);
|
|
|
|
ClutterTextPrivate *priv = text->priv;
|
|
|
|
PangoLayout *layout;
|
|
|
|
ClutterActorBox alloc = { 0, };
|
|
|
|
CoglColor color = { 0, };
|
2008-12-11 12:18:26 +00:00
|
|
|
guint8 real_opacity;
|
2009-01-07 00:25:24 +00:00
|
|
|
gint text_x = priv->text_x;
|
2012-06-07 15:14:21 +00:00
|
|
|
gint text_y = priv->text_y;
|
2009-01-07 00:25:24 +00:00
|
|
|
gboolean clip_set = FALSE;
|
2012-03-06 15:06:52 +00:00
|
|
|
gboolean bg_color_set = FALSE;
|
2011-06-15 09:06:31 +00:00
|
|
|
guint n_chars;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2011-03-07 18:53:07 +00:00
|
|
|
/* Note that if anything in this paint method changes it needs to be
|
|
|
|
reflected in the get_paint_volume implementation which is tightly
|
|
|
|
tied to the workings of this function */
|
2011-06-15 09:06:31 +00:00
|
|
|
n_chars = clutter_text_buffer_get_length (get_buffer (text));
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2008-12-11 11:17:26 +00:00
|
|
|
clutter_actor_get_allocation_box (self, &alloc);
|
2010-07-09 17:37:34 +00:00
|
|
|
|
2012-03-06 15:06:52 +00:00
|
|
|
g_object_get (self, "background-color-set", &bg_color_set, NULL);
|
|
|
|
if (bg_color_set)
|
|
|
|
{
|
|
|
|
ClutterColor bg_color;
|
|
|
|
|
|
|
|
clutter_actor_get_background_color (self, &bg_color);
|
|
|
|
bg_color.alpha = clutter_actor_get_paint_opacity (self)
|
|
|
|
* bg_color.alpha
|
|
|
|
/ 255;
|
|
|
|
|
|
|
|
cogl_set_source_color4ub (bg_color.red,
|
|
|
|
bg_color.green,
|
|
|
|
bg_color.blue,
|
|
|
|
bg_color.alpha);
|
|
|
|
cogl_rectangle (0, 0, alloc.x2 - alloc.x1, alloc.y2 - alloc.y1);
|
|
|
|
}
|
|
|
|
|
2012-07-25 16:34:03 +00:00
|
|
|
/* don't bother painting an empty text actor, unless it's
|
|
|
|
* editable, in which case we want to paint at least the
|
|
|
|
* cursor
|
|
|
|
*/
|
|
|
|
if (n_chars == 0 && (!priv->editable || !priv->cursor_visible))
|
|
|
|
return;
|
|
|
|
|
2010-07-09 17:37:34 +00:00
|
|
|
if (priv->editable && priv->single_line_mode)
|
|
|
|
layout = clutter_text_create_layout (text, -1, -1);
|
|
|
|
else
|
2011-09-04 16:57:50 +00:00
|
|
|
{
|
|
|
|
/* the only time when we create the PangoLayout using the full
|
|
|
|
* width and height of the allocation is when we can both wrap
|
|
|
|
* and ellipsize
|
|
|
|
*/
|
|
|
|
if (priv->wrap && priv->ellipsize)
|
|
|
|
{
|
|
|
|
layout = clutter_text_create_layout (text,
|
|
|
|
alloc.x2 - alloc.x1,
|
|
|
|
alloc.y2 - alloc.y1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* if we're not wrapping we cannot set the height of the
|
|
|
|
* layout, otherwise Pango will happily wrap the text to
|
|
|
|
* fit in the rectangle - thus making the :wrap property
|
|
|
|
* useless
|
|
|
|
*
|
|
|
|
* see bug:
|
|
|
|
*
|
|
|
|
* http://bugzilla.clutter-project.org/show_bug.cgi?id=2339
|
|
|
|
*
|
|
|
|
* in order to fix this, we create a layout that would fit
|
|
|
|
* in the assigned width, then we clip the actor if the
|
|
|
|
* logical rectangle overflows the allocation.
|
|
|
|
*/
|
|
|
|
layout = clutter_text_create_layout (text,
|
|
|
|
alloc.x2 - alloc.x1,
|
|
|
|
-1);
|
|
|
|
}
|
|
|
|
}
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2009-01-07 13:14:13 +00:00
|
|
|
if (priv->editable && priv->cursor_visible)
|
|
|
|
clutter_text_ensure_cursor_position (text);
|
|
|
|
|
|
|
|
if (priv->editable && priv->single_line_mode)
|
2009-01-07 00:25:24 +00:00
|
|
|
{
|
|
|
|
PangoRectangle logical_rect = { 0, };
|
|
|
|
gint actor_width, text_width;
|
|
|
|
|
|
|
|
pango_layout_get_extents (layout, NULL, &logical_rect);
|
|
|
|
|
2009-11-05 16:50:24 +00:00
|
|
|
cogl_clip_push_rectangle (0, 0,
|
|
|
|
(alloc.x2 - alloc.x1),
|
|
|
|
(alloc.y2 - alloc.y1));
|
2009-01-07 00:25:24 +00:00
|
|
|
clip_set = TRUE;
|
|
|
|
|
2009-06-02 17:44:30 +00:00
|
|
|
actor_width = (alloc.x2 - alloc.x1)
|
2009-01-07 00:25:24 +00:00
|
|
|
- 2 * TEXT_PADDING;
|
|
|
|
text_width = logical_rect.width / PANGO_SCALE;
|
|
|
|
|
|
|
|
if (actor_width < text_width)
|
|
|
|
{
|
2013-03-26 22:03:19 +00:00
|
|
|
gint cursor_x = clutter_rect_get_x (&priv->cursor_rect);
|
2009-01-07 00:25:24 +00:00
|
|
|
|
|
|
|
if (priv->position == -1)
|
|
|
|
{
|
|
|
|
text_x = actor_width - text_width;
|
|
|
|
}
|
|
|
|
else if (priv->position == 0)
|
|
|
|
{
|
2009-05-14 09:17:24 +00:00
|
|
|
text_x = TEXT_PADDING;
|
2009-01-07 00:25:24 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-05-14 12:31:51 +00:00
|
|
|
if (cursor_x < 0)
|
2009-01-07 00:25:24 +00:00
|
|
|
{
|
2009-05-14 12:31:51 +00:00
|
|
|
text_x = text_x - cursor_x - TEXT_PADDING;
|
|
|
|
}
|
|
|
|
else if (cursor_x > actor_width)
|
|
|
|
{
|
|
|
|
text_x = text_x + (actor_width - cursor_x) - TEXT_PADDING;
|
2009-01-07 00:25:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-05-14 09:17:24 +00:00
|
|
|
text_x = TEXT_PADDING;
|
2009-01-07 00:25:24 +00:00
|
|
|
}
|
|
|
|
}
|
2011-09-04 16:57:50 +00:00
|
|
|
else if (!priv->editable && !(priv->wrap && priv->ellipsize))
|
|
|
|
{
|
|
|
|
PangoRectangle logical_rect = { 0, };
|
|
|
|
|
|
|
|
pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
|
|
|
|
|
|
|
|
/* don't clip if the layout managed to fit inside our allocation */
|
|
|
|
if (logical_rect.width > (alloc.x2 - alloc.x1) ||
|
|
|
|
logical_rect.height > (alloc.y2 - alloc.y1))
|
|
|
|
{
|
|
|
|
cogl_clip_push_rectangle (0, 0,
|
|
|
|
alloc.x2 - alloc.x1,
|
|
|
|
alloc.y2 - alloc.y1);
|
|
|
|
clip_set = TRUE;
|
|
|
|
}
|
|
|
|
|
2012-06-07 15:14:21 +00:00
|
|
|
clutter_text_compute_layout_offsets (text, layout, &alloc, &text_x, &text_y);
|
2011-09-04 16:57:50 +00:00
|
|
|
}
|
2009-01-07 00:25:24 +00:00
|
|
|
else
|
2012-06-07 15:14:21 +00:00
|
|
|
clutter_text_compute_layout_offsets (text, layout, &alloc, &text_x, &text_y);
|
2009-01-07 00:25:24 +00:00
|
|
|
|
2012-06-07 15:14:21 +00:00
|
|
|
if (priv->text_x != text_x ||
|
|
|
|
priv->text_y != text_y)
|
2011-07-03 20:43:17 +00:00
|
|
|
{
|
|
|
|
priv->text_x = text_x;
|
2012-06-07 15:14:21 +00:00
|
|
|
priv->text_y = text_y;
|
|
|
|
|
2011-07-03 20:43:17 +00:00
|
|
|
clutter_text_ensure_cursor_position (text);
|
|
|
|
}
|
2009-05-14 12:31:51 +00:00
|
|
|
|
2008-12-11 12:18:26 +00:00
|
|
|
real_opacity = clutter_actor_get_paint_opacity (self)
|
|
|
|
* priv->text_color.alpha
|
|
|
|
/ 255;
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
CLUTTER_NOTE (PAINT, "painting text (text: '%s')",
|
|
|
|
clutter_text_buffer_get_text (get_buffer (text)));
|
2009-01-07 00:25:24 +00:00
|
|
|
|
2010-09-03 15:55:12 +00:00
|
|
|
cogl_color_init_from_4ub (&color,
|
|
|
|
priv->text_color.red,
|
|
|
|
priv->text_color.green,
|
|
|
|
priv->text_color.blue,
|
|
|
|
real_opacity);
|
2012-06-07 15:14:21 +00:00
|
|
|
cogl_pango_render_layout (layout, priv->text_x, priv->text_y, &color, 0);
|
2009-01-07 00:25:24 +00:00
|
|
|
|
2011-05-13 13:26:22 +00:00
|
|
|
selection_paint (text);
|
2011-03-02 17:02:56 +00:00
|
|
|
|
2009-01-07 00:25:24 +00:00
|
|
|
if (clip_set)
|
2009-02-12 11:08:00 +00:00
|
|
|
cogl_clip_pop ();
|
2008-12-11 11:17:26 +00:00
|
|
|
}
|
|
|
|
|
2011-03-07 18:53:07 +00:00
|
|
|
static void
|
2011-07-10 09:24:40 +00:00
|
|
|
add_selection_to_paint_volume (ClutterText *text,
|
|
|
|
const ClutterActorBox *box,
|
|
|
|
gpointer user_data)
|
2011-03-07 18:53:07 +00:00
|
|
|
{
|
|
|
|
ClutterPaintVolume *total_volume = user_data;
|
|
|
|
ClutterPaintVolume rect_volume;
|
|
|
|
ClutterVertex vertex;
|
|
|
|
|
|
|
|
_clutter_paint_volume_init_static (&rect_volume, CLUTTER_ACTOR (text));
|
|
|
|
|
|
|
|
vertex.x = box->x1;
|
|
|
|
vertex.y = box->y1;
|
|
|
|
vertex.z = 0.0f;
|
|
|
|
clutter_paint_volume_set_origin (&rect_volume, &vertex);
|
|
|
|
clutter_paint_volume_set_width (&rect_volume, box->x2 - box->x1);
|
|
|
|
clutter_paint_volume_set_height (&rect_volume, box->y2 - box->y1);
|
|
|
|
|
|
|
|
clutter_paint_volume_union (total_volume, &rect_volume);
|
|
|
|
|
|
|
|
clutter_paint_volume_free (&rect_volume);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clutter_text_get_paint_volume_for_cursor (ClutterText *text,
|
|
|
|
ClutterPaintVolume *volume)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = text->priv;
|
|
|
|
ClutterVertex origin;
|
|
|
|
|
|
|
|
clutter_text_ensure_cursor_position (text);
|
|
|
|
|
|
|
|
if (priv->position == priv->selection_bound)
|
|
|
|
{
|
2013-03-26 22:03:19 +00:00
|
|
|
origin.x = priv->cursor_rect.origin.x;
|
|
|
|
origin.y = priv->cursor_rect.origin.y;
|
2011-03-07 18:53:07 +00:00
|
|
|
origin.z = 0;
|
2013-03-26 22:03:19 +00:00
|
|
|
|
2011-03-07 18:53:07 +00:00
|
|
|
clutter_paint_volume_set_origin (volume, &origin);
|
2013-03-26 22:03:19 +00:00
|
|
|
clutter_paint_volume_set_width (volume, priv->cursor_rect.size.width);
|
|
|
|
clutter_paint_volume_set_height (volume, priv->cursor_rect.size.height);
|
2011-03-07 18:53:07 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-07-10 09:24:40 +00:00
|
|
|
clutter_text_foreach_selection_rectangle (text,
|
|
|
|
add_selection_to_paint_volume,
|
|
|
|
volume);
|
2011-03-07 18:53:07 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-09-08 18:47:11 +00:00
|
|
|
static gboolean
|
2010-09-09 11:38:25 +00:00
|
|
|
clutter_text_get_paint_volume (ClutterActor *self,
|
2010-09-08 18:47:11 +00:00
|
|
|
ClutterPaintVolume *volume)
|
|
|
|
{
|
2011-03-07 18:53:07 +00:00
|
|
|
ClutterText *text = CLUTTER_TEXT (self);
|
|
|
|
ClutterTextPrivate *priv = text->priv;
|
|
|
|
|
|
|
|
/* ClutterText uses the logical layout as the natural size of the
|
|
|
|
actor. This means that it can sometimes paint outside of its
|
|
|
|
allocation for example with italic fonts with serifs. Therefore
|
|
|
|
we should use the ink rectangle of the layout instead */
|
|
|
|
|
|
|
|
if (!priv->paint_volume_valid)
|
|
|
|
{
|
|
|
|
PangoLayout *layout;
|
|
|
|
PangoRectangle ink_rect;
|
|
|
|
ClutterVertex origin;
|
|
|
|
|
|
|
|
/* If the text is single line editable then it gets clipped to
|
|
|
|
the allocation anyway so we can just use that */
|
|
|
|
if (priv->editable && priv->single_line_mode)
|
|
|
|
return _clutter_actor_set_default_paint_volume (self,
|
|
|
|
CLUTTER_TYPE_TEXT,
|
|
|
|
volume);
|
|
|
|
|
|
|
|
if (G_OBJECT_TYPE (self) != CLUTTER_TYPE_TEXT)
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
if (!clutter_actor_has_allocation (self))
|
|
|
|
return FALSE;
|
|
|
|
|
|
|
|
_clutter_paint_volume_init_static (&priv->paint_volume, self);
|
|
|
|
|
|
|
|
layout = clutter_text_get_layout (text);
|
|
|
|
pango_layout_get_extents (layout, &ink_rect, NULL);
|
|
|
|
|
|
|
|
origin.x = ink_rect.x / (float) PANGO_SCALE;
|
|
|
|
origin.y = ink_rect.y / (float) PANGO_SCALE;
|
|
|
|
origin.z = 0;
|
|
|
|
clutter_paint_volume_set_origin (&priv->paint_volume, &origin);
|
|
|
|
clutter_paint_volume_set_width (&priv->paint_volume,
|
|
|
|
ink_rect.width / (float) PANGO_SCALE);
|
|
|
|
clutter_paint_volume_set_height (&priv->paint_volume,
|
|
|
|
ink_rect.height / (float) PANGO_SCALE);
|
|
|
|
|
|
|
|
/* If the cursor is visible then that will likely be drawn
|
|
|
|
outside of the ink rectangle so we should merge that in */
|
|
|
|
if (priv->editable && priv->cursor_visible && priv->has_focus)
|
|
|
|
{
|
|
|
|
ClutterPaintVolume cursor_paint_volume;
|
|
|
|
|
|
|
|
_clutter_paint_volume_init_static (&cursor_paint_volume,
|
|
|
|
self);
|
|
|
|
|
|
|
|
clutter_text_get_paint_volume_for_cursor (text, &cursor_paint_volume);
|
|
|
|
|
|
|
|
clutter_paint_volume_union (&priv->paint_volume,
|
|
|
|
&cursor_paint_volume);
|
|
|
|
|
|
|
|
clutter_paint_volume_free (&cursor_paint_volume);
|
|
|
|
}
|
|
|
|
|
|
|
|
priv->paint_volume_valid = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
_clutter_paint_volume_copy_static (&priv->paint_volume, volume);
|
|
|
|
|
|
|
|
return TRUE;
|
2010-09-08 18:47:11 +00:00
|
|
|
}
|
|
|
|
|
2008-12-11 11:17:26 +00:00
|
|
|
static void
|
|
|
|
clutter_text_get_preferred_width (ClutterActor *self,
|
Remove Units from the public API
With the recent change to internal floating point values, ClutterUnit
has become a redundant type, defined to be a float. All integer entry
points are being internally converted to floating point values to be
passed to the GL pipeline with the least amount of conversion.
ClutterUnit is thus exposed as just a "pixel with fractionary bits",
and not -- as users might think -- as generic, resolution and device
independent units. not that it was the case, but a definitive amount
of people was convinced it did provide this "feature", and was flummoxed
about the mere existence of this type.
So, having ClutterUnit exposed in the public API doubles the entry
points and has the following disadvantages:
- we have to maintain twice the amount of entry points in ClutterActor
- we still do an integer-to-float implicit conversion
- we introduce a weird impedance between pixels and "pixels with
fractionary bits"
- language bindings will have to choose what to bind, and resort
to manually overriding the API
+ *except* for language bindings based on GObject-Introspection, as
they cannot do manual overrides, thus will replicate the entire
set of entry points
For these reason, we should coalesces every Actor entry point for
pixels and for ClutterUnit into a single entry point taking a float,
like:
void clutter_actor_set_x (ClutterActor *self,
gfloat x);
void clutter_actor_get_size (ClutterActor *self,
gfloat *width,
gfloat *height);
gfloat clutter_actor_get_height (ClutterActor *self);
etc.
The issues I have identified are:
- we'll have a two cases of compiler warnings:
- printf() format of the return values from %d to %f
- clutter_actor_get_size() taking floats instead of unsigned ints
- we'll have a problem with varargs when passing an integer instead
of a floating point value, except on 64bit platforms where the
size of a float is the same as the size of an int
To be clear: the *intent* of the API should not change -- we still use
pixels everywhere -- but:
- we remove ambiguity in the API with regard to pixels and units
- we remove entry points we get to maintain for the whole 1.0
version of the API
- we make things simpler to bind for both manual language bindings
and automatic (gobject-introspection based) ones
- we have the simplest API possible while still exposing the
capabilities of the underlying GL implementation
2009-05-06 15:44:47 +00:00
|
|
|
gfloat for_height,
|
|
|
|
gfloat *min_width_p,
|
|
|
|
gfloat *natural_width_p)
|
2008-12-11 11:17:26 +00:00
|
|
|
{
|
|
|
|
ClutterText *text = CLUTTER_TEXT (self);
|
|
|
|
ClutterTextPrivate *priv = text->priv;
|
|
|
|
PangoRectangle logical_rect = { 0, };
|
|
|
|
PangoLayout *layout;
|
2008-12-15 18:24:42 +00:00
|
|
|
gint logical_width;
|
Remove Units from the public API
With the recent change to internal floating point values, ClutterUnit
has become a redundant type, defined to be a float. All integer entry
points are being internally converted to floating point values to be
passed to the GL pipeline with the least amount of conversion.
ClutterUnit is thus exposed as just a "pixel with fractionary bits",
and not -- as users might think -- as generic, resolution and device
independent units. not that it was the case, but a definitive amount
of people was convinced it did provide this "feature", and was flummoxed
about the mere existence of this type.
So, having ClutterUnit exposed in the public API doubles the entry
points and has the following disadvantages:
- we have to maintain twice the amount of entry points in ClutterActor
- we still do an integer-to-float implicit conversion
- we introduce a weird impedance between pixels and "pixels with
fractionary bits"
- language bindings will have to choose what to bind, and resort
to manually overriding the API
+ *except* for language bindings based on GObject-Introspection, as
they cannot do manual overrides, thus will replicate the entire
set of entry points
For these reason, we should coalesces every Actor entry point for
pixels and for ClutterUnit into a single entry point taking a float,
like:
void clutter_actor_set_x (ClutterActor *self,
gfloat x);
void clutter_actor_get_size (ClutterActor *self,
gfloat *width,
gfloat *height);
gfloat clutter_actor_get_height (ClutterActor *self);
etc.
The issues I have identified are:
- we'll have a two cases of compiler warnings:
- printf() format of the return values from %d to %f
- clutter_actor_get_size() taking floats instead of unsigned ints
- we'll have a problem with varargs when passing an integer instead
of a floating point value, except on 64bit platforms where the
size of a float is the same as the size of an int
To be clear: the *intent* of the API should not change -- we still use
pixels everywhere -- but:
- we remove ambiguity in the API with regard to pixels and units
- we remove entry points we get to maintain for the whole 1.0
version of the API
- we make things simpler to bind for both manual language bindings
and automatic (gobject-introspection based) ones
- we have the simplest API possible while still exposing the
capabilities of the underlying GL implementation
2009-05-06 15:44:47 +00:00
|
|
|
gfloat layout_width;
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2008-12-16 14:02:05 +00:00
|
|
|
layout = clutter_text_create_layout (text, -1, -1);
|
2008-12-11 11:17:26 +00:00
|
|
|
|
|
|
|
pango_layout_get_extents (layout, NULL, &logical_rect);
|
|
|
|
|
2008-12-15 18:24:42 +00:00
|
|
|
/* the X coordinate of the logical rectangle might be non-zero
|
|
|
|
* according to the Pango documentation; hence, we need to offset
|
|
|
|
* the width accordingly
|
|
|
|
*/
|
|
|
|
logical_width = logical_rect.x + logical_rect.width;
|
|
|
|
|
|
|
|
layout_width = logical_width > 0
|
2011-02-21 17:13:37 +00:00
|
|
|
? ceilf (logical_width / 1024.0f)
|
2008-12-11 11:17:26 +00:00
|
|
|
: 1;
|
|
|
|
|
|
|
|
if (min_width_p)
|
|
|
|
{
|
2009-04-16 15:34:15 +00:00
|
|
|
if (priv->wrap || priv->ellipsize || priv->editable)
|
2008-12-11 11:17:26 +00:00
|
|
|
*min_width_p = 1;
|
|
|
|
else
|
|
|
|
*min_width_p = layout_width;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (natural_width_p)
|
2009-05-14 08:53:41 +00:00
|
|
|
{
|
|
|
|
if (priv->editable && priv->single_line_mode)
|
|
|
|
*natural_width_p = layout_width + TEXT_PADDING * 2;
|
|
|
|
else
|
|
|
|
*natural_width_p = layout_width;
|
|
|
|
}
|
2008-12-11 11:17:26 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clutter_text_get_preferred_height (ClutterActor *self,
|
Remove Units from the public API
With the recent change to internal floating point values, ClutterUnit
has become a redundant type, defined to be a float. All integer entry
points are being internally converted to floating point values to be
passed to the GL pipeline with the least amount of conversion.
ClutterUnit is thus exposed as just a "pixel with fractionary bits",
and not -- as users might think -- as generic, resolution and device
independent units. not that it was the case, but a definitive amount
of people was convinced it did provide this "feature", and was flummoxed
about the mere existence of this type.
So, having ClutterUnit exposed in the public API doubles the entry
points and has the following disadvantages:
- we have to maintain twice the amount of entry points in ClutterActor
- we still do an integer-to-float implicit conversion
- we introduce a weird impedance between pixels and "pixels with
fractionary bits"
- language bindings will have to choose what to bind, and resort
to manually overriding the API
+ *except* for language bindings based on GObject-Introspection, as
they cannot do manual overrides, thus will replicate the entire
set of entry points
For these reason, we should coalesces every Actor entry point for
pixels and for ClutterUnit into a single entry point taking a float,
like:
void clutter_actor_set_x (ClutterActor *self,
gfloat x);
void clutter_actor_get_size (ClutterActor *self,
gfloat *width,
gfloat *height);
gfloat clutter_actor_get_height (ClutterActor *self);
etc.
The issues I have identified are:
- we'll have a two cases of compiler warnings:
- printf() format of the return values from %d to %f
- clutter_actor_get_size() taking floats instead of unsigned ints
- we'll have a problem with varargs when passing an integer instead
of a floating point value, except on 64bit platforms where the
size of a float is the same as the size of an int
To be clear: the *intent* of the API should not change -- we still use
pixels everywhere -- but:
- we remove ambiguity in the API with regard to pixels and units
- we remove entry points we get to maintain for the whole 1.0
version of the API
- we make things simpler to bind for both manual language bindings
and automatic (gobject-introspection based) ones
- we have the simplest API possible while still exposing the
capabilities of the underlying GL implementation
2009-05-06 15:44:47 +00:00
|
|
|
gfloat for_width,
|
|
|
|
gfloat *min_height_p,
|
|
|
|
gfloat *natural_height_p)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
2009-05-13 22:04:25 +00:00
|
|
|
ClutterTextPrivate *priv = CLUTTER_TEXT (self)->priv;
|
2008-12-11 11:17:26 +00:00
|
|
|
|
|
|
|
if (for_width == 0)
|
|
|
|
{
|
|
|
|
if (min_height_p)
|
|
|
|
*min_height_p = 0;
|
|
|
|
|
|
|
|
if (natural_height_p)
|
|
|
|
*natural_height_p = 0;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
PangoLayout *layout;
|
|
|
|
PangoRectangle logical_rect = { 0, };
|
2008-12-15 18:24:42 +00:00
|
|
|
gint logical_height;
|
Remove Units from the public API
With the recent change to internal floating point values, ClutterUnit
has become a redundant type, defined to be a float. All integer entry
points are being internally converted to floating point values to be
passed to the GL pipeline with the least amount of conversion.
ClutterUnit is thus exposed as just a "pixel with fractionary bits",
and not -- as users might think -- as generic, resolution and device
independent units. not that it was the case, but a definitive amount
of people was convinced it did provide this "feature", and was flummoxed
about the mere existence of this type.
So, having ClutterUnit exposed in the public API doubles the entry
points and has the following disadvantages:
- we have to maintain twice the amount of entry points in ClutterActor
- we still do an integer-to-float implicit conversion
- we introduce a weird impedance between pixels and "pixels with
fractionary bits"
- language bindings will have to choose what to bind, and resort
to manually overriding the API
+ *except* for language bindings based on GObject-Introspection, as
they cannot do manual overrides, thus will replicate the entire
set of entry points
For these reason, we should coalesces every Actor entry point for
pixels and for ClutterUnit into a single entry point taking a float,
like:
void clutter_actor_set_x (ClutterActor *self,
gfloat x);
void clutter_actor_get_size (ClutterActor *self,
gfloat *width,
gfloat *height);
gfloat clutter_actor_get_height (ClutterActor *self);
etc.
The issues I have identified are:
- we'll have a two cases of compiler warnings:
- printf() format of the return values from %d to %f
- clutter_actor_get_size() taking floats instead of unsigned ints
- we'll have a problem with varargs when passing an integer instead
of a floating point value, except on 64bit platforms where the
size of a float is the same as the size of an int
To be clear: the *intent* of the API should not change -- we still use
pixels everywhere -- but:
- we remove ambiguity in the API with regard to pixels and units
- we remove entry points we get to maintain for the whole 1.0
version of the API
- we make things simpler to bind for both manual language bindings
and automatic (gobject-introspection based) ones
- we have the simplest API possible while still exposing the
capabilities of the underlying GL implementation
2009-05-06 15:44:47 +00:00
|
|
|
gfloat layout_height;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2010-11-25 15:11:42 +00:00
|
|
|
if (priv->single_line_mode)
|
|
|
|
for_width = -1;
|
|
|
|
|
2009-05-13 22:04:25 +00:00
|
|
|
layout = clutter_text_create_layout (CLUTTER_TEXT (self),
|
|
|
|
for_width, -1);
|
2008-12-11 11:17:26 +00:00
|
|
|
|
|
|
|
pango_layout_get_extents (layout, NULL, &logical_rect);
|
2008-12-15 18:24:42 +00:00
|
|
|
|
|
|
|
/* the Y coordinate of the logical rectangle might be non-zero
|
|
|
|
* according to the Pango documentation; hence, we need to offset
|
|
|
|
* the height accordingly
|
|
|
|
*/
|
|
|
|
logical_height = logical_rect.y + logical_rect.height;
|
2011-02-21 17:13:37 +00:00
|
|
|
layout_height = ceilf (logical_height / 1024.0f);
|
2008-12-11 11:17:26 +00:00
|
|
|
|
|
|
|
if (min_height_p)
|
2008-12-16 14:02:05 +00:00
|
|
|
{
|
2009-05-13 22:04:25 +00:00
|
|
|
/* if we wrap and ellipsize then the minimum height is
|
|
|
|
* going to be at least the size of the first line
|
|
|
|
*/
|
2010-11-25 15:11:42 +00:00
|
|
|
if ((priv->ellipsize && priv->wrap) && !priv->single_line_mode)
|
2009-05-13 22:04:25 +00:00
|
|
|
{
|
|
|
|
PangoLayoutLine *line;
|
2009-06-02 17:44:30 +00:00
|
|
|
gfloat line_height;
|
2009-05-13 22:04:25 +00:00
|
|
|
|
|
|
|
line = pango_layout_get_line_readonly (layout, 0);
|
|
|
|
pango_layout_line_get_extents (line, NULL, &logical_rect);
|
|
|
|
|
|
|
|
logical_height = logical_rect.y + logical_rect.height;
|
2011-02-21 17:13:37 +00:00
|
|
|
line_height = ceilf (logical_height / 1024.0f);
|
2009-05-13 22:04:25 +00:00
|
|
|
|
|
|
|
*min_height_p = line_height;
|
|
|
|
}
|
2008-12-16 14:02:05 +00:00
|
|
|
else
|
|
|
|
*min_height_p = layout_height;
|
|
|
|
}
|
2008-12-11 11:17:26 +00:00
|
|
|
|
|
|
|
if (natural_height_p)
|
2008-12-15 18:24:42 +00:00
|
|
|
*natural_height_p = layout_height;
|
2008-12-11 11:17:26 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2009-06-03 13:02:06 +00:00
|
|
|
clutter_text_allocate (ClutterActor *self,
|
|
|
|
const ClutterActorBox *box,
|
|
|
|
ClutterAllocationFlags flags)
|
2008-12-11 11:17:26 +00:00
|
|
|
{
|
|
|
|
ClutterText *text = CLUTTER_TEXT (self);
|
|
|
|
ClutterActorClass *parent_class;
|
|
|
|
|
2008-12-11 11:40:55 +00:00
|
|
|
/* Ensure that there is a cached layout with the right width so
|
|
|
|
* that we don't need to create the text during the paint run
|
2010-07-09 17:37:34 +00:00
|
|
|
*
|
|
|
|
* if the Text is editable and in single line mode we don't want
|
|
|
|
* to have any limit on the layout size, since the paint will clip
|
|
|
|
* it to the allocation of the actor
|
2008-12-11 11:40:55 +00:00
|
|
|
*/
|
2010-07-09 17:37:34 +00:00
|
|
|
if (text->priv->editable && text->priv->single_line_mode)
|
|
|
|
clutter_text_create_layout (text, -1, -1);
|
|
|
|
else
|
|
|
|
clutter_text_create_layout (text,
|
|
|
|
box->x2 - box->x1,
|
|
|
|
box->y2 - box->y1);
|
2008-12-11 11:17:26 +00:00
|
|
|
|
|
|
|
parent_class = CLUTTER_ACTOR_CLASS (clutter_text_parent_class);
|
2009-06-03 13:02:06 +00:00
|
|
|
parent_class->allocate (self, box, flags);
|
2008-12-11 11:17:26 +00:00
|
|
|
}
|
|
|
|
|
2011-05-13 13:17:39 +00:00
|
|
|
static gboolean
|
|
|
|
clutter_text_has_overlaps (ClutterActor *self)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = CLUTTER_TEXT (self)->priv;
|
|
|
|
|
|
|
|
return priv->editable ||
|
|
|
|
priv->selectable ||
|
|
|
|
priv->cursor_visible;
|
|
|
|
}
|
|
|
|
|
2010-12-21 10:50:24 +00:00
|
|
|
static void
|
|
|
|
clutter_text_key_focus_in (ClutterActor *actor)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = CLUTTER_TEXT (actor)->priv;
|
|
|
|
|
|
|
|
priv->has_focus = TRUE;
|
|
|
|
|
2011-03-07 18:53:07 +00:00
|
|
|
clutter_text_queue_redraw (actor);
|
2010-12-21 10:50:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clutter_text_key_focus_out (ClutterActor *actor)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = CLUTTER_TEXT (actor)->priv;
|
|
|
|
|
|
|
|
priv->has_focus = FALSE;
|
|
|
|
|
2011-03-07 18:53:07 +00:00
|
|
|
clutter_text_queue_redraw (actor);
|
2010-12-21 10:50:24 +00:00
|
|
|
}
|
|
|
|
|
2008-12-11 12:03:17 +00:00
|
|
|
static gboolean
|
|
|
|
clutter_text_real_move_left (ClutterText *self,
|
|
|
|
const gchar *action,
|
|
|
|
guint keyval,
|
|
|
|
ClutterModifierType modifiers)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
|
|
|
gint pos = priv->position;
|
2009-07-23 18:04:27 +00:00
|
|
|
gint new_pos = 0;
|
2008-12-11 12:03:17 +00:00
|
|
|
gint len;
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
len = clutter_text_buffer_get_length (get_buffer (self));
|
2008-12-11 12:03:17 +00:00
|
|
|
|
2010-01-25 15:13:58 +00:00
|
|
|
g_object_freeze_notify (G_OBJECT (self));
|
|
|
|
|
2009-03-30 15:46:57 +00:00
|
|
|
if (pos != 0 && len != 0)
|
2008-12-11 12:03:17 +00:00
|
|
|
{
|
2009-07-23 18:04:27 +00:00
|
|
|
if (modifiers & CLUTTER_CONTROL_MASK)
|
|
|
|
{
|
|
|
|
if (pos == -1)
|
2009-08-16 21:00:35 +00:00
|
|
|
new_pos = clutter_text_move_word_backward (self, len);
|
2009-07-23 18:04:27 +00:00
|
|
|
else
|
2009-08-16 21:00:35 +00:00
|
|
|
new_pos = clutter_text_move_word_backward (self, pos);
|
2009-07-23 18:04:27 +00:00
|
|
|
}
|
2008-12-11 12:03:17 +00:00
|
|
|
else
|
2009-07-23 18:04:27 +00:00
|
|
|
{
|
|
|
|
if (pos == -1)
|
|
|
|
new_pos = len - 1;
|
|
|
|
else
|
|
|
|
new_pos = pos - 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
clutter_text_set_cursor_position (self, new_pos);
|
2008-12-11 12:03:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
|
|
|
|
clutter_text_clear_selection (self);
|
|
|
|
|
2010-01-25 15:13:58 +00:00
|
|
|
g_object_thaw_notify (G_OBJECT (self));
|
|
|
|
|
2008-12-11 12:03:17 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
clutter_text_real_move_right (ClutterText *self,
|
|
|
|
const gchar *action,
|
|
|
|
guint keyval,
|
|
|
|
ClutterModifierType modifiers)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
|
|
|
gint pos = priv->position;
|
2011-06-15 09:06:31 +00:00
|
|
|
gint len = clutter_text_buffer_get_length (get_buffer (self));
|
2010-02-09 16:57:14 +00:00
|
|
|
gint new_pos = 0;
|
2008-12-11 12:03:17 +00:00
|
|
|
|
2010-01-25 15:13:58 +00:00
|
|
|
g_object_freeze_notify (G_OBJECT (self));
|
|
|
|
|
2008-12-11 12:03:17 +00:00
|
|
|
if (pos != -1 && len !=0)
|
|
|
|
{
|
2009-07-23 18:04:27 +00:00
|
|
|
if (modifiers & CLUTTER_CONTROL_MASK)
|
|
|
|
{
|
|
|
|
if (pos != len)
|
2009-08-16 21:00:35 +00:00
|
|
|
new_pos = clutter_text_move_word_forward (self, pos);
|
2009-07-23 18:04:27 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (pos != len)
|
|
|
|
new_pos = pos + 1;
|
|
|
|
}
|
|
|
|
|
|
|
|
clutter_text_set_cursor_position (self, new_pos);
|
2008-12-11 12:03:17 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
|
|
|
|
clutter_text_clear_selection (self);
|
|
|
|
|
2010-01-25 15:13:58 +00:00
|
|
|
g_object_thaw_notify (G_OBJECT (self));
|
|
|
|
|
2008-12-11 12:03:17 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
clutter_text_real_move_up (ClutterText *self,
|
|
|
|
const gchar *action,
|
|
|
|
guint keyval,
|
|
|
|
ClutterModifierType modifiers)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
|
|
|
PangoLayoutLine *layout_line;
|
|
|
|
PangoLayout *layout;
|
|
|
|
gint line_no;
|
2009-01-14 11:12:02 +00:00
|
|
|
gint index_, trailing;
|
2010-02-02 17:07:22 +00:00
|
|
|
gint pos;
|
2008-12-11 12:03:17 +00:00
|
|
|
gint x;
|
2011-06-15 09:06:31 +00:00
|
|
|
const gchar *text;
|
2008-12-11 12:03:17 +00:00
|
|
|
|
|
|
|
layout = clutter_text_get_layout (self);
|
2011-06-15 09:06:31 +00:00
|
|
|
text = clutter_text_buffer_get_text (get_buffer (self));
|
2008-12-11 12:03:17 +00:00
|
|
|
|
2008-12-15 18:46:08 +00:00
|
|
|
if (priv->position == 0)
|
|
|
|
index_ = 0;
|
|
|
|
else
|
2011-06-15 09:06:31 +00:00
|
|
|
index_ = offset_to_bytes (text, priv->position);
|
2008-12-15 18:46:08 +00:00
|
|
|
|
|
|
|
pango_layout_index_to_line_x (layout, index_,
|
2008-12-11 12:03:17 +00:00
|
|
|
0,
|
|
|
|
&line_no, &x);
|
|
|
|
|
2008-12-15 18:46:08 +00:00
|
|
|
line_no -= 1;
|
|
|
|
if (line_no < 0)
|
|
|
|
return FALSE;
|
|
|
|
|
2008-12-11 12:03:17 +00:00
|
|
|
if (priv->x_pos != -1)
|
|
|
|
x = priv->x_pos;
|
|
|
|
|
|
|
|
layout_line = pango_layout_get_line_readonly (layout, line_no);
|
|
|
|
if (!layout_line)
|
|
|
|
return FALSE;
|
|
|
|
|
2009-01-14 11:12:02 +00:00
|
|
|
pango_layout_line_x_to_index (layout_line, x, &index_, &trailing);
|
2008-12-11 12:03:17 +00:00
|
|
|
|
2010-02-02 17:07:22 +00:00
|
|
|
g_object_freeze_notify (G_OBJECT (self));
|
2008-12-11 12:03:17 +00:00
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
pos = bytes_to_offset (text, index_);
|
2010-02-02 17:07:22 +00:00
|
|
|
clutter_text_set_cursor_position (self, pos + trailing);
|
2008-12-11 12:03:17 +00:00
|
|
|
|
2009-01-14 11:12:02 +00:00
|
|
|
/* Store the target x position to avoid drifting left and right when
|
|
|
|
moving the cursor up and down */
|
|
|
|
priv->x_pos = x;
|
|
|
|
|
2008-12-11 12:03:17 +00:00
|
|
|
if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
|
|
|
|
clutter_text_clear_selection (self);
|
|
|
|
|
2010-01-25 15:13:58 +00:00
|
|
|
g_object_thaw_notify (G_OBJECT (self));
|
|
|
|
|
2008-12-11 12:03:17 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
clutter_text_real_move_down (ClutterText *self,
|
|
|
|
const gchar *action,
|
|
|
|
guint keyval,
|
|
|
|
ClutterModifierType modifiers)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
|
|
|
PangoLayoutLine *layout_line;
|
|
|
|
PangoLayout *layout;
|
|
|
|
gint line_no;
|
2009-01-14 11:12:02 +00:00
|
|
|
gint index_, trailing;
|
2008-12-11 12:03:17 +00:00
|
|
|
gint x;
|
2010-02-02 17:07:22 +00:00
|
|
|
gint pos;
|
2011-06-15 09:06:31 +00:00
|
|
|
const gchar *text;
|
2010-01-25 15:13:58 +00:00
|
|
|
|
2008-12-11 12:03:17 +00:00
|
|
|
layout = clutter_text_get_layout (self);
|
2011-06-15 09:06:31 +00:00
|
|
|
text = clutter_text_buffer_get_text (get_buffer (self));
|
2008-12-11 12:03:17 +00:00
|
|
|
|
2008-12-15 18:46:08 +00:00
|
|
|
if (priv->position == 0)
|
|
|
|
index_ = 0;
|
|
|
|
else
|
2011-06-15 09:06:31 +00:00
|
|
|
index_ = offset_to_bytes (text, priv->position);
|
2008-12-15 18:46:08 +00:00
|
|
|
|
|
|
|
pango_layout_index_to_line_x (layout, index_,
|
2008-12-11 12:03:17 +00:00
|
|
|
0,
|
|
|
|
&line_no, &x);
|
|
|
|
|
|
|
|
if (priv->x_pos != -1)
|
|
|
|
x = priv->x_pos;
|
|
|
|
|
|
|
|
layout_line = pango_layout_get_line_readonly (layout, line_no + 1);
|
|
|
|
if (!layout_line)
|
|
|
|
return FALSE;
|
|
|
|
|
2009-01-14 11:12:02 +00:00
|
|
|
pango_layout_line_x_to_index (layout_line, x, &index_, &trailing);
|
2008-12-11 12:03:17 +00:00
|
|
|
|
2010-02-02 17:07:22 +00:00
|
|
|
g_object_freeze_notify (G_OBJECT (self));
|
2008-12-11 12:03:17 +00:00
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
pos = bytes_to_offset (text, index_);
|
2010-02-02 17:07:22 +00:00
|
|
|
clutter_text_set_cursor_position (self, pos + trailing);
|
2008-12-11 12:03:17 +00:00
|
|
|
|
2009-01-14 11:12:02 +00:00
|
|
|
/* Store the target x position to avoid drifting left and right when
|
|
|
|
moving the cursor up and down */
|
|
|
|
priv->x_pos = x;
|
|
|
|
|
2008-12-11 12:03:17 +00:00
|
|
|
if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
|
|
|
|
clutter_text_clear_selection (self);
|
|
|
|
|
2010-01-25 15:13:58 +00:00
|
|
|
g_object_thaw_notify (G_OBJECT (self));
|
|
|
|
|
2008-12-11 12:03:17 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
clutter_text_real_line_start (ClutterText *self,
|
|
|
|
const gchar *action,
|
|
|
|
guint keyval,
|
|
|
|
ClutterModifierType modifiers)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
|
|
|
gint position;
|
|
|
|
|
2010-01-25 15:13:58 +00:00
|
|
|
g_object_freeze_notify (G_OBJECT (self));
|
|
|
|
|
2009-03-30 15:46:57 +00:00
|
|
|
position = clutter_text_move_line_start (self, priv->position);
|
2008-12-11 12:03:17 +00:00
|
|
|
clutter_text_set_cursor_position (self, position);
|
|
|
|
|
|
|
|
if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
|
|
|
|
clutter_text_clear_selection (self);
|
|
|
|
|
2010-01-25 15:13:58 +00:00
|
|
|
g_object_thaw_notify (G_OBJECT (self));
|
|
|
|
|
2008-12-11 12:03:17 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
clutter_text_real_line_end (ClutterText *self,
|
|
|
|
const gchar *action,
|
|
|
|
guint keyval,
|
|
|
|
ClutterModifierType modifiers)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
|
|
|
gint position;
|
|
|
|
|
2010-01-25 15:13:58 +00:00
|
|
|
g_object_freeze_notify (G_OBJECT (self));
|
|
|
|
|
2009-03-30 15:46:57 +00:00
|
|
|
position = clutter_text_move_line_end (self, priv->position);
|
2008-12-11 12:03:17 +00:00
|
|
|
clutter_text_set_cursor_position (self, position);
|
|
|
|
|
|
|
|
if (!(priv->selectable && (modifiers & CLUTTER_SHIFT_MASK)))
|
|
|
|
clutter_text_clear_selection (self);
|
|
|
|
|
2010-01-25 15:13:58 +00:00
|
|
|
g_object_thaw_notify (G_OBJECT (self));
|
|
|
|
|
2008-12-11 12:03:17 +00:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2009-01-05 12:27:45 +00:00
|
|
|
static gboolean
|
|
|
|
clutter_text_real_select_all (ClutterText *self,
|
|
|
|
const gchar *action,
|
|
|
|
guint keyval,
|
|
|
|
ClutterModifierType modifiers)
|
|
|
|
{
|
2011-06-15 09:06:31 +00:00
|
|
|
guint n_chars = clutter_text_buffer_get_length (get_buffer (self));
|
|
|
|
clutter_text_set_positions (self, 0, n_chars);
|
2009-01-05 12:27:45 +00:00
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2008-12-11 12:03:17 +00:00
|
|
|
static gboolean
|
|
|
|
clutter_text_real_del_next (ClutterText *self,
|
|
|
|
const gchar *action,
|
|
|
|
guint keyval,
|
|
|
|
ClutterModifierType modifiers)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
|
|
|
gint pos;
|
|
|
|
gint len;
|
|
|
|
|
2009-05-06 16:08:25 +00:00
|
|
|
if (clutter_text_delete_selection (self))
|
2008-12-11 12:08:20 +00:00
|
|
|
return TRUE;
|
2008-12-11 12:03:17 +00:00
|
|
|
|
|
|
|
pos = priv->position;
|
2011-06-15 09:06:31 +00:00
|
|
|
len = clutter_text_buffer_get_length (get_buffer (self));
|
2008-12-11 12:03:17 +00:00
|
|
|
|
|
|
|
if (len && pos != -1 && pos < len)
|
2009-01-06 20:54:20 +00:00
|
|
|
clutter_text_delete_text (self, pos, pos + 1);
|
2008-12-11 12:03:17 +00:00
|
|
|
|
2009-01-06 20:54:20 +00:00
|
|
|
return TRUE;
|
2008-12-11 12:03:17 +00:00
|
|
|
}
|
|
|
|
|
2010-02-03 17:04:38 +00:00
|
|
|
static gboolean
|
|
|
|
clutter_text_real_del_word_next (ClutterText *self,
|
|
|
|
const gchar *action,
|
|
|
|
guint keyval,
|
|
|
|
ClutterModifierType modifiers)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
|
|
|
gint pos;
|
|
|
|
gint len;
|
|
|
|
|
|
|
|
pos = priv->position;
|
2011-06-15 09:06:31 +00:00
|
|
|
len = clutter_text_buffer_get_length (get_buffer (self));
|
2010-02-03 17:04:38 +00:00
|
|
|
|
|
|
|
if (len && pos != -1 && pos < len)
|
|
|
|
{
|
|
|
|
gint end;
|
|
|
|
|
|
|
|
end = clutter_text_move_word_forward (self, pos);
|
|
|
|
clutter_text_delete_text (self, pos, end);
|
|
|
|
|
|
|
|
if (priv->selection_bound >= end)
|
|
|
|
{
|
|
|
|
gint new_bound;
|
|
|
|
|
|
|
|
new_bound = priv->selection_bound - (end - pos);
|
|
|
|
clutter_text_set_selection_bound (self, new_bound);
|
|
|
|
}
|
|
|
|
else if (priv->selection_bound > pos)
|
|
|
|
{
|
|
|
|
clutter_text_set_selection_bound (self, pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2008-12-11 12:03:17 +00:00
|
|
|
static gboolean
|
|
|
|
clutter_text_real_del_prev (ClutterText *self,
|
|
|
|
const gchar *action,
|
|
|
|
guint keyval,
|
|
|
|
ClutterModifierType modifiers)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
|
|
|
gint pos;
|
|
|
|
gint len;
|
|
|
|
|
2009-05-06 16:08:25 +00:00
|
|
|
if (clutter_text_delete_selection (self))
|
2008-12-11 12:08:20 +00:00
|
|
|
return TRUE;
|
2008-12-11 12:03:17 +00:00
|
|
|
|
|
|
|
pos = priv->position;
|
2011-06-15 09:06:31 +00:00
|
|
|
len = clutter_text_buffer_get_length (get_buffer (self));
|
2008-12-11 12:03:17 +00:00
|
|
|
|
|
|
|
if (pos != 0 && len != 0)
|
|
|
|
{
|
|
|
|
if (pos == -1)
|
|
|
|
{
|
2009-01-06 20:54:20 +00:00
|
|
|
clutter_text_delete_text (self, len - 1, len);
|
2009-05-14 11:00:51 +00:00
|
|
|
|
2010-01-25 15:13:58 +00:00
|
|
|
clutter_text_set_positions (self, -1, -1);
|
2008-12-11 12:03:17 +00:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-05-14 11:00:51 +00:00
|
|
|
clutter_text_delete_text (self, pos - 1, pos);
|
|
|
|
|
2010-01-25 15:13:58 +00:00
|
|
|
clutter_text_set_positions (self, pos - 1, pos - 1);
|
2009-01-06 20:54:20 +00:00
|
|
|
}
|
2008-12-11 12:03:17 +00:00
|
|
|
}
|
|
|
|
|
2009-01-06 20:54:20 +00:00
|
|
|
return TRUE;
|
2008-12-11 12:03:17 +00:00
|
|
|
}
|
|
|
|
|
2010-02-03 17:04:38 +00:00
|
|
|
static gboolean
|
|
|
|
clutter_text_real_del_word_prev (ClutterText *self,
|
|
|
|
const gchar *action,
|
|
|
|
guint keyval,
|
|
|
|
ClutterModifierType modifiers)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
|
|
|
gint pos;
|
|
|
|
gint len;
|
|
|
|
|
|
|
|
pos = priv->position;
|
2011-06-15 09:06:31 +00:00
|
|
|
len = clutter_text_buffer_get_length (get_buffer (self));
|
2010-02-03 17:04:38 +00:00
|
|
|
|
|
|
|
if (pos != 0 && len != 0)
|
|
|
|
{
|
|
|
|
gint new_pos;
|
|
|
|
|
|
|
|
if (pos == -1)
|
|
|
|
{
|
|
|
|
new_pos = clutter_text_move_word_backward (self, len);
|
|
|
|
clutter_text_delete_text (self, new_pos, len);
|
|
|
|
|
|
|
|
clutter_text_set_positions (self, -1, -1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
new_pos = clutter_text_move_word_backward (self, pos);
|
|
|
|
clutter_text_delete_text (self, new_pos, pos);
|
|
|
|
|
|
|
|
clutter_text_set_cursor_position (self, new_pos);
|
|
|
|
if (priv->selection_bound >= pos)
|
|
|
|
{
|
|
|
|
gint new_bound;
|
|
|
|
|
|
|
|
new_bound = priv->selection_bound - (pos - new_pos);
|
|
|
|
clutter_text_set_selection_bound (self, new_bound);
|
|
|
|
}
|
|
|
|
else if (priv->selection_bound >= new_pos)
|
|
|
|
{
|
|
|
|
clutter_text_set_selection_bound (self, new_pos);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2008-12-11 12:03:17 +00:00
|
|
|
static gboolean
|
2008-12-11 12:15:49 +00:00
|
|
|
clutter_text_real_activate (ClutterText *self,
|
|
|
|
const gchar *action,
|
|
|
|
guint keyval,
|
|
|
|
ClutterModifierType modifiers)
|
2008-12-11 12:03:17 +00:00
|
|
|
{
|
2008-12-16 12:05:10 +00:00
|
|
|
return clutter_text_activate (self);
|
2008-12-11 12:03:17 +00:00
|
|
|
}
|
|
|
|
|
2008-12-16 10:39:52 +00:00
|
|
|
static inline void
|
2009-07-23 18:04:27 +00:00
|
|
|
clutter_text_add_move_binding (ClutterBindingPool *pool,
|
|
|
|
const gchar *action,
|
|
|
|
guint key_val,
|
|
|
|
ClutterModifierType additional_modifiers,
|
|
|
|
GCallback callback)
|
2008-12-11 12:03:17 +00:00
|
|
|
{
|
|
|
|
clutter_binding_pool_install_action (pool, action,
|
2009-07-23 18:04:27 +00:00
|
|
|
key_val,
|
|
|
|
0,
|
2008-12-11 12:03:17 +00:00
|
|
|
callback,
|
|
|
|
NULL, NULL);
|
|
|
|
clutter_binding_pool_install_action (pool, action,
|
2009-07-23 18:04:27 +00:00
|
|
|
key_val,
|
|
|
|
CLUTTER_SHIFT_MASK,
|
2008-12-11 12:03:17 +00:00
|
|
|
callback,
|
|
|
|
NULL, NULL);
|
2009-07-23 18:04:27 +00:00
|
|
|
|
|
|
|
if (additional_modifiers != 0)
|
|
|
|
{
|
|
|
|
clutter_binding_pool_install_action (pool, action,
|
|
|
|
key_val,
|
|
|
|
additional_modifiers,
|
|
|
|
callback,
|
|
|
|
NULL, NULL);
|
|
|
|
clutter_binding_pool_install_action (pool, action,
|
|
|
|
key_val,
|
|
|
|
CLUTTER_SHIFT_MASK |
|
|
|
|
additional_modifiers,
|
|
|
|
callback,
|
|
|
|
NULL, NULL);
|
|
|
|
}
|
2008-12-11 12:03:17 +00:00
|
|
|
}
|
|
|
|
|
2011-08-16 16:31:42 +00:00
|
|
|
static gboolean
|
|
|
|
clutter_text_parse_custom_node (ClutterScriptable *scriptable,
|
|
|
|
ClutterScript *script,
|
|
|
|
GValue *value,
|
|
|
|
const gchar *name,
|
|
|
|
JsonNode *node)
|
|
|
|
{
|
|
|
|
if (strncmp (name, "font-description", 16) == 0)
|
|
|
|
{
|
|
|
|
g_value_init (value, G_TYPE_STRING);
|
|
|
|
g_value_set_string (value, json_node_get_string (node));
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2012-06-08 13:13:36 +00:00
|
|
|
return parent_scriptable_iface->parse_custom_node (scriptable, script,
|
|
|
|
value,
|
|
|
|
name,
|
|
|
|
node);
|
2011-08-16 16:31:42 +00:00
|
|
|
}
|
|
|
|
|
2012-05-28 12:02:25 +00:00
|
|
|
static void
|
|
|
|
clutter_text_set_color_internal (ClutterText *self,
|
|
|
|
GParamSpec *pspec,
|
|
|
|
const ClutterColor *color)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = CLUTTER_TEXT (self)->priv;
|
|
|
|
GParamSpec *other = NULL;
|
|
|
|
|
|
|
|
switch (pspec->param_id)
|
|
|
|
{
|
|
|
|
case PROP_COLOR:
|
|
|
|
priv->text_color = *color;
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_CURSOR_COLOR:
|
|
|
|
if (color)
|
|
|
|
{
|
|
|
|
priv->cursor_color = *color;
|
|
|
|
priv->cursor_color_set = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
priv->cursor_color_set = FALSE;
|
|
|
|
|
|
|
|
other = obj_props[PROP_CURSOR_COLOR_SET];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_SELECTION_COLOR:
|
|
|
|
if (color)
|
|
|
|
{
|
|
|
|
priv->selection_color = *color;
|
|
|
|
priv->selection_color_set = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
priv->selection_color_set = FALSE;
|
|
|
|
|
|
|
|
other = obj_props[PROP_SELECTION_COLOR_SET];
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_SELECTED_TEXT_COLOR:
|
|
|
|
if (color)
|
|
|
|
{
|
|
|
|
priv->selected_text_color = *color;
|
|
|
|
priv->selected_text_color_set = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
priv->selected_text_color_set = FALSE;
|
|
|
|
|
|
|
|
other = obj_props[PROP_SELECTED_TEXT_COLOR_SET];
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
g_assert_not_reached ();
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
clutter_text_queue_redraw (CLUTTER_ACTOR (self));
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), pspec);
|
|
|
|
if (other)
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), other);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clutter_text_set_color_animated (ClutterText *self,
|
|
|
|
GParamSpec *pspec,
|
|
|
|
const ClutterColor *color)
|
|
|
|
{
|
|
|
|
ClutterActor *actor = CLUTTER_ACTOR (self);
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
|
|
|
const ClutterAnimationInfo *info;
|
|
|
|
ClutterTransition *transition;
|
|
|
|
|
|
|
|
info = _clutter_actor_get_animation_info (actor);
|
|
|
|
transition = clutter_actor_get_transition (actor, pspec->name);
|
|
|
|
|
|
|
|
/* jump to the end if there is no easing state, or if the easing
|
|
|
|
* state has a duration of 0 msecs
|
|
|
|
*/
|
|
|
|
if (info->cur_state == NULL ||
|
|
|
|
info->cur_state->easing_duration == 0)
|
|
|
|
{
|
|
|
|
/* ensure that we remove any currently running transition */
|
|
|
|
if (transition != NULL)
|
|
|
|
{
|
|
|
|
clutter_actor_remove_transition (actor, pspec->name);
|
|
|
|
transition = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
clutter_text_set_color_internal (self, pspec, color);
|
|
|
|
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (transition == NULL)
|
|
|
|
{
|
|
|
|
transition = clutter_property_transition_new (pspec->name);
|
|
|
|
clutter_transition_set_animatable (transition,
|
|
|
|
CLUTTER_ANIMATABLE (self));
|
|
|
|
clutter_transition_set_remove_on_complete (transition, TRUE);
|
|
|
|
|
|
|
|
/* delay only makes sense if the transition has just been created */
|
|
|
|
clutter_timeline_set_delay (CLUTTER_TIMELINE (transition),
|
|
|
|
info->cur_state->easing_delay);
|
|
|
|
|
|
|
|
clutter_actor_add_transition (actor, pspec->name, transition);
|
|
|
|
|
|
|
|
/* the actor now owns the transition */
|
|
|
|
g_object_unref (transition);
|
|
|
|
}
|
|
|
|
|
|
|
|
/* if a transition already exist, update its bounds */
|
|
|
|
switch (pspec->param_id)
|
|
|
|
{
|
|
|
|
case PROP_COLOR:
|
|
|
|
clutter_transition_set_from (transition, CLUTTER_TYPE_COLOR,
|
|
|
|
&priv->text_color);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_CURSOR_COLOR:
|
|
|
|
clutter_transition_set_from (transition, CLUTTER_TYPE_COLOR,
|
|
|
|
&priv->cursor_color);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_SELECTION_COLOR:
|
|
|
|
clutter_transition_set_from (transition, CLUTTER_TYPE_COLOR,
|
|
|
|
&priv->selection_color);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case PROP_SELECTED_TEXT_COLOR:
|
|
|
|
clutter_transition_set_from (transition, CLUTTER_TYPE_COLOR,
|
|
|
|
&priv->selected_text_color);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
g_assert_not_reached ();
|
|
|
|
}
|
|
|
|
|
|
|
|
clutter_transition_set_to (transition, CLUTTER_TYPE_COLOR, color);
|
|
|
|
|
|
|
|
/* always use the current easing state */
|
|
|
|
clutter_timeline_set_duration (CLUTTER_TIMELINE (transition),
|
|
|
|
info->cur_state->easing_duration);
|
|
|
|
clutter_timeline_set_progress_mode (CLUTTER_TIMELINE (transition),
|
|
|
|
info->cur_state->easing_mode);
|
|
|
|
|
|
|
|
/* ensure that we start from the beginning */
|
|
|
|
clutter_timeline_rewind (CLUTTER_TIMELINE (transition));
|
|
|
|
clutter_timeline_start (CLUTTER_TIMELINE (transition));
|
|
|
|
}
|
|
|
|
|
2011-08-16 16:31:42 +00:00
|
|
|
static void
|
|
|
|
clutter_text_set_custom_property (ClutterScriptable *scriptable,
|
|
|
|
ClutterScript *script,
|
|
|
|
const gchar *name,
|
|
|
|
const GValue *value)
|
|
|
|
{
|
|
|
|
if (strncmp (name, "font-description", 16) == 0)
|
|
|
|
{
|
|
|
|
g_assert (G_VALUE_HOLDS (value, G_TYPE_STRING));
|
|
|
|
if (g_value_get_string (value) != NULL)
|
|
|
|
clutter_text_set_font_name (CLUTTER_TEXT (scriptable),
|
|
|
|
g_value_get_string (value));
|
|
|
|
}
|
|
|
|
else
|
2012-06-08 13:13:36 +00:00
|
|
|
parent_scriptable_iface->set_custom_property (scriptable, script,
|
|
|
|
name,
|
|
|
|
value);
|
2011-08-16 16:31:42 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clutter_scriptable_iface_init (ClutterScriptableIface *iface)
|
|
|
|
{
|
2012-06-08 13:13:36 +00:00
|
|
|
parent_scriptable_iface = g_type_interface_peek_parent (iface);
|
|
|
|
|
2011-08-16 16:31:42 +00:00
|
|
|
iface->parse_custom_node = clutter_text_parse_custom_node;
|
|
|
|
iface->set_custom_property = clutter_text_set_custom_property;
|
|
|
|
}
|
|
|
|
|
2012-05-28 12:02:25 +00:00
|
|
|
static void
|
|
|
|
clutter_text_set_final_state (ClutterAnimatable *animatable,
|
|
|
|
const char *property_name,
|
|
|
|
const GValue *value)
|
|
|
|
{
|
|
|
|
if (strcmp (property_name, "color") == 0)
|
|
|
|
{
|
|
|
|
const ClutterColor *color = clutter_value_get_color (value);
|
|
|
|
clutter_text_set_color_internal (CLUTTER_TEXT (animatable),
|
|
|
|
obj_props[PROP_COLOR], color);
|
|
|
|
}
|
|
|
|
else if (strcmp (property_name, "cursor-color") == 0)
|
|
|
|
{
|
|
|
|
const ClutterColor *color = clutter_value_get_color (value);
|
|
|
|
clutter_text_set_color_internal (CLUTTER_TEXT (animatable),
|
|
|
|
obj_props[PROP_CURSOR_COLOR],
|
|
|
|
color);
|
|
|
|
}
|
|
|
|
else if (strcmp (property_name, "selected-text-color") == 0)
|
|
|
|
{
|
|
|
|
const ClutterColor *color = clutter_value_get_color (value);
|
|
|
|
clutter_text_set_color_internal (CLUTTER_TEXT (animatable),
|
|
|
|
obj_props[PROP_SELECTED_TEXT_COLOR],
|
|
|
|
color);
|
|
|
|
}
|
|
|
|
else if (strcmp (property_name, "selection-color") == 0)
|
|
|
|
{
|
|
|
|
const ClutterColor *color = clutter_value_get_color (value);
|
|
|
|
clutter_text_set_color_internal (CLUTTER_TEXT (animatable),
|
|
|
|
obj_props[PROP_SELECTION_COLOR],
|
|
|
|
color);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
parent_animatable_iface->set_final_state (animatable, property_name, value);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clutter_animatable_iface_init (ClutterAnimatableIface *iface)
|
|
|
|
{
|
|
|
|
parent_animatable_iface = g_type_interface_peek_parent (iface);
|
|
|
|
|
|
|
|
iface->set_final_state = clutter_text_set_final_state;
|
|
|
|
}
|
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
static void
|
|
|
|
clutter_text_class_init (ClutterTextClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *gobject_class = G_OBJECT_CLASS (klass);
|
|
|
|
ClutterActorClass *actor_class = CLUTTER_ACTOR_CLASS (klass);
|
2008-12-11 12:03:17 +00:00
|
|
|
ClutterBindingPool *binding_pool;
|
2008-12-11 11:17:26 +00:00
|
|
|
GParamSpec *pspec;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2008-12-11 11:40:55 +00:00
|
|
|
g_type_class_add_private (klass, sizeof (ClutterTextPrivate));
|
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
gobject_class->set_property = clutter_text_set_property;
|
|
|
|
gobject_class->get_property = clutter_text_get_property;
|
2008-12-11 11:33:10 +00:00
|
|
|
gobject_class->dispose = clutter_text_dispose;
|
2008-12-11 11:12:48 +00:00
|
|
|
gobject_class->finalize = clutter_text_finalize;
|
|
|
|
|
2008-12-11 11:17:26 +00:00
|
|
|
actor_class->paint = clutter_text_paint;
|
2010-09-08 18:47:11 +00:00
|
|
|
actor_class->get_paint_volume = clutter_text_get_paint_volume;
|
2008-12-11 11:17:26 +00:00
|
|
|
actor_class->get_preferred_width = clutter_text_get_preferred_width;
|
|
|
|
actor_class->get_preferred_height = clutter_text_get_preferred_height;
|
|
|
|
actor_class->allocate = clutter_text_allocate;
|
2008-12-11 11:12:48 +00:00
|
|
|
actor_class->key_press_event = clutter_text_key_press;
|
2008-12-11 11:33:10 +00:00
|
|
|
actor_class->button_press_event = clutter_text_button_press;
|
|
|
|
actor_class->button_release_event = clutter_text_button_release;
|
2008-12-11 11:12:48 +00:00
|
|
|
actor_class->motion_event = clutter_text_motion;
|
2012-06-18 01:03:58 +00:00
|
|
|
actor_class->touch_event = clutter_text_touch_event;
|
2010-12-21 10:50:24 +00:00
|
|
|
actor_class->key_focus_in = clutter_text_key_focus_in;
|
|
|
|
actor_class->key_focus_out = clutter_text_key_focus_out;
|
2011-05-13 13:17:39 +00:00
|
|
|
actor_class->has_overlaps = clutter_text_has_overlaps;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
/**
|
|
|
|
* ClutterText:buffer:
|
|
|
|
*
|
|
|
|
* The buffer which stores the text for this #ClutterText.
|
|
|
|
*
|
|
|
|
* If set to %NULL, a default buffer will be created.
|
|
|
|
*/
|
|
|
|
pspec = g_param_spec_object ("buffer",
|
|
|
|
P_("Buffer"),
|
|
|
|
P_("The buffer for the text"),
|
|
|
|
CLUTTER_TYPE_TEXT_BUFFER,
|
|
|
|
CLUTTER_PARAM_READWRITE);
|
|
|
|
obj_props[PROP_BUFFER] = pspec;
|
|
|
|
g_object_class_install_property (gobject_class, PROP_BUFFER, pspec);
|
|
|
|
|
2008-12-11 11:17:26 +00:00
|
|
|
/**
|
|
|
|
* ClutterText:font-name:
|
|
|
|
*
|
|
|
|
* The font to be used by the #ClutterText, as a string
|
|
|
|
* that can be parsed by pango_font_description_from_string().
|
|
|
|
*
|
2010-06-26 22:05:36 +00:00
|
|
|
* If set to %NULL, the default system font will be used instead.
|
2008-12-11 11:17:26 +00:00
|
|
|
*/
|
|
|
|
pspec = g_param_spec_string ("font-name",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Font Name"),
|
|
|
|
P_("The font to be used by the text"),
|
2008-12-11 11:17:26 +00:00
|
|
|
NULL,
|
|
|
|
CLUTTER_PARAM_READWRITE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_FONT_NAME] = pspec;
|
2008-12-11 11:17:26 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_FONT_NAME, pspec);
|
|
|
|
|
2010-02-03 14:35:45 +00:00
|
|
|
/**
|
|
|
|
* ClutterText:font-description:
|
|
|
|
*
|
|
|
|
* The #PangoFontDescription that should be used by the #ClutterText
|
|
|
|
*
|
|
|
|
* If you have a string describing the font then you should look at
|
|
|
|
* #ClutterText:font-name instead
|
|
|
|
*/
|
|
|
|
pspec = g_param_spec_boxed ("font-description",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Font Description"),
|
|
|
|
P_("The font description to be used"),
|
2010-02-03 14:35:45 +00:00
|
|
|
PANGO_TYPE_FONT_DESCRIPTION,
|
|
|
|
CLUTTER_PARAM_READWRITE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_FONT_DESCRIPTION] = pspec;
|
2010-02-03 14:35:45 +00:00
|
|
|
g_object_class_install_property (gobject_class,
|
|
|
|
PROP_FONT_DESCRIPTION,
|
|
|
|
pspec);
|
|
|
|
|
2008-12-16 11:30:47 +00:00
|
|
|
/**
|
|
|
|
* ClutterText:text:
|
|
|
|
*
|
|
|
|
* The text to render inside the actor.
|
|
|
|
*/
|
2008-12-11 11:17:26 +00:00
|
|
|
pspec = g_param_spec_string ("text",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Text"),
|
|
|
|
P_("The text to render"),
|
2008-12-22 13:29:10 +00:00
|
|
|
"",
|
2008-12-11 11:17:26 +00:00
|
|
|
CLUTTER_PARAM_READWRITE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_TEXT] = pspec;
|
2008-12-11 11:17:26 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_TEXT, pspec);
|
|
|
|
|
2008-12-16 11:30:47 +00:00
|
|
|
/**
|
|
|
|
* ClutterText:color:
|
|
|
|
*
|
|
|
|
* The color used to render the text.
|
|
|
|
*/
|
2008-12-11 11:17:26 +00:00
|
|
|
pspec = clutter_param_spec_color ("color",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Font Color"),
|
|
|
|
P_("Color of the font used by the text"),
|
2008-12-11 11:17:26 +00:00
|
|
|
&default_text_color,
|
2012-05-28 12:02:25 +00:00
|
|
|
CLUTTER_PARAM_READWRITE |
|
|
|
|
CLUTTER_PARAM_ANIMATABLE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_COLOR] = pspec;
|
2008-12-11 11:17:26 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_COLOR, pspec);
|
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
/**
|
|
|
|
* ClutterText:editable:
|
|
|
|
*
|
|
|
|
* Whether key events delivered to the actor causes editing.
|
|
|
|
*/
|
2008-12-11 11:33:10 +00:00
|
|
|
pspec = g_param_spec_boolean ("editable",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Editable"),
|
|
|
|
P_("Whether the text is editable"),
|
2011-07-12 16:32:26 +00:00
|
|
|
FALSE,
|
2008-12-11 11:33:10 +00:00
|
|
|
G_PARAM_READWRITE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_EDITABLE] = pspec;
|
2008-12-11 11:33:10 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_EDITABLE, pspec);
|
2008-12-11 11:12:48 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* ClutterText:selectable:
|
|
|
|
*
|
2008-12-16 11:30:47 +00:00
|
|
|
* Whether it is possible to select text, either using the pointer
|
|
|
|
* or the keyboard.
|
2008-12-11 11:12:48 +00:00
|
|
|
*/
|
2008-12-11 11:33:10 +00:00
|
|
|
pspec = g_param_spec_boolean ("selectable",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Selectable"),
|
|
|
|
P_("Whether the text is selectable"),
|
2008-12-11 11:33:10 +00:00
|
|
|
TRUE,
|
|
|
|
G_PARAM_READWRITE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_SELECTABLE] = pspec;
|
2008-12-11 11:33:10 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_SELECTABLE, pspec);
|
2008-12-11 11:12:48 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* ClutterText:activatable:
|
|
|
|
*
|
|
|
|
* Toggles whether return invokes the activate signal or not.
|
|
|
|
*/
|
2008-12-11 11:33:10 +00:00
|
|
|
pspec = g_param_spec_boolean ("activatable",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Activatable"),
|
|
|
|
P_("Whether pressing return causes the activate signal to be emitted"),
|
2008-12-11 11:33:10 +00:00
|
|
|
TRUE,
|
|
|
|
G_PARAM_READWRITE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_ACTIVATABLE] = pspec;
|
2008-12-11 11:33:10 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_ACTIVATABLE, pspec);
|
2008-12-11 11:12:48 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* ClutterText:cursor-visible:
|
|
|
|
*
|
|
|
|
* Whether the input cursor is visible or not, it will only be visible
|
2008-12-16 11:30:47 +00:00
|
|
|
* if both #ClutterText:cursor-visible and #ClutterText:editable are
|
|
|
|
* set to %TRUE.
|
2008-12-11 11:12:48 +00:00
|
|
|
*/
|
2008-12-11 11:40:55 +00:00
|
|
|
pspec = g_param_spec_boolean ("cursor-visible",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Cursor Visible"),
|
|
|
|
P_("Whether the input cursor is visible"),
|
2008-12-11 11:40:55 +00:00
|
|
|
TRUE,
|
|
|
|
CLUTTER_PARAM_READWRITE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_CURSOR_VISIBLE] = pspec;
|
2008-12-11 11:40:55 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_CURSOR_VISIBLE, pspec);
|
|
|
|
|
2008-12-16 11:30:47 +00:00
|
|
|
/**
|
|
|
|
* ClutterText:cursor-color:
|
|
|
|
*
|
|
|
|
* The color of the cursor.
|
|
|
|
*/
|
2008-12-11 11:40:55 +00:00
|
|
|
pspec = clutter_param_spec_color ("cursor-color",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Cursor Color"),
|
|
|
|
P_("Cursor Color"),
|
2008-12-11 11:40:55 +00:00
|
|
|
&default_cursor_color,
|
2012-05-28 12:02:25 +00:00
|
|
|
CLUTTER_PARAM_READWRITE |
|
|
|
|
CLUTTER_PARAM_ANIMATABLE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_CURSOR_COLOR] = pspec;
|
2008-12-11 11:40:55 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_CURSOR_COLOR, pspec);
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2008-12-16 11:30:47 +00:00
|
|
|
/**
|
|
|
|
* ClutterText:cursor-color-set:
|
|
|
|
*
|
|
|
|
* Will be set to %TRUE if #ClutterText:cursor-color has been set.
|
|
|
|
*/
|
2008-12-11 11:49:14 +00:00
|
|
|
pspec = g_param_spec_boolean ("cursor-color-set",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Cursor Color Set"),
|
|
|
|
P_("Whether the cursor color has been set"),
|
2008-12-11 11:49:14 +00:00
|
|
|
FALSE,
|
|
|
|
CLUTTER_PARAM_READABLE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_CURSOR_COLOR_SET] = pspec;
|
2008-12-11 11:49:14 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_CURSOR_COLOR_SET, pspec);
|
|
|
|
|
2008-12-16 10:37:45 +00:00
|
|
|
/**
|
|
|
|
* ClutterText:cursor-size:
|
|
|
|
*
|
|
|
|
* The size of the cursor, in pixels. If set to -1 the size used will
|
|
|
|
* be the default cursor size of 2 pixels.
|
|
|
|
*/
|
|
|
|
pspec = g_param_spec_int ("cursor-size",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Cursor Size"),
|
|
|
|
P_("The width of the cursor, in pixels"),
|
2008-12-16 10:37:45 +00:00
|
|
|
-1, G_MAXINT, DEFAULT_CURSOR_SIZE,
|
|
|
|
CLUTTER_PARAM_READWRITE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_CURSOR_SIZE] = pspec;
|
2008-12-16 10:37:45 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_CURSOR_SIZE, pspec);
|
|
|
|
|
2012-07-05 15:23:52 +00:00
|
|
|
/**
|
|
|
|
* ClutterText:cursor-position:
|
|
|
|
*
|
|
|
|
* The current input cursor position. -1 is taken to be the end of the text
|
|
|
|
*/
|
|
|
|
pspec = g_param_spec_int ("cursor-position",
|
|
|
|
P_("Cursor Position"),
|
|
|
|
P_("The cursor position"),
|
|
|
|
-1, G_MAXINT,
|
|
|
|
-1,
|
|
|
|
CLUTTER_PARAM_READWRITE);
|
|
|
|
obj_props[PROP_CURSOR_POSITION] = pspec;
|
|
|
|
g_object_class_install_property (gobject_class, PROP_CURSOR_POSITION, pspec);
|
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
/**
|
|
|
|
* ClutterText:selection-bound:
|
|
|
|
*
|
|
|
|
* The current input cursor position. -1 is taken to be the end of the text
|
|
|
|
*/
|
2008-12-11 11:33:10 +00:00
|
|
|
pspec = g_param_spec_int ("selection-bound",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Selection-bound"),
|
|
|
|
P_("The cursor position of the other end of the selection"),
|
2008-12-11 11:40:55 +00:00
|
|
|
-1, G_MAXINT,
|
|
|
|
-1,
|
|
|
|
CLUTTER_PARAM_READWRITE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_SELECTION_BOUND] = pspec;
|
2008-12-11 11:33:10 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_SELECTION_BOUND, pspec);
|
|
|
|
|
2009-04-06 14:22:31 +00:00
|
|
|
/**
|
|
|
|
* ClutterText:selection-color:
|
|
|
|
*
|
|
|
|
* The color of the selection.
|
|
|
|
*/
|
|
|
|
pspec = clutter_param_spec_color ("selection-color",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Selection Color"),
|
|
|
|
P_("Selection Color"),
|
2009-04-06 14:22:31 +00:00
|
|
|
&default_selection_color,
|
2012-05-28 12:02:25 +00:00
|
|
|
CLUTTER_PARAM_READWRITE |
|
|
|
|
CLUTTER_PARAM_ANIMATABLE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_SELECTION_COLOR] = pspec;
|
2009-04-06 14:22:31 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_SELECTION_COLOR, pspec);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ClutterText:selection-color-set:
|
|
|
|
*
|
|
|
|
* Will be set to %TRUE if #ClutterText:selection-color has been set.
|
|
|
|
*/
|
|
|
|
pspec = g_param_spec_boolean ("selection-color-set",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Selection Color Set"),
|
|
|
|
P_("Whether the selection color has been set"),
|
2009-04-06 14:22:31 +00:00
|
|
|
FALSE,
|
|
|
|
CLUTTER_PARAM_READABLE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_SELECTION_COLOR_SET] = pspec;
|
2009-04-06 14:22:31 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_SELECTION_COLOR_SET, pspec);
|
|
|
|
|
2008-12-16 11:30:47 +00:00
|
|
|
/**
|
|
|
|
* ClutterText:attributes:
|
|
|
|
*
|
|
|
|
* A list of #PangoStyleAttribute<!-- -->s to be applied to the
|
|
|
|
* contents of the #ClutterText actor.
|
|
|
|
*/
|
2008-12-11 11:33:10 +00:00
|
|
|
pspec = g_param_spec_boxed ("attributes",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Attributes"),
|
|
|
|
P_("A list of style attributes to apply to the contents of the actor"),
|
2008-12-11 11:33:10 +00:00
|
|
|
PANGO_TYPE_ATTR_LIST,
|
|
|
|
CLUTTER_PARAM_READWRITE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_ATTRIBUTES] = pspec;
|
2008-12-11 11:33:10 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_ATTRIBUTES, pspec);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ClutterText:use-markup:
|
|
|
|
*
|
2010-08-06 16:04:37 +00:00
|
|
|
* Whether the text includes Pango markup.
|
|
|
|
*
|
|
|
|
* For more informations about the Pango markup format, see
|
|
|
|
* pango_layout_set_markup() in the Pango documentation.
|
|
|
|
*
|
|
|
|
* <note>It is not possible to round-trip this property between
|
|
|
|
* %TRUE and %FALSE. Once a string with markup has been set on
|
|
|
|
* a #ClutterText actor with :use-markup set to %TRUE, the markup
|
|
|
|
* is stripped from the string.</note>
|
2008-12-11 11:33:10 +00:00
|
|
|
*/
|
|
|
|
pspec = g_param_spec_boolean ("use-markup",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Use markup"),
|
|
|
|
P_("Whether or not the text includes Pango markup"),
|
2008-12-11 11:33:10 +00:00
|
|
|
FALSE,
|
|
|
|
CLUTTER_PARAM_READWRITE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_USE_MARKUP] = pspec;
|
2008-12-11 11:33:10 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_USE_MARKUP, pspec);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ClutterText:line-wrap:
|
|
|
|
*
|
|
|
|
* Whether to wrap the lines of #ClutterText:text if the contents
|
|
|
|
* exceed the available allocation. The wrapping strategy is
|
|
|
|
* controlled by the #ClutterText:line-wrap-mode property.
|
|
|
|
*/
|
|
|
|
pspec = g_param_spec_boolean ("line-wrap",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Line wrap"),
|
|
|
|
P_("If set, wrap the lines if the text becomes too wide"),
|
2008-12-11 11:33:10 +00:00
|
|
|
FALSE,
|
|
|
|
CLUTTER_PARAM_READWRITE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_LINE_WRAP] = pspec;
|
2008-12-11 11:33:10 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_LINE_WRAP, pspec);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ClutterText:line-wrap-mode:
|
|
|
|
*
|
|
|
|
* If #ClutterText:line-wrap is set to %TRUE, this property will
|
|
|
|
* control how the text is wrapped.
|
|
|
|
*/
|
|
|
|
pspec = g_param_spec_enum ("line-wrap-mode",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Line wrap mode"),
|
|
|
|
P_("Control how line-wrapping is done"),
|
2008-12-11 11:33:10 +00:00
|
|
|
PANGO_TYPE_WRAP_MODE,
|
|
|
|
PANGO_WRAP_WORD,
|
|
|
|
CLUTTER_PARAM_READWRITE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_LINE_WRAP_MODE] = pspec;
|
2008-12-11 11:33:10 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_LINE_WRAP_MODE, pspec);
|
|
|
|
|
2008-12-16 11:30:47 +00:00
|
|
|
/**
|
|
|
|
* ClutterText:ellipsize:
|
|
|
|
*
|
|
|
|
* The preferred place to ellipsize the contents of the #ClutterText actor
|
|
|
|
*/
|
2008-12-11 11:33:10 +00:00
|
|
|
pspec = g_param_spec_enum ("ellipsize",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Ellipsize"),
|
|
|
|
P_("The preferred place to ellipsize the string"),
|
2008-12-11 11:33:10 +00:00
|
|
|
PANGO_TYPE_ELLIPSIZE_MODE,
|
|
|
|
PANGO_ELLIPSIZE_NONE,
|
|
|
|
CLUTTER_PARAM_READWRITE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_ELLIPSIZE] = pspec;
|
2008-12-11 11:33:10 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_ELLIPSIZE, pspec);
|
|
|
|
|
|
|
|
/**
|
2009-02-02 23:55:30 +00:00
|
|
|
* ClutterText:line-alignment:
|
2008-12-11 11:33:10 +00:00
|
|
|
*
|
|
|
|
* The preferred alignment for the text. This property controls
|
|
|
|
* the alignment of multi-line paragraphs.
|
|
|
|
*/
|
2009-02-02 23:55:30 +00:00
|
|
|
pspec = g_param_spec_enum ("line-alignment",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Line Alignment"),
|
|
|
|
P_("The preferred alignment for the string, for multi-line text"),
|
2008-12-11 11:33:10 +00:00
|
|
|
PANGO_TYPE_ALIGNMENT,
|
|
|
|
PANGO_ALIGN_LEFT,
|
|
|
|
CLUTTER_PARAM_READWRITE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_LINE_ALIGNMENT] = pspec;
|
2009-02-02 23:55:30 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_LINE_ALIGNMENT, pspec);
|
2008-12-11 11:33:10 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* ClutterText:justify:
|
|
|
|
*
|
|
|
|
* Whether the contents of the #ClutterText should be justified
|
|
|
|
* on both margins.
|
|
|
|
*/
|
|
|
|
pspec = g_param_spec_boolean ("justify",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Justify"),
|
|
|
|
P_("Whether the text should be justified"),
|
2008-12-11 11:33:10 +00:00
|
|
|
FALSE,
|
|
|
|
CLUTTER_PARAM_READWRITE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_JUSTIFY] = pspec;
|
2008-12-11 11:33:10 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_JUSTIFY, pspec);
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2008-12-16 11:30:47 +00:00
|
|
|
/**
|
2009-01-06 15:22:31 +00:00
|
|
|
* ClutterText:password-char:
|
2008-12-16 11:30:47 +00:00
|
|
|
*
|
2009-01-06 15:22:31 +00:00
|
|
|
* If non-zero, the character that should be used in place of
|
|
|
|
* the actual text in a password text actor.
|
2008-12-16 11:30:47 +00:00
|
|
|
*/
|
2009-01-06 15:22:31 +00:00
|
|
|
pspec = g_param_spec_unichar ("password-char",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Password Character"),
|
|
|
|
P_("If non-zero, use this character to display the actor's contents"),
|
2009-01-06 15:22:31 +00:00
|
|
|
0,
|
2008-12-11 11:40:55 +00:00
|
|
|
CLUTTER_PARAM_READWRITE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_PASSWORD_CHAR] = pspec;
|
2009-01-06 15:22:31 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_PASSWORD_CHAR, pspec);
|
2008-12-11 11:40:55 +00:00
|
|
|
|
2008-12-16 11:30:47 +00:00
|
|
|
/**
|
|
|
|
* ClutterText:max-length:
|
|
|
|
*
|
|
|
|
* The maximum length of the contents of the #ClutterText actor.
|
|
|
|
*/
|
2008-12-11 11:54:07 +00:00
|
|
|
pspec = g_param_spec_int ("max-length",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Max Length"),
|
|
|
|
P_("Maximum length of the text inside the actor"),
|
2008-12-11 11:54:07 +00:00
|
|
|
-1, G_MAXINT, 0,
|
|
|
|
CLUTTER_PARAM_READWRITE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_MAX_LENGTH] = pspec;
|
2008-12-11 11:54:07 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_MAX_LENGTH, pspec);
|
|
|
|
|
2009-01-07 00:25:24 +00:00
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*
|
2010-06-14 13:05:49 +00:00
|
|
|
* The #ClutterText:single-line-mode property is used only if the
|
|
|
|
* #ClutterText:editable property is set to %TRUE.
|
2009-01-07 00:25:24 +00:00
|
|
|
*/
|
|
|
|
pspec = g_param_spec_boolean ("single-line-mode",
|
2010-06-03 11:57:50 +00:00
|
|
|
P_("Single Line Mode"),
|
|
|
|
P_("Whether the text should be a single line"),
|
2009-01-07 00:25:24 +00:00
|
|
|
FALSE,
|
|
|
|
CLUTTER_PARAM_READWRITE);
|
2010-06-21 09:20:32 +00:00
|
|
|
obj_props[PROP_SINGLE_LINE_MODE] = pspec;
|
2009-01-07 00:25:24 +00:00
|
|
|
g_object_class_install_property (gobject_class, PROP_SINGLE_LINE_MODE, pspec);
|
|
|
|
|
2011-03-02 17:02:56 +00:00
|
|
|
/**
|
|
|
|
* ClutterText:selected-text-color:
|
|
|
|
*
|
|
|
|
* The color of selected text.
|
|
|
|
*/
|
|
|
|
pspec = clutter_param_spec_color ("selected-text-color",
|
|
|
|
P_("Selected Text Color"),
|
|
|
|
P_("Selected Text Color"),
|
|
|
|
&default_selected_text_color,
|
2012-05-28 12:02:25 +00:00
|
|
|
CLUTTER_PARAM_READWRITE |
|
|
|
|
CLUTTER_PARAM_ANIMATABLE);
|
2011-03-02 17:02:56 +00:00
|
|
|
obj_props[PROP_SELECTED_TEXT_COLOR] = pspec;
|
|
|
|
g_object_class_install_property (gobject_class, PROP_SELECTED_TEXT_COLOR, pspec);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ClutterText:selected-text-color-set:
|
|
|
|
*
|
|
|
|
* Will be set to %TRUE if #ClutterText:selected-text-color has been set.
|
|
|
|
*/
|
|
|
|
pspec = g_param_spec_boolean ("selected-text-color-set",
|
|
|
|
P_("Selected Text Color Set"),
|
|
|
|
P_("Whether the selected text color has been set"),
|
|
|
|
FALSE,
|
|
|
|
CLUTTER_PARAM_READABLE);
|
|
|
|
obj_props[PROP_SELECTED_TEXT_COLOR_SET] = pspec;
|
|
|
|
g_object_class_install_property (gobject_class, PROP_SELECTED_TEXT_COLOR_SET, pspec);
|
|
|
|
|
2008-12-11 11:40:55 +00:00
|
|
|
/**
|
2008-12-11 11:12:48 +00:00
|
|
|
* ClutterText::text-changed:
|
2008-12-11 12:17:11 +00:00
|
|
|
* @self: the #ClutterText that emitted the signal
|
2008-12-11 11:12:48 +00:00
|
|
|
*
|
2008-12-11 11:40:55 +00:00
|
|
|
* The ::text-changed signal is emitted after @actor's text changes
|
2008-12-11 11:12:48 +00:00
|
|
|
*/
|
2008-12-11 11:17:26 +00:00
|
|
|
text_signals[TEXT_CHANGED] =
|
2010-06-03 11:57:50 +00:00
|
|
|
g_signal_new (I_("text-changed"),
|
2008-12-11 11:12:48 +00:00
|
|
|
G_TYPE_FROM_CLASS (gobject_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
2008-12-11 11:15:56 +00:00
|
|
|
G_STRUCT_OFFSET (ClutterTextClass, text_changed),
|
2008-12-11 11:12:48 +00:00
|
|
|
NULL, NULL,
|
2010-06-11 14:49:46 +00:00
|
|
|
_clutter_marshal_VOID__VOID,
|
2008-12-11 11:12:48 +00:00
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
2009-11-20 14:17:41 +00:00
|
|
|
/**
|
|
|
|
* ClutterText::insert-text:
|
|
|
|
* @self: the #ClutterText that emitted the signal
|
|
|
|
* @new_text: the new text to insert
|
|
|
|
* @new_text_length: the length of the new text, in bytes, or -1 if
|
|
|
|
* new_text is nul-terminated
|
|
|
|
* @position: the position, in characters, at which to insert the
|
|
|
|
* new text. this is an in-out parameter. After the signal
|
|
|
|
* emission is finished, it should point after the newly
|
|
|
|
* inserted text.
|
|
|
|
*
|
|
|
|
* This signal is emitted when text is inserted into the actor by
|
|
|
|
* the user. It is emitted before @self text changes.
|
|
|
|
*/
|
|
|
|
text_signals[INSERT_TEXT] =
|
2010-06-03 11:57:50 +00:00
|
|
|
g_signal_new (I_("insert-text"),
|
2009-11-20 14:17:41 +00:00
|
|
|
G_TYPE_FROM_CLASS (gobject_class),
|
2010-01-04 12:03:47 +00:00
|
|
|
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
2009-11-20 14:17:41 +00:00
|
|
|
0,
|
|
|
|
NULL, NULL,
|
2010-06-11 14:49:46 +00:00
|
|
|
_clutter_marshal_VOID__STRING_INT_POINTER,
|
2009-11-20 14:17:41 +00:00
|
|
|
G_TYPE_NONE, 3,
|
|
|
|
G_TYPE_STRING,
|
|
|
|
G_TYPE_INT,
|
|
|
|
G_TYPE_POINTER);
|
|
|
|
|
|
|
|
/**
|
|
|
|
* ClutterText::delete-text:
|
|
|
|
* @self: the #ClutterText that emitted the signal
|
|
|
|
* @start_pos: the starting position
|
|
|
|
* @end_pos: the end position
|
|
|
|
*
|
|
|
|
* This signal is emitted when text is deleted from the actor by
|
|
|
|
* the user. It is emitted before @self text changes.
|
|
|
|
*/
|
|
|
|
text_signals[DELETE_TEXT] =
|
2010-06-03 11:57:50 +00:00
|
|
|
g_signal_new (I_("delete-text"),
|
2009-11-20 14:17:41 +00:00
|
|
|
G_TYPE_FROM_CLASS (gobject_class),
|
2010-01-04 12:03:47 +00:00
|
|
|
G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
|
2009-11-20 14:17:41 +00:00
|
|
|
0,
|
|
|
|
NULL, NULL,
|
2010-06-11 14:49:46 +00:00
|
|
|
_clutter_marshal_VOID__INT_INT,
|
2009-11-20 14:17:41 +00:00
|
|
|
G_TYPE_NONE, 2,
|
|
|
|
G_TYPE_INT,
|
|
|
|
G_TYPE_INT);
|
|
|
|
|
2013-03-26 22:03:19 +00:00
|
|
|
/**
|
|
|
|
* ClutterText::cursor-changed:
|
|
|
|
* @self: the #ClutterText that emitted the signal
|
|
|
|
*
|
|
|
|
* The ::cursor-changed signal is emitted whenever the cursor
|
|
|
|
* position or size changes.
|
|
|
|
*/
|
|
|
|
text_signals[CURSOR_CHANGED] =
|
|
|
|
g_signal_new (I_("cursor-changed"),
|
|
|
|
G_TYPE_FROM_CLASS (gobject_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
|
|
|
G_STRUCT_OFFSET (ClutterTextClass, cursor_changed),
|
|
|
|
NULL, NULL,
|
|
|
|
_clutter_marshal_VOID__VOID,
|
|
|
|
G_TYPE_NONE, 0);
|
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
/**
|
2012-04-30 16:12:12 +00:00
|
|
|
* ClutterText::activate:
|
2008-12-11 12:17:11 +00:00
|
|
|
* @self: the #ClutterText that emitted the signal
|
2008-12-11 11:12:48 +00:00
|
|
|
*
|
2008-12-11 11:40:55 +00:00
|
|
|
* The ::activate signal is emitted each time the actor is 'activated'
|
2008-12-16 11:30:47 +00:00
|
|
|
* by the user, normally by pressing the 'Enter' key. The signal is
|
|
|
|
* emitted only if #ClutterText:activatable is set to %TRUE.
|
2008-12-11 11:12:48 +00:00
|
|
|
*/
|
2008-12-11 11:17:26 +00:00
|
|
|
text_signals[ACTIVATE] =
|
2010-06-03 11:57:50 +00:00
|
|
|
g_signal_new (I_("activate"),
|
2008-12-11 11:12:48 +00:00
|
|
|
G_TYPE_FROM_CLASS (gobject_class),
|
|
|
|
G_SIGNAL_RUN_LAST,
|
2008-12-11 11:15:56 +00:00
|
|
|
G_STRUCT_OFFSET (ClutterTextClass, activate),
|
2008-12-11 11:12:48 +00:00
|
|
|
NULL, NULL,
|
2010-06-11 14:49:46 +00:00
|
|
|
_clutter_marshal_VOID__VOID,
|
2008-12-11 11:12:48 +00:00
|
|
|
G_TYPE_NONE, 0);
|
2008-12-11 12:03:17 +00:00
|
|
|
|
|
|
|
binding_pool = clutter_binding_pool_get_for_class (klass);
|
|
|
|
|
|
|
|
clutter_text_add_move_binding (binding_pool, "move-left",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_Left, CLUTTER_CONTROL_MASK,
|
2008-12-11 12:03:17 +00:00
|
|
|
G_CALLBACK (clutter_text_real_move_left));
|
|
|
|
clutter_text_add_move_binding (binding_pool, "move-left",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_KP_Left, CLUTTER_CONTROL_MASK,
|
2008-12-11 12:03:17 +00:00
|
|
|
G_CALLBACK (clutter_text_real_move_left));
|
|
|
|
clutter_text_add_move_binding (binding_pool, "move-right",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_Right, CLUTTER_CONTROL_MASK,
|
2008-12-11 12:03:17 +00:00
|
|
|
G_CALLBACK (clutter_text_real_move_right));
|
|
|
|
clutter_text_add_move_binding (binding_pool, "move-right",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_KP_Right, CLUTTER_CONTROL_MASK,
|
2008-12-11 12:03:17 +00:00
|
|
|
G_CALLBACK (clutter_text_real_move_right));
|
|
|
|
clutter_text_add_move_binding (binding_pool, "move-up",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_Up, 0,
|
2008-12-11 12:03:17 +00:00
|
|
|
G_CALLBACK (clutter_text_real_move_up));
|
|
|
|
clutter_text_add_move_binding (binding_pool, "move-up",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_KP_Up, 0,
|
2008-12-11 12:03:17 +00:00
|
|
|
G_CALLBACK (clutter_text_real_move_up));
|
|
|
|
clutter_text_add_move_binding (binding_pool, "move-down",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_Down, 0,
|
2008-12-11 12:03:17 +00:00
|
|
|
G_CALLBACK (clutter_text_real_move_down));
|
|
|
|
clutter_text_add_move_binding (binding_pool, "move-down",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_KP_Down, 0,
|
2008-12-11 12:03:17 +00:00
|
|
|
G_CALLBACK (clutter_text_real_move_down));
|
|
|
|
|
2008-12-16 10:39:52 +00:00
|
|
|
clutter_text_add_move_binding (binding_pool, "line-start",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_Home, 0,
|
2008-12-16 10:39:52 +00:00
|
|
|
G_CALLBACK (clutter_text_real_line_start));
|
|
|
|
clutter_text_add_move_binding (binding_pool, "line-start",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_KP_Home, 0,
|
2008-12-16 10:39:52 +00:00
|
|
|
G_CALLBACK (clutter_text_real_line_start));
|
|
|
|
clutter_text_add_move_binding (binding_pool, "line-start",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_Begin, 0,
|
2008-12-16 10:39:52 +00:00
|
|
|
G_CALLBACK (clutter_text_real_line_start));
|
|
|
|
clutter_text_add_move_binding (binding_pool, "line-end",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_End, 0,
|
2008-12-16 10:39:52 +00:00
|
|
|
G_CALLBACK (clutter_text_real_line_end));
|
|
|
|
clutter_text_add_move_binding (binding_pool, "line-end",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_KP_End, 0,
|
2008-12-16 10:39:52 +00:00
|
|
|
G_CALLBACK (clutter_text_real_line_end));
|
2008-12-11 12:03:17 +00:00
|
|
|
|
2009-01-05 12:27:45 +00:00
|
|
|
clutter_binding_pool_install_action (binding_pool, "select-all",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_a, CLUTTER_CONTROL_MASK,
|
2009-01-05 12:27:45 +00:00
|
|
|
G_CALLBACK (clutter_text_real_select_all),
|
|
|
|
NULL, NULL);
|
|
|
|
|
2008-12-11 12:03:17 +00:00
|
|
|
clutter_binding_pool_install_action (binding_pool, "delete-next",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_Delete, 0,
|
2008-12-11 12:03:17 +00:00
|
|
|
G_CALLBACK (clutter_text_real_del_next),
|
|
|
|
NULL, NULL);
|
2010-02-03 17:04:38 +00:00
|
|
|
clutter_binding_pool_install_action (binding_pool, "delete-next",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_Delete, CLUTTER_CONTROL_MASK,
|
2010-02-03 17:04:38 +00:00
|
|
|
G_CALLBACK (clutter_text_real_del_word_next),
|
|
|
|
NULL, NULL);
|
2008-12-11 12:03:17 +00:00
|
|
|
clutter_binding_pool_install_action (binding_pool, "delete-next",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_KP_Delete, 0,
|
2008-12-11 12:03:17 +00:00
|
|
|
G_CALLBACK (clutter_text_real_del_next),
|
|
|
|
NULL, NULL);
|
2010-02-03 17:04:38 +00:00
|
|
|
clutter_binding_pool_install_action (binding_pool, "delete-next",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_KP_Delete, CLUTTER_CONTROL_MASK,
|
2010-02-03 17:04:38 +00:00
|
|
|
G_CALLBACK (clutter_text_real_del_word_next),
|
|
|
|
NULL, NULL);
|
2008-12-11 12:03:17 +00:00
|
|
|
clutter_binding_pool_install_action (binding_pool, "delete-prev",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_BackSpace, 0,
|
2008-12-11 12:03:17 +00:00
|
|
|
G_CALLBACK (clutter_text_real_del_prev),
|
|
|
|
NULL, NULL);
|
2011-01-30 23:00:00 +00:00
|
|
|
clutter_binding_pool_install_action (binding_pool, "delete-prev",
|
|
|
|
CLUTTER_KEY_BackSpace, CLUTTER_SHIFT_MASK,
|
|
|
|
G_CALLBACK (clutter_text_real_del_prev),
|
|
|
|
NULL, NULL);
|
2010-02-03 17:04:38 +00:00
|
|
|
clutter_binding_pool_install_action (binding_pool, "delete-prev",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_BackSpace, CLUTTER_CONTROL_MASK,
|
2010-02-03 17:04:38 +00:00
|
|
|
G_CALLBACK (clutter_text_real_del_word_prev),
|
|
|
|
NULL, NULL);
|
2008-12-11 12:03:17 +00:00
|
|
|
|
|
|
|
clutter_binding_pool_install_action (binding_pool, "activate",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_Return, 0,
|
2008-12-11 12:03:17 +00:00
|
|
|
G_CALLBACK (clutter_text_real_activate),
|
|
|
|
NULL, NULL);
|
|
|
|
clutter_binding_pool_install_action (binding_pool, "activate",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_KP_Enter, 0,
|
2008-12-11 12:03:17 +00:00
|
|
|
G_CALLBACK (clutter_text_real_activate),
|
|
|
|
NULL, NULL);
|
|
|
|
clutter_binding_pool_install_action (binding_pool, "activate",
|
2010-09-10 12:41:49 +00:00
|
|
|
CLUTTER_KEY_ISO_Enter, 0,
|
2008-12-11 12:03:17 +00:00
|
|
|
G_CALLBACK (clutter_text_real_activate),
|
|
|
|
NULL, NULL);
|
2008-12-11 11:12:48 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
clutter_text_init (ClutterText *self)
|
|
|
|
{
|
2010-09-10 13:27:37 +00:00
|
|
|
ClutterSettings *settings;
|
2008-12-11 11:12:48 +00:00
|
|
|
ClutterTextPrivate *priv;
|
2010-09-10 13:27:37 +00:00
|
|
|
gchar *font_name;
|
2011-09-19 15:44:22 +00:00
|
|
|
int i, password_hint_time;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
|
|
|
self->priv = priv = CLUTTER_TEXT_GET_PRIVATE (self);
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2008-12-11 11:35:52 +00:00
|
|
|
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->justify = FALSE;
|
|
|
|
|
|
|
|
for (i = 0; i < N_CACHED_LAYOUTS; i++)
|
|
|
|
priv->cached_layouts[i].layout = NULL;
|
|
|
|
|
2008-12-22 13:29:10 +00:00
|
|
|
/* default to "" so that clutter_text_get_text() will
|
|
|
|
* return a valid string and we can safely call strlen()
|
|
|
|
* or strcmp() on it
|
|
|
|
*/
|
2011-06-15 09:06:31 +00:00
|
|
|
priv->buffer = NULL;
|
2008-12-11 11:35:52 +00:00
|
|
|
|
|
|
|
priv->text_color = default_text_color;
|
|
|
|
priv->cursor_color = default_cursor_color;
|
2009-04-06 14:22:31 +00:00
|
|
|
priv->selection_color = default_selection_color;
|
2011-03-02 17:02:56 +00:00
|
|
|
priv->selected_text_color = default_selected_text_color;
|
2008-12-11 11:35:52 +00:00
|
|
|
|
2010-02-03 14:35:45 +00:00
|
|
|
/* get the default font name from the context; we don't use
|
|
|
|
* set_font_description() here because we are initializing
|
|
|
|
* the Text and we don't need notifications and sanity checks
|
|
|
|
*/
|
2010-09-10 13:27:37 +00:00
|
|
|
settings = clutter_settings_get_default ();
|
2011-09-19 15:44:22 +00:00
|
|
|
g_object_get (settings,
|
|
|
|
"font-name", &font_name,
|
|
|
|
"password-hint-time", &password_hint_time,
|
|
|
|
NULL);
|
2010-09-10 13:27:37 +00:00
|
|
|
|
|
|
|
priv->font_name = font_name; /* font_name is allocated */
|
2008-12-23 15:05:16 +00:00
|
|
|
priv->font_desc = pango_font_description_from_string (font_name);
|
2010-06-26 14:49:15 +00:00
|
|
|
priv->is_default_font = TRUE;
|
2008-12-11 11:35:52 +00:00
|
|
|
|
2008-12-11 11:42:33 +00:00
|
|
|
priv->position = -1;
|
2008-12-11 11:48:17 +00:00
|
|
|
priv->selection_bound = -1;
|
2008-12-11 11:42:33 +00:00
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
priv->x_pos = -1;
|
|
|
|
priv->cursor_visible = TRUE;
|
|
|
|
priv->editable = FALSE;
|
2008-12-11 11:40:55 +00:00
|
|
|
priv->selectable = TRUE;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2009-04-06 14:22:31 +00:00
|
|
|
priv->selection_color_set = FALSE;
|
2008-12-11 11:12:48 +00:00
|
|
|
priv->cursor_color_set = FALSE;
|
2011-03-02 17:02:56 +00:00
|
|
|
priv->selected_text_color_set = FALSE;
|
2009-09-09 11:15:23 +00:00
|
|
|
priv->preedit_set = FALSE;
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2009-01-06 15:22:31 +00:00
|
|
|
priv->password_char = 0;
|
2011-09-19 15:44:22 +00:00
|
|
|
priv->show_password_hint = password_hint_time > 0;
|
|
|
|
priv->password_hint_timeout = password_hint_time;
|
2008-12-11 11:40:55 +00:00
|
|
|
|
2011-02-04 11:33:53 +00:00
|
|
|
priv->text_y = 0;
|
|
|
|
|
2008-12-15 18:24:42 +00:00
|
|
|
priv->cursor_size = DEFAULT_CURSOR_SIZE;
|
2009-01-27 16:47:20 +00:00
|
|
|
|
2011-09-19 15:44:22 +00:00
|
|
|
priv->settings_changed_id =
|
2009-01-29 13:18:57 +00:00
|
|
|
g_signal_connect_swapped (clutter_get_default_backend (),
|
2010-06-28 09:43:13 +00:00
|
|
|
"settings-changed",
|
2011-09-19 15:44:22 +00:00
|
|
|
G_CALLBACK (clutter_text_settings_changed_cb),
|
2009-01-29 13:18:57 +00:00
|
|
|
self);
|
2009-11-10 12:18:32 +00:00
|
|
|
|
|
|
|
priv->direction_changed_id =
|
|
|
|
g_signal_connect (self, "notify::text-direction",
|
|
|
|
G_CALLBACK (clutter_text_direction_changed_cb),
|
|
|
|
NULL);
|
2009-01-29 13:18:57 +00:00
|
|
|
}
|
|
|
|
|
2008-12-16 11:52:57 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_new:
|
|
|
|
*
|
|
|
|
* Creates a new #ClutterText actor. This actor can be used to
|
|
|
|
* display and edit text.
|
|
|
|
*
|
|
|
|
* Return value: the newly created #ClutterText actor
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-16 11:52:57 +00:00
|
|
|
*/
|
2008-12-11 11:43:37 +00:00
|
|
|
ClutterActor *
|
|
|
|
clutter_text_new (void)
|
|
|
|
{
|
|
|
|
return g_object_new (CLUTTER_TYPE_TEXT, NULL);
|
|
|
|
}
|
|
|
|
|
2008-12-16 11:52:57 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_new_full:
|
|
|
|
* @font_name: a string with a font description
|
|
|
|
* @text: the contents of the actor
|
|
|
|
* @color: the color to be used to render @text
|
|
|
|
*
|
|
|
|
* Creates a new #ClutterText actor, using @font_name as the font
|
|
|
|
* description; @text will be used to set the contents of the actor;
|
|
|
|
* and @color will be used as the color to render @text.
|
|
|
|
*
|
|
|
|
* This function is equivalent to calling clutter_text_new(),
|
|
|
|
* clutter_text_set_font_name(), clutter_text_set_text() and
|
|
|
|
* clutter_text_set_color().
|
|
|
|
*
|
|
|
|
* Return value: the newly created #ClutterText actor
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-16 11:52:57 +00:00
|
|
|
*/
|
2008-12-11 11:12:48 +00:00
|
|
|
ClutterActor *
|
|
|
|
clutter_text_new_full (const gchar *font_name,
|
2008-12-11 11:17:26 +00:00
|
|
|
const gchar *text,
|
|
|
|
const ClutterColor *color)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
|
|
|
return g_object_new (CLUTTER_TYPE_TEXT,
|
|
|
|
"font-name", font_name,
|
|
|
|
"text", text,
|
|
|
|
"color", color,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
2008-12-16 11:52:57 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_new_with_text:
|
2011-07-27 07:14:10 +00:00
|
|
|
* @font_name: (allow-none): a string with a font description
|
2008-12-16 11:52:57 +00:00
|
|
|
* @text: the contents of the actor
|
|
|
|
*
|
|
|
|
* Creates a new #ClutterText actor, using @font_name as the font
|
|
|
|
* description; @text will be used to set the contents of the actor.
|
|
|
|
*
|
|
|
|
* This function is equivalent to calling clutter_text_new(),
|
|
|
|
* clutter_text_set_font_name(), and clutter_text_set_text().
|
|
|
|
*
|
|
|
|
* Return value: the newly created #ClutterText actor
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-16 11:52:57 +00:00
|
|
|
*/
|
2008-12-11 11:12:48 +00:00
|
|
|
ClutterActor *
|
|
|
|
clutter_text_new_with_text (const gchar *font_name,
|
2008-12-11 11:40:55 +00:00
|
|
|
const gchar *text)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
|
|
|
return g_object_new (CLUTTER_TYPE_TEXT,
|
|
|
|
"font-name", font_name,
|
|
|
|
"text", text,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
static ClutterTextBuffer*
|
|
|
|
get_buffer (ClutterText *self)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
|
|
|
|
|
|
|
if (priv->buffer == NULL)
|
|
|
|
{
|
|
|
|
ClutterTextBuffer *buffer;
|
|
|
|
buffer = clutter_text_buffer_new ();
|
|
|
|
clutter_text_set_buffer (self, buffer);
|
|
|
|
g_object_unref (buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
return priv->buffer;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* GtkEntryBuffer signal handlers
|
|
|
|
*/
|
|
|
|
static void
|
|
|
|
buffer_inserted_text (ClutterTextBuffer *buffer,
|
|
|
|
guint position,
|
|
|
|
const gchar *chars,
|
|
|
|
guint n_chars,
|
|
|
|
ClutterText *self)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
gint new_position;
|
|
|
|
gint new_selection_bound;
|
|
|
|
gsize n_bytes;
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
if (priv->position >= 0 || priv->selection_bound >= 0)
|
|
|
|
{
|
|
|
|
new_position = priv->position;
|
|
|
|
new_selection_bound = priv->selection_bound;
|
|
|
|
|
|
|
|
if (position <= new_position)
|
|
|
|
new_position += n_chars;
|
|
|
|
if (position <= new_selection_bound)
|
|
|
|
new_selection_bound += n_chars;
|
|
|
|
|
|
|
|
if (priv->position != new_position || priv->selection_bound != new_selection_bound)
|
|
|
|
clutter_text_set_positions (self, new_position, new_selection_bound);
|
|
|
|
}
|
|
|
|
|
|
|
|
n_bytes = g_utf8_offset_to_pointer (chars, n_chars) - chars;
|
|
|
|
g_signal_emit (self, text_signals[INSERT_TEXT], 0, chars,
|
|
|
|
n_bytes, &position);
|
|
|
|
|
|
|
|
/* TODO: What are we supposed to with the out value of position? */
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
buffer_deleted_text (ClutterTextBuffer *buffer,
|
|
|
|
guint position,
|
|
|
|
guint n_chars,
|
|
|
|
ClutterText *self)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
gint new_position;
|
|
|
|
gint new_selection_bound;
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
if (priv->position >= 0 || priv->selection_bound >= 0)
|
|
|
|
{
|
|
|
|
new_position = priv->position;
|
|
|
|
new_selection_bound = priv->selection_bound;
|
|
|
|
|
|
|
|
if (position < new_position)
|
|
|
|
new_position -= n_chars;
|
|
|
|
if (position < new_selection_bound)
|
|
|
|
new_selection_bound -= n_chars;
|
|
|
|
|
|
|
|
if (priv->position != new_position || priv->selection_bound != new_selection_bound)
|
|
|
|
clutter_text_set_positions (self, new_position, new_selection_bound);
|
|
|
|
}
|
|
|
|
|
|
|
|
g_signal_emit (self, text_signals[DELETE_TEXT], 0, position, position + n_chars);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
buffer_notify_text (ClutterTextBuffer *buffer,
|
|
|
|
GParamSpec *spec,
|
|
|
|
ClutterText *self)
|
|
|
|
{
|
|
|
|
g_object_freeze_notify (G_OBJECT (self));
|
|
|
|
|
|
|
|
clutter_text_dirty_cache (self);
|
|
|
|
|
|
|
|
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
|
|
|
|
|
|
|
|
g_signal_emit (self, text_signals[TEXT_CHANGED], 0);
|
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_TEXT]);
|
|
|
|
|
|
|
|
g_object_thaw_notify (G_OBJECT (self));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
buffer_notify_max_length (ClutterTextBuffer *buffer,
|
|
|
|
GParamSpec *spec,
|
|
|
|
ClutterText *self)
|
|
|
|
{
|
|
|
|
g_object_notify (G_OBJECT (self), "max-length");
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
buffer_connect_signals (ClutterText *self)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
|
|
|
g_signal_connect (priv->buffer, "inserted-text", G_CALLBACK (buffer_inserted_text), self);
|
|
|
|
g_signal_connect (priv->buffer, "deleted-text", G_CALLBACK (buffer_deleted_text), self);
|
|
|
|
g_signal_connect (priv->buffer, "notify::text", G_CALLBACK (buffer_notify_text), self);
|
|
|
|
g_signal_connect (priv->buffer, "notify::max-length", G_CALLBACK (buffer_notify_max_length), self);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
buffer_disconnect_signals (ClutterText *self)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv = self->priv;
|
|
|
|
g_signal_handlers_disconnect_by_func (priv->buffer, buffer_inserted_text, self);
|
|
|
|
g_signal_handlers_disconnect_by_func (priv->buffer, buffer_deleted_text, self);
|
|
|
|
g_signal_handlers_disconnect_by_func (priv->buffer, buffer_notify_text, self);
|
|
|
|
g_signal_handlers_disconnect_by_func (priv->buffer, buffer_notify_max_length, self);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_text_new_with_buffer:
|
|
|
|
* @buffer: The buffer to use for the new #ClutterText.
|
|
|
|
*
|
|
|
|
* Creates a new entry with the specified text buffer.
|
|
|
|
*
|
|
|
|
* Return value: a new #ClutterText
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2011-06-15 09:06:31 +00:00
|
|
|
*/
|
|
|
|
ClutterActor *
|
|
|
|
clutter_text_new_with_buffer (ClutterTextBuffer *buffer)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT_BUFFER (buffer), NULL);
|
|
|
|
return g_object_new (CLUTTER_TYPE_TEXT, "buffer", buffer, NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_text_get_buffer:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
|
|
|
* Get the #ClutterTextBuffer object which holds the text for
|
|
|
|
* this widget.
|
|
|
|
*
|
|
|
|
* Returns: (transfer none): A #GtkEntryBuffer object.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2011-06-15 09:06:31 +00:00
|
|
|
*/
|
|
|
|
ClutterTextBuffer*
|
|
|
|
clutter_text_get_buffer (ClutterText *self)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
|
|
|
|
|
|
|
|
return get_buffer (self);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_text_set_buffer:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @buffer: a #ClutterTextBuffer
|
|
|
|
*
|
|
|
|
* Set the #ClutterTextBuffer object which holds the text for
|
|
|
|
* this widget.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2011-06-15 09:06:31 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
clutter_text_set_buffer (ClutterText *self,
|
|
|
|
ClutterTextBuffer *buffer)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
GObject *obj;
|
|
|
|
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
|
|
|
if (buffer)
|
|
|
|
{
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT_BUFFER (buffer));
|
|
|
|
g_object_ref (buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (priv->buffer)
|
|
|
|
{
|
|
|
|
buffer_disconnect_signals (self);
|
|
|
|
g_object_unref (priv->buffer);
|
|
|
|
}
|
|
|
|
|
|
|
|
priv->buffer = buffer;
|
|
|
|
|
|
|
|
if (priv->buffer)
|
|
|
|
buffer_connect_signals (self);
|
|
|
|
|
|
|
|
obj = G_OBJECT (self);
|
|
|
|
g_object_freeze_notify (obj);
|
|
|
|
g_object_notify (obj, "buffer");
|
|
|
|
g_object_notify (obj, "text");
|
|
|
|
g_object_notify (obj, "max-length");
|
|
|
|
g_object_thaw_notify (obj);
|
|
|
|
}
|
|
|
|
|
2008-12-16 11:52:57 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_set_editable:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @editable: whether the #ClutterText should be editable
|
|
|
|
*
|
|
|
|
* Sets whether the #ClutterText actor should be editable.
|
|
|
|
*
|
|
|
|
* An editable #ClutterText with key focus set using
|
2011-09-12 12:12:14 +00:00
|
|
|
* clutter_actor_grab_key_focus() or clutter_stage_set_key_focus()
|
2008-12-16 11:52:57 +00:00
|
|
|
* will receive key events and will update its contents accordingly.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-16 11:52:57 +00:00
|
|
|
*/
|
2008-12-11 11:12:48 +00:00
|
|
|
void
|
2008-12-11 11:40:55 +00:00
|
|
|
clutter_text_set_editable (ClutterText *self,
|
2008-12-11 11:17:26 +00:00
|
|
|
gboolean editable)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
|
2008-12-11 11:40:55 +00:00
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
|
|
|
if (priv->editable != editable)
|
|
|
|
{
|
|
|
|
priv->editable = editable;
|
|
|
|
|
2011-03-07 18:53:07 +00:00
|
|
|
clutter_text_queue_redraw (CLUTTER_ACTOR (self));
|
2008-12-11 11:40:55 +00:00
|
|
|
|
2011-03-03 11:35:46 +00:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EDITABLE]);
|
2008-12-11 11:40:55 +00:00
|
|
|
}
|
2008-12-11 11:12:48 +00:00
|
|
|
}
|
|
|
|
|
2008-12-16 11:52:57 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_get_editable:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
|
|
|
* Retrieves whether a #ClutterText is editable or not.
|
|
|
|
*
|
|
|
|
* Return value: %TRUE if the actor is editable
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-16 11:52:57 +00:00
|
|
|
*/
|
2008-12-11 11:12:48 +00:00
|
|
|
gboolean
|
2008-12-11 11:40:55 +00:00
|
|
|
clutter_text_get_editable (ClutterText *self)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
2008-12-11 11:40:55 +00:00
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
|
|
|
|
|
|
|
|
return self->priv->editable;
|
2008-12-11 11:12:48 +00:00
|
|
|
}
|
|
|
|
|
2008-12-16 11:52:57 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_set_selectable:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @selectable: whether the #ClutterText actor should be selectable
|
|
|
|
*
|
|
|
|
* Sets whether a #ClutterText actor should be selectable.
|
|
|
|
*
|
|
|
|
* A selectable #ClutterText will allow selecting its contents using
|
|
|
|
* the pointer or the keyboard.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-16 11:52:57 +00:00
|
|
|
*/
|
2008-12-11 11:12:48 +00:00
|
|
|
void
|
2008-12-11 11:40:55 +00:00
|
|
|
clutter_text_set_selectable (ClutterText *self,
|
|
|
|
gboolean selectable)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
|
2008-12-11 11:40:55 +00:00
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
|
|
|
if (priv->selectable != selectable)
|
|
|
|
{
|
|
|
|
priv->selectable = selectable;
|
|
|
|
|
2011-03-07 18:53:07 +00:00
|
|
|
clutter_text_queue_redraw (CLUTTER_ACTOR (self));
|
2008-12-11 11:40:55 +00:00
|
|
|
|
2011-03-03 11:35:46 +00:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SELECTABLE]);
|
2008-12-11 11:40:55 +00:00
|
|
|
}
|
2008-12-11 11:12:48 +00:00
|
|
|
}
|
|
|
|
|
2008-12-16 11:52:57 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_get_selectable:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
|
|
|
* Retrieves whether a #ClutterText is selectable or not.
|
|
|
|
*
|
|
|
|
* Return value: %TRUE if the actor is selectable
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-16 11:52:57 +00:00
|
|
|
*/
|
2008-12-11 11:12:48 +00:00
|
|
|
gboolean
|
2008-12-11 11:40:55 +00:00
|
|
|
clutter_text_get_selectable (ClutterText *self)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
2008-12-11 11:40:55 +00:00
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), TRUE);
|
|
|
|
|
|
|
|
return self->priv->selectable;
|
2008-12-11 11:12:48 +00:00
|
|
|
}
|
|
|
|
|
2008-12-16 11:52:57 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_set_activatable:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @activatable: whether the #ClutterText actor should be activatable
|
|
|
|
*
|
|
|
|
* Sets whether a #ClutterText actor should be activatable.
|
|
|
|
*
|
|
|
|
* An activatable #ClutterText actor will emit the #ClutterText::activate
|
|
|
|
* signal whenever the 'Enter' (or 'Return') key is pressed; if it is not
|
|
|
|
* activatable, a new line will be appended to the current content.
|
|
|
|
*
|
|
|
|
* An activatable #ClutterText must also be set as editable using
|
|
|
|
* clutter_text_set_editable().
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-16 11:52:57 +00:00
|
|
|
*/
|
2008-12-11 11:12:48 +00:00
|
|
|
void
|
2008-12-11 11:40:55 +00:00
|
|
|
clutter_text_set_activatable (ClutterText *self,
|
|
|
|
gboolean activatable)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
|
2008-12-11 11:40:55 +00:00
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
|
|
|
if (priv->activatable != activatable)
|
|
|
|
{
|
|
|
|
priv->activatable = activatable;
|
|
|
|
|
2011-03-07 18:53:07 +00:00
|
|
|
clutter_text_queue_redraw (CLUTTER_ACTOR (self));
|
2008-12-11 11:40:55 +00:00
|
|
|
|
2011-03-03 11:35:46 +00:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIVATABLE]);
|
2008-12-11 11:40:55 +00:00
|
|
|
}
|
2008-12-11 11:12:48 +00:00
|
|
|
}
|
|
|
|
|
2008-12-16 11:52:57 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_get_activatable:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
|
|
|
* Retrieves whether a #ClutterText is activatable or not.
|
|
|
|
*
|
|
|
|
* Return value: %TRUE if the actor is activatable
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-16 11:52:57 +00:00
|
|
|
*/
|
2008-12-11 11:12:48 +00:00
|
|
|
gboolean
|
2008-12-11 11:40:55 +00:00
|
|
|
clutter_text_get_activatable (ClutterText *self)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
2008-12-11 11:40:55 +00:00
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), TRUE);
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2008-12-11 11:40:55 +00:00
|
|
|
return self->priv->activatable;
|
|
|
|
}
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2008-12-16 12:02:58 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_activate:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
|
|
|
* Emits the #ClutterText::activate signal, if @self has been set
|
|
|
|
* as activatable using clutter_text_set_activatable().
|
|
|
|
*
|
|
|
|
* This function can be used to emit the ::activate signal inside
|
|
|
|
* a #ClutterActor::captured-event or #ClutterActor::key-press-event
|
|
|
|
* signal handlers before the default signal handler for the
|
|
|
|
* #ClutterText is invoked.
|
|
|
|
*
|
|
|
|
* Return value: %TRUE if the ::activate signal has been emitted,
|
|
|
|
* and %FALSE otherwise
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-16 12:02:58 +00:00
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
clutter_text_activate (ClutterText *self)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
|
|
|
if (priv->activatable)
|
|
|
|
{
|
|
|
|
g_signal_emit (self, text_signals[ACTIVATE], 0);
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2008-12-16 12:25:15 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_set_cursor_visible:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @cursor_visible: whether the cursor should be visible
|
|
|
|
*
|
|
|
|
* Sets whether the cursor of a #ClutterText actor should be
|
|
|
|
* visible or not.
|
|
|
|
*
|
|
|
|
* The color of the cursor will be the same as the text color
|
|
|
|
* unless clutter_text_set_cursor_color() has been called.
|
|
|
|
*
|
|
|
|
* The size of the cursor can be set using clutter_text_set_cursor_size().
|
|
|
|
*
|
|
|
|
* The position of the cursor can be changed programmatically using
|
|
|
|
* clutter_text_set_cursor_position().
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-16 12:25:15 +00:00
|
|
|
*/
|
2008-12-11 11:12:48 +00:00
|
|
|
void
|
2008-12-11 11:40:55 +00:00
|
|
|
clutter_text_set_cursor_visible (ClutterText *self,
|
|
|
|
gboolean cursor_visible)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
|
2008-12-11 11:40:55 +00:00
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
|
|
|
if (priv->cursor_visible != cursor_visible)
|
|
|
|
{
|
|
|
|
priv->cursor_visible = cursor_visible;
|
|
|
|
|
2011-03-07 18:53:07 +00:00
|
|
|
clutter_text_queue_redraw (CLUTTER_ACTOR (self));
|
2008-12-11 11:40:55 +00:00
|
|
|
|
2011-03-03 11:35:46 +00:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CURSOR_VISIBLE]);
|
2008-12-11 11:40:55 +00:00
|
|
|
}
|
2008-12-11 11:12:48 +00:00
|
|
|
}
|
|
|
|
|
2008-12-16 12:25:15 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_get_cursor_visible:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
|
|
|
* Retrieves whether the cursor of a #ClutterText actor is visible.
|
|
|
|
*
|
|
|
|
* Return value: %TRUE if the cursor is visible
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-16 12:25:15 +00:00
|
|
|
*/
|
2008-12-11 11:12:48 +00:00
|
|
|
gboolean
|
2008-12-11 11:40:55 +00:00
|
|
|
clutter_text_get_cursor_visible (ClutterText *self)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
2008-12-11 11:40:55 +00:00
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), TRUE);
|
|
|
|
|
|
|
|
return self->priv->cursor_visible;
|
2008-12-11 11:12:48 +00:00
|
|
|
}
|
|
|
|
|
2008-12-16 12:25:15 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_set_cursor_color:
|
|
|
|
* @self: a #ClutterText
|
2012-05-14 23:44:51 +00:00
|
|
|
* @color: (allow-none): the color of the cursor, or %NULL to unset it
|
2008-12-16 12:25:15 +00:00
|
|
|
*
|
|
|
|
* Sets the color of the cursor of a #ClutterText actor.
|
|
|
|
*
|
|
|
|
* If @color is %NULL, the cursor color will be the same as the
|
|
|
|
* text color.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-16 12:25:15 +00:00
|
|
|
*/
|
2008-12-11 11:12:48 +00:00
|
|
|
void
|
2008-12-11 11:40:55 +00:00
|
|
|
clutter_text_set_cursor_color (ClutterText *self,
|
|
|
|
const ClutterColor *color)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
2008-12-11 11:40:55 +00:00
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2012-05-28 12:02:25 +00:00
|
|
|
clutter_text_set_color_animated (self, obj_props[PROP_CURSOR_COLOR], color);
|
2008-12-11 11:12:48 +00:00
|
|
|
}
|
|
|
|
|
2008-12-16 12:25:15 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_get_cursor_color:
|
|
|
|
* @self: a #ClutterText
|
2011-07-27 07:14:10 +00:00
|
|
|
* @color: (out): return location for a #ClutterColor
|
2008-12-16 12:25:15 +00:00
|
|
|
*
|
|
|
|
* Retrieves the color of the cursor of a #ClutterText actor.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-16 12:25:15 +00:00
|
|
|
*/
|
2008-12-11 11:12:48 +00:00
|
|
|
void
|
2008-12-11 11:40:55 +00:00
|
|
|
clutter_text_get_cursor_color (ClutterText *self,
|
|
|
|
ClutterColor *color)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
|
2008-12-11 11:40:55 +00:00
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
2008-12-11 11:12:48 +00:00
|
|
|
g_return_if_fail (color != NULL);
|
|
|
|
|
2008-12-11 11:40:55 +00:00
|
|
|
priv = self->priv;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
|
|
|
*color = priv->cursor_color;
|
|
|
|
}
|
|
|
|
|
2008-12-16 12:41:20 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_set_selection:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @start_pos: start of the selection, in characters
|
|
|
|
* @end_pos: end of the selection, in characters
|
|
|
|
*
|
|
|
|
* Selects the region of text between @start_pos and @end_pos.
|
|
|
|
*
|
|
|
|
* This function changes the position of the cursor to match
|
|
|
|
* @start_pos and the selection bound to match @end_pos.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-16 12:41:20 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
clutter_text_set_selection (ClutterText *self,
|
|
|
|
gssize start_pos,
|
|
|
|
gssize end_pos)
|
|
|
|
{
|
2011-06-15 09:06:31 +00:00
|
|
|
guint n_chars;
|
2008-12-16 12:41:20 +00:00
|
|
|
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
n_chars = clutter_text_buffer_get_length (get_buffer (self));
|
2008-12-16 12:41:20 +00:00
|
|
|
if (end_pos < 0)
|
2011-06-15 09:06:31 +00:00
|
|
|
end_pos = n_chars;
|
2008-12-16 12:41:20 +00:00
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
start_pos = MIN (n_chars, start_pos);
|
|
|
|
end_pos = MIN (n_chars, end_pos);
|
2008-12-16 12:41:20 +00:00
|
|
|
|
2010-01-25 15:13:58 +00:00
|
|
|
clutter_text_set_positions (self, start_pos, end_pos);
|
2008-12-16 12:41:20 +00:00
|
|
|
}
|
|
|
|
|
2008-12-16 12:25:45 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_get_selection:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
|
|
|
* Retrieves the currently selected text.
|
|
|
|
*
|
|
|
|
* Return value: a newly allocated string containing the currently
|
|
|
|
* selected text, or %NULL. Use g_free() to free the returned
|
|
|
|
* string.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-16 12:25:45 +00:00
|
|
|
*/
|
2008-12-11 11:12:48 +00:00
|
|
|
gchar *
|
2008-12-16 12:25:45 +00:00
|
|
|
clutter_text_get_selection (ClutterText *self)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
2008-12-16 12:25:45 +00:00
|
|
|
gchar *str;
|
|
|
|
gint len;
|
|
|
|
gint start_index, end_index;
|
|
|
|
gint start_offset, end_offset;
|
2011-06-15 09:06:31 +00:00
|
|
|
const gchar *text;
|
2008-12-16 12:25:45 +00:00
|
|
|
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2008-12-16 12:25:45 +00:00
|
|
|
priv = self->priv;
|
2008-12-11 11:12:48 +00:00
|
|
|
|
|
|
|
start_index = priv->position;
|
|
|
|
end_index = priv->selection_bound;
|
|
|
|
|
|
|
|
if (end_index == start_index)
|
|
|
|
return g_strdup ("");
|
2008-12-16 10:15:57 +00:00
|
|
|
|
2009-05-13 11:11:54 +00:00
|
|
|
if ((end_index != -1 && end_index < start_index) ||
|
|
|
|
start_index == -1)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
|
|
|
gint temp = start_index;
|
|
|
|
start_index = end_index;
|
|
|
|
end_index = temp;
|
|
|
|
}
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
text = clutter_text_buffer_get_text (get_buffer (self));
|
|
|
|
start_offset = offset_to_bytes (text, start_index);
|
|
|
|
end_offset = offset_to_bytes (text, end_index);
|
2008-12-11 11:12:48 +00:00
|
|
|
len = end_offset - start_offset;
|
|
|
|
|
|
|
|
str = g_malloc (len + 1);
|
2011-06-15 09:06:31 +00:00
|
|
|
g_utf8_strncpy (str, text + start_offset, end_index - start_index);
|
2008-12-16 12:25:45 +00:00
|
|
|
|
2008-12-11 11:12:48 +00:00
|
|
|
return str;
|
|
|
|
}
|
|
|
|
|
2008-12-16 12:25:45 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_set_selection_bound:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @selection_bound: the position of the end of the selection, in characters
|
|
|
|
*
|
|
|
|
* Sets the other end of the selection, starting from the current
|
|
|
|
* cursor position.
|
|
|
|
*
|
|
|
|
* If @selection_bound is -1, the selection unset.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-16 12:25:45 +00:00
|
|
|
*/
|
2008-12-11 11:12:48 +00:00
|
|
|
void
|
2008-12-11 11:33:10 +00:00
|
|
|
clutter_text_set_selection_bound (ClutterText *self,
|
|
|
|
gint selection_bound)
|
2008-12-11 11:12:48 +00:00
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
priv = self->priv;
|
|
|
|
|
|
|
|
if (priv->selection_bound != selection_bound)
|
|
|
|
{
|
2011-06-15 09:06:31 +00:00
|
|
|
gint len = clutter_text_buffer_get_length (get_buffer (self));;
|
2009-03-30 06:54:42 +00:00
|
|
|
|
|
|
|
if (selection_bound < 0 || selection_bound >= len)
|
|
|
|
priv->selection_bound = -1;
|
|
|
|
else
|
|
|
|
priv->selection_bound = selection_bound;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2011-03-07 18:53:07 +00:00
|
|
|
clutter_text_queue_redraw (CLUTTER_ACTOR (self));
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2011-03-03 11:35:46 +00:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SELECTION_BOUND]);
|
2008-12-11 11:33:10 +00:00
|
|
|
}
|
2008-12-11 11:12:48 +00:00
|
|
|
}
|
|
|
|
|
2008-12-16 12:25:45 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_get_selection_bound:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
|
|
|
* Retrieves the other end of the selection of a #ClutterText actor,
|
|
|
|
* in characters from the current cursor position.
|
|
|
|
*
|
|
|
|
* Return value: the position of the other end of the selection
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-16 12:25:45 +00:00
|
|
|
*/
|
2008-12-11 11:33:10 +00:00
|
|
|
gint
|
|
|
|
clutter_text_get_selection_bound (ClutterText *self)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), -1);
|
|
|
|
|
|
|
|
return self->priv->selection_bound;
|
|
|
|
}
|
2008-12-11 11:12:48 +00:00
|
|
|
|
2009-04-06 14:22:31 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_set_selection_color:
|
|
|
|
* @self: a #ClutterText
|
2012-05-14 23:44:51 +00:00
|
|
|
* @color: (allow-none): the color of the selection, or %NULL to unset it
|
2009-04-06 14:22:31 +00:00
|
|
|
*
|
|
|
|
* Sets the color of the selection of a #ClutterText actor.
|
|
|
|
*
|
|
|
|
* If @color is %NULL, the selection color will be the same as the
|
|
|
|
* cursor color, or if no cursor color is set either then it will be
|
|
|
|
* the same as the text color.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2009-04-06 14:22:31 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
clutter_text_set_selection_color (ClutterText *self,
|
|
|
|
const ClutterColor *color)
|
|
|
|
{
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
|
2012-05-28 12:02:25 +00:00
|
|
|
clutter_text_set_color_animated (self, obj_props[PROP_SELECTION_COLOR],
|
|
|
|
color);
|
2009-04-06 14:22:31 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_text_get_selection_color:
|
|
|
|
* @self: a #ClutterText
|
2011-02-14 18:36:51 +00:00
|
|
|
* @color: (out caller-allocates): return location for a #ClutterColor
|
2009-04-06 14:22:31 +00:00
|
|
|
*
|
|
|
|
* Retrieves the color of the selection of a #ClutterText actor.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2009-04-06 14:22:31 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
clutter_text_get_selection_color (ClutterText *self,
|
|
|
|
ClutterColor *color)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
g_return_if_fail (color != NULL);
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
|
|
|
*color = priv->selection_color;
|
|
|
|
}
|
|
|
|
|
2011-03-02 17:02:56 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_set_selected_text_color:
|
|
|
|
* @self: a #ClutterText
|
2012-05-14 23:44:51 +00:00
|
|
|
* @color: (allow-none): the selected text color, or %NULL to unset it
|
2011-03-02 17:02:56 +00:00
|
|
|
*
|
|
|
|
* Sets the selected text color of a #ClutterText actor.
|
|
|
|
*
|
|
|
|
* If @color is %NULL, the selected text color will be the same as the
|
|
|
|
* selection color, which then falls back to cursor, and then text color.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2011-03-02 17:02:56 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
clutter_text_set_selected_text_color (ClutterText *self,
|
|
|
|
const ClutterColor *color)
|
|
|
|
{
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
|
2012-05-28 12:02:25 +00:00
|
|
|
clutter_text_set_color_animated (self, obj_props[PROP_SELECTED_TEXT_COLOR],
|
|
|
|
color);
|
2011-03-02 17:02:56 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_text_get_selected_text_color:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @color: (out caller-allocates): return location for a #ClutterColor
|
|
|
|
*
|
|
|
|
* Retrieves the color of selected text of a #ClutterText actor.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2011-03-02 17:02:56 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
clutter_text_get_selected_text_color (ClutterText *self,
|
|
|
|
ClutterColor *color)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
g_return_if_fail (color != NULL);
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
|
|
|
*color = priv->selected_text_color;
|
|
|
|
}
|
|
|
|
|
2010-02-03 14:35:45 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_set_font_description:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @font_desc: a #PangoFontDescription
|
|
|
|
*
|
|
|
|
* Sets @font_desc as the font description for a #ClutterText
|
|
|
|
*
|
|
|
|
* The #PangoFontDescription is copied by the #ClutterText actor
|
|
|
|
* so you can safely call pango_font_description_free() on it after
|
|
|
|
* calling this function.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2010-02-03 14:35:45 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
clutter_text_set_font_description (ClutterText *self,
|
|
|
|
PangoFontDescription *font_desc)
|
|
|
|
{
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
|
2013-03-04 13:02:44 +00:00
|
|
|
clutter_text_set_font_description_internal (self, font_desc);
|
2010-02-03 14:35:45 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_text_get_font_description:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
|
|
|
* Retrieves the #PangoFontDescription used by @self
|
|
|
|
*
|
|
|
|
* Return value: a #PangoFontDescription. The returned value is owned
|
|
|
|
* by the #ClutterText actor and it should not be modified or freed
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2010-02-03 14:35:45 +00:00
|
|
|
*/
|
|
|
|
PangoFontDescription *
|
|
|
|
clutter_text_get_font_description (ClutterText *self)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
|
|
|
|
|
|
|
|
return self->priv->font_desc;
|
|
|
|
}
|
|
|
|
|
2008-12-11 12:17:11 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_get_font_name:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
|
|
|
* Retrieves the font name as set by clutter_text_set_font_name().
|
|
|
|
*
|
|
|
|
* Return value: a string containing the font name. The returned
|
|
|
|
* string is owned by the #ClutterText actor and should not be
|
|
|
|
* modified or freed
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 12:17:11 +00:00
|
|
|
*/
|
Eliminate G_CONST_RETURN
The G_CONST_RETURN define in GLib is, and has always been, a bit fuzzy.
We always used it to conform to the platform, at least for public-facing
API.
At first I assumed it has something to do with brain-damaged compilers
or with weird platforms where const was not really supported; sadly,
it's something much, much worse: it's a define that can be toggled at
compile-time to remove const from the signature of public API. This is a
truly terrifying feature that I assume was added in the past century,
and whose inception clearly had something to do with massive doses of
absynthe and opium — because any other explanation would make the
existence of such a feature even worse than assuming drugs had anything
to do with it.
Anyway, and pleasing the gods, this dubious feature is being
removed/deprecated in GLib; see bug:
https://bugzilla.gnome.org/show_bug.cgi?id=644611
Before deprecation, though, we should just remove its usage from the
whole API. We should especially remove its usage from Cally's internals,
since there it never made sense in the first place.
2011-06-07 14:49:20 +00:00
|
|
|
const gchar *
|
2008-12-11 11:17:26 +00:00
|
|
|
clutter_text_get_font_name (ClutterText *text)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (text), NULL);
|
|
|
|
|
|
|
|
return text->priv->font_name;
|
|
|
|
}
|
|
|
|
|
2008-12-11 12:17:11 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_set_font_name:
|
|
|
|
* @self: a #ClutterText
|
2010-06-26 22:05:36 +00:00
|
|
|
* @font_name: (allow-none): a font name, or %NULL to set the default font name
|
2008-12-11 12:17:11 +00:00
|
|
|
*
|
|
|
|
* Sets the font used by a #ClutterText. The @font_name string
|
2008-12-23 15:05:16 +00:00
|
|
|
* must either be %NULL, which means that the font name from the
|
|
|
|
* default #ClutterBackend will be used; or be something that can
|
|
|
|
* be parsed by the pango_font_description_from_string() function,
|
|
|
|
* like:
|
2008-12-11 12:17:11 +00:00
|
|
|
*
|
|
|
|
* |[
|
|
|
|
* clutter_text_set_font_name (text, "Sans 10pt");
|
|
|
|
* clutter_text_set_font_name (text, "Serif 16px");
|
|
|
|
* clutter_text_set_font_name (text, "Helvetica 10");
|
|
|
|
* ]|
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 12:17:11 +00:00
|
|
|
*/
|
2008-12-11 11:17:26 +00:00
|
|
|
void
|
2008-12-11 11:54:32 +00:00
|
|
|
clutter_text_set_font_name (ClutterText *self,
|
2008-12-11 11:17:26 +00:00
|
|
|
const gchar *font_name)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
PangoFontDescription *desc;
|
2010-06-26 14:49:15 +00:00
|
|
|
gboolean is_default_font;
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2008-12-11 11:54:32 +00:00
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2008-12-23 15:05:16 +00:00
|
|
|
/* get the default font name from the backend */
|
2010-11-14 15:23:36 +00:00
|
|
|
if (font_name == NULL || font_name[0] == '\0')
|
2010-06-26 14:49:15 +00:00
|
|
|
{
|
2010-09-10 13:27:37 +00:00
|
|
|
ClutterSettings *settings = clutter_settings_get_default ();
|
|
|
|
gchar *default_font_name = NULL;
|
|
|
|
|
2010-11-14 15:23:36 +00:00
|
|
|
g_object_get (settings, "font-name", &default_font_name, NULL);
|
|
|
|
|
|
|
|
if (default_font_name != NULL)
|
|
|
|
font_name = default_font_name;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
/* last fallback */
|
2012-12-01 02:39:10 +00:00
|
|
|
font_name = g_strdup ("Sans 12");
|
2010-11-14 15:23:36 +00:00
|
|
|
}
|
|
|
|
|
2010-06-26 14:49:15 +00:00
|
|
|
is_default_font = TRUE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
is_default_font = FALSE;
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2008-12-11 11:54:32 +00:00
|
|
|
priv = self->priv;
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2010-11-14 15:23:36 +00:00
|
|
|
if (g_strcmp0 (priv->font_name, font_name) == 0)
|
2010-09-10 13:27:37 +00:00
|
|
|
goto out;
|
2008-12-11 11:17:26 +00:00
|
|
|
|
|
|
|
desc = pango_font_description_from_string (font_name);
|
2013-03-04 13:02:44 +00:00
|
|
|
if (desc == NULL)
|
2008-12-11 11:17:26 +00:00
|
|
|
{
|
|
|
|
g_warning ("Attempting to create a PangoFontDescription for "
|
2009-03-17 14:12:01 +00:00
|
|
|
"font name '%s', but failed.",
|
2008-12-11 11:17:26 +00:00
|
|
|
font_name);
|
2010-09-10 13:27:37 +00:00
|
|
|
goto out;
|
2008-12-11 11:17:26 +00:00
|
|
|
}
|
|
|
|
|
2010-02-03 14:35:45 +00:00
|
|
|
/* this will set the font_name field as well */
|
|
|
|
clutter_text_set_font_description_internal (self, desc);
|
2010-06-26 14:49:15 +00:00
|
|
|
priv->is_default_font = is_default_font;
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2011-03-03 11:35:46 +00:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_FONT_NAME]);
|
2010-09-10 13:27:37 +00:00
|
|
|
|
2013-03-04 13:02:44 +00:00
|
|
|
pango_font_description_free (desc);
|
|
|
|
|
2010-09-10 13:27:37 +00:00
|
|
|
out:
|
|
|
|
if (is_default_font)
|
|
|
|
g_free ((gchar *) font_name);
|
2008-12-11 11:17:26 +00:00
|
|
|
}
|
|
|
|
|
2008-12-11 12:17:11 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_get_text:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
|
|
|
* Retrieves a pointer to the current contents of a #ClutterText
|
|
|
|
* actor.
|
|
|
|
*
|
|
|
|
* If you need a copy of the contents for manipulating, either
|
|
|
|
* use g_strdup() on the returned string, or use:
|
|
|
|
*
|
|
|
|
* |[
|
|
|
|
* copy = clutter_text_get_chars (text, 0, -1);
|
|
|
|
* ]|
|
|
|
|
*
|
|
|
|
* Which will return a newly allocated string.
|
|
|
|
*
|
2011-09-07 12:28:15 +00:00
|
|
|
* If the #ClutterText actor is empty, this function will return
|
|
|
|
* an empty string, and not %NULL.
|
|
|
|
*
|
|
|
|
* Return value: (transfer none): the contents of the actor. The returned
|
|
|
|
* string is owned by the #ClutterText actor and should never be modified
|
|
|
|
* or freed
|
2008-12-11 12:17:11 +00:00
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 12:17:11 +00:00
|
|
|
*/
|
Eliminate G_CONST_RETURN
The G_CONST_RETURN define in GLib is, and has always been, a bit fuzzy.
We always used it to conform to the platform, at least for public-facing
API.
At first I assumed it has something to do with brain-damaged compilers
or with weird platforms where const was not really supported; sadly,
it's something much, much worse: it's a define that can be toggled at
compile-time to remove const from the signature of public API. This is a
truly terrifying feature that I assume was added in the past century,
and whose inception clearly had something to do with massive doses of
absynthe and opium — because any other explanation would make the
existence of such a feature even worse than assuming drugs had anything
to do with it.
Anyway, and pleasing the gods, this dubious feature is being
removed/deprecated in GLib; see bug:
https://bugzilla.gnome.org/show_bug.cgi?id=644611
Before deprecation, though, we should just remove its usage from the
whole API. We should especially remove its usage from Cally's internals,
since there it never made sense in the first place.
2011-06-07 14:49:20 +00:00
|
|
|
const gchar *
|
2008-12-11 11:54:32 +00:00
|
|
|
clutter_text_get_text (ClutterText *self)
|
2008-12-11 11:17:26 +00:00
|
|
|
{
|
2008-12-11 11:54:32 +00:00
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
return clutter_text_buffer_get_text (get_buffer (self));
|
2008-12-11 11:17:26 +00:00
|
|
|
}
|
|
|
|
|
2009-01-29 13:18:57 +00:00
|
|
|
static inline void
|
|
|
|
clutter_text_set_use_markup_internal (ClutterText *self,
|
|
|
|
gboolean use_markup)
|
2008-12-11 11:17:26 +00:00
|
|
|
{
|
2009-01-29 13:18:57 +00:00
|
|
|
ClutterTextPrivate *priv = self->priv;
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2009-01-29 13:18:57 +00:00
|
|
|
if (priv->use_markup != use_markup)
|
|
|
|
{
|
|
|
|
priv->use_markup = use_markup;
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2010-08-06 16:04:37 +00:00
|
|
|
/* reset the attributes lists so that they can be
|
|
|
|
* re-generated
|
|
|
|
*/
|
|
|
|
if (priv->effective_attrs != NULL)
|
|
|
|
{
|
|
|
|
pango_attr_list_unref (priv->effective_attrs);
|
|
|
|
priv->effective_attrs = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (priv->markup_attrs)
|
|
|
|
{
|
|
|
|
pango_attr_list_unref (priv->markup_attrs);
|
|
|
|
priv->markup_attrs = NULL;
|
|
|
|
}
|
|
|
|
|
2011-03-03 11:35:46 +00:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_USE_MARKUP]);
|
2009-01-29 13:18:57 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_text_set_text:
|
|
|
|
* @self: a #ClutterText
|
2012-02-07 11:33:12 +00:00
|
|
|
* @text: (allow-none): the text to set. Passing %NULL is the same
|
|
|
|
* as passing "" (the empty string)
|
2009-01-29 13:18:57 +00:00
|
|
|
*
|
2009-02-27 16:56:39 +00:00
|
|
|
* Sets the contents of a #ClutterText actor.
|
2009-01-29 13:18:57 +00:00
|
|
|
*
|
2009-10-07 20:44:17 +00:00
|
|
|
* If the #ClutterText:use-markup property was set to %TRUE it
|
|
|
|
* will be reset to %FALSE as a side effect. If you want to
|
|
|
|
* maintain the #ClutterText:use-markup you should use the
|
|
|
|
* clutter_text_set_markup() function instead
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2009-01-29 13:18:57 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
clutter_text_set_text (ClutterText *self,
|
|
|
|
const gchar *text)
|
|
|
|
{
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
|
2012-02-07 11:36:27 +00:00
|
|
|
/* if the text is editable (i.e. there is not markup flag to reset) then
|
|
|
|
* changing the contents will result in selection and cursor changes that
|
|
|
|
* we should avoid
|
|
|
|
*/
|
|
|
|
if (self->priv->editable)
|
|
|
|
{
|
2012-05-11 17:26:50 +00:00
|
|
|
if (g_strcmp0 (clutter_text_buffer_get_text (get_buffer (self)), text) == 0)
|
2012-02-07 11:36:27 +00:00
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2009-01-29 13:18:57 +00:00
|
|
|
clutter_text_set_use_markup_internal (self, FALSE);
|
2012-05-11 17:26:50 +00:00
|
|
|
clutter_text_buffer_set_text (get_buffer (self), text ? text : "", -1);
|
2009-01-29 13:18:57 +00:00
|
|
|
}
|
2008-12-11 11:40:55 +00:00
|
|
|
|
2009-01-29 13:18:57 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_set_markup:
|
|
|
|
* @self: a #ClutterText
|
2012-02-07 11:33:12 +00:00
|
|
|
* @markup: (allow-none): a string containing Pango markup.
|
|
|
|
* Passing %NULL is the same as passing "" (the empty string)
|
2009-01-29 13:18:57 +00:00
|
|
|
*
|
|
|
|
* Sets @markup as the contents of a #ClutterText.
|
|
|
|
*
|
|
|
|
* This is a convenience function for setting a string containing
|
|
|
|
* Pango markup, and it is logically equivalent to:
|
|
|
|
*
|
|
|
|
* |[
|
2011-09-07 12:08:22 +00:00
|
|
|
* /* the order is important */
|
2009-01-29 13:18:57 +00:00
|
|
|
* clutter_text_set_text (CLUTTER_TEXT (actor), markup);
|
2009-10-07 20:44:17 +00:00
|
|
|
* clutter_text_set_use_markup (CLUTTER_TEXT (actor), TRUE);
|
2009-01-29 13:18:57 +00:00
|
|
|
* ]|
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2009-01-29 13:18:57 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
clutter_text_set_markup (ClutterText *self,
|
|
|
|
const gchar *markup)
|
|
|
|
{
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2009-01-29 13:18:57 +00:00
|
|
|
clutter_text_set_use_markup_internal (self, TRUE);
|
2011-06-15 09:06:31 +00:00
|
|
|
if (markup != NULL && *markup != '\0')
|
|
|
|
clutter_text_set_markup_internal (self, markup);
|
|
|
|
else
|
|
|
|
clutter_text_buffer_set_text (get_buffer (self), "", 0);
|
2008-12-11 11:17:26 +00:00
|
|
|
}
|
|
|
|
|
2008-12-11 12:17:11 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_get_layout:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
|
|
|
* Retrieves the current #PangoLayout used by a #ClutterText actor.
|
|
|
|
*
|
2009-02-17 00:25:20 +00:00
|
|
|
* Return value: (transfer none): a #PangoLayout. The returned object is owned by
|
2008-12-11 12:17:11 +00:00
|
|
|
* the #ClutterText actor and should not be modified or freed
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 12:17:11 +00:00
|
|
|
*/
|
2008-12-11 11:17:26 +00:00
|
|
|
PangoLayout *
|
2008-12-11 11:54:32 +00:00
|
|
|
clutter_text_get_layout (ClutterText *self)
|
2008-12-11 11:17:26 +00:00
|
|
|
{
|
Remove Units from the public API
With the recent change to internal floating point values, ClutterUnit
has become a redundant type, defined to be a float. All integer entry
points are being internally converted to floating point values to be
passed to the GL pipeline with the least amount of conversion.
ClutterUnit is thus exposed as just a "pixel with fractionary bits",
and not -- as users might think -- as generic, resolution and device
independent units. not that it was the case, but a definitive amount
of people was convinced it did provide this "feature", and was flummoxed
about the mere existence of this type.
So, having ClutterUnit exposed in the public API doubles the entry
points and has the following disadvantages:
- we have to maintain twice the amount of entry points in ClutterActor
- we still do an integer-to-float implicit conversion
- we introduce a weird impedance between pixels and "pixels with
fractionary bits"
- language bindings will have to choose what to bind, and resort
to manually overriding the API
+ *except* for language bindings based on GObject-Introspection, as
they cannot do manual overrides, thus will replicate the entire
set of entry points
For these reason, we should coalesces every Actor entry point for
pixels and for ClutterUnit into a single entry point taking a float,
like:
void clutter_actor_set_x (ClutterActor *self,
gfloat x);
void clutter_actor_get_size (ClutterActor *self,
gfloat *width,
gfloat *height);
gfloat clutter_actor_get_height (ClutterActor *self);
etc.
The issues I have identified are:
- we'll have a two cases of compiler warnings:
- printf() format of the return values from %d to %f
- clutter_actor_get_size() taking floats instead of unsigned ints
- we'll have a problem with varargs when passing an integer instead
of a floating point value, except on 64bit platforms where the
size of a float is the same as the size of an int
To be clear: the *intent* of the API should not change -- we still use
pixels everywhere -- but:
- we remove ambiguity in the API with regard to pixels and units
- we remove entry points we get to maintain for the whole 1.0
version of the API
- we make things simpler to bind for both manual language bindings
and automatic (gobject-introspection based) ones
- we have the simplest API possible while still exposing the
capabilities of the underlying GL implementation
2009-05-06 15:44:47 +00:00
|
|
|
gfloat width, height;
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2008-12-11 11:54:32 +00:00
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2010-07-09 17:37:34 +00:00
|
|
|
if (self->priv->editable && self->priv->single_line_mode)
|
|
|
|
return clutter_text_create_layout (self, -1, -1);
|
|
|
|
|
Remove Units from the public API
With the recent change to internal floating point values, ClutterUnit
has become a redundant type, defined to be a float. All integer entry
points are being internally converted to floating point values to be
passed to the GL pipeline with the least amount of conversion.
ClutterUnit is thus exposed as just a "pixel with fractionary bits",
and not -- as users might think -- as generic, resolution and device
independent units. not that it was the case, but a definitive amount
of people was convinced it did provide this "feature", and was flummoxed
about the mere existence of this type.
So, having ClutterUnit exposed in the public API doubles the entry
points and has the following disadvantages:
- we have to maintain twice the amount of entry points in ClutterActor
- we still do an integer-to-float implicit conversion
- we introduce a weird impedance between pixels and "pixels with
fractionary bits"
- language bindings will have to choose what to bind, and resort
to manually overriding the API
+ *except* for language bindings based on GObject-Introspection, as
they cannot do manual overrides, thus will replicate the entire
set of entry points
For these reason, we should coalesces every Actor entry point for
pixels and for ClutterUnit into a single entry point taking a float,
like:
void clutter_actor_set_x (ClutterActor *self,
gfloat x);
void clutter_actor_get_size (ClutterActor *self,
gfloat *width,
gfloat *height);
gfloat clutter_actor_get_height (ClutterActor *self);
etc.
The issues I have identified are:
- we'll have a two cases of compiler warnings:
- printf() format of the return values from %d to %f
- clutter_actor_get_size() taking floats instead of unsigned ints
- we'll have a problem with varargs when passing an integer instead
of a floating point value, except on 64bit platforms where the
size of a float is the same as the size of an int
To be clear: the *intent* of the API should not change -- we still use
pixels everywhere -- but:
- we remove ambiguity in the API with regard to pixels and units
- we remove entry points we get to maintain for the whole 1.0
version of the API
- we make things simpler to bind for both manual language bindings
and automatic (gobject-introspection based) ones
- we have the simplest API possible while still exposing the
capabilities of the underlying GL implementation
2009-05-06 15:44:47 +00:00
|
|
|
clutter_actor_get_size (CLUTTER_ACTOR (self), &width, &height);
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2008-12-16 14:02:05 +00:00
|
|
|
return clutter_text_create_layout (self, width, height);
|
2008-12-11 11:17:26 +00:00
|
|
|
}
|
|
|
|
|
2008-12-11 12:17:11 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_set_color:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @color: a #ClutterColor
|
|
|
|
*
|
|
|
|
* Sets the color of the contents of a #ClutterText actor.
|
|
|
|
*
|
|
|
|
* The overall opacity of the #ClutterText actor will be the
|
|
|
|
* result of the alpha value of @color and the composited
|
|
|
|
* opacity of the actor itself on the scenegraph, as returned
|
|
|
|
* by clutter_actor_get_paint_opacity().
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 12:17:11 +00:00
|
|
|
*/
|
2008-12-11 11:17:26 +00:00
|
|
|
void
|
2008-12-11 11:54:32 +00:00
|
|
|
clutter_text_set_color (ClutterText *self,
|
2008-12-11 11:17:26 +00:00
|
|
|
const ClutterColor *color)
|
|
|
|
{
|
2008-12-11 11:54:32 +00:00
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
2008-12-11 11:17:26 +00:00
|
|
|
g_return_if_fail (color != NULL);
|
|
|
|
|
2012-05-28 12:02:25 +00:00
|
|
|
clutter_text_set_color_animated (self, obj_props[PROP_COLOR], color);
|
2008-12-11 11:17:26 +00:00
|
|
|
}
|
|
|
|
|
2008-12-11 12:17:11 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_get_color:
|
|
|
|
* @self: a #ClutterText
|
2011-02-14 18:36:51 +00:00
|
|
|
* @color: (out caller-allocates): return location for a #ClutterColor
|
2008-12-11 12:17:11 +00:00
|
|
|
*
|
2009-08-05 14:51:49 +00:00
|
|
|
* Retrieves the text color as set by clutter_text_set_color().
|
2008-12-11 12:17:11 +00:00
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 12:17:11 +00:00
|
|
|
*/
|
2008-12-11 11:17:26 +00:00
|
|
|
void
|
2008-12-11 11:54:32 +00:00
|
|
|
clutter_text_get_color (ClutterText *self,
|
2008-12-11 11:17:26 +00:00
|
|
|
ClutterColor *color)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
|
2008-12-11 11:54:32 +00:00
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
2008-12-11 11:17:26 +00:00
|
|
|
g_return_if_fail (color != NULL);
|
|
|
|
|
2008-12-11 11:54:32 +00:00
|
|
|
priv = self->priv;
|
2008-12-11 11:17:26 +00:00
|
|
|
|
|
|
|
*color = priv->text_color;
|
|
|
|
}
|
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_set_ellipsize:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @mode: a #PangoEllipsizeMode
|
|
|
|
*
|
|
|
|
* Sets the mode used to ellipsize (add an ellipsis: "...") to the
|
|
|
|
* text if there is not enough space to render the entire contents
|
|
|
|
* of a #ClutterText actor
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 11:33:10 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
clutter_text_set_ellipsize (ClutterText *self,
|
|
|
|
PangoEllipsizeMode mode)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
g_return_if_fail (mode >= PANGO_ELLIPSIZE_NONE &&
|
|
|
|
mode <= PANGO_ELLIPSIZE_END);
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
|
|
|
if ((PangoEllipsizeMode) priv->ellipsize != mode)
|
|
|
|
{
|
|
|
|
priv->ellipsize = mode;
|
|
|
|
|
|
|
|
clutter_text_dirty_cache (self);
|
|
|
|
|
|
|
|
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
|
|
|
|
|
2011-03-03 11:35:46 +00:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ELLIPSIZE]);
|
2008-12-11 11:33:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_text_get_ellipsize:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
|
|
|
* Returns the ellipsizing position of a #ClutterText actor, as
|
|
|
|
* set by clutter_text_set_ellipsize().
|
|
|
|
*
|
|
|
|
* Return value: #PangoEllipsizeMode
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 11:33:10 +00:00
|
|
|
*/
|
|
|
|
PangoEllipsizeMode
|
|
|
|
clutter_text_get_ellipsize (ClutterText *self)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), PANGO_ELLIPSIZE_NONE);
|
|
|
|
|
|
|
|
return self->priv->ellipsize;
|
|
|
|
}
|
|
|
|
|
2008-12-11 12:17:11 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_get_line_wrap:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
|
|
|
* Retrieves the value set using clutter_text_set_line_wrap().
|
|
|
|
*
|
|
|
|
* Return value: %TRUE if the #ClutterText actor should wrap
|
|
|
|
* its contents
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 12:17:11 +00:00
|
|
|
*/
|
2008-12-11 11:17:26 +00:00
|
|
|
gboolean
|
2008-12-11 11:33:10 +00:00
|
|
|
clutter_text_get_line_wrap (ClutterText *self)
|
2008-12-11 11:17:26 +00:00
|
|
|
{
|
2008-12-11 11:33:10 +00:00
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
return self->priv->wrap;
|
2008-12-11 11:17:26 +00:00
|
|
|
}
|
|
|
|
|
2008-12-11 12:17:11 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_set_line_wrap:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @line_wrap: whether the contents should wrap
|
|
|
|
*
|
|
|
|
* Sets whether the contents of a #ClutterText actor should wrap,
|
|
|
|
* if they don't fit the size assigned to the actor.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 12:17:11 +00:00
|
|
|
*/
|
2008-12-11 11:17:26 +00:00
|
|
|
void
|
2008-12-11 11:33:10 +00:00
|
|
|
clutter_text_set_line_wrap (ClutterText *self,
|
2008-12-11 11:17:26 +00:00
|
|
|
gboolean line_wrap)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
priv = self->priv;
|
2008-12-11 11:17:26 +00:00
|
|
|
|
|
|
|
if (priv->wrap != line_wrap)
|
|
|
|
{
|
|
|
|
priv->wrap = line_wrap;
|
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
clutter_text_dirty_cache (self);
|
|
|
|
|
|
|
|
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
|
|
|
|
|
2011-03-03 11:35:46 +00:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LINE_WRAP]);
|
2008-12-11 11:33:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_text_set_line_wrap_mode:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @wrap_mode: the line wrapping mode
|
|
|
|
*
|
|
|
|
* If line wrapping is enabled (see clutter_text_set_line_wrap()) this
|
|
|
|
* function controls how the line wrapping is performed. The default is
|
|
|
|
* %PANGO_WRAP_WORD which means wrap on word boundaries.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 11:33:10 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
clutter_text_set_line_wrap_mode (ClutterText *self,
|
|
|
|
PangoWrapMode wrap_mode)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
|
|
|
if (priv->wrap_mode != wrap_mode)
|
|
|
|
{
|
|
|
|
priv->wrap_mode = wrap_mode;
|
|
|
|
|
|
|
|
clutter_text_dirty_cache (self);
|
|
|
|
|
|
|
|
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
|
2008-12-11 11:17:26 +00:00
|
|
|
|
2011-03-03 11:35:46 +00:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LINE_WRAP_MODE]);
|
2008-12-11 11:17:26 +00:00
|
|
|
}
|
|
|
|
}
|
2008-12-11 11:33:10 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_text_get_line_wrap_mode:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
|
|
|
* Retrieves the line wrap mode used by the #ClutterText actor.
|
|
|
|
*
|
|
|
|
* See clutter_text_set_line_wrap_mode ().
|
|
|
|
*
|
|
|
|
* Return value: the wrap mode used by the #ClutterText
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 11:33:10 +00:00
|
|
|
*/
|
|
|
|
PangoWrapMode
|
|
|
|
clutter_text_get_line_wrap_mode (ClutterText *self)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), PANGO_WRAP_WORD);
|
|
|
|
|
|
|
|
return self->priv->wrap_mode;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_text_set_attributes:
|
|
|
|
* @self: a #ClutterText
|
2012-05-14 23:44:51 +00:00
|
|
|
* @attrs: (allow-none): a #PangoAttrList or %NULL to unset the attributes
|
2008-12-11 11:33:10 +00:00
|
|
|
*
|
|
|
|
* Sets the attributes list that are going to be applied to the
|
2009-01-29 13:18:57 +00:00
|
|
|
* #ClutterText contents.
|
2008-12-11 11:33:10 +00:00
|
|
|
*
|
|
|
|
* The #ClutterText actor will take a reference on the #PangoAttrList
|
|
|
|
* passed to this function.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 11:33:10 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
clutter_text_set_attributes (ClutterText *self,
|
|
|
|
PangoAttrList *attrs)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
2012-12-01 01:21:23 +00:00
|
|
|
/* While we should probably test for equality, Pango doesn't
|
|
|
|
* provide us an easy method to check for AttrList equality.
|
|
|
|
*/
|
|
|
|
if (priv->attrs == attrs)
|
|
|
|
return;
|
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
if (attrs)
|
|
|
|
pango_attr_list_ref (attrs);
|
|
|
|
|
|
|
|
if (priv->attrs)
|
|
|
|
pango_attr_list_unref (priv->attrs);
|
|
|
|
|
2009-01-29 13:18:57 +00:00
|
|
|
priv->attrs = attrs;
|
|
|
|
|
2010-01-05 11:58:12 +00:00
|
|
|
/* Clear the effective attributes so they will be regenerated when a
|
|
|
|
layout is created */
|
|
|
|
if (priv->effective_attrs)
|
2008-12-11 11:33:10 +00:00
|
|
|
{
|
2010-01-05 11:58:12 +00:00
|
|
|
pango_attr_list_unref (priv->effective_attrs);
|
|
|
|
priv->effective_attrs = NULL;
|
2008-12-11 11:33:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
clutter_text_dirty_cache (self);
|
|
|
|
|
2011-03-03 11:35:46 +00:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ATTRIBUTES]);
|
2008-12-11 11:33:10 +00:00
|
|
|
|
|
|
|
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_text_get_attributes:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
|
|
|
* Gets the attribute list that was set on the #ClutterText actor
|
|
|
|
* clutter_text_set_attributes(), if any.
|
|
|
|
*
|
2009-02-17 00:25:20 +00:00
|
|
|
* Return value: (transfer none): the attribute list, or %NULL if none was set. The
|
|
|
|
* returned value is owned by the #ClutterText and should not be unreferenced.
|
2008-12-11 11:33:10 +00:00
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 11:33:10 +00:00
|
|
|
*/
|
|
|
|
PangoAttrList *
|
|
|
|
clutter_text_get_attributes (ClutterText *self)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
|
|
|
|
|
|
|
|
return self->priv->attrs;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-02-02 23:55:30 +00:00
|
|
|
* clutter_text_set_line_alignment:
|
2008-12-11 11:33:10 +00:00
|
|
|
* @self: a #ClutterText
|
|
|
|
* @alignment: A #PangoAlignment
|
|
|
|
*
|
2009-02-02 23:55:30 +00:00
|
|
|
* Sets the way that the lines of a wrapped label are aligned with
|
|
|
|
* respect to each other. This does not affect the overall alignment
|
|
|
|
* of the label within its allocated or specified width.
|
2008-12-11 11:33:10 +00:00
|
|
|
*
|
2009-02-02 23:55:30 +00:00
|
|
|
* To align a #ClutterText actor you should add it to a container
|
|
|
|
* that supports alignment, or use the anchor point.
|
2008-12-11 11:33:10 +00:00
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 11:33:10 +00:00
|
|
|
*/
|
|
|
|
void
|
2009-02-02 23:55:30 +00:00
|
|
|
clutter_text_set_line_alignment (ClutterText *self,
|
|
|
|
PangoAlignment alignment)
|
2008-12-11 11:33:10 +00:00
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
|
|
|
if (priv->alignment != alignment)
|
|
|
|
{
|
|
|
|
priv->alignment = alignment;
|
|
|
|
|
|
|
|
clutter_text_dirty_cache (self);
|
|
|
|
|
|
|
|
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
|
|
|
|
|
2011-03-03 11:35:46 +00:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_LINE_ALIGNMENT]);
|
2008-12-11 11:33:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-02-02 23:55:30 +00:00
|
|
|
* clutter_text_get_line_alignment:
|
2008-12-11 11:33:10 +00:00
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
2009-02-02 23:55:30 +00:00
|
|
|
* Retrieves the alignment of a #ClutterText, as set by
|
|
|
|
* clutter_text_set_line_alignment().
|
2008-12-11 11:33:10 +00:00
|
|
|
*
|
|
|
|
* Return value: a #PangoAlignment
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 11:33:10 +00:00
|
|
|
*/
|
|
|
|
PangoAlignment
|
2009-02-02 23:55:30 +00:00
|
|
|
clutter_text_get_line_alignment (ClutterText *self)
|
2008-12-11 11:33:10 +00:00
|
|
|
{
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), PANGO_ALIGN_LEFT);
|
|
|
|
|
|
|
|
return self->priv->alignment;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_text_set_use_markup:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @setting: %TRUE if the text should be parsed for markup.
|
|
|
|
*
|
|
|
|
* Sets whether the contents of the #ClutterText actor contains markup
|
|
|
|
* in <link linkend="PangoMarkupFormat">Pango's text markup language</link>.
|
|
|
|
*
|
2009-01-29 13:18:57 +00:00
|
|
|
* Setting #ClutterText:use-markup on an editable #ClutterText will
|
2010-08-06 16:04:37 +00:00
|
|
|
* not have any effect except hiding the markup.
|
|
|
|
*
|
|
|
|
* See also #ClutterText:use-markup.
|
2009-01-07 13:48:45 +00:00
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 11:33:10 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
clutter_text_set_use_markup (ClutterText *self,
|
|
|
|
gboolean setting)
|
|
|
|
{
|
2011-06-15 09:06:31 +00:00
|
|
|
const gchar *text;
|
2010-08-06 16:04:37 +00:00
|
|
|
|
2008-12-11 11:33:10 +00:00
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
text = clutter_text_buffer_get_text (get_buffer (self));
|
2010-08-06 16:04:37 +00:00
|
|
|
|
2009-01-29 13:18:57 +00:00
|
|
|
clutter_text_set_use_markup_internal (self, setting);
|
2010-08-06 16:04:37 +00:00
|
|
|
|
|
|
|
if (setting)
|
2011-06-15 09:06:31 +00:00
|
|
|
clutter_text_set_markup_internal (self, text);
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2009-01-29 13:18:57 +00:00
|
|
|
clutter_text_dirty_cache (self);
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2009-01-29 13:18:57 +00:00
|
|
|
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
|
2008-12-11 11:33:10 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_text_get_use_markup:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
|
|
|
* Retrieves whether the contents of the #ClutterText actor should be
|
|
|
|
* parsed for the Pango text markup.
|
|
|
|
*
|
|
|
|
* Return value: %TRUE if the contents will be parsed for markup
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 11:33:10 +00:00
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
clutter_text_get_use_markup (ClutterText *self)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
|
|
|
|
|
|
|
|
return self->priv->use_markup;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_text_set_justify:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @justify: whether the text should be justified
|
|
|
|
*
|
|
|
|
* Sets whether the text of the #ClutterText actor should be justified
|
|
|
|
* on both margins. This setting is ignored if Clutter is compiled
|
|
|
|
* against Pango < 1.18.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 11:33:10 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
clutter_text_set_justify (ClutterText *self,
|
|
|
|
gboolean justify)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
|
|
|
if (priv->justify != justify)
|
|
|
|
{
|
|
|
|
priv->justify = justify;
|
|
|
|
|
|
|
|
clutter_text_dirty_cache (self);
|
|
|
|
|
|
|
|
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
|
|
|
|
|
2011-03-03 11:35:46 +00:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_JUSTIFY]);
|
2008-12-11 11:33:10 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_text_get_justify:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
|
|
|
* Retrieves whether the #ClutterText actor should justify its contents
|
|
|
|
* on both margins.
|
|
|
|
*
|
|
|
|
* Return value: %TRUE if the text should be justified
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 11:33:10 +00:00
|
|
|
*/
|
|
|
|
gboolean
|
|
|
|
clutter_text_get_justify (ClutterText *self)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), FALSE);
|
|
|
|
|
|
|
|
return self->priv->justify;
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_text_get_cursor_position:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
|
|
|
* Retrieves the cursor position.
|
|
|
|
*
|
|
|
|
* Return value: the cursor position, in characters
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 11:33:10 +00:00
|
|
|
*/
|
|
|
|
gint
|
|
|
|
clutter_text_get_cursor_position (ClutterText *self)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), -1);
|
|
|
|
|
|
|
|
return self->priv->position;
|
|
|
|
}
|
|
|
|
|
2008-12-11 12:17:11 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_set_cursor_position:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @position: the new cursor position, in characters
|
|
|
|
*
|
|
|
|
* Sets the cursor of a #ClutterText actor at @position.
|
|
|
|
*
|
|
|
|
* The position is expressed in characters, not in bytes.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 12:17:11 +00:00
|
|
|
*/
|
2008-12-11 11:33:10 +00:00
|
|
|
void
|
|
|
|
clutter_text_set_cursor_position (ClutterText *self,
|
|
|
|
gint position)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
gint len;
|
|
|
|
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
2009-10-16 13:22:15 +00:00
|
|
|
if (priv->position == position)
|
|
|
|
return;
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
len = clutter_text_buffer_get_length (get_buffer (self));
|
2008-12-11 11:33:10 +00:00
|
|
|
|
|
|
|
if (position < 0 || position >= len)
|
|
|
|
priv->position = -1;
|
|
|
|
else
|
|
|
|
priv->position = position;
|
|
|
|
|
2009-01-14 11:12:02 +00:00
|
|
|
/* Forget the target x position so that it will be recalculated next
|
|
|
|
time the cursor is moved up or down */
|
|
|
|
priv->x_pos = -1;
|
|
|
|
|
2011-03-07 18:53:07 +00:00
|
|
|
clutter_text_queue_redraw (CLUTTER_ACTOR (self));
|
2009-10-16 13:22:15 +00:00
|
|
|
|
2012-07-05 15:23:52 +00:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CURSOR_POSITION]);
|
2008-12-11 11:33:10 +00:00
|
|
|
}
|
|
|
|
|
2008-12-16 10:37:45 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_set_cursor_size:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @size: the size of the cursor, in pixels, or -1 to use the
|
|
|
|
* default value
|
|
|
|
*
|
|
|
|
* Sets the size of the cursor of a #ClutterText. The cursor
|
|
|
|
* will only be visible if the #ClutterText:cursor-visible property
|
|
|
|
* is set to %TRUE.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-16 10:37:45 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
clutter_text_set_cursor_size (ClutterText *self,
|
|
|
|
gint size)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
|
|
|
if (priv->cursor_size != size)
|
|
|
|
{
|
|
|
|
if (size < 0)
|
|
|
|
size = DEFAULT_CURSOR_SIZE;
|
|
|
|
|
|
|
|
priv->cursor_size = size;
|
|
|
|
|
2011-03-07 18:53:07 +00:00
|
|
|
clutter_text_queue_redraw (CLUTTER_ACTOR (self));
|
2008-12-16 10:37:45 +00:00
|
|
|
|
2011-03-03 11:35:46 +00:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_CURSOR_SIZE]);
|
2008-12-16 10:37:45 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_text_get_cursor_size:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
|
|
|
* Retrieves the size of the cursor of a #ClutterText actor.
|
|
|
|
*
|
|
|
|
* Return value: the size of the cursor, in pixels
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-16 10:37:45 +00:00
|
|
|
*/
|
|
|
|
guint
|
|
|
|
clutter_text_get_cursor_size (ClutterText *self)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), DEFAULT_CURSOR_SIZE);
|
|
|
|
|
|
|
|
return self->priv->cursor_size;
|
|
|
|
}
|
|
|
|
|
2008-12-11 11:40:55 +00:00
|
|
|
/**
|
2009-01-06 15:22:31 +00:00
|
|
|
* clutter_text_set_password_char:
|
2008-12-11 11:40:55 +00:00
|
|
|
* @self: a #ClutterText
|
2009-01-07 00:43:24 +00:00
|
|
|
* @wc: a Unicode character, or 0 to unset the password character
|
2008-12-11 11:40:55 +00:00
|
|
|
*
|
2009-01-06 15:22:31 +00:00
|
|
|
* Sets the character to use in place of the actual text in a
|
|
|
|
* password text actor.
|
2008-12-11 11:40:55 +00:00
|
|
|
*
|
2009-01-06 15:22:31 +00:00
|
|
|
* If @wc is 0 the text will be displayed as it is entered in the
|
|
|
|
* #ClutterText actor.
|
2008-12-11 11:40:55 +00:00
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 11:40:55 +00:00
|
|
|
*/
|
|
|
|
void
|
2009-01-06 15:22:31 +00:00
|
|
|
clutter_text_set_password_char (ClutterText *self,
|
|
|
|
gunichar wc)
|
2008-12-11 11:40:55 +00:00
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
2009-01-06 15:22:31 +00:00
|
|
|
if (priv->password_char != wc)
|
2008-12-11 11:40:55 +00:00
|
|
|
{
|
2009-01-06 15:22:31 +00:00
|
|
|
priv->password_char = wc;
|
2008-12-11 11:40:55 +00:00
|
|
|
|
|
|
|
clutter_text_dirty_cache (self);
|
|
|
|
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
|
|
|
|
|
2011-03-03 11:35:46 +00:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_PASSWORD_CHAR]);
|
2008-12-11 11:40:55 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
2009-01-06 15:22:31 +00:00
|
|
|
* clutter_text_get_password_char:
|
2008-12-11 11:40:55 +00:00
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
2009-01-06 15:22:31 +00:00
|
|
|
* Retrieves the character to use in place of the actual text
|
|
|
|
* as set by clutter_text_set_password_char().
|
2008-12-11 11:40:55 +00:00
|
|
|
*
|
2009-01-06 15:22:31 +00:00
|
|
|
* Return value: a Unicode character or 0 if the password
|
|
|
|
* character is not set
|
2008-12-11 11:40:55 +00:00
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 11:40:55 +00:00
|
|
|
*/
|
|
|
|
gunichar
|
2009-01-06 15:22:31 +00:00
|
|
|
clutter_text_get_password_char (ClutterText *self)
|
2008-12-11 11:40:55 +00:00
|
|
|
{
|
2009-01-06 15:22:31 +00:00
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), 0);
|
2008-12-11 11:40:55 +00:00
|
|
|
|
2009-01-06 15:22:31 +00:00
|
|
|
return self->priv->password_char;
|
2008-12-11 11:40:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* 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.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 11:40:55 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
clutter_text_set_max_length (ClutterText *self,
|
2008-12-11 11:54:07 +00:00
|
|
|
gint max)
|
2008-12-11 11:40:55 +00:00
|
|
|
{
|
2008-12-11 11:54:07 +00:00
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
2011-06-15 09:06:31 +00:00
|
|
|
clutter_text_buffer_set_max_length (get_buffer (self), max);
|
2008-12-11 11:40:55 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_text_get_max_length:
|
2008-12-11 11:54:07 +00:00
|
|
|
* @self: a #ClutterText
|
|
|
|
*
|
|
|
|
* Gets the maximum length of text that can be set into a text actor.
|
2008-12-11 11:40:55 +00:00
|
|
|
*
|
|
|
|
* See clutter_text_set_max_length().
|
|
|
|
*
|
|
|
|
* Return value: the maximum number of characters.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 11:40:55 +00:00
|
|
|
*/
|
|
|
|
gint
|
|
|
|
clutter_text_get_max_length (ClutterText *self)
|
|
|
|
{
|
2008-12-11 11:54:07 +00:00
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), 0);
|
2008-12-11 11:40:55 +00:00
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
return clutter_text_buffer_get_max_length (get_buffer (self));
|
2008-12-11 11:40:55 +00:00
|
|
|
}
|
|
|
|
|
2008-12-11 12:17:11 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_insert_unichar:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @wc: a Unicode character
|
|
|
|
*
|
|
|
|
* Inserts @wc at the current cursor position of a
|
|
|
|
* #ClutterText actor.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 12:17:11 +00:00
|
|
|
*/
|
2008-12-11 11:33:10 +00:00
|
|
|
void
|
|
|
|
clutter_text_insert_unichar (ClutterText *self,
|
|
|
|
gunichar wc)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
2011-06-15 09:06:31 +00:00
|
|
|
GString *new;
|
2008-12-11 11:33:10 +00:00
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
new = g_string_new ("");
|
|
|
|
g_string_append_unichar (new, wc);
|
2008-12-11 11:49:45 +00:00
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
clutter_text_buffer_insert_text (get_buffer (self), priv->position, new->str, 1);
|
2008-12-11 11:33:10 +00:00
|
|
|
|
|
|
|
g_string_free (new, TRUE);
|
|
|
|
}
|
|
|
|
|
2008-12-11 12:17:11 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_insert_text:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @text: the text to be inserted
|
|
|
|
* @position: the position of the insertion, or -1
|
|
|
|
*
|
|
|
|
* Inserts @text into a #ClutterActor at the given position.
|
|
|
|
*
|
|
|
|
* If @position is a negative number, the text will be appended
|
|
|
|
* at the end of the current contents of the #ClutterText.
|
|
|
|
*
|
|
|
|
* The position is expressed in characters, not in bytes.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 12:17:11 +00:00
|
|
|
*/
|
2008-12-11 11:33:10 +00:00
|
|
|
void
|
2008-12-11 11:43:56 +00:00
|
|
|
clutter_text_insert_text (ClutterText *self,
|
|
|
|
const gchar *text,
|
|
|
|
gssize position)
|
|
|
|
{
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
g_return_if_fail (text != NULL);
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
clutter_text_buffer_insert_text (get_buffer (self), position, text,
|
|
|
|
g_utf8_strlen (text, -1));
|
2008-12-11 11:43:56 +00:00
|
|
|
}
|
|
|
|
|
2008-12-11 12:17:11 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_delete_text:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @start_pos: starting position
|
|
|
|
* @end_pos: ending position
|
|
|
|
*
|
|
|
|
* Deletes the text inside a #ClutterText actor between @start_pos
|
|
|
|
* and @end_pos.
|
|
|
|
*
|
|
|
|
* The starting and ending positions are expressed in characters,
|
|
|
|
* not in bytes.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 12:17:11 +00:00
|
|
|
*/
|
2008-12-11 11:43:56 +00:00
|
|
|
void
|
|
|
|
clutter_text_delete_text (ClutterText *self,
|
2008-12-11 11:33:10 +00:00
|
|
|
gssize start_pos,
|
|
|
|
gssize end_pos)
|
|
|
|
{
|
2008-12-11 11:43:56 +00:00
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
2008-12-11 11:33:10 +00:00
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
clutter_text_buffer_delete_text (get_buffer (self), start_pos, end_pos - start_pos);
|
2008-12-11 11:43:56 +00:00
|
|
|
}
|
|
|
|
|
2008-12-11 12:17:11 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_delete_chars:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @n_chars: the number of characters to delete
|
|
|
|
*
|
|
|
|
* Deletes @n_chars inside a #ClutterText actor, starting from the
|
|
|
|
* current cursor position.
|
|
|
|
*
|
2011-06-15 09:06:31 +00:00
|
|
|
* Somewhat awkwardly, the cursor position is decremented by the same
|
|
|
|
* number of characters you've deleted.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 12:17:11 +00:00
|
|
|
*/
|
2008-12-11 11:43:56 +00:00
|
|
|
void
|
|
|
|
clutter_text_delete_chars (ClutterText *self,
|
|
|
|
guint n_chars)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
clutter_text_buffer_delete_text (get_buffer (self), priv->position, n_chars);
|
2008-12-11 11:43:56 +00:00
|
|
|
|
|
|
|
if (priv->position > 0)
|
|
|
|
clutter_text_set_cursor_position (self, priv->position - n_chars);
|
2008-12-11 11:33:10 +00:00
|
|
|
}
|
|
|
|
|
2008-12-11 11:59:50 +00:00
|
|
|
/**
|
|
|
|
* clutter_text_get_chars:
|
2008-12-11 12:17:11 +00:00
|
|
|
* @self: a #ClutterText
|
2008-12-11 11:59:50 +00:00
|
|
|
* @start_pos: start of text, in characters
|
|
|
|
* @end_pos: end of text, in characters
|
|
|
|
*
|
|
|
|
* Retrieves the contents of the #ClutterText actor between
|
2010-04-14 16:07:21 +00:00
|
|
|
* @start_pos and @end_pos, but not including @end_pos.
|
2008-12-11 11:59:50 +00:00
|
|
|
*
|
|
|
|
* The positions are specified in characters, not in bytes.
|
|
|
|
*
|
|
|
|
* Return value: a newly allocated string with the contents of
|
|
|
|
* the text actor between the specified positions. Use g_free()
|
|
|
|
* to free the resources when done
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2008-12-11 11:59:50 +00:00
|
|
|
*/
|
2008-12-11 11:43:56 +00:00
|
|
|
gchar *
|
|
|
|
clutter_text_get_chars (ClutterText *self,
|
|
|
|
gssize start_pos,
|
|
|
|
gssize end_pos)
|
|
|
|
{
|
2008-12-11 11:59:50 +00:00
|
|
|
gint start_index, end_index;
|
2011-06-15 09:06:31 +00:00
|
|
|
guint n_chars;
|
|
|
|
const gchar *text;
|
2008-12-11 11:59:50 +00:00
|
|
|
|
2008-12-11 11:43:56 +00:00
|
|
|
g_return_val_if_fail (CLUTTER_IS_TEXT (self), NULL);
|
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
n_chars = clutter_text_buffer_get_length (get_buffer (self));
|
|
|
|
text = clutter_text_buffer_get_text (get_buffer (self));
|
2008-12-11 11:59:50 +00:00
|
|
|
|
|
|
|
if (end_pos < 0)
|
2011-06-15 09:06:31 +00:00
|
|
|
end_pos = n_chars;
|
2008-12-11 11:59:50 +00:00
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
start_pos = MIN (n_chars, start_pos);
|
|
|
|
end_pos = MIN (n_chars, end_pos);
|
2008-12-11 11:59:50 +00:00
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
start_index = g_utf8_offset_to_pointer (text, start_pos) - text;
|
|
|
|
end_index = g_utf8_offset_to_pointer (text, end_pos) - text;
|
2008-12-11 11:59:50 +00:00
|
|
|
|
2011-06-15 09:06:31 +00:00
|
|
|
return g_strndup (text + start_index, end_index - start_index);
|
2008-12-11 11:43:56 +00:00
|
|
|
}
|
2009-01-07 00:25:24 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* 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
|
2010-06-14 13:05:49 +00:00
|
|
|
* or not. Only editable #ClutterText<!-- -->s can be in single line
|
|
|
|
* mode.
|
2009-01-07 00:25:24 +00:00
|
|
|
*
|
|
|
|
* A text actor in single line mode will not wrap text and will clip
|
2010-11-25 18:13:51 +00:00
|
|
|
* the visible area to the predefined size. The contents of the
|
2009-01-07 00:25:24 +00:00
|
|
|
* 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.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2009-01-07 00:25:24 +00:00
|
|
|
*/
|
|
|
|
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;
|
|
|
|
|
2011-03-03 11:35:46 +00:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_ACTIVATABLE]);
|
2009-01-07 00:25:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
clutter_text_dirty_cache (self);
|
|
|
|
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
|
|
|
|
|
2011-03-03 11:35:46 +00:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_SINGLE_LINE_MODE]);
|
2009-01-07 00:25:24 +00:00
|
|
|
|
|
|
|
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
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2009-01-07 00:25:24 +00:00
|
|
|
*/
|
|
|
|
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;
|
|
|
|
}
|
2009-09-09 11:15:23 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_text_set_preedit_string:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @preedit_str: (allow-none): the pre-edit string, or %NULL to unset it
|
|
|
|
* @preedit_attrs: (allow-none): the pre-edit string attributes
|
|
|
|
* @cursor_pos: the cursor position for the pre-edit string
|
|
|
|
*
|
|
|
|
* Sets, or unsets, the pre-edit string. This function is useful
|
|
|
|
* for input methods to display a string (with eventual specific
|
|
|
|
* Pango attributes) before it is entered inside the #ClutterText
|
|
|
|
* buffer.
|
|
|
|
*
|
|
|
|
* The preedit string and attributes are ignored if the #ClutterText
|
|
|
|
* actor is not editable.
|
|
|
|
*
|
|
|
|
* This function should not be used by applications
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2009-09-09 11:15:23 +00:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
clutter_text_set_preedit_string (ClutterText *self,
|
|
|
|
const gchar *preedit_str,
|
|
|
|
PangoAttrList *preedit_attrs,
|
|
|
|
guint cursor_pos)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
|
|
|
g_free (priv->preedit_str);
|
2009-09-19 08:19:06 +00:00
|
|
|
priv->preedit_str = NULL;
|
2009-09-09 11:15:23 +00:00
|
|
|
|
|
|
|
if (priv->preedit_attrs != NULL)
|
|
|
|
{
|
|
|
|
pango_attr_list_unref (priv->preedit_attrs);
|
|
|
|
priv->preedit_attrs = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
priv->preedit_n_chars = 0;
|
|
|
|
priv->preedit_cursor_pos = 0;
|
|
|
|
|
|
|
|
if (preedit_str == NULL || *preedit_str == '\0')
|
|
|
|
priv->preedit_set = FALSE;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
priv->preedit_str = g_strdup (preedit_str);
|
|
|
|
|
|
|
|
if (priv->preedit_str != NULL)
|
|
|
|
priv->preedit_n_chars = g_utf8_strlen (priv->preedit_str, -1);
|
|
|
|
else
|
|
|
|
priv->preedit_n_chars = 0;
|
|
|
|
|
|
|
|
if (preedit_attrs != NULL)
|
|
|
|
priv->preedit_attrs = pango_attr_list_ref (preedit_attrs);
|
|
|
|
|
|
|
|
priv->preedit_cursor_pos =
|
|
|
|
CLAMP (cursor_pos, 0, priv->preedit_n_chars);
|
|
|
|
|
|
|
|
priv->preedit_set = TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
clutter_text_dirty_cache (self);
|
|
|
|
clutter_actor_queue_relayout (CLUTTER_ACTOR (self));
|
|
|
|
}
|
2011-02-04 11:33:53 +00:00
|
|
|
|
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_text_get_layout_offsets:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @x: (out): location to store X offset of layout, or %NULL
|
|
|
|
* @y: (out): location to store Y offset of layout, or %NULL
|
|
|
|
*
|
|
|
|
* Obtains the coordinates where the #ClutterText will draw the #PangoLayout
|
|
|
|
* representing the text.
|
|
|
|
*
|
2012-08-27 08:48:36 +00:00
|
|
|
*
|
2012-02-06 17:34:26 +00:00
|
|
|
*/
|
2011-02-04 11:33:53 +00:00
|
|
|
void
|
|
|
|
clutter_text_get_layout_offsets (ClutterText *self,
|
|
|
|
gint *x,
|
|
|
|
gint *y)
|
|
|
|
{
|
|
|
|
ClutterTextPrivate *priv;
|
|
|
|
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
|
|
|
|
priv = self->priv;
|
|
|
|
|
|
|
|
if (x != NULL)
|
|
|
|
*x = priv->text_x;
|
|
|
|
|
|
|
|
if (y != NULL)
|
|
|
|
*y = priv->text_y;
|
|
|
|
}
|
2013-03-26 22:03:19 +00:00
|
|
|
|
|
|
|
/**
|
|
|
|
* clutter_text_get_cursor_rect:
|
|
|
|
* @self: a #ClutterText
|
|
|
|
* @rect: (out caller-allocates): return location of a #ClutterRect
|
|
|
|
*
|
|
|
|
* Retrieves the rectangle that contains the cursor.
|
|
|
|
*
|
|
|
|
* The coordinates of the rectangle's origin are in actor-relative
|
|
|
|
* coordinates.
|
|
|
|
*/
|
|
|
|
void
|
|
|
|
clutter_text_get_cursor_rect (ClutterText *self,
|
|
|
|
ClutterRect *rect)
|
|
|
|
{
|
|
|
|
g_return_if_fail (CLUTTER_IS_TEXT (self));
|
|
|
|
g_return_if_fail (rect != NULL);
|
|
|
|
|
|
|
|
*rect = self->priv->cursor_rect;
|
|
|
|
}
|