diff --git a/gtk/gtkrange.c b/gtk/gtkrange.c index f79001771b..3748fe0bf8 100644 --- a/gtk/gtkrange.c +++ b/gtk/gtkrange.c @@ -45,6 +45,7 @@ #include "gtkwindow.h" #include "gtkwidgetprivate.h" #include "a11y/gtkrangeaccessible.h" +#include "gtkcssstylepropertyprivate.h" /** * SECTION:gtkrange @@ -103,6 +104,12 @@ struct _GtkRangePrivate GdkRectangle slider; GdkWindow *event_window; + GtkCssNode *stepper_a_node; + GtkCssNode *stepper_b_node; + GtkCssNode *stepper_c_node; + GtkCssNode *stepper_d_node; + GtkCssNode *slider_node; + GtkOrientation orientation; gdouble fill_level; @@ -178,10 +185,10 @@ enum { }; typedef enum { - STEPPER_A, - STEPPER_B, - STEPPER_C, - STEPPER_D + STEPPER_A = MOUSE_STEPPER_A, + STEPPER_B = MOUSE_STEPPER_B, + STEPPER_C = MOUSE_STEPPER_C, + STEPPER_D = MOUSE_STEPPER_D } Stepper; static void gtk_range_set_property (GObject *object, @@ -297,6 +304,8 @@ static gboolean gtk_range_real_change_value (GtkRange *range, gdouble value); static gboolean gtk_range_key_press (GtkWidget *range, GdkEventKey *event); +static void gtk_range_state_flags_changed (GtkWidget *widget, + GtkStateFlags previous_state); G_DEFINE_ABSTRACT_TYPE_WITH_CODE (GtkRange, gtk_range, GTK_TYPE_WIDGET, @@ -331,6 +340,7 @@ gtk_range_class_init (GtkRangeClass *class) widget_class->event = gtk_range_event; widget_class->scroll_event = gtk_range_scroll_event; widget_class->key_press_event = gtk_range_key_press; + widget_class->state_flags_changed = gtk_range_state_flags_changed; class->move_slider = gtk_range_move_slider; class->change_value = gtk_range_real_change_value; @@ -703,10 +713,34 @@ gtk_range_get_property (GObject *object, } } +static void +node_style_changed_cb (GtkCssNode *node, + GtkCssStyle *old_style, + GtkCssStyle *new_style, + GtkWidget *widget) +{ + GtkBitmask *changes; + static GtkBitmask *affects_size = NULL; + + if (G_UNLIKELY (affects_size == NULL)) + affects_size = _gtk_css_style_property_get_mask_affecting (GTK_CSS_AFFECTS_SIZE | GTK_CSS_AFFECTS_CLIP); + + changes = _gtk_bitmask_new (); + changes = gtk_css_style_add_difference (changes, old_style, new_style); + + if (_gtk_bitmask_intersects (changes, affects_size)) + gtk_widget_queue_resize (widget); + else + gtk_widget_queue_draw (widget); + + _gtk_bitmask_free (changes); +} + static void gtk_range_init (GtkRange *range) { GtkRangePrivate *priv; + GtkCssNode *widget_node; range->priv = gtk_range_get_instance_private (range); priv = range->priv; @@ -739,6 +773,14 @@ gtk_range_init (GtkRange *range) _gtk_orientable_set_style_classes (GTK_ORIENTABLE (range)); + widget_node = gtk_widget_get_css_node (GTK_WIDGET (range)); + priv->slider_node = gtk_css_node_new (); + gtk_css_node_set_name (priv->slider_node, I_("slider")); + gtk_css_node_set_parent (priv->slider_node, widget_node); + gtk_css_node_set_state (priv->slider_node, gtk_css_node_get_state (widget_node)); + g_signal_connect_object (priv->slider_node, "style-changed", G_CALLBACK (node_style_changed_cb), range, 0); + g_object_unref (priv->slider_node); + /* Note: Order is important here. * The ::drag-begin handler relies on the state set up by the * multipress ::pressed handler. Gestures are handling events @@ -850,6 +892,57 @@ gtk_range_set_adjustment (GtkRange *range, } } +static void +update_stepper_state (GtkRange *range, + Stepper stepper, + GtkCssNode *node) +{ + GtkRangePrivate *priv = range->priv; + GtkStateFlags state; + gboolean arrow_sensitive; + + state = gtk_widget_get_state_flags (GTK_WIDGET (range)); + + if ((!priv->inverted && (stepper == STEPPER_A || + stepper == STEPPER_C)) || + (priv->inverted && (stepper == STEPPER_B || + stepper == STEPPER_D))) + arrow_sensitive = priv->lower_sensitive; + else + arrow_sensitive = priv->upper_sensitive; + + state &= ~(GTK_STATE_FLAG_ACTIVE | GTK_STATE_FLAG_PRELIGHT); + + if ((state & GTK_STATE_FLAG_INSENSITIVE) || !arrow_sensitive) + { + state |= GTK_STATE_FLAG_INSENSITIVE; + } + else + { + if (priv->grab_location == (MouseLocation)stepper) + state |= GTK_STATE_FLAG_ACTIVE; + if (priv->mouse_location == (MouseLocation)stepper) + state |= GTK_STATE_FLAG_PRELIGHT; + } + + gtk_css_node_set_state (node, state); +} + +static void +update_steppers_state (GtkRange *range) +{ + GtkRangePrivate *priv = range->priv; + + if (priv->has_stepper_a) + update_stepper_state (range, STEPPER_A, priv->stepper_a_node); + if (priv->has_stepper_b) + update_stepper_state (range, STEPPER_B, priv->stepper_b_node); + if (priv->has_stepper_c) + update_stepper_state (range, STEPPER_C, priv->stepper_c_node); + if (priv->has_stepper_d) + update_stepper_state (range, STEPPER_D, priv->stepper_d_node); +} + /** * gtk_range_set_inverted: * @range: a #GtkRange @@ -875,8 +968,11 @@ gtk_range_set_inverted (GtkRange *range, if (setting != priv->inverted) { priv->inverted = setting; - g_object_notify_by_pspec (G_OBJECT (range), properties[PROP_INVERTED]); + + update_steppers_state (range); gtk_widget_queue_resize (GTK_WIDGET (range)); + + g_object_notify_by_pspec (G_OBJECT (range), properties[PROP_INVERTED]); } } @@ -1700,169 +1796,50 @@ gtk_range_unmap (GtkWidget *widget) } static void -_gtk_range_update_context_for_stepper (GtkRange *range, - GtkStyleContext *context, - Stepper stepper) +update_slider_state (GtkRange *range) { GtkRangePrivate *priv = range->priv; - GtkJunctionSides sides = 0; - gboolean vertical, is_rtl; + GtkStateFlags state; - vertical = (priv->orientation == GTK_ORIENTATION_VERTICAL); - is_rtl = (gtk_widget_get_direction (GTK_WIDGET (range)) == GTK_TEXT_DIR_RTL); + state = gtk_widget_get_state_flags (GTK_WIDGET (range)); - /* Take junction sides from what's been - * previously set to the widget itself - */ - sides = gtk_style_context_get_junction_sides (context); + state &= ~(GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_ACTIVE); - if (vertical) - sides &= ~(GTK_JUNCTION_TOP | GTK_JUNCTION_BOTTOM); - else - sides &= ~(GTK_JUNCTION_LEFT | GTK_JUNCTION_RIGHT); + if (priv->mouse_location == MOUSE_SLIDER && !(state & GTK_STATE_FLAG_INSENSITIVE)) + state |= GTK_STATE_FLAG_PRELIGHT; - switch (stepper) - { - case STEPPER_A: - if (vertical) - sides |= GTK_JUNCTION_BOTTOM; - else - sides |= (is_rtl) ? GTK_JUNCTION_LEFT : GTK_JUNCTION_RIGHT; - break; - case STEPPER_B: - if (priv->has_stepper_a) - { - if (vertical) - sides |= GTK_JUNCTION_TOP; - else - sides |= (is_rtl) ? GTK_JUNCTION_RIGHT : GTK_JUNCTION_LEFT; - } + if (priv->grab_location == MOUSE_SLIDER) + state |= GTK_STATE_FLAG_ACTIVE; - if (vertical) - sides |= GTK_JUNCTION_BOTTOM; - else - sides |= (is_rtl) ? GTK_JUNCTION_LEFT : GTK_JUNCTION_RIGHT; - break; - case STEPPER_C: - if (priv->has_stepper_d) - { - if (vertical) - sides |= GTK_JUNCTION_BOTTOM; - else - sides |= (is_rtl) ? GTK_JUNCTION_LEFT : GTK_JUNCTION_RIGHT; - } + gtk_css_node_set_state (priv->slider_node, state); +} - if (vertical) - sides |= GTK_JUNCTION_TOP; - else - sides |= (is_rtl) ? GTK_JUNCTION_RIGHT : GTK_JUNCTION_LEFT; - break; - case STEPPER_D: - if (vertical) - sides |= GTK_JUNCTION_TOP; - else - sides |= (is_rtl) ? GTK_JUNCTION_RIGHT : GTK_JUNCTION_LEFT; - break; - } +static void +gtk_range_state_flags_changed (GtkWidget *widget, + GtkStateFlags previous_state) +{ + GtkRange *range = GTK_RANGE (widget); - gtk_style_context_set_junction_sides (context, sides); + update_slider_state (range); + update_steppers_state (range); } static void draw_stepper (GtkRange *range, - Stepper stepper, cairo_t *cr, - GtkArrowType arrow_type, - gboolean clicked, - gboolean prelighted, - GtkStateFlags state) + GdkRectangle *rect, + GtkCssNode *node, + GtkArrowType arrow_type) { - GtkRangePrivate *priv = range->priv; - GtkAllocation allocation; GtkStyleContext *context; GtkWidget *widget = GTK_WIDGET (range); gfloat arrow_scaling; - GdkRectangle *rect; gdouble arrow_x; gdouble arrow_y; gdouble arrow_size, angle; - gboolean arrow_sensitive; - - switch (stepper) - { - case STEPPER_A: - rect = &priv->stepper_a; - break; - case STEPPER_B: - rect = &priv->stepper_b; - break; - case STEPPER_C: - rect = &priv->stepper_c; - break; - case STEPPER_D: - rect = &priv->stepper_d; - break; - default: - g_assert_not_reached (); - }; - - gtk_widget_get_allocation (widget, &allocation); - - if ((!priv->inverted && (arrow_type == GTK_ARROW_DOWN || - arrow_type == GTK_ARROW_RIGHT)) || - (priv->inverted && (arrow_type == GTK_ARROW_UP || - arrow_type == GTK_ARROW_LEFT))) - { - arrow_sensitive = priv->upper_sensitive; - } - else - { - arrow_sensitive = priv->lower_sensitive; - } - - state &= ~(GTK_STATE_FLAG_ACTIVE | GTK_STATE_FLAG_PRELIGHT); - - if ((state & GTK_STATE_FLAG_INSENSITIVE) || !arrow_sensitive) - { - state |= GTK_STATE_FLAG_INSENSITIVE; - } - else - { - if (clicked) - state |= GTK_STATE_FLAG_ACTIVE; - if (prelighted) - state |= GTK_STATE_FLAG_PRELIGHT; - } context = gtk_widget_get_style_context (widget); - - gtk_style_context_save (context); - - /* don't set junction sides on scrollbar steppers */ - if (gtk_style_context_has_class (context, GTK_STYLE_CLASS_SCROLLBAR)) - gtk_style_context_set_junction_sides (context, GTK_JUNCTION_NONE); - else - _gtk_range_update_context_for_stepper (range, context, stepper); - - gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON); - gtk_style_context_set_state (context, state); - - switch (arrow_type) - { - case GTK_ARROW_RIGHT: - gtk_style_context_add_class (context, GTK_STYLE_CLASS_RIGHT); - break; - case GTK_ARROW_DOWN: - gtk_style_context_add_class (context, GTK_STYLE_CLASS_BOTTOM); - break; - case GTK_ARROW_LEFT: - gtk_style_context_add_class (context, GTK_STYLE_CLASS_LEFT); - break; - case GTK_ARROW_UP: - default: - gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOP); - break; - } + gtk_style_context_save_to_node (context, node); gtk_render_background (context, cr, rect->x, rect->y, @@ -1877,19 +1854,6 @@ draw_stepper (GtkRange *range, arrow_x = rect->x + (rect->width - arrow_size) / 2; arrow_y = rect->y + (rect->height - arrow_size) / 2; - if (clicked && arrow_sensitive) - { - gint arrow_displacement_x; - gint arrow_displacement_y; - - gtk_range_get_props (GTK_RANGE (widget), - NULL, NULL, NULL, NULL, NULL, - &arrow_displacement_x, &arrow_displacement_y); - - arrow_x += arrow_displacement_x; - arrow_y += arrow_displacement_y; - } - switch (arrow_type) { case GTK_ARROW_RIGHT: @@ -2011,8 +1975,6 @@ gtk_range_draw (GtkWidget *widget, } } - gtk_style_context_save (context); - gtk_style_context_add_class (context, GTK_STYLE_CLASS_TROUGH); gtk_style_context_get_margin (context, widget_state, &margin); x += margin.left; @@ -2091,8 +2053,6 @@ gtk_range_draw (GtkWidget *widget, } } - gtk_style_context_restore (context); - if (priv->show_fill_level && gtk_adjustment_get_upper (priv->adjustment) - gtk_adjustment_get_page_size (priv->adjustment) - gtk_adjustment_get_lower (priv->adjustment) != 0) @@ -2163,24 +2123,12 @@ gtk_range_draw (GtkWidget *widget, if (draw_slider) { - GtkStateFlags state = widget_state; - - state &= ~(GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_ACTIVE); - - if (priv->mouse_location == MOUSE_SLIDER && !(state & GTK_STATE_FLAG_INSENSITIVE)) - state |= GTK_STATE_FLAG_PRELIGHT; - - if (priv->grab_location == MOUSE_SLIDER) - state |= GTK_STATE_FLAG_ACTIVE; - cairo_save (cr); gdk_cairo_rectangle (cr, &priv->slider); cairo_clip (cr); - gtk_style_context_save (context); - gtk_style_context_add_class (context, GTK_STYLE_CLASS_SLIDER); + gtk_style_context_save_to_node (context, priv->slider_node); gtk_style_context_get_margin (context, widget_state, &margin); - gtk_style_context_set_state (context, state); gtk_render_slider (context, cr, priv->slider.x + margin.left, @@ -2195,32 +2143,28 @@ gtk_range_draw (GtkWidget *widget, } if (priv->has_stepper_a) - draw_stepper (range, STEPPER_A, cr, - priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_UP : GTK_ARROW_LEFT, - priv->grab_location == MOUSE_STEPPER_A, - priv->mouse_location == MOUSE_STEPPER_A, - widget_state); + draw_stepper (range, cr, + &priv->stepper_a, + priv->stepper_a_node, + priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_UP : GTK_ARROW_LEFT); if (priv->has_stepper_b) - draw_stepper (range, STEPPER_B, cr, - priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT, - priv->grab_location == MOUSE_STEPPER_B, - priv->mouse_location == MOUSE_STEPPER_B, - widget_state); + draw_stepper (range, cr, + &priv->stepper_b, + priv->stepper_b_node, + priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT); if (priv->has_stepper_c) - draw_stepper (range, STEPPER_C, cr, - priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_UP : GTK_ARROW_LEFT, - priv->grab_location == MOUSE_STEPPER_C, - priv->mouse_location == MOUSE_STEPPER_C, - widget_state); + draw_stepper (range, cr, + &priv->stepper_c, + priv->stepper_c_node, + priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_UP : GTK_ARROW_LEFT); if (priv->has_stepper_d) - draw_stepper (range, STEPPER_D, cr, - priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT, - priv->grab_location == MOUSE_STEPPER_D, - priv->mouse_location == MOUSE_STEPPER_D, - widget_state); + draw_stepper (range, cr, + &priv->stepper_d, + priv->stepper_d_node, + priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT); return FALSE; } @@ -2242,6 +2186,9 @@ range_grab_add (GtkRange *range, priv->grab_location = location; gtk_range_queue_draw_location (range, location); + update_slider_state (range); + update_steppers_state (range); + gtk_style_context_add_class (context, "dragging"); } @@ -2275,6 +2222,8 @@ range_grab_remove (GtkRange *range) gtk_range_update_mouse_location (range); + update_slider_state (range); + update_steppers_state (range); update_zoom_state (range, FALSE); gtk_style_context_remove_class (context, "dragging"); @@ -3364,6 +3313,9 @@ gtk_range_update_mouse_location (GtkRange *range) gtk_widget_unset_state_flags (widget, GTK_STATE_FLAG_PRELIGHT); else gtk_widget_set_state_flags (widget, GTK_STATE_FLAG_PRELIGHT, FALSE); + + update_slider_state (range); + update_steppers_state (range); } } @@ -3727,6 +3679,8 @@ gtk_range_calc_stepper_sensitivity (GtkRange *range) if (was_upper_sensitive != priv->upper_sensitive || was_lower_sensitive != priv->lower_sensitive) { + update_steppers_state (range); + gtk_range_queue_draw_location (range, MOUSE_STEPPER_A); gtk_range_queue_draw_location (range, MOUSE_STEPPER_B); gtk_range_queue_draw_location (range, MOUSE_STEPPER_C); @@ -4250,17 +4204,105 @@ gtk_range_get_round_digits (GtkRange *range) return range->priv->round_digits; } -void -_gtk_range_set_steppers (GtkRange *range, - gboolean has_a, - gboolean has_b, - gboolean has_c, - gboolean has_d) +static GtkCssNode * +create_stepper_node (GtkRange *range, + const gchar *class, + GtkCssNode *before, + GtkCssNode *after) { - range->priv->has_stepper_a = has_a; - range->priv->has_stepper_b = has_b; - range->priv->has_stepper_c = has_c; - range->priv->has_stepper_d = has_d; + GtkCssNode *widget_node, *node; + + widget_node = gtk_widget_get_css_node (GTK_WIDGET (range)); + node = gtk_css_node_new (); + gtk_css_node_set_name (node, I_("button")); + gtk_css_node_add_class (node, g_quark_from_static_string (class)); + if (before) + gtk_css_node_insert_before (widget_node, node, before); + else + gtk_css_node_insert_after (widget_node, node, after); + gtk_css_node_set_state (node, gtk_css_node_get_state (widget_node)); + g_signal_connect_object (node, "style-changed", G_CALLBACK (node_style_changed_cb), range, 0); + g_object_unref (node); + + return node; +} + +void +_gtk_range_set_steppers (GtkRange *range, + gboolean has_a, + gboolean has_b, + gboolean has_c, + gboolean has_d) +{ + GtkRangePrivate *priv = range->priv; + + if (priv->has_stepper_a != has_a) + { + priv->has_stepper_a = has_a; + if (has_a) + { + priv->stepper_a_node = create_stepper_node (range, + "down", + priv->has_stepper_b ? priv->stepper_b_node : priv->slider_node, + NULL); + } + else + { + gtk_css_node_set_parent (priv->stepper_a_node, NULL); + priv->stepper_a_node = NULL; + } + } + + if (priv->has_stepper_b != has_b) + { + priv->has_stepper_b = has_b; + if (has_b) + { + priv->stepper_b_node = create_stepper_node (range, + "up", + priv->slider_node, + NULL); + } + else + { + gtk_css_node_set_parent (priv->stepper_b_node, NULL); + priv->stepper_b_node = NULL; + } + } + + if (priv->has_stepper_c != has_c) + { + priv->has_stepper_c = has_c; + if (has_c) + { + priv->stepper_c_node = create_stepper_node (range, + "down", + NULL, + priv->slider_node); + } + else + { + gtk_css_node_set_parent (priv->stepper_c_node, NULL); + priv->stepper_c_node = NULL; + } + } + + if (priv->has_stepper_d != has_d) + { + priv->has_stepper_d = has_d; + if (has_d) + { + priv->stepper_d_node = create_stepper_node (range, + "up", + NULL, + priv->has_stepper_c ? priv->stepper_c_node : priv->slider_node); + } + else + { + gtk_css_node_set_parent (priv->stepper_d_node, NULL); + priv->stepper_d_node = NULL; + } + } gtk_widget_queue_resize (GTK_WIDGET (range)); } diff --git a/gtk/gtkscale.c b/gtk/gtkscale.c index 4efebd2fe8..97f96a6000 100644 --- a/gtk/gtkscale.c +++ b/gtk/gtkscale.c @@ -40,6 +40,8 @@ #include "gtkorientable.h" #include "gtkprivate.h" #include "gtktypebuiltins.h" +#include "gtkstylecontextprivate.h" +#include "gtkwidgetprivate.h" #include "a11y/gtkscaleaccessible.h" @@ -69,6 +71,21 @@ * element is not empty, its content is taken as the markup to show at * the mark. It can be translated with the usual ”translatable” and * “context” attributes. + * + * # CSS nodes + * + * |[ + * scale + * ├── slider + * ╰── marks + * ├── mark.bottom + * ├── mark.top + * ╰── ... + * ]| + * + * GtkScale has a main CSS node with name scale and a subnode with name slider. + * If marks are present, there is a marks subnode, below which each mark gets + * a node with name mark, and either the .top or .bottom style class. */ @@ -86,6 +103,8 @@ struct _GtkScalePrivate GSList *marks; + GtkCssNode *marks_node; + gint digits; guint draw_value : 1; @@ -96,6 +115,7 @@ struct _GtkScaleMark { gdouble value; gchar *markup; + GtkCssNode *node; GtkPositionType position; /* always GTK_POS_TOP or GTK_POS_BOTTOM */ }; @@ -469,6 +489,7 @@ gtk_scale_class_init (GtkScaleClass *class) GTK_SCROLL_END); gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_SCALE_ACCESSIBLE); + gtk_widget_class_set_css_name (widget_class, "scale"); } static void @@ -476,7 +497,6 @@ gtk_scale_init (GtkScale *scale) { GtkScalePrivate *priv; GtkRange *range = GTK_RANGE (scale); - GtkStyleContext *context; scale->priv = gtk_scale_get_instance_private (scale); priv = scale->priv; @@ -494,8 +514,6 @@ gtk_scale_init (GtkScale *scale) gtk_range_set_flippable (range, TRUE); - context = gtk_widget_get_style_context (GTK_WIDGET (scale)); - gtk_style_context_add_class (context, GTK_STYLE_CLASS_SCALE); gtk_scale_update_style (scale); } @@ -1153,6 +1171,8 @@ gtk_scale_draw (GtkWidget *widget, { GtkScaleMark *mark = m->data; + gtk_style_context_save_to_node (context, mark->node); + if (orientation == GTK_ORIENTATION_HORIZONTAL) { x1 = marks[i]; @@ -1171,12 +1191,7 @@ gtk_scale_draw (GtkWidget *widget, max_pos = find_next_pos (widget, m, marks + i, GTK_POS_BOTTOM) - min_sep; } - gtk_style_context_save (context); - gtk_style_context_add_class (context, GTK_STYLE_CLASS_MARK); - - gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR); gtk_render_line (context, cr, x1, y1, x1, y2); - gtk_style_context_remove_class (context, GTK_STYLE_CLASS_SEPARATOR); if (mark->markup) { @@ -1203,8 +1218,6 @@ gtk_scale_draw (GtkWidget *widget, gtk_render_layout (context, cr, x3, y3, layout); } - - gtk_style_context_restore (context); } else { @@ -1224,12 +1237,7 @@ gtk_scale_draw (GtkWidget *widget, } y1 = marks[i]; - gtk_style_context_save (context); - gtk_style_context_add_class (context, GTK_STYLE_CLASS_MARK); - - gtk_style_context_add_class (context, GTK_STYLE_CLASS_SEPARATOR); gtk_render_line (context, cr, x1, y1, x2, y1); - gtk_style_context_remove_class (context, GTK_STYLE_CLASS_SEPARATOR); if (mark->markup) { @@ -1256,9 +1264,9 @@ gtk_scale_draw (GtkWidget *widget, gtk_render_layout (context, cr, x3, y3, layout); } - - gtk_style_context_restore (context); } + + gtk_style_context_restore (context); } g_object_unref (layout); @@ -1504,6 +1512,7 @@ gtk_scale_mark_free (gpointer data) { GtkScaleMark *mark = data; + gtk_css_node_set_parent (mark->node, NULL); g_free (mark->markup); g_free (mark); } @@ -1533,6 +1542,9 @@ gtk_scale_clear_marks (GtkScale *scale) gtk_style_context_remove_class (context, GTK_STYLE_CLASS_SCALE_HAS_MARKS_BELOW); gtk_style_context_remove_class (context, GTK_STYLE_CLASS_SCALE_HAS_MARKS_ABOVE); + gtk_css_node_set_parent (priv->marks_node, NULL); + priv->marks_node = NULL; + _gtk_range_set_stop_values (GTK_RANGE (scale), NULL, 0); gtk_widget_queue_resize (GTK_WIDGET (scale)); @@ -1593,6 +1605,37 @@ gtk_scale_add_mark (GtkScale *scale, compare_marks, GINT_TO_POINTER (gtk_range_get_inverted (GTK_RANGE (scale)))); + m = g_slist_find (priv->marks, mark); + + if (!priv->marks_node) + { + GtkCssNode *widget_node; + + widget_node = gtk_widget_get_css_node (GTK_WIDGET (scale)); + priv->marks_node = gtk_css_node_new (); + gtk_css_node_set_name (priv->marks_node, I_("marks")); + gtk_css_node_set_parent (priv->marks_node, widget_node); + gtk_css_node_set_state (priv->marks_node, gtk_css_node_get_state (widget_node)); + g_object_unref (priv->marks_node); + } + + mark->node = gtk_css_node_new (); + gtk_css_node_set_name (mark->node, I_("mark")); + gtk_css_node_add_class (mark->node, g_quark_from_static_string (mark->position == GTK_POS_TOP ? "top" : "bottom")); + gtk_css_node_set_state (mark->node, gtk_css_node_get_state (priv->marks_node)); + + if (m->next) + { + GtkScaleMark *next = m->next->data; + gtk_css_node_insert_before (priv->marks_node, mark->node, next->node); + } + else + { + gtk_css_node_set_parent (mark->node, priv->marks_node); + } + + g_object_unref (mark->node); + #define MARKS_ABOVE 1 #define MARKS_BELOW 2 diff --git a/gtk/gtkscrollbar.c b/gtk/gtkscrollbar.c index a609045c86..d61df75792 100644 --- a/gtk/gtkscrollbar.c +++ b/gtk/gtkscrollbar.c @@ -52,6 +52,22 @@ * #GtkAdjustment:page-increment fields are properties when the user asks to * step down (using the small stepper arrows) or page down (using for * example the `Page Down` key). + * + * # CSS nodes + * + * |[ + * scrollbar + * ├── [button.down] + * ├── [button.up] + * ├── slider + * ├── [button.down] + * ╰── [button.up] + * ]| + * + * GtkScrollbar has a main CSS node with name scrollbar, and a subnode + * with name slider. If steppers are enabled, they are represented by up + * to four additional subnodes with name button. These get the style classes + * .up and .down to indicate in which direction they are moving. */ @@ -111,6 +127,7 @@ gtk_scrollbar_class_init (GtkScrollbarClass *class) GTK_PARAM_READABLE)); gtk_widget_class_set_accessible_role (widget_class, ATK_ROLE_SCROLL_BAR); + gtk_widget_class_set_css_name (widget_class, "scrollbar"); } static void @@ -133,17 +150,12 @@ gtk_scrollbar_update_style (GtkScrollbar *scrollbar) gtk_range_set_min_slider_size (range, slider_length); gtk_range_set_slider_size_fixed (range, fixed_size); - _gtk_range_set_steppers (range, - has_a, has_b, has_c, has_d); + _gtk_range_set_steppers (range, has_a, has_b, has_c, has_d); } static void gtk_scrollbar_init (GtkScrollbar *scrollbar) { - GtkStyleContext *context; - - context = gtk_widget_get_style_context (GTK_WIDGET (scrollbar)); - gtk_style_context_add_class (context, GTK_STYLE_CLASS_SCROLLBAR); gtk_scrollbar_update_style (scrollbar); }