2008-05-27 05:20:16 +08:00
|
|
|
/* LIBGIMP - The GIMP Library
|
|
|
|
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
|
|
|
*
|
2009-01-18 06:28:01 +08:00
|
|
|
* This library is free software: you can redistribute it and/or
|
2008-05-27 05:20:16 +08:00
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
2009-01-18 06:28:01 +08:00
|
|
|
* version 3 of the License, or (at your option) any later version.
|
2008-05-27 05:20:16 +08:00
|
|
|
*
|
|
|
|
* This library 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
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2009-01-18 06:28:01 +08:00
|
|
|
* License along with this library. If not, see
|
2018-07-12 05:27:07 +08:00
|
|
|
* <https://www.gnu.org/licenses/>.
|
2008-05-27 05:20:16 +08:00
|
|
|
*/
|
|
|
|
|
|
|
|
#include "config.h"
|
|
|
|
|
|
|
|
#include <gtk/gtk.h>
|
2024-07-27 00:21:01 +08:00
|
|
|
#include <string.h>
|
2008-05-27 05:20:16 +08:00
|
|
|
|
2008-05-28 19:49:24 +08:00
|
|
|
#include "libgimpbase/gimpbase.h"
|
2008-08-29 18:25:29 +08:00
|
|
|
#include "libgimpmath/gimpmath.h"
|
2008-05-28 19:49:24 +08:00
|
|
|
|
2008-05-27 05:20:16 +08:00
|
|
|
#include "gimpwidgetstypes.h"
|
|
|
|
|
|
|
|
#include "gimpruler.h"
|
|
|
|
|
|
|
|
|
2010-07-06 00:01:28 +08:00
|
|
|
/**
|
|
|
|
* SECTION: gimpruler
|
|
|
|
* @title: GimpRuler
|
|
|
|
* @short_description: A ruler widget with configurable unit and orientation.
|
|
|
|
*
|
|
|
|
* A ruler widget with configurable unit and orientation.
|
|
|
|
**/
|
|
|
|
|
|
|
|
|
2015-09-06 12:05:32 +08:00
|
|
|
#define MINIMUM_INCR 5
|
|
|
|
#define IMMEDIATE_REDRAW_THRESHOLD 20
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2008-05-27 05:20:16 +08:00
|
|
|
|
|
|
|
enum
|
|
|
|
{
|
|
|
|
PROP_0,
|
2008-08-29 18:25:29 +08:00
|
|
|
PROP_ORIENTATION,
|
2008-05-28 19:49:24 +08:00
|
|
|
PROP_UNIT,
|
2008-05-27 05:20:16 +08:00
|
|
|
PROP_LOWER,
|
|
|
|
PROP_UPPER,
|
|
|
|
PROP_POSITION,
|
2020-12-30 05:03:26 +08:00
|
|
|
PROP_MAX_SIZE,
|
|
|
|
N_PROPS
|
2008-05-27 05:20:16 +08:00
|
|
|
};
|
2020-12-30 05:03:26 +08:00
|
|
|
static GParamSpec *object_props[N_PROPS] = { NULL, };
|
2008-05-27 05:20:16 +08:00
|
|
|
|
2008-08-29 18:25:29 +08:00
|
|
|
|
|
|
|
/* All distances below are in 1/72nd's of an inch. (According to
|
|
|
|
* Adobe that's a point, but points are really 1/72.27 in.)
|
|
|
|
*/
|
2024-07-27 00:21:01 +08:00
|
|
|
struct _GimpRuler
|
2008-08-29 18:25:29 +08:00
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
GtkWidget parent_instance;
|
|
|
|
|
2010-12-18 05:49:55 +08:00
|
|
|
GtkOrientation orientation;
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-26 02:55:21 +08:00
|
|
|
GimpUnit *unit;
|
2010-12-18 05:49:55 +08:00
|
|
|
gdouble lower;
|
|
|
|
gdouble upper;
|
|
|
|
gdouble position;
|
|
|
|
gdouble max_size;
|
|
|
|
|
2011-04-10 08:00:40 +08:00
|
|
|
GdkWindow *input_window;
|
2010-12-18 05:49:55 +08:00
|
|
|
cairo_surface_t *backing_store;
|
2015-08-12 04:20:59 +08:00
|
|
|
gboolean backing_store_valid;
|
2015-09-06 12:05:32 +08:00
|
|
|
GdkRectangle last_pos_rect;
|
|
|
|
guint pos_redraw_idle_id;
|
2010-12-18 05:49:55 +08:00
|
|
|
PangoLayout *layout;
|
|
|
|
|
2011-01-21 03:23:14 +08:00
|
|
|
GList *track_widgets;
|
2018-05-03 18:51:36 +08:00
|
|
|
};
|
2008-08-29 18:25:29 +08:00
|
|
|
|
|
|
|
|
2018-02-12 19:20:32 +08:00
|
|
|
typedef struct
|
2008-08-29 18:25:29 +08:00
|
|
|
{
|
2008-10-04 06:11:15 +08:00
|
|
|
const gdouble ruler_scale[16];
|
|
|
|
const gint subdivide[5];
|
2018-02-12 19:20:32 +08:00
|
|
|
} RulerMetric;
|
|
|
|
|
|
|
|
static const RulerMetric ruler_metric_decimal =
|
2008-08-29 18:25:29 +08:00
|
|
|
{
|
|
|
|
{ 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000, 25000, 50000, 100000 },
|
|
|
|
{ 1, 5, 10, 50, 100 }
|
|
|
|
};
|
|
|
|
|
2018-02-12 19:20:32 +08:00
|
|
|
static const RulerMetric ruler_metric_inches =
|
|
|
|
{
|
2019-06-23 22:29:47 +08:00
|
|
|
/* 12 inch = 1 foot; 36 inch = 1 yard; 72 inchs = 1 fathom */
|
|
|
|
{ 1, 2, 6, 12, 36, 72, 100, 250, 500, 1000, 2500, 5000, 10000, 25000, 50000, 100000 },
|
|
|
|
|
|
|
|
/* Inches are divided by multiples of 2. */
|
2019-06-24 01:07:32 +08:00
|
|
|
{ 1, 2, 4, 8, 16 }
|
2018-02-12 19:20:32 +08:00
|
|
|
};
|
|
|
|
|
2018-02-28 03:28:50 +08:00
|
|
|
static const RulerMetric ruler_metric_feet =
|
|
|
|
{
|
2019-06-23 22:29:47 +08:00
|
|
|
/* 3 feet = 1 yard; 6 feet = 1 fathom */
|
2019-06-24 01:07:32 +08:00
|
|
|
{ 1, 3, 6, 12, 36, 72, 100, 250, 500, 1000, 2500, 5000, 10000, 25000, 50000, 100000 },
|
2019-06-23 22:29:47 +08:00
|
|
|
|
2019-06-24 01:07:32 +08:00
|
|
|
/* 1 foot = 12 inches, so let's divide up to 12, */
|
2019-06-23 22:29:47 +08:00
|
|
|
{ 1, 3, 6, 12,
|
2019-06-24 01:07:32 +08:00
|
|
|
/* then divide the inch by 2. */
|
|
|
|
24 }
|
2018-02-28 03:28:50 +08:00
|
|
|
};
|
|
|
|
|
|
|
|
static const RulerMetric ruler_metric_yards =
|
|
|
|
{
|
2019-06-23 22:29:47 +08:00
|
|
|
/* 1 fathom = 2 yards. Should we go back to base-10 digits? */
|
|
|
|
{ 1, 2, 5, 10, 25, 50, 100, 250, 500, 1000, 2500, 5000, 10000, 25000, 50000, 100000 },
|
|
|
|
|
|
|
|
/* 1 yard = 3 feet = 36 inches. */
|
2019-06-24 01:07:32 +08:00
|
|
|
{ 1, 3, 6, 12, 36 }
|
2018-02-28 03:28:50 +08:00
|
|
|
};
|
|
|
|
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2015-09-27 19:45:13 +08:00
|
|
|
static void gimp_ruler_dispose (GObject *object);
|
|
|
|
static void gimp_ruler_set_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec);
|
|
|
|
static void gimp_ruler_get_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec);
|
|
|
|
|
|
|
|
static void gimp_ruler_realize (GtkWidget *widget);
|
|
|
|
static void gimp_ruler_unrealize (GtkWidget *widget);
|
|
|
|
static void gimp_ruler_map (GtkWidget *widget);
|
|
|
|
static void gimp_ruler_unmap (GtkWidget *widget);
|
|
|
|
static void gimp_ruler_size_allocate (GtkWidget *widget,
|
|
|
|
GtkAllocation *allocation);
|
2010-10-28 19:26:39 +08:00
|
|
|
static void gimp_ruler_get_preferred_width (GtkWidget *widget,
|
|
|
|
gint *minimum_width,
|
|
|
|
gint *natural_width);
|
|
|
|
static void gimp_ruler_get_preferred_height (GtkWidget *widget,
|
|
|
|
gint *minimum_height,
|
|
|
|
gint *natural_height);
|
2010-12-21 16:32:10 +08:00
|
|
|
static void gimp_ruler_style_updated (GtkWidget *widget);
|
2015-09-27 19:45:13 +08:00
|
|
|
static gboolean gimp_ruler_motion_notify (GtkWidget *widget,
|
|
|
|
GdkEventMotion *event);
|
2010-10-20 00:59:50 +08:00
|
|
|
static gboolean gimp_ruler_draw (GtkWidget *widget,
|
|
|
|
cairo_t *cr);
|
2015-09-27 19:45:13 +08:00
|
|
|
|
|
|
|
static void gimp_ruler_draw_ticks (GimpRuler *ruler);
|
|
|
|
static GdkRectangle gimp_ruler_get_pos_rect (GimpRuler *ruler,
|
|
|
|
gdouble position);
|
|
|
|
static gboolean gimp_ruler_idle_queue_pos_redraw (gpointer data);
|
|
|
|
static void gimp_ruler_queue_pos_redraw (GimpRuler *ruler);
|
|
|
|
static void gimp_ruler_draw_pos (GimpRuler *ruler,
|
|
|
|
cairo_t *cr);
|
|
|
|
static void gimp_ruler_make_pixmap (GimpRuler *ruler);
|
|
|
|
static PangoLayout * gimp_ruler_get_layout (GtkWidget *widget,
|
|
|
|
const gchar *text);
|
2018-02-12 19:20:32 +08:00
|
|
|
static const RulerMetric *
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-26 02:55:21 +08:00
|
|
|
gimp_ruler_get_metric (GimpUnit *unit);
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2008-05-27 05:20:16 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
G_DEFINE_TYPE (GimpRuler, gimp_ruler, GTK_TYPE_WIDGET)
|
2008-05-27 05:20:16 +08:00
|
|
|
|
2011-01-21 03:23:14 +08:00
|
|
|
#define parent_class gimp_ruler_parent_class
|
2008-05-27 05:20:16 +08:00
|
|
|
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_ruler_class_init (GimpRulerClass *klass)
|
|
|
|
{
|
|
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass);
|
|
|
|
|
2010-10-28 19:26:39 +08:00
|
|
|
object_class->dispose = gimp_ruler_dispose;
|
|
|
|
object_class->set_property = gimp_ruler_set_property;
|
|
|
|
object_class->get_property = gimp_ruler_get_property;
|
|
|
|
|
|
|
|
widget_class->realize = gimp_ruler_realize;
|
|
|
|
widget_class->unrealize = gimp_ruler_unrealize;
|
|
|
|
widget_class->map = gimp_ruler_map;
|
|
|
|
widget_class->unmap = gimp_ruler_unmap;
|
|
|
|
widget_class->get_preferred_width = gimp_ruler_get_preferred_width;
|
|
|
|
widget_class->get_preferred_height = gimp_ruler_get_preferred_height;
|
|
|
|
widget_class->size_allocate = gimp_ruler_size_allocate;
|
2010-12-21 16:32:10 +08:00
|
|
|
widget_class->style_updated = gimp_ruler_style_updated;
|
2010-10-28 19:26:39 +08:00
|
|
|
widget_class->motion_notify_event = gimp_ruler_motion_notify;
|
|
|
|
widget_class->draw = gimp_ruler_draw;
|
2008-05-27 05:20:16 +08:00
|
|
|
|
2020-12-30 05:03:26 +08:00
|
|
|
object_props[PROP_ORIENTATION] = g_param_spec_enum ("orientation",
|
2008-08-29 18:25:29 +08:00
|
|
|
"Orientation",
|
|
|
|
"The orientation of the ruler",
|
|
|
|
GTK_TYPE_ORIENTATION,
|
|
|
|
GTK_ORIENTATION_HORIZONTAL,
|
2020-12-30 05:03:26 +08:00
|
|
|
GIMP_PARAM_READWRITE);
|
|
|
|
|
|
|
|
object_props[PROP_UNIT] = gimp_param_spec_unit ("unit",
|
|
|
|
"Unit",
|
|
|
|
"Unit of ruler",
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-26 02:55:21 +08:00
|
|
|
TRUE, TRUE, gimp_unit_pixel (),
|
2020-12-30 05:03:26 +08:00
|
|
|
GIMP_PARAM_READWRITE);
|
|
|
|
|
|
|
|
object_props[PROP_LOWER] = g_param_spec_double ("lower",
|
|
|
|
"Lower",
|
|
|
|
"Lower limit of ruler",
|
|
|
|
-G_MAXDOUBLE,
|
|
|
|
G_MAXDOUBLE,
|
|
|
|
0.0,
|
|
|
|
GIMP_PARAM_READWRITE);
|
|
|
|
|
|
|
|
object_props[PROP_UPPER] = g_param_spec_double ("upper",
|
|
|
|
"Upper",
|
|
|
|
"Upper limit of ruler",
|
|
|
|
-G_MAXDOUBLE,
|
|
|
|
G_MAXDOUBLE,
|
|
|
|
0.0,
|
|
|
|
GIMP_PARAM_READWRITE);
|
|
|
|
|
|
|
|
object_props[PROP_POSITION] = g_param_spec_double ("position",
|
|
|
|
"Position",
|
|
|
|
"Position of mark on the ruler",
|
|
|
|
-G_MAXDOUBLE,
|
|
|
|
G_MAXDOUBLE,
|
|
|
|
0.0,
|
|
|
|
GIMP_PARAM_READWRITE);
|
|
|
|
|
|
|
|
object_props[PROP_MAX_SIZE] = g_param_spec_double ("max-size",
|
|
|
|
"Max Size",
|
|
|
|
"Maximum size of the ruler",
|
|
|
|
-G_MAXDOUBLE,
|
|
|
|
G_MAXDOUBLE,
|
|
|
|
0.0,
|
|
|
|
GIMP_PARAM_READWRITE);
|
|
|
|
|
|
|
|
g_object_class_install_properties (object_class, N_PROPS, object_props);
|
2008-10-04 06:11:15 +08:00
|
|
|
|
2018-05-01 06:17:27 +08:00
|
|
|
gtk_widget_class_set_css_name (widget_class, "GimpRuler");
|
2008-05-27 05:20:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_ruler_init (GimpRuler *ruler)
|
|
|
|
{
|
2018-05-03 18:51:36 +08:00
|
|
|
gtk_widget_set_has_window (GTK_WIDGET (ruler), FALSE);
|
2015-09-06 12:05:32 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->orientation = GTK_ORIENTATION_HORIZONTAL;
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-26 02:55:21 +08:00
|
|
|
ruler->unit = gimp_unit_pixel ();
|
2008-05-27 05:20:16 +08:00
|
|
|
}
|
|
|
|
|
2011-01-21 03:23:14 +08:00
|
|
|
static void
|
|
|
|
gimp_ruler_dispose (GObject *object)
|
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
GimpRuler *ruler = GIMP_RULER (object);
|
2011-01-21 03:23:14 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
while (ruler->track_widgets)
|
|
|
|
gimp_ruler_remove_track_widget (ruler, ruler->track_widgets->data);
|
2011-01-21 03:23:14 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->pos_redraw_idle_id)
|
2015-09-06 12:05:32 +08:00
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
g_source_remove (ruler->pos_redraw_idle_id);
|
|
|
|
ruler->pos_redraw_idle_id = 0;
|
2015-09-06 12:05:32 +08:00
|
|
|
}
|
|
|
|
|
2015-09-07 05:41:09 +08:00
|
|
|
G_OBJECT_CLASS (parent_class)->dispose (object);
|
2015-09-06 12:05:32 +08:00
|
|
|
}
|
|
|
|
|
2008-05-27 05:20:16 +08:00
|
|
|
static void
|
|
|
|
gimp_ruler_set_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
const GValue *value,
|
|
|
|
GParamSpec *pspec)
|
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
GimpRuler *ruler = GIMP_RULER (object);
|
2008-05-27 05:20:16 +08:00
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
2008-08-29 18:25:29 +08:00
|
|
|
case PROP_ORIENTATION:
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->orientation = g_value_get_enum (value);
|
2008-10-09 02:47:13 +08:00
|
|
|
gtk_widget_queue_resize (GTK_WIDGET (ruler));
|
2008-08-29 18:25:29 +08:00
|
|
|
break;
|
2008-10-05 07:13:44 +08:00
|
|
|
|
2008-05-28 19:49:24 +08:00
|
|
|
case PROP_UNIT:
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-26 02:55:21 +08:00
|
|
|
gimp_ruler_set_unit (ruler, g_value_get_object (value));
|
2008-05-28 19:49:24 +08:00
|
|
|
break;
|
2008-10-05 07:13:44 +08:00
|
|
|
|
2008-05-27 05:20:16 +08:00
|
|
|
case PROP_LOWER:
|
2008-05-28 18:18:43 +08:00
|
|
|
gimp_ruler_set_range (ruler,
|
|
|
|
g_value_get_double (value),
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->upper,
|
|
|
|
ruler->max_size);
|
2008-05-27 05:20:16 +08:00
|
|
|
break;
|
|
|
|
case PROP_UPPER:
|
2008-05-28 18:18:43 +08:00
|
|
|
gimp_ruler_set_range (ruler,
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->lower,
|
2008-05-28 18:18:43 +08:00
|
|
|
g_value_get_double (value),
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->max_size);
|
2008-05-27 05:20:16 +08:00
|
|
|
break;
|
2008-10-05 07:13:44 +08:00
|
|
|
|
2008-05-27 05:20:16 +08:00
|
|
|
case PROP_POSITION:
|
2008-05-28 18:18:43 +08:00
|
|
|
gimp_ruler_set_position (ruler, g_value_get_double (value));
|
2008-05-27 05:20:16 +08:00
|
|
|
break;
|
2008-10-05 07:13:44 +08:00
|
|
|
|
2008-05-27 05:20:16 +08:00
|
|
|
case PROP_MAX_SIZE:
|
2008-05-28 18:18:43 +08:00
|
|
|
gimp_ruler_set_range (ruler,
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->lower,
|
|
|
|
ruler->upper,
|
2008-05-28 18:18:43 +08:00
|
|
|
g_value_get_double (value));
|
2008-05-27 05:20:16 +08:00
|
|
|
break;
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2008-05-27 05:20:16 +08:00
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
2008-10-09 02:47:13 +08:00
|
|
|
gimp_ruler_get_property (GObject *object,
|
|
|
|
guint prop_id,
|
|
|
|
GValue *value,
|
|
|
|
GParamSpec *pspec)
|
2008-05-27 05:20:16 +08:00
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
GimpRuler *ruler = GIMP_RULER (object);
|
2008-05-27 05:20:16 +08:00
|
|
|
|
|
|
|
switch (prop_id)
|
|
|
|
{
|
2008-08-29 18:25:29 +08:00
|
|
|
case PROP_ORIENTATION:
|
2024-07-27 00:21:01 +08:00
|
|
|
g_value_set_enum (value, ruler->orientation);
|
2008-08-29 18:25:29 +08:00
|
|
|
break;
|
2008-10-05 07:13:44 +08:00
|
|
|
|
2008-05-28 19:49:24 +08:00
|
|
|
case PROP_UNIT:
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-26 02:55:21 +08:00
|
|
|
g_value_set_object (value, ruler->unit);
|
2008-05-28 19:49:24 +08:00
|
|
|
break;
|
2008-10-05 07:13:44 +08:00
|
|
|
|
2008-05-27 05:20:16 +08:00
|
|
|
case PROP_LOWER:
|
2024-07-27 00:21:01 +08:00
|
|
|
g_value_set_double (value, ruler->lower);
|
2008-05-27 05:20:16 +08:00
|
|
|
break;
|
2008-10-05 07:13:44 +08:00
|
|
|
|
2008-05-27 05:20:16 +08:00
|
|
|
case PROP_UPPER:
|
2024-07-27 00:21:01 +08:00
|
|
|
g_value_set_double (value, ruler->upper);
|
2008-05-27 05:20:16 +08:00
|
|
|
break;
|
2008-10-05 07:13:44 +08:00
|
|
|
|
2008-05-27 05:20:16 +08:00
|
|
|
case PROP_POSITION:
|
2024-07-27 00:21:01 +08:00
|
|
|
g_value_set_double (value, ruler->position);
|
2008-05-27 05:20:16 +08:00
|
|
|
break;
|
2008-10-05 07:13:44 +08:00
|
|
|
|
2008-05-27 05:20:16 +08:00
|
|
|
case PROP_MAX_SIZE:
|
2024-07-27 00:21:01 +08:00
|
|
|
g_value_set_double (value, ruler->max_size);
|
2008-05-27 05:20:16 +08:00
|
|
|
break;
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2008-05-27 05:20:16 +08:00
|
|
|
default:
|
|
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-08-29 18:25:29 +08:00
|
|
|
/**
|
2008-08-29 18:43:21 +08:00
|
|
|
* gimp_ruler_new:
|
2008-08-29 18:25:29 +08:00
|
|
|
* @orientation: the ruler's orientation.
|
|
|
|
*
|
|
|
|
* Creates a new ruler.
|
|
|
|
*
|
2019-08-03 06:10:14 +08:00
|
|
|
* Returns: a new #GimpRuler widget.
|
2008-08-29 18:25:29 +08:00
|
|
|
*
|
2015-06-01 03:18:09 +08:00
|
|
|
* Since: 2.8
|
2008-08-29 18:25:29 +08:00
|
|
|
**/
|
|
|
|
GtkWidget *
|
|
|
|
gimp_ruler_new (GtkOrientation orientation)
|
|
|
|
{
|
|
|
|
return g_object_new (GIMP_TYPE_RULER,
|
|
|
|
"orientation", orientation,
|
|
|
|
NULL);
|
|
|
|
}
|
|
|
|
|
2011-01-21 03:23:14 +08:00
|
|
|
static void
|
|
|
|
gimp_ruler_update_position (GimpRuler *ruler,
|
|
|
|
gdouble x,
|
|
|
|
gdouble y)
|
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
GtkAllocation allocation;
|
|
|
|
gdouble lower = 0;
|
|
|
|
gdouble upper = 0;
|
2011-01-21 03:23:14 +08:00
|
|
|
|
|
|
|
gtk_widget_get_allocation (GTK_WIDGET (ruler), &allocation);
|
|
|
|
gimp_ruler_get_range (ruler, &lower, &upper, NULL);
|
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->orientation == GTK_ORIENTATION_HORIZONTAL)
|
2011-01-21 03:23:14 +08:00
|
|
|
{
|
|
|
|
gimp_ruler_set_position (ruler,
|
|
|
|
lower +
|
|
|
|
(upper - lower) * x / allocation.width);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gimp_ruler_set_position (ruler,
|
|
|
|
lower +
|
|
|
|
(upper - lower) * y / allocation.height);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/* Returns TRUE if a translation should be done */
|
|
|
|
static gboolean
|
|
|
|
gtk_widget_get_translation_to_window (GtkWidget *widget,
|
|
|
|
GdkWindow *window,
|
|
|
|
int *x,
|
|
|
|
int *y)
|
|
|
|
{
|
|
|
|
GdkWindow *w, *widget_window;
|
|
|
|
|
|
|
|
if (! gtk_widget_get_has_window (widget))
|
|
|
|
{
|
|
|
|
GtkAllocation allocation;
|
|
|
|
|
|
|
|
gtk_widget_get_allocation (widget, &allocation);
|
|
|
|
|
|
|
|
*x = -allocation.x;
|
|
|
|
*y = -allocation.y;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
*x = 0;
|
|
|
|
*y = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
widget_window = gtk_widget_get_window (widget);
|
|
|
|
|
|
|
|
for (w = window;
|
|
|
|
w && w != widget_window;
|
|
|
|
w = gdk_window_get_effective_parent (w))
|
|
|
|
{
|
|
|
|
gdouble px, py;
|
|
|
|
|
|
|
|
gdk_window_coords_to_parent (w, *x, *y, &px, &py);
|
|
|
|
|
|
|
|
*x += px;
|
|
|
|
*y += py;
|
|
|
|
}
|
|
|
|
|
|
|
|
if (w == NULL)
|
|
|
|
{
|
|
|
|
*x = 0;
|
|
|
|
*y = 0;
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
return TRUE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_ruler_event_to_widget_coords (GtkWidget *widget,
|
|
|
|
GdkWindow *window,
|
|
|
|
gdouble event_x,
|
|
|
|
gdouble event_y,
|
|
|
|
gint *widget_x,
|
|
|
|
gint *widget_y)
|
|
|
|
{
|
|
|
|
gint tx, ty;
|
|
|
|
|
|
|
|
if (gtk_widget_get_translation_to_window (widget, window, &tx, &ty))
|
|
|
|
{
|
|
|
|
event_x += tx;
|
|
|
|
event_y += ty;
|
|
|
|
}
|
|
|
|
|
|
|
|
*widget_x = event_x;
|
|
|
|
*widget_y = event_y;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
|
|
|
gimp_ruler_track_widget_motion_notify (GtkWidget *widget,
|
|
|
|
GdkEventMotion *mevent,
|
|
|
|
GimpRuler *ruler)
|
|
|
|
{
|
|
|
|
gint widget_x;
|
|
|
|
gint widget_y;
|
|
|
|
gint ruler_x;
|
|
|
|
gint ruler_y;
|
|
|
|
|
|
|
|
widget = gtk_get_event_widget ((GdkEvent *) mevent);
|
|
|
|
|
|
|
|
gimp_ruler_event_to_widget_coords (widget, mevent->window,
|
|
|
|
mevent->x, mevent->y,
|
|
|
|
&widget_x, &widget_y);
|
|
|
|
|
2011-02-06 09:35:52 +08:00
|
|
|
if (gtk_widget_translate_coordinates (widget, GTK_WIDGET (ruler),
|
|
|
|
widget_x, widget_y,
|
|
|
|
&ruler_x, &ruler_y))
|
|
|
|
{
|
|
|
|
gimp_ruler_update_position (ruler, ruler_x, ruler_y);
|
|
|
|
}
|
2011-01-21 03:23:14 +08:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2008-05-28 19:49:24 +08:00
|
|
|
/**
|
2011-01-21 03:23:14 +08:00
|
|
|
* gimp_ruler_add_track_widget:
|
|
|
|
* @ruler: a #GimpRuler
|
|
|
|
* @widget: the track widget to add
|
|
|
|
*
|
|
|
|
* Adds a "track widget" to the ruler. The ruler will connect to
|
|
|
|
* GtkWidget:motion-notify-event: on the track widget and update its
|
|
|
|
* position marker accordingly. The marker is correctly updated also
|
|
|
|
* for the track widget's children, regardless of whether they are
|
|
|
|
* ordinary children of off-screen children.
|
|
|
|
*
|
2015-06-01 03:18:09 +08:00
|
|
|
* Since: 2.8
|
2011-01-21 03:23:14 +08:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
gimp_ruler_add_track_widget (GimpRuler *ruler,
|
|
|
|
GtkWidget *widget)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_RULER (ruler));
|
|
|
|
g_return_if_fail (GTK_IS_WIDGET (ruler));
|
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
g_return_if_fail (g_list_find (ruler->track_widgets, widget) == NULL);
|
2011-01-21 03:23:14 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->track_widgets = g_list_prepend (ruler->track_widgets, widget);
|
2011-01-21 03:23:14 +08:00
|
|
|
|
|
|
|
g_signal_connect (widget, "motion-notify-event",
|
|
|
|
G_CALLBACK (gimp_ruler_track_widget_motion_notify),
|
|
|
|
ruler);
|
|
|
|
g_signal_connect_swapped (widget, "destroy",
|
|
|
|
G_CALLBACK (gimp_ruler_remove_track_widget),
|
|
|
|
ruler);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gimp_ruler_remove_track_widget:
|
|
|
|
* @ruler: a #GimpRuler
|
|
|
|
* @widget: the track widget to remove
|
|
|
|
*
|
|
|
|
* Removes a previously added track widget from the ruler. See
|
|
|
|
* gimp_ruler_add_track_widget().
|
|
|
|
*
|
2015-06-01 03:18:09 +08:00
|
|
|
* Since: 2.8
|
2011-01-21 03:23:14 +08:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
gimp_ruler_remove_track_widget (GimpRuler *ruler,
|
|
|
|
GtkWidget *widget)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_RULER (ruler));
|
|
|
|
g_return_if_fail (GTK_IS_WIDGET (ruler));
|
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
g_return_if_fail (g_list_find (ruler->track_widgets, widget) != NULL);
|
2011-01-21 03:23:14 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->track_widgets = g_list_remove (ruler->track_widgets, widget);
|
2011-01-21 03:23:14 +08:00
|
|
|
|
|
|
|
g_signal_handlers_disconnect_by_func (widget,
|
|
|
|
gimp_ruler_track_widget_motion_notify,
|
|
|
|
ruler);
|
|
|
|
g_signal_handlers_disconnect_by_func (widget,
|
|
|
|
gimp_ruler_remove_track_widget,
|
|
|
|
ruler);
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gimp_ruler_set_unit:
|
2008-05-28 19:49:24 +08:00
|
|
|
* @ruler: a #GimpRuler
|
|
|
|
* @unit: the #GimpUnit to set the ruler to
|
|
|
|
*
|
|
|
|
* This sets the unit of the ruler.
|
|
|
|
*
|
2015-06-01 03:18:09 +08:00
|
|
|
* Since: 2.8
|
2008-05-28 19:49:24 +08:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
gimp_ruler_set_unit (GimpRuler *ruler,
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-26 02:55:21 +08:00
|
|
|
GimpUnit *unit)
|
2008-05-28 19:49:24 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_RULER (ruler));
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-26 02:55:21 +08:00
|
|
|
g_return_if_fail (GIMP_IS_UNIT (unit));
|
2008-05-28 19:49:24 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->unit != unit)
|
2008-05-28 19:49:24 +08:00
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->unit = unit;
|
2020-12-30 05:03:26 +08:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (ruler), object_props[PROP_UNIT]);
|
2008-05-28 19:49:24 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->backing_store_valid = FALSE;
|
2008-05-28 19:49:24 +08:00
|
|
|
gtk_widget_queue_draw (GTK_WIDGET (ruler));
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gimp_ruler_get_unit:
|
|
|
|
* @ruler: a #GimpRuler
|
|
|
|
*
|
2019-08-03 06:10:14 +08:00
|
|
|
* Returns: (transfer none): the unit currently used in the @ruler widget.
|
2008-05-28 19:49:24 +08:00
|
|
|
*
|
2015-06-01 03:18:09 +08:00
|
|
|
* Since: 2.8
|
2008-05-28 19:49:24 +08:00
|
|
|
**/
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-26 02:55:21 +08:00
|
|
|
GimpUnit *
|
2008-05-28 19:49:24 +08:00
|
|
|
gimp_ruler_get_unit (GimpRuler *ruler)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_RULER (ruler), 0);
|
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
return ruler->unit;
|
2008-05-28 19:49:24 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gimp_ruler_set_position:
|
|
|
|
* @ruler: a #GimpRuler
|
|
|
|
* @position: the position to set the ruler to
|
|
|
|
*
|
|
|
|
* This sets the position of the ruler.
|
|
|
|
*
|
2015-06-01 03:18:09 +08:00
|
|
|
* Since: 2.8
|
2008-05-28 19:49:24 +08:00
|
|
|
*/
|
2008-05-27 05:20:16 +08:00
|
|
|
void
|
2008-05-28 18:18:43 +08:00
|
|
|
gimp_ruler_set_position (GimpRuler *ruler,
|
|
|
|
gdouble position)
|
2008-05-27 05:20:16 +08:00
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_RULER (ruler));
|
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->position != position)
|
2008-05-28 18:18:43 +08:00
|
|
|
{
|
2015-09-06 12:05:32 +08:00
|
|
|
GdkRectangle rect;
|
|
|
|
gint xdiff, ydiff;
|
2015-08-12 04:20:59 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->position = position;
|
2020-12-30 05:03:26 +08:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (ruler), object_props[PROP_POSITION]);
|
2008-05-27 05:20:16 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
rect = gimp_ruler_get_pos_rect (ruler, ruler->position);
|
2015-09-06 12:05:32 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
xdiff = rect.x - ruler->last_pos_rect.x;
|
|
|
|
ydiff = rect.y - ruler->last_pos_rect.y;
|
2015-09-06 12:05:32 +08:00
|
|
|
|
macos: Fix 7690 (slow drawing)
Gets drawing in the canvas speed on retina displays up to the speed
of FullHD displays on macOS, making 2.99 usable on macOS.
Generic change:
Changes the cursor_label to delay the drawing phase to the idle
queue, from immediate draw on all platforms.
Before the fix in 32049afd (using a deprecated function in Gtk3)
any draws on this label forced a full canvas redraw. This is due
to a quirk in how GtkLabel functions.
The redraw occurred because GtkLabels resize themselves and everything
around them by sending a resize message any time they receive new
text. These resizes then trigger the full canvas resize which triggers
a full canvas redraw that cannot be optimized by either Gtk or Big Sur.
MacOS changes:
Only redraws the cursor position label and each of the horizontal and
vertical rules (cursor tracking widgets) 3 times a second max for a
total of 9 redraws a second (ideally out of 60, though I don't believe
under any circumstances that GIMP achieves a 60fps).
Each of the cursor tracking widgets gets its own timeslice, and so
will not redraw when the other cursor tracking widgets are drawing.
This is required because Big Sur is merging all draw rects into
one large rect, dramatically slowing down draws.
This timeslicing ensures that draw rects are maintained at the smallest
possible size. So the typical redraw is a small rect around the
brush. However, 9 times a second, the rect will include one of the
3 cursor tracking widgets (rulers and cursor label).
Additionally, the code tries to minimize resizing the width of the
cursor label by checking if the widget is too small for the text,
then setting the char_width to a greater size so that resizes won't
be that common.
This improves the appearance of the widget as it no longer
constantly jumps about in size on each cursor move.
Here is a discussion of the issue:
https://gitlab.gnome.org/GNOME/gimp/-/merge_requests/572#note_1389445
Reviewer's (Jehan) notes:
* The whole issue about GtkLabel resizing is no more after 32049afd. It
is normal for a widget to request a resize when needed. We just don't
want the statusbar to resize and triggering canvas redraws.
* Changing cursor position text into an idle function generally makes
sense.
Also it reverts commit 6de9ea70223 which had a bug I hadn't realized
when I accepted it: when we test for time, we don't know yet if it
will be the last position change, hence we could "refuse" the last
update. Therefore displayed cursor position would end up outdated
on macOS. This new implementation doesn't have the problem (the last
idle update always happens after the last move).
* The change about giving 1/3 timeslices to side canvas components
(rulers and statusbar) is a complete hack to work around the fact that
macOs doesn't report properly each damaged rectangle. Instead it
returns a huge bounding box. The workaround here is to expose these
area separately.
We have not been able to find a proper solution yet. This is the only
reason why I accept this code, for macOS only, to at least have
something usable there.
See discussions in MRs gimp!572 and gimp-macos-build!86. With these 2
MRs, Lukas reported GIMP 2.99 to perform even better than GIMP 2.10 on
Monterey, though it could not be tested on Big Sur unfortunately.
* Lastly the set_width_chars() thing is also an ugly hack which I will
try later to revisit (see !581). I only accepted it (with mandatory
macOS-only macro) to have an acceptable state for release after seeing
a screencast where the label size indeed "jumps around" on macOS.
2022-02-19 09:25:51 +08:00
|
|
|
#ifndef GDK_WINDOWING_QUARTZ
|
2015-09-06 12:05:32 +08:00
|
|
|
/*
|
|
|
|
* If the position has changed far enough, queue a redraw immediately.
|
|
|
|
* Otherwise, we only queue a redraw in a low priority idle handler, to
|
|
|
|
* allow for other things (like updating the canvas) to run.
|
|
|
|
*
|
|
|
|
* TODO: This might not be necessary any more in GTK3 with the frame
|
|
|
|
* clock. Investigate this more after the port to GTK3.
|
|
|
|
*/
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->last_pos_rect.width != 0 &&
|
|
|
|
ruler->last_pos_rect.height != 0 &&
|
2015-09-06 12:05:32 +08:00
|
|
|
(ABS (xdiff) > IMMEDIATE_REDRAW_THRESHOLD ||
|
|
|
|
ABS (ydiff) > IMMEDIATE_REDRAW_THRESHOLD))
|
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->pos_redraw_idle_id)
|
2016-09-23 05:03:53 +08:00
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
g_source_remove (ruler->pos_redraw_idle_id);
|
|
|
|
ruler->pos_redraw_idle_id = 0;
|
2016-09-23 05:03:53 +08:00
|
|
|
}
|
|
|
|
|
2015-09-06 12:05:32 +08:00
|
|
|
gimp_ruler_queue_pos_redraw (ruler);
|
|
|
|
}
|
2024-07-27 00:21:01 +08:00
|
|
|
else if (! ruler->pos_redraw_idle_id)
|
macos: Fix 7690 (slow drawing)
Gets drawing in the canvas speed on retina displays up to the speed
of FullHD displays on macOS, making 2.99 usable on macOS.
Generic change:
Changes the cursor_label to delay the drawing phase to the idle
queue, from immediate draw on all platforms.
Before the fix in 32049afd (using a deprecated function in Gtk3)
any draws on this label forced a full canvas redraw. This is due
to a quirk in how GtkLabel functions.
The redraw occurred because GtkLabels resize themselves and everything
around them by sending a resize message any time they receive new
text. These resizes then trigger the full canvas resize which triggers
a full canvas redraw that cannot be optimized by either Gtk or Big Sur.
MacOS changes:
Only redraws the cursor position label and each of the horizontal and
vertical rules (cursor tracking widgets) 3 times a second max for a
total of 9 redraws a second (ideally out of 60, though I don't believe
under any circumstances that GIMP achieves a 60fps).
Each of the cursor tracking widgets gets its own timeslice, and so
will not redraw when the other cursor tracking widgets are drawing.
This is required because Big Sur is merging all draw rects into
one large rect, dramatically slowing down draws.
This timeslicing ensures that draw rects are maintained at the smallest
possible size. So the typical redraw is a small rect around the
brush. However, 9 times a second, the rect will include one of the
3 cursor tracking widgets (rulers and cursor label).
Additionally, the code tries to minimize resizing the width of the
cursor label by checking if the widget is too small for the text,
then setting the char_width to a greater size so that resizes won't
be that common.
This improves the appearance of the widget as it no longer
constantly jumps about in size on each cursor move.
Here is a discussion of the issue:
https://gitlab.gnome.org/GNOME/gimp/-/merge_requests/572#note_1389445
Reviewer's (Jehan) notes:
* The whole issue about GtkLabel resizing is no more after 32049afd. It
is normal for a widget to request a resize when needed. We just don't
want the statusbar to resize and triggering canvas redraws.
* Changing cursor position text into an idle function generally makes
sense.
Also it reverts commit 6de9ea70223 which had a bug I hadn't realized
when I accepted it: when we test for time, we don't know yet if it
will be the last position change, hence we could "refuse" the last
update. Therefore displayed cursor position would end up outdated
on macOS. This new implementation doesn't have the problem (the last
idle update always happens after the last move).
* The change about giving 1/3 timeslices to side canvas components
(rulers and statusbar) is a complete hack to work around the fact that
macOs doesn't report properly each damaged rectangle. Instead it
returns a huge bounding box. The workaround here is to expose these
area separately.
We have not been able to find a proper solution yet. This is the only
reason why I accept this code, for macOS only, to at least have
something usable there.
See discussions in MRs gimp!572 and gimp-macos-build!86. With these 2
MRs, Lukas reported GIMP 2.99 to perform even better than GIMP 2.10 on
Monterey, though it could not be tested on Big Sur unfortunately.
* Lastly the set_width_chars() thing is also an ugly hack which I will
try later to revisit (see !581). I only accepted it (with mandatory
macOS-only macro) to have an acceptable state for release after seeing
a screencast where the label size indeed "jumps around" on macOS.
2022-02-19 09:25:51 +08:00
|
|
|
#else
|
|
|
|
/*
|
|
|
|
* pos_redraw_idle_id being set can be counted on to mean
|
|
|
|
* a redraw is needed (on mac only) since we will not do
|
|
|
|
* a high priority draws due to the dramatic performance
|
|
|
|
* they will have.
|
|
|
|
*/
|
2024-07-27 00:21:01 +08:00
|
|
|
if (! ruler->pos_redraw_idle_id)
|
macos: Fix 7690 (slow drawing)
Gets drawing in the canvas speed on retina displays up to the speed
of FullHD displays on macOS, making 2.99 usable on macOS.
Generic change:
Changes the cursor_label to delay the drawing phase to the idle
queue, from immediate draw on all platforms.
Before the fix in 32049afd (using a deprecated function in Gtk3)
any draws on this label forced a full canvas redraw. This is due
to a quirk in how GtkLabel functions.
The redraw occurred because GtkLabels resize themselves and everything
around them by sending a resize message any time they receive new
text. These resizes then trigger the full canvas resize which triggers
a full canvas redraw that cannot be optimized by either Gtk or Big Sur.
MacOS changes:
Only redraws the cursor position label and each of the horizontal and
vertical rules (cursor tracking widgets) 3 times a second max for a
total of 9 redraws a second (ideally out of 60, though I don't believe
under any circumstances that GIMP achieves a 60fps).
Each of the cursor tracking widgets gets its own timeslice, and so
will not redraw when the other cursor tracking widgets are drawing.
This is required because Big Sur is merging all draw rects into
one large rect, dramatically slowing down draws.
This timeslicing ensures that draw rects are maintained at the smallest
possible size. So the typical redraw is a small rect around the
brush. However, 9 times a second, the rect will include one of the
3 cursor tracking widgets (rulers and cursor label).
Additionally, the code tries to minimize resizing the width of the
cursor label by checking if the widget is too small for the text,
then setting the char_width to a greater size so that resizes won't
be that common.
This improves the appearance of the widget as it no longer
constantly jumps about in size on each cursor move.
Here is a discussion of the issue:
https://gitlab.gnome.org/GNOME/gimp/-/merge_requests/572#note_1389445
Reviewer's (Jehan) notes:
* The whole issue about GtkLabel resizing is no more after 32049afd. It
is normal for a widget to request a resize when needed. We just don't
want the statusbar to resize and triggering canvas redraws.
* Changing cursor position text into an idle function generally makes
sense.
Also it reverts commit 6de9ea70223 which had a bug I hadn't realized
when I accepted it: when we test for time, we don't know yet if it
will be the last position change, hence we could "refuse" the last
update. Therefore displayed cursor position would end up outdated
on macOS. This new implementation doesn't have the problem (the last
idle update always happens after the last move).
* The change about giving 1/3 timeslices to side canvas components
(rulers and statusbar) is a complete hack to work around the fact that
macOs doesn't report properly each damaged rectangle. Instead it
returns a huge bounding box. The workaround here is to expose these
area separately.
We have not been able to find a proper solution yet. This is the only
reason why I accept this code, for macOS only, to at least have
something usable there.
See discussions in MRs gimp!572 and gimp-macos-build!86. With these 2
MRs, Lukas reported GIMP 2.99 to perform even better than GIMP 2.10 on
Monterey, though it could not be tested on Big Sur unfortunately.
* Lastly the set_width_chars() thing is also an ugly hack which I will
try later to revisit (see !581). I only accepted it (with mandatory
macOS-only macro) to have an acceptable state for release after seeing
a screencast where the label size indeed "jumps around" on macOS.
2022-02-19 09:25:51 +08:00
|
|
|
#endif
|
2015-09-06 12:05:32 +08:00
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->pos_redraw_idle_id =
|
2015-09-27 19:45:13 +08:00
|
|
|
g_idle_add_full (G_PRIORITY_LOW,
|
|
|
|
gimp_ruler_idle_queue_pos_redraw,
|
|
|
|
ruler, NULL);
|
2015-09-06 12:05:32 +08:00
|
|
|
}
|
2008-05-28 19:49:24 +08:00
|
|
|
}
|
2008-05-27 05:20:16 +08:00
|
|
|
}
|
|
|
|
|
2008-05-28 19:49:24 +08:00
|
|
|
/**
|
|
|
|
* gimp_ruler_get_position:
|
|
|
|
* @ruler: a #GimpRuler
|
|
|
|
*
|
2019-08-03 06:10:14 +08:00
|
|
|
* Returns: the current position of the @ruler widget.
|
2008-05-28 19:49:24 +08:00
|
|
|
*
|
2015-06-01 03:18:09 +08:00
|
|
|
* Since: 2.8
|
2008-05-28 19:49:24 +08:00
|
|
|
**/
|
2008-05-28 18:18:43 +08:00
|
|
|
gdouble
|
|
|
|
gimp_ruler_get_position (GimpRuler *ruler)
|
|
|
|
{
|
|
|
|
g_return_val_if_fail (GIMP_IS_RULER (ruler), 0.0);
|
2008-05-27 05:20:16 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
return ruler->position;
|
2008-05-27 05:20:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gimp_ruler_set_range:
|
2008-05-28 19:49:24 +08:00
|
|
|
* @ruler: a #GimpRuler
|
2008-05-27 05:20:16 +08:00
|
|
|
* @lower: the lower limit of the ruler
|
|
|
|
* @upper: the upper limit of the ruler
|
|
|
|
* @max_size: the maximum size of the ruler used when calculating the space to
|
|
|
|
* leave for the text
|
|
|
|
*
|
|
|
|
* This sets the range of the ruler.
|
|
|
|
*
|
2015-06-01 03:18:09 +08:00
|
|
|
* Since: 2.8
|
2008-05-27 05:20:16 +08:00
|
|
|
*/
|
|
|
|
void
|
|
|
|
gimp_ruler_set_range (GimpRuler *ruler,
|
|
|
|
gdouble lower,
|
|
|
|
gdouble upper,
|
|
|
|
gdouble max_size)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_RULER (ruler));
|
|
|
|
|
|
|
|
g_object_freeze_notify (G_OBJECT (ruler));
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->lower != lower)
|
2008-05-27 05:20:16 +08:00
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->lower = lower;
|
2020-12-30 05:03:26 +08:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (ruler), object_props[PROP_LOWER]);
|
2008-05-27 05:20:16 +08:00
|
|
|
}
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->upper != upper)
|
2008-05-27 05:20:16 +08:00
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->upper = upper;
|
2020-12-30 05:03:26 +08:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (ruler), object_props[PROP_UPPER]);
|
2008-05-27 05:20:16 +08:00
|
|
|
}
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->max_size != max_size)
|
2008-05-27 05:20:16 +08:00
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->max_size = max_size;
|
2020-12-30 05:03:26 +08:00
|
|
|
g_object_notify_by_pspec (G_OBJECT (ruler), object_props[PROP_MAX_SIZE]);
|
2008-05-27 05:20:16 +08:00
|
|
|
}
|
|
|
|
g_object_thaw_notify (G_OBJECT (ruler));
|
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->backing_store_valid = FALSE;
|
2008-05-28 19:49:24 +08:00
|
|
|
gtk_widget_queue_draw (GTK_WIDGET (ruler));
|
2008-05-27 05:20:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/**
|
|
|
|
* gimp_ruler_get_range:
|
|
|
|
* @ruler: a #GimpRuler
|
2020-05-03 23:57:23 +08:00
|
|
|
* @lower: (out) (optional): location to store lower limit of the ruler,
|
|
|
|
* or %NULL
|
|
|
|
* @upper: (out) (optional): location to store upper limit of the ruler,
|
|
|
|
* or %NULL
|
|
|
|
* @max_size: (out) (optional): location to store the maximum size of the ruler
|
|
|
|
* used when calculating the space to leave for
|
|
|
|
* the text, or %NULL.
|
2008-05-27 05:20:16 +08:00
|
|
|
*
|
|
|
|
* Retrieves values indicating the range and current position of a #GimpRuler.
|
|
|
|
* See gimp_ruler_set_range().
|
|
|
|
*
|
2015-06-01 03:18:09 +08:00
|
|
|
* Since: 2.8
|
2008-05-27 05:20:16 +08:00
|
|
|
**/
|
|
|
|
void
|
|
|
|
gimp_ruler_get_range (GimpRuler *ruler,
|
|
|
|
gdouble *lower,
|
|
|
|
gdouble *upper,
|
|
|
|
gdouble *max_size)
|
|
|
|
{
|
|
|
|
g_return_if_fail (GIMP_IS_RULER (ruler));
|
|
|
|
|
|
|
|
if (lower)
|
2024-07-27 00:21:01 +08:00
|
|
|
*lower = ruler->lower;
|
2008-05-27 05:20:16 +08:00
|
|
|
if (upper)
|
2024-07-27 00:21:01 +08:00
|
|
|
*upper = ruler->upper;
|
2008-05-27 05:20:16 +08:00
|
|
|
if (max_size)
|
2024-07-27 00:21:01 +08:00
|
|
|
*max_size = ruler->max_size;
|
2008-05-27 05:20:16 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_ruler_realize (GtkWidget *widget)
|
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
GimpRuler *ruler = GIMP_RULER (widget);
|
|
|
|
GtkAllocation allocation;
|
|
|
|
GdkWindowAttr attributes;
|
|
|
|
gint attributes_mask;
|
2008-05-27 05:20:16 +08:00
|
|
|
|
2011-04-10 08:00:40 +08:00
|
|
|
GTK_WIDGET_CLASS (gimp_ruler_parent_class)->realize (widget);
|
2008-05-27 05:20:16 +08:00
|
|
|
|
2009-10-18 00:51:48 +08:00
|
|
|
gtk_widget_get_allocation (widget, &allocation);
|
|
|
|
|
2008-05-27 05:20:16 +08:00
|
|
|
attributes.window_type = GDK_WINDOW_CHILD;
|
2009-10-18 00:51:48 +08:00
|
|
|
attributes.x = allocation.x;
|
|
|
|
attributes.y = allocation.y;
|
|
|
|
attributes.width = allocation.width;
|
|
|
|
attributes.height = allocation.height;
|
2011-04-10 08:00:40 +08:00
|
|
|
attributes.wclass = GDK_INPUT_ONLY;
|
2008-08-29 18:25:29 +08:00
|
|
|
attributes.event_mask = (gtk_widget_get_events (widget) |
|
|
|
|
GDK_EXPOSURE_MASK |
|
2012-11-16 02:02:42 +08:00
|
|
|
GDK_POINTER_MOTION_MASK);
|
2008-05-27 05:20:16 +08:00
|
|
|
|
2011-04-10 08:00:40 +08:00
|
|
|
attributes_mask = GDK_WA_X | GDK_WA_Y;
|
2008-05-27 05:20:16 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->input_window = gdk_window_new (gtk_widget_get_window (widget),
|
2011-04-10 08:00:40 +08:00
|
|
|
&attributes, attributes_mask);
|
2024-07-27 00:21:01 +08:00
|
|
|
gdk_window_set_user_data (ruler->input_window, ruler);
|
2008-05-27 05:20:16 +08:00
|
|
|
|
|
|
|
gimp_ruler_make_pixmap (ruler);
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_ruler_unrealize (GtkWidget *widget)
|
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
GimpRuler *ruler = GIMP_RULER (widget);
|
2008-05-27 05:20:16 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
g_clear_pointer (&ruler->backing_store, cairo_surface_destroy);
|
|
|
|
ruler->backing_store_valid = FALSE;
|
2015-08-12 04:20:59 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
g_clear_object (&ruler->layout);
|
2008-10-05 07:32:41 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
g_clear_pointer (&ruler->input_window, gdk_window_destroy);
|
2011-04-10 08:00:40 +08:00
|
|
|
|
2008-08-29 18:25:29 +08:00
|
|
|
GTK_WIDGET_CLASS (gimp_ruler_parent_class)->unrealize (widget);
|
2008-05-27 05:20:16 +08:00
|
|
|
}
|
|
|
|
|
2011-04-10 08:00:40 +08:00
|
|
|
static void
|
|
|
|
gimp_ruler_map (GtkWidget *widget)
|
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
GimpRuler *ruler = GIMP_RULER (widget);
|
2011-04-10 08:00:40 +08:00
|
|
|
|
|
|
|
GTK_WIDGET_CLASS (parent_class)->map (widget);
|
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->input_window)
|
|
|
|
gdk_window_show (ruler->input_window);
|
2011-04-10 08:00:40 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_ruler_unmap (GtkWidget *widget)
|
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
GimpRuler *ruler = GIMP_RULER (widget);
|
2011-04-10 08:00:40 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->input_window)
|
|
|
|
gdk_window_hide (ruler->input_window);
|
2011-04-10 08:00:40 +08:00
|
|
|
|
|
|
|
GTK_WIDGET_CLASS (parent_class)->unmap (widget);
|
|
|
|
}
|
|
|
|
|
2008-05-27 05:20:16 +08:00
|
|
|
static void
|
|
|
|
gimp_ruler_size_allocate (GtkWidget *widget,
|
|
|
|
GtkAllocation *allocation)
|
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
GimpRuler *ruler = GIMP_RULER (widget);
|
|
|
|
GtkAllocation widget_allocation;
|
|
|
|
gboolean resized;
|
2016-09-09 16:02:53 +08:00
|
|
|
|
|
|
|
gtk_widget_get_allocation (widget, &widget_allocation);
|
|
|
|
|
|
|
|
resized = (widget_allocation.width != allocation->width ||
|
|
|
|
widget_allocation.height != allocation->height);
|
2008-05-27 05:20:16 +08:00
|
|
|
|
2016-09-10 00:32:03 +08:00
|
|
|
GTK_WIDGET_CLASS (parent_class)->size_allocate (widget, allocation);
|
2008-05-27 05:20:16 +08:00
|
|
|
|
2010-04-20 01:21:07 +08:00
|
|
|
if (gtk_widget_get_realized (widget))
|
2008-05-27 05:20:16 +08:00
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
gdk_window_move_resize (ruler->input_window,
|
2008-05-27 21:41:48 +08:00
|
|
|
allocation->x, allocation->y,
|
|
|
|
allocation->width, allocation->height);
|
2008-05-27 05:20:16 +08:00
|
|
|
|
2016-09-09 16:02:53 +08:00
|
|
|
if (resized)
|
|
|
|
gimp_ruler_make_pixmap (ruler);
|
2008-05-27 05:20:16 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2008-10-05 07:13:44 +08:00
|
|
|
static void
|
|
|
|
gimp_ruler_size_request (GtkWidget *widget,
|
|
|
|
GtkRequisition *requisition)
|
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
GimpRuler *ruler = GIMP_RULER (widget);
|
2010-12-17 05:12:09 +08:00
|
|
|
GtkStyleContext *context = gtk_widget_get_style_context (widget);
|
2008-10-05 07:32:41 +08:00
|
|
|
PangoLayout *layout;
|
|
|
|
PangoRectangle ink_rect;
|
2010-12-17 05:12:09 +08:00
|
|
|
GtkBorder border;
|
2008-10-05 07:13:44 +08:00
|
|
|
gint size;
|
|
|
|
|
2008-10-05 07:32:41 +08:00
|
|
|
layout = gimp_ruler_get_layout (widget, "0123456789");
|
|
|
|
pango_layout_get_pixel_extents (layout, &ink_rect, NULL);
|
|
|
|
|
|
|
|
size = 2 + ink_rect.height * 1.7;
|
2008-10-05 07:13:44 +08:00
|
|
|
|
2020-12-29 03:05:09 +08:00
|
|
|
gtk_style_context_get_border (context, gtk_widget_get_state_flags (widget), &border);
|
2010-12-17 05:12:09 +08:00
|
|
|
|
|
|
|
requisition->width = border.left + border.right;
|
|
|
|
requisition->height = border.top + border.bottom;
|
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->orientation == GTK_ORIENTATION_HORIZONTAL)
|
2008-10-05 07:13:44 +08:00
|
|
|
{
|
2010-12-17 05:12:09 +08:00
|
|
|
requisition->width += 1;
|
|
|
|
requisition->height += size;
|
2008-10-05 07:13:44 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-12-17 05:12:09 +08:00
|
|
|
requisition->width += size;
|
|
|
|
requisition->height += 1;
|
2008-10-05 07:13:44 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2010-10-28 19:26:39 +08:00
|
|
|
static void
|
|
|
|
gimp_ruler_get_preferred_width (GtkWidget *widget,
|
|
|
|
gint *minimum_width,
|
|
|
|
gint *natural_width)
|
|
|
|
{
|
|
|
|
GtkRequisition requisition;
|
|
|
|
|
|
|
|
gimp_ruler_size_request (widget, &requisition);
|
|
|
|
|
|
|
|
*minimum_width = *natural_width = requisition.width;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_ruler_get_preferred_height (GtkWidget *widget,
|
|
|
|
gint *minimum_height,
|
|
|
|
gint *natural_height)
|
|
|
|
{
|
|
|
|
GtkRequisition requisition;
|
|
|
|
|
|
|
|
gimp_ruler_size_request (widget, &requisition);
|
|
|
|
|
|
|
|
*minimum_height = *natural_height = requisition.height;
|
|
|
|
}
|
|
|
|
|
2008-10-04 06:11:15 +08:00
|
|
|
static void
|
2010-12-21 16:32:10 +08:00
|
|
|
gimp_ruler_style_updated (GtkWidget *widget)
|
2008-10-04 06:11:15 +08:00
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
GimpRuler *ruler = GIMP_RULER (widget);
|
2008-10-04 06:11:15 +08:00
|
|
|
|
2010-12-21 16:32:10 +08:00
|
|
|
GTK_WIDGET_CLASS (gimp_ruler_parent_class)->style_updated (widget);
|
2008-10-04 06:11:15 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->backing_store_valid = FALSE;
|
2017-02-27 18:03:59 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
g_clear_object (&ruler->layout);
|
2008-10-04 06:11:15 +08:00
|
|
|
}
|
|
|
|
|
2008-08-29 18:25:29 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_ruler_motion_notify (GtkWidget *widget,
|
|
|
|
GdkEventMotion *event)
|
|
|
|
{
|
2011-01-21 03:23:14 +08:00
|
|
|
GimpRuler *ruler = GIMP_RULER (widget);
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2011-01-21 03:23:14 +08:00
|
|
|
gimp_ruler_update_position (ruler, event->x, event->y);
|
2008-08-29 18:25:29 +08:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static gboolean
|
2010-10-20 00:59:50 +08:00
|
|
|
gimp_ruler_draw (GtkWidget *widget,
|
|
|
|
cairo_t *cr)
|
2008-05-27 05:20:16 +08:00
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
GimpRuler *ruler = GIMP_RULER (widget);
|
|
|
|
GtkStyleContext *context = gtk_widget_get_style_context (widget);
|
|
|
|
GtkAllocation allocation;
|
2015-09-29 10:42:46 +08:00
|
|
|
|
|
|
|
gtk_widget_get_allocation (widget, &allocation);
|
|
|
|
gtk_render_background (context, cr, 0, 0, allocation.width, allocation.height);
|
|
|
|
gtk_render_frame (context, cr, 0, 0, allocation.width, allocation.height);
|
2010-12-18 05:49:55 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
if (! ruler->backing_store_valid)
|
2010-10-20 00:59:50 +08:00
|
|
|
gimp_ruler_draw_ticks (ruler);
|
2008-05-27 05:20:16 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
cairo_set_source_surface (cr, ruler->backing_store, 0, 0);
|
2010-10-20 00:59:50 +08:00
|
|
|
cairo_paint (cr);
|
2010-12-18 05:49:55 +08:00
|
|
|
|
2010-10-20 00:59:50 +08:00
|
|
|
gimp_ruler_draw_pos (ruler, cr);
|
2008-05-27 05:20:16 +08:00
|
|
|
|
|
|
|
return FALSE;
|
|
|
|
}
|
|
|
|
|
2008-05-28 19:49:24 +08:00
|
|
|
static void
|
|
|
|
gimp_ruler_draw_ticks (GimpRuler *ruler)
|
|
|
|
{
|
2010-12-17 05:12:09 +08:00
|
|
|
GtkWidget *widget = GTK_WIDGET (ruler);
|
|
|
|
GtkStyleContext *context = gtk_widget_get_style_context (widget);
|
2018-02-12 19:20:32 +08:00
|
|
|
GtkAllocation allocation;
|
2010-12-17 05:12:09 +08:00
|
|
|
GtkBorder border;
|
|
|
|
GdkRGBA color;
|
2018-02-12 19:20:32 +08:00
|
|
|
cairo_t *cr;
|
|
|
|
gint i;
|
|
|
|
gint width, height;
|
|
|
|
gint length, ideal_length;
|
2023-10-26 00:15:04 +08:00
|
|
|
gdouble lower = 0; /* Upper and lower limits, in ruler units */
|
|
|
|
gdouble upper = 0;
|
2018-02-12 19:20:32 +08:00
|
|
|
gdouble increment; /* Number of pixels per unit */
|
|
|
|
gint scale; /* Number of units per major unit */
|
|
|
|
gdouble start, end, cur;
|
|
|
|
gchar unit_str[32];
|
|
|
|
gint digit_height;
|
|
|
|
gint digit_offset;
|
|
|
|
gint text_size;
|
|
|
|
gint pos;
|
|
|
|
gdouble max_size;
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-26 02:55:21 +08:00
|
|
|
GimpUnit *unit;
|
2018-02-12 19:20:32 +08:00
|
|
|
PangoLayout *layout;
|
|
|
|
PangoRectangle logical_rect, ink_rect;
|
|
|
|
const RulerMetric *ruler_metric;
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2009-10-18 00:51:48 +08:00
|
|
|
if (! gtk_widget_is_drawable (widget))
|
2008-08-29 18:25:29 +08:00
|
|
|
return;
|
|
|
|
|
2009-10-18 00:51:48 +08:00
|
|
|
gtk_widget_get_allocation (widget, &allocation);
|
2020-12-29 03:05:09 +08:00
|
|
|
gtk_style_context_get_border (context, gtk_widget_get_state_flags (widget), &border);
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2008-10-05 07:32:41 +08:00
|
|
|
layout = gimp_ruler_get_layout (widget, "0123456789");
|
2008-08-29 18:25:29 +08:00
|
|
|
pango_layout_get_extents (layout, &ink_rect, &logical_rect);
|
|
|
|
|
|
|
|
digit_height = PANGO_PIXELS (ink_rect.height) + 2;
|
|
|
|
digit_offset = ink_rect.y;
|
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->orientation == GTK_ORIENTATION_HORIZONTAL)
|
2008-08-29 18:25:29 +08:00
|
|
|
{
|
2009-10-18 00:51:48 +08:00
|
|
|
width = allocation.width;
|
2010-12-17 05:12:09 +08:00
|
|
|
height = allocation.height - (border.top + border.bottom);
|
2008-08-29 18:25:29 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2009-10-18 00:51:48 +08:00
|
|
|
width = allocation.height;
|
2010-12-17 05:12:09 +08:00
|
|
|
height = allocation.width - (border.top + border.bottom);
|
2008-08-29 18:25:29 +08:00
|
|
|
}
|
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
cr = cairo_create (ruler->backing_store);
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2015-09-29 10:42:46 +08:00
|
|
|
cairo_set_operator (cr, CAIRO_OPERATOR_CLEAR);
|
|
|
|
cairo_paint (cr);
|
|
|
|
cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
|
2010-12-17 05:12:09 +08:00
|
|
|
|
|
|
|
gtk_style_context_get_color (context, gtk_widget_get_state_flags (widget),
|
|
|
|
&color);
|
|
|
|
gdk_cairo_set_source_rgba (cr, &color);
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->orientation == GTK_ORIENTATION_HORIZONTAL)
|
2008-08-29 18:25:29 +08:00
|
|
|
{
|
|
|
|
cairo_rectangle (cr,
|
2010-12-17 05:12:09 +08:00
|
|
|
border.left,
|
|
|
|
height + border.top,
|
|
|
|
allocation.width - (border.left + border.right),
|
2008-08-29 18:25:29 +08:00
|
|
|
1);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cairo_rectangle (cr,
|
2010-12-17 05:12:09 +08:00
|
|
|
height + border.left,
|
|
|
|
border.top,
|
2008-08-29 18:25:29 +08:00
|
|
|
1,
|
2010-12-17 05:12:09 +08:00
|
|
|
allocation.height - (border.top + border.bottom));
|
2008-08-29 18:25:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
gimp_ruler_get_range (ruler, &lower, &upper, &max_size);
|
|
|
|
|
|
|
|
if ((upper - lower) == 0)
|
|
|
|
goto out;
|
|
|
|
|
|
|
|
increment = (gdouble) width / (upper - lower);
|
|
|
|
|
|
|
|
/* determine the scale
|
|
|
|
* use the maximum extents of the ruler to determine the largest
|
|
|
|
* possible number to be displayed. Calculate the height in pixels
|
|
|
|
* of this displayed text. Use this height to find a scale which
|
|
|
|
* leaves sufficient room for drawing the ruler.
|
|
|
|
*
|
2009-11-10 02:07:54 +08:00
|
|
|
* We calculate the text size as for the vruler instead of
|
|
|
|
* actually measuring the text width, so that the result for the
|
|
|
|
* scale looks consistent with an accompanying vruler.
|
2008-08-29 18:25:29 +08:00
|
|
|
*/
|
|
|
|
scale = ceil (max_size);
|
|
|
|
g_snprintf (unit_str, sizeof (unit_str), "%d", scale);
|
|
|
|
text_size = strlen (unit_str) * digit_height + 1;
|
|
|
|
|
2018-02-12 19:20:32 +08:00
|
|
|
unit = gimp_ruler_get_unit (ruler);
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2018-02-12 19:20:32 +08:00
|
|
|
ruler_metric = gimp_ruler_get_metric (unit);
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2018-02-12 19:20:32 +08:00
|
|
|
for (scale = 0; scale < G_N_ELEMENTS (ruler_metric->ruler_scale); scale++)
|
|
|
|
if (ruler_metric->ruler_scale[scale] * fabs (increment) > 2 * text_size)
|
|
|
|
break;
|
|
|
|
|
|
|
|
if (scale == G_N_ELEMENTS (ruler_metric->ruler_scale))
|
|
|
|
scale = G_N_ELEMENTS (ruler_metric->ruler_scale) - 1;
|
2008-08-29 18:25:29 +08:00
|
|
|
|
|
|
|
/* drawing starts here */
|
|
|
|
length = 0;
|
2018-02-12 19:20:32 +08:00
|
|
|
for (i = G_N_ELEMENTS (ruler_metric->subdivide) - 1; i >= 0; i--)
|
2008-08-29 18:25:29 +08:00
|
|
|
{
|
|
|
|
gdouble subd_incr;
|
|
|
|
|
|
|
|
/* hack to get proper subdivisions at full pixels */
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-26 02:55:21 +08:00
|
|
|
if (unit == gimp_unit_pixel () && scale == 1 && i == 1)
|
2008-08-29 18:25:29 +08:00
|
|
|
subd_incr = 1.0;
|
|
|
|
else
|
2018-02-12 19:20:32 +08:00
|
|
|
subd_incr = ((gdouble) ruler_metric->ruler_scale[scale] /
|
|
|
|
(gdouble) ruler_metric->subdivide[i]);
|
2008-08-29 18:25:29 +08:00
|
|
|
|
|
|
|
if (subd_incr * fabs (increment) <= MINIMUM_INCR)
|
|
|
|
continue;
|
|
|
|
|
|
|
|
/* don't subdivide pixels */
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-26 02:55:21 +08:00
|
|
|
if (unit == gimp_unit_pixel () && subd_incr < 1.0)
|
2008-08-29 18:25:29 +08:00
|
|
|
continue;
|
|
|
|
|
|
|
|
/* Calculate the length of the tickmarks. Make sure that
|
|
|
|
* this length increases for each set of ticks
|
|
|
|
*/
|
|
|
|
ideal_length = height / (i + 1) - 1;
|
|
|
|
if (ideal_length > ++length)
|
|
|
|
length = ideal_length;
|
|
|
|
|
|
|
|
if (lower < upper)
|
|
|
|
{
|
|
|
|
start = floor (lower / subd_incr) * subd_incr;
|
|
|
|
end = ceil (upper / subd_incr) * subd_incr;
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
start = floor (upper / subd_incr) * subd_incr;
|
|
|
|
end = ceil (lower / subd_incr) * subd_incr;
|
|
|
|
}
|
|
|
|
|
|
|
|
for (cur = start; cur <= end; cur += subd_incr)
|
|
|
|
{
|
|
|
|
pos = ROUND ((cur - lower) * increment);
|
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->orientation == GTK_ORIENTATION_HORIZONTAL)
|
2008-08-29 18:25:29 +08:00
|
|
|
{
|
|
|
|
cairo_rectangle (cr,
|
2010-12-17 05:12:09 +08:00
|
|
|
pos, height + border.top - length,
|
2008-08-29 18:25:29 +08:00
|
|
|
1, length);
|
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
cairo_rectangle (cr,
|
2010-12-17 05:12:09 +08:00
|
|
|
height + border.left - length, pos,
|
|
|
|
length, 1);
|
2008-08-29 18:25:29 +08:00
|
|
|
}
|
|
|
|
|
|
|
|
/* draw label */
|
|
|
|
if (i == 0)
|
|
|
|
{
|
|
|
|
g_snprintf (unit_str, sizeof (unit_str), "%d", (int) cur);
|
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->orientation == GTK_ORIENTATION_HORIZONTAL)
|
2008-08-29 18:25:29 +08:00
|
|
|
{
|
|
|
|
pango_layout_set_text (layout, unit_str, -1);
|
|
|
|
pango_layout_get_extents (layout, &logical_rect, NULL);
|
|
|
|
|
2010-12-18 05:49:55 +08:00
|
|
|
cairo_move_to (cr,
|
|
|
|
pos + 2,
|
2010-12-17 05:12:09 +08:00
|
|
|
border.top + PANGO_PIXELS (logical_rect.y - digit_offset));
|
2010-12-18 05:49:55 +08:00
|
|
|
pango_cairo_show_layout (cr, layout);
|
2008-08-29 18:25:29 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
gint j;
|
|
|
|
|
|
|
|
for (j = 0; j < (int) strlen (unit_str); j++)
|
|
|
|
{
|
|
|
|
pango_layout_set_text (layout, unit_str + j, 1);
|
|
|
|
pango_layout_get_extents (layout, NULL, &logical_rect);
|
|
|
|
|
2010-12-18 05:49:55 +08:00
|
|
|
cairo_move_to (cr,
|
2010-12-17 05:12:09 +08:00
|
|
|
border.left + 1,
|
2010-12-18 05:49:55 +08:00
|
|
|
pos + digit_height * j + 2 + PANGO_PIXELS (logical_rect.y - digit_offset));
|
|
|
|
pango_cairo_show_layout (cr, layout);
|
2008-08-29 18:25:29 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
2008-05-28 19:49:24 +08:00
|
|
|
|
2008-08-29 18:25:29 +08:00
|
|
|
cairo_fill (cr);
|
2015-08-12 04:20:59 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->backing_store_valid = TRUE;
|
2015-08-12 04:20:59 +08:00
|
|
|
|
2008-08-29 18:25:29 +08:00
|
|
|
out:
|
|
|
|
cairo_destroy (cr);
|
2008-05-28 19:49:24 +08:00
|
|
|
}
|
|
|
|
|
2015-08-12 04:20:59 +08:00
|
|
|
static GdkRectangle
|
2015-09-27 19:45:13 +08:00
|
|
|
gimp_ruler_get_pos_rect (GimpRuler *ruler,
|
|
|
|
gdouble position)
|
2008-05-28 19:49:24 +08:00
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
GtkWidget *widget = GTK_WIDGET (ruler);
|
|
|
|
GtkStyleContext *context = gtk_widget_get_style_context (widget);
|
|
|
|
GtkAllocation allocation;
|
|
|
|
GtkBorder border;
|
|
|
|
gint width, height;
|
|
|
|
gdouble upper = 0;
|
|
|
|
gdouble lower = 0;
|
|
|
|
gdouble increment;
|
|
|
|
GdkRectangle rect = { 0, };
|
2008-05-28 19:49:24 +08:00
|
|
|
|
2009-10-18 00:51:48 +08:00
|
|
|
if (! gtk_widget_is_drawable (widget))
|
2015-08-12 04:20:59 +08:00
|
|
|
return rect;
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2009-10-18 00:51:48 +08:00
|
|
|
gtk_widget_get_allocation (widget, &allocation);
|
2020-12-29 03:05:09 +08:00
|
|
|
gtk_style_context_get_border (context, gtk_widget_get_state_flags (widget), &border);
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->orientation == GTK_ORIENTATION_HORIZONTAL)
|
2008-09-02 20:30:53 +08:00
|
|
|
{
|
2009-10-18 00:51:48 +08:00
|
|
|
width = allocation.width;
|
2010-12-17 05:12:09 +08:00
|
|
|
height = allocation.height - (border.top + border.bottom);
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2015-08-12 04:20:59 +08:00
|
|
|
rect.width = height / 2 + 2;
|
|
|
|
rect.width |= 1; /* make sure it's odd */
|
|
|
|
rect.height = rect.width / 2 + 1;
|
2008-09-02 20:30:53 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2010-12-17 05:12:09 +08:00
|
|
|
width = allocation.width - (border.left + border.right);
|
2009-10-18 00:51:48 +08:00
|
|
|
height = allocation.height;
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2015-08-12 04:20:59 +08:00
|
|
|
rect.height = width / 2 + 2;
|
|
|
|
rect.height |= 1; /* make sure it's odd */
|
|
|
|
rect.width = rect.height / 2 + 1;
|
2008-09-02 20:30:53 +08:00
|
|
|
}
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2015-08-12 04:20:59 +08:00
|
|
|
gimp_ruler_get_range (ruler, &lower, &upper, NULL);
|
2011-04-20 06:31:59 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->orientation == GTK_ORIENTATION_HORIZONTAL)
|
2015-08-12 04:20:59 +08:00
|
|
|
{
|
|
|
|
increment = (gdouble) width / (upper - lower);
|
2014-12-03 14:44:45 +08:00
|
|
|
|
2010-12-17 05:12:09 +08:00
|
|
|
rect.x = ROUND ((position - lower) * increment) + (border.left + border.right - rect.width) / 2 - 1;
|
|
|
|
rect.y = (height + rect.height) / 2 + border.top;
|
2015-08-12 04:20:59 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
|
|
|
increment = (gdouble) height / (upper - lower);
|
2011-04-10 08:00:40 +08:00
|
|
|
|
2010-12-17 05:12:09 +08:00
|
|
|
rect.x = (width + rect.width) / 2 + border.left;
|
|
|
|
rect.y = ROUND ((position - lower) * increment) + (border.top + border.bottom - rect.height) / 2 - 1;
|
2015-08-12 04:20:59 +08:00
|
|
|
}
|
2010-12-18 05:49:55 +08:00
|
|
|
|
2015-08-12 04:20:59 +08:00
|
|
|
return rect;
|
|
|
|
}
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2015-09-06 12:05:32 +08:00
|
|
|
static gboolean
|
|
|
|
gimp_ruler_idle_queue_pos_redraw (gpointer data)
|
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
GimpRuler *ruler = data;
|
macos: Fix 7690 (slow drawing)
Gets drawing in the canvas speed on retina displays up to the speed
of FullHD displays on macOS, making 2.99 usable on macOS.
Generic change:
Changes the cursor_label to delay the drawing phase to the idle
queue, from immediate draw on all platforms.
Before the fix in 32049afd (using a deprecated function in Gtk3)
any draws on this label forced a full canvas redraw. This is due
to a quirk in how GtkLabel functions.
The redraw occurred because GtkLabels resize themselves and everything
around them by sending a resize message any time they receive new
text. These resizes then trigger the full canvas resize which triggers
a full canvas redraw that cannot be optimized by either Gtk or Big Sur.
MacOS changes:
Only redraws the cursor position label and each of the horizontal and
vertical rules (cursor tracking widgets) 3 times a second max for a
total of 9 redraws a second (ideally out of 60, though I don't believe
under any circumstances that GIMP achieves a 60fps).
Each of the cursor tracking widgets gets its own timeslice, and so
will not redraw when the other cursor tracking widgets are drawing.
This is required because Big Sur is merging all draw rects into
one large rect, dramatically slowing down draws.
This timeslicing ensures that draw rects are maintained at the smallest
possible size. So the typical redraw is a small rect around the
brush. However, 9 times a second, the rect will include one of the
3 cursor tracking widgets (rulers and cursor label).
Additionally, the code tries to minimize resizing the width of the
cursor label by checking if the widget is too small for the text,
then setting the char_width to a greater size so that resizes won't
be that common.
This improves the appearance of the widget as it no longer
constantly jumps about in size on each cursor move.
Here is a discussion of the issue:
https://gitlab.gnome.org/GNOME/gimp/-/merge_requests/572#note_1389445
Reviewer's (Jehan) notes:
* The whole issue about GtkLabel resizing is no more after 32049afd. It
is normal for a widget to request a resize when needed. We just don't
want the statusbar to resize and triggering canvas redraws.
* Changing cursor position text into an idle function generally makes
sense.
Also it reverts commit 6de9ea70223 which had a bug I hadn't realized
when I accepted it: when we test for time, we don't know yet if it
will be the last position change, hence we could "refuse" the last
update. Therefore displayed cursor position would end up outdated
on macOS. This new implementation doesn't have the problem (the last
idle update always happens after the last move).
* The change about giving 1/3 timeslices to side canvas components
(rulers and statusbar) is a complete hack to work around the fact that
macOs doesn't report properly each damaged rectangle. Instead it
returns a huge bounding box. The workaround here is to expose these
area separately.
We have not been able to find a proper solution yet. This is the only
reason why I accept this code, for macOS only, to at least have
something usable there.
See discussions in MRs gimp!572 and gimp-macos-build!86. With these 2
MRs, Lukas reported GIMP 2.99 to perform even better than GIMP 2.10 on
Monterey, though it could not be tested on Big Sur unfortunately.
* Lastly the set_width_chars() thing is also an ugly hack which I will
try later to revisit (see !581). I only accepted it (with mandatory
macOS-only macro) to have an acceptable state for release after seeing
a screencast where the label size indeed "jumps around" on macOS.
2022-02-19 09:25:51 +08:00
|
|
|
|
2015-09-06 12:05:32 +08:00
|
|
|
gimp_ruler_queue_pos_redraw (ruler);
|
|
|
|
|
macos: Fix 7690 (slow drawing)
Gets drawing in the canvas speed on retina displays up to the speed
of FullHD displays on macOS, making 2.99 usable on macOS.
Generic change:
Changes the cursor_label to delay the drawing phase to the idle
queue, from immediate draw on all platforms.
Before the fix in 32049afd (using a deprecated function in Gtk3)
any draws on this label forced a full canvas redraw. This is due
to a quirk in how GtkLabel functions.
The redraw occurred because GtkLabels resize themselves and everything
around them by sending a resize message any time they receive new
text. These resizes then trigger the full canvas resize which triggers
a full canvas redraw that cannot be optimized by either Gtk or Big Sur.
MacOS changes:
Only redraws the cursor position label and each of the horizontal and
vertical rules (cursor tracking widgets) 3 times a second max for a
total of 9 redraws a second (ideally out of 60, though I don't believe
under any circumstances that GIMP achieves a 60fps).
Each of the cursor tracking widgets gets its own timeslice, and so
will not redraw when the other cursor tracking widgets are drawing.
This is required because Big Sur is merging all draw rects into
one large rect, dramatically slowing down draws.
This timeslicing ensures that draw rects are maintained at the smallest
possible size. So the typical redraw is a small rect around the
brush. However, 9 times a second, the rect will include one of the
3 cursor tracking widgets (rulers and cursor label).
Additionally, the code tries to minimize resizing the width of the
cursor label by checking if the widget is too small for the text,
then setting the char_width to a greater size so that resizes won't
be that common.
This improves the appearance of the widget as it no longer
constantly jumps about in size on each cursor move.
Here is a discussion of the issue:
https://gitlab.gnome.org/GNOME/gimp/-/merge_requests/572#note_1389445
Reviewer's (Jehan) notes:
* The whole issue about GtkLabel resizing is no more after 32049afd. It
is normal for a widget to request a resize when needed. We just don't
want the statusbar to resize and triggering canvas redraws.
* Changing cursor position text into an idle function generally makes
sense.
Also it reverts commit 6de9ea70223 which had a bug I hadn't realized
when I accepted it: when we test for time, we don't know yet if it
will be the last position change, hence we could "refuse" the last
update. Therefore displayed cursor position would end up outdated
on macOS. This new implementation doesn't have the problem (the last
idle update always happens after the last move).
* The change about giving 1/3 timeslices to side canvas components
(rulers and statusbar) is a complete hack to work around the fact that
macOs doesn't report properly each damaged rectangle. Instead it
returns a huge bounding box. The workaround here is to expose these
area separately.
We have not been able to find a proper solution yet. This is the only
reason why I accept this code, for macOS only, to at least have
something usable there.
See discussions in MRs gimp!572 and gimp-macos-build!86. With these 2
MRs, Lukas reported GIMP 2.99 to perform even better than GIMP 2.10 on
Monterey, though it could not be tested on Big Sur unfortunately.
* Lastly the set_width_chars() thing is also an ugly hack which I will
try later to revisit (see !581). I only accepted it (with mandatory
macOS-only macro) to have an acceptable state for release after seeing
a screencast where the label size indeed "jumps around" on macOS.
2022-02-19 09:25:51 +08:00
|
|
|
/*
|
|
|
|
* pos_redraw_idle_id being set can be counted on to mean
|
|
|
|
* a redraw is needed (on mac only) since we will not do
|
|
|
|
* a high priority draws due to the dramatic performance
|
|
|
|
* they will have.
|
|
|
|
*/
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->pos_redraw_idle_id = 0;
|
2015-09-27 19:45:13 +08:00
|
|
|
|
2015-09-06 12:05:32 +08:00
|
|
|
return G_SOURCE_REMOVE;
|
|
|
|
}
|
|
|
|
|
|
|
|
static void
|
|
|
|
gimp_ruler_queue_pos_redraw (GimpRuler *ruler)
|
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
const GdkRectangle rect = gimp_ruler_get_pos_rect (ruler, ruler->position);
|
2015-09-29 10:10:30 +08:00
|
|
|
GtkAllocation allocation;
|
|
|
|
|
|
|
|
gtk_widget_get_allocation (GTK_WIDGET(ruler), &allocation);
|
2015-09-06 12:05:32 +08:00
|
|
|
|
2016-09-23 05:03:53 +08:00
|
|
|
gtk_widget_queue_draw_area (GTK_WIDGET (ruler),
|
2015-09-29 10:10:30 +08:00
|
|
|
rect.x + allocation.x,
|
|
|
|
rect.y + allocation.y,
|
2015-09-06 12:05:32 +08:00
|
|
|
rect.width,
|
|
|
|
rect.height);
|
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->last_pos_rect.width != 0 &&
|
|
|
|
ruler->last_pos_rect.height != 0)
|
2015-09-06 12:05:32 +08:00
|
|
|
{
|
2016-09-23 05:03:53 +08:00
|
|
|
gtk_widget_queue_draw_area (GTK_WIDGET (ruler),
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->last_pos_rect.x + allocation.x,
|
|
|
|
ruler->last_pos_rect.y + allocation.y,
|
|
|
|
ruler->last_pos_rect.width,
|
|
|
|
ruler->last_pos_rect.height);
|
|
|
|
|
|
|
|
ruler->last_pos_rect.x = 0;
|
|
|
|
ruler->last_pos_rect.y = 0;
|
|
|
|
ruler->last_pos_rect.width = 0;
|
|
|
|
ruler->last_pos_rect.height = 0;
|
2015-09-06 12:05:32 +08:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2015-08-12 04:20:59 +08:00
|
|
|
static void
|
2015-09-27 19:45:13 +08:00
|
|
|
gimp_ruler_draw_pos (GimpRuler *ruler,
|
|
|
|
cairo_t *cr)
|
2015-08-12 04:20:59 +08:00
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
GtkWidget *widget = GTK_WIDGET (ruler);
|
|
|
|
GtkStyleContext *context = gtk_widget_get_style_context (widget);
|
|
|
|
GdkRectangle pos_rect;
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2015-08-12 04:20:59 +08:00
|
|
|
if (! gtk_widget_is_drawable (widget))
|
|
|
|
return;
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2015-08-12 04:20:59 +08:00
|
|
|
pos_rect = gimp_ruler_get_pos_rect (ruler, gimp_ruler_get_position (ruler));
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2015-08-12 04:20:59 +08:00
|
|
|
if ((pos_rect.width > 0) && (pos_rect.height > 0))
|
|
|
|
{
|
2010-12-17 05:12:09 +08:00
|
|
|
GdkRGBA color;
|
|
|
|
|
|
|
|
gtk_style_context_get_color (context, gtk_widget_get_state_flags (widget),
|
|
|
|
&color);
|
|
|
|
gdk_cairo_set_source_rgba (cr, &color);
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2015-08-12 04:20:59 +08:00
|
|
|
cairo_move_to (cr, pos_rect.x, pos_rect.y);
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->orientation == GTK_ORIENTATION_HORIZONTAL)
|
2008-09-02 20:30:53 +08:00
|
|
|
{
|
2015-08-12 04:20:59 +08:00
|
|
|
cairo_line_to (cr, pos_rect.x + pos_rect.width / 2.0,
|
|
|
|
pos_rect.y + pos_rect.height);
|
|
|
|
cairo_line_to (cr, pos_rect.x + pos_rect.width,
|
|
|
|
pos_rect.y);
|
2008-09-02 20:30:53 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2015-08-12 04:20:59 +08:00
|
|
|
cairo_line_to (cr, pos_rect.x + pos_rect.width,
|
|
|
|
pos_rect.y + pos_rect.height / 2.0);
|
|
|
|
cairo_line_to (cr, pos_rect.x,
|
|
|
|
pos_rect.y + pos_rect.height);
|
2008-09-02 20:30:53 +08:00
|
|
|
}
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2008-09-02 20:30:53 +08:00
|
|
|
cairo_fill (cr);
|
2008-08-29 18:25:29 +08:00
|
|
|
}
|
2015-09-06 12:05:32 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->last_pos_rect.width != 0 &&
|
|
|
|
ruler->last_pos_rect.height != 0)
|
2016-09-23 05:03:53 +08:00
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
gdk_rectangle_union (&ruler->last_pos_rect,
|
2016-09-23 05:03:53 +08:00
|
|
|
&pos_rect,
|
2024-07-27 00:21:01 +08:00
|
|
|
&ruler->last_pos_rect);
|
2016-09-23 05:03:53 +08:00
|
|
|
}
|
|
|
|
else
|
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->last_pos_rect = pos_rect;
|
2016-09-23 05:03:53 +08:00
|
|
|
}
|
2008-05-28 19:49:24 +08:00
|
|
|
}
|
|
|
|
|
2008-05-27 05:20:16 +08:00
|
|
|
static void
|
|
|
|
gimp_ruler_make_pixmap (GimpRuler *ruler)
|
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
GtkWidget *widget = GTK_WIDGET (ruler);
|
|
|
|
GtkAllocation allocation;
|
2008-05-27 05:20:16 +08:00
|
|
|
|
2009-10-18 00:51:48 +08:00
|
|
|
gtk_widget_get_allocation (widget, &allocation);
|
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->backing_store)
|
|
|
|
cairo_surface_destroy (ruler->backing_store);
|
2008-05-27 05:20:16 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->backing_store =
|
2011-04-07 02:18:14 +08:00
|
|
|
gdk_window_create_similar_surface (gtk_widget_get_window (widget),
|
2015-09-29 10:42:46 +08:00
|
|
|
CAIRO_CONTENT_COLOR_ALPHA,
|
2011-04-07 02:18:14 +08:00
|
|
|
allocation.width,
|
|
|
|
allocation.height);
|
2015-08-12 04:20:59 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->backing_store_valid = FALSE;
|
2008-05-27 05:20:16 +08:00
|
|
|
}
|
2008-08-29 18:25:29 +08:00
|
|
|
|
2008-10-05 07:32:41 +08:00
|
|
|
static PangoLayout *
|
|
|
|
gimp_ruler_get_layout (GtkWidget *widget,
|
|
|
|
const gchar *text)
|
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
GimpRuler *ruler = GIMP_RULER (widget);
|
2008-10-05 07:32:41 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
if (ruler->layout)
|
2008-10-05 07:32:41 +08:00
|
|
|
{
|
2024-07-27 00:21:01 +08:00
|
|
|
pango_layout_set_text (ruler->layout, text, -1);
|
|
|
|
return ruler->layout;
|
2008-10-05 07:32:41 +08:00
|
|
|
}
|
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
ruler->layout = gtk_widget_create_pango_layout (widget, text);
|
2008-10-05 07:32:41 +08:00
|
|
|
|
2024-07-27 00:21:01 +08:00
|
|
|
return ruler->layout;
|
2008-10-05 07:32:41 +08:00
|
|
|
}
|
2018-02-12 19:20:32 +08:00
|
|
|
|
2018-02-28 03:28:50 +08:00
|
|
|
#define FACTOR_EPSILON 0.0000001
|
|
|
|
#define FACTOR_EQUAL(u, f) (ABS (f - gimp_unit_get_factor (u)) < FACTOR_EPSILON)
|
|
|
|
|
2018-02-12 19:20:32 +08:00
|
|
|
static const RulerMetric *
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-26 02:55:21 +08:00
|
|
|
gimp_ruler_get_metric (GimpUnit *unit)
|
2018-02-12 19:20:32 +08:00
|
|
|
{
|
Issue #8900 and #9923: reimplementing GimpUnit as a proper class.
This fixes all our GObject Introspection issues with GimpUnit which was
both an enum and an int-derived type of user-defined units *completing*
the enum values. GIR clearly didn't like this!
Now GimpUnit is a proper class and units are unique objects, allowing to
compare them with an identity test (i.e. `unit == gimp_unit_pixel ()`
tells us if unit is the pixel unit or not), which makes it easy to use,
just like with int, yet adding also methods, making for nicer
introspected API.
As an aside, this also fixes #10738, by having all the built-in units
retrievable even if libgimpbase had not been properly initialized with
gimp_base_init().
I haven't checked in details how GIR works to introspect, but it looks
like it loads the library to inspect and runs functions, hence
triggering some CRITICALS because virtual methods (supposed to be
initialized with gimp_base_init() run by libgimp) are not set. This new
code won't trigger any critical because the vtable method are now not
necessary, at least for all built-in units.
Note that GimpUnit is still in libgimpbase. It could have been moved to
libgimp in order to avoid any virtual method table (since we need to
keep core and libgimp side's units in sync, PDB is required), but too
many libgimpwidgets widgets were already using GimpUnit. And technically
most of GimpUnit logic doesn't require PDB (only the creation/sync
part). This is one of the reasons why user-created GimpUnit list is
handled and stored differently from other types of objects.
Globally this simplifies the code a lot too and we don't need separate
implementations of various utils for core and libgimp, which means less
prone to errors.
2024-07-26 02:55:21 +08:00
|
|
|
if (unit == gimp_unit_inch ())
|
2018-02-28 03:28:50 +08:00
|
|
|
{
|
|
|
|
return &ruler_metric_inches;
|
|
|
|
}
|
2019-06-23 22:29:47 +08:00
|
|
|
/* XXX: recognizing feet or yard unit this way definitely sucks.
|
|
|
|
* Actually the subdvision and rule scale rules should probably become
|
|
|
|
* settable values in unitrc instead of hardcoded rules.
|
|
|
|
* This way, people would be able to set how they want a unit to be
|
|
|
|
* shown (we could definitely imagine someone wanting to see inches
|
|
|
|
* with base-10 divisions).
|
|
|
|
*/
|
2018-02-28 03:28:50 +08:00
|
|
|
else if (FACTOR_EQUAL (unit, 0.083333))
|
|
|
|
{
|
|
|
|
return &ruler_metric_feet;
|
|
|
|
}
|
|
|
|
else if (FACTOR_EQUAL (unit, 0.027778))
|
|
|
|
{
|
|
|
|
return &ruler_metric_yards;
|
|
|
|
}
|
2018-02-12 19:20:32 +08:00
|
|
|
|
|
|
|
return &ruler_metric_decimal;
|
|
|
|
}
|