#include <stdio.h>
#include <math.h>
-#include "gtkmainprivate.h"
+#include "gtkmain.h"
#include "gtkmarshalers.h"
-#include "gtkorientable.h"
+#include "gtkorientableprivate.h"
#include "gtkrange.h"
#include "gtkscale.h"
#include "gtkscrollbar.h"
#include "gtkwindow.h"
#include "gtkprivate.h"
#include "gtkintl.h"
+#include "gtkmain.h"
#include "gtktypebuiltins.h"
+#include "a11y/gtkrangeaccessible.h"
/**
* SECTION:gtkrange
gint mouse_x;
gint mouse_y;
MouseLocation grab_location; /* "grabbed" mouse location, OUTSIDE for no grab */
- guint grab_button : 8; /* 0 if none */
GtkRangeStepTimer *timer;
GtkAdjustment *adjustment;
- GtkOrientation orientation;
GtkSensitivityType lower_sensitivity;
GtkSensitivityType upper_sensitivity;
GQuark slider_detail_quark;
GQuark stepper_detail_quark[4];
- gboolean recalc_marks;
+ GtkOrientation orientation;
gdouble fill_level;
gdouble *marks;
guint flippable : 1;
guint inverted : 1;
guint need_recalc : 1;
+ guint recalc_marks : 1;
guint slider_size_fixed : 1;
guint trough_click_forward : 1; /* trough click was on the forward side of slider */
guint lower_sensitive : 1;
guint upper_sensitive : 1;
+ /* The range has an origin, should be drawn differently. Used by GtkScale */
+ guint has_origin : 1;
+
/* Fill level */
guint show_fill_level : 1;
guint restrict_to_fill_level : 1;
+
+ guint grab_button : 8; /* 0 if none */
};
PROP_UPPER_STEPPER_SENSITIVITY,
PROP_SHOW_FILL_LEVEL,
PROP_RESTRICT_TO_FILL_LEVEL,
- PROP_FILL_LEVEL
+ PROP_FILL_LEVEL,
+ PROP_ROUND_DIGITS
};
enum {
* @range: the #GtkRange that received the signal
* @scroll: the type of scroll action that was performed
* @value: the new value resulting from the scroll action
- * @returns: %TRUE to prevent other handlers from being invoked for the
- * signal, %FALSE to propagate the signal further
*
- * The ::change-value signal is emitted when a scroll action is
+ * The #GtkRange::change-value signal is emitted when a scroll action is
* performed on a range. It allows an application to determine the
* type of scroll event that occurred and the resultant new value.
* The application can handle the event itself and return %TRUE to
* reached.
*
* The value parameter is unrounded. An application that overrides
- * the ::change-value signal is responsible for clamping the value to
- * the desired number of decimal digits; the default GTK+ handler
- * clamps the value based on @range->round_digits.
+ * the GtkRange::change-value signal is responsible for clamping the
+ * value to the desired number of decimal digits; the default GTK+
+ * handler clamps the value based on #GtkRange:round-digits.
*
* It is not possible to use delayed update policies in an overridden
- * ::change-value handler.
+ * #GtkRange::change-value handler.
+ *
+ * Returns: %TRUE to prevent other handlers from being invoked for
+ * the signal, %FALSE to propagate the signal further
*
* Since: 2.6
*/
G_MAXDOUBLE,
GTK_PARAM_READWRITE));
+ /**
+ * GtkRange:round-digits:
+ *
+ * The number of digits to round the value to when
+ * it changes, or -1. See #GtkRange::change-value.
+ *
+ * Since: 2.24
+ */
+ g_object_class_install_property (gobject_class,
+ PROP_ROUND_DIGITS,
+ g_param_spec_int ("round-digits",
+ P_("Round Digits"),
+ P_("The number of digits to round the value to."),
+ -1,
+ G_MAXINT,
+ -1,
+ GTK_PARAM_READWRITE));
+
gtk_widget_class_install_style_property (widget_class,
g_param_spec_int ("slider-width",
P_("Slider Width"),
* GtkRange:stepper-spacing:
*
* The spacing between the stepper buttons and thumb. Note that
- * setting this value to anything > 0 will automatically set the
- * trough-under-steppers style property to %TRUE as well. Also,
* stepper-spacing won't have any effect if there are no steppers.
*/
gtk_widget_class_install_style_property (widget_class,
* GtkRange:trough-under-steppers:
*
* Whether to draw the trough across the full length of the range or
- * to exclude the steppers and their spacing. Note that setting the
- * #GtkRange:stepper-spacing style property to any value > 0 will
- * automatically enable trough-under-steppers too.
+ * to exclude the steppers and their spacing.
*
* Since: 2.10
*/
GTK_PARAM_READABLE));
g_type_class_add_private (class, sizeof (GtkRangePrivate));
+
+ gtk_widget_class_set_accessible_type (widget_class, GTK_TYPE_RANGE_ACCESSIBLE);
}
static void
priv->stepper_detail_quark[2] = 0;
priv->stepper_detail_quark[3] = 0;
+ _gtk_orientable_set_style_classes (GTK_ORIENTABLE (range));
gtk_widget_queue_resize (GTK_WIDGET (range));
break;
case PROP_ADJUSTMENT:
case PROP_FILL_LEVEL:
gtk_range_set_fill_level (range, g_value_get_double (value));
break;
+ case PROP_ROUND_DIGITS:
+ gtk_range_set_round_digits (range, g_value_get_int (value));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
case PROP_FILL_LEVEL:
g_value_set_double (value, gtk_range_get_fill_level (range));
break;
+ case PROP_ROUND_DIGITS:
+ g_value_set_int (value, gtk_range_get_round_digits (range));
+ break;
default:
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
break;
priv->upper_sensitivity = GTK_SENSITIVITY_AUTO;
priv->lower_sensitive = TRUE;
priv->upper_sensitive = TRUE;
+ priv->has_origin = FALSE;
priv->show_fill_level = FALSE;
priv->restrict_to_fill_level = TRUE;
priv->fill_level = G_MAXDOUBLE;
* @size_fixed: %TRUE to make the slider size constant
*
* Sets whether the range's slider has a fixed size, or a size that
- * depends on it's adjustment's page size.
+ * depends on its adjustment's page size.
*
* This function is useful mainly for #GtkRange subclasses.
*
/**
* gtk_range_get_range_rect:
* @range: a #GtkRange
- * @range_rect: return location for the range rectangle
+ * @range_rect: (out): return location for the range rectangle
*
* This function returns the area that contains the range's trough
* and its steppers, in widget->window coordinates.
/**
* gtk_range_get_slider_range:
* @range: a #GtkRange
- * @slider_start: (allow-none): return location for the slider's start, or %NULL
- * @slider_end: (allow-none): return location for the slider's end, or %NULL
+ * @slider_start: (out) (allow-none): return location for the slider's
+ * start, or %NULL
+ * @slider_end: (out) (allow-none): return location for the slider's
+ * end, or %NULL
*
* This function returns sliders range along the long dimension,
* in widget->window coordinates.
translated_rect = *allocation;
else
{
- gtk_widget_translate_coordinates (gtk_widget_get_parent (widget),
+ gtk_widget_translate_coordinates (parent,
window,
allocation->x, allocation->y,
&x, &y);
G_CALLBACK (resize_grip_visible_changed),
widget);
window = gtk_widget_get_toplevel (widget);
- if (GTK_IS_WINDOW (window))
+ if (gtk_widget_is_toplevel (window))
g_signal_connect (window, "notify::resize-grip-visible",
G_CALLBACK (resize_grip_visible_changed), widget);
}
}
gtk_style_context_set_junction_sides (context, sides);
- gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON);
}
static void
cairo_t *cr,
GtkArrowType arrow_type,
gboolean clicked,
- gboolean prelighted)
+ gboolean prelighted,
+ GtkStateFlags state)
{
GtkRangePrivate *priv = range->priv;
GtkAllocation allocation;
- GtkStateFlags state = 0;
GtkStyleContext *context;
GtkWidget *widget = GTK_WIDGET (range);
- GdkWindow *window;
gfloat arrow_scaling;
GdkRectangle *rect;
- gint arrow_x;
- gint arrow_y;
+ gdouble arrow_x;
+ gdouble arrow_y;
gdouble arrow_size, angle;
gboolean arrow_sensitive;
arrow_sensitive = priv->lower_sensitive;
}
- if (!gtk_widget_is_sensitive (GTK_WIDGET (range)) || !arrow_sensitive)
- state = GTK_STATE_FLAG_INSENSITIVE;
+ state &= ~(GTK_STATE_FLAG_ACTIVE | GTK_STATE_FLAG_PRELIGHT);
+
+ if ((state & GTK_STATE_FLAG_INSENSITIVE) || !arrow_sensitive)
+ {
+ state |= GTK_STATE_FLAG_INSENSITIVE;
+ }
else
{
if (clicked)
state |= GTK_STATE_FLAG_PRELIGHT;
}
- window = gtk_widget_get_window (widget);
context = gtk_widget_get_style_context (widget);
gtk_style_context_save (context);
- _gtk_range_update_context_for_stepper (range, context, stepper);
+
+ /* don't set juction sides on scrollbar steppers */
+ if (gtk_style_context_has_class (context, GTK_STYLE_CLASS_SCROLLBAR))
+ gtk_style_context_set_junction_sides (context, GTK_JUNCTION_NONE);
+ else
+ _gtk_range_update_context_for_stepper (range, context, stepper);
+
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_BUTTON);
gtk_style_context_set_state (context, state);
+ switch (arrow_type)
+ {
+ case GTK_ARROW_RIGHT:
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_RIGHT);
+ break;
+ case GTK_ARROW_DOWN:
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_BOTTOM);
+ break;
+ case GTK_ARROW_LEFT:
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_LEFT);
+ break;
+ case GTK_ARROW_UP:
+ default:
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOP);
+ break;
+ }
+
gtk_render_background (context, cr,
rect->x, rect->y,
rect->width, rect->height);
gtk_range_get_props (GTK_RANGE (widget),
NULL, NULL, NULL, NULL, NULL, NULL,
- &arrow_displacement_x, &arrow_displacement_y);
-
+ &arrow_displacement_x, &arrow_displacement_y);
+
arrow_x += arrow_displacement_x;
arrow_y += arrow_displacement_y;
}
}
static gboolean
-gtk_range_draw (GtkWidget *widget,
- cairo_t *cr)
+gtk_range_draw (GtkWidget *widget,
+ cairo_t *cr)
{
GtkRange *range = GTK_RANGE (widget);
GtkRangePrivate *priv = range->priv;
- gboolean sensitive;
- GtkStateFlags state = 0;
- GdkWindow *window;
+ GtkStateFlags widget_state;
gint focus_line_width = 0;
gint focus_padding = 0;
gboolean touchscreen;
"focus-padding", &focus_padding,
NULL);
- window = gtk_widget_get_window (widget);
-
/* we're now exposing, so there's no need to force early repaints */
if (priv->repaint_id)
g_source_remove (priv->repaint_id);
gtk_range_calc_marks (range);
gtk_range_calc_layout (range, gtk_adjustment_get_value (priv->adjustment));
- sensitive = gtk_widget_is_sensitive (widget);
+ widget_state = gtk_widget_get_state_flags (widget);
/* Just to be confusing, we draw the trough for the whole
* range rectangle, not the trough rectangle (the trough
"stepper-spacing", &stepper_spacing,
NULL);
- gtk_style_context_save (context);
-
- if (!sensitive)
- gtk_style_context_set_state (context, GTK_STATE_FLAG_INSENSITIVE);
-
- if (stepper_spacing > 0)
- trough_under_steppers = FALSE;
-
if (!trough_under_steppers)
{
gint offset = 0;
y += offset;
height -= shorter;
}
- }
+ }
gtk_style_context_save (context);
gtk_style_context_add_class (context, GTK_STYLE_CLASS_TROUGH);
if (draw_trough)
{
- gint trough_change_pos_x = width;
- gint trough_change_pos_y = height;
-
- if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
- trough_change_pos_x = (priv->slider.x +
- priv->slider.width / 2 -
- x);
- else
- trough_change_pos_y = (priv->slider.y +
- priv->slider.height / 2 -
- y);
-
- /* FIXME: was trough-upper and trough-lower really used,
- * in that case, it should still be exposed somehow.
- */
- gtk_render_background (context, cr, x, y,
- trough_change_pos_x,
- trough_change_pos_y);
-
- if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
- trough_change_pos_y = 0;
- else
- trough_change_pos_x = 0;
-
- gtk_render_background (context, cr,
- x + trough_change_pos_x, y + trough_change_pos_y,
- width - trough_change_pos_x,
- height - trough_change_pos_y);
+ if (!priv->has_origin)
+ {
+ gtk_render_background (context, cr,
+ x, y, width, height);
- gtk_render_frame (context, cr,
- x, y, width, height);
+ gtk_render_frame (context, cr,
+ x, y, width, height);
+ }
+ else
+ {
+ gboolean is_rtl = gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL;
+
+ gint trough_change_pos_x = width;
+ gint trough_change_pos_y = height;
+
+ if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ trough_change_pos_x = (priv->slider.x +
+ priv->slider.width / 2 -
+ x);
+ else
+ trough_change_pos_y = (priv->slider.y +
+ priv->slider.height / 2 -
+ y);
+
+ gtk_style_context_save (context);
+ if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_LEFT);
+
+ if (!is_rtl)
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_HIGHLIGHT);
+ }
+ else
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_TOP);
+
+ gtk_render_background (context, cr, x, y,
+ trough_change_pos_x,
+ trough_change_pos_y);
+
+ gtk_render_frame (context, cr, x, y,
+ trough_change_pos_x,
+ trough_change_pos_y);
+
+ gtk_style_context_restore (context);
+
+ if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ trough_change_pos_y = 0;
+ else
+ trough_change_pos_x = 0;
+
+ gtk_style_context_save (context);
+ if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_RIGHT);
+
+ if (is_rtl)
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_HIGHLIGHT);
+ }
+ else
+ {
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_BOTTOM);
+ gtk_style_context_add_class (context, GTK_STYLE_CLASS_HIGHLIGHT);
+ }
+
+ gtk_render_background (context, cr,
+ x + trough_change_pos_x, y + trough_change_pos_y,
+ width - trough_change_pos_x,
+ height - trough_change_pos_y);
+
+ gtk_render_frame (context, cr,
+ x + trough_change_pos_x, y + trough_change_pos_y,
+ width - trough_change_pos_x,
+ height - trough_change_pos_y);
+
+ gtk_style_context_restore (context);
+ }
}
else
{
if (priv->show_fill_level &&
gtk_adjustment_get_upper (priv->adjustment) - gtk_adjustment_get_page_size (priv->adjustment) -
gtk_adjustment_get_lower (priv->adjustment) != 0)
- {
+ {
gdouble fill_level = priv->fill_level;
- gint fill_x = x;
- gint fill_y = y;
- gint fill_width = width;
- gint fill_height = height;
- gchar *fill_detail;
+ gint fill_x = x;
+ gint fill_y = y;
+ gint fill_width = width;
+ gint fill_height = height;
gtk_style_context_save (context);
gtk_style_context_add_class (context, GTK_STYLE_CLASS_PROGRESSBAR);
gtk_adjustment_get_upper (priv->adjustment) -
gtk_adjustment_get_page_size (priv->adjustment));
- if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
- {
- fill_x = priv->trough.x;
- fill_width = (priv->slider.width +
+ if (priv->orientation == GTK_ORIENTATION_HORIZONTAL)
+ {
+ fill_x = priv->trough.x;
+ fill_width = (priv->slider.width +
(fill_level - gtk_adjustment_get_lower (priv->adjustment)) /
(gtk_adjustment_get_upper (priv->adjustment) -
gtk_adjustment_get_lower (priv->adjustment) -
if (should_invert (range))
fill_x += priv->trough.width - fill_width;
- }
- else
- {
- fill_y = priv->trough.y;
- fill_height = (priv->slider.height +
+ }
+ else
+ {
+ fill_y = priv->trough.y;
+ fill_height = (priv->slider.height +
(fill_level - gtk_adjustment_get_lower (priv->adjustment)) /
(gtk_adjustment_get_upper (priv->adjustment) -
gtk_adjustment_get_lower (priv->adjustment) -
if (should_invert (range))
fill_y += priv->trough.height - fill_height;
- }
+ }
- if (fill_level < gtk_adjustment_get_upper (priv->adjustment) - gtk_adjustment_get_page_size (priv->adjustment))
- fill_detail = "trough-fill-level-full";
- else
- fill_detail = "trough-fill-level";
+#if 0
+ if (fill_level < gtk_adjustment_get_upper (priv->adjustment) - gtk_adjustment_get_page_size (priv->adjustment))
+ fill_detail = "trough-fill-level-full";
+ else
+ fill_detail = "trough-fill-level";
+#endif
gtk_render_activity (context, cr,
fill_x, fill_y,
fill_width, fill_height);
gtk_style_context_restore (context);
- }
-
- gtk_style_context_restore (context);
+ }
- if (sensitive && gtk_widget_has_focus (widget))
+ if (!(widget_state & GTK_STATE_FLAG_INSENSITIVE) && gtk_widget_has_visible_focus (widget))
{
- gtk_style_context_save (context);
- gtk_style_context_set_state (context,
- gtk_widget_get_state_flags (widget));
-
gtk_render_focus (context, cr,
priv->range_rect.x,
priv->range_rect.y,
priv->range_rect.width,
priv->range_rect.height);
-
- gtk_style_context_restore (context);
}
}
cairo_restore (cr);
- if (!sensitive)
- state = GTK_STATE_FLAG_INSENSITIVE;
- else if (!touchscreen && priv->mouse_location == MOUSE_SLIDER)
- state = GTK_STATE_FLAG_PRELIGHT;
+ if (draw_trough)
+ {
+ GtkStateFlags state = widget_state;
+
+ state &= ~(GTK_STATE_FLAG_PRELIGHT | GTK_STATE_FLAG_ACTIVE);
- if (priv->grab_location == MOUSE_SLIDER)
- state |= GTK_STATE_FLAG_ACTIVE;
+ if (!touchscreen && priv->mouse_location == MOUSE_SLIDER && !(state & GTK_STATE_FLAG_INSENSITIVE))
+ state |= GTK_STATE_FLAG_PRELIGHT;
- cairo_save (cr);
- gdk_cairo_rectangle (cr, &priv->slider);
- cairo_clip (cr);
+ if (priv->grab_location == MOUSE_SLIDER)
+ state |= GTK_STATE_FLAG_ACTIVE;
+
+ cairo_save (cr);
+ gdk_cairo_rectangle (cr, &priv->slider);
+ cairo_clip (cr);
- if (draw_trough)
- {
gtk_style_context_save (context);
gtk_style_context_add_class (context, GTK_STYLE_CLASS_SLIDER);
gtk_style_context_set_state (context, state);
priv->orientation);
gtk_style_context_restore (context);
- }
- cairo_restore (cr);
+ cairo_restore (cr);
+ }
if (priv->has_stepper_a)
draw_stepper (range, STEPPER_A, cr,
priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_UP : GTK_ARROW_LEFT,
priv->grab_location == MOUSE_STEPPER_A,
- !touchscreen && priv->mouse_location == MOUSE_STEPPER_A);
+ !touchscreen && priv->mouse_location == MOUSE_STEPPER_A,
+ widget_state);
if (priv->has_stepper_b)
draw_stepper (range, STEPPER_B, cr,
priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT,
priv->grab_location == MOUSE_STEPPER_B,
- !touchscreen && priv->mouse_location == MOUSE_STEPPER_B);
+ !touchscreen && priv->mouse_location == MOUSE_STEPPER_B,
+ widget_state);
if (priv->has_stepper_c)
draw_stepper (range, STEPPER_C, cr,
priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_UP : GTK_ARROW_LEFT,
priv->grab_location == MOUSE_STEPPER_C,
- !touchscreen && priv->mouse_location == MOUSE_STEPPER_C);
+ !touchscreen && priv->mouse_location == MOUSE_STEPPER_C,
+ widget_state);
if (priv->has_stepper_d)
draw_stepper (range, STEPPER_D, cr,
priv->orientation == GTK_ORIENTATION_VERTICAL ? GTK_ARROW_DOWN : GTK_ARROW_RIGHT,
priv->grab_location == MOUSE_STEPPER_D,
- !touchscreen && priv->mouse_location == MOUSE_STEPPER_D);
-
+ !touchscreen && priv->mouse_location == MOUSE_STEPPER_D,
+ widget_state);
+
return FALSE;
}
181, force_repaint,
range, NULL);
}
-
+
/* Note that we don't round off to priv->round_digits here.
* that's because it's really broken to change a value
* in response to a change signal on that value; round_digits
"arrow-displacement-y", &tmp_arrow_displacement_y,
NULL);
- if (tmp_stepper_spacing > 0)
- tmp_trough_under_steppers = FALSE;
-
if (gtk_widget_get_can_focus (GTK_WIDGET (range)))
{
gint focus_line_width;
}
}
+void
+_gtk_range_set_has_origin (GtkRange *range,
+ gboolean has_origin)
+{
+ range->priv->has_origin = has_origin;
+}
+
+gboolean
+_gtk_range_get_has_origin (GtkRange *range)
+{
+ return range->priv->has_origin;
+}
+
void
_gtk_range_set_stop_values (GtkRange *range,
gdouble *values,
return priv->n_marks;
}
+/**
+ * gtk_range_set_round_digits:
+ * @range: a #GtkRange
+ * @round_digits: the precision in digits, or -1
+ *
+ * Sets the number of digits to round the value to when
+ * it changes. See #GtkRange::change-value.
+ *
+ * Since: 2.24
+ */
void
-_gtk_range_set_round_digits (GtkRange *range,
- gint round_digits)
+gtk_range_set_round_digits (GtkRange *range,
+ gint round_digits)
{
+ g_return_if_fail (GTK_IS_RANGE (range));
+ g_return_if_fail (round_digits >= -1);
+
range->priv->round_digits = round_digits;
+
+ g_object_notify (G_OBJECT (range), "round-digits");
+}
+
+/**
+ * gtk_range_get_round_digits:
+ * @range: a #GtkRange
+ *
+ * Gets the number of digits to round the value to when
+ * it changes. See #GtkRange::change-value.
+ *
+ * Return value: the number of digits to round to
+ *
+ * Since: 2.24
+ */
+gint
+gtk_range_get_round_digits (GtkRange *range)
+{
+ g_return_val_if_fail (GTK_IS_RANGE (range), -1);
+
+ return range->priv->round_digits;
}
void