[gtk+] label: Use css nodes for links
- From: Matthias Clasen <matthiasc src gnome org>
- To: commits-list gnome org
- Cc:
- Subject: [gtk+] label: Use css nodes for links
- Date: Sun, 15 Nov 2015 06:05:16 +0000 (UTC)
commit 3811eb4f32bbb719d15954f4a4c422e34001a91b
Author: Matthias Clasen <mclasen redhat com>
Date: Sun Nov 15 01:00:20 2015 -0500
label: Use css nodes for links
Use a subnode with name link for links in labels. These subnodes
carry the :link or :visited state.
gtk/gtklabel.c | 104 ++++++++++++++++++++++++++++++++++++++++---------------
1 files changed, 75 insertions(+), 29 deletions(-)
---
diff --git a/gtk/gtklabel.c b/gtk/gtklabel.c
index e0f564e..7da71bf 100644
--- a/gtk/gtklabel.c
+++ b/gtk/gtklabel.c
@@ -75,10 +75,24 @@
*
* # CSS nodes
*
+ * |[<!-- language="plain" -->
+ * label
+ * ├── [selection]
+ * ├── [link]
+ * ┊
+ * ╰── [link]
+ * ]|
+ *
* GtkLabel has a single CSS node with the name label. A wide variety
* of style classes may be applied to labels, such as .title, .subtitle,
* .dim-label, etc.
*
+ * If the label has a selection, it gets a subnode with name selection.
+ *
+ * If the label has links, there is one subnode per link. These subnodes
+ * carry the link or visited state depending on whether they have been
+ * visited.
+ *
* # GtkLabel as GtkBuildable
*
* The GtkLabel implementation of the GtkBuildable interface supports a
@@ -301,6 +315,9 @@ typedef struct
{
gchar *uri;
gchar *title; /* the title attribute, used as tooltip */
+
+ GtkCssNode *cssnode;
+
gboolean visited; /* get set when the link is activated; this flag
* gets preserved over later set_markup() calls
*/
@@ -2376,6 +2393,8 @@ start_element_handler (GMarkupParseContext *context,
gint line_number;
gint char_number;
gint i;
+ GtkCssNode *widget_node;
+ GtkStateFlags state;
g_markup_parse_context_get_position (context, &line_number, &char_number);
@@ -2429,6 +2448,19 @@ start_element_handler (GMarkupParseContext *context,
link = g_new0 (GtkLabelLink, 1);
link->uri = g_strdup (uri);
link->title = g_strdup (title);
+
+ widget_node = gtk_widget_get_css_node (GTK_WIDGET (pdata->label));
+ link->cssnode = gtk_css_node_new ();
+ gtk_css_node_set_name (link->cssnode, I_("link"));
+ gtk_css_node_set_parent (link->cssnode, widget_node);
+ state = gtk_css_node_get_state (widget_node);
+ if (visited)
+ state |= GTK_STATE_FLAG_VISITED;
+ else
+ state |= GTK_STATE_FLAG_LINK;
+ gtk_css_node_set_state (link->cssnode, state);
+ g_object_unref (link->cssnode);
+
link->visited = visited;
link->start = pdata->text_len;
pdata->links = g_list_prepend (pdata->links, link);
@@ -2515,6 +2547,7 @@ xml_isspace (gchar c)
static void
link_free (GtkLabelLink *link)
{
+ gtk_css_node_set_parent (link->cssnode, NULL);
g_free (link->uri);
g_free (link->title);
g_free (link);
@@ -3456,26 +3489,18 @@ gtk_label_update_layout_attributes (GtkLabel *label)
attrs = pango_attr_list_new ();
- gtk_style_context_save (context);
-
for (list = priv->select_info->links; list; list = list->next)
{
GtkLabelLink *link = list->data;
- GtkStateFlags state;
attribute = pango_attr_underline_new (TRUE);
attribute->start_index = link->start;
attribute->end_index = link->end;
pango_attr_list_insert (attrs, attribute);
- state = gtk_widget_get_state_flags (widget);
- if (link->visited)
- state |= GTK_STATE_FLAG_VISITED;
- else
- state |= GTK_STATE_FLAG_LINK;
-
- gtk_style_context_set_state (context, state);
- gtk_style_context_get_color (context, state, &link_color);
+ gtk_style_context_save_to_node (context, link->cssnode);
+ gtk_style_context_get_color (context, gtk_style_context_get_state (context), &link_color);
+ gtk_style_context_restore (context);
attribute = pango_attr_foreground_new (link_color.red * 65535,
link_color.green * 65535,
@@ -3484,8 +3509,6 @@ gtk_label_update_layout_attributes (GtkLabel *label)
attribute->end_index = link->end;
pango_attr_list_insert (attrs, attribute);
}
-
- gtk_style_context_restore (context);
}
else if (priv->markup_attrs && priv->attrs)
attrs = pango_attr_list_new ();
@@ -4125,6 +4148,36 @@ gtk_label_update_cursor (GtkLabel *label)
}
static void
+update_link_state (GtkLabel *label)
+{
+ GtkLabelPrivate *priv = label->priv;
+ GList *l;
+ GtkStateFlags state;
+
+ if (!priv->select_info)
+ return;
+
+ for (l = priv->select_info->links; l; l = l->next)
+ {
+ GtkLabelLink *link = l->data;
+
+ state = gtk_widget_get_state_flags (GTK_WIDGET (label));
+ if (link->visited)
+ state |= GTK_STATE_FLAG_VISITED;
+ else
+ state |= GTK_STATE_FLAG_LINK;
+ if (link == priv->select_info->active_link)
+ {
+ if (priv->select_info->link_clicked)
+ state |= GTK_STATE_FLAG_ACTIVE;
+ else
+ state |= GTK_STATE_FLAG_PRELIGHT;
+ }
+ gtk_css_node_set_state (link->cssnode, state);
+ }
+}
+
+static void
gtk_label_state_flags_changed (GtkWidget *widget,
GtkStateFlags prev_state)
{
@@ -4137,6 +4190,7 @@ gtk_label_state_flags_changed (GtkWidget *widget,
gtk_label_select_region (label, 0, 0);
gtk_label_update_cursor (label);
+ update_link_state (label);
}
if (GTK_WIDGET_CLASS (gtk_label_parent_class)->state_flags_changed)
@@ -4226,7 +4280,6 @@ gtk_label_draw (GtkWidget *widget,
GtkLabelSelectionInfo *info = priv->select_info;
GtkAllocation allocation;
GtkStyleContext *context;
- GtkStateFlags state;
gint x, y;
gtk_label_ensure_layout (label);
@@ -4315,7 +4368,7 @@ gtk_label_draw (GtkWidget *widget,
range[1] = active_link->end;
cairo_save (cr);
- gtk_style_context_save (context);
+ gtk_style_context_save_to_node (context, active_link->cssnode);
clip = gdk_pango_layout_get_clip_region (priv->layout,
x, y,
@@ -4326,20 +4379,6 @@ gtk_label_draw (GtkWidget *widget,
cairo_clip (cr);
cairo_region_destroy (clip);
- state = gtk_style_context_get_state (context);
-
- if (info->link_clicked)
- state |= GTK_STATE_FLAG_ACTIVE;
- else
- state |= GTK_STATE_FLAG_PRELIGHT;
-
- if (active_link->visited)
- state |= GTK_STATE_FLAG_VISITED;
- else
- state |= GTK_STATE_FLAG_LINK;
-
- gtk_style_context_set_state (context, state);
-
gtk_render_background (context, cr,
allocation.x, allocation.y,
allocation.width, allocation.height);
@@ -4942,12 +4981,14 @@ gtk_label_multipress_gesture_pressed (GtkGestureMultiPress *gesture,
if (gdk_event_triggers_context_menu (event))
{
info->link_clicked = 1;
+ update_link_state (label);
gtk_label_do_popup (label, (GdkEventButton*) event);
return;
}
else if (button == GDK_BUTTON_PRIMARY)
{
info->link_clicked = 1;
+ update_link_state (label);
gtk_widget_queue_draw (widget);
if (!info->selectable)
return;
@@ -5313,6 +5354,7 @@ gtk_label_motion (GtkWidget *widget,
{
info->link_clicked = 0;
info->active_link = link;
+ update_link_state (label);
gtk_label_update_cursor (label);
gtk_widget_queue_draw (widget);
}
@@ -5323,6 +5365,7 @@ gtk_label_motion (GtkWidget *widget,
{
info->link_clicked = 0;
info->active_link = NULL;
+ update_link_state (label);
gtk_label_update_cursor (label);
gtk_widget_queue_draw (widget);
}
@@ -6709,11 +6752,14 @@ emit_activate_link (GtkLabel *label,
{
GtkLabelPrivate *priv = label->priv;
gboolean handled;
+ GtkStateFlags state;
g_signal_emit (label, signals[ACTIVATE_LINK], 0, link->uri, &handled);
if (handled && priv->track_links && !link->visited)
{
link->visited = TRUE;
+ state = gtk_css_node_get_state (link->cssnode);
+ gtk_css_node_set_state (link->cssnode, (state & ~GTK_STATE_FLAG_LINK) | GTK_STATE_FLAG_VISITED);
/* FIXME: shouldn't have to redo everything here */
gtk_label_clear_layout (label);
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]