#include "gtkmain.h"
#include "gtkintl.h"
#include "gtkbindings.h"
+#include "gtkhscale.h"
#include "gtkvscale.h"
#include "gtkframe.h"
#include "gtkvbox.h"
{
PROP_0,
+ PROP_ORIENTATION,
PROP_VALUE,
PROP_SIZE,
PROP_ADJUSTMENT,
GtkWidget *image;
GtkIconSize size;
+ GtkOrientation orientation;
guint click_id;
gint click_timeout;
guint32 pop_time;
gchar **icon_list;
+
+ GtkAdjustment *adjustment; /* needed because it must be settable in init() */
};
+static GObject* gtk_scale_button_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_params);
static void gtk_scale_button_dispose (GObject *object);
static void gtk_scale_button_finalize (GObject *object);
static void gtk_scale_button_set_property (GObject *object,
static void gtk_scale_button_scale_value_changed(GtkRange *range);
/* see below for scale definitions */
-static GtkWidget *gtk_scale_button_scale_new (GtkScaleButton *button,
- gdouble min,
- gdouble max,
- gdouble step);
+static GtkWidget *gtk_scale_button_scale_new (GtkScaleButton *button,
+ gdouble min,
+ gdouble max,
+ gdouble step);
static guint signals[LAST_SIGNAL] = { 0, };
g_type_class_add_private (klass, sizeof (GtkScaleButtonPrivate));
+ gobject_class->constructor = gtk_scale_button_constructor;
gobject_class->finalize = gtk_scale_button_finalize;
gobject_class->dispose = gtk_scale_button_dispose;
gobject_class->set_property = gtk_scale_button_set_property;
widget_class->scroll_event = gtk_scale_button_scroll;
widget_class->screen_changed = gtk_scale_button_screen_changed;
+ g_object_class_install_property (gobject_class,
+ PROP_ORIENTATION,
+ g_param_spec_enum ("orientation",
+ P_("Orientation"),
+ P_("The orientation of the scale"),
+ GTK_TYPE_ORIENTATION,
+ GTK_ORIENTATION_VERTICAL,
+ GTK_PARAM_READWRITE |
+ G_PARAM_CONSTRUCT_ONLY));
+
g_object_class_install_property (gobject_class,
PROP_VALUE,
g_param_spec_double ("value",
static void
gtk_scale_button_init (GtkScaleButton *button)
{
- GtkWidget *frame, *box;
GtkScaleButtonPrivate *priv;
button->priv = priv = GET_PRIVATE (button);
G_CALLBACK (cb_dock_grab_broken_event), button);
gtk_window_set_decorated (GTK_WINDOW (priv->dock), FALSE);
+ /* + */
+ button->plus_button = gtk_button_new_with_label ("+");
+ gtk_button_set_relief (GTK_BUTTON (button->plus_button), GTK_RELIEF_NONE);
+ g_signal_connect (button->plus_button, "button-press-event",
+ G_CALLBACK (cb_button_press), button);
+ g_signal_connect (button->plus_button, "button-release-event",
+ G_CALLBACK (cb_button_release), button);
+
+ /* - */
+ button->minus_button = gtk_button_new_with_label ("-");
+ gtk_button_set_relief (GTK_BUTTON (button->minus_button), GTK_RELIEF_NONE);
+ g_signal_connect (button->minus_button, "button-press-event",
+ G_CALLBACK (cb_button_press), button);
+ g_signal_connect (button->minus_button, "button-release-event",
+ G_CALLBACK (cb_button_release), button);
+
+ priv->adjustment = GTK_ADJUSTMENT (gtk_adjustment_new (0.0, 0.0, 100.0, 2, 20, 0));
+ g_object_ref_sink (priv->adjustment);
+}
+
+static GObject *
+gtk_scale_button_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_params)
+{
+ GObject *object;
+ GtkScaleButton *button;
+ GtkWidget *frame, *box;
+ GtkScaleButtonPrivate *priv;
+
+ object = G_OBJECT_CLASS (gtk_scale_button_parent_class)->constructor (type, n_construct_properties, construct_params);
+
+ button = GTK_SCALE_BUTTON (object);
+
+ priv = button->priv;
+
/* frame */
frame = gtk_frame_new (NULL);
gtk_frame_set_shadow_type (GTK_FRAME (frame), GTK_SHADOW_OUT);
gtk_container_add (GTK_CONTAINER (frame), box);
/* + */
- button->plus_button = gtk_button_new_with_label ("+");
- gtk_button_set_relief (GTK_BUTTON (button->plus_button), GTK_RELIEF_NONE);
- g_signal_connect (button->plus_button, "button-press-event",
- G_CALLBACK (cb_button_press), button);
- g_signal_connect (button->plus_button, "button-release-event",
- G_CALLBACK (cb_button_release), button);
gtk_box_pack_start (GTK_BOX (box), button->plus_button, TRUE, FALSE, 0);
/* scale */
priv->scale = gtk_scale_button_scale_new (button, 0., 100., 2.);
- gtk_widget_set_size_request (priv->scale, -1, SCALE_SIZE);
+ if (priv->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ gtk_widget_set_size_request (priv->scale, -1, SCALE_SIZE);
+ gtk_range_set_inverted (GTK_RANGE (priv->scale), TRUE);
+ }
+ else
+ {
+ gtk_widget_set_size_request (priv->scale, SCALE_SIZE, -1);
+ }
+
gtk_scale_set_draw_value (GTK_SCALE (priv->scale), FALSE);
- gtk_range_set_inverted (GTK_RANGE (priv->scale), TRUE);
gtk_box_pack_start (GTK_BOX (box), priv->scale, TRUE, FALSE, 0);
g_signal_connect (priv->scale, "grab-notify",
G_CALLBACK (cb_scale_grab_notify), button);
/* - */
- button->minus_button = gtk_button_new_with_label ("-");
- gtk_button_set_relief (GTK_BUTTON (button->minus_button), GTK_RELIEF_NONE);
- g_signal_connect (button->minus_button, "button-press-event",
- G_CALLBACK (cb_button_press), button);
- g_signal_connect (button->minus_button, "button-release-event",
- G_CALLBACK (cb_button_release), button);
gtk_box_pack_start (GTK_BOX (box), button->minus_button, TRUE, FALSE, 0);
/* set button text and size */
priv->size = GTK_ICON_SIZE_SMALL_TOOLBAR;
gtk_scale_button_update_icon (button);
+
+ return object;
}
static void
switch (prop_id)
{
+ case PROP_ORIENTATION:
+ button->priv->orientation = g_value_get_enum (value);
+ break;
case PROP_VALUE:
gtk_scale_button_set_value (button, g_value_get_double (value));
break;
switch (prop_id)
{
+ case PROP_ORIENTATION:
+ g_value_set_enum (value, priv->orientation);
+ break;
case PROP_VALUE:
g_value_set_double (value, gtk_scale_button_get_value (button));
break;
priv->icon_list = NULL;
}
+ if (priv->adjustment)
+ {
+ g_object_unref (priv->adjustment);
+ priv->adjustment = NULL;
+ }
+
G_OBJECT_CLASS (gtk_scale_button_parent_class)->finalize (object);
}
priv = button->priv;
- return gtk_range_get_value (GTK_RANGE (priv->scale));
+ return gtk_adjustment_get_value (priv->adjustment);
}
/**
GtkAdjustment*
gtk_scale_button_get_adjustment (GtkScaleButton *button)
{
- GtkRange *range;
-
g_return_val_if_fail (GTK_IS_SCALE_BUTTON (button), NULL);
- range = GTK_RANGE (button->priv->scale);
- g_return_val_if_fail (range != NULL, NULL);
-
- return gtk_range_get_adjustment (range);
+ return button->priv->adjustment;
}
/**
g_return_if_fail (GTK_IS_SCALE_BUTTON (button));
g_return_if_fail (GTK_IS_ADJUSTMENT (adjustment));
- gtk_range_set_adjustment (GTK_RANGE (button->priv->scale),
- adjustment);
+ if (button->priv->adjustment)
+ g_object_unref (button->priv->adjustment);
+ button->priv->adjustment = g_object_ref_sink (adjustment);
+
+ if (button->priv->scale)
+ gtk_range_set_adjustment (GTK_RANGE (button->priv->scale), adjustment);
g_object_notify (G_OBJECT (button), "adjustment");
}
button = GTK_SCALE_BUTTON (widget);
priv = button->priv;
- adj = gtk_range_get_adjustment (GTK_RANGE (priv->scale));
+ adj = priv->adjustment;
if (event->type != GDK_SCROLL)
return FALSE;
GtkScaleButton *button;
GtkScaleButtonPrivate *priv;
GtkAdjustment *adj;
- gint x, y, m, dx, dy, sx, sy, ystartoff;
+ gint x, y, m, dx, dy, sx, sy, startoff;
gdouble v;
GdkDisplay *display;
GdkScreen *screen;
button = GTK_SCALE_BUTTON (widget);
priv = button->priv;
- adj = gtk_range_get_adjustment (GTK_RANGE (priv->scale));
+ adj = priv->adjustment;
display = gtk_widget_get_display (widget);
screen = gtk_widget_get_screen (widget);
gdk_window_get_origin (widget->window, &x, &y);
x += widget->allocation.x;
y += widget->allocation.y;
- gtk_window_move (GTK_WINDOW (priv->dock), x, y - (SCALE_SIZE / 2));
+
+ if (priv->orientation == GTK_ORIENTATION_VERTICAL)
+ gtk_window_move (GTK_WINDOW (priv->dock), x, y - (SCALE_SIZE / 2));
+ else
+ gtk_window_move (GTK_WINDOW (priv->dock), x - (SCALE_SIZE / 2), y);
+
gtk_widget_show_all (priv->dock);
+
gdk_window_get_origin (priv->dock->window, &dx, &dy);
+ dx += priv->dock->allocation.x;
dy += priv->dock->allocation.y;
+
gdk_window_get_origin (priv->scale->window, &sx, &sy);
+ sx += priv->scale->allocation.x;
sy += priv->scale->allocation.y;
- ystartoff = sy - dy;
+
priv->timeout = TRUE;
/* position (needs widget to be shown already) */
v = gtk_scale_button_get_value (button) / (adj->upper - adj->lower);
- x += (widget->allocation.width - priv->dock->allocation.width) / 2;
- y -= ystartoff;
- y -= GTK_RANGE (priv->scale)->min_slider_size / 2;
- m = priv->scale->allocation.height -
- GTK_RANGE (priv->scale)->min_slider_size;
- y -= m * (1.0 - v);
+
+ if (priv->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ startoff = sy - dy;
+
+ x += (widget->allocation.width - priv->dock->allocation.width) / 2;
+ y -= startoff;
+ y -= GTK_RANGE (priv->scale)->min_slider_size / 2;
+ m = priv->scale->allocation.height -
+ GTK_RANGE (priv->scale)->min_slider_size;
+ y -= m * (1.0 - v);
+ }
+ else
+ {
+ startoff = sx - dx;
+
+ x -= startoff;
+ y += (widget->allocation.height - priv->dock->allocation.height) / 2;
+ x -= GTK_RANGE (priv->scale)->min_slider_size / 2;
+ m = priv->scale->allocation.width -
+ GTK_RANGE (priv->scale)->min_slider_size;
+ x -= m * v;
+ }
/* Make sure the dock stays inside the monitor */
if (event->type == GDK_BUTTON_PRESS)
button_event->y_root);
gdk_screen_get_monitor_geometry (screen, monitor, &rect);
- y += button_event->y;
+ if (priv->orientation == GTK_ORIENTATION_VERTICAL)
+ y += button_event->y;
+ else
+ x += button_event->x;
+
if (y < rect.y)
y = rect.y;
else if (y + d->allocation.height > rect.height + rect.y)
/* position: the X position isn't relevant, halfway will work just fine.
* The vertical position should be *exactly* in the middle of the slider
* of the scale; if we don't do that correctly, it'll move from its current
- * position, which means a position change on-click, which is bad. */
- e->x = priv->scale->allocation.width / 2;
- m = priv->scale->allocation.height -
- GTK_RANGE (priv->scale)->min_slider_size;
- e->y = ((1.0 - v) * m) + GTK_RANGE (priv->scale)->min_slider_size / 2;
+ * position, which means a position change on-click, which is bad.
+ */
+ if (priv->orientation == GTK_ORIENTATION_VERTICAL)
+ {
+ e->x = priv->scale->allocation.width / 2;
+ m = priv->scale->allocation.height -
+ GTK_RANGE (priv->scale)->min_slider_size;
+ e->y = ((1.0 - v) * m) + GTK_RANGE (priv->scale)->min_slider_size / 2;
+ }
+ else
+ {
+ e->y = priv->scale->allocation.height / 2;
+ m = priv->scale->allocation.width -
+ GTK_RANGE (priv->scale)->min_slider_size;
+ e->x = (v * m) + GTK_RANGE (priv->scale)->min_slider_size / 2;
+ }
+
gtk_widget_event (priv->scale, (GdkEvent *) e);
e->window = button_event->window;
gdk_event_free ((GdkEvent *) e);
if (priv->click_id == 0)
return FALSE;
- adj = gtk_range_get_adjustment (GTK_RANGE (priv->scale));
+ adj = priv->adjustment;
val = gtk_scale_button_get_value (button);
val += priv->direction;
button = GTK_SCALE_BUTTON (user_data);
priv = button->priv;
- adj = gtk_range_get_adjustment (GTK_RANGE (priv->scale));
+ adj = priv->adjustment;
if (priv->click_id != 0)
g_source_remove (priv->click_id);
* Scale stuff.
*/
-#define GTK_TYPE_SCALE_BUTTON_SCALE \
- (gtk_scale_button_scale_get_type ())
-#define GTK_SCALE_BUTTON_SCALE(obj) \
- (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SCALE_BUTTON_SCALE, \
- GtkScaleButtonScale))
+#define GTK_TYPE_SCALE_BUTTON_VSCALE (gtk_scale_button_vscale_get_type ())
+#define GTK_SCALE_BUTTON_VSCALE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SCALE_BUTTON_VSCALE, GtkScaleButtonVScale))
+#define GTK_IS_SCALE_BUTTON_VSCALE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SCALE_BUTTON_VSCALE))
-typedef struct _GtkScaleButtonScaleClass {
+typedef struct _GtkScaleButtonVScale {
+ GtkVScale parent;
+ GtkScaleButton *button;
+} GtkScaleButtonVScale;
+
+typedef struct _GtkScaleButtonVScaleClass {
GtkVScaleClass parent_class;
-} GtkScaleButtonScaleClass;
+} GtkScaleButtonVScaleClass;
+
+#define GTK_TYPE_SCALE_BUTTON_HSCALE (gtk_scale_button_hscale_get_type ())
+#define GTK_SCALE_BUTTON_HSCALE(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), GTK_TYPE_SCALE_BUTTON_HSCALE, GtkScaleButtonHScale))
+#define GTK_IS_SCALE_BUTTON_HSCALE(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), GTK_TYPE_SCALE_BUTTON_HSCALE))
-typedef struct _GtkScaleButtonScale {
+typedef struct _GtkScaleButtonHScale {
GtkVScale parent;
GtkScaleButton *button;
-} GtkScaleButtonScale;
+} GtkScaleButtonHScale;
-static gboolean gtk_scale_button_scale_press (GtkWidget *widget,
+typedef struct _GtkScaleButtonHScaleClass {
+ GtkVScaleClass parent_class;
+} GtkScaleButtonHScaleClass;
+
+static gboolean gtk_scale_button_scale_press (GtkWidget *widget,
GdkEventButton *event);
static gboolean gtk_scale_button_scale_release (GtkWidget *widget,
GdkEventButton *event);
-G_DEFINE_TYPE (GtkScaleButtonScale, gtk_scale_button_scale, GTK_TYPE_VSCALE)
+G_DEFINE_TYPE (GtkScaleButtonVScale, gtk_scale_button_vscale, GTK_TYPE_VSCALE)
+
+G_DEFINE_TYPE (GtkScaleButtonHScale, gtk_scale_button_hscale, GTK_TYPE_HSCALE)
+
+static void
+gtk_scale_button_vscale_class_init (GtkScaleButtonVScaleClass *klass)
+{
+ GtkWidgetClass *gtkwidget_class = GTK_WIDGET_CLASS (klass);
+ GtkRangeClass *gtkrange_class = GTK_RANGE_CLASS (klass);
+
+ gtkwidget_class->button_press_event = gtk_scale_button_scale_press;
+ gtkwidget_class->button_release_event = gtk_scale_button_scale_release;
+ gtkrange_class->value_changed = gtk_scale_button_scale_value_changed;
+}
static void
-gtk_scale_button_scale_class_init (GtkScaleButtonScaleClass *klass)
+gtk_scale_button_hscale_class_init (GtkScaleButtonHScaleClass *klass)
{
GtkWidgetClass *gtkwidget_class = GTK_WIDGET_CLASS (klass);
GtkRangeClass *gtkrange_class = GTK_RANGE_CLASS (klass);
}
static void
-gtk_scale_button_scale_init (GtkScaleButtonScale *scale)
+gtk_scale_button_vscale_init (GtkScaleButtonVScale *scale)
+{
+}
+
+static void
+gtk_scale_button_hscale_init (GtkScaleButtonHScale *scale)
{
}
static GtkWidget *
gtk_scale_button_scale_new (GtkScaleButton *button,
- gdouble min,
- gdouble max,
- gdouble step)
+ gdouble min,
+ gdouble max,
+ gdouble step)
{
- GtkScaleButtonScale *scale;
- GtkScaleButtonPrivate *priv;
- GtkObject *adj;
+ GtkScaleButtonPrivate *priv = button->priv;
+ GtkScaleButtonVScale *scale;
+
+ if (priv->orientation == GTK_ORIENTATION_VERTICAL)
+ scale = g_object_new (GTK_TYPE_SCALE_BUTTON_VSCALE, NULL);
+ else
+ scale = g_object_new (GTK_TYPE_SCALE_BUTTON_HSCALE, NULL);
+
+ gtk_range_set_adjustment (GTK_RANGE (scale),
+ GTK_ADJUSTMENT (priv->adjustment));
- priv = button->priv;
- scale = g_object_new (GTK_TYPE_SCALE_BUTTON_SCALE, NULL);
- adj = gtk_adjustment_new (min, min, max, step, 10 * step, 0);
- gtk_range_set_adjustment (GTK_RANGE (scale), GTK_ADJUSTMENT (adj));
scale->button = button;
return GTK_WIDGET (scale);
gtk_scale_button_scale_press (GtkWidget *widget,
GdkEventButton *event)
{
- GtkScaleButtonScale *scale;
GtkScaleButtonPrivate *priv;
+ GtkWidgetClass *widget_class;
- scale = GTK_SCALE_BUTTON_SCALE (widget);
- priv = scale->button->priv;
+ if (GTK_IS_SCALE_BUTTON_VSCALE (widget))
+ {
+ priv = GTK_SCALE_BUTTON_VSCALE (widget)->button->priv;
+ widget_class = GTK_WIDGET_CLASS (gtk_scale_button_vscale_parent_class);
+ }
+ else
+ {
+ priv = GTK_SCALE_BUTTON_HSCALE (widget)->button->priv;
+ widget_class = GTK_WIDGET_CLASS (gtk_scale_button_hscale_parent_class);
+ }
/* the scale will grab input; if we have input grabbed, all goes
* horribly wrong, so let's not do that. */
gtk_grab_remove (priv->dock);
- return GTK_WIDGET_CLASS (gtk_scale_button_scale_parent_class)->button_press_event (widget, event);
+ return widget_class->button_press_event (widget, event);
}
static gboolean
gtk_scale_button_scale_release (GtkWidget *widget,
GdkEventButton *event)
{
- GtkScaleButtonScale *scale;
- GtkScaleButtonPrivate *priv;
+ GtkScaleButton *button;
GtkWidgetClass *widget_class;
gboolean res;
- scale = GTK_SCALE_BUTTON_SCALE (widget);
- priv = scale->button->priv;
-
- widget_class = GTK_WIDGET_CLASS (gtk_scale_button_scale_parent_class);
+ if (GTK_IS_SCALE_BUTTON_VSCALE (widget))
+ {
+ button = GTK_SCALE_BUTTON_VSCALE (widget)->button;
+ widget_class = GTK_WIDGET_CLASS (gtk_scale_button_vscale_parent_class);
+ }
+ else
+ {
+ button = GTK_SCALE_BUTTON_HSCALE (widget)->button;
+ widget_class = GTK_WIDGET_CLASS (gtk_scale_button_hscale_parent_class);
+ }
- if (priv->timeout)
+ if (button->priv->timeout)
{
/* if we did a quick click, leave the window open; else, hide it */
- if (event->time > priv->pop_time + priv->click_timeout)
+ if (event->time > button->priv->pop_time + button->priv->click_timeout)
{
- gtk_scale_button_release_grab (scale->button, event);
+ gtk_scale_button_release_grab (button, event);
widget_class->button_release_event (widget, event);
return TRUE;
}
- priv->timeout = FALSE;
+ button->priv->timeout = FALSE;
}
res = widget_class->button_release_event (widget, event);
* it back so we can catch out-of-scale clicks and hide the popup,
* so I basically want a g_signal_connect_after_always(), but I can't
* find that, so we do this complex 'first-call-parent-then-do-actual-
- * action' thingy... */
- gtk_grab_add (priv->dock);
+ * action' thingy...
+ */
+ gtk_grab_add (button->priv->dock);
return res;
}
}
range = GTK_RANGE (priv->scale);
- adj = gtk_range_get_adjustment (range);
+ adj = priv->adjustment;
value = gtk_scale_button_get_value (button);
/* The 2-icons special case */
static void
gtk_scale_button_scale_value_changed (GtkRange *range)
{
- GtkScaleButtonScale *scale = GTK_SCALE_BUTTON_SCALE (range);
- GtkScaleButton *button = scale->button;
+ GtkScaleButton *button;
gdouble value;
+ if (GTK_IS_SCALE_BUTTON_VSCALE (range))
+ button = GTK_SCALE_BUTTON_VSCALE (range)->button;
+ else
+ button = GTK_SCALE_BUTTON_HSCALE (range)->button;
+
value = gtk_range_get_value (range);
gtk_scale_button_update_icon (button);