1 /* LIBGIMP - The GIMP Library
2  * Copyright (C) 1995-1997 Peter Mattis and Spencer Kimball
3  *
4  * gimpunit.c
5  * Copyright (C) 2003 Michael Natterer <mitch@gimp.org>
6  *
7  * This library is free software: you can redistribute it and/or
8  * modify it under the terms of the GNU Lesser General Public
9  * License as published by the Free Software Foundation; either
10  * version 3 of the License, or (at your option) any later version.
11  *
12  * This library is distributed in the hope that it will be useful,
13  * but WITHOUT ANY WARRANTY; without even the implied warranty of
14  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
15  * Lesser General Public License for more details.
16  *
17  * You should have received a copy of the GNU Lesser General Public
18  * License along with this library.  If not, see
19  * <https://www.gnu.org/licenses/>.
20  */
21 
22 #include "config.h"
23 
24 #include <math.h>
25 #include <string.h>
26 
27 #include <glib-object.h>
28 
29 #include "gimpbasetypes.h"
30 
31 #include "gimpbase-private.h"
32 #include "gimpunit.h"
33 
34 
35 /**
36  * SECTION: gimpunit
37  * @title: gimpunit
38  * @short_description: Provides a collection of predefined units and
39  *                     functions for creating user-defined units.
40  * @see_also: #GimpUnitMenu, #GimpSizeEntry.
41  *
42  * Provides a collection of predefined units and functions for
43  * creating user-defined units.
44  **/
45 
46 
47 static void   unit_to_string (const GValue *src_value,
48                               GValue       *dest_value);
49 static void   string_to_unit (const GValue *src_value,
50                               GValue       *dest_value);
51 
52 GType
gimp_unit_get_type(void)53 gimp_unit_get_type (void)
54 {
55   static GType unit_type = 0;
56 
57   if (! unit_type)
58     {
59       const GTypeInfo type_info = { 0, };
60 
61       unit_type = g_type_register_static (G_TYPE_INT, "GimpUnit",
62                                           &type_info, 0);
63 
64       g_value_register_transform_func (unit_type, G_TYPE_STRING,
65                                        unit_to_string);
66       g_value_register_transform_func (G_TYPE_STRING, unit_type,
67                                        string_to_unit);
68     }
69 
70   return unit_type;
71 }
72 
73 static void
unit_to_string(const GValue * src_value,GValue * dest_value)74 unit_to_string (const GValue *src_value,
75                 GValue       *dest_value)
76 {
77   GimpUnit unit = (GimpUnit) g_value_get_int (src_value);
78 
79   g_value_set_string (dest_value, gimp_unit_get_identifier (unit));
80 }
81 
82 static void
string_to_unit(const GValue * src_value,GValue * dest_value)83 string_to_unit (const GValue *src_value,
84                 GValue       *dest_value)
85 {
86   const gchar *str;
87   gint         num_units;
88   gint         i;
89 
90   str = g_value_get_string (src_value);
91 
92   if (!str || !*str)
93     goto error;
94 
95   num_units = gimp_unit_get_number_of_units ();
96 
97   for (i = GIMP_UNIT_PIXEL; i < num_units; i++)
98     if (strcmp (str, gimp_unit_get_identifier (i)) == 0)
99       break;
100 
101   if (i == num_units)
102     {
103       if (strcmp (str, gimp_unit_get_identifier (GIMP_UNIT_PERCENT)) == 0)
104         i = GIMP_UNIT_PERCENT;
105       else
106         goto error;
107     }
108 
109   g_value_set_int (dest_value, i);
110   return;
111 
112  error:
113   g_warning ("Can't convert string '%s' to GimpUnit.", str);
114 }
115 
116 
117 /**
118  * gimp_unit_get_number_of_units:
119  *
120  * Returns the number of units which are known to the #GimpUnit system.
121  *
122  * Returns: The number of defined units.
123  **/
124 gint
gimp_unit_get_number_of_units(void)125 gimp_unit_get_number_of_units (void)
126 {
127   g_return_val_if_fail (_gimp_unit_vtable.unit_get_number_of_units != NULL,
128                         GIMP_UNIT_END);
129 
130   return _gimp_unit_vtable.unit_get_number_of_units ();
131 }
132 
133 /**
134  * gimp_unit_get_number_of_built_in_units:
135  *
136  * Returns the number of #GimpUnit's which are hardcoded in the unit system
137  * (UNIT_INCH, UNIT_MM, UNIT_POINT, UNIT_PICA and the two "pseudo unit"
138  *  UNIT_PIXEL).
139  *
140  * Returns: The number of built-in units.
141  **/
142 gint
gimp_unit_get_number_of_built_in_units(void)143 gimp_unit_get_number_of_built_in_units (void)
144 {
145   g_return_val_if_fail (_gimp_unit_vtable.unit_get_number_of_built_in_units
146                         != NULL, GIMP_UNIT_END);
147 
148   return _gimp_unit_vtable.unit_get_number_of_built_in_units ();
149 }
150 
151 /**
152  * gimp_unit_new:
153  * @identifier: The unit's identifier string.
154  * @factor: The unit's factor (how many units are in one inch).
155  * @digits: The unit's suggested number of digits (see gimp_unit_get_digits()).
156  * @symbol: The symbol of the unit (e.g. "''" for inch).
157  * @abbreviation: The abbreviation of the unit.
158  * @singular: The singular form of the unit.
159  * @plural: The plural form of the unit.
160  *
161  * Returns the integer ID of the new #GimpUnit.
162  *
163  * Note that a new unit is always created with its deletion flag
164  * set to %TRUE. You will have to set it to %FALSE with
165  * gimp_unit_set_deletion_flag() to make the unit definition persistent.
166  *
167  * Returns: The ID of the new unit.
168  **/
169 GimpUnit
gimp_unit_new(gchar * identifier,gdouble factor,gint digits,gchar * symbol,gchar * abbreviation,gchar * singular,gchar * plural)170 gimp_unit_new (gchar   *identifier,
171                gdouble  factor,
172                gint     digits,
173                gchar   *symbol,
174                gchar   *abbreviation,
175                gchar   *singular,
176                gchar   *plural)
177 {
178   g_return_val_if_fail (_gimp_unit_vtable.unit_new != NULL, GIMP_UNIT_INCH);
179 
180   return _gimp_unit_vtable.unit_new (identifier, factor, digits,
181                                      symbol, abbreviation, singular, plural);
182 }
183 
184 /**
185  * gimp_unit_get_deletion_flag:
186  * @unit: The unit you want to know the @deletion_flag of.
187  *
188  * Returns: The unit's @deletion_flag.
189  **/
190 gboolean
gimp_unit_get_deletion_flag(GimpUnit unit)191 gimp_unit_get_deletion_flag (GimpUnit unit)
192 {
193   g_return_val_if_fail (_gimp_unit_vtable.unit_get_deletion_flag != NULL, FALSE);
194 
195   return _gimp_unit_vtable.unit_get_deletion_flag (unit);
196 }
197 
198 /**
199  * gimp_unit_set_deletion_flag:
200  * @unit: The unit you want to set the @deletion_flag for.
201  * @deletion_flag: The new deletion_flag.
202  *
203  * Sets a #GimpUnit's @deletion_flag. If the @deletion_flag of a unit is
204  * %TRUE when GIMP exits, this unit will not be saved in the users's
205  * "unitrc" file.
206  *
207  * Trying to change the @deletion_flag of a built-in unit will be silently
208  * ignored.
209  **/
210 void
gimp_unit_set_deletion_flag(GimpUnit unit,gboolean deletion_flag)211 gimp_unit_set_deletion_flag (GimpUnit unit,
212                              gboolean deletion_flag)
213 {
214   g_return_if_fail (_gimp_unit_vtable.unit_set_deletion_flag != NULL);
215 
216   _gimp_unit_vtable.unit_set_deletion_flag (unit, deletion_flag);
217 }
218 
219 /**
220  * gimp_unit_get_factor:
221  * @unit: The unit you want to know the factor of.
222  *
223  * A #GimpUnit's @factor is defined to be:
224  *
225  * distance_in_units == (@factor * distance_in_inches)
226  *
227  * Returns 0 for @unit == GIMP_UNIT_PIXEL.
228  *
229  * Returns: The unit's factor.
230  **/
231 gdouble
gimp_unit_get_factor(GimpUnit unit)232 gimp_unit_get_factor (GimpUnit unit)
233 {
234   g_return_val_if_fail (_gimp_unit_vtable.unit_get_factor != NULL, 1.0);
235 
236   return _gimp_unit_vtable.unit_get_factor (unit);
237 }
238 
239 /**
240  * gimp_unit_get_digits:
241  * @unit: The unit you want to know the digits.
242  *
243  * Returns the number of digits set for @unit.
244  * Built-in units' accuracy is approximately the same as an inch with
245  * two digits. User-defined units can suggest a different accuracy.
246  *
247  * Note: the value is as-set by defaults or by the user and does not
248  * necessary provide enough precision on high-resolution images.
249  * When the information is needed for a specific image, the use of
250  * gimp_unit_get_scaled_digits() may be more appropriate.
251  *
252  * Returns 0 for @unit == GIMP_UNIT_PIXEL.
253  *
254  * Returns: The suggested number of digits.
255  **/
256 gint
gimp_unit_get_digits(GimpUnit unit)257 gimp_unit_get_digits (GimpUnit unit)
258 {
259   g_return_val_if_fail (_gimp_unit_vtable.unit_get_digits != NULL, 2);
260 
261   return _gimp_unit_vtable.unit_get_digits (unit);
262 }
263 
264 /**
265  * gimp_unit_get_scaled_digits:
266  * @unit: The unit you want to know the digits.
267  * @resolution: the resolution in PPI.
268  *
269  * Returns the number of digits a @unit field should provide to get
270  * enough accuracy so that every pixel position shows a different
271  * value from neighboring pixels.
272  *
273  * Note: when needing digit accuracy to display a diagonal distance,
274  * the @resolution may not correspond to the image's horizontal or
275  * vertical resolution, but instead to the result of:
276  * `distance_in_pixel / distance_in_inch`.
277  *
278  * Returns: The suggested number of digits.
279  **/
280 gint
gimp_unit_get_scaled_digits(GimpUnit unit,gdouble resolution)281 gimp_unit_get_scaled_digits (GimpUnit unit,
282                              gdouble  resolution)
283 {
284   gint digits;
285 
286   g_return_val_if_fail (_gimp_unit_vtable.unit_get_digits != NULL, 2);
287 
288   digits = ceil (log10 (1.0 /
289                         gimp_pixels_to_units (1.0, unit, resolution)));
290 
291   return MAX (digits, gimp_unit_get_digits (unit));
292 }
293 
294 /**
295  * gimp_unit_get_identifier:
296  * @unit: The unit you want to know the identifier of.
297  *
298  * This is an untranslated string and must not be changed or freed.
299  *
300  * Returns: The unit's identifier.
301  **/
302 const gchar *
gimp_unit_get_identifier(GimpUnit unit)303 gimp_unit_get_identifier (GimpUnit unit)
304 {
305   g_return_val_if_fail (_gimp_unit_vtable.unit_get_identifier != NULL, NULL);
306 
307   return _gimp_unit_vtable.unit_get_identifier (unit);
308 }
309 
310 /**
311  * gimp_unit_get_symbol:
312  * @unit: The unit you want to know the symbol of.
313  *
314  * This is e.g. "''" for UNIT_INCH.
315  *
316  * NOTE: This string must not be changed or freed.
317  *
318  * Returns: The unit's symbol.
319  **/
320 const gchar *
gimp_unit_get_symbol(GimpUnit unit)321 gimp_unit_get_symbol (GimpUnit unit)
322 {
323   g_return_val_if_fail (_gimp_unit_vtable.unit_get_symbol != NULL, NULL);
324 
325   return _gimp_unit_vtable.unit_get_symbol (unit);
326 }
327 
328 /**
329  * gimp_unit_get_abbreviation:
330  * @unit: The unit you want to know the abbreviation of.
331  *
332  * For built-in units, this function returns the translated abbreviation
333  * of the unit.
334  *
335  * NOTE: This string must not be changed or freed.
336  *
337  * Returns: The unit's abbreviation.
338  **/
339 const gchar *
gimp_unit_get_abbreviation(GimpUnit unit)340 gimp_unit_get_abbreviation (GimpUnit unit)
341 {
342   g_return_val_if_fail (_gimp_unit_vtable.unit_get_abbreviation != NULL, NULL);
343 
344   return _gimp_unit_vtable.unit_get_abbreviation (unit);
345 }
346 
347 /**
348  * gimp_unit_get_singular:
349  * @unit: The unit you want to know the singular form of.
350  *
351  * For built-in units, this function returns the translated singular form
352  * of the unit's name.
353  *
354  * NOTE: This string must not be changed or freed.
355  *
356  * Returns: The unit's singular form.
357  **/
358 const gchar *
gimp_unit_get_singular(GimpUnit unit)359 gimp_unit_get_singular (GimpUnit unit)
360 {
361   g_return_val_if_fail (_gimp_unit_vtable.unit_get_singular != NULL, NULL);
362 
363   return _gimp_unit_vtable.unit_get_singular (unit);
364 }
365 
366 /**
367  * gimp_unit_get_plural:
368  * @unit: The unit you want to know the plural form of.
369  *
370  * For built-in units, this function returns the translated plural form
371  * of the unit's name.
372  *
373  * NOTE: This string must not be changed or freed.
374  *
375  * Returns: The unit's plural form.
376  **/
377 const gchar *
gimp_unit_get_plural(GimpUnit unit)378 gimp_unit_get_plural (GimpUnit unit)
379 {
380   g_return_val_if_fail (_gimp_unit_vtable.unit_get_plural != NULL, NULL);
381 
382   return _gimp_unit_vtable.unit_get_plural (unit);
383 }
384 
385 static gint print (gchar       *buf,
386                    gint         len,
387                    gint         start,
388                    const gchar *fmt,
389                    ...) G_GNUC_PRINTF (4, 5);
390 
391 static gint
print(gchar * buf,gint len,gint start,const gchar * fmt,...)392 print (gchar       *buf,
393        gint         len,
394        gint         start,
395        const gchar *fmt,
396        ...)
397 {
398   va_list args;
399   gint printed;
400 
401   va_start (args, fmt);
402 
403   printed = g_vsnprintf (buf + start, len - start, fmt, args);
404   if (printed < 0)
405     printed = len - start;
406 
407   va_end (args);
408 
409   return printed;
410 }
411 
412 /**
413  * gimp_unit_format_string:
414  * @format: A printf-like format string which is used to create the unit
415  *          string.
416  * @unit:   A unit.
417  *
418  * The @format string supports the following percent expansions:
419  *
420  * <informaltable pgwide="1" frame="none" role="enum">
421  *   <tgroup cols="2"><colspec colwidth="1*"/><colspec colwidth="8*"/>
422  *     <tbody>
423  *       <row>
424  *         <entry>% f</entry>
425  *         <entry>Factor (how many units make up an inch)</entry>
426  *        </row>
427  *       <row>
428  *         <entry>% y</entry>
429  *         <entry>Symbol (e.g. "''" for GIMP_UNIT_INCH)</entry>
430  *       </row>
431  *       <row>
432  *         <entry>% a</entry>
433  *         <entry>Abbreviation</entry>
434  *       </row>
435  *       <row>
436  *         <entry>% s</entry>
437  *         <entry>Singular</entry>
438  *       </row>
439  *       <row>
440  *         <entry>% p</entry>
441  *         <entry>Plural</entry>
442  *       </row>
443  *       <row>
444  *         <entry>%%</entry>
445  *         <entry>Literal percent</entry>
446  *       </row>
447  *     </tbody>
448  *   </tgroup>
449  * </informaltable>
450  *
451  * Returns: A newly allocated string with above percent expressions
452  *          replaced with the resp. strings for @unit.
453  *
454  * Since: 2.8
455  **/
456 gchar *
gimp_unit_format_string(const gchar * format,GimpUnit unit)457 gimp_unit_format_string (const gchar *format,
458                          GimpUnit     unit)
459 {
460   gchar buffer[1024];
461   gint  i = 0;
462 
463   g_return_val_if_fail (format != NULL, NULL);
464   g_return_val_if_fail (unit == GIMP_UNIT_PERCENT ||
465                         (unit >= GIMP_UNIT_PIXEL &&
466                          unit < gimp_unit_get_number_of_units ()), NULL);
467 
468   while (i < (sizeof (buffer) - 1) && *format)
469     {
470       switch (*format)
471         {
472         case '%':
473           format++;
474           switch (*format)
475             {
476             case 0:
477               g_warning ("%s: unit-menu-format string ended within %%-sequence",
478                          G_STRFUNC);
479               break;
480 
481             case '%':
482               buffer[i++] = '%';
483               break;
484 
485             case 'f': /* factor (how many units make up an inch) */
486               i += print (buffer, sizeof (buffer), i, "%f",
487                           gimp_unit_get_factor (unit));
488               break;
489 
490             case 'y': /* symbol ("''" for inch) */
491               i += print (buffer, sizeof (buffer), i, "%s",
492                           gimp_unit_get_symbol (unit));
493               break;
494 
495             case 'a': /* abbreviation */
496               i += print (buffer, sizeof (buffer), i, "%s",
497                           gimp_unit_get_abbreviation (unit));
498               break;
499 
500             case 's': /* singular */
501               i += print (buffer, sizeof (buffer), i, "%s",
502                           gimp_unit_get_singular (unit));
503               break;
504 
505             case 'p': /* plural */
506               i += print (buffer, sizeof (buffer), i, "%s",
507                           gimp_unit_get_plural (unit));
508               break;
509 
510             default:
511               g_warning ("%s: unit-menu-format contains unknown format "
512                          "sequence '%%%c'", G_STRFUNC, *format);
513               break;
514             }
515           break;
516 
517         default:
518           buffer[i++] = *format;
519           break;
520         }
521 
522       format++;
523     }
524 
525   buffer[MIN (i, sizeof (buffer) - 1)] = 0;
526 
527   return g_strdup (buffer);
528 }
529 
530 /*
531  * GIMP_TYPE_PARAM_UNIT
532  */
533 
534 #define GIMP_PARAM_SPEC_UNIT(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), GIMP_TYPE_PARAM_UNIT, GimpParamSpecUnit))
535 
536 typedef struct _GimpParamSpecUnit GimpParamSpecUnit;
537 
538 struct _GimpParamSpecUnit
539 {
540   GParamSpecInt parent_instance;
541 
542   gboolean      allow_percent;
543 };
544 
545 static void      gimp_param_unit_class_init     (GParamSpecClass *class);
546 static gboolean  gimp_param_unit_value_validate (GParamSpec      *pspec,
547                                                  GValue          *value);
548 
549 /**
550  * gimp_param_unit_get_type:
551  *
552  * Reveals the object type
553  *
554  * Returns: the #GType for a unit param object
555  *
556  * Since: 2.4
557  **/
558 GType
gimp_param_unit_get_type(void)559 gimp_param_unit_get_type (void)
560 {
561   static GType spec_type = 0;
562 
563   if (! spec_type)
564     {
565       const GTypeInfo type_info =
566       {
567         sizeof (GParamSpecClass),
568         NULL, NULL,
569         (GClassInitFunc) gimp_param_unit_class_init,
570         NULL, NULL,
571         sizeof (GimpParamSpecUnit),
572         0, NULL, NULL
573       };
574 
575       spec_type = g_type_register_static (G_TYPE_PARAM_INT,
576                                           "GimpParamUnit",
577                                           &type_info, 0);
578     }
579 
580   return spec_type;
581 }
582 
583 static void
gimp_param_unit_class_init(GParamSpecClass * class)584 gimp_param_unit_class_init (GParamSpecClass *class)
585 {
586   class->value_type     = GIMP_TYPE_UNIT;
587   class->value_validate = gimp_param_unit_value_validate;
588 }
589 
590 static gboolean
gimp_param_unit_value_validate(GParamSpec * pspec,GValue * value)591 gimp_param_unit_value_validate (GParamSpec *pspec,
592                                 GValue     *value)
593 {
594   GParamSpecInt     *ispec = G_PARAM_SPEC_INT (pspec);
595   GimpParamSpecUnit *uspec = GIMP_PARAM_SPEC_UNIT (pspec);
596   gint               oval  = value->data[0].v_int;
597 
598   if (!(uspec->allow_percent && value->data[0].v_int == GIMP_UNIT_PERCENT))
599     {
600       value->data[0].v_int = CLAMP (value->data[0].v_int,
601                                     ispec->minimum,
602                                     gimp_unit_get_number_of_units () - 1);
603     }
604 
605   return value->data[0].v_int != oval;
606 }
607 
608 /**
609  * gimp_param_spec_unit:
610  * @name:          Canonical name of the param
611  * @nick:          Nickname of the param
612  * @blurb:         Brief description of param.
613  * @allow_pixels:  Whether "pixels" is an allowed unit.
614  * @allow_percent: Whether "percent" is an allowed unit.
615  * @default_value: Unit to use if none is assigned.
616  * @flags:         a combination of #GParamFlags
617  *
618  * Creates a param spec to hold a units param.
619  * See g_param_spec_internal() for more information.
620  *
621  * Returns: a newly allocated #GParamSpec instance
622  *
623  * Since: 2.4
624  **/
625 GParamSpec *
gimp_param_spec_unit(const gchar * name,const gchar * nick,const gchar * blurb,gboolean allow_pixels,gboolean allow_percent,GimpUnit default_value,GParamFlags flags)626 gimp_param_spec_unit (const gchar *name,
627                       const gchar *nick,
628                       const gchar *blurb,
629                       gboolean     allow_pixels,
630                       gboolean     allow_percent,
631                       GimpUnit     default_value,
632                       GParamFlags  flags)
633 {
634   GimpParamSpecUnit *pspec;
635   GParamSpecInt     *ispec;
636 
637   pspec = g_param_spec_internal (GIMP_TYPE_PARAM_UNIT,
638                                  name, nick, blurb, flags);
639 
640   ispec = G_PARAM_SPEC_INT (pspec);
641 
642   ispec->default_value = default_value;
643   ispec->minimum       = allow_pixels ? GIMP_UNIT_PIXEL : GIMP_UNIT_INCH;
644   ispec->maximum       = GIMP_UNIT_PERCENT - 1;
645 
646   pspec->allow_percent = allow_percent;
647 
648   return G_PARAM_SPEC (pspec);
649 }
650 
651 /**
652  * gimp_pixels_to_units:
653  * @pixels:     value in pixels
654  * @unit:       unit to convert to
655  * @resolution: resolution in DPI
656  *
657  * Converts a @value specified in pixels to @unit.
658  *
659  * Returns: @pixels converted to units.
660  *
661  * Since: 2.8
662  **/
663 gdouble
gimp_pixels_to_units(gdouble pixels,GimpUnit unit,gdouble resolution)664 gimp_pixels_to_units (gdouble  pixels,
665                       GimpUnit unit,
666                       gdouble  resolution)
667 {
668   if (unit == GIMP_UNIT_PIXEL)
669     return pixels;
670 
671   return pixels * gimp_unit_get_factor (unit) / resolution;
672 }
673 
674 /**
675  * gimp_units_to_pixels:
676  * @value:      value in units
677  * @unit:       unit of @value
678  * @resolution: resloution in DPI
679  *
680  * Converts a @value specified in @unit to pixels.
681  *
682  * Returns: @value converted to pixels.
683  *
684  * Since: 2.8
685  **/
686 gdouble
gimp_units_to_pixels(gdouble value,GimpUnit unit,gdouble resolution)687 gimp_units_to_pixels (gdouble  value,
688                       GimpUnit unit,
689                       gdouble  resolution)
690 {
691   if (unit == GIMP_UNIT_PIXEL)
692     return value;
693 
694   return value * resolution / gimp_unit_get_factor (unit);
695 }
696 
697 /**
698  * gimp_units_to_points:
699  * @value:      value in units
700  * @unit:       unit of @value
701  * @resolution: resloution in DPI
702  *
703  * Converts a @value specified in @unit to points.
704  *
705  * Returns: @value converted to points.
706  *
707  * Since: 2.8
708  **/
709 gdouble
gimp_units_to_points(gdouble value,GimpUnit unit,gdouble resolution)710 gimp_units_to_points (gdouble  value,
711                       GimpUnit unit,
712                       gdouble  resolution)
713 {
714   if (unit == GIMP_UNIT_POINT)
715     return value;
716 
717   if (unit == GIMP_UNIT_PIXEL)
718     return (value * gimp_unit_get_factor (GIMP_UNIT_POINT) / resolution);
719 
720   return (value *
721           gimp_unit_get_factor (GIMP_UNIT_POINT) / gimp_unit_get_factor (unit));
722 }
723 
724 /**
725  * gimp_unit_is_metric:
726  * @unit: The unit
727  *
728  * Checks if the given @unit is metric. A simplistic test is used
729  * that looks at the unit's factor and checks if it is 2.54 multiplied
730  * by some common powers of 10. Currently it checks for mm, cm, dm, m.
731  *
732  * See also: gimp_unit_get_factor()
733  *
734  * Returns: %TRUE if the @unit is metric.
735  *
736  * Since: 2.10
737  **/
738 gboolean
gimp_unit_is_metric(GimpUnit unit)739 gimp_unit_is_metric (GimpUnit unit)
740 {
741   gdouble factor;
742 
743   if (unit == GIMP_UNIT_MM)
744     return TRUE;
745 
746   factor = gimp_unit_get_factor (unit);
747 
748   if (factor == 0.0)
749     return FALSE;
750 
751   return ((ABS (factor -  0.0254) < 1e-7) || /* m  */
752           (ABS (factor -  0.254)  < 1e-6) || /* dm */
753           (ABS (factor -  2.54)   < 1e-5) || /* cm */
754           (ABS (factor - 25.4)    < 1e-4));  /* mm */
755 }
756