Bug 565656 – Add marks to scales
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 svn path=/trunk/; revision=22149
This commit is contained in:
parent
b6b5237663
commit
26490a2dd7
16
ChangeLog
16
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:
|
||||
|
@ -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.
|
||||
|
@ -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
|
||||
|
@ -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
|
||||
|
||||
|
119
gtk/gtkrange.c
119
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);
|
||||
|
||||
@ -2408,6 +2445,26 @@ gtk_range_style_set (GtkWidget *widget,
|
||||
GTK_WIDGET_CLASS (gtk_range_parent_class)->style_set (widget, previous_style);
|
||||
}
|
||||
|
||||
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)
|
||||
{
|
||||
@ -2415,6 +2472,7 @@ step_back (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_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"
|
||||
|
@ -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
|
||||
|
||||
|
340
gtk/gtkscale.c
340
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. */
|
||||
@ -738,6 +793,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"
|
||||
|
@ -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,
|
||||
|
@ -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)
|
||||
|
149
tests/testscale.c
Executable file
149
tests/testscale.c
Executable file
@ -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;
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user