GtkScale: Fix marks for inverted scales
Problem pointed out by Stefan Sauer in bug 667598. The solution here is different from his patch. We always draw marks in increasing direction, and flip the marks and stop positions to match.
This commit is contained in:
114
gtk/gtkscale.c
114
gtk/gtkscale.c
@ -85,7 +85,7 @@ struct _GtkScalePrivate
|
|||||||
{
|
{
|
||||||
PangoLayout *layout;
|
PangoLayout *layout;
|
||||||
|
|
||||||
GList *marks;
|
GSList *marks;
|
||||||
|
|
||||||
gint digits;
|
gint digits;
|
||||||
|
|
||||||
@ -166,6 +166,44 @@ G_DEFINE_TYPE_WITH_CODE (GtkScale, gtk_scale, GTK_TYPE_RANGE,
|
|||||||
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
|
G_IMPLEMENT_INTERFACE (GTK_TYPE_BUILDABLE,
|
||||||
gtk_scale_buildable_interface_init))
|
gtk_scale_buildable_interface_init))
|
||||||
|
|
||||||
|
static gint
|
||||||
|
compare_marks (gconstpointer a, gconstpointer b, gpointer data)
|
||||||
|
{
|
||||||
|
gboolean inverted = GPOINTER_TO_INT (data);
|
||||||
|
gint val;
|
||||||
|
const GtkScaleMark *ma, *mb;
|
||||||
|
|
||||||
|
val = inverted ? -1 : 1;
|
||||||
|
|
||||||
|
ma = a; mb = b;
|
||||||
|
|
||||||
|
return (ma->value > mb->value) ? val : ((ma->value < mb->value) ? -val : 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
gtk_scale_notify (GObject *object,
|
||||||
|
GParamSpec *pspec)
|
||||||
|
{
|
||||||
|
if (strcmp (pspec->name, "orientation") == 0)
|
||||||
|
{
|
||||||
|
GtkOrientation orientation;
|
||||||
|
|
||||||
|
orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (object));
|
||||||
|
gtk_range_set_flippable (GTK_RANGE (object),
|
||||||
|
orientation == GTK_ORIENTATION_HORIZONTAL);
|
||||||
|
}
|
||||||
|
else if (strcmp (pspec->name, "inverted") == 0)
|
||||||
|
{
|
||||||
|
GtkScale *scale = GTK_SCALE (object);
|
||||||
|
|
||||||
|
scale->priv->marks = g_slist_sort_with_data (scale->priv->marks,
|
||||||
|
compare_marks,
|
||||||
|
GINT_TO_POINTER (gtk_range_get_inverted (GTK_RANGE (scale))));
|
||||||
|
}
|
||||||
|
else if (G_OBJECT_CLASS (gtk_scale_parent_class)->notify)
|
||||||
|
G_OBJECT_CLASS (gtk_scale_parent_class)->notify (object, pspec);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
#define add_slider_binding(binding_set, keyval, mask, scroll) \
|
#define add_slider_binding(binding_set, keyval, mask, scroll) \
|
||||||
gtk_binding_entry_add_signal (binding_set, keyval, mask, \
|
gtk_binding_entry_add_signal (binding_set, keyval, mask, \
|
||||||
@ -186,6 +224,7 @@ gtk_scale_class_init (GtkScaleClass *class)
|
|||||||
|
|
||||||
gobject_class->set_property = gtk_scale_set_property;
|
gobject_class->set_property = gtk_scale_set_property;
|
||||||
gobject_class->get_property = gtk_scale_get_property;
|
gobject_class->get_property = gtk_scale_get_property;
|
||||||
|
gobject_class->notify = gtk_scale_notify;
|
||||||
gobject_class->finalize = gtk_scale_finalize;
|
gobject_class->finalize = gtk_scale_finalize;
|
||||||
|
|
||||||
widget_class->style_updated = gtk_scale_style_updated;
|
widget_class->style_updated = gtk_scale_style_updated;
|
||||||
@ -408,17 +447,6 @@ gtk_scale_class_init (GtkScaleClass *class)
|
|||||||
gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_SCALE_ACCESSIBLE);
|
gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_SCALE_ACCESSIBLE);
|
||||||
}
|
}
|
||||||
|
|
||||||
static void
|
|
||||||
gtk_scale_orientation_notify (GtkRange *range,
|
|
||||||
const GParamSpec *pspec)
|
|
||||||
{
|
|
||||||
GtkOrientation orientation;
|
|
||||||
|
|
||||||
orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (range));
|
|
||||||
gtk_range_set_flippable (range,
|
|
||||||
orientation == GTK_ORIENTATION_HORIZONTAL);
|
|
||||||
}
|
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gtk_scale_init (GtkScale *scale)
|
gtk_scale_init (GtkScale *scale)
|
||||||
{
|
{
|
||||||
@ -442,10 +470,8 @@ gtk_scale_init (GtkScale *scale)
|
|||||||
priv->digits = 1;
|
priv->digits = 1;
|
||||||
gtk_range_set_round_digits (range, priv->digits);
|
gtk_range_set_round_digits (range, priv->digits);
|
||||||
|
|
||||||
gtk_scale_orientation_notify (range, NULL);
|
gtk_range_set_flippable (range,
|
||||||
g_signal_connect (scale, "notify::orientation",
|
gtk_orientable_get_orientation (GTK_ORIENTABLE (range))== GTK_ORIENTATION_HORIZONTAL);
|
||||||
G_CALLBACK (gtk_scale_orientation_notify),
|
|
||||||
NULL);
|
|
||||||
|
|
||||||
context = gtk_widget_get_style_context (GTK_WIDGET (scale));
|
context = gtk_widget_get_style_context (GTK_WIDGET (scale));
|
||||||
gtk_style_context_add_class (context, GTK_STYLE_CLASS_SCALE);
|
gtk_style_context_add_class (context, GTK_STYLE_CLASS_SCALE);
|
||||||
@ -930,7 +956,7 @@ gtk_scale_get_mark_label_size (GtkScale *scale,
|
|||||||
GtkScalePrivate *priv = scale->priv;
|
GtkScalePrivate *priv = scale->priv;
|
||||||
PangoLayout *layout;
|
PangoLayout *layout;
|
||||||
PangoRectangle logical_rect;
|
PangoRectangle logical_rect;
|
||||||
GList *m;
|
GSList *m;
|
||||||
gint w, h;
|
gint w, h;
|
||||||
|
|
||||||
*count1 = *count2 = 0;
|
*count1 = *count2 = 0;
|
||||||
@ -1054,12 +1080,12 @@ gtk_scale_get_preferred_height (GtkWidget *widget,
|
|||||||
|
|
||||||
static gint
|
static gint
|
||||||
find_next_pos (GtkWidget *widget,
|
find_next_pos (GtkWidget *widget,
|
||||||
GList *list,
|
GSList *list,
|
||||||
gint *marks,
|
gint *marks,
|
||||||
GtkPositionType pos)
|
GtkPositionType pos)
|
||||||
{
|
{
|
||||||
GtkAllocation allocation;
|
GtkAllocation allocation;
|
||||||
GList *m;
|
GSList *m;
|
||||||
gint i;
|
gint i;
|
||||||
|
|
||||||
for (m = list->next, i = 1; m; m = m->next, i++)
|
for (m = list->next, i = 1; m; m = m->next, i++)
|
||||||
@ -1111,12 +1137,27 @@ gtk_scale_draw (GtkWidget *widget,
|
|||||||
gint x1, x2, x3, y1, y2, y3;
|
gint x1, x2, x3, y1, y2, y3;
|
||||||
PangoLayout *layout;
|
PangoLayout *layout;
|
||||||
PangoRectangle logical_rect;
|
PangoRectangle logical_rect;
|
||||||
GList *m;
|
GSList *m;
|
||||||
gint min_pos_before, min_pos_after;
|
gint min_pos_before, min_pos_after;
|
||||||
gint min_pos, max_pos;
|
gint min_pos, max_pos;
|
||||||
|
gint n_marks;
|
||||||
|
|
||||||
orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (range));
|
orientation = gtk_orientable_get_orientation (GTK_ORIENTABLE (range));
|
||||||
_gtk_range_get_stop_positions (range, &marks);
|
n_marks = _gtk_range_get_stop_positions (range, &marks);
|
||||||
|
/* We always draw the marks in increasing direction, so flip
|
||||||
|
* the stop positions to match the marks (which we flip in
|
||||||
|
* gtk_scale_notify)
|
||||||
|
*/
|
||||||
|
if (gtk_range_get_inverted (range))
|
||||||
|
{
|
||||||
|
for (i = 0; i < n_marks / 2; i++)
|
||||||
|
{
|
||||||
|
x1 = marks[i];
|
||||||
|
marks[i] = marks[n_marks - 1 - i];
|
||||||
|
marks[n_marks - 1 - i] = x1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
layout = gtk_widget_create_pango_layout (widget, NULL);
|
layout = gtk_widget_create_pango_layout (widget, NULL);
|
||||||
gtk_range_get_range_rect (range, &range_rect);
|
gtk_range_get_range_rect (range, &range_rect);
|
||||||
|
|
||||||
@ -1484,8 +1525,10 @@ _gtk_scale_clear_layout (GtkScale *scale)
|
|||||||
}
|
}
|
||||||
|
|
||||||
static void
|
static void
|
||||||
gtk_scale_mark_free (GtkScaleMark *mark)
|
gtk_scale_mark_free (gpointer data)
|
||||||
{
|
{
|
||||||
|
GtkScaleMark *mark = data;
|
||||||
|
|
||||||
g_free (mark->markup);
|
g_free (mark->markup);
|
||||||
g_free (mark);
|
g_free (mark);
|
||||||
}
|
}
|
||||||
@ -1508,8 +1551,7 @@ gtk_scale_clear_marks (GtkScale *scale)
|
|||||||
|
|
||||||
priv = scale->priv;
|
priv = scale->priv;
|
||||||
|
|
||||||
g_list_foreach (priv->marks, (GFunc)gtk_scale_mark_free, NULL);
|
g_slist_free_full (priv->marks, gtk_scale_mark_free);
|
||||||
g_list_free (priv->marks);
|
|
||||||
priv->marks = NULL;
|
priv->marks = NULL;
|
||||||
|
|
||||||
context = gtk_widget_get_style_context (GTK_WIDGET (scale));
|
context = gtk_widget_get_style_context (GTK_WIDGET (scale));
|
||||||
@ -1521,16 +1563,6 @@ gtk_scale_clear_marks (GtkScale *scale)
|
|||||||
gtk_widget_queue_resize (GTK_WIDGET (scale));
|
gtk_widget_queue_resize (GTK_WIDGET (scale));
|
||||||
}
|
}
|
||||||
|
|
||||||
static gint
|
|
||||||
compare_marks (gpointer a, gpointer b)
|
|
||||||
{
|
|
||||||
GtkScaleMark *ma, *mb;
|
|
||||||
|
|
||||||
ma = a; mb = b;
|
|
||||||
|
|
||||||
return (ma->value > mb->value) ? 1 : ((ma->value < mb->value) ? -1 : 0);
|
|
||||||
}
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* gtk_scale_add_mark:
|
* gtk_scale_add_mark:
|
||||||
* @scale: a #GtkScale
|
* @scale: a #GtkScale
|
||||||
@ -1563,7 +1595,7 @@ gtk_scale_add_mark (GtkScale *scale,
|
|||||||
{
|
{
|
||||||
GtkScalePrivate *priv;
|
GtkScalePrivate *priv;
|
||||||
GtkScaleMark *mark;
|
GtkScaleMark *mark;
|
||||||
GList *m;
|
GSList *m;
|
||||||
gdouble *values;
|
gdouble *values;
|
||||||
gint n, i;
|
gint n, i;
|
||||||
GtkStyleContext *context;
|
GtkStyleContext *context;
|
||||||
@ -1582,14 +1614,14 @@ gtk_scale_add_mark (GtkScale *scale,
|
|||||||
else
|
else
|
||||||
mark->position = GTK_POS_BOTTOM;
|
mark->position = GTK_POS_BOTTOM;
|
||||||
|
|
||||||
priv->marks = g_list_insert_sorted (priv->marks, mark,
|
priv->marks = g_slist_insert_sorted (priv->marks, mark,
|
||||||
(GCompareFunc) compare_marks);
|
(GCompareFunc) compare_marks);
|
||||||
|
|
||||||
#define MARKS_ABOVE 1
|
#define MARKS_ABOVE 1
|
||||||
#define MARKS_BELOW 2
|
#define MARKS_BELOW 2
|
||||||
|
|
||||||
all_pos = 0;
|
all_pos = 0;
|
||||||
n = g_list_length (priv->marks);
|
n = g_slist_length (priv->marks);
|
||||||
values = g_new (gdouble, n);
|
values = g_new (gdouble, n);
|
||||||
for (m = priv->marks, i = 0; m; m = m->next, i++)
|
for (m = priv->marks, i = 0; m; m = m->next, i++)
|
||||||
{
|
{
|
||||||
@ -1636,7 +1668,7 @@ typedef struct
|
|||||||
{
|
{
|
||||||
GtkScale *scale;
|
GtkScale *scale;
|
||||||
GtkBuilder *builder;
|
GtkBuilder *builder;
|
||||||
GList *marks;
|
GSList *marks;
|
||||||
} MarksSubparserData;
|
} MarksSubparserData;
|
||||||
|
|
||||||
typedef struct
|
typedef struct
|
||||||
@ -1752,7 +1784,7 @@ marks_start_element (GMarkupParseContext *context,
|
|||||||
mark->context = g_strdup (msg_context);
|
mark->context = g_strdup (msg_context);
|
||||||
mark->translatable = translatable;
|
mark->translatable = translatable;
|
||||||
|
|
||||||
parser_data->marks = g_list_prepend (parser_data->marks, mark);
|
parser_data->marks = g_slist_prepend (parser_data->marks, mark);
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1834,7 +1866,7 @@ gtk_scale_buildable_custom_finished (GtkBuildable *buildable,
|
|||||||
|
|
||||||
if (strcmp (tagname, "marks") == 0)
|
if (strcmp (tagname, "marks") == 0)
|
||||||
{
|
{
|
||||||
GList *m;
|
GSList *m;
|
||||||
gchar *markup;
|
gchar *markup;
|
||||||
|
|
||||||
marks_data = (MarksSubparserData *)user_data;
|
marks_data = (MarksSubparserData *)user_data;
|
||||||
@ -1855,7 +1887,7 @@ gtk_scale_buildable_custom_finished (GtkBuildable *buildable,
|
|||||||
mark_data_free (mdata);
|
mark_data_free (mdata);
|
||||||
}
|
}
|
||||||
|
|
||||||
g_list_free (marks_data->marks);
|
g_slist_free (marks_data->marks);
|
||||||
g_slice_free (MarksSubparserData, marks_data);
|
g_slice_free (MarksSubparserData, marks_data);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|||||||
Reference in New Issue
Block a user