st-entry: Add support for a "hint actor"
This allows a full ClutterActor to be used as hint in the entry, instead of a simple string. The string case has been now re-implemented on top of the hint actor. https://bugzilla.gnome.org/show_bug.cgi?id=783484
This commit is contained in:
parent
4e07d0b073
commit
6ed7034a6b
@ -34,7 +34,7 @@
|
||||
* <para>focus: the widget has focus</para>
|
||||
* </listitem>
|
||||
* <listitem>
|
||||
* <para>indeterminate: the widget is showing the hint text</para>
|
||||
* <para>indeterminate: the widget is showing the hint text or actor</para>
|
||||
* </listitem>
|
||||
* </itemizedlist>
|
||||
*/
|
||||
@ -56,6 +56,7 @@
|
||||
|
||||
#include "st-im-text.h"
|
||||
#include "st-icon.h"
|
||||
#include "st-label.h"
|
||||
#include "st-widget.h"
|
||||
#include "st-texture-cache.h"
|
||||
#include "st-clipboard.h"
|
||||
@ -75,6 +76,7 @@ enum
|
||||
PROP_PRIMARY_ICON,
|
||||
PROP_SECONDARY_ICON,
|
||||
PROP_HINT_TEXT,
|
||||
PROP_HINT_ACTOR,
|
||||
PROP_TEXT,
|
||||
PROP_INPUT_PURPOSE,
|
||||
PROP_INPUT_HINTS,
|
||||
@ -96,14 +98,14 @@ typedef struct _StEntryPrivate StEntryPrivate;
|
||||
struct _StEntryPrivate
|
||||
{
|
||||
ClutterActor *entry;
|
||||
gchar *hint;
|
||||
|
||||
ClutterActor *primary_icon;
|
||||
ClutterActor *secondary_icon;
|
||||
|
||||
ClutterActor *hint_actor;
|
||||
|
||||
gfloat spacing;
|
||||
|
||||
gboolean hint_visible;
|
||||
gboolean capslock_warning_shown;
|
||||
gboolean has_ibeam;
|
||||
|
||||
@ -140,6 +142,10 @@ st_entry_set_property (GObject *gobject,
|
||||
st_entry_set_hint_text (entry, g_value_get_string (value));
|
||||
break;
|
||||
|
||||
case PROP_HINT_ACTOR:
|
||||
st_entry_set_hint_actor (entry, g_value_get_object (value));
|
||||
break;
|
||||
|
||||
case PROP_TEXT:
|
||||
st_entry_set_text (entry, g_value_get_string (value));
|
||||
break;
|
||||
@ -181,7 +187,11 @@ st_entry_get_property (GObject *gobject,
|
||||
break;
|
||||
|
||||
case PROP_HINT_TEXT:
|
||||
g_value_set_string (value, priv->hint);
|
||||
g_value_set_string (value, st_entry_get_hint_text (ST_ENTRY (gobject)));
|
||||
break;
|
||||
|
||||
case PROP_HINT_ACTOR:
|
||||
g_value_set_object (value, priv->hint_actor);
|
||||
break;
|
||||
|
||||
case PROP_TEXT:
|
||||
@ -265,14 +275,21 @@ st_entry_dispose (GObject *object)
|
||||
}
|
||||
|
||||
static void
|
||||
st_entry_finalize (GObject *object)
|
||||
st_entry_update_hint_visibility (StEntry *self)
|
||||
{
|
||||
StEntryPrivate *priv = ST_ENTRY_PRIV (object);
|
||||
StEntryPrivate *priv = ST_ENTRY_PRIV (self);
|
||||
gboolean hint_visible =
|
||||
priv->hint_actor != NULL &&
|
||||
strcmp (clutter_text_get_text (CLUTTER_TEXT (priv->entry)), "") == 0 &&
|
||||
!HAS_FOCUS (priv->entry);
|
||||
|
||||
g_free (priv->hint);
|
||||
priv->hint = NULL;
|
||||
if (priv->hint_actor)
|
||||
g_object_set (priv->hint_actor, "visible", hint_visible, NULL);
|
||||
|
||||
G_OBJECT_CLASS (st_entry_parent_class)->finalize (object);
|
||||
if (hint_visible)
|
||||
st_widget_add_style_pseudo_class (ST_WIDGET (self), "indeterminate");
|
||||
else
|
||||
st_widget_remove_style_pseudo_class (ST_WIDGET (self), "indeterminate");
|
||||
}
|
||||
|
||||
static void
|
||||
@ -352,7 +369,7 @@ st_entry_get_preferred_width (ClutterActor *actor,
|
||||
{
|
||||
StEntryPrivate *priv = ST_ENTRY_PRIV (actor);
|
||||
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
|
||||
gfloat icon_w;
|
||||
gfloat hint_w, icon_w;
|
||||
|
||||
st_theme_node_adjust_for_height (theme_node, &for_height);
|
||||
|
||||
@ -360,6 +377,17 @@ st_entry_get_preferred_width (ClutterActor *actor,
|
||||
min_width_p,
|
||||
natural_width_p);
|
||||
|
||||
if (priv->hint_actor)
|
||||
{
|
||||
clutter_actor_get_preferred_width (priv->hint_actor, -1, NULL, &hint_w);
|
||||
|
||||
if (min_width_p && hint_w > *min_width_p)
|
||||
*min_width_p = hint_w;
|
||||
|
||||
if (natural_width_p && hint_w > *natural_width_p)
|
||||
*natural_width_p = hint_w;
|
||||
}
|
||||
|
||||
if (priv->primary_icon)
|
||||
{
|
||||
clutter_actor_get_preferred_width (priv->primary_icon, -1, NULL, &icon_w);
|
||||
@ -394,7 +422,7 @@ st_entry_get_preferred_height (ClutterActor *actor,
|
||||
{
|
||||
StEntryPrivate *priv = ST_ENTRY_PRIV (actor);
|
||||
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
|
||||
gfloat icon_h;
|
||||
gfloat hint_h, icon_h;
|
||||
|
||||
st_theme_node_adjust_for_width (theme_node, &for_width);
|
||||
|
||||
@ -402,6 +430,17 @@ st_entry_get_preferred_height (ClutterActor *actor,
|
||||
min_height_p,
|
||||
natural_height_p);
|
||||
|
||||
if (priv->hint_actor)
|
||||
{
|
||||
clutter_actor_get_preferred_height (priv->hint_actor, -1, NULL, &hint_h);
|
||||
|
||||
if (min_height_p && hint_h > *min_height_p)
|
||||
*min_height_p = hint_h;
|
||||
|
||||
if (natural_height_p && hint_h > *natural_height_p)
|
||||
*natural_height_p = hint_h;
|
||||
}
|
||||
|
||||
if (priv->primary_icon)
|
||||
{
|
||||
clutter_actor_get_preferred_height (priv->primary_icon,
|
||||
@ -436,12 +475,16 @@ st_entry_allocate (ClutterActor *actor,
|
||||
{
|
||||
StEntryPrivate *priv = ST_ENTRY_PRIV (actor);
|
||||
StThemeNode *theme_node = st_widget_get_theme_node (ST_WIDGET (actor));
|
||||
ClutterActorBox content_box, child_box, icon_box;
|
||||
ClutterActorBox content_box, child_box, icon_box, hint_box;
|
||||
gfloat icon_w, icon_h;
|
||||
gfloat hint_w, hint_h;
|
||||
gfloat entry_h, min_h, pref_h, avail_h;
|
||||
ClutterActor *left_icon, *right_icon;
|
||||
gboolean is_rtl;
|
||||
|
||||
if (clutter_actor_get_text_direction (actor) == CLUTTER_TEXT_DIRECTION_RTL)
|
||||
is_rtl = clutter_actor_get_text_direction (actor) == CLUTTER_TEXT_DIRECTION_RTL;
|
||||
|
||||
if (is_rtl)
|
||||
{
|
||||
right_icon = priv->primary_icon;
|
||||
left_icon = priv->secondary_icon;
|
||||
@ -495,6 +538,25 @@ st_entry_allocate (ClutterActor *actor,
|
||||
child_box.x2 = MAX (child_box.x1, child_box.x2 - icon_w - priv->spacing);
|
||||
}
|
||||
|
||||
if (priv->hint_actor)
|
||||
{
|
||||
/* now allocate the hint actor */
|
||||
hint_box = child_box;
|
||||
|
||||
clutter_actor_get_preferred_width (priv->hint_actor, -1, NULL, &hint_w);
|
||||
clutter_actor_get_preferred_height (priv->hint_actor, -1, NULL, &hint_h);
|
||||
|
||||
if (is_rtl)
|
||||
hint_box.x1 = hint_box.x2 - hint_w;
|
||||
else
|
||||
hint_box.x2 = hint_box.x1 + hint_w;
|
||||
|
||||
hint_box.y1 = ceil (content_box.y1 + avail_h / 2 - hint_h / 2);
|
||||
hint_box.y2 = hint_box.y1 + hint_h;
|
||||
|
||||
clutter_actor_allocate (priv->hint_actor, &hint_box, flags);
|
||||
}
|
||||
|
||||
clutter_actor_get_preferred_height (priv->entry, child_box.x2 - child_box.x1,
|
||||
&min_h, &pref_h);
|
||||
|
||||
@ -511,23 +573,15 @@ clutter_text_focus_in_cb (ClutterText *text,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
StEntry *entry = ST_ENTRY (actor);
|
||||
StEntryPrivate *priv = ST_ENTRY_PRIV (entry);
|
||||
GdkKeymap *keymap;
|
||||
|
||||
/* remove the hint if visible */
|
||||
if (priv->hint && priv->hint_visible)
|
||||
{
|
||||
priv->hint_visible = FALSE;
|
||||
|
||||
clutter_text_set_text (text, "");
|
||||
}
|
||||
st_entry_update_hint_visibility (entry);
|
||||
|
||||
keymap = gdk_keymap_get_for_display (gdk_display_get_default ());
|
||||
keymap_state_changed (keymap, entry);
|
||||
g_signal_connect (keymap, "state-changed",
|
||||
G_CALLBACK (keymap_state_changed), entry);
|
||||
|
||||
st_widget_remove_style_pseudo_class (ST_WIDGET (actor), "indeterminate");
|
||||
st_widget_add_style_pseudo_class (ST_WIDGET (actor), "focus");
|
||||
clutter_text_set_cursor_visible (text, TRUE);
|
||||
}
|
||||
@ -537,19 +591,12 @@ clutter_text_focus_out_cb (ClutterText *text,
|
||||
ClutterActor *actor)
|
||||
{
|
||||
StEntry *entry = ST_ENTRY (actor);
|
||||
StEntryPrivate *priv = ST_ENTRY_PRIV (entry);
|
||||
GdkKeymap *keymap;
|
||||
|
||||
st_widget_remove_style_pseudo_class (ST_WIDGET (actor), "focus");
|
||||
|
||||
/* add a hint if the entry is empty */
|
||||
if (priv->hint && !strcmp (clutter_text_get_text (text), ""))
|
||||
{
|
||||
priv->hint_visible = TRUE;
|
||||
st_entry_update_hint_visibility (entry);
|
||||
|
||||
clutter_text_set_text (text, priv->hint);
|
||||
st_widget_add_style_pseudo_class (ST_WIDGET (actor), "indeterminate");
|
||||
}
|
||||
clutter_text_set_cursor_visible (text, FALSE);
|
||||
remove_capslock_feedback (entry);
|
||||
|
||||
@ -870,7 +917,6 @@ st_entry_class_init (StEntryClass *klass)
|
||||
|
||||
gobject_class->set_property = st_entry_set_property;
|
||||
gobject_class->get_property = st_entry_get_property;
|
||||
gobject_class->finalize = st_entry_finalize;
|
||||
gobject_class->dispose = st_entry_dispose;
|
||||
|
||||
actor_class->get_preferred_width = st_entry_get_preferred_width;
|
||||
@ -917,6 +963,14 @@ st_entry_class_init (StEntryClass *klass)
|
||||
NULL, G_PARAM_READWRITE);
|
||||
g_object_class_install_property (gobject_class, PROP_HINT_TEXT, pspec);
|
||||
|
||||
pspec = g_param_spec_object ("hint-actor",
|
||||
"Hint Actor",
|
||||
"An actor to display when the entry is not focused "
|
||||
"and the text property is empty",
|
||||
CLUTTER_TYPE_ACTOR,
|
||||
G_PARAM_READWRITE);
|
||||
g_object_class_install_property (gobject_class, PROP_HINT_ACTOR, pspec);
|
||||
|
||||
pspec = g_param_spec_string ("text",
|
||||
"Text",
|
||||
"Text of the entry",
|
||||
@ -1052,7 +1106,7 @@ st_entry_get_text (StEntry *entry)
|
||||
g_return_val_if_fail (ST_IS_ENTRY (entry), NULL);
|
||||
|
||||
priv = st_entry_get_instance_private (entry);
|
||||
if (priv->hint_visible)
|
||||
if (clutter_actor_is_visible (priv->hint_actor))
|
||||
return "";
|
||||
else
|
||||
return clutter_text_get_text (CLUTTER_TEXT (priv->entry));
|
||||
@ -1075,24 +1129,10 @@ st_entry_set_text (StEntry *entry,
|
||||
|
||||
priv = st_entry_get_instance_private (entry);
|
||||
|
||||
/* set a hint if we are blanking the entry */
|
||||
if (priv->hint
|
||||
&& text && !strcmp ("", text)
|
||||
&& !HAS_FOCUS (priv->entry))
|
||||
{
|
||||
text = priv->hint;
|
||||
priv->hint_visible = TRUE;
|
||||
st_widget_add_style_pseudo_class (ST_WIDGET (entry), "indeterminate");
|
||||
}
|
||||
else
|
||||
{
|
||||
st_widget_remove_style_pseudo_class (ST_WIDGET (entry), "indeterminate");
|
||||
|
||||
priv->hint_visible = FALSE;
|
||||
}
|
||||
|
||||
clutter_text_set_text (CLUTTER_TEXT (priv->entry), text);
|
||||
|
||||
st_entry_update_hint_visibility (entry);
|
||||
|
||||
g_object_notify (G_OBJECT (entry), "text");
|
||||
}
|
||||
|
||||
@ -1126,24 +1166,12 @@ void
|
||||
st_entry_set_hint_text (StEntry *entry,
|
||||
const gchar *text)
|
||||
{
|
||||
StEntryPrivate *priv;
|
||||
StWidget *label;
|
||||
|
||||
g_return_if_fail (ST_IS_ENTRY (entry));
|
||||
|
||||
priv = st_entry_get_instance_private (entry);
|
||||
|
||||
g_free (priv->hint);
|
||||
|
||||
priv->hint = g_strdup (text);
|
||||
|
||||
if (!strcmp (clutter_text_get_text (CLUTTER_TEXT (priv->entry)), "")
|
||||
&& !HAS_FOCUS (priv->entry))
|
||||
{
|
||||
priv->hint_visible = TRUE;
|
||||
|
||||
clutter_text_set_text (CLUTTER_TEXT (priv->entry), priv->hint);
|
||||
st_widget_add_style_pseudo_class (ST_WIDGET (entry), "indeterminate");
|
||||
}
|
||||
label = st_label_new (text);
|
||||
st_entry_set_hint_actor (ST_ENTRY (entry), CLUTTER_ACTOR (label));
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1158,9 +1186,16 @@ st_entry_set_hint_text (StEntry *entry,
|
||||
const gchar *
|
||||
st_entry_get_hint_text (StEntry *entry)
|
||||
{
|
||||
StEntryPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (ST_IS_ENTRY (entry), NULL);
|
||||
|
||||
return ((StEntryPrivate *)ST_ENTRY_PRIV (entry))->hint;
|
||||
priv = ST_ENTRY_PRIV (entry);
|
||||
|
||||
if (priv->hint_actor != NULL && ST_IS_LABEL (priv->hint_actor))
|
||||
return st_label_get_text (ST_LABEL (priv->hint_actor));
|
||||
|
||||
return NULL;
|
||||
}
|
||||
|
||||
/**
|
||||
@ -1370,6 +1405,57 @@ st_entry_get_secondary_icon (StEntry *entry)
|
||||
return priv->secondary_icon;
|
||||
}
|
||||
|
||||
/**
|
||||
* st_entry_set_hint_actor:
|
||||
* @entry: a #StEntry
|
||||
* @hint_actor: (allow-none): a #ClutterActor
|
||||
*
|
||||
* Set the hint actor of the entry to @hint_actor
|
||||
*/
|
||||
void
|
||||
st_entry_set_hint_actor (StEntry *entry,
|
||||
ClutterActor *hint_actor)
|
||||
{
|
||||
StEntryPrivate *priv;
|
||||
|
||||
g_return_if_fail (ST_IS_ENTRY (entry));
|
||||
|
||||
priv = ST_ENTRY_PRIV (entry);
|
||||
|
||||
if (priv->hint_actor != NULL)
|
||||
{
|
||||
clutter_actor_remove_child (CLUTTER_ACTOR (entry), priv->hint_actor);
|
||||
priv->hint_actor = NULL;
|
||||
}
|
||||
|
||||
if (hint_actor != NULL)
|
||||
{
|
||||
priv->hint_actor = hint_actor;
|
||||
clutter_actor_add_child (CLUTTER_ACTOR (entry), priv->hint_actor);
|
||||
}
|
||||
|
||||
st_entry_update_hint_visibility (entry);
|
||||
|
||||
clutter_actor_queue_relayout (CLUTTER_ACTOR (entry));
|
||||
}
|
||||
|
||||
/**
|
||||
* st_entry_get_hint_actor:
|
||||
* @entry: a #StEntry
|
||||
*
|
||||
* Returns: (transfer none): a #ClutterActor
|
||||
*/
|
||||
ClutterActor *
|
||||
st_entry_get_hint_actor (StEntry *entry)
|
||||
{
|
||||
StEntryPrivate *priv;
|
||||
|
||||
g_return_val_if_fail (ST_IS_ENTRY (entry), NULL);
|
||||
|
||||
priv = ST_ENTRY_PRIV (entry);
|
||||
return priv->hint_actor;
|
||||
}
|
||||
|
||||
/******************************************************************************/
|
||||
/*************************** ACCESSIBILITY SUPPORT ****************************/
|
||||
/******************************************************************************/
|
||||
|
@ -65,6 +65,10 @@ void st_entry_set_secondary_icon (StEntry *entry,
|
||||
ClutterActor *icon);
|
||||
ClutterActor * st_entry_get_secondary_icon (StEntry *entry);
|
||||
|
||||
void st_entry_set_hint_actor (StEntry *entry,
|
||||
ClutterActor *hint_actor);
|
||||
ClutterActor * st_entry_get_hint_actor (StEntry *entry);
|
||||
|
||||
typedef void (*StEntryCursorFunc) (StEntry *entry, gboolean use_ibeam, gpointer data);
|
||||
void st_entry_set_cursor_func (StEntryCursorFunc func,
|
||||
gpointer user_data);
|
||||
|
Loading…
Reference in New Issue
Block a user