summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCosimo Cecchi <cosimoc@gnome.org>2016-02-28 13:45:48 -0800
committerCosimo Cecchi <cosimoc@gnome.org>2016-02-29 10:45:14 -0800
commit7bd3d87eeb604b52912902b23e23aa38eb92a97d (patch)
tree040f92ed4fb1ba215a65af098c7fe0634f86a99d
parent74a8bbfd3849b5d6dbe9ae620a0351d4fe8e8f2c (diff)
downloadgtk+-7bd3d87eeb604b52912902b23e23aa38eb92a97d.tar.gz
scale: add a gadget for every mark
We want to add another gadget for the mark indicator. This will allow us to do so.
-rw-r--r--gtk/gtkscale.c552
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++)