summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--ChangeLog16
-rw-r--r--docs/reference/ChangeLog4
-rw-r--r--docs/reference/gtk/gtk-sections.txt2
-rw-r--r--gtk/gtk.symbols2
-rw-r--r--gtk/gtkrange.c119
-rw-r--r--gtk/gtkrange.h6
-rw-r--r--gtk/gtkscale.c340
-rw-r--r--gtk/gtkscale.h8
-rw-r--r--tests/Makefile.am3
-rwxr-xr-xtests/testscale.c149
10 files changed, 641 insertions, 8 deletions
diff --git a/ChangeLog b/ChangeLog
index 9ef794a388..8263c0bbe2 100644
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,19 @@
+2009-01-20 Matthias Clasen <mclasen@redhat.com>
+
+ Bug 565656 – Add marks to scales
+
+ * gtk/gtkrange.[hc]: Add internal api to define 'stop values'
+ that have a little resistance when dragging the slider over it.
+
+ * gtk/gtk.symbols:
+ * gtk/gtkscale.[hc] (gtk_scale_add_mark): New function to add
+ a 'mark' to a scale, which will draws a tick, plus optionally
+ some text, and makes the value a stop value.
+ (gtk_scale_clear_values): Removes all marks.
+
+ * tests/testscale.c: Test for marks on scales
+ * tests/Makefile.am: Integrate it
+
2009-01-19 Matthias Clasen <mclasen@redhat.com>
* gtk/gtkentry.c:
diff --git a/docs/reference/ChangeLog b/docs/reference/ChangeLog
index d86a1d04e4..dd3da2b828 100644
--- a/docs/reference/ChangeLog
+++ b/docs/reference/ChangeLog
@@ -1,3 +1,7 @@
+2009-01-20 Matthias Clasen <mclasen@redhat.com>
+
+ * gtk/gtk-sections.txt: Add new scale api
+
2009-01-19 Matthias Clasen <mclasen@redhat.com>
* gdk/tmpl/cursors.sgml: Document GDK_BLANK_CURSOR.
diff --git a/docs/reference/gtk/gtk-sections.txt b/docs/reference/gtk/gtk-sections.txt
index 448ba4e68a..597e65a740 100644
--- a/docs/reference/gtk/gtk-sections.txt
+++ b/docs/reference/gtk/gtk-sections.txt
@@ -3229,6 +3229,8 @@ gtk_scale_get_draw_value
gtk_scale_get_value_pos
gtk_scale_get_layout
gtk_scale_get_layout_offsets
+gtk_scale_add_mark
+gtk_scale_clear_marks
<SUBSECTION Standard>
GTK_SCALE
GTK_IS_SCALE
diff --git a/gtk/gtk.symbols b/gtk/gtk.symbols
index 0e73df53de..096b8fe01e 100644
--- a/gtk/gtk.symbols
+++ b/gtk/gtk.symbols
@@ -3460,6 +3460,8 @@ gtk_scale_get_value_pos
gtk_scale_set_digits
gtk_scale_set_draw_value
gtk_scale_set_value_pos
+gtk_scale_add_mark
+gtk_scale_clear_marks
#endif
#endif
diff --git a/gtk/gtkrange.c b/gtk/gtkrange.c
index e926f70d34..cdf9212839 100644
--- a/gtk/gtkrange.c
+++ b/gtk/gtkrange.c
@@ -117,6 +117,11 @@ struct _GtkRangeLayout
GQuark slider_detail_quark;
GQuark stepper_detail_quark;
+
+ gdouble *marks;
+ gint *mark_pos;
+ gint n_marks;
+ gboolean recalc_marks;
};
@@ -175,6 +180,7 @@ static gboolean gtk_range_scroll (GtkRange *range,
static gboolean gtk_range_update_mouse_location (GtkRange *range);
static void gtk_range_calc_layout (GtkRange *range,
gdouble adjustment_value);
+static void gtk_range_calc_marks (GtkRange *range);
static void gtk_range_get_props (GtkRange *range,
gint *slider_width,
gint *stepper_size,
@@ -1216,6 +1222,13 @@ gtk_range_destroy (GtkObject *object)
range->adjustment = NULL;
}
+ if (range->layout->n_marks)
+ {
+ g_free (range->layout->marks);
+ g_free (range->layout->mark_pos);
+ range->layout->n_marks = 0;
+ }
+
GTK_OBJECT_CLASS (gtk_range_parent_class)->destroy (object);
}
@@ -1255,6 +1268,8 @@ gtk_range_size_allocate (GtkWidget *widget,
widget->allocation = *allocation;
+ range->layout->recalc_marks = TRUE;
+
range->need_recalc = TRUE;
gtk_range_calc_layout (range, range->adjustment->value);
@@ -1520,6 +1535,7 @@ gtk_range_expose (GtkWidget *widget,
expose_area.x -= widget->allocation.x;
expose_area.y -= widget->allocation.y;
+ gtk_range_calc_marks (range);
gtk_range_calc_layout (range, range->adjustment->value);
sensitive = GTK_WIDGET_IS_SENSITIVE (widget);
@@ -2101,6 +2117,10 @@ update_slider_position (GtkRange *range,
gint c;
gdouble new_value;
gboolean handled;
+ gdouble next_value;
+ gdouble mark_value;
+ gdouble mark_delta;
+ gint i;
if (range->orientation == GTK_ORIENTATION_VERTICAL)
delta = mouse_y - range->slide_initial_coordinate;
@@ -2110,7 +2130,23 @@ update_slider_position (GtkRange *range,
c = range->slide_initial_slider_position + delta;
new_value = coord_to_value (range, c);
-
+ next_value = coord_to_value (range, c + 1);
+ mark_delta = fabs (next_value - new_value);
+
+ for (i = 0; i < range->layout->n_marks; i++)
+ {
+ mark_value = range->layout->marks[i];
+
+ if (fabs (range->adjustment->value - mark_value) < 3 * mark_delta)
+ {
+ if (fabs (new_value - mark_value) < (range->slider_end - range->slider_start) * 0.5 * mark_delta)
+ {
+ new_value = mark_value;
+ break;
+ }
+ }
+ }
+
g_signal_emit (range, signals[CHANGE_VALUE], 0, GTK_SCROLL_JUMP, new_value,
&handled);
}
@@ -2340,6 +2376,7 @@ gtk_range_adjustment_changed (GtkAdjustment *adjustment,
/* create a copy of the layout */
GtkRangeLayout layout = *range->layout;
+ range->layout->recalc_marks = TRUE;
range->need_recalc = TRUE;
gtk_range_calc_layout (range, range->adjustment->value);
@@ -2409,12 +2446,33 @@ gtk_range_style_set (GtkWidget *widget,
}
static void
+apply_marks (GtkRange *range,
+ gdouble oldval,
+ gdouble *newval)
+{
+ gint i;
+ gdouble mark;
+
+ for (i = 0; i < range->layout->n_marks; i++)
+ {
+ mark = range->layout->marks[i];
+ if ((oldval < mark && mark < *newval) ||
+ (oldval > mark && mark > *newval))
+ {
+ *newval = mark;
+ return;
+ }
+ }
+}
+
+static void
step_back (GtkRange *range)
{
gdouble newval;
gboolean handled;
newval = range->adjustment->value - range->adjustment->step_increment;
+ apply_marks (range, range->adjustment->value, &newval);
g_signal_emit (range, signals[CHANGE_VALUE], 0,
GTK_SCROLL_STEP_BACKWARD, newval, &handled);
}
@@ -2426,6 +2484,7 @@ step_forward (GtkRange *range)
gboolean handled;
newval = range->adjustment->value + range->adjustment->step_increment;
+ apply_marks (range, range->adjustment->value, &newval);
g_signal_emit (range, signals[CHANGE_VALUE], 0,
GTK_SCROLL_STEP_FORWARD, newval, &handled);
}
@@ -2438,6 +2497,7 @@ page_back (GtkRange *range)
gboolean handled;
newval = range->adjustment->value - range->adjustment->page_increment;
+ apply_marks (range, range->adjustment->value, &newval);
g_signal_emit (range, signals[CHANGE_VALUE], 0,
GTK_SCROLL_PAGE_BACKWARD, newval, &handled);
}
@@ -2449,6 +2509,7 @@ page_forward (GtkRange *range)
gboolean handled;
newval = range->adjustment->value + range->adjustment->page_increment;
+ apply_marks (range, range->adjustment->value, &newval);
g_signal_emit (range, signals[CHANGE_VALUE], 0,
GTK_SCROLL_PAGE_FORWARD, newval, &handled);
}
@@ -3337,6 +3398,29 @@ get_area (GtkRange *range,
return NULL;
}
+static void
+gtk_range_calc_marks (GtkRange *range)
+{
+ gint i;
+
+ if (!range->layout->recalc_marks)
+ return;
+
+ range->layout->recalc_marks = FALSE;
+
+ for (i = 0; i < range->layout->n_marks; i++)
+ {
+ range->need_recalc = TRUE;
+ gtk_range_calc_layout (range, range->layout->marks[i]);
+ if (range->orientation == GTK_ORIENTATION_HORIZONTAL)
+ range->layout->mark_pos[i] = range->layout->slider.x + range->layout->slider.width / 2;
+ else
+ range->layout->mark_pos[i] = range->layout->slider.y + range->layout->slider.height / 2;
+ }
+
+ range->need_recalc = TRUE;
+}
+
static gboolean
gtk_range_real_change_value (GtkRange *range,
GtkScrollType scroll,
@@ -3511,5 +3595,38 @@ gtk_range_remove_update_timer (GtkRange *range)
}
}
+void
+_gtk_range_set_stop_values (GtkRange *range,
+ gdouble *values,
+ gint n_values)
+{
+ gint i;
+
+ g_free (range->layout->marks);
+ range->layout->marks = g_new (gdouble, n_values);
+
+ g_free (range->layout->mark_pos);
+ range->layout->mark_pos = g_new (gint, n_values);
+
+ range->layout->n_marks = n_values;
+
+ for (i = 0; i < n_values; i++)
+ range->layout->marks[i] = values[i];
+
+ range->layout->recalc_marks = TRUE;
+}
+
+gint
+_gtk_range_get_stop_positions (GtkRange *range,
+ gint **values)
+{
+ gtk_range_calc_marks (range);
+
+ if (values)
+ *values = g_memdup (range->layout->mark_pos, range->layout->n_marks * sizeof (gint));
+
+ return range->layout->n_marks;
+}
+
#define __GTK_RANGE_C__
#include "gtkaliasdef.c"
diff --git a/gtk/gtkrange.h b/gtk/gtkrange.h
index 08860f8121..f7f3b96aa7 100644
--- a/gtk/gtkrange.h
+++ b/gtk/gtkrange.h
@@ -178,6 +178,12 @@ gdouble gtk_range_get_fill_level (GtkRange *range
gdouble _gtk_range_get_wheel_delta (GtkRange *range,
GdkScrollDirection direction);
+void _gtk_range_set_stop_values (GtkRange *range,
+ gdouble *values,
+ gint n_values);
+gint _gtk_range_get_stop_positions (GtkRange *range,
+ gint **values);
+
G_END_DECLS
diff --git a/gtk/gtkscale.c b/gtk/gtkscale.c
index e602f9e4f7..87ba227991 100644
--- a/gtk/gtkscale.c
+++ b/gtk/gtkscale.c
@@ -32,6 +32,8 @@
#include "gdk/gdkkeysyms.h"
#include "gtkscale.h"
+#include "gtkiconfactory.h"
+#include "gtkicontheme.h"
#include "gtkmarshalers.h"
#include "gtkbindings.h"
#include "gtkprivate.h"
@@ -49,9 +51,19 @@
typedef struct _GtkScalePrivate GtkScalePrivate;
+typedef struct _GtkScaleMark GtkScaleMark;
+
+struct _GtkScaleMark
+{
+ gdouble value;
+ const gchar *markup;
+ GtkPositionType position;
+};
+
struct _GtkScalePrivate
{
PangoLayout *layout;
+ GSList *marks;
};
enum {
@@ -76,10 +88,20 @@ static void gtk_scale_get_property (GObject *object,
guint prop_id,
GValue *value,
GParamSpec *pspec);
+static void gtk_scale_size_request (GtkWidget *widget,
+ GtkRequisition *requisition);
static void gtk_scale_style_set (GtkWidget *widget,
GtkStyle *previous);
static void gtk_scale_get_range_border (GtkRange *range,
GtkBorder *border);
+static void gtk_scale_get_mark_label_size (GtkScale *scale,
+ GtkPositionType position,
+ gint *count1,
+ gint *width1,
+ gint *height1,
+ gint *count2,
+ gint *width2,
+ gint *height2);
static void gtk_scale_finalize (GObject *object);
static void gtk_scale_screen_changed (GtkWidget *widget,
GdkScreen *old_screen);
@@ -132,6 +154,7 @@ gtk_scale_class_init (GtkScaleClass *class)
widget_class->style_set = gtk_scale_style_set;
widget_class->screen_changed = gtk_scale_screen_changed;
widget_class->expose_event = gtk_scale_expose;
+ widget_class->size_request = gtk_scale_size_request;
range_class->slider_detail = "Xscale";
range_class->get_range_border = gtk_scale_get_range_border;
@@ -647,12 +670,14 @@ static void
gtk_scale_get_range_border (GtkRange *range,
GtkBorder *border)
{
+ GtkScalePrivate *priv;
GtkWidget *widget;
GtkScale *scale;
gint w, h;
widget = GTK_WIDGET (range);
scale = GTK_SCALE (range);
+ priv = GTK_SCALE_GET_PRIVATE (scale);
_gtk_scale_get_value_size (scale, &w, &h);
@@ -682,6 +707,36 @@ gtk_scale_get_range_border (GtkRange *range,
break;
}
}
+
+ if (priv->marks)
+ {
+ gint slider_width;
+ gint value_spacing;
+ gint n1, w1, h1, n2, w2, h2;
+
+ gtk_widget_style_get (widget,
+ "slider-width", &slider_width,
+ "value-spacing", &value_spacing,
+ NULL);
+
+
+ if (GTK_RANGE (scale)->orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ gtk_scale_get_mark_label_size (scale, GTK_POS_TOP, &n1, &w1, &h1, &n2, &w2, &h2);
+ if (n1 > 0)
+ border->top += h1 + value_spacing + slider_width / 2;
+ if (n2 > 0)
+ border->bottom += h2 + value_spacing + slider_width / 2;
+ }
+ else
+ {
+ gtk_scale_get_mark_label_size (scale, GTK_POS_LEFT, &n1, &w1, &h1, &n2, &w2, &h2);
+ if (n1 > 0)
+ border->left += w1 + value_spacing + slider_width / 2;
+ if (n2 > 0)
+ border->right += w2 + value_spacing + slider_width / 2;
+ }
+ }
}
/* FIXME this could actually be static at the moment. */
@@ -739,6 +794,63 @@ _gtk_scale_get_value_size (GtkScale *scale,
}
static void
+gtk_scale_get_mark_label_size (GtkScale *scale,
+ GtkPositionType position,
+ gint *count1,
+ gint *width1,
+ gint *height1,
+ gint *count2,
+ gint *width2,
+ gint *height2)
+{
+ GtkScalePrivate *priv = GTK_SCALE_GET_PRIVATE (scale);
+ PangoLayout *layout;
+ PangoRectangle logical_rect;
+ GSList *m;
+ gint w, h;
+
+ *count1 = *count2 = 0;
+ *width1 = *width2 = 0;
+ *height1 = *height2 = 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)
+ {
+ 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 == position)
+ {
+ (*count1)++;
+ *width1 = MAX (*width1, w);
+ *height1 = MAX (*height1, h);
+ }
+ else
+ {
+ (*count2)++;
+ *width2 = MAX (*width2, w);
+ *height2 = MAX (*height2, h);
+ }
+ }
+
+ g_object_unref (layout);
+}
+
+static void
gtk_scale_style_set (GtkWidget *widget,
GtkStyle *previous)
{
@@ -765,31 +877,160 @@ gtk_scale_screen_changed (GtkWidget *widget,
_gtk_scale_clear_layout (GTK_SCALE (widget));
}
+static void
+gtk_scale_size_request (GtkWidget *widget,
+ GtkRequisition *requisition)
+{
+ GtkRange *range = GTK_RANGE (widget);
+ gint n1, w1, h1, n2, w2, h2;
+ gint slider_length;
+
+ GTK_WIDGET_CLASS (gtk_scale_parent_class)->size_request (widget, requisition);
+
+ gtk_widget_style_get (widget, "slider-length", &slider_length, NULL);
+
+
+ if (range->orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ gtk_scale_get_mark_label_size (GTK_SCALE (widget), GTK_POS_TOP, &n1, &w1, &h1, &n2, &w2, &h2);
+
+ w1 = (n1 - 1) * w1 + MAX (w1, slider_length);
+ w2 = (n2 - 1) * w2 + MAX (w2, slider_length);
+ requisition->width = MAX (requisition->width, MAX (w1, w2));
+ }
+ else
+ {
+ gtk_scale_get_mark_label_size (GTK_SCALE (widget), GTK_POS_LEFT, &n1, &w1, &h1, &n2, &w2, &h2);
+ h1 = (n1 - 1) * h1 + MAX (h1, slider_length);
+ h2 = (n2 - 1) * h1 + MAX (h2, slider_length);
+ requisition->height = MAX (requisition->height, MAX (h1, h2));
+ }
+}
+
static gboolean
gtk_scale_expose (GtkWidget *widget,
GdkEventExpose *event)
{
GtkScale *scale = GTK_SCALE (widget);
+ GtkScalePrivate *priv = GTK_SCALE_GET_PRIVATE (scale);
+ GtkRange *range = GTK_RANGE (scale);
+ GtkStateType state_type;
+ gint n_marks;
+ gint *marks;
+ gint focus_padding;
+ gint slider_width;
+ gint value_spacing;
+
+ gtk_widget_style_get (widget,
+ "focus-padding", &focus_padding,
+ "slider-width", &slider_width,
+ "value-spacing", &value_spacing,
+ NULL);
/* We need to chain up _first_ so the various geometry members of
* GtkRange struct are updated.
*/
GTK_WIDGET_CLASS (gtk_scale_parent_class)->expose_event (widget, event);
+ state_type = GTK_STATE_NORMAL;
+ if (!GTK_WIDGET_IS_SENSITIVE (widget))
+ state_type = GTK_STATE_INSENSITIVE;
+
+ if (priv->marks)
+ {
+ gint i;
+ gint x1, x2, x3, y1, y2, y3;
+ PangoLayout *layout;
+ PangoRectangle logical_rect;
+ GSList *m;
+
+ n_marks = _gtk_range_get_stop_positions (range, &marks);
+ layout = gtk_widget_create_pango_layout (widget, NULL);
+
+ for (m = priv->marks, i = 0; m; m = m->next, i++)
+ {
+ GtkScaleMark *mark = m->data;
+
+ if (range->orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ x1 = widget->allocation.x + marks[i];
+ if (mark->position == GTK_POS_TOP)
+ {
+ y1 = widget->allocation.y + range->range_rect.y;
+ y2 = y1 - slider_width / 2;
+ }
+ else
+ {
+ y1 = widget->allocation.y + range->range_rect.y + range->range_rect.height;
+ y2 = y1 + slider_width / 2;
+ }
+
+ gtk_paint_vline (widget->style, widget->window, state_type,
+ NULL, widget, "scale-mark", y1, y2, x1);
+
+ 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 (mark->position == GTK_POS_TOP)
+ y3 = y2 - value_spacing - logical_rect.height;
+ else
+ y3 = y2 + value_spacing;
+
+ gtk_paint_layout (widget->style, widget->window, state_type,
+ FALSE, NULL, widget, "scale-mark",
+ x3, y3, layout);
+ }
+ }
+ else
+ {
+ if (mark->position == GTK_POS_LEFT)
+ {
+ x1 = widget->allocation.x + range->range_rect.x;
+ x2 = widget->allocation.x + range->range_rect.x - slider_width / 2;
+ }
+ else
+ {
+ x1 = widget->allocation.x + range->range_rect.x + range->range_rect.width;
+ x2 = widget->allocation.x + range->range_rect.x + range->range_rect.width + slider_width / 2;
+ }
+ y1 = widget->allocation.y + marks[i];
+
+ gtk_paint_hline (widget->style, widget->window, state_type,
+ NULL, widget, "range-mark", x1, x2, y1);
+
+ if (mark->markup)
+ {
+ pango_layout_set_markup (layout, mark->markup, -1);
+ pango_layout_get_pixel_extents (layout, NULL, &logical_rect);
+
+ if (mark->position == GTK_POS_LEFT)
+ x3 = x2 - value_spacing - logical_rect.width;
+ else
+ x3 = x2 + value_spacing;
+ y3 = y1 - logical_rect.height / 2;
+
+ gtk_paint_layout (widget->style, widget->window, state_type,
+ FALSE, NULL, widget, "scale-mark",
+ x3, y3, layout);
+ }
+ }
+ }
+
+ g_object_unref (layout);
+ g_free (marks);
+ }
+
if (scale->draw_value)
{
- GtkRange *range = GTK_RANGE (scale);
PangoLayout *layout;
gint x, y;
- GtkStateType state_type;
layout = gtk_scale_get_layout (scale);
gtk_scale_get_layout_offsets (scale, &x, &y);
- state_type = GTK_STATE_NORMAL;
- if (!GTK_WIDGET_IS_SENSITIVE (scale))
- state_type = GTK_STATE_INSENSITIVE;
-
gtk_paint_layout (widget->style,
widget->window,
state_type,
@@ -932,6 +1173,7 @@ gtk_scale_finalize (GObject *object)
GtkScale *scale = GTK_SCALE (object);
_gtk_scale_clear_layout (scale);
+ gtk_scale_clear_marks (scale);
G_OBJECT_CLASS (gtk_scale_parent_class)->finalize (object);
}
@@ -1024,5 +1266,91 @@ _gtk_scale_clear_layout (GtkScale *scale)
}
}
+static void
+gtk_scale_mark_free (GtkScaleMark *mark)
+{
+ g_free (mark->markup);
+ g_free (mark);
+}
+
+/**
+ * gtk_scale_clear_marks:
+ * @scale: a #GtkScale
+ *
+ * Removes any marks that have been added with gtk_scale_add_mark().
+ *
+ * Since: 2.16
+ */
+void
+gtk_scale_clear_marks (GtkScale *scale)
+{
+ GtkScalePrivate *priv = GTK_SCALE_GET_PRIVATE (scale);
+
+ g_return_if_fail (GTK_IS_SCALE (scale));
+
+ g_slist_foreach (priv->marks, (GFunc)gtk_scale_mark_free, NULL);
+ g_slist_free (priv->marks);
+ priv->marks = NULL;
+
+ _gtk_range_set_stop_values (GTK_RANGE (scale), NULL, 0);
+}
+
+/**
+ * gtk_scale_add_mark:
+ * @scale: a #GtkScale
+ * @value: the value at which the mark is placed, must be between
+ * the lower and upper limits of the scales' adjustment
+ * @position: where to draw the mark. For a horizontal scale, #GTK_POS_TOP
+ * is drawn above the scale, anything else below. For a vertical scale,
+ * #GTK_POS_LEFT is drawn to the left of the scale, anything else to the
+ * right.
+ * @markup: Text to be shown at the mark, using <link linkend="PangoMarkupFormat">Pango markup</link>, or %NULL
+ *
+ *
+ * Adds a mark at @value.
+ *
+ * A mark is indicated visually by drawing a tick mark next to the scale,
+ * and GTK+ makes it easy for the user to position the scale exactly at the
+ * marks value.
+ *
+ * If @markup is not %NULL, text is shown next to the tick mark.
+ *
+ * To remove marks from a scale, use gtk_scale_clear_marks().
+ *
+ * Since: 2.16
+ */
+void
+gtk_scale_add_mark (GtkScale *scale,
+ gdouble value,
+ GtkPositionType position,
+ const gchar *markup)
+{
+ GtkScalePrivate *priv = GTK_SCALE_GET_PRIVATE (scale);
+ GtkScaleMark *mark;
+ GSList *m;
+ gdouble *values;
+ gint n, i;
+
+ mark = g_new (GtkScaleMark, 1);
+ mark->value = value;
+ mark->markup = g_strdup (markup);
+ mark->position = position;
+
+ priv->marks = g_slist_prepend (priv->marks, mark);
+
+ n = g_slist_length (priv->marks);
+ values = g_new (gdouble, n);
+ for (m = priv->marks, i = 0; m; m = m->next, i++)
+ {
+ mark = m->data;
+ values[i] = mark->value;
+ }
+
+ _gtk_range_set_stop_values (GTK_RANGE (scale), values, n);
+
+ g_free (values);
+}
+
+
#define __GTK_SCALE_C__
#include "gtkaliasdef.c"
diff --git a/gtk/gtkscale.h b/gtk/gtkscale.h
index 34e690adac..4221dd281c 100644
--- a/gtk/gtkscale.h
+++ b/gtk/gtkscale.h
@@ -71,9 +71,9 @@ struct _GtkScaleClass
gint *y);
/* Padding for future expansion */
+ void (*_gtk_reserved1) (void);
void (*_gtk_reserved2) (void);
void (*_gtk_reserved3) (void);
- void (*_gtk_reserved4) (void);
};
GType gtk_scale_get_type (void) G_GNUC_CONST;
@@ -92,6 +92,12 @@ void gtk_scale_get_layout_offsets (GtkScale *scale,
gint *x,
gint *y);
+void gtk_scale_add_mark (GtkScale *scale,
+ gdouble value,
+ GtkPositionType position,
+ const gchar *markup);
+void gtk_scale_clear_marks (GtkScale *scale);
+
/* internal API */
void _gtk_scale_clear_layout (GtkScale *scale);
void _gtk_scale_get_value_size (GtkScale *scale,
diff --git a/tests/Makefile.am b/tests/Makefile.am
index 370b997ef3..426dea30e9 100644
--- a/tests/Makefile.am
+++ b/tests/Makefile.am
@@ -60,6 +60,7 @@ noinst_PROGRAMS = $(TEST_PROGS) \
testrecentchooser \
testrecentchoosermenu \
testrichtext \
+ testscale \
testselection \
$(testsocket_programs) \
testspinbutton \
@@ -137,6 +138,7 @@ testrecentchooser_DEPENDENCIES = $(TEST_DEPS)
testrecentchoosermenu_DEPENDENCIES = $(TEST_DEPS)
testrgb_DEPENDENCIES = $(TEST_DEPS)
testrichtext_DEPENDENCIES = $(TEST_DEPS)
+testscale_DEPENDENCIES = $(TEST_DEPS)
testselection_DEPENDENCIES = $(TEST_DEPS)
testsocket_DEPENDENCIES = $(DEPS)
testsocket_child_DEPENDENCIES = $(DEPS)
@@ -194,6 +196,7 @@ testrecentchooser_LDADD = $(LDADDS)
testrecentchoosermenu_LDADD = $(LDADDS)
testrgb_LDADD = $(LDADDS)
testrichtext_LDADD = $(LDADDS)
+testscale_LDADD = $(LDADDS)
testselection_LDADD = $(LDADDS)
testsocket_LDADD = $(LDADDS)
testsocket_child_LDADD = $(LDADDS)
diff --git a/tests/testscale.c b/tests/testscale.c
new file mode 100755
index 0000000000..35b287e2dd
--- /dev/null
+++ b/tests/testscale.c
@@ -0,0 +1,149 @@
+/* testscale.c - scale mark demo
+ * Copyright (C) 2009 Red Hat, Inc.
+ * Author: Matthias Clasen
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 2 of the License, or (at your option) any later version.
+ *
+ * This library is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <gtk/gtk.h>
+
+int main (int argc, char *argv[])
+{
+ GtkWidget *window;
+ GtkWidget *box;
+ GtkWidget *box2;
+ GtkWidget *frame;
+ GtkWidget *scale;
+ GIcon *icon;
+ gdouble marks[3] = { 0.0, 50.0, 100.0 };
+ const gchar *labels[3] = {
+ "<small>Left</small>",
+ "<small>Middle</small>",
+ "<small>Right</small>"
+ };
+
+ gdouble bath_marks[4] = { 0.0, 33.3, 66.6, 100.0 };
+ const gchar *bath_labels[4] = {
+ "<span color='blue' size='small'>Cold</span>",
+ "<span size='small'>Baby bath</span>",
+ "<span size='small'>Hot tub</span>",
+ "<span color='Red' size='small'>Hot</span>"
+ };
+
+ gtk_init (&argc, &argv);
+
+ window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title (GTK_WINDOW (window), "Ranges with marks");
+ box = gtk_vbox_new (FALSE, 5);
+
+ frame = gtk_frame_new ("No marks");
+ scale = gtk_hscale_new_with_range (0, 100, 1);
+ gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
+ gtk_container_add (GTK_CONTAINER (frame), scale);
+ gtk_box_pack_start (GTK_BOX (box), frame, FALSE, FALSE, 0);
+
+ frame = gtk_frame_new ("Simple marks");
+ scale = gtk_hscale_new_with_range (0, 100, 1);
+ gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
+ gtk_scale_add_mark (GTK_SCALE (scale), marks[0], GTK_POS_BOTTOM, NULL);
+ gtk_scale_add_mark (GTK_SCALE (scale), marks[1], GTK_POS_BOTTOM, NULL);
+ gtk_scale_add_mark (GTK_SCALE (scale), marks[2], GTK_POS_BOTTOM, NULL);
+ gtk_container_add (GTK_CONTAINER (frame), scale);
+ gtk_box_pack_start (GTK_BOX (box), frame, FALSE, FALSE, 0);
+
+ frame = gtk_frame_new ("Labeled marks");
+ scale = gtk_hscale_new_with_range (0, 100, 1);
+ gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
+ gtk_scale_add_mark (GTK_SCALE (scale), marks[0], GTK_POS_BOTTOM, labels[0]);
+ gtk_scale_add_mark (GTK_SCALE (scale), marks[1], GTK_POS_BOTTOM, labels[1]);
+ gtk_scale_add_mark (GTK_SCALE (scale), marks[2], GTK_POS_BOTTOM, labels[2]);
+ gtk_container_add (GTK_CONTAINER (frame), scale);
+ gtk_box_pack_start (GTK_BOX (box), frame, FALSE, FALSE, 0);
+
+ frame = gtk_frame_new ("Some labels");
+ scale = gtk_hscale_new_with_range (0, 100, 1);
+ gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
+ gtk_scale_add_mark (GTK_SCALE (scale), marks[0], GTK_POS_BOTTOM, labels[0]);
+ gtk_scale_add_mark (GTK_SCALE (scale), marks[1], GTK_POS_BOTTOM, NULL);
+ gtk_scale_add_mark (GTK_SCALE (scale), marks[2], GTK_POS_BOTTOM, labels[2]);
+ gtk_container_add (GTK_CONTAINER (frame), scale);
+ gtk_box_pack_start (GTK_BOX (box), frame, FALSE, FALSE, 0);
+
+ frame = gtk_frame_new ("Above and below");
+ scale = gtk_hscale_new_with_range (0, 100, 1);
+ gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
+ gtk_scale_add_mark (GTK_SCALE (scale), bath_marks[0], GTK_POS_TOP, bath_labels[0]);
+ gtk_scale_add_mark (GTK_SCALE (scale), bath_marks[1], GTK_POS_BOTTOM, bath_labels[1]);
+ gtk_scale_add_mark (GTK_SCALE (scale), bath_marks[2], GTK_POS_BOTTOM, bath_labels[2]);
+ gtk_scale_add_mark (GTK_SCALE (scale), bath_marks[3], GTK_POS_TOP, bath_labels[3]);
+ gtk_container_add (GTK_CONTAINER (frame), scale);
+ gtk_box_pack_start (GTK_BOX (box), frame, FALSE, FALSE, 0);
+
+ box2 = gtk_hbox_new (FALSE, 5);
+ gtk_box_pack_start (GTK_BOX (box), box2, TRUE, TRUE, 0);
+
+ frame = gtk_frame_new ("No marks");
+ scale = gtk_vscale_new_with_range (0, 100, 1);
+ gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
+ gtk_container_add (GTK_CONTAINER (frame), scale);
+ gtk_box_pack_start (GTK_BOX (box2), frame, FALSE, FALSE, 0);
+
+ frame = gtk_frame_new ("Simple marks");
+ scale = gtk_vscale_new_with_range (0, 100, 1);
+ gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
+ gtk_scale_add_mark (GTK_SCALE (scale), marks[0], GTK_POS_LEFT, NULL);
+ gtk_scale_add_mark (GTK_SCALE (scale), marks[1], GTK_POS_LEFT, NULL);
+ gtk_scale_add_mark (GTK_SCALE (scale), marks[2], GTK_POS_LEFT, NULL);
+ gtk_container_add (GTK_CONTAINER (frame), scale);
+ gtk_box_pack_start (GTK_BOX (box2), frame, FALSE, FALSE, 0);
+
+ frame = gtk_frame_new ("Labeled marks");
+ scale = gtk_vscale_new_with_range (0, 100, 1);
+ gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
+ gtk_scale_add_mark (GTK_SCALE (scale), marks[0], GTK_POS_LEFT, labels[0]);
+ gtk_scale_add_mark (GTK_SCALE (scale), marks[1], GTK_POS_LEFT, labels[1]);
+ gtk_scale_add_mark (GTK_SCALE (scale), marks[2], GTK_POS_LEFT, labels[2]);
+ gtk_container_add (GTK_CONTAINER (frame), scale);
+ gtk_box_pack_start (GTK_BOX (box2), frame, FALSE, FALSE, 0);
+
+ frame = gtk_frame_new ("Some labels");
+ scale = gtk_vscale_new_with_range (0, 100, 1);
+ gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
+ gtk_scale_add_mark (GTK_SCALE (scale), marks[0], GTK_POS_LEFT, labels[0]);
+ gtk_scale_add_mark (GTK_SCALE (scale), marks[1], GTK_POS_LEFT, NULL);
+ gtk_scale_add_mark (GTK_SCALE (scale), marks[2], GTK_POS_LEFT, labels[2]);
+ gtk_container_add (GTK_CONTAINER (frame), scale);
+ gtk_box_pack_start (GTK_BOX (box2), frame, FALSE, FALSE, 0);
+
+ frame = gtk_frame_new ("Right and left");
+ scale = gtk_vscale_new_with_range (0, 100, 1);
+ gtk_scale_set_draw_value (GTK_SCALE (scale), FALSE);
+ gtk_scale_add_mark (GTK_SCALE (scale), bath_marks[0], GTK_POS_RIGHT, bath_labels[0]);
+ gtk_scale_add_mark (GTK_SCALE (scale), bath_marks[1], GTK_POS_LEFT, bath_labels[1]);
+ gtk_scale_add_mark (GTK_SCALE (scale), bath_marks[2], GTK_POS_LEFT, bath_labels[2]);
+ gtk_scale_add_mark (GTK_SCALE (scale), bath_marks[3], GTK_POS_RIGHT, bath_labels[3]);
+ gtk_container_add (GTK_CONTAINER (frame), scale);
+ gtk_box_pack_start (GTK_BOX (box2), frame, FALSE, FALSE, 0);
+
+ gtk_container_add (GTK_CONTAINER (window), box);
+ gtk_widget_show_all (window);
+
+ gtk_main ();
+
+ return 0;
+}
+
+