
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.
1174 lines
32 KiB
C
1174 lines
32 KiB
C
/* LIBGIMP - The GIMP Library
|
|
* Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
|
|
*
|
|
* gimpunit.c
|
|
* Copyright (C) 2003 Michael Natterer <mitch@gimp.org>
|
|
*
|
|
* This library is free software: you can redistribute it and/or
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
* License as published by the Free Software Foundation; either
|
|
* version 3 of the License, or (at your option) any later version.
|
|
*
|
|
* 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
|
|
* License along with this library. If not, see
|
|
* <https://www.gnu.org/licenses/>.
|
|
*/
|
|
|
|
#include "config.h"
|
|
|
|
#include <math.h>
|
|
#include <string.h>
|
|
|
|
#include <gegl.h>
|
|
#include <glib-object.h>
|
|
|
|
#include "gimpbasetypes.h"
|
|
|
|
#include "gimpbase-private.h"
|
|
#include "gimpparamspecs.h"
|
|
#include "gimpunit.h"
|
|
|
|
#include "libgimp/libgimp-intl.h"
|
|
|
|
|
|
enum
|
|
{
|
|
PROP_0,
|
|
PROP_ID,
|
|
PROP_NAME,
|
|
PROP_FACTOR,
|
|
PROP_DIGITS,
|
|
PROP_SYMBOL,
|
|
PROP_ABBREVIATION,
|
|
PROP_SINGULAR,
|
|
PROP_PLURAL,
|
|
};
|
|
|
|
typedef struct
|
|
{
|
|
gboolean delete_on_exit;
|
|
gdouble factor;
|
|
gint digits;
|
|
gchar *identifier;
|
|
gchar *symbol;
|
|
gchar *abbreviation;
|
|
gchar *singular;
|
|
gchar *plural;
|
|
} GimpUnitDef;
|
|
|
|
struct _GimpUnit
|
|
{
|
|
GObject parent_instance;
|
|
|
|
gint id;
|
|
gchar *name;
|
|
|
|
gboolean built_in;
|
|
|
|
gboolean delete_on_exit;
|
|
gdouble factor;
|
|
gint digits;
|
|
gchar *symbol;
|
|
gchar *abbreviation;
|
|
gchar *singular;
|
|
gchar *plural;
|
|
};
|
|
|
|
|
|
/* these are the built-in units
|
|
*/
|
|
static const GimpUnitDef _gimp_unit_defs[GIMP_UNIT_END] =
|
|
{
|
|
/* pseudo unit */
|
|
{ FALSE, 0.0, 0, "pixels", "px", "px",
|
|
NC_("unit-singular", "pixel"), NC_("unit-plural", "pixels") },
|
|
|
|
/* standard units */
|
|
{ FALSE, 1.0, 2, "inches", "''", "in",
|
|
NC_("unit-singular", "inch"), NC_("unit-plural", "inches") },
|
|
|
|
{ FALSE, 25.4, 1, "millimeters", "mm", "mm",
|
|
NC_("unit-singular", "millimeter"), NC_("unit-plural", "millimeters") },
|
|
|
|
/* professional units */
|
|
{ FALSE, 72.0, 0, "points", "pt", "pt",
|
|
NC_("unit-singular", "point"), NC_("unit-plural", "points") },
|
|
|
|
{ FALSE, 6.0, 1, "picas", "pc", "pc",
|
|
NC_("unit-singular", "pica"), NC_("unit-plural", "picas") }
|
|
};
|
|
|
|
/* not a unit at all but kept here to have the strings in one place
|
|
*/
|
|
static const GimpUnitDef _gimp_unit_percent_def =
|
|
{
|
|
FALSE, 0.0, 0, "percent", "%", "%",
|
|
NC_("singular", "percent"), NC_("plural", "percent")
|
|
};
|
|
|
|
|
|
static void gimp_unit_constructed (GObject *object);
|
|
static void gimp_unit_finalize (GObject *object);
|
|
static void gimp_unit_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec);
|
|
static void gimp_unit_get_property (GObject *object,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec);
|
|
|
|
static gint print (gchar *buf,
|
|
gint len,
|
|
gint start,
|
|
const gchar *fmt,
|
|
...) G_GNUC_PRINTF (4, 5);
|
|
|
|
|
|
G_DEFINE_TYPE (GimpUnit, gimp_unit, G_TYPE_OBJECT)
|
|
|
|
#define parent_class gimp_unit_parent_class
|
|
|
|
|
|
static void
|
|
gimp_unit_class_init (GimpUnitClass *klass)
|
|
{
|
|
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
|
|
|
parent_class = g_type_class_peek_parent (klass);
|
|
|
|
object_class->constructed = gimp_unit_constructed;
|
|
object_class->finalize = gimp_unit_finalize;
|
|
object_class->set_property = gimp_unit_set_property;
|
|
object_class->get_property = gimp_unit_get_property;
|
|
|
|
g_object_class_install_property (object_class, PROP_ID,
|
|
g_param_spec_int ("id", NULL, NULL,
|
|
0, G_MAXINT, 0,
|
|
GIMP_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY));
|
|
g_object_class_install_property (object_class, PROP_NAME,
|
|
g_param_spec_string ("name", NULL, NULL,
|
|
NULL,
|
|
GIMP_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY));
|
|
g_object_class_install_property (object_class, PROP_FACTOR,
|
|
g_param_spec_double ("factor", NULL, NULL,
|
|
0.0, G_MAXDOUBLE, 1.0,
|
|
GIMP_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY));
|
|
g_object_class_install_property (object_class, PROP_DIGITS,
|
|
g_param_spec_int ("digits", NULL, NULL,
|
|
0, G_MAXINT, 0,
|
|
GIMP_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY));
|
|
g_object_class_install_property (object_class, PROP_SYMBOL,
|
|
g_param_spec_string ("symbol", NULL, NULL,
|
|
NULL,
|
|
GIMP_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY));
|
|
g_object_class_install_property (object_class, PROP_ABBREVIATION,
|
|
g_param_spec_string ("abbreviation", NULL, NULL,
|
|
NULL,
|
|
GIMP_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY));
|
|
g_object_class_install_property (object_class, PROP_SINGULAR,
|
|
g_param_spec_string ("singular", NULL, NULL,
|
|
NULL,
|
|
GIMP_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY));
|
|
g_object_class_install_property (object_class, PROP_PLURAL,
|
|
g_param_spec_string ("plural", NULL, NULL,
|
|
NULL,
|
|
GIMP_PARAM_READWRITE |
|
|
G_PARAM_CONSTRUCT_ONLY));
|
|
|
|
/*klass->id_table = gimp_id_table_new ();*/
|
|
}
|
|
|
|
static void
|
|
gimp_unit_init (GimpUnit *unit)
|
|
{
|
|
unit->name = NULL;
|
|
unit->symbol = NULL;
|
|
unit->abbreviation = NULL;
|
|
unit->singular = NULL;
|
|
unit->plural = NULL;
|
|
}
|
|
|
|
static void
|
|
gimp_unit_constructed (GObject *object)
|
|
{
|
|
G_OBJECT_CLASS (parent_class)->constructed (object);
|
|
}
|
|
|
|
static void
|
|
gimp_unit_finalize (GObject *object)
|
|
{
|
|
GimpUnit *unit = GIMP_UNIT (object);
|
|
|
|
g_free (unit->name);
|
|
g_free (unit->symbol);
|
|
g_free (unit->abbreviation);
|
|
g_free (unit->singular);
|
|
g_free (unit->plural);
|
|
|
|
G_OBJECT_CLASS (parent_class)->finalize (object);
|
|
}
|
|
|
|
static void
|
|
gimp_unit_set_property (GObject *object,
|
|
guint property_id,
|
|
const GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GimpUnit *unit = GIMP_UNIT (object);
|
|
|
|
switch (property_id)
|
|
{
|
|
case PROP_ID:
|
|
unit->id = g_value_get_int (value);
|
|
break;
|
|
case PROP_NAME:
|
|
unit->name = g_value_dup_string (value);
|
|
break;
|
|
case PROP_FACTOR:
|
|
unit->factor = g_value_get_double (value);
|
|
break;
|
|
case PROP_DIGITS:
|
|
unit->digits = g_value_get_int (value);
|
|
break;
|
|
case PROP_SYMBOL:
|
|
unit->symbol = g_value_dup_string (value);
|
|
break;
|
|
case PROP_ABBREVIATION:
|
|
unit->abbreviation = g_value_dup_string (value);
|
|
break;
|
|
case PROP_SINGULAR:
|
|
unit->singular = g_value_dup_string (value);
|
|
break;
|
|
case PROP_PLURAL:
|
|
unit->plural = g_value_dup_string (value);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
static void
|
|
gimp_unit_get_property (GObject *object,
|
|
guint property_id,
|
|
GValue *value,
|
|
GParamSpec *pspec)
|
|
{
|
|
GimpUnit *unit = GIMP_UNIT (object);
|
|
|
|
switch (property_id)
|
|
{
|
|
case PROP_ID:
|
|
g_value_set_int (value, unit->id);
|
|
break;
|
|
case PROP_NAME:
|
|
g_value_set_string (value, unit->name);
|
|
break;
|
|
case PROP_FACTOR:
|
|
g_value_set_double (value, unit->factor);
|
|
break;
|
|
case PROP_DIGITS:
|
|
g_value_set_int (value, unit->digits);
|
|
break;
|
|
case PROP_SYMBOL:
|
|
g_value_set_string (value, unit->symbol);
|
|
break;
|
|
case PROP_ABBREVIATION:
|
|
g_value_set_string (value, unit->abbreviation);
|
|
break;
|
|
case PROP_SINGULAR:
|
|
g_value_set_string (value, unit->singular);
|
|
break;
|
|
case PROP_PLURAL:
|
|
g_value_set_string (value, unit->plural);
|
|
break;
|
|
|
|
default:
|
|
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
|
break;
|
|
}
|
|
}
|
|
|
|
/* public functions */
|
|
|
|
|
|
/**
|
|
* gimp_unit_get_id:
|
|
* @unit: The unit you want to know the integer ID of.
|
|
*
|
|
* The ID can be used to retrieve the unit with [func@Unit.get_by_id].
|
|
*
|
|
* Note that this ID will be stable within a single session of GIMP, but
|
|
* you should not expect this ID to stay the same across multiple runs.
|
|
*
|
|
* Returns: The unit's ID.
|
|
**/
|
|
gint
|
|
gimp_unit_get_id (GimpUnit *unit)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_UNIT (unit), -1);
|
|
|
|
return unit->id;
|
|
}
|
|
|
|
/**
|
|
* gimp_unit_get_identifier:
|
|
* @unit: The unit you want to know the identifier of.
|
|
*
|
|
* This is an untranslated string which must not be changed or freed.
|
|
*
|
|
* Returns: The unit's identifier.
|
|
**/
|
|
const gchar *
|
|
gimp_unit_get_identifier (GimpUnit *unit)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_UNIT (unit), NULL);
|
|
|
|
return unit->name;
|
|
}
|
|
|
|
/**
|
|
* gimp_unit_get_factor:
|
|
* @unit: The unit you want to know the factor of.
|
|
*
|
|
* A #GimpUnit's @factor is defined to be:
|
|
*
|
|
* distance_in_units == (@factor * distance_in_inches)
|
|
*
|
|
* Returns 0 for @unit == GIMP_UNIT_PIXEL.
|
|
*
|
|
* Returns: The unit's factor.
|
|
**/
|
|
gdouble
|
|
gimp_unit_get_factor (GimpUnit *unit)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_UNIT (unit), 1.0);
|
|
|
|
return unit->factor;
|
|
}
|
|
|
|
/**
|
|
* gimp_unit_get_digits:
|
|
* @unit: The unit you want to know the digits.
|
|
*
|
|
* Returns the number of digits set for @unit.
|
|
* Built-in units' accuracy is approximately the same as an inch with
|
|
* two digits. User-defined units can suggest a different accuracy.
|
|
*
|
|
* Note: the value is as-set by defaults or by the user and does not
|
|
* necessary provide enough precision on high-resolution units.
|
|
* When the information is needed for a specific unit, the use of
|
|
* gimp_unit_get_scaled_digits() may be more appropriate.
|
|
*
|
|
* Returns 0 for @unit == GIMP_UNIT_PIXEL.
|
|
*
|
|
* Returns: The suggested number of digits.
|
|
**/
|
|
gint
|
|
gimp_unit_get_digits (GimpUnit *unit)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_UNIT (unit), 0);
|
|
|
|
return unit->digits;
|
|
}
|
|
|
|
/**
|
|
* gimp_unit_get_scaled_digits:
|
|
* @unit: The unit you want to know the digits.
|
|
* @resolution: the resolution in PPI.
|
|
*
|
|
* Returns the number of digits a @unit field should provide to get
|
|
* enough accuracy so that every pixel position shows a different
|
|
* value from neighboring pixels.
|
|
*
|
|
* Note: when needing digit accuracy to display a diagonal distance,
|
|
* the @resolution may not correspond to the unit's horizontal or
|
|
* vertical resolution, but instead to the result of:
|
|
* `distance_in_pixel / distance_in_inch`.
|
|
*
|
|
* Returns: The suggested number of digits.
|
|
**/
|
|
gint
|
|
gimp_unit_get_scaled_digits (GimpUnit *unit,
|
|
gdouble resolution)
|
|
{
|
|
gint digits;
|
|
|
|
g_return_val_if_fail (GIMP_IS_UNIT (unit), 0);
|
|
|
|
digits = ceil (log10 (1.0 /
|
|
gimp_pixels_to_units (1.0, unit, resolution)));
|
|
|
|
return MAX (digits, gimp_unit_get_digits (unit));
|
|
}
|
|
|
|
/**
|
|
* gimp_unit_get_symbol:
|
|
* @unit: The unit you want to know the symbol of.
|
|
*
|
|
* This is e.g. "''" for UNIT_INCH.
|
|
*
|
|
* NOTE: This string must not be changed or freed.
|
|
*
|
|
* Returns: The unit's symbol.
|
|
**/
|
|
const gchar *
|
|
gimp_unit_get_symbol (GimpUnit *unit)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_UNIT (unit), NULL);
|
|
|
|
return unit->symbol;
|
|
}
|
|
|
|
/**
|
|
* gimp_unit_get_abbreviation:
|
|
* @unit: The unit you want to know the abbreviation of.
|
|
*
|
|
* For built-in units, this function returns the abbreviation
|
|
* of the unit (e.g. "in" for inches).
|
|
*
|
|
* NOTE: This string must not be changed or freed.
|
|
*
|
|
* Returns: The unit's abbreviation.
|
|
**/
|
|
const gchar *
|
|
gimp_unit_get_abbreviation (GimpUnit *unit)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_UNIT (unit), NULL);
|
|
|
|
return unit->abbreviation;
|
|
}
|
|
|
|
/**
|
|
* gimp_unit_get_singular:
|
|
* @unit: The unit you want to know the singular form of.
|
|
*
|
|
* For built-in units, this function returns the singular form of the
|
|
* unit's name.
|
|
*
|
|
* NOTE: This string must not be changed or freed.
|
|
*
|
|
* Returns: The unit's singular form.
|
|
**/
|
|
const gchar *
|
|
gimp_unit_get_singular (GimpUnit *unit)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_UNIT (unit), NULL);
|
|
|
|
return unit->singular;
|
|
}
|
|
|
|
/**
|
|
* gimp_unit_get_plural:
|
|
* @unit: The unit you want to know the plural form of.
|
|
*
|
|
* For built-in units, this function returns the plural form of the
|
|
* unit's name.
|
|
*
|
|
* NOTE: This string must not be changed or freed.
|
|
*
|
|
* Returns: The unit's plural form.
|
|
**/
|
|
const gchar *
|
|
gimp_unit_get_plural (GimpUnit *unit)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_UNIT (unit), NULL);
|
|
|
|
return unit->plural;
|
|
}
|
|
|
|
/**
|
|
* gimp_unit_get_deletion_flag:
|
|
* @unit: The unit you want to know the @deletion_flag of.
|
|
*
|
|
* Returns: The unit's @deletion_flag.
|
|
**/
|
|
gboolean
|
|
gimp_unit_get_deletion_flag (GimpUnit *unit)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_UNIT (unit), TRUE);
|
|
|
|
if ((unit->id >= 0 && unit->id < GIMP_UNIT_END) ||
|
|
unit->id == GIMP_UNIT_PERCENT)
|
|
return FALSE;
|
|
|
|
if (_gimp_unit_vtable.get_deletion_flag != NULL)
|
|
/* This code path will only happen in libgimp. */
|
|
return _gimp_unit_vtable.get_deletion_flag (unit);
|
|
else
|
|
return unit->delete_on_exit;
|
|
}
|
|
|
|
/**
|
|
* gimp_unit_set_deletion_flag:
|
|
* @unit: The unit you want to set the @deletion_flag for.
|
|
* @deletion_flag: The new deletion_flag.
|
|
*
|
|
* Sets a #GimpUnit's @deletion_flag. If the @deletion_flag of a unit is
|
|
* %TRUE when GIMP exits, this unit will not be saved in the users's
|
|
* "unitrc" file.
|
|
*
|
|
* Trying to change the @deletion_flag of a built-in unit will be silently
|
|
* ignored.
|
|
**/
|
|
void
|
|
gimp_unit_set_deletion_flag (GimpUnit *unit,
|
|
gboolean deletion_flag)
|
|
{
|
|
g_return_if_fail (GIMP_IS_UNIT (unit));
|
|
|
|
if ((unit->id >= 0 && unit->id < GIMP_UNIT_END) ||
|
|
unit->id == GIMP_UNIT_PERCENT)
|
|
return;
|
|
|
|
unit->delete_on_exit = deletion_flag;
|
|
|
|
if (_gimp_unit_vtable.set_deletion_flag != NULL)
|
|
/* This code path will only happen in libgimp. */
|
|
_gimp_unit_vtable.set_deletion_flag (unit, deletion_flag);
|
|
}
|
|
|
|
/**
|
|
* gimp_unit_get_by_id:
|
|
* @unit_id: The unit id.
|
|
*
|
|
* Returns the unique [class@Unit] object corresponding to @unit_id,
|
|
* which is the integer identifier as returned by [method@Unit.get_id].
|
|
*
|
|
* Returns: (transfer none): the #GimpUnit object with ID @unit_id.
|
|
*
|
|
* Since: 3.0
|
|
**/
|
|
GimpUnit *
|
|
gimp_unit_get_by_id (gint unit_id)
|
|
{
|
|
GimpUnit *unit = NULL;
|
|
|
|
if (unit_id < 0)
|
|
return NULL;
|
|
|
|
if (G_UNLIKELY (! _gimp_units))
|
|
_gimp_units = g_hash_table_new_full (g_direct_hash,
|
|
g_direct_equal,
|
|
NULL,
|
|
(GDestroyNotify) g_object_unref);
|
|
|
|
unit = g_hash_table_lookup (_gimp_units, GINT_TO_POINTER (unit_id));
|
|
|
|
if (! unit)
|
|
{
|
|
if (unit_id < GIMP_UNIT_END)
|
|
{
|
|
GimpUnitDef def = _gimp_unit_defs[unit_id];
|
|
|
|
unit = g_object_new (GIMP_TYPE_UNIT,
|
|
"id", unit_id,
|
|
"name", def.identifier,
|
|
"factor", def.factor,
|
|
"digits", def.digits,
|
|
"symbol", def.symbol,
|
|
"abbreviation", def.abbreviation,
|
|
"singular", def.singular,
|
|
"plural", def.plural,
|
|
NULL);
|
|
unit->delete_on_exit = FALSE;
|
|
}
|
|
else if (unit_id == GIMP_UNIT_PERCENT)
|
|
{
|
|
unit = g_object_new (GIMP_TYPE_UNIT,
|
|
"id", unit_id,
|
|
"name", _gimp_unit_percent_def.identifier,
|
|
"factor", _gimp_unit_percent_def.factor,
|
|
"digits", _gimp_unit_percent_def.digits,
|
|
"symbol", _gimp_unit_percent_def.symbol,
|
|
"abbreviation", _gimp_unit_percent_def.abbreviation,
|
|
"singular", _gimp_unit_percent_def.singular,
|
|
"plural", _gimp_unit_percent_def.plural,
|
|
NULL);
|
|
unit->delete_on_exit = FALSE;
|
|
}
|
|
else if (_gimp_unit_vtable.get_data != NULL)
|
|
{
|
|
/* This code path should never happen in app/ where get_data()
|
|
* is NULL, because non built-in units are created in app/
|
|
* whereas they are only queried in libgimp.
|
|
*/
|
|
gchar *identifier = NULL;
|
|
gdouble factor;
|
|
gint digits;
|
|
gchar *symbol = NULL;
|
|
gchar *abbreviation = NULL;
|
|
gchar *singular = NULL;
|
|
gchar *plural = NULL;
|
|
|
|
identifier = _gimp_unit_vtable.get_data (unit_id,
|
|
&factor,
|
|
&digits,
|
|
&symbol,
|
|
&abbreviation,
|
|
&singular,
|
|
&plural);
|
|
|
|
if (identifier != NULL)
|
|
unit = g_object_new (GIMP_TYPE_UNIT,
|
|
"id", unit_id,
|
|
"name", identifier,
|
|
"factor", factor,
|
|
"digits", digits,
|
|
"symbol", symbol,
|
|
"abbreviation", abbreviation,
|
|
"singular", singular,
|
|
"plural", plural,
|
|
NULL);
|
|
|
|
g_free (identifier);
|
|
g_free (symbol);
|
|
g_free (abbreviation);
|
|
g_free (singular);
|
|
g_free (plural);
|
|
}
|
|
else if (_gimp_unit_vtable.get_user_unit != NULL)
|
|
{
|
|
/* This code path should never happen in libgimp, only in app/. */
|
|
|
|
unit = _gimp_unit_vtable.get_user_unit (unit_id);
|
|
|
|
if (unit != NULL)
|
|
g_object_ref (unit);
|
|
}
|
|
|
|
if (unit != NULL)
|
|
g_hash_table_insert (_gimp_units, GINT_TO_POINTER (unit_id), unit);
|
|
}
|
|
|
|
return unit;
|
|
}
|
|
|
|
/**
|
|
* gimp_unit_pixel:
|
|
*
|
|
* Returns the unique object representing pixel unit.
|
|
*
|
|
* This procedure returns the unit representing pixel. The returned
|
|
* object is unique across the whole run.
|
|
*
|
|
* Returns: (transfer none): The unique pixel unit.
|
|
*
|
|
* Since: 3.0
|
|
**/
|
|
GimpUnit *
|
|
gimp_unit_pixel (void)
|
|
{
|
|
return gimp_unit_get_by_id (GIMP_UNIT_PIXEL);
|
|
}
|
|
|
|
/**
|
|
* gimp_unit_inch:
|
|
*
|
|
* Returns the unique object representing inch unit.
|
|
*
|
|
* This procedure returns the unit representing inch. The returned
|
|
* object is unique across the whole run.
|
|
*
|
|
* Returns: (transfer none): The unique inch unit.
|
|
*
|
|
* Since: 3.0
|
|
**/
|
|
GimpUnit *
|
|
gimp_unit_inch (void)
|
|
{
|
|
return gimp_unit_get_by_id (GIMP_UNIT_INCH);
|
|
}
|
|
|
|
/**
|
|
* gimp_unit_mm:
|
|
*
|
|
* Returns the unique object representing millimeter unit.
|
|
*
|
|
* This procedure returns the unit representing millimeter. The
|
|
* returned object is unique across the whole run.
|
|
*
|
|
* Returns: (transfer none): The unique millimeter unit.
|
|
*
|
|
* Since: 3.0
|
|
**/
|
|
GimpUnit *
|
|
gimp_unit_mm (void)
|
|
{
|
|
return gimp_unit_get_by_id (GIMP_UNIT_MM);
|
|
}
|
|
|
|
/**
|
|
* gimp_unit_point:
|
|
*
|
|
* Returns the unique object representing typographical point unit.
|
|
*
|
|
* This procedure returns the unit representing typographical points.
|
|
* The returned object is unique across the whole run.
|
|
*
|
|
* Returns: (transfer none): The unique point unit.
|
|
*
|
|
* Since: 3.0
|
|
**/
|
|
GimpUnit *
|
|
gimp_unit_point (void)
|
|
{
|
|
return gimp_unit_get_by_id (GIMP_UNIT_POINT);
|
|
}
|
|
|
|
/**
|
|
* gimp_unit_pica:
|
|
*
|
|
* Returns the unique object representing Pica unit.
|
|
*
|
|
* This procedure returns the unit representing Picas.
|
|
* The returned object is unique across the whole run.
|
|
*
|
|
* Returns: (transfer none): The unique pica unit.
|
|
*
|
|
* Since: 3.0
|
|
**/
|
|
GimpUnit *
|
|
gimp_unit_pica (void)
|
|
{
|
|
return gimp_unit_get_by_id (GIMP_UNIT_PICA);
|
|
}
|
|
|
|
/**
|
|
* gimp_unit_percent:
|
|
*
|
|
* Returns the unique object representing percent dimensions relatively
|
|
* to an image.
|
|
*
|
|
* This procedure returns the unit representing typographical points.
|
|
* The returned object is unique across the whole run.
|
|
*
|
|
* Returns: (transfer none): The unique percent unit.
|
|
*
|
|
* Since: 3.0
|
|
**/
|
|
GimpUnit *
|
|
gimp_unit_percent (void)
|
|
{
|
|
return gimp_unit_get_by_id (GIMP_UNIT_PERCENT);
|
|
}
|
|
|
|
/**
|
|
* gimp_unit_is_built_in:
|
|
* @unit: the unit.
|
|
*
|
|
* Returns whether the unit is built-in.
|
|
*
|
|
* This procedure returns @unit is a built-in unit. In particular the
|
|
* deletion flag cannot be set on built-in units.
|
|
*
|
|
* Returns: Whether @unit is built-in.
|
|
*
|
|
* Since: 3.0
|
|
**/
|
|
gboolean
|
|
gimp_unit_is_built_in (GimpUnit *unit)
|
|
{
|
|
g_return_val_if_fail (GIMP_IS_UNIT (unit), FALSE);
|
|
|
|
return (unit->id >= 0 && unit->id < GIMP_UNIT_END) || unit->id == GIMP_UNIT_PERCENT;
|
|
}
|
|
|
|
/**
|
|
* gimp_unit_is_metric:
|
|
* @unit: The unit
|
|
*
|
|
* Checks if the given @unit is metric. A simplistic test is used
|
|
* that looks at the unit's factor and checks if it is 2.54 multiplied
|
|
* by some common powers of 10. Currently it checks for mm, cm, dm, m.
|
|
*
|
|
* See also: gimp_unit_get_factor()
|
|
*
|
|
* Returns: %TRUE if the @unit is metric.
|
|
*
|
|
* Since: 2.10
|
|
**/
|
|
gboolean
|
|
gimp_unit_is_metric (GimpUnit *unit)
|
|
{
|
|
gdouble factor;
|
|
|
|
if (unit == gimp_unit_mm ())
|
|
return TRUE;
|
|
|
|
factor = gimp_unit_get_factor (unit);
|
|
|
|
if (factor == 0.0)
|
|
return FALSE;
|
|
|
|
return ((ABS (factor - 0.0254) < 1e-7) || /* m */
|
|
(ABS (factor - 0.254) < 1e-6) || /* dm */
|
|
(ABS (factor - 2.54) < 1e-5) || /* cm */
|
|
(ABS (factor - 25.4) < 1e-4)); /* mm */
|
|
}
|
|
|
|
/**
|
|
* gimp_unit_format_string:
|
|
* @format: A printf-like format string which is used to create the unit
|
|
* string.
|
|
* @unit: A unit.
|
|
*
|
|
* The @format string supports the following percent expansions:
|
|
*
|
|
* <informaltable pgwide="1" frame="none" role="enum">
|
|
* <tgroup cols="2"><colspec colwidth="1*"/><colspec colwidth="8*"/>
|
|
* <tbody>
|
|
* <row>
|
|
* <entry>% f</entry>
|
|
* <entry>Factor (how many units make up an inch)</entry>
|
|
* </row>
|
|
* <row>
|
|
* <entry>% y</entry>
|
|
* <entry>Symbol (e.g. "''" for GIMP_UNIT_INCH)</entry>
|
|
* </row>
|
|
* <row>
|
|
* <entry>% a</entry>
|
|
* <entry>Abbreviation</entry>
|
|
* </row>
|
|
* <row>
|
|
* <entry>% s</entry>
|
|
* <entry>Singular</entry>
|
|
* </row>
|
|
* <row>
|
|
* <entry>% p</entry>
|
|
* <entry>Plural</entry>
|
|
* </row>
|
|
* <row>
|
|
* <entry>%%</entry>
|
|
* <entry>Literal percent</entry>
|
|
* </row>
|
|
* </tbody>
|
|
* </tgroup>
|
|
* </informaltable>
|
|
*
|
|
* Returns: A newly allocated string with above percent expressions
|
|
* replaced with the resp. strings for @unit.
|
|
*
|
|
* Since: 2.8
|
|
**/
|
|
gchar *
|
|
gimp_unit_format_string (const gchar *format,
|
|
GimpUnit *unit)
|
|
{
|
|
gchar buffer[1024];
|
|
gint i = 0;
|
|
|
|
g_return_val_if_fail (GIMP_IS_UNIT (unit), NULL);
|
|
g_return_val_if_fail (format != NULL, NULL);
|
|
|
|
while (i < (sizeof (buffer) - 1) && *format)
|
|
{
|
|
switch (*format)
|
|
{
|
|
case '%':
|
|
format++;
|
|
switch (*format)
|
|
{
|
|
case 0:
|
|
g_warning ("%s: unit-menu-format string ended within %%-sequence",
|
|
G_STRFUNC);
|
|
break;
|
|
|
|
case '%':
|
|
buffer[i++] = '%';
|
|
break;
|
|
|
|
case 'f': /* factor (how many units make up an inch) */
|
|
i += print (buffer, sizeof (buffer), i, "%f",
|
|
gimp_unit_get_factor (unit));
|
|
break;
|
|
|
|
case 'y': /* symbol ("''" for inch) */
|
|
i += print (buffer, sizeof (buffer), i, "%s",
|
|
gimp_unit_get_symbol (unit));
|
|
break;
|
|
|
|
case 'a': /* abbreviation */
|
|
i += print (buffer, sizeof (buffer), i, "%s",
|
|
gimp_unit_get_abbreviation (unit));
|
|
break;
|
|
|
|
case 's': /* singular */
|
|
i += print (buffer, sizeof (buffer), i, "%s",
|
|
gimp_unit_get_singular (unit));
|
|
break;
|
|
|
|
case 'p': /* plural */
|
|
i += print (buffer, sizeof (buffer), i, "%s",
|
|
gimp_unit_get_plural (unit));
|
|
break;
|
|
|
|
default:
|
|
g_warning ("%s: unit-menu-format contains unknown format "
|
|
"sequence '%%%c'", G_STRFUNC, *format);
|
|
break;
|
|
}
|
|
break;
|
|
|
|
default:
|
|
buffer[i++] = *format;
|
|
break;
|
|
}
|
|
|
|
format++;
|
|
}
|
|
|
|
buffer[MIN (i, sizeof (buffer) - 1)] = 0;
|
|
|
|
return g_strdup (buffer);
|
|
}
|
|
|
|
/**
|
|
* gimp_pixels_to_units:
|
|
* @pixels: value in pixels
|
|
* @unit: unit to convert to
|
|
* @resolution: resolution in DPI
|
|
*
|
|
* Converts a @value specified in pixels to @unit.
|
|
*
|
|
* Returns: @pixels converted to units.
|
|
*
|
|
* Since: 2.8
|
|
**/
|
|
gdouble
|
|
gimp_pixels_to_units (gdouble pixels,
|
|
GimpUnit *unit,
|
|
gdouble resolution)
|
|
{
|
|
g_return_val_if_fail (gimp_unit_pixel != NULL, 0.0);
|
|
|
|
if (unit == gimp_unit_pixel ())
|
|
return pixels;
|
|
|
|
return pixels * gimp_unit_get_factor (unit) / resolution;
|
|
}
|
|
|
|
/**
|
|
* gimp_units_to_pixels:
|
|
* @value: value in units
|
|
* @unit: unit of @value
|
|
* @resolution: resloution in DPI
|
|
*
|
|
* Converts a @value specified in @unit to pixels.
|
|
*
|
|
* Returns: @value converted to pixels.
|
|
*
|
|
* Since: 2.8
|
|
**/
|
|
gdouble
|
|
gimp_units_to_pixels (gdouble value,
|
|
GimpUnit *unit,
|
|
gdouble resolution)
|
|
{
|
|
g_return_val_if_fail (gimp_unit_pixel != NULL, 0.0);
|
|
|
|
if (unit == gimp_unit_pixel ())
|
|
return value;
|
|
|
|
return value * resolution / gimp_unit_get_factor (unit);
|
|
}
|
|
|
|
/**
|
|
* gimp_units_to_points:
|
|
* @value: value in units
|
|
* @unit: unit of @value
|
|
* @resolution: resloution in DPI
|
|
*
|
|
* Converts a @value specified in @unit to points.
|
|
*
|
|
* Returns: @value converted to points.
|
|
*
|
|
* Since: 2.8
|
|
**/
|
|
gdouble
|
|
gimp_units_to_points (gdouble value,
|
|
GimpUnit *unit,
|
|
gdouble resolution)
|
|
{
|
|
g_return_val_if_fail (gimp_unit_pixel != NULL, 0.0);
|
|
g_return_val_if_fail (gimp_unit_point != NULL, 0.0);
|
|
|
|
if (unit == gimp_unit_point ())
|
|
return value;
|
|
|
|
if (unit == gimp_unit_pixel ())
|
|
return (value * gimp_unit_get_factor (gimp_unit_point ()) / resolution);
|
|
|
|
return (value *
|
|
gimp_unit_get_factor (gimp_unit_point ()) / gimp_unit_get_factor (unit));
|
|
}
|
|
|
|
|
|
/*
|
|
* GIMP_TYPE_PARAM_UNIT
|
|
*/
|
|
|
|
static void gimp_param_unit_class_init (GParamSpecClass *klass);
|
|
static void gimp_param_unit_init (GParamSpec *pspec);
|
|
static void gimp_param_unit_set_default (GParamSpec *pspec,
|
|
GValue *value);
|
|
static gboolean gimp_param_unit_validate (GParamSpec *pspec,
|
|
GValue *value);
|
|
|
|
/**
|
|
* gimp_param_unit_get_type:
|
|
*
|
|
* Reveals the object type
|
|
*
|
|
* Returns: the #GType for a unit param object
|
|
*
|
|
* Since: 2.4
|
|
**/
|
|
GType
|
|
gimp_param_unit_get_type (void)
|
|
{
|
|
static GType type = 0;
|
|
|
|
if (! type)
|
|
{
|
|
const GTypeInfo info =
|
|
{
|
|
sizeof (GParamSpecClass),
|
|
NULL, NULL,
|
|
(GClassInitFunc) gimp_param_unit_class_init,
|
|
NULL, NULL,
|
|
sizeof (GimpParamSpecUnit),
|
|
0,
|
|
(GInstanceInitFunc) gimp_param_unit_init
|
|
};
|
|
|
|
type = g_type_register_static (G_TYPE_PARAM_OBJECT,
|
|
"GimpParamUnit", &info, 0);
|
|
}
|
|
|
|
return type;
|
|
}
|
|
|
|
static void
|
|
gimp_param_unit_class_init (GParamSpecClass *klass)
|
|
{
|
|
klass->value_type = GIMP_TYPE_UNIT;
|
|
klass->value_set_default = gimp_param_unit_set_default;
|
|
klass->value_validate = gimp_param_unit_validate;
|
|
}
|
|
|
|
static void
|
|
gimp_param_unit_init (GParamSpec *pspec)
|
|
{
|
|
GimpParamSpecUnit *uspec = GIMP_PARAM_SPEC_UNIT (pspec);
|
|
|
|
uspec->allow_pixel = TRUE;
|
|
uspec->allow_percent = TRUE;
|
|
uspec->default_value = gimp_unit_inch ();
|
|
}
|
|
|
|
static void
|
|
gimp_param_unit_set_default (GParamSpec *pspec,
|
|
GValue *value)
|
|
{
|
|
GimpParamSpecUnit *uspec = GIMP_PARAM_SPEC_UNIT (pspec);
|
|
|
|
g_value_set_object (value, uspec->default_value);
|
|
}
|
|
|
|
static gboolean
|
|
gimp_param_unit_validate (GParamSpec *pspec,
|
|
GValue *value)
|
|
{
|
|
GimpParamSpecUnit *uspec = GIMP_PARAM_SPEC_UNIT (pspec);
|
|
GObject *unit = value->data[0].v_pointer;
|
|
|
|
if (unit == NULL ||
|
|
(! uspec->allow_percent && value->data[0].v_pointer == gimp_unit_percent ()) ||
|
|
(! uspec->allow_pixel && value->data[0].v_pointer == gimp_unit_pixel ()))
|
|
{
|
|
g_clear_object (&unit);
|
|
value->data[0].v_pointer = g_object_ref (uspec->default_value);
|
|
return TRUE;
|
|
}
|
|
|
|
return FALSE;
|
|
}
|
|
|
|
/**
|
|
* gimp_param_spec_unit:
|
|
* @name: Canonical name of the param
|
|
* @nick: Nickname of the param
|
|
* @blurb: Brief description of param.
|
|
* @allow_pixel: Whether "pixels" is an allowed unit.
|
|
* @allow_percent: Whether "percent" is an allowed unit.
|
|
* @default_value: Unit to use if none is assigned.
|
|
* @flags: a combination of #GParamFlags
|
|
*
|
|
* Creates a param spec to hold a units param.
|
|
* See g_param_spec_internal() for more information.
|
|
*
|
|
* Returns: (transfer full): a newly allocated #GParamSpec instance
|
|
*
|
|
* Since: 2.4
|
|
**/
|
|
GParamSpec *
|
|
gimp_param_spec_unit (const gchar *name,
|
|
const gchar *nick,
|
|
const gchar *blurb,
|
|
gboolean allow_pixel,
|
|
gboolean allow_percent,
|
|
GimpUnit *default_value,
|
|
GParamFlags flags)
|
|
{
|
|
GimpParamSpecUnit *uspec;
|
|
|
|
g_return_val_if_fail (GIMP_IS_UNIT (default_value), NULL);
|
|
|
|
uspec = g_param_spec_internal (GIMP_TYPE_PARAM_UNIT,
|
|
name, nick, blurb, flags);
|
|
|
|
g_return_val_if_fail (uspec, NULL);
|
|
|
|
uspec->allow_pixel = allow_pixel;
|
|
uspec->allow_percent = allow_percent;
|
|
uspec->default_value = default_value;
|
|
|
|
return G_PARAM_SPEC (uspec);
|
|
}
|
|
|
|
static gint
|
|
print (gchar *buf,
|
|
gint len,
|
|
gint start,
|
|
const gchar *fmt,
|
|
...)
|
|
{
|
|
va_list args;
|
|
gint printed;
|
|
|
|
va_start (args, fmt);
|
|
|
|
printed = g_vsnprintf (buf + start, len - start, fmt, args);
|
|
if (printed < 0)
|
|
printed = len - start;
|
|
|
|
va_end (args);
|
|
|
|
return printed;
|
|
}
|