2010-11-02 03:03:39 +08:00
|
|
|
/* GIMP - The GNU Image Manipulation Program
|
|
|
|
* Copyright (C) 1995 Spencer Kimball and Peter Mattis
|
|
|
|
*
|
|
|
|
* gimpspinscale.c
|
|
|
|
* Copyright (C) 2010 Michael Natterer <mitch@gimp.org>
|
2012-03-31 04:52:20 +08:00
|
|
|
* 2012 Øyvind Kolås <pippin@gimp.org>
|
2010-11-02 03:03:39 +08:00
|
|
|
*
|
|
|
|
* 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 <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
2013-11-02 05:28:18 +08:00
|
|
|
#include <gegl.h>
|
2010-11-02 03:03:39 +08:00
|
|
|
#include <gtk/gtk.h>
|
2013-05-29 04:46:22 +08:00
|
|
|
#include <gdk/gdkkeysyms.h>
|
2010-11-02 03:03:39 +08:00
|
|
|
|
|
|
|
#include "libgimpwidgets/gimpwidgets.h"
|
2012-03-31 04:34:59 +08:00
|
|
|
#include "libgimpmath/gimpmath.h"
|
2010-11-02 03:03:39 +08:00
|
|
|
|
|
|
|
#include "widgets-types.h"
|
|
|
|
|
|
|
|
#include "gimpspinscale.h"
|
|
|
|
|
|
|
|
#include "gimp-intl.h"
|
|
|
|
|
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
PROP_0,
|
|
|
|
PROP_LABEL
|
|
|
|
};
|
|
|
|
|
2011-03-18 22:07:44 +08:00
|
|
|
typedef enum
|
|
|
|
{
|
2017-10-19 02:50:20 +08:00
|
|
|
TARGET_NONE,
|
2011-03-18 22:07:44 +08:00
|
|
|
TARGET_NUMBER,
|
|
|
|
TARGET_UPPER,
|
|
|
|
TARGET_LOWER
|
|
|
|
} SpinScaleTarget;
|
|
|
|
|
2010-11-02 03:03:39 +08:00
|
|
|
|
|
|
|
typedef struct _GimpSpinScalePrivate GimpSpinScalePrivate;
|
|
|
|
|
|
|
|
struct _GimpSpinScalePrivate
|
|
|
|
{
|
2017-10-19 02:50:20 +08:00
|
|
|
gchar *label;
|
|
|
|
gchar *label_text;
|
|
|
|
gchar *label_pattern;
|
|
|
|
|
|
|
|
GtkWindow *mnemonic_window;
|
|
|
|
guint mnemonic_keyval;
|
|
|
|
gboolean mnemonics_visible;
|
|
|
|
|
|
|
|
gboolean scale_limits_set;
|
|
|
|
gdouble scale_lower;
|
|
|
|
gdouble scale_upper;
|
|
|
|
gdouble gamma;
|
|
|
|
|
|
|
|
PangoLayout *layout;
|
|
|
|
gboolean changing_value;
|
|
|
|
gboolean relative_change;
|
|
|
|
gdouble start_x;
|
|
|
|
gdouble start_value;
|
app: wrap pointer around screen edges during relative spin scale adjustment
While applying a relative spin scale adjusment (i.e., when dragging
from the lower half of the spin scale), wrap the pointer around the
screen edges (of the current monitor), so that the maximal possible
adjustment amount isn't artifically limited by the screen geometry.
This is especially useful for spin scales in dockables, since
dockables are normally placed near the edge of the screen.
When the mouse is released, move the pointer back to its initial
position (at the beginning of the drag), to allow for subsequent
adjustments.
Unfortunately, moving the pointer programatically isn't supported
on all envrionments (Wayland, Xephyr, ...), and worse yet,
detecting that the pointer failed to move is tricky, so we have to
resort to an ungly hack to maintain the current behavior in this
case. Gah :P
2017-11-02 03:43:19 +08:00
|
|
|
GdkScreen *start_screen;
|
|
|
|
gint start_pointer_x;
|
|
|
|
gint start_pointer_y;
|
2017-10-19 02:50:20 +08:00
|
|
|
SpinScaleTarget target;
|
|
|
|
gboolean hover;
|
app: wrap pointer around screen edges during relative spin scale adjustment
While applying a relative spin scale adjusment (i.e., when dragging
from the lower half of the spin scale), wrap the pointer around the
screen edges (of the current monitor), so that the maximal possible
adjustment amount isn't artifically limited by the screen geometry.
This is especially useful for spin scales in dockables, since
dockables are normally placed near the edge of the screen.
When the mouse is released, move the pointer back to its initial
position (at the beginning of the drag), to allow for subsequent
adjustments.
Unfortunately, moving the pointer programatically isn't supported
on all envrionments (Wayland, Xephyr, ...), and worse yet,
detecting that the pointer failed to move is tricky, so we have to
resort to an ungly hack to maintain the current behavior in this
case. Gah :P
2017-11-02 03:43:19 +08:00
|
|
|
gboolean pointer_warp;
|
|
|
|
gint pointer_warp_x;
|
|
|
|
gint pointer_warp_start_x;
|
2010-11-02 03:03:39 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
#define GET_PRIVATE(obj) (G_TYPE_INSTANCE_GET_PRIVATE ((obj), \
|
|
|
|
GIMP_TYPE_SPIN_SCALE, \
|
|
|
|
GimpSpinScalePrivate))
|
|
|
|
|
|
|
|
|
2013-05-29 04:46:22 +08:00
|
|
|
static void gimp_spin_scale_dispose (GObject *object);
|
|
|
|
static void gimp_spin_scale_finalize (GObject *object);
|
|
|
|
static void gimp_spin_scale_set_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec);
|
|
|
|
static void gimp_spin_scale_get_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec);
|
|
|
|
|
|
|
|
static void gimp_spin_scale_size_request (GtkWidget *widget,
|
|
|
|
GtkRequisition *requisition);
|
|
|
|
static void gimp_spin_scale_style_set (GtkWidget *widget,
|
|
|
|
GtkStyle *prev_style);
|
|
|
|
static gboolean gimp_spin_scale_expose (GtkWidget *widget,
|
|
|
|
GdkEventExpose *event);
|
|
|
|
static gboolean gimp_spin_scale_button_press (GtkWidget *widget,
|
|
|
|
GdkEventButton *event);
|
|
|
|
static gboolean gimp_spin_scale_button_release (GtkWidget *widget,
|
|
|
|
GdkEventButton *event);
|
|
|
|
static gboolean gimp_spin_scale_motion_notify (GtkWidget *widget,
|
|
|
|
GdkEventMotion *event);
|
|
|
|
static gboolean gimp_spin_scale_leave_notify (GtkWidget *widget,
|
|
|
|
GdkEventCrossing *event);
|
|
|
|
static void gimp_spin_scale_hierarchy_changed (GtkWidget *widget,
|
|
|
|
GtkWidget *old_toplevel);
|
|
|
|
static void gimp_spin_scale_screen_changed (GtkWidget *widget,
|
|
|
|
GdkScreen *old_screen);
|
|
|
|
|
|
|
|
static void gimp_spin_scale_value_changed (GtkSpinButton *spin_button);
|
|
|
|
|
|
|
|
static void gimp_spin_scale_settings_notify (GtkSettings *settings,
|
|
|
|
const GParamSpec *pspec,
|
|
|
|
GimpSpinScale *scale);
|
|
|
|
static void gimp_spin_scale_mnemonics_notify (GtkWindow *window,
|
|
|
|
const GParamSpec *pspec,
|
|
|
|
GimpSpinScale *scale);
|
|
|
|
static void gimp_spin_scale_setup_mnemonic (GimpSpinScale *scale,
|
|
|
|
guint previous_keyval);
|
2010-11-02 03:03:39 +08:00
|
|
|
|
|
|
|
|
|
|
|
G_DEFINE_TYPE (GimpSpinScale, gimp_spin_scale, GTK_TYPE_SPIN_BUTTON);
|
|
|
|
|
|
|
|
#define parent_class gimp_spin_scale_parent_class
|
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_spin_scale_class_init (GimpSpinScaleClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
|
|
|
GtkSpinButtonClass *spin_button_class = GTK_SPIN_BUTTON_CLASS (klass);
|
|
|
|
|
|
|
|
object_class->dispose = gimp_spin_scale_dispose;
|
|
|
|
object_class->finalize = gimp_spin_scale_finalize;
|
|
|
|
object_class->set_property = gimp_spin_scale_set_property;
|
|
|
|
object_class->get_property = gimp_spin_scale_get_property;
|
|
|
|
|
2012-02-23 05:46:41 +08:00
|
|
|
widget_class->size_request = gimp_spin_scale_size_request;
|
2010-11-02 03:03:39 +08:00
|
|
|
widget_class->style_set = gimp_spin_scale_style_set;
|
|
|
|
widget_class->expose_event = gimp_spin_scale_expose;
|
|
|
|
widget_class->button_press_event = gimp_spin_scale_button_press;
|
|
|
|
widget_class->button_release_event = gimp_spin_scale_button_release;
|
2011-04-04 07:10:44 +08:00
|
|
|
widget_class->motion_notify_event = gimp_spin_scale_motion_notify;
|
|
|
|
widget_class->leave_notify_event = gimp_spin_scale_leave_notify;
|
2013-05-29 04:46:22 +08:00
|
|
|
widget_class->hierarchy_changed = gimp_spin_scale_hierarchy_changed;
|
|
|
|
widget_class->screen_changed = gimp_spin_scale_screen_changed;
|
2010-11-02 03:03:39 +08:00
|
|
|
|
|
|
|
spin_button_class->value_changed = gimp_spin_scale_value_changed;
|
|
|
|
|
|
|
|
g_object_class_install_property (object_class, PROP_LABEL,
|
|
|
|
g_param_spec_string ("label", NULL, NULL,
|
|
|
|
NULL,
|
|
|
|
GIMP_PARAM_READWRITE));
|
|
|
|
|
|
|
|
g_type_class_add_private (klass, sizeof (GimpSpinScalePrivate));
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_spin_scale_init (GimpSpinScale *scale)
|
|
|
|
{
|
2012-03-31 06:44:41 +08:00
|
|
|
GimpSpinScalePrivate *private = GET_PRIVATE (scale);
|
2012-04-01 01:41:15 +08:00
|
|
|
|
2012-11-19 03:02:51 +08:00
|
|
|
gtk_widget_add_events (GTK_WIDGET (scale),
|
|
|
|
GDK_BUTTON_PRESS_MASK |
|
|
|
|
GDK_BUTTON_RELEASE_MASK |
|
|
|
|
GDK_POINTER_MOTION_MASK |
|
|
|
|
GDK_BUTTON1_MOTION_MASK |
|
|
|
|
GDK_LEAVE_NOTIFY_MASK);
|
|
|
|
|
2010-11-02 03:03:39 +08:00
|
|
|
gtk_entry_set_alignment (GTK_ENTRY (scale), 1.0);
|
|
|
|
gtk_entry_set_has_frame (GTK_ENTRY (scale), FALSE);
|
2011-04-16 17:52:38 +08:00
|
|
|
gtk_spin_button_set_numeric (GTK_SPIN_BUTTON (scale), TRUE);
|
2012-04-01 01:41:15 +08:00
|
|
|
|
2013-05-29 05:13:13 +08:00
|
|
|
private->mnemonic_keyval = GDK_KEY_VoidSymbol;
|
|
|
|
private->gamma = 1.0;
|
2010-11-02 03:03:39 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_spin_scale_dispose (GObject *object)
|
|
|
|
{
|
2011-04-21 02:12:21 +08:00
|
|
|
GimpSpinScalePrivate *private = GET_PRIVATE (object);
|
2013-05-29 04:46:22 +08:00
|
|
|
guint keyval;
|
|
|
|
|
|
|
|
keyval = private->mnemonic_keyval;
|
2013-05-29 05:13:13 +08:00
|
|
|
private->mnemonic_keyval = GDK_KEY_VoidSymbol;
|
2013-05-29 04:46:22 +08:00
|
|
|
|
|
|
|
gimp_spin_scale_setup_mnemonic (GIMP_SPIN_SCALE (object), keyval);
|
2011-04-21 02:12:21 +08:00
|
|
|
|
2017-07-16 00:38:01 +08:00
|
|
|
g_clear_object (&private->layout);
|
2010-11-02 03:03:39 +08:00
|
|
|
|
|
|
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_spin_scale_finalize (GObject *object)
|
|
|
|
{
|
|
|
|
GimpSpinScalePrivate *private = GET_PRIVATE (object);
|
|
|
|
|
2017-07-16 00:38:01 +08:00
|
|
|
g_clear_pointer (&private->label, g_free);
|
|
|
|
g_clear_pointer (&private->label_text, g_free);
|
|
|
|
g_clear_pointer (&private->label_pattern, g_free);
|
2013-05-29 04:46:22 +08:00
|
|
|
|
2010-11-02 03:03:39 +08:00
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_spin_scale_set_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
2013-05-28 21:29:44 +08:00
|
|
|
GimpSpinScale *scale = GIMP_SPIN_SCALE (object);
|
2010-11-02 03:03:39 +08:00
|
|
|
|
|
|
|
switch (property_id)
|
|
|
|
{
|
|
|
|
case PROP_LABEL:
|
2013-05-28 21:29:44 +08:00
|
|
|
gimp_spin_scale_set_label (scale, g_value_get_string (value));
|
2010-11-02 03:03:39 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_spin_scale_get_property (GObject *object,
|
|
|
|
guint property_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
2013-05-28 21:29:44 +08:00
|
|
|
GimpSpinScale *scale = GIMP_SPIN_SCALE (object);
|
2010-11-02 03:03:39 +08:00
|
|
|
|
|
|
|
switch (property_id)
|
|
|
|
{
|
|
|
|
case PROP_LABEL:
|
2013-05-28 21:29:44 +08:00
|
|
|
g_value_set_string (value, gimp_spin_scale_get_label (scale));
|
2010-11-02 03:03:39 +08:00
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2012-02-23 05:46:41 +08:00
|
|
|
gimp_spin_scale_size_request (GtkWidget *widget,
|
|
|
|
GtkRequisition *requisition)
|
2010-11-02 03:03:39 +08:00
|
|
|
{
|
2011-04-21 02:12:21 +08:00
|
|
|
GimpSpinScalePrivate *private = GET_PRIVATE (widget);
|
|
|
|
GtkStyle *style = gtk_widget_get_style (widget);
|
|
|
|
PangoContext *context = gtk_widget_get_pango_context (widget);
|
|
|
|
PangoFontMetrics *metrics;
|
|
|
|
gint height;
|
2010-11-02 03:03:39 +08:00
|
|
|
|
2012-02-23 05:46:41 +08:00
|
|
|
GTK_WIDGET_CLASS (parent_class)->size_request (widget, requisition);
|
2010-11-02 03:03:39 +08:00
|
|
|
|
|
|
|
metrics = pango_context_get_metrics (context, style->font_desc,
|
|
|
|
pango_context_get_language (context));
|
|
|
|
|
2012-02-23 05:46:41 +08:00
|
|
|
height = PANGO_PIXELS (pango_font_metrics_get_ascent (metrics) +
|
|
|
|
pango_font_metrics_get_descent (metrics));
|
|
|
|
|
|
|
|
requisition->height += height;
|
|
|
|
|
|
|
|
if (private->label)
|
|
|
|
{
|
2012-02-23 06:37:32 +08:00
|
|
|
gint char_width;
|
|
|
|
gint digit_width;
|
|
|
|
gint char_pixels;
|
2012-02-23 05:46:41 +08:00
|
|
|
|
|
|
|
char_width = pango_font_metrics_get_approximate_char_width (metrics);
|
|
|
|
digit_width = pango_font_metrics_get_approximate_digit_width (metrics);
|
|
|
|
char_pixels = PANGO_PIXELS (MAX (char_width, digit_width));
|
|
|
|
|
|
|
|
/* ~3 chars for the ellipses */
|
|
|
|
requisition->width += char_pixels * 3;
|
|
|
|
}
|
2010-11-02 03:03:39 +08:00
|
|
|
|
|
|
|
pango_font_metrics_unref (metrics);
|
2012-02-23 05:46:41 +08:00
|
|
|
}
|
2010-11-02 03:03:39 +08:00
|
|
|
|
2012-02-23 05:46:41 +08:00
|
|
|
static void
|
|
|
|
gimp_spin_scale_style_set (GtkWidget *widget,
|
|
|
|
GtkStyle *prev_style)
|
|
|
|
{
|
|
|
|
GimpSpinScalePrivate *private = GET_PRIVATE (widget);
|
2010-11-02 03:03:39 +08:00
|
|
|
|
2012-02-23 05:46:41 +08:00
|
|
|
GTK_WIDGET_CLASS (parent_class)->style_set (widget, prev_style);
|
2011-04-21 02:12:21 +08:00
|
|
|
|
2017-07-16 00:38:01 +08:00
|
|
|
g_clear_object (&private->layout);
|
2010-11-02 03:03:39 +08:00
|
|
|
}
|
|
|
|
|
2013-05-29 04:46:22 +08:00
|
|
|
static PangoAttrList *
|
|
|
|
pattern_to_attrs (const gchar *text,
|
|
|
|
const gchar *pattern)
|
|
|
|
{
|
|
|
|
PangoAttrList *attrs = pango_attr_list_new ();
|
|
|
|
const char *p = text;
|
|
|
|
const char *q = pattern;
|
|
|
|
const char *start;
|
|
|
|
|
|
|
|
while (TRUE)
|
|
|
|
{
|
|
|
|
while (*p && *q && *q != '_')
|
|
|
|
{
|
|
|
|
p = g_utf8_next_char (p);
|
|
|
|
q++;
|
|
|
|
}
|
|
|
|
start = p;
|
|
|
|
while (*p && *q && *q == '_')
|
|
|
|
{
|
|
|
|
p = g_utf8_next_char (p);
|
|
|
|
q++;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (p > start)
|
|
|
|
{
|
|
|
|
PangoAttribute *attr = pango_attr_underline_new (PANGO_UNDERLINE_LOW);
|
|
|
|
|
|
|
|
attr->start_index = start - text;
|
|
|
|
attr->end_index = p - text;
|
|
|
|
|
|
|
|
pango_attr_list_insert (attrs, attr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
return attrs;
|
|
|
|
}
|
|
|
|
|
2010-11-02 03:03:39 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_spin_scale_expose (GtkWidget *widget,
|
|
|
|
GdkEventExpose *event)
|
|
|
|
{
|
|
|
|
GimpSpinScalePrivate *private = GET_PRIVATE (widget);
|
|
|
|
GtkStyle *style = gtk_widget_get_style (widget);
|
|
|
|
cairo_t *cr;
|
2011-04-21 02:12:21 +08:00
|
|
|
gboolean rtl;
|
2010-11-02 03:03:39 +08:00
|
|
|
gint w, h;
|
|
|
|
|
|
|
|
GTK_WIDGET_CLASS (parent_class)->expose_event (widget, event);
|
|
|
|
|
|
|
|
cr = gdk_cairo_create (event->window);
|
|
|
|
gdk_cairo_region (cr, event->region);
|
|
|
|
cairo_clip (cr);
|
|
|
|
|
2011-04-21 02:12:21 +08:00
|
|
|
rtl = (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL);
|
|
|
|
|
2011-03-17 22:10:17 +08:00
|
|
|
w = gdk_window_get_width (event->window);
|
|
|
|
h = gdk_window_get_height (event->window);
|
2010-11-02 03:03:39 +08:00
|
|
|
|
2017-10-19 02:50:20 +08:00
|
|
|
/* upper/lower halves highlight */
|
|
|
|
if (event->window == gtk_entry_get_text_window (GTK_ENTRY (widget)) &&
|
|
|
|
gtk_widget_get_sensitive (widget) &&
|
|
|
|
(private->target == TARGET_UPPER || private->target == TARGET_LOWER))
|
|
|
|
{
|
|
|
|
gint window_width;
|
|
|
|
gint window_height;
|
|
|
|
const GdkColor *color;
|
|
|
|
gdouble r, g, b, a;
|
|
|
|
|
|
|
|
window_width = gdk_window_get_width (event->window);
|
|
|
|
window_height = gdk_window_get_height (event->window);
|
|
|
|
|
|
|
|
color = &style->text[gtk_widget_get_state (widget)];
|
|
|
|
|
|
|
|
switch (private->target)
|
|
|
|
{
|
|
|
|
case TARGET_UPPER:
|
|
|
|
cairo_rectangle (cr, 0, 0, window_width, window_height / 2);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TARGET_LOWER:
|
|
|
|
cairo_rectangle (cr, 0, window_height / 2, window_width, (window_height + 1) / 2);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
r = (gdouble) color->red / 0xffff;
|
|
|
|
g = (gdouble) color->green / 0xffff;
|
|
|
|
b = (gdouble) color->blue / 0xffff;
|
|
|
|
a = 0.12 + 0.04 * MAX (r, MAX (g, b));
|
|
|
|
|
|
|
|
if (private->changing_value)
|
|
|
|
a *= 1.6;
|
|
|
|
|
|
|
|
cairo_set_source_rgba (cr, r, g, b, a);
|
|
|
|
|
|
|
|
cairo_fill (cr);
|
|
|
|
}
|
|
|
|
|
2010-11-02 03:03:39 +08:00
|
|
|
cairo_set_line_width (cr, 1.0);
|
|
|
|
|
|
|
|
if (event->window == gtk_entry_get_text_window (GTK_ENTRY (widget)))
|
|
|
|
{
|
2011-04-21 02:12:21 +08:00
|
|
|
/* let spinbutton-side line of rectangle disappear */
|
|
|
|
if (rtl)
|
|
|
|
cairo_rectangle (cr, -0.5, 0.5, w, h - 1.0);
|
|
|
|
else
|
|
|
|
cairo_rectangle (cr, 0.5, 0.5, w, h - 1.0);
|
|
|
|
|
2010-11-02 03:03:39 +08:00
|
|
|
gdk_cairo_set_source_color (cr,
|
|
|
|
&style->text[gtk_widget_get_state (widget)]);
|
|
|
|
cairo_stroke (cr);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2011-04-21 02:12:21 +08:00
|
|
|
/* let text-box-side line of rectangle disappear */
|
|
|
|
if (rtl)
|
|
|
|
cairo_rectangle (cr, 0.5, 0.5, w, h - 1.0);
|
|
|
|
else
|
|
|
|
cairo_rectangle (cr, -0.5, 0.5, w, h - 1.0);
|
|
|
|
|
2010-11-02 03:03:39 +08:00
|
|
|
gdk_cairo_set_source_color (cr,
|
|
|
|
&style->text[gtk_widget_get_state (widget)]);
|
|
|
|
cairo_stroke (cr);
|
|
|
|
|
2011-04-21 02:12:21 +08:00
|
|
|
if (rtl)
|
|
|
|
cairo_rectangle (cr, 1.5, 1.5, w - 2.0, h - 3.0);
|
|
|
|
else
|
|
|
|
cairo_rectangle (cr, 0.5, 1.5, w - 2.0, h - 3.0);
|
|
|
|
|
2010-11-02 03:03:39 +08:00
|
|
|
gdk_cairo_set_source_color (cr,
|
|
|
|
&style->base[gtk_widget_get_state (widget)]);
|
|
|
|
cairo_stroke (cr);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (private->label &&
|
|
|
|
gtk_widget_is_drawable (widget) &&
|
|
|
|
event->window == gtk_entry_get_text_window (GTK_ENTRY (widget)))
|
|
|
|
{
|
2012-02-23 05:46:41 +08:00
|
|
|
GtkRequisition requisition;
|
|
|
|
GtkAllocation allocation;
|
|
|
|
PangoRectangle logical;
|
|
|
|
gint layout_offset_x;
|
|
|
|
gint layout_offset_y;
|
2013-05-14 08:00:20 +08:00
|
|
|
GtkStateType state;
|
|
|
|
GdkColor text_color;
|
|
|
|
GdkColor bar_text_color;
|
|
|
|
gint window_width;
|
|
|
|
gint window_height;
|
|
|
|
gdouble progress_fraction;
|
|
|
|
gint progress_x;
|
|
|
|
gint progress_y;
|
|
|
|
gint progress_width;
|
|
|
|
gint progress_height;
|
2012-02-23 05:46:41 +08:00
|
|
|
|
|
|
|
GTK_WIDGET_CLASS (parent_class)->size_request (widget, &requisition);
|
|
|
|
gtk_widget_get_allocation (widget, &allocation);
|
2011-04-21 02:12:21 +08:00
|
|
|
|
|
|
|
if (! private->layout)
|
2012-02-23 05:46:41 +08:00
|
|
|
{
|
|
|
|
private->layout = gtk_widget_create_pango_layout (widget,
|
2013-05-29 04:46:22 +08:00
|
|
|
private->label_text);
|
2012-02-23 05:46:41 +08:00
|
|
|
pango_layout_set_ellipsize (private->layout, PANGO_ELLIPSIZE_END);
|
2013-05-29 04:46:22 +08:00
|
|
|
|
|
|
|
if (private->mnemonics_visible)
|
|
|
|
{
|
|
|
|
PangoAttrList *attrs;
|
|
|
|
|
|
|
|
attrs = pattern_to_attrs (private->label_text,
|
|
|
|
private->label_pattern);
|
|
|
|
if (attrs)
|
|
|
|
{
|
|
|
|
pango_layout_set_attributes (private->layout, attrs);
|
|
|
|
pango_attr_list_unref (attrs);
|
|
|
|
}
|
|
|
|
}
|
2012-02-23 05:46:41 +08:00
|
|
|
}
|
2011-04-21 02:12:21 +08:00
|
|
|
|
2012-02-23 05:46:41 +08:00
|
|
|
pango_layout_set_width (private->layout,
|
|
|
|
PANGO_SCALE *
|
|
|
|
(allocation.width - requisition.width));
|
|
|
|
pango_layout_get_pixel_extents (private->layout, NULL, &logical);
|
2010-11-02 03:03:39 +08:00
|
|
|
|
2012-02-23 05:46:41 +08:00
|
|
|
gtk_entry_get_layout_offsets (GTK_ENTRY (widget), NULL, &layout_offset_y);
|
2010-11-02 03:03:39 +08:00
|
|
|
|
2011-04-21 02:12:21 +08:00
|
|
|
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
|
2012-02-23 05:46:41 +08:00
|
|
|
layout_offset_x = w - logical.width - 2;
|
2010-11-02 03:03:39 +08:00
|
|
|
else
|
2012-02-23 05:46:41 +08:00
|
|
|
layout_offset_x = 2;
|
|
|
|
|
|
|
|
layout_offset_x -= logical.x;
|
|
|
|
|
2013-05-14 08:00:20 +08:00
|
|
|
state = GTK_STATE_SELECTED;
|
|
|
|
if (! gtk_widget_get_sensitive (widget))
|
|
|
|
state = GTK_STATE_INSENSITIVE;
|
|
|
|
text_color = style->text[gtk_widget_get_state (widget)];
|
|
|
|
bar_text_color = style->fg[state];
|
|
|
|
|
|
|
|
window_width = gdk_window_get_width (event->window);
|
|
|
|
window_height = gdk_window_get_height (event->window);
|
|
|
|
|
|
|
|
progress_fraction = gtk_entry_get_progress_fraction (GTK_ENTRY (widget));
|
|
|
|
|
|
|
|
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
|
|
|
|
{
|
|
|
|
progress_fraction = 1.0 - progress_fraction;
|
|
|
|
|
|
|
|
progress_x = window_width * progress_fraction;
|
|
|
|
progress_y = 0;
|
|
|
|
progress_width = window_width - progress_x;
|
|
|
|
progress_height = window_height;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
progress_x = 0;
|
|
|
|
progress_y = 0;
|
|
|
|
progress_width = window_width * progress_fraction;
|
|
|
|
progress_height = window_height;
|
|
|
|
}
|
|
|
|
|
|
|
|
cairo_save (cr);
|
|
|
|
|
|
|
|
cairo_set_fill_rule (cr, CAIRO_FILL_RULE_EVEN_ODD);
|
|
|
|
cairo_rectangle (cr, 0, 0, window_width, window_height);
|
|
|
|
cairo_rectangle (cr, progress_x, progress_y,
|
|
|
|
progress_width, progress_height);
|
|
|
|
cairo_clip (cr);
|
|
|
|
cairo_set_fill_rule (cr, CAIRO_FILL_RULE_WINDING);
|
|
|
|
|
2012-02-23 05:46:41 +08:00
|
|
|
cairo_move_to (cr, layout_offset_x, layout_offset_y);
|
2013-05-14 08:00:20 +08:00
|
|
|
gdk_cairo_set_source_color (cr, &text_color);
|
|
|
|
pango_cairo_show_layout (cr, private->layout);
|
2010-11-02 03:03:39 +08:00
|
|
|
|
2013-05-14 08:00:20 +08:00
|
|
|
cairo_restore (cr);
|
|
|
|
|
|
|
|
cairo_rectangle (cr, progress_x, progress_y,
|
|
|
|
progress_width, progress_height);
|
|
|
|
cairo_clip (cr);
|
2010-11-19 21:08:37 +08:00
|
|
|
|
2013-05-14 08:00:20 +08:00
|
|
|
cairo_move_to (cr, layout_offset_x, layout_offset_y);
|
|
|
|
gdk_cairo_set_source_color (cr, &bar_text_color);
|
2011-04-21 02:12:21 +08:00
|
|
|
pango_cairo_show_layout (cr, private->layout);
|
2010-11-02 03:03:39 +08:00
|
|
|
}
|
|
|
|
|
2011-04-20 06:43:30 +08:00
|
|
|
cairo_destroy (cr);
|
|
|
|
|
2010-11-02 03:03:39 +08:00
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2011-03-18 22:07:44 +08:00
|
|
|
static SpinScaleTarget
|
|
|
|
gimp_spin_scale_get_target (GtkWidget *widget,
|
|
|
|
gdouble x,
|
|
|
|
gdouble y)
|
2010-11-02 03:51:13 +08:00
|
|
|
{
|
2017-10-19 02:50:20 +08:00
|
|
|
GtkAllocation allocation;
|
|
|
|
PangoRectangle logical;
|
|
|
|
gint layout_x;
|
|
|
|
gint layout_y;
|
2010-11-02 03:51:13 +08:00
|
|
|
|
2011-03-18 22:07:44 +08:00
|
|
|
gtk_widget_get_allocation (widget, &allocation);
|
2010-11-02 03:51:13 +08:00
|
|
|
gtk_entry_get_layout_offsets (GTK_ENTRY (widget), &layout_x, &layout_y);
|
2012-02-23 05:46:41 +08:00
|
|
|
pango_layout_get_pixel_extents (gtk_entry_get_layout (GTK_ENTRY (widget)),
|
|
|
|
NULL, &logical);
|
2010-11-02 03:51:13 +08:00
|
|
|
|
2017-10-19 03:29:40 +08:00
|
|
|
if (x >= layout_x && x < layout_x + logical.width &&
|
|
|
|
y >= layout_y && y < layout_y + logical.height)
|
2010-11-02 03:51:13 +08:00
|
|
|
{
|
2011-03-18 22:07:44 +08:00
|
|
|
return TARGET_NUMBER;
|
|
|
|
}
|
2017-10-19 03:29:40 +08:00
|
|
|
else if (y >= allocation.height / 2)
|
2011-03-18 22:07:44 +08:00
|
|
|
{
|
|
|
|
return TARGET_LOWER;
|
2010-11-02 03:51:13 +08:00
|
|
|
}
|
|
|
|
|
2011-03-18 22:07:44 +08:00
|
|
|
return TARGET_UPPER;
|
2010-11-19 21:08:37 +08:00
|
|
|
}
|
2010-11-02 03:51:13 +08:00
|
|
|
|
2017-10-19 02:50:20 +08:00
|
|
|
static void
|
|
|
|
gimp_spin_scale_update_target (GtkWidget *widget,
|
2018-02-11 22:44:35 +08:00
|
|
|
GdkWindow *window,
|
2017-10-19 02:50:20 +08:00
|
|
|
gdouble x,
|
|
|
|
gdouble y)
|
|
|
|
{
|
|
|
|
GimpSpinScalePrivate *private = GET_PRIVATE (widget);
|
|
|
|
SpinScaleTarget target;
|
|
|
|
|
|
|
|
target = gimp_spin_scale_get_target (widget, x, y);
|
|
|
|
|
|
|
|
if (target != private->target)
|
|
|
|
{
|
|
|
|
GdkDisplay *display = gtk_widget_get_display (widget);
|
|
|
|
GdkCursor *cursor = NULL;
|
|
|
|
|
|
|
|
private->target = target;
|
|
|
|
|
|
|
|
switch (target)
|
|
|
|
{
|
|
|
|
case TARGET_NUMBER:
|
|
|
|
cursor = gdk_cursor_new_for_display (display, GDK_XTERM);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TARGET_UPPER:
|
|
|
|
cursor = gdk_cursor_new_for_display (display, GDK_SB_UP_ARROW);
|
|
|
|
break;
|
|
|
|
|
|
|
|
case TARGET_LOWER:
|
|
|
|
cursor = gdk_cursor_new_for_display (display, GDK_SB_H_DOUBLE_ARROW);
|
|
|
|
break;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
gdk_window_set_cursor (window, cursor);
|
|
|
|
|
|
|
|
gtk_widget_queue_draw (widget);
|
|
|
|
|
|
|
|
if (cursor)
|
|
|
|
gdk_cursor_unref (cursor);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2018-02-11 22:44:35 +08:00
|
|
|
gimp_spin_scale_clear_target (GtkWidget *widget,
|
|
|
|
GdkWindow *window)
|
2017-10-19 02:50:20 +08:00
|
|
|
{
|
|
|
|
GimpSpinScalePrivate *private = GET_PRIVATE (widget);
|
|
|
|
|
|
|
|
if (private->target != TARGET_NONE)
|
|
|
|
{
|
|
|
|
private->target = TARGET_NONE;
|
|
|
|
|
|
|
|
gdk_window_set_cursor (window, NULL);
|
|
|
|
|
|
|
|
gtk_widget_queue_draw (widget);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-19 03:01:48 +08:00
|
|
|
static void
|
|
|
|
gimp_spin_scale_get_limits (GimpSpinScale *scale,
|
|
|
|
gdouble *lower,
|
|
|
|
gdouble *upper)
|
|
|
|
{
|
|
|
|
GimpSpinScalePrivate *private = GET_PRIVATE (scale);
|
|
|
|
|
|
|
|
if (private->scale_limits_set)
|
|
|
|
{
|
|
|
|
*lower = private->scale_lower;
|
|
|
|
*upper = private->scale_upper;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
GtkSpinButton *spin_button = GTK_SPIN_BUTTON (scale);
|
|
|
|
GtkAdjustment *adjustment = gtk_spin_button_get_adjustment (spin_button);
|
|
|
|
|
|
|
|
*lower = gtk_adjustment_get_lower (adjustment);
|
|
|
|
*upper = gtk_adjustment_get_upper (adjustment);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-02 03:03:39 +08:00
|
|
|
static void
|
2011-03-18 22:42:50 +08:00
|
|
|
gimp_spin_scale_change_value (GtkWidget *widget,
|
|
|
|
gdouble x)
|
2010-11-02 03:03:39 +08:00
|
|
|
{
|
2011-03-18 22:42:50 +08:00
|
|
|
GimpSpinScalePrivate *private = GET_PRIVATE (widget);
|
|
|
|
GtkSpinButton *spin_button = GTK_SPIN_BUTTON (widget);
|
|
|
|
GtkAdjustment *adjustment = gtk_spin_button_get_adjustment (spin_button);
|
|
|
|
GdkWindow *text_window = gtk_entry_get_text_window (GTK_ENTRY (widget));
|
2011-04-19 03:01:48 +08:00
|
|
|
gdouble lower;
|
|
|
|
gdouble upper;
|
2011-03-18 22:42:50 +08:00
|
|
|
gint width;
|
|
|
|
gdouble value;
|
2014-06-19 21:49:27 +08:00
|
|
|
gint digits;
|
2014-06-20 01:00:23 +08:00
|
|
|
gint power = 1;
|
2010-11-02 03:03:39 +08:00
|
|
|
|
2011-04-19 03:01:48 +08:00
|
|
|
gimp_spin_scale_get_limits (GIMP_SPIN_SCALE (widget), &lower, &upper);
|
|
|
|
|
2011-03-17 22:10:17 +08:00
|
|
|
width = gdk_window_get_width (text_window);
|
2010-11-02 03:03:39 +08:00
|
|
|
|
2011-04-21 02:12:21 +08:00
|
|
|
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
|
|
|
|
x = width - x;
|
|
|
|
|
2011-03-18 22:42:50 +08:00
|
|
|
if (private->relative_change)
|
|
|
|
{
|
|
|
|
gdouble diff;
|
|
|
|
gdouble step;
|
2010-11-02 03:03:39 +08:00
|
|
|
|
2011-04-19 03:21:45 +08:00
|
|
|
step = (upper - lower) / width / 10.0;
|
2010-11-02 03:03:39 +08:00
|
|
|
|
2011-04-21 02:12:21 +08:00
|
|
|
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
|
|
|
|
diff = x - (width - private->start_x);
|
|
|
|
else
|
|
|
|
diff = x - private->start_x;
|
2010-11-02 03:03:39 +08:00
|
|
|
|
2011-03-18 22:42:50 +08:00
|
|
|
value = (private->start_value + diff * step);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gdouble fraction;
|
2011-03-18 22:07:44 +08:00
|
|
|
|
2011-03-18 22:42:50 +08:00
|
|
|
fraction = x / (gdouble) width;
|
2012-03-31 07:50:51 +08:00
|
|
|
if (fraction > 0.0)
|
|
|
|
fraction = pow (fraction, private->gamma);
|
2011-03-18 22:07:44 +08:00
|
|
|
|
2011-04-19 03:01:48 +08:00
|
|
|
value = fraction * (upper - lower) + lower;
|
2011-03-18 22:42:50 +08:00
|
|
|
}
|
2011-03-18 22:07:44 +08:00
|
|
|
|
2014-06-19 21:49:27 +08:00
|
|
|
digits = gtk_spin_button_get_digits (spin_button);
|
2014-06-20 01:00:23 +08:00
|
|
|
while (digits--)
|
|
|
|
power *= 10;
|
|
|
|
|
|
|
|
/* round the value to the possible precision of the spinbutton, so
|
|
|
|
* a focus-out will not change the value again, causing inadvertend
|
|
|
|
* adjustment signals.
|
|
|
|
*/
|
|
|
|
value *= power;
|
|
|
|
value = RINT (value);
|
|
|
|
value /= power;
|
2014-06-19 21:49:27 +08:00
|
|
|
|
2011-03-18 22:07:44 +08:00
|
|
|
gtk_adjustment_set_value (adjustment, value);
|
|
|
|
}
|
|
|
|
|
2010-11-02 03:03:39 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_spin_scale_button_press (GtkWidget *widget,
|
|
|
|
GdkEventButton *event)
|
|
|
|
{
|
|
|
|
GimpSpinScalePrivate *private = GET_PRIVATE (widget);
|
|
|
|
|
2011-03-18 22:07:44 +08:00
|
|
|
private->changing_value = FALSE;
|
|
|
|
private->relative_change = FALSE;
|
2017-11-02 21:03:02 +08:00
|
|
|
private->pointer_warp = FALSE;
|
2010-11-02 03:03:39 +08:00
|
|
|
|
|
|
|
if (event->window == gtk_entry_get_text_window (GTK_ENTRY (widget)))
|
|
|
|
{
|
2018-02-11 22:44:35 +08:00
|
|
|
gimp_spin_scale_update_target (widget, event->window,
|
|
|
|
event->x, event->y);
|
2017-10-19 02:50:20 +08:00
|
|
|
|
|
|
|
gtk_widget_queue_draw (widget);
|
|
|
|
|
|
|
|
switch (private->target)
|
2010-11-02 03:03:39 +08:00
|
|
|
{
|
2011-03-18 22:07:44 +08:00
|
|
|
case TARGET_UPPER:
|
2010-11-02 03:03:39 +08:00
|
|
|
private->changing_value = TRUE;
|
|
|
|
|
|
|
|
gtk_widget_grab_focus (widget);
|
|
|
|
|
2011-03-18 22:42:50 +08:00
|
|
|
gimp_spin_scale_change_value (widget, event->x);
|
2010-11-02 03:03:39 +08:00
|
|
|
|
|
|
|
return TRUE;
|
2011-03-18 22:07:44 +08:00
|
|
|
|
|
|
|
case TARGET_LOWER:
|
|
|
|
private->changing_value = TRUE;
|
|
|
|
|
|
|
|
gtk_widget_grab_focus (widget);
|
|
|
|
|
|
|
|
private->relative_change = TRUE;
|
|
|
|
private->start_x = event->x;
|
|
|
|
private->start_value = gtk_adjustment_get_value (gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (widget)));
|
|
|
|
|
app: wrap pointer around screen edges during relative spin scale adjustment
While applying a relative spin scale adjusment (i.e., when dragging
from the lower half of the spin scale), wrap the pointer around the
screen edges (of the current monitor), so that the maximal possible
adjustment amount isn't artifically limited by the screen geometry.
This is especially useful for spin scales in dockables, since
dockables are normally placed near the edge of the screen.
When the mouse is released, move the pointer back to its initial
position (at the beginning of the drag), to allow for subsequent
adjustments.
Unfortunately, moving the pointer programatically isn't supported
on all envrionments (Wayland, Xephyr, ...), and worse yet,
detecting that the pointer failed to move is tricky, so we have to
resort to an ungly hack to maintain the current behavior in this
case. Gah :P
2017-11-02 03:43:19 +08:00
|
|
|
private->start_screen = gdk_event_get_screen ((GdkEvent *) event);
|
|
|
|
private->start_pointer_x = floor (event->x_root);
|
|
|
|
private->start_pointer_y = floor (event->y_root);
|
|
|
|
|
2011-03-18 22:07:44 +08:00
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
default:
|
|
|
|
break;
|
2010-11-02 03:03:39 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return GTK_WIDGET_CLASS (parent_class)->button_press_event (widget, event);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
gimp_spin_scale_button_release (GtkWidget *widget,
|
|
|
|
GdkEventButton *event)
|
|
|
|
{
|
|
|
|
GimpSpinScalePrivate *private = GET_PRIVATE (widget);
|
|
|
|
|
|
|
|
if (private->changing_value)
|
|
|
|
{
|
|
|
|
private->changing_value = FALSE;
|
|
|
|
|
app: wrap pointer around screen edges during relative spin scale adjustment
While applying a relative spin scale adjusment (i.e., when dragging
from the lower half of the spin scale), wrap the pointer around the
screen edges (of the current monitor), so that the maximal possible
adjustment amount isn't artifically limited by the screen geometry.
This is especially useful for spin scales in dockables, since
dockables are normally placed near the edge of the screen.
When the mouse is released, move the pointer back to its initial
position (at the beginning of the drag), to allow for subsequent
adjustments.
Unfortunately, moving the pointer programatically isn't supported
on all envrionments (Wayland, Xephyr, ...), and worse yet,
detecting that the pointer failed to move is tricky, so we have to
resort to an ungly hack to maintain the current behavior in this
case. Gah :P
2017-11-02 03:43:19 +08:00
|
|
|
/* don't change the value if we're in the middle of a pointer warp, since
|
|
|
|
* we didn't adjust start_x yet. see the comment in
|
|
|
|
* gimp_spin_scale_motion_notify().
|
|
|
|
*/
|
|
|
|
if (! private->pointer_warp)
|
|
|
|
gimp_spin_scale_change_value (widget, event->x);
|
|
|
|
|
|
|
|
if (private->relative_change)
|
|
|
|
{
|
|
|
|
gdk_display_warp_pointer (gdk_screen_get_display (private->start_screen),
|
|
|
|
private->start_screen,
|
|
|
|
private->start_pointer_x,
|
|
|
|
private->start_pointer_y);
|
|
|
|
}
|
2010-11-02 03:03:39 +08:00
|
|
|
|
2017-10-19 02:50:20 +08:00
|
|
|
if (private->hover)
|
2018-02-11 22:44:35 +08:00
|
|
|
gimp_spin_scale_update_target (widget, event->window,
|
|
|
|
event->x, event->y);
|
2017-10-19 02:50:20 +08:00
|
|
|
else
|
2018-02-11 22:44:35 +08:00
|
|
|
gimp_spin_scale_clear_target (widget, event->window);
|
2017-10-19 02:50:20 +08:00
|
|
|
|
|
|
|
gtk_widget_queue_draw (widget);
|
|
|
|
|
2010-11-02 03:03:39 +08:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return GTK_WIDGET_CLASS (parent_class)->button_release_event (widget, event);
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2011-04-04 07:10:44 +08:00
|
|
|
gimp_spin_scale_motion_notify (GtkWidget *widget,
|
2010-11-02 03:03:39 +08:00
|
|
|
GdkEventMotion *event)
|
|
|
|
{
|
|
|
|
GimpSpinScalePrivate *private = GET_PRIVATE (widget);
|
|
|
|
|
2012-11-19 03:02:51 +08:00
|
|
|
gdk_event_request_motions (event);
|
|
|
|
|
2017-10-19 02:50:20 +08:00
|
|
|
if (event->window == gtk_entry_get_text_window (GTK_ENTRY (widget)))
|
|
|
|
private->hover = TRUE;
|
|
|
|
|
2010-11-02 03:03:39 +08:00
|
|
|
if (private->changing_value)
|
|
|
|
{
|
app: wrap pointer around screen edges during relative spin scale adjustment
While applying a relative spin scale adjusment (i.e., when dragging
from the lower half of the spin scale), wrap the pointer around the
screen edges (of the current monitor), so that the maximal possible
adjustment amount isn't artifically limited by the screen geometry.
This is especially useful for spin scales in dockables, since
dockables are normally placed near the edge of the screen.
When the mouse is released, move the pointer back to its initial
position (at the beginning of the drag), to allow for subsequent
adjustments.
Unfortunately, moving the pointer programatically isn't supported
on all envrionments (Wayland, Xephyr, ...), and worse yet,
detecting that the pointer failed to move is tricky, so we have to
resort to an ungly hack to maintain the current behavior in this
case. Gah :P
2017-11-02 03:43:19 +08:00
|
|
|
GdkScreen *screen;
|
|
|
|
GdkDisplay *display;
|
|
|
|
gint pointer_x;
|
|
|
|
gint pointer_y;
|
|
|
|
gint monitor;
|
|
|
|
GdkRectangle monitor_geometry;
|
|
|
|
|
|
|
|
screen = gdk_event_get_screen ((GdkEvent *) event);
|
|
|
|
display = gdk_screen_get_display (screen);
|
|
|
|
|
|
|
|
pointer_x = floor (event->x_root);
|
|
|
|
pointer_y = floor (event->y_root);
|
|
|
|
|
|
|
|
monitor = gdk_screen_get_monitor_at_point (screen, pointer_x, pointer_y);
|
|
|
|
gdk_screen_get_monitor_geometry (screen, monitor, &monitor_geometry);
|
|
|
|
|
|
|
|
/* when applying a relative change, we wrap the pointer around the left
|
|
|
|
* and right edges of the current monitor, so that the adjustment is not
|
|
|
|
* limited by the monitor geometry. when the pointer reaches one of the
|
|
|
|
* monitor edges, we move it one pixel away from the opposite edge, so
|
|
|
|
* that it can be subsequently moved in the other direction, and adjust
|
|
|
|
* start_x accordingly.
|
|
|
|
*
|
|
|
|
* unfortunately, we can't rely on gdk_display_warp_pointer() to actually
|
|
|
|
* move the pointer (for example, it doesn't work on wayland), and
|
|
|
|
* there's no easy way to tell whether the pointer moved or not. in
|
|
|
|
* particular, even when the pointer doesn't move, gdk still simulates a
|
|
|
|
* motion event, and reports the "new" pointer position until a real
|
|
|
|
* motion event occurs.
|
|
|
|
*
|
|
|
|
* in order not to erroneously adjust start_x when
|
|
|
|
* gdk_display_warp_pointer() fails, we remember that we *tried* to warp
|
|
|
|
* the pointer, and defer the actual adjustment of start_x until a future
|
|
|
|
* motion event, where the pointer's x coordinate is different from the
|
|
|
|
* one passed to gdk_display_warp_pointer(). when that happens, we
|
|
|
|
* "guess" whether the pointer got warped or not by comparing its x
|
|
|
|
* coordinate to the one passed to gdk_display_warp_pointer(): if their
|
|
|
|
* difference is less than half the monitor width, then we assume the
|
|
|
|
* pointer got warped (otherwise, the user must have very quickly moved
|
|
|
|
* the mouse across half the screen.) yes, this is an ugly ugly hack :)
|
|
|
|
*/
|
|
|
|
|
2017-11-02 21:03:02 +08:00
|
|
|
if (private->pointer_warp)
|
app: wrap pointer around screen edges during relative spin scale adjustment
While applying a relative spin scale adjusment (i.e., when dragging
from the lower half of the spin scale), wrap the pointer around the
screen edges (of the current monitor), so that the maximal possible
adjustment amount isn't artifically limited by the screen geometry.
This is especially useful for spin scales in dockables, since
dockables are normally placed near the edge of the screen.
When the mouse is released, move the pointer back to its initial
position (at the beginning of the drag), to allow for subsequent
adjustments.
Unfortunately, moving the pointer programatically isn't supported
on all envrionments (Wayland, Xephyr, ...), and worse yet,
detecting that the pointer failed to move is tricky, so we have to
resort to an ungly hack to maintain the current behavior in this
case. Gah :P
2017-11-02 03:43:19 +08:00
|
|
|
{
|
|
|
|
if (pointer_x == private->pointer_warp_x)
|
|
|
|
return TRUE;
|
|
|
|
|
|
|
|
private->pointer_warp = FALSE;
|
|
|
|
|
|
|
|
if (ABS (pointer_x - private->pointer_warp_x) < monitor_geometry.width / 2)
|
|
|
|
private->start_x = private->pointer_warp_start_x;
|
|
|
|
}
|
|
|
|
|
2011-03-18 22:42:50 +08:00
|
|
|
gimp_spin_scale_change_value (widget, event->x);
|
2010-11-02 03:03:39 +08:00
|
|
|
|
app: wrap pointer around screen edges during relative spin scale adjustment
While applying a relative spin scale adjusment (i.e., when dragging
from the lower half of the spin scale), wrap the pointer around the
screen edges (of the current monitor), so that the maximal possible
adjustment amount isn't artifically limited by the screen geometry.
This is especially useful for spin scales in dockables, since
dockables are normally placed near the edge of the screen.
When the mouse is released, move the pointer back to its initial
position (at the beginning of the drag), to allow for subsequent
adjustments.
Unfortunately, moving the pointer programatically isn't supported
on all envrionments (Wayland, Xephyr, ...), and worse yet,
detecting that the pointer failed to move is tricky, so we have to
resort to an ungly hack to maintain the current behavior in this
case. Gah :P
2017-11-02 03:43:19 +08:00
|
|
|
if (private->relative_change)
|
|
|
|
{
|
2017-11-02 14:25:11 +08:00
|
|
|
GtkAdjustment *adjustment;
|
|
|
|
gdouble value;
|
|
|
|
gdouble lower;
|
|
|
|
gdouble upper;
|
|
|
|
|
|
|
|
adjustment = gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (widget));
|
|
|
|
|
|
|
|
value = gtk_adjustment_get_value (adjustment);
|
|
|
|
lower = gtk_adjustment_get_lower (adjustment);
|
|
|
|
upper = gtk_adjustment_get_upper (adjustment);
|
|
|
|
|
|
|
|
if (gtk_widget_get_direction (widget) == GTK_TEXT_DIR_RTL)
|
|
|
|
{
|
|
|
|
gdouble temp;
|
|
|
|
|
|
|
|
value = -value;
|
|
|
|
|
|
|
|
temp = lower;
|
|
|
|
lower = -upper;
|
|
|
|
upper = -temp;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (pointer_x <= monitor_geometry.x &&
|
|
|
|
value > lower)
|
app: wrap pointer around screen edges during relative spin scale adjustment
While applying a relative spin scale adjusment (i.e., when dragging
from the lower half of the spin scale), wrap the pointer around the
screen edges (of the current monitor), so that the maximal possible
adjustment amount isn't artifically limited by the screen geometry.
This is especially useful for spin scales in dockables, since
dockables are normally placed near the edge of the screen.
When the mouse is released, move the pointer back to its initial
position (at the beginning of the drag), to allow for subsequent
adjustments.
Unfortunately, moving the pointer programatically isn't supported
on all envrionments (Wayland, Xephyr, ...), and worse yet,
detecting that the pointer failed to move is tricky, so we have to
resort to an ungly hack to maintain the current behavior in this
case. Gah :P
2017-11-02 03:43:19 +08:00
|
|
|
{
|
|
|
|
private->pointer_warp = TRUE;
|
|
|
|
private->pointer_warp_x = (monitor_geometry.width - 1) + pointer_x - 1;
|
|
|
|
private->pointer_warp_start_x = private->start_x + (monitor_geometry.width - 2);
|
|
|
|
}
|
2017-11-02 14:25:11 +08:00
|
|
|
else if (pointer_x >= monitor_geometry.x + (monitor_geometry.width - 1) &&
|
|
|
|
value < upper)
|
app: wrap pointer around screen edges during relative spin scale adjustment
While applying a relative spin scale adjusment (i.e., when dragging
from the lower half of the spin scale), wrap the pointer around the
screen edges (of the current monitor), so that the maximal possible
adjustment amount isn't artifically limited by the screen geometry.
This is especially useful for spin scales in dockables, since
dockables are normally placed near the edge of the screen.
When the mouse is released, move the pointer back to its initial
position (at the beginning of the drag), to allow for subsequent
adjustments.
Unfortunately, moving the pointer programatically isn't supported
on all envrionments (Wayland, Xephyr, ...), and worse yet,
detecting that the pointer failed to move is tricky, so we have to
resort to an ungly hack to maintain the current behavior in this
case. Gah :P
2017-11-02 03:43:19 +08:00
|
|
|
{
|
|
|
|
private->pointer_warp = TRUE;
|
|
|
|
private->pointer_warp_x = pointer_x - (monitor_geometry.width - 1) + 1;
|
|
|
|
private->pointer_warp_start_x = private->start_x - (monitor_geometry.width - 2);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (private->pointer_warp)
|
|
|
|
{
|
|
|
|
gdk_display_warp_pointer (display,
|
|
|
|
screen,
|
|
|
|
private->pointer_warp_x,
|
|
|
|
pointer_y);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-11-02 03:03:39 +08:00
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2010-11-02 03:51:13 +08:00
|
|
|
GTK_WIDGET_CLASS (parent_class)->motion_notify_event (widget, event);
|
|
|
|
|
|
|
|
if (! (event->state &
|
|
|
|
(GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK)) &&
|
2017-10-19 02:50:20 +08:00
|
|
|
private->hover)
|
2010-11-02 03:51:13 +08:00
|
|
|
{
|
2018-02-11 22:44:35 +08:00
|
|
|
gimp_spin_scale_update_target (widget, event->window,
|
|
|
|
event->x, event->y);
|
2010-11-02 03:51:13 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
return FALSE;
|
2010-11-02 03:03:39 +08:00
|
|
|
}
|
|
|
|
|
2011-04-04 07:10:44 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_spin_scale_leave_notify (GtkWidget *widget,
|
|
|
|
GdkEventCrossing *event)
|
|
|
|
{
|
2017-10-19 02:50:20 +08:00
|
|
|
GimpSpinScalePrivate *private = GET_PRIVATE (widget);
|
|
|
|
|
|
|
|
if (event->window == gtk_entry_get_text_window (GTK_ENTRY (widget)))
|
|
|
|
{
|
|
|
|
private->hover = FALSE;
|
|
|
|
|
|
|
|
if (! (event->state &
|
|
|
|
(GDK_BUTTON1_MASK | GDK_BUTTON2_MASK | GDK_BUTTON3_MASK)))
|
|
|
|
{
|
2018-02-11 22:44:35 +08:00
|
|
|
gimp_spin_scale_clear_target (widget, event->window);
|
2017-10-19 02:50:20 +08:00
|
|
|
}
|
|
|
|
}
|
2011-04-04 07:10:44 +08:00
|
|
|
|
|
|
|
return GTK_WIDGET_CLASS (parent_class)->leave_notify_event (widget, event);
|
|
|
|
}
|
|
|
|
|
2013-05-29 04:46:22 +08:00
|
|
|
static void
|
|
|
|
gimp_spin_scale_hierarchy_changed (GtkWidget *widget,
|
|
|
|
GtkWidget *old_toplevel)
|
|
|
|
{
|
|
|
|
GimpSpinScalePrivate *private = GET_PRIVATE (widget);
|
|
|
|
|
|
|
|
gimp_spin_scale_setup_mnemonic (GIMP_SPIN_SCALE (widget),
|
|
|
|
private->mnemonic_keyval);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_spin_scale_screen_changed (GtkWidget *widget,
|
|
|
|
GdkScreen *old_screen)
|
|
|
|
{
|
|
|
|
GimpSpinScale *scale = GIMP_SPIN_SCALE (widget);
|
|
|
|
GimpSpinScalePrivate *private = GET_PRIVATE (scale);
|
|
|
|
GtkSettings *settings;
|
|
|
|
|
2017-07-16 00:38:01 +08:00
|
|
|
g_clear_object (&private->layout);
|
2013-05-29 04:46:22 +08:00
|
|
|
|
|
|
|
if (old_screen)
|
|
|
|
{
|
|
|
|
settings = gtk_settings_get_for_screen (old_screen);
|
|
|
|
|
|
|
|
g_signal_handlers_disconnect_by_func (settings,
|
|
|
|
gimp_spin_scale_settings_notify,
|
|
|
|
scale);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (! gtk_widget_has_screen (widget))
|
|
|
|
return;
|
|
|
|
|
|
|
|
settings = gtk_widget_get_settings (widget);
|
|
|
|
|
|
|
|
g_signal_connect (settings, "notify::gtk-enable-mnemonics",
|
|
|
|
G_CALLBACK (gimp_spin_scale_settings_notify),
|
|
|
|
scale);
|
|
|
|
g_signal_connect (settings, "notify::gtk-enable-accels",
|
|
|
|
G_CALLBACK (gimp_spin_scale_settings_notify),
|
|
|
|
scale);
|
|
|
|
|
|
|
|
gimp_spin_scale_settings_notify (settings, NULL, scale);
|
|
|
|
}
|
|
|
|
|
2010-11-02 03:03:39 +08:00
|
|
|
static void
|
|
|
|
gimp_spin_scale_value_changed (GtkSpinButton *spin_button)
|
|
|
|
{
|
2013-05-29 04:46:22 +08:00
|
|
|
GimpSpinScalePrivate *private = GET_PRIVATE (spin_button);
|
|
|
|
GtkAdjustment *adjustment = gtk_spin_button_get_adjustment (spin_button);
|
|
|
|
gdouble lower;
|
|
|
|
gdouble upper;
|
|
|
|
gdouble value;
|
2011-04-19 03:01:48 +08:00
|
|
|
|
|
|
|
gimp_spin_scale_get_limits (GIMP_SPIN_SCALE (spin_button), &lower, &upper);
|
|
|
|
|
|
|
|
value = CLAMP (gtk_adjustment_get_value (adjustment), lower, upper);
|
2010-11-02 03:03:39 +08:00
|
|
|
|
|
|
|
gtk_entry_set_progress_fraction (GTK_ENTRY (spin_button),
|
2012-04-01 01:41:15 +08:00
|
|
|
pow ((value - lower) / (upper - lower),
|
|
|
|
1.0 / private->gamma));
|
2010-11-02 03:03:39 +08:00
|
|
|
}
|
|
|
|
|
2013-05-29 04:46:22 +08:00
|
|
|
static void
|
|
|
|
gimp_spin_scale_settings_notify (GtkSettings *settings,
|
|
|
|
const GParamSpec *pspec,
|
|
|
|
GimpSpinScale *scale)
|
|
|
|
{
|
|
|
|
GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (scale));
|
|
|
|
|
|
|
|
if (GTK_IS_WINDOW (toplevel))
|
|
|
|
gimp_spin_scale_mnemonics_notify (GTK_WINDOW (toplevel), NULL, scale);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_spin_scale_mnemonics_notify (GtkWindow *window,
|
|
|
|
const GParamSpec *pspec,
|
|
|
|
GimpSpinScale *scale)
|
|
|
|
{
|
|
|
|
GimpSpinScalePrivate *private = GET_PRIVATE (scale);
|
|
|
|
gboolean mnemonics_visible = FALSE;
|
|
|
|
gboolean enable_mnemonics;
|
|
|
|
gboolean auto_mnemonics;
|
|
|
|
|
|
|
|
g_object_get (gtk_widget_get_settings (GTK_WIDGET (scale)),
|
|
|
|
"gtk-enable-mnemonics", &enable_mnemonics,
|
|
|
|
"gtk-auto-mnemonics", &auto_mnemonics,
|
|
|
|
NULL);
|
|
|
|
|
|
|
|
if (enable_mnemonics &&
|
|
|
|
(! auto_mnemonics ||
|
|
|
|
gtk_widget_is_sensitive (GTK_WIDGET (scale))))
|
|
|
|
{
|
|
|
|
g_object_get (window,
|
|
|
|
"mnemonics-visible", &mnemonics_visible,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (private->mnemonics_visible != mnemonics_visible)
|
|
|
|
{
|
|
|
|
private->mnemonics_visible = mnemonics_visible;
|
|
|
|
|
2017-07-16 00:38:01 +08:00
|
|
|
g_clear_object (&private->layout);
|
2013-05-29 04:46:22 +08:00
|
|
|
|
|
|
|
gtk_widget_queue_draw (GTK_WIDGET (scale));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_spin_scale_setup_mnemonic (GimpSpinScale *scale,
|
|
|
|
guint previous_keyval)
|
|
|
|
{
|
|
|
|
GimpSpinScalePrivate *private = GET_PRIVATE (scale);
|
|
|
|
GtkWidget *widget = GTK_WIDGET (scale);
|
|
|
|
GtkWidget *toplevel;
|
|
|
|
|
|
|
|
if (private->mnemonic_window)
|
|
|
|
{
|
|
|
|
g_signal_handlers_disconnect_by_func (private->mnemonic_window,
|
|
|
|
gimp_spin_scale_mnemonics_notify,
|
|
|
|
scale);
|
|
|
|
|
|
|
|
gtk_window_remove_mnemonic (private->mnemonic_window,
|
|
|
|
previous_keyval,
|
|
|
|
widget);
|
|
|
|
private->mnemonic_window = NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
toplevel = gtk_widget_get_toplevel (widget);
|
|
|
|
|
|
|
|
if (gtk_widget_is_toplevel (toplevel) &&
|
|
|
|
private->mnemonic_keyval != GDK_KEY_VoidSymbol)
|
|
|
|
{
|
|
|
|
gtk_window_add_mnemonic (GTK_WINDOW (toplevel),
|
|
|
|
private->mnemonic_keyval,
|
|
|
|
widget);
|
|
|
|
private->mnemonic_window = GTK_WINDOW (toplevel);
|
|
|
|
|
|
|
|
g_signal_connect (toplevel, "notify::mnemonics-visible",
|
|
|
|
G_CALLBACK (gimp_spin_scale_mnemonics_notify),
|
|
|
|
scale);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2011-04-19 03:01:48 +08:00
|
|
|
|
|
|
|
/* public functions */
|
|
|
|
|
2010-11-02 03:03:39 +08:00
|
|
|
GtkWidget *
|
|
|
|
gimp_spin_scale_new (GtkAdjustment *adjustment,
|
|
|
|
const gchar *label,
|
|
|
|
gint digits)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GTK_IS_ADJUSTMENT (adjustment), NULL);
|
|
|
|
|
|
|
|
return g_object_new (GIMP_TYPE_SPIN_SCALE,
|
|
|
|
"adjustment", adjustment,
|
|
|
|
"label", label,
|
|
|
|
"digits", digits,
|
|
|
|
NULL);
|
|
|
|
}
|
2011-04-19 03:01:48 +08:00
|
|
|
|
2013-05-29 04:46:22 +08:00
|
|
|
static gboolean
|
|
|
|
separate_uline_pattern (const gchar *str,
|
|
|
|
guint *accel_key,
|
|
|
|
gchar **new_str,
|
|
|
|
gchar **pattern)
|
|
|
|
{
|
|
|
|
gboolean underscore;
|
|
|
|
const gchar *src;
|
|
|
|
gchar *dest;
|
|
|
|
gchar *pattern_dest;
|
|
|
|
|
|
|
|
*accel_key = GDK_KEY_VoidSymbol;
|
|
|
|
*new_str = g_new (gchar, strlen (str) + 1);
|
|
|
|
*pattern = g_new (gchar, g_utf8_strlen (str, -1) + 1);
|
|
|
|
|
|
|
|
underscore = FALSE;
|
|
|
|
|
|
|
|
src = str;
|
|
|
|
dest = *new_str;
|
|
|
|
pattern_dest = *pattern;
|
|
|
|
|
|
|
|
while (*src)
|
|
|
|
{
|
|
|
|
gunichar c;
|
|
|
|
const gchar *next_src;
|
|
|
|
|
|
|
|
c = g_utf8_get_char (src);
|
|
|
|
if (c == (gunichar)-1)
|
|
|
|
{
|
|
|
|
g_warning ("Invalid input string");
|
|
|
|
g_free (*new_str);
|
|
|
|
g_free (*pattern);
|
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
next_src = g_utf8_next_char (src);
|
|
|
|
|
|
|
|
if (underscore)
|
|
|
|
{
|
|
|
|
if (c == '_')
|
|
|
|
*pattern_dest++ = ' ';
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*pattern_dest++ = '_';
|
|
|
|
if (*accel_key == GDK_KEY_VoidSymbol)
|
|
|
|
*accel_key = gdk_keyval_to_lower (gdk_unicode_to_keyval (c));
|
|
|
|
}
|
|
|
|
|
|
|
|
while (src < next_src)
|
|
|
|
*dest++ = *src++;
|
|
|
|
|
|
|
|
underscore = FALSE;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
if (c == '_')
|
|
|
|
{
|
|
|
|
underscore = TRUE;
|
|
|
|
src = next_src;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
while (src < next_src)
|
|
|
|
*dest++ = *src++;
|
|
|
|
|
|
|
|
*pattern_dest++ = ' ';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
*dest = 0;
|
|
|
|
*pattern_dest = 0;
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
2013-05-28 21:29:44 +08:00
|
|
|
void
|
|
|
|
gimp_spin_scale_set_label (GimpSpinScale *scale,
|
|
|
|
const gchar *label)
|
|
|
|
{
|
|
|
|
GimpSpinScalePrivate *private;
|
2013-05-29 04:46:22 +08:00
|
|
|
guint accel_key = GDK_KEY_VoidSymbol;
|
|
|
|
gchar *text = NULL;
|
|
|
|
gchar *pattern = NULL;
|
2013-05-28 21:29:44 +08:00
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_SPIN_SCALE (scale));
|
|
|
|
|
|
|
|
private = GET_PRIVATE (scale);
|
|
|
|
|
|
|
|
if (label == private->label)
|
|
|
|
return;
|
|
|
|
|
2013-05-29 04:46:22 +08:00
|
|
|
if (label && ! separate_uline_pattern (label, &accel_key, &text, &pattern))
|
|
|
|
return;
|
|
|
|
|
2013-05-28 21:29:44 +08:00
|
|
|
g_free (private->label);
|
|
|
|
private->label = g_strdup (label);
|
|
|
|
|
2013-05-29 04:46:22 +08:00
|
|
|
g_free (private->label_text);
|
2014-10-07 02:34:22 +08:00
|
|
|
private->label_text = text; /* don't dup */
|
2013-05-29 04:46:22 +08:00
|
|
|
|
|
|
|
g_free (private->label_pattern);
|
2014-10-07 02:34:22 +08:00
|
|
|
private->label_pattern = pattern; /* don't dup */
|
2013-05-29 04:46:22 +08:00
|
|
|
|
|
|
|
if (private->mnemonic_keyval != accel_key)
|
|
|
|
{
|
|
|
|
guint previous = private->mnemonic_keyval;
|
|
|
|
|
|
|
|
private->mnemonic_keyval = accel_key;
|
|
|
|
|
|
|
|
gimp_spin_scale_setup_mnemonic (scale, previous);
|
|
|
|
}
|
|
|
|
|
2017-07-16 00:38:01 +08:00
|
|
|
g_clear_object (&private->layout);
|
2013-05-28 21:29:44 +08:00
|
|
|
|
|
|
|
gtk_widget_queue_resize (GTK_WIDGET (scale));
|
|
|
|
|
|
|
|
g_object_notify (G_OBJECT (scale), "label");
|
|
|
|
}
|
|
|
|
|
|
|
|
const gchar *
|
|
|
|
gimp_spin_scale_get_label (GimpSpinScale *scale)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_SPIN_SCALE (scale), NULL);
|
|
|
|
|
|
|
|
return GET_PRIVATE (scale)->label;
|
|
|
|
}
|
|
|
|
|
2011-04-19 03:01:48 +08:00
|
|
|
void
|
|
|
|
gimp_spin_scale_set_scale_limits (GimpSpinScale *scale,
|
|
|
|
gdouble lower,
|
|
|
|
gdouble upper)
|
|
|
|
{
|
|
|
|
GimpSpinScalePrivate *private;
|
|
|
|
GtkSpinButton *spin_button;
|
|
|
|
GtkAdjustment *adjustment;
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_SPIN_SCALE (scale));
|
|
|
|
|
|
|
|
private = GET_PRIVATE (scale);
|
|
|
|
spin_button = GTK_SPIN_BUTTON (scale);
|
|
|
|
adjustment = gtk_spin_button_get_adjustment (spin_button);
|
|
|
|
|
|
|
|
g_return_if_fail (lower >= gtk_adjustment_get_lower (adjustment));
|
|
|
|
g_return_if_fail (upper <= gtk_adjustment_get_upper (adjustment));
|
|
|
|
|
|
|
|
private->scale_limits_set = TRUE;
|
|
|
|
private->scale_lower = lower;
|
|
|
|
private->scale_upper = upper;
|
2012-03-31 04:34:59 +08:00
|
|
|
private->gamma = 1.0;
|
2011-04-19 03:01:48 +08:00
|
|
|
|
|
|
|
gimp_spin_scale_value_changed (spin_button);
|
|
|
|
}
|
|
|
|
|
2012-03-31 04:34:59 +08:00
|
|
|
void
|
2013-05-28 21:19:04 +08:00
|
|
|
gimp_spin_scale_unset_scale_limits (GimpSpinScale *scale)
|
2012-03-31 04:34:59 +08:00
|
|
|
{
|
|
|
|
GimpSpinScalePrivate *private;
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_SPIN_SCALE (scale));
|
|
|
|
|
|
|
|
private = GET_PRIVATE (scale);
|
|
|
|
|
2013-05-28 21:19:04 +08:00
|
|
|
private->scale_limits_set = FALSE;
|
|
|
|
private->scale_lower = 0.0;
|
|
|
|
private->scale_upper = 0.0;
|
2012-03-31 06:44:41 +08:00
|
|
|
|
|
|
|
gimp_spin_scale_value_changed (GTK_SPIN_BUTTON (scale));
|
2012-03-31 04:34:59 +08:00
|
|
|
}
|
|
|
|
|
2013-05-28 21:19:04 +08:00
|
|
|
gboolean
|
|
|
|
gimp_spin_scale_get_scale_limits (GimpSpinScale *scale,
|
|
|
|
gdouble *lower,
|
|
|
|
gdouble *upper)
|
2012-03-31 04:34:59 +08:00
|
|
|
{
|
|
|
|
GimpSpinScalePrivate *private;
|
|
|
|
|
2013-05-28 21:19:04 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_SPIN_SCALE (scale), FALSE);
|
2012-03-31 04:34:59 +08:00
|
|
|
|
|
|
|
private = GET_PRIVATE (scale);
|
|
|
|
|
2013-05-28 21:19:04 +08:00
|
|
|
if (lower)
|
|
|
|
*lower = private->scale_lower;
|
|
|
|
|
|
|
|
if (upper)
|
|
|
|
*upper = private->scale_upper;
|
|
|
|
|
|
|
|
return private->scale_limits_set;
|
2012-03-31 04:34:59 +08:00
|
|
|
}
|
|
|
|
|
2011-04-19 03:01:48 +08:00
|
|
|
void
|
2013-05-28 21:19:04 +08:00
|
|
|
gimp_spin_scale_set_gamma (GimpSpinScale *scale,
|
|
|
|
gdouble gamma)
|
2011-04-19 03:01:48 +08:00
|
|
|
{
|
|
|
|
GimpSpinScalePrivate *private;
|
|
|
|
|
|
|
|
g_return_if_fail (GIMP_IS_SPIN_SCALE (scale));
|
|
|
|
|
|
|
|
private = GET_PRIVATE (scale);
|
|
|
|
|
2013-05-28 21:19:04 +08:00
|
|
|
private->gamma = gamma;
|
2011-04-19 03:01:48 +08:00
|
|
|
|
|
|
|
gimp_spin_scale_value_changed (GTK_SPIN_BUTTON (scale));
|
|
|
|
}
|
|
|
|
|
2013-05-28 21:19:04 +08:00
|
|
|
gdouble
|
|
|
|
gimp_spin_scale_get_gamma (GimpSpinScale *scale)
|
2011-04-19 03:01:48 +08:00
|
|
|
{
|
2013-05-28 21:19:04 +08:00
|
|
|
g_return_val_if_fail (GIMP_IS_SPIN_SCALE (scale), 1.0);
|
2011-04-19 03:01:48 +08:00
|
|
|
|
2013-05-28 21:29:44 +08:00
|
|
|
return GET_PRIVATE (scale)->gamma;
|
2011-04-19 03:01:48 +08:00
|
|
|
}
|