diff options
-rw-r--r-- | gtk/gtkscale.c | 552 |
1 files changed, 302 insertions, 250 deletions
diff --git a/gtk/gtkscale.c b/gtk/gtkscale.c index 3794724071..4adc0220da 100644 --- a/gtk/gtkscale.c +++ b/gtk/gtkscale.c @@ -137,8 +137,9 @@ struct _GtkScalePrivate struct _GtkScaleMark { gdouble value; + int stop_position; gchar *markup; - GtkCssNode *node; + GtkCssGadget *gadget; GtkPositionType position; /* always GTK_POS_TOP or GTK_POS_BOTTOM */ }; @@ -256,6 +257,143 @@ gtk_scale_notify (GObject *object, G_OBJECT_CLASS (gtk_scale_parent_class)->notify (object, pspec); } +static gint +find_next_pos (GtkWidget *widget, + GSList *list, + gint *marks, + GtkPositionType pos) +{ + GtkAllocation allocation; + GSList *m; + gint i; + + for (m = list->next, i = 1; m; m = m->next, i++) + { + GtkScaleMark *mark = m->data; + + if (mark->position == pos) + return marks[i]; + } + + gtk_widget_get_allocation (widget, &allocation); + if (gtk_orientable_get_orientation (GTK_ORIENTABLE (widget)) == GTK_ORIENTATION_HORIZONTAL) + return allocation.width; + else + return allocation.height; +} + +static void +gtk_scale_allocate_marks (GtkCssGadget *gadget, + const GtkAllocation *allocation, + int baseline, + GtkAllocation *out_clip, + gpointer data) +{ + GtkWidget *widget = gtk_css_gadget_get_owner (gadget); + GtkScale *scale = GTK_SCALE (widget); + GtkScalePrivate *priv = scale->priv; + GtkOrientation orientation; + int *marks; + int min_pos_before, min_pos_after; + int min_sep = 4; + int i; + int min_pos, max_pos; + GSList *m; + GtkAllocation widget_alloc; + + orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (scale)); + _gtk_range_get_stop_positions (GTK_RANGE (scale), &marks); + min_pos_before = min_pos_after = 0; + gtk_widget_get_allocation (widget, &widget_alloc); + + for (m = priv->marks, i = 0; m; m = m->next, i++) + { + GtkScaleMark *mark = m->data; + GtkAllocation mark_alloc, mark_clip; + int mark_size; + + if ((mark->position == GTK_POS_TOP && gadget == priv->bottom_marks_gadget) || + (mark->position == GTK_POS_BOTTOM && gadget == priv->top_marks_gadget)) + continue; + + gtk_css_gadget_get_preferred_size (mark->gadget, + orientation, -1, + &mark_size, NULL, + NULL, NULL); + mark->stop_position = marks[i]; + + if (orientation == GTK_ORIENTATION_HORIZONTAL) + { + mark_alloc.x = mark->stop_position + widget_alloc.x; + mark_alloc.y = allocation->y; + mark_alloc.width = mark_size; + mark_alloc.height = allocation->height; + + if (mark->position == GTK_POS_TOP) + { + min_pos = min_pos_before; + max_pos = find_next_pos (widget, m, marks + i, GTK_POS_TOP) - min_sep + widget_alloc.x; + } + else + { + min_pos = min_pos_after; + max_pos = find_next_pos (widget, m, marks + i, GTK_POS_BOTTOM) - min_sep + widget_alloc.x; + } + + mark_alloc.x -= mark_size / 2; + + if (mark_alloc.x < min_pos) + mark_alloc.x = min_pos; + if (mark_alloc.x + mark_size > max_pos) + mark_alloc.x = max_pos - mark_size; + if (mark_alloc.x < 0) + mark_alloc.x = 0; + + if (mark->position == GTK_POS_TOP) + min_pos_before = mark_alloc.x + mark_size + min_sep; + else + min_pos_after = mark_alloc.x + mark_size + min_sep; + } + else + { + mark_alloc.x = allocation->x; + mark_alloc.y = mark->stop_position + widget_alloc.y; + mark_alloc.width = allocation->width; + mark_alloc.height = mark_size; + + if (mark->position == GTK_POS_TOP) + { + min_pos = min_pos_before; + max_pos = find_next_pos (widget, m, marks + i, GTK_POS_TOP) - min_sep + widget_alloc.y; + } + else + { + min_pos = min_pos_after; + max_pos = find_next_pos (widget, m, marks + i, GTK_POS_BOTTOM) - min_sep + widget_alloc.y; + } + + mark_alloc.y -= mark_size / 2; + + if (mark_alloc.y < min_pos) + mark_alloc.y = min_pos; + if (mark_alloc.y + mark_size > max_pos) + mark_alloc.y = max_pos - mark_size; + if (mark_alloc.y < 0) + mark_alloc.y = 0; + + if (mark->position == GTK_POS_TOP) + min_pos_before = mark_alloc.y + mark_size + min_sep; + else + min_pos_after = mark_alloc.y + mark_size + min_sep; + } + + gtk_css_gadget_allocate (mark->gadget, &mark_alloc, baseline, &mark_clip); + gdk_rectangle_union (out_clip, &mark_clip, out_clip); + } + + g_free (marks); +} + static void gtk_scale_size_allocate (GtkWidget *widget, GtkAllocation *allocation) @@ -1102,62 +1240,6 @@ gtk_scale_get_value_size (GtkScale *scale, } static void -gtk_scale_get_mark_label_size (GtkScale *scale, - gint *count_top, - gint *width_top, - gint *height_top, - gint *count_bottom, - gint *width_bottom, - gint *height_bottom) -{ - GtkScalePrivate *priv = scale->priv; - PangoLayout *layout; - PangoRectangle logical_rect; - GSList *m; - gint w, h; - - *count_top = *count_bottom = 0; - *width_top = *width_bottom = 0; - *height_top = *height_bottom = 0; - - layout = gtk_widget_create_pango_layout (GTK_WIDGET (scale), NULL); - - for (m = priv->marks; m; m = m->next) - { - GtkScaleMark *mark = m->data; - - if (mark->markup && *mark->markup) - { - pango_layout_set_markup (layout, mark->markup, -1); - pango_layout_get_pixel_extents (layout, NULL, &logical_rect); - - w = logical_rect.width; - h = logical_rect.height; - } - else - { - w = 0; - h = 0; - } - - if (mark->position == GTK_POS_TOP) - { - (*count_top)++; - *width_top = MAX (*width_top, w); - *height_top = MAX (*height_top, h); - } - else - { - (*count_bottom)++; - *width_bottom = MAX (*width_bottom, w); - *height_bottom = MAX (*height_bottom, h); - } - } - - g_object_unref (layout); -} - -static void gtk_scale_style_updated (GtkWidget *widget) { gtk_scale_clear_layout (GTK_SCALE (widget)); @@ -1173,6 +1255,39 @@ gtk_scale_screen_changed (GtkWidget *widget, } static void +gtk_scale_measure_mark (GtkCssGadget *gadget, + GtkOrientation orientation, + gint for_size, + gint *minimum, + gint *natural, + gint *minimum_baseline, + gint *natural_baseline, + gpointer user_data) +{ + GtkWidget *widget = gtk_css_gadget_get_owner (gadget); + GtkScaleMark *mark = user_data; + + *minimum = *natural = 0; + + if (mark->markup) + { + PangoLayout *layout; + PangoRectangle logical_rect; + + layout = gtk_widget_create_pango_layout (widget, NULL); + pango_layout_set_markup (layout, mark->markup, -1); + pango_layout_get_pixel_extents (layout, NULL, &logical_rect); + + if (orientation == GTK_ORIENTATION_HORIZONTAL) + *minimum = *natural = logical_rect.width; + else + *minimum = *natural = logical_rect.height; + + g_object_unref (layout); + } +} + +static void gtk_scale_measure_marks (GtkCssGadget *gadget, GtkOrientation orientation, gint for_size, @@ -1185,51 +1300,34 @@ gtk_scale_measure_marks (GtkCssGadget *gadget, GtkWidget *widget = gtk_css_gadget_get_owner (gadget); GtkScale *scale = GTK_SCALE (widget); GtkScalePrivate *priv = scale->priv; - GtkCssGadget *slider_gadget = gtk_range_get_slider_gadget (GTK_RANGE (scale)); GtkOrientation scale_orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (scale)); - int n_top, w_top, h_top, n_bottom, w_bottom, h_bottom; - int slider_length; - - gtk_scale_get_mark_label_size (scale, - &n_top, &w_top, &h_top, - &n_bottom, &w_bottom, &h_bottom); - gtk_css_gadget_get_preferred_size (slider_gadget, - orientation, -1, - &slider_length, NULL, - NULL, NULL); - - if (gadget == priv->top_marks_gadget) - { - if (scale_orientation == GTK_ORIENTATION_HORIZONTAL) - { - if (orientation == GTK_ORIENTATION_HORIZONTAL) - *minimum = *natural = (n_top - 1) * w_top + MAX (w_top, slider_length); - else - *minimum = *natural = h_top; - } - else - { - if (orientation == GTK_ORIENTATION_HORIZONTAL) - *minimum = *natural = w_top; - else - *minimum = *natural = (n_top - 1) * h_top + MAX (h_top, slider_length); - } - } - else + GSList *m; + + *minimum = *natural = 0; + + for (m = priv->marks; m; m = m->next) { - if (scale_orientation == GTK_ORIENTATION_HORIZONTAL) + GtkScaleMark *mark = m->data; + int mark_size; + + if ((mark->position == GTK_POS_TOP && gadget == priv->bottom_marks_gadget) || + (mark->position == GTK_POS_BOTTOM && gadget == priv->top_marks_gadget)) + continue; + + gtk_css_gadget_get_preferred_size (mark->gadget, + orientation, -1, + &mark_size, NULL, + NULL, NULL); + + if (scale_orientation == orientation) { - if (orientation == GTK_ORIENTATION_HORIZONTAL) - *minimum = *natural = (n_bottom - 1) * w_bottom + MAX (w_bottom, slider_length); - else - *minimum = *natural = h_bottom; + *minimum += mark_size; + *natural += mark_size; } else { - if (orientation == GTK_ORIENTATION_HORIZONTAL) - *minimum = *natural = w_bottom; - else - *minimum = *natural = (n_bottom - 1) * h_bottom + MAX (h_bottom, slider_length); + *minimum = MAX (*minimum, mark_size); + *natural = MAX (*natural, mark_size); } } } @@ -1298,183 +1396,132 @@ gtk_scale_get_preferred_height (GtkWidget *widget, } } -static gint -find_next_pos (GtkWidget *widget, - GSList *list, - gint *marks, - GtkPositionType pos) -{ - GtkAllocation allocation; - GSList *m; - gint i; - - for (m = list->next, i = 1; m; m = m->next, i++) - { - GtkScaleMark *mark = m->data; - - if (mark->position == pos) - return marks[i]; - } - - gtk_widget_get_allocation (widget, &allocation); - if (gtk_orientable_get_orientation (GTK_ORIENTABLE (widget)) == GTK_ORIENTATION_HORIZONTAL) - return allocation.width; - else - return allocation.height; -} - static gboolean -gtk_scale_render_marks (GtkCssGadget *gadget, - cairo_t *cr, - int x, - int y, - int width, - int height, - gpointer user_data) +gtk_scale_render_mark (GtkCssGadget *gadget, + cairo_t *cr, + int x, + int y, + int width, + int height, + gpointer user_data) { GtkWidget *widget = gtk_css_gadget_get_owner (gadget); GtkScale *scale = GTK_SCALE (widget); - GtkScalePrivate *priv = scale->priv; + GtkScaleMark *mark = user_data; GtkOrientation orientation; - gint i; - gint x1, x2, x3, y1, y2, y3; - PangoLayout *layout; - PangoRectangle logical_rect; - GSList *m; - gint min_pos_before, min_pos_after; - gint min_pos, max_pos; - GtkCssGadget *slider_gadget; GtkAllocation slider_alloc; - gint value_spacing; - gint min_sep = 4; - gint *marks; + GtkCssGadget *slider_gadget; GtkStyleContext *context; - GtkRange *range = GTK_RANGE (scale); - - context = gtk_widget_get_style_context (widget); - gtk_widget_style_get (widget, - "value-spacing", &value_spacing, - NULL); + PangoLayout *layout; - slider_gadget = gtk_range_get_slider_gadget (range); + slider_gadget = gtk_range_get_slider_gadget (GTK_RANGE (scale)); gtk_css_gadget_get_content_allocation (slider_gadget, &slider_alloc, NULL); - orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (range)); - _gtk_range_get_stop_positions (range, &marks); + orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (scale)); - layout = gtk_widget_create_pango_layout (widget, NULL); + context = gtk_widget_get_style_context (widget); + gtk_style_context_save_to_node (context, gtk_css_gadget_get_node (gadget)); - min_pos_before = min_pos_after = 0; + layout = gtk_widget_create_pango_layout (widget, NULL); - for (m = priv->marks, i = 0; m; m = m->next, i++) + if (orientation == GTK_ORIENTATION_HORIZONTAL) { - GtkScaleMark *mark = m->data; + int y1, y2; - if ((mark->position == GTK_POS_TOP && gadget == priv->bottom_marks_gadget) || - (mark->position == GTK_POS_BOTTOM && gadget == priv->top_marks_gadget)) - continue; + if (mark->position == GTK_POS_TOP) + { + y1 = y + height; + y2 = y + height - slider_alloc.height / 4; + } + else + { + y1 = y; + y2 = y + slider_alloc.height / 4; + } - gtk_style_context_save_to_node (context, mark->node); + gtk_render_line (context, cr, + mark->stop_position, y1, + mark->stop_position, y2); - if (orientation == GTK_ORIENTATION_HORIZONTAL) + if (mark->markup) { - x1 = marks[i]; + int y3; + + pango_layout_set_markup (layout, mark->markup, -1); + if (mark->position == GTK_POS_TOP) - { - y1 = y + height; - y2 = y + height - slider_alloc.height / 4; - min_pos = min_pos_before; - max_pos = find_next_pos (widget, m, marks + i, GTK_POS_TOP) - min_sep; - } + y3 = y; else - { - y1 = y; - y2 = y + slider_alloc.height / 4; - min_pos = min_pos_after; - max_pos = find_next_pos (widget, m, marks + i, GTK_POS_BOTTOM) - min_sep; - } + y3 = y2; - gtk_render_line (context, cr, x1, y1, x1, y2); + gtk_render_layout (context, cr, x, y3, layout); + } + } + else + { + int x1, x2; - if (mark->markup) - { - pango_layout_set_markup (layout, mark->markup, -1); - pango_layout_get_pixel_extents (layout, NULL, &logical_rect); - - x3 = x1 - logical_rect.width / 2; - if (x3 < min_pos) - x3 = min_pos; - if (x3 + logical_rect.width > max_pos) - x3 = max_pos - logical_rect.width; - if (x3 < 0) - x3 = 0; - if (mark->position == GTK_POS_TOP) - { - y3 = y2 - value_spacing - logical_rect.height; - min_pos_before = x3 + logical_rect.width + min_sep; - } - else - { - y3 = y2 + value_spacing; - min_pos_after = x3 + logical_rect.width + min_sep; - } - - gtk_render_layout (context, cr, x3, y3, layout); - } + if (mark->position == GTK_POS_TOP) + { + x1 = x + width; + x2 = x + width - slider_alloc.width / 4; } else { + x1 = x; + x2 = x + slider_alloc.width / 4; + } + + gtk_render_line (context, cr, + x1, mark->stop_position, + x2, mark->stop_position); + + if (mark->markup) + { + int x3; + + pango_layout_set_markup (layout, mark->markup, -1); + if (mark->position == GTK_POS_TOP) - { - x1 = x + width; - x2 = x + width - slider_alloc.width / 4; - min_pos = min_pos_before; - max_pos = find_next_pos (widget, m, marks + i, GTK_POS_TOP) - min_sep; - } + x3 = x; else - { - x1 = x; - x2 = x + slider_alloc.width / 4; - min_pos = min_pos_after; - max_pos = find_next_pos (widget, m, marks + i, GTK_POS_BOTTOM) - min_sep; - } - y1 = marks[i]; - - gtk_render_line (context, cr, x1, y1, x2, y1); + x3 = x2; - if (mark->markup) - { - pango_layout_set_markup (layout, mark->markup, -1); - pango_layout_get_pixel_extents (layout, NULL, &logical_rect); - - y3 = y1 - logical_rect.height / 2; - if (y3 < min_pos) - y3 = min_pos; - if (y3 + logical_rect.height > max_pos) - y3 = max_pos - logical_rect.height; - if (y3 < 0) - y3 = 0; - if (mark->position == GTK_POS_TOP) - { - x3 = x2 - value_spacing - logical_rect.width; - min_pos_before = y3 + logical_rect.height + min_sep; - } - else - { - x3 = x2 + value_spacing; - min_pos_after = y3 + logical_rect.height + min_sep; - } - - gtk_render_layout (context, cr, x3, y3, layout); - } + gtk_render_layout (context, cr, x3, y, layout); } - - gtk_style_context_restore (context); } + gtk_style_context_restore (context); g_object_unref (layout); - g_free (marks); + + return FALSE; +} + +static gboolean +gtk_scale_render_marks (GtkCssGadget *gadget, + cairo_t *cr, + int x, + int y, + int width, + int height, + gpointer user_data) +{ + GtkWidget *widget = gtk_css_gadget_get_owner (gadget); + GtkScale *scale = GTK_SCALE (widget); + GtkScalePrivate *priv = scale->priv; + GSList *m; + + for (m = priv->marks; m; m = m->next) + { + GtkScaleMark *mark = m->data; + + if ((mark->position == GTK_POS_TOP && gadget == priv->bottom_marks_gadget) || + (mark->position == GTK_POS_BOTTOM && gadget == priv->top_marks_gadget)) + continue; + + gtk_css_gadget_draw (mark->gadget, cr); + } return FALSE; } @@ -1731,7 +1778,7 @@ gtk_scale_mark_free (gpointer data) { GtkScaleMark *mark = data; - gtk_css_node_set_parent (mark->node, NULL); + g_object_unref (mark->gadget); g_free (mark->markup); g_free (mark); } @@ -1827,7 +1874,7 @@ gtk_scale_add_mark (GtkScale *scale, gtk_css_custom_gadget_new ("marks", GTK_WIDGET (scale), NULL, NULL, gtk_scale_measure_marks, - NULL, + gtk_scale_allocate_marks, gtk_scale_render_marks, NULL, NULL); gtk_css_node_insert_after (widget_node, gtk_css_gadget_get_node (priv->top_marks_gadget), NULL); @@ -1844,7 +1891,7 @@ gtk_scale_add_mark (GtkScale *scale, gtk_css_custom_gadget_new ("marks", GTK_WIDGET (scale), NULL, NULL, gtk_scale_measure_marks, - NULL, + gtk_scale_allocate_marks, gtk_scale_render_marks, NULL, NULL); gtk_css_node_insert_before (widget_node, gtk_css_gadget_get_node (priv->bottom_marks_gadget), NULL); @@ -1854,9 +1901,14 @@ gtk_scale_add_mark (GtkScale *scale, marks_node = gtk_css_gadget_get_node (priv->bottom_marks_gadget); } - mark->node = gtk_css_node_new (); - gtk_css_node_set_name (mark->node, I_("mark")); - gtk_css_node_set_state (mark->node, gtk_css_node_get_state (marks_node)); + mark->gadget = + gtk_css_custom_gadget_new ("mark", + GTK_WIDGET (scale), NULL, NULL, + gtk_scale_measure_mark, + NULL, + gtk_scale_render_mark, + mark, NULL); + gtk_css_gadget_set_state (mark->gadget, gtk_css_node_get_state (marks_node)); m = g_slist_find (priv->marks, mark); m = m->next; @@ -1871,15 +1923,15 @@ gtk_scale_add_mark (GtkScale *scale, if (m) { GtkScaleMark *next = m->data; - gtk_css_node_insert_before (marks_node, mark->node, next->node); + gtk_css_node_insert_before (marks_node, + gtk_css_gadget_get_node (mark->gadget), + gtk_css_gadget_get_node (next->gadget)); } else { - gtk_css_node_set_parent (mark->node, marks_node); + gtk_css_node_set_parent (gtk_css_gadget_get_node (mark->gadget), marks_node); } - g_object_unref (mark->node); - n = g_slist_length (priv->marks); values = g_new (gdouble, n); for (m = priv->marks, i = 0; m; m = m->next, i++) |