diff options
Diffstat (limited to 'app/widgets/gimphandlebar.c')
-rw-r--r-- | app/widgets/gimphandlebar.c | 441 |
1 files changed, 441 insertions, 0 deletions
diff --git a/app/widgets/gimphandlebar.c b/app/widgets/gimphandlebar.c new file mode 100644 index 0000000..09b425b --- /dev/null +++ b/app/widgets/gimphandlebar.c @@ -0,0 +1,441 @@ +/* GIMP - The GNU Image Manipulation Program + * Copyright (C) 1995 Spencer Kimball and Peter Mattis + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 3 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see <https://www.gnu.org/licenses/>. + */ + +#include "config.h" + +#include <gtk/gtk.h> + +#include "libgimpmath/gimpmath.h" + +#include "widgets-types.h" + +#include "gimphandlebar.h" + + +enum +{ + PROP_0, + PROP_ORIENTATION +}; + + +/* local function prototypes */ + +static void gimp_handle_bar_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec); +static void gimp_handle_bar_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec); + +static gboolean gimp_handle_bar_expose (GtkWidget *widget, + GdkEventExpose *eevent); +static gboolean gimp_handle_bar_button_press (GtkWidget *widget, + GdkEventButton *bevent); +static gboolean gimp_handle_bar_button_release (GtkWidget *widget, + GdkEventButton *bevent); +static gboolean gimp_handle_bar_motion_notify (GtkWidget *widget, + GdkEventMotion *mevent); + +static void gimp_handle_bar_adjustment_changed (GtkAdjustment *adjustment, + GimpHandleBar *bar); + + +G_DEFINE_TYPE (GimpHandleBar, gimp_handle_bar, GTK_TYPE_EVENT_BOX) + +#define parent_class gimp_handle_bar_parent_class + + +static void +gimp_handle_bar_class_init (GimpHandleBarClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->set_property = gimp_handle_bar_set_property; + object_class->get_property = gimp_handle_bar_get_property; + + widget_class->expose_event = gimp_handle_bar_expose; + widget_class->button_press_event = gimp_handle_bar_button_press; + widget_class->button_release_event = gimp_handle_bar_button_release; + widget_class->motion_notify_event = gimp_handle_bar_motion_notify; + + g_object_class_install_property (object_class, PROP_ORIENTATION, + g_param_spec_enum ("orientation", + NULL, NULL, + GTK_TYPE_ORIENTATION, + GTK_ORIENTATION_HORIZONTAL, + GIMP_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY)); +} + +static void +gimp_handle_bar_init (GimpHandleBar *bar) +{ + gtk_widget_add_events (GTK_WIDGET (bar), + GDK_BUTTON_PRESS_MASK | + GDK_BUTTON_RELEASE_MASK | + GDK_BUTTON_MOTION_MASK); + + gtk_event_box_set_visible_window (GTK_EVENT_BOX (bar), FALSE); + + bar->orientation = GTK_ORIENTATION_HORIZONTAL; + + bar->limits_set = FALSE; + bar->lower = 0.0; + bar->upper = 1.0; +} + +static void +gimp_handle_bar_set_property (GObject *object, + guint property_id, + const GValue *value, + GParamSpec *pspec) +{ + GimpHandleBar *bar = GIMP_HANDLE_BAR (object); + + switch (property_id) + { + case PROP_ORIENTATION: + bar->orientation = g_value_get_enum (value); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static void +gimp_handle_bar_get_property (GObject *object, + guint property_id, + GValue *value, + GParamSpec *pspec) +{ + GimpHandleBar *bar = GIMP_HANDLE_BAR (object); + + switch (property_id) + { + case PROP_ORIENTATION: + g_value_set_enum (value, bar->orientation); + break; + + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec); + break; + } +} + +static gboolean +gimp_handle_bar_expose (GtkWidget *widget, + GdkEventExpose *eevent) +{ + GimpHandleBar *bar = GIMP_HANDLE_BAR (widget); + GtkAllocation allocation; + cairo_t *cr; + gint x, y; + gint width, height; + gint i; + + gtk_widget_get_allocation (widget, &allocation); + + x = y = gtk_container_get_border_width (GTK_CONTAINER (widget)); + + width = allocation.width - 2 * x; + height = allocation.height - 2 * y; + + if (! gtk_widget_get_has_window (widget)) + { + x += allocation.x; + y += allocation.y; + } + + cr = gdk_cairo_create (gtk_widget_get_window (widget)); + gdk_cairo_region (cr, eevent->region); + cairo_clip (cr); + + cairo_set_line_width (cr, 1.0); + cairo_translate (cr, 0.5, 0.5); + + for (i = 0; i < 3; i++) + { + bar->slider_pos[i] = -1; + + if (bar->slider_adj[i]) + { + bar->slider_pos[i] = ROUND ((gdouble) (width - 1) * + (gtk_adjustment_get_value (bar->slider_adj[i]) - bar->lower) / + (bar->upper - bar->lower)); + + cairo_set_source_rgb (cr, 0.5 * i, 0.5 * i, 0.5 * i); + + cairo_move_to (cr, + x + bar->slider_pos[i], + y); + cairo_line_to (cr, + x + bar->slider_pos[i] - (height - 1) / 2, + y + height - 1); + cairo_line_to (cr, + x + bar->slider_pos[i] + (height - 1) / 2, + y + height - 1); + cairo_line_to (cr, + x + bar->slider_pos[i], + y); + + cairo_fill_preserve (cr); + + /* Make all sliders well visible even on similar colored + * backgrounds. + */ + if (i == 0) + cairo_set_source_rgb (cr, 0.6, 0.6, 0.6); + else + cairo_set_source_rgb (cr, 0.0, 0.0, 0.0); + + cairo_stroke (cr); + } + } + + cairo_destroy (cr); + + return FALSE; +} + +static gboolean +gimp_handle_bar_button_press (GtkWidget *widget, + GdkEventButton *bevent) +{ + GimpHandleBar *bar= GIMP_HANDLE_BAR (widget); + GtkAllocation allocation; + gint border; + gint width; + gdouble value; + gint min_dist; + gint i; + + gtk_widget_get_allocation (widget, &allocation); + + border = gtk_container_get_border_width (GTK_CONTAINER (widget)); + width = allocation.width - 2 * border; + + if (width < 1) + return FALSE; + + min_dist = G_MAXINT; + for (i = 0; i < 3; i++) + if (bar->slider_pos[i] != -1) + { + gdouble dist = bevent->x - bar->slider_pos[i] + border; + + if (fabs (dist) < min_dist || + (fabs (dist) == min_dist && dist > 0)) + { + bar->active_slider = i; + min_dist = fabs (dist); + } + } + + if (width == 1) + value = 0; + else + value = ((gdouble) (bevent->x - border) / + (gdouble) (width - 1) * + (bar->upper - bar->lower)); + + gtk_adjustment_set_value (bar->slider_adj[bar->active_slider], value); + + return TRUE; +} + +static gboolean +gimp_handle_bar_button_release (GtkWidget *widget, + GdkEventButton *bevent) +{ + return TRUE; +} + +static gboolean +gimp_handle_bar_motion_notify (GtkWidget *widget, + GdkEventMotion *mevent) +{ + GimpHandleBar *bar = GIMP_HANDLE_BAR (widget); + GtkAllocation allocation; + gint border; + gint width; + gdouble value; + + gtk_widget_get_allocation (widget, &allocation); + + border = gtk_container_get_border_width (GTK_CONTAINER (widget)); + width = allocation.width - 2 * border; + + if (width < 1) + return FALSE; + + if (width == 1) + value = 0; + else + value = ((gdouble) (mevent->x - border) / + (gdouble) (width - 1) * + (bar->upper - bar->lower)); + + gtk_adjustment_set_value (bar->slider_adj[bar->active_slider], value); + + return TRUE; +} + + +/* public functions */ + +/** + * gimp_handle_bar_new: + * @orientation: whether the bar should be oriented horizontally or + * vertically + * + * Creates a new #GimpHandleBar widget. + * + * Return value: The new #GimpHandleBar widget. + **/ +GtkWidget * +gimp_handle_bar_new (GtkOrientation orientation) +{ + return g_object_new (GIMP_TYPE_HANDLE_BAR, + "orientation", orientation, + NULL); +} + +void +gimp_handle_bar_set_adjustment (GimpHandleBar *bar, + gint handle_no, + GtkAdjustment *adjustment) +{ + g_return_if_fail (GIMP_IS_HANDLE_BAR (bar)); + g_return_if_fail (handle_no >= 0 && handle_no <= 2); + g_return_if_fail (adjustment == NULL || GTK_IS_ADJUSTMENT (adjustment)); + + if (adjustment == bar->slider_adj[handle_no]) + return; + + if (bar->slider_adj[handle_no]) + { + g_signal_handlers_disconnect_by_func (bar->slider_adj[handle_no], + gimp_handle_bar_adjustment_changed, + bar); + + g_object_unref (bar->slider_adj[handle_no]); + } + + bar->slider_adj[handle_no] = adjustment; + + if (bar->slider_adj[handle_no]) + { + g_object_ref (bar->slider_adj[handle_no]); + + g_signal_connect (bar->slider_adj[handle_no], "value-changed", + G_CALLBACK (gimp_handle_bar_adjustment_changed), + bar); + g_signal_connect (bar->slider_adj[handle_no], "changed", + G_CALLBACK (gimp_handle_bar_adjustment_changed), + bar); + } + + gimp_handle_bar_adjustment_changed (bar->slider_adj[handle_no], bar); +} + +void +gimp_handle_bar_set_limits (GimpHandleBar *bar, + gdouble lower, + gdouble upper) +{ + g_return_if_fail (GIMP_IS_HANDLE_BAR (bar)); + + bar->limits_set = TRUE; + bar->lower = lower; + bar->upper = upper; + + gtk_widget_queue_draw (GTK_WIDGET (bar)); +} + +void +gimp_handle_bar_unset_limits (GimpHandleBar *bar) +{ + g_return_if_fail (GIMP_IS_HANDLE_BAR (bar)); + + bar->limits_set = FALSE; + bar->lower = 0.0; + bar->upper = 1.0; + + gimp_handle_bar_adjustment_changed (NULL, bar); +} + +gboolean +gimp_handle_bar_get_limits (GimpHandleBar *bar, + gdouble *lower, + gdouble *upper) +{ + g_return_val_if_fail (GIMP_IS_HANDLE_BAR (bar), FALSE); + + if (lower) *lower = bar->lower; + if (upper) *upper = bar->upper; + + return bar->limits_set; +} + +void +gimp_handle_bar_connect_events (GimpHandleBar *bar, + GtkWidget *event_source) +{ + GtkWidgetClass *widget_class; + + g_return_if_fail (GIMP_IS_HANDLE_BAR (bar)); + g_return_if_fail (GTK_IS_WIDGET (event_source)); + + widget_class = GTK_WIDGET_GET_CLASS (bar); + + g_signal_connect_object (event_source, "button-press-event", + G_CALLBACK (widget_class->button_press_event), + bar, G_CONNECT_SWAPPED); + + g_signal_connect_object (event_source, "button-release-event", + G_CALLBACK (widget_class->button_release_event), + bar, G_CONNECT_SWAPPED); + + g_signal_connect_object (event_source, "motion-notify-event", + G_CALLBACK (widget_class->motion_notify_event), + bar, G_CONNECT_SWAPPED); +} + + +/* private functions */ + +static void +gimp_handle_bar_adjustment_changed (GtkAdjustment *adjustment, + GimpHandleBar *bar) +{ + if (! bar->limits_set) + { + if (bar->slider_adj[0]) + bar->lower = gtk_adjustment_get_lower (bar->slider_adj[0]); + + if (bar->slider_adj[2]) + bar->upper = gtk_adjustment_get_upper (bar->slider_adj[2]); + } + + gtk_widget_queue_draw (GTK_WIDGET (bar)); +} |