clutter: Make ClutterText implement ClutterInputFocus

This only applies when the actor is editable. Implementing this interface
will allow it to interact with the input method.
This commit is contained in:
Carlos Garnacho 2017-12-06 12:49:34 +01:00
parent ca654ac544
commit d7cb3da324

View File

@ -63,6 +63,7 @@
#include "clutter-units.h" #include "clutter-units.h"
#include "clutter-paint-volume-private.h" #include "clutter-paint-volume-private.h"
#include "clutter-scriptable.h" #include "clutter-scriptable.h"
#include "clutter-input-focus.h"
/* cursor width in pixels */ /* cursor width in pixels */
#define DEFAULT_CURSOR_SIZE 2 #define DEFAULT_CURSOR_SIZE 2
@ -269,6 +270,7 @@ static const ClutterColor default_selected_text_color = { 0, 0, 0, 255 };
static ClutterAnimatableIface *parent_animatable_iface = NULL; static ClutterAnimatableIface *parent_animatable_iface = NULL;
static ClutterScriptableIface *parent_scriptable_iface = NULL; static ClutterScriptableIface *parent_scriptable_iface = NULL;
static void clutter_input_focus_iface_init (ClutterInputFocusInterface *iface);
static void clutter_scriptable_iface_init (ClutterScriptableIface *iface); static void clutter_scriptable_iface_init (ClutterScriptableIface *iface);
static void clutter_animatable_iface_init (ClutterAnimatableIface *iface); static void clutter_animatable_iface_init (ClutterAnimatableIface *iface);
@ -276,11 +278,91 @@ G_DEFINE_TYPE_WITH_CODE (ClutterText,
clutter_text, clutter_text,
CLUTTER_TYPE_ACTOR, CLUTTER_TYPE_ACTOR,
G_ADD_PRIVATE (ClutterText) G_ADD_PRIVATE (ClutterText)
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_INPUT_FOCUS,
clutter_input_focus_iface_init)
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE, G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_SCRIPTABLE,
clutter_scriptable_iface_init) clutter_scriptable_iface_init)
G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE, G_IMPLEMENT_INTERFACE (CLUTTER_TYPE_ANIMATABLE,
clutter_animatable_iface_init)); clutter_animatable_iface_init));
static void
clutter_text_input_focus_request_surrounding (ClutterInputFocus *focus)
{
ClutterText *clutter_text = CLUTTER_TEXT (focus);
ClutterTextBuffer *buffer;
const gchar *text;
gint anchor_pos, cursor_pos;
buffer = clutter_text_get_buffer (clutter_text);
text = clutter_text_buffer_get_text (buffer);
cursor_pos = clutter_text_get_cursor_position (clutter_text);
if (cursor_pos < 0)
cursor_pos = clutter_text_buffer_get_length (buffer);
anchor_pos = clutter_text_get_selection_bound (clutter_text);
if (anchor_pos < 0)
anchor_pos = cursor_pos;
clutter_input_focus_set_surrounding (focus, text,
g_utf8_offset_to_pointer (text, cursor_pos) - text,
g_utf8_offset_to_pointer (text, anchor_pos) - text);
}
static void
clutter_text_input_focus_delete_surrounding (ClutterInputFocus *focus,
guint offset,
guint len)
{
ClutterText *clutter_text = CLUTTER_TEXT (focus);
if (clutter_text_get_editable (clutter_text))
clutter_text_delete_text (clutter_text, offset, len);
}
static void
clutter_text_input_focus_commit_text (ClutterInputFocus *focus,
const gchar *text)
{
ClutterText *clutter_text = CLUTTER_TEXT (focus);
if (clutter_text_get_editable (clutter_text))
{
clutter_text_delete_selection (clutter_text);
clutter_text_insert_text (clutter_text, text,
clutter_text_get_cursor_position (clutter_text));
}
}
static void
clutter_text_input_focus_set_preedit_text (ClutterInputFocus *focus,
const gchar *preedit_text,
guint cursor_pos)
{
ClutterText *clutter_text = CLUTTER_TEXT (focus);
if (clutter_text_get_editable (clutter_text))
{
PangoAttrList *list;
list = pango_attr_list_new ();
pango_attr_list_insert (list, pango_attr_underline_new (PANGO_UNDERLINE_SINGLE));
clutter_text_set_preedit_string (clutter_text,
preedit_text, list,
cursor_pos);
pango_attr_list_unref (list);
}
}
static void
clutter_input_focus_iface_init (ClutterInputFocusInterface *iface)
{
iface->request_surrounding = clutter_text_input_focus_request_surrounding;
iface->delete_surrounding = clutter_text_input_focus_delete_surrounding;
iface->commit_text = clutter_text_input_focus_commit_text;
iface->set_preedit_text = clutter_text_input_focus_set_preedit_text;
}
static inline void static inline void
clutter_text_dirty_paint_volume (ClutterText *text) clutter_text_dirty_paint_volume (ClutterText *text)
{ {
@ -1009,6 +1091,22 @@ clutter_text_position_to_coords (ClutterText *self,
return TRUE; return TRUE;
} }
static inline void
update_cursor_location (ClutterText *self)
{
ClutterTextPrivate *priv = self->priv;
ClutterRect rect;
float x, y;
if (!priv->editable)
return;
rect = priv->cursor_rect;
clutter_actor_get_transformed_position (CLUTTER_ACTOR (self), &x, &y);
clutter_rect_offset (&rect, x, y);
clutter_input_focus_set_cursor_location (CLUTTER_INPUT_FOCUS (self), &rect);
}
static inline void static inline void
clutter_text_ensure_cursor_position (ClutterText *self) clutter_text_ensure_cursor_position (ClutterText *self)
{ {
@ -1057,6 +1155,8 @@ clutter_text_ensure_cursor_position (ClutterText *self)
g_signal_emit (self, text_signals[CURSOR_EVENT], 0, &cursor_pos); g_signal_emit (self, text_signals[CURSOR_EVENT], 0, &cursor_pos);
g_signal_emit (self, text_signals[CURSOR_CHANGED], 0); g_signal_emit (self, text_signals[CURSOR_CHANGED], 0);
update_cursor_location (self);
} }
} }
@ -2085,9 +2185,11 @@ clutter_text_key_press (ClutterActor *actor,
g_assert (pool != NULL); g_assert (pool != NULL);
/* we allow passing synthetic events that only contain /* we allow passing synthetic events that only contain
* the Unicode value and not the key symbol * the Unicode value and not the key symbol, unless they
* contain the input method flag.
*/ */
if (event->keyval == 0 && (event->flags & CLUTTER_EVENT_FLAG_SYNTHETIC)) if (event->keyval == 0 && (event->flags & CLUTTER_EVENT_FLAG_SYNTHETIC) &&
!(event->flags & CLUTTER_EVENT_FLAG_INPUT_METHOD))
res = FALSE; res = FALSE;
else else
res = clutter_binding_pool_activate (pool, event->keyval, res = clutter_binding_pool_activate (pool, event->keyval,
@ -2105,6 +2207,9 @@ clutter_text_key_press (ClutterActor *actor,
{ {
gunichar key_unichar; gunichar key_unichar;
if (clutter_input_focus_filter_key_event (CLUTTER_INPUT_FOCUS (actor), event))
return CLUTTER_EVENT_STOP;
/* Skip keys when control is pressed */ /* Skip keys when control is pressed */
key_unichar = clutter_event_get_key_unicode ((ClutterEvent *) event); key_unichar = clutter_event_get_key_unicode ((ClutterEvent *) event);
@ -2141,6 +2246,16 @@ clutter_text_key_press (ClutterActor *actor,
return CLUTTER_EVENT_PROPAGATE; return CLUTTER_EVENT_PROPAGATE;
} }
static gboolean
clutter_text_key_release (ClutterActor *actor,
ClutterKeyEvent *event)
{
if (clutter_input_focus_filter_key_event (CLUTTER_INPUT_FOCUS (actor), event))
return CLUTTER_EVENT_STOP;
return CLUTTER_EVENT_PROPAGATE;
}
static void static void
clutter_text_compute_layout_offsets (ClutterText *self, clutter_text_compute_layout_offsets (ClutterText *self,
PangoLayout *layout, PangoLayout *layout,
@ -2664,6 +2779,9 @@ clutter_text_key_focus_in (ClutterActor *actor)
{ {
ClutterTextPrivate *priv = CLUTTER_TEXT (actor)->priv; ClutterTextPrivate *priv = CLUTTER_TEXT (actor)->priv;
if (priv->editable)
clutter_input_focus_focus_in (CLUTTER_INPUT_FOCUS (actor));
priv->has_focus = TRUE; priv->has_focus = TRUE;
clutter_text_queue_redraw (actor); clutter_text_queue_redraw (actor);
@ -2676,6 +2794,9 @@ clutter_text_key_focus_out (ClutterActor *actor)
priv->has_focus = FALSE; priv->has_focus = FALSE;
if (priv->editable)
clutter_input_focus_focus_out (CLUTTER_INPUT_FOCUS (actor));
clutter_text_queue_redraw (actor); clutter_text_queue_redraw (actor);
} }
@ -3369,6 +3490,7 @@ clutter_text_class_init (ClutterTextClass *klass)
actor_class->get_preferred_height = clutter_text_get_preferred_height; actor_class->get_preferred_height = clutter_text_get_preferred_height;
actor_class->allocate = clutter_text_allocate; actor_class->allocate = clutter_text_allocate;
actor_class->key_press_event = clutter_text_key_press; actor_class->key_press_event = clutter_text_key_press;
actor_class->key_release_event = clutter_text_key_release;
actor_class->button_press_event = clutter_text_button_press; actor_class->button_press_event = clutter_text_button_press;
actor_class->button_release_event = clutter_text_button_release; actor_class->button_release_event = clutter_text_button_release;
actor_class->motion_event = clutter_text_motion; actor_class->motion_event = clutter_text_motion;
@ -4469,6 +4591,11 @@ clutter_text_set_editable (ClutterText *self,
{ {
priv->editable = editable; priv->editable = editable;
if (!priv->editable)
clutter_input_focus_focus_out (CLUTTER_INPUT_FOCUS (self));
else if (priv->has_focus)
clutter_input_focus_focus_in (CLUTTER_INPUT_FOCUS (self));
clutter_text_queue_redraw (CLUTTER_ACTOR (self)); clutter_text_queue_redraw (CLUTTER_ACTOR (self));
g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EDITABLE]); g_object_notify_by_pspec (G_OBJECT (self), obj_props[PROP_EDITABLE]);