enum {
PROP_0,
PROP_UPDATE_POLICY,
- PROP_ADJUSTMENT
+ PROP_ADJUSTMENT,
+ PROP_INVERTED
};
enum {
gint grab_button; /* 0 if none */
};
+
static void gtk_range_class_init (GtkRangeClass *klass);
static void gtk_range_init (GtkRange *range);
static void gtk_range_set_property (GObject *object,
GdkEventScroll *event);
static void gtk_range_style_set (GtkWidget *widget,
GtkStyle *previous_style);
+static void update_slider_position (GtkRange *range,
+ gint mouse_x,
+ gint mouse_y);
/* Range methods */
static void gtk_range_scroll (GtkRange *range,
GtkScrollType scroll);
static gboolean gtk_range_update_mouse_location (GtkRange *range);
-static void gtk_range_calc_layout (GtkRange *range);
+static void gtk_range_calc_layout (GtkRange *range,
+ gdouble adjustment_value);
static void gtk_range_get_props (GtkRange *range,
gint *slider_width,
gint *stepper_size,
class->stepper_detail = "stepper";
signals[VALUE_CHANGED] =
- g_signal_newc ("value_changed",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST,
- G_STRUCT_OFFSET (GtkRangeClass, value_changed),
- NULL, NULL,
- gtk_marshal_NONE__NONE,
- G_TYPE_NONE, 0);
+ g_signal_new ("value_changed",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (GtkRangeClass, value_changed),
+ NULL, NULL,
+ gtk_marshal_NONE__NONE,
+ G_TYPE_NONE, 0);
signals[MOVE_SLIDER] =
- g_signal_newc ("move_slider",
- G_TYPE_FROM_CLASS (object_class),
- G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
- G_STRUCT_OFFSET (GtkRangeClass, move_slider),
- NULL, NULL,
- gtk_marshal_VOID__ENUM,
- G_TYPE_NONE, 1,
- GTK_TYPE_SCROLL_TYPE);
-
+ g_signal_new ("move_slider",
+ G_TYPE_FROM_CLASS (object_class),
+ G_SIGNAL_RUN_LAST | G_SIGNAL_ACTION,
+ G_STRUCT_OFFSET (GtkRangeClass, move_slider),
+ NULL, NULL,
+ gtk_marshal_VOID__ENUM,
+ G_TYPE_NONE, 1,
+ GTK_TYPE_SCROLL_TYPE);
+
g_object_class_install_property (gobject_class,
PROP_UPDATE_POLICY,
_("Adjustment"),
_("The GtkAdjustment that contains the current value of this range object"),
GTK_TYPE_ADJUSTMENT,
- G_PARAM_READWRITE));
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT));
+ g_object_class_install_property (gobject_class,
+ PROP_INVERTED,
+ g_param_spec_boolean ("inverted",
+ _("Inverted"),
+ _("Invert direction slider moves to increase range value"),
+ FALSE,
+ G_PARAM_READWRITE));
+
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("slider_width",
_("Slider Width"),
case PROP_ADJUSTMENT:
gtk_range_set_adjustment (range, g_value_get_object (value));
break;
+ case PROP_INVERTED:
+ gtk_range_set_inverted (range, g_value_get_boolean (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
case PROP_ADJUSTMENT:
g_value_set_object (value, G_OBJECT (range->adjustment));
break;
+ case PROP_INVERTED:
+ g_value_set_boolean (value, range->inverted);
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
GtkAdjustment*
gtk_range_get_adjustment (GtkRange *range)
{
- g_return_val_if_fail (range != NULL, NULL);
g_return_val_if_fail (GTK_IS_RANGE (range), NULL);
if (!range->adjustment)
gtk_range_set_update_policy (GtkRange *range,
GtkUpdateType policy)
{
- g_return_if_fail (range != NULL);
g_return_if_fail (GTK_IS_RANGE (range));
if (range->update_policy != policy)
}
}
+/**
+ * gtk_range_get_update_policy:
+ * @range: a #GtkRange
+ *
+ * Gets the update policy of @range. See gtk_range_set_update_policy().
+ *
+ * Return value: the current update policy
+ **/
+GtkUpdateType
+gtk_range_get_update_policy (GtkRange *range)
+{
+ g_return_val_if_fail (GTK_IS_RANGE (range), GTK_UPDATE_CONTINUOUS);
+
+ return range->update_policy;
+}
+
/**
* gtk_range_set_adjustment:
* @range: a #GtkRange
gtk_range_set_adjustment (GtkRange *range,
GtkAdjustment *adjustment)
{
- g_return_if_fail (range != NULL);
g_return_if_fail (GTK_IS_RANGE (range));
if (!adjustment)
if (setting != range->inverted)
{
range->inverted = setting;
+ g_object_notify (G_OBJECT (range), "inverted");
gtk_widget_queue_resize (GTK_WIDGET (range));
}
}
range = GTK_RANGE (widget);
range->need_recalc = TRUE;
- gtk_range_calc_layout (range);
+ gtk_range_calc_layout (range, range->adjustment->value);
(* GTK_WIDGET_CLASS (parent_class)->size_allocate) (widget, allocation);
}
range = GTK_RANGE (widget);
- gtk_range_calc_layout (range);
+ gtk_range_calc_layout (range, range->adjustment->value);
GTK_WIDGET_SET_FLAGS (widget, GTK_REALIZED);
{
GtkRange *range;
- g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_RANGE (widget));
range = GTK_RANGE (widget);
GtkStateType state;
GdkRectangle area;
- g_return_val_if_fail (widget != NULL, FALSE);
g_return_val_if_fail (GTK_IS_RANGE (widget), FALSE);
g_return_val_if_fail (event != NULL, FALSE);
range = GTK_RANGE (widget);
- gtk_range_calc_layout (range);
+ gtk_range_calc_layout (range, range->adjustment->value);
sensitive = GTK_WIDGET_IS_SENSITIVE (widget);
gdouble value;
if (range->orientation == GTK_ORIENTATION_VERTICAL)
- frac = ((coord - range->layout->trough.y) /
- (gdouble) (range->layout->trough.height - range->layout->slider.height));
+ if (range->layout->trough.height == range->layout->slider.height)
+ frac = 1.0;
+ else
+ frac = ((coord - range->layout->trough.y) /
+ (gdouble) (range->layout->trough.height - range->layout->slider.height));
else
- frac = ((coord - range->layout->trough.x) /
- (gdouble) (range->layout->trough.width - range->layout->slider.width));
+ if (range->layout->trough.width == range->layout->slider.width)
+ frac = 1.0;
+ else
+ frac = ((coord - range->layout->trough.x) /
+ (gdouble) (range->layout->trough.width - range->layout->slider.width));
if (should_invert (range))
frac = 1.0 - frac;
event->button == 2) ||
range->layout->mouse_location == MOUSE_SLIDER)
{
+ gboolean need_value_update = FALSE;
+
/* Any button can be used to drag the slider, but you can start
* dragging the slider with a trough click using button 2;
* On button 2 press, we warp the slider to mouse position,
*/
if (event->button == 2)
{
- gdouble slider_low_value, slider_high_value;
+ gdouble slider_low_value, slider_high_value, new_value;
slider_high_value =
coord_to_value (range,
event->y - range->layout->slider.height :
event->x - range->layout->slider.width);
- /* middle button jumps to point */
- gtk_range_internal_set_value (range,
- slider_low_value + (slider_high_value - slider_low_value) / 2);
+ /* compute new value for warped slider */
+ new_value = slider_low_value + (slider_high_value - slider_low_value) / 2;
- /* Calc layout so we can set slide_initial_slider_position
+ /* recalc slider, so we can set slide_initial_slider_position
* properly
*/
- gtk_range_calc_layout (range);
+ range->need_recalc = TRUE;
+ gtk_range_calc_layout (range, new_value);
+
+ /* defer adjustment updates to update_slider_position() in order
+ * to keep pixel quantisation
+ */
+ need_value_update = TRUE;
}
if (range->orientation == GTK_ORIENTATION_VERTICAL)
range->slide_initial_coordinate = event->x;
}
+ if (need_value_update)
+ update_slider_position (range, event->x, event->y);
+
range_grab_add (range, MOUSE_SLIDER, event->button);
return TRUE;
gtk_widget_queue_draw (widget);
if (range->layout->grab_location == MOUSE_SLIDER)
- update_slider_position (range, event->x, event->y);
+ update_slider_position (range, x, y);
/* We handled the event if the mouse was in the range_rect */
return range->layout->mouse_location != MOUSE_OUTSIDE;
{
GtkRange *range;
- g_return_if_fail (widget != NULL);
g_return_if_fail (GTK_IS_RANGE (widget));
range = GTK_RANGE (widget);
}
static void
-gtk_range_calc_layout (GtkRange *range)
+gtk_range_calc_layout (GtkRange *range,
+ gdouble adjustment_value)
{
gint slider_width, stepper_size, trough_border, stepper_spacing;
gint slider_length;
y = top;
- y += (bottom - top - height) * ((range->adjustment->value - range->adjustment->lower) /
+ y += (bottom - top - height) * ((adjustment_value - range->adjustment->lower) /
(range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size));
y = CLAMP (y, top, bottom);
x = left;
- x += (right - left - width) * ((range->adjustment->value - range->adjustment->lower) /
+ x += (right - left - width) * ((adjustment_value - range->adjustment->lower) /
(range->adjustment->upper - range->adjustment->lower - range->adjustment->page_size));
x = CLAMP (x, left, right);
{
GtkRange *range;
+ GDK_THREADS_ENTER ();
range = GTK_RANGE (data);
-
gtk_range_scroll (range, range->timer->step);
+ GDK_THREADS_LEAVE ();
return TRUE;
}
{
GtkRange *range;
+ GDK_THREADS_ENTER ();
range = GTK_RANGE (data);
-
range->timer->timeout_id =
g_timeout_add (SCROLL_LATER_DELAY,
second_timeout,
range);
+ GDK_THREADS_LEAVE ();
/* remove self */
return FALSE;
{
GtkRange *range;
+ GDK_THREADS_ENTER ();
range = GTK_RANGE (data);
-
gtk_range_update_value (range);
-
range->update_timeout_id = 0;
+ GDK_THREADS_LEAVE ();
/* self-remove */
return FALSE;