Fix wrong include
[claws.git] / src / gtk / gtkunit.c
1 /* LIBGTK - The GTK 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  * <http://www.gnu.org/licenses/>.
20  */
21
22 #include "config.h"
23 #include "claws-features.h"
24
25 #include "gtkunit.h"
26
27 #include <string.h>
28
29 #include <glib-object.h>
30
31
32 GtkCMUnitVtable _gtk_unit_vtable = { NULL, };
33
34
35 void
36 gtk_base_init (GtkCMUnitVtable *vtable)
37 {
38   static gboolean gtk_base_initialized = FALSE;
39
40   g_return_if_fail (vtable != NULL);
41
42   if (gtk_base_initialized)
43     g_error ("gtk_base_init() must only be called once!");
44
45   _gtk_unit_vtable = *vtable;
46
47   gtk_base_initialized = TRUE;
48 }
49
50
51 /**
52  * SECTION: gimpunit
53  * @title: gimpunit
54  * @short_description: Provides a collection of predefined units and
55  *                     functions for creating user-defined units.
56  * @see_also: #GtkCMUnitMenu, #GtkSizeEntry.
57  *
58  * Provides a collection of predefined units and functions for
59  * creating user-defined units.
60  **/
61
62
63 static void   unit_to_string (const GValue *src_value,
64                               GValue       *dest_value);
65 static void   string_to_unit (const GValue *src_value,
66                               GValue       *dest_value);
67
68 GType
69 gtk_unit_get_type (void)
70 {
71   static GType unit_type = 0;
72
73   if (! unit_type)
74     {
75       const GTypeInfo type_info = { 0, };
76
77       unit_type = g_type_register_static (G_TYPE_INT, "GtkCMUnit",
78                                           &type_info, 0);
79
80       g_value_register_transform_func (unit_type, G_TYPE_STRING,
81                                        unit_to_string);
82       g_value_register_transform_func (G_TYPE_STRING, unit_type,
83                                        string_to_unit);
84     }
85
86   return unit_type;
87 }
88
89 static void
90 unit_to_string (const GValue *src_value,
91                 GValue       *dest_value)
92 {
93   GtkCMUnit unit = (GtkCMUnit) g_value_get_int (src_value);
94
95   g_value_set_string (dest_value, gtk_unit_get_identifier (unit));
96 }
97
98 static void
99 string_to_unit (const GValue *src_value,
100                 GValue       *dest_value)
101 {
102   const gchar *str;
103   gint         num_units;
104   gint         i;
105
106   str = g_value_get_string (src_value);
107
108   if (!str || !*str)
109     goto error;
110
111   num_units = gtk_unit_get_number_of_units ();
112
113   for (i = CM_UNIT_PIXEL; i < num_units; i++)
114     if (strcmp (str, gtk_unit_get_identifier (i)) == 0)
115       break;
116
117   if (i == num_units)
118     {
119       if (strcmp (str, gtk_unit_get_identifier (CM_UNIT_PERCENT)) == 0)
120         i = CM_UNIT_PERCENT;
121       else
122         goto error;
123     }
124
125   g_value_set_int (dest_value, i);
126   return;
127
128  error:
129   g_warning ("Can't convert string to GtkCMUnit.");
130 }
131
132
133 /**
134  * gtk_unit_get_number_of_units:
135  *
136  * Returns the number of units which are known to the #GtkCMUnit system.
137  *
138  * Returns: The number of defined units.
139  **/
140 gint
141 gtk_unit_get_number_of_units (void)
142 {
143   g_return_val_if_fail (_gtk_unit_vtable.unit_get_number_of_units != NULL,
144                         CM_UNIT_END);
145
146   return _gtk_unit_vtable.unit_get_number_of_units ();
147 }
148
149 /**
150  * gtk_unit_get_number_of_built_in_units:
151  *
152  * Returns the number of #GtkCMUnit's which are hardcoded in the unit system
153  * (UNIT_INCH, UNIT_MM, UNIT_POINT, UNIT_PICA and the two "pseudo unit"
154  *  UNIT_PIXEL).
155  *
156  * Returns: The number of built-in units.
157  **/
158 gint
159 gtk_unit_get_number_of_built_in_units (void)
160 {
161   g_return_val_if_fail (_gtk_unit_vtable.unit_get_number_of_built_in_units
162                         != NULL, CM_UNIT_END);
163
164   return _gtk_unit_vtable.unit_get_number_of_built_in_units ();
165 }
166
167 /**
168  * gtk_unit_new:
169  * @identifier: The unit's identifier string.
170  * @factor: The unit's factor (how many units are in one inch).
171  * @digits: The unit's suggested number of digits (see gtk_unit_get_digits()).
172  * @symbol: The symbol of the unit (e.g. "''" for inch).
173  * @abbreviation: The abbreviation of the unit.
174  * @singular: The singular form of the unit.
175  * @plural: The plural form of the unit.
176  *
177  * Returns the integer ID of the new #GtkCMUnit.
178  *
179  * Note that a new unit is always created with it's deletion flag
180  * set to %TRUE. You will have to set it to %FALSE with
181  * gtk_unit_set_deletion_flag() to make the unit definition persistent.
182  *
183  * Returns: The ID of the new unit.
184  **/
185 GtkCMUnit
186 gtk_unit_new (gchar   *identifier,
187                gdouble  factor,
188                gint     digits,
189                gchar   *symbol,
190                gchar   *abbreviation,
191                gchar   *singular,
192                gchar   *plural)
193 {
194   g_return_val_if_fail (_gtk_unit_vtable.unit_new != NULL, CM_UNIT_INCH);
195
196   return _gtk_unit_vtable.unit_new (identifier, factor, digits,
197                                      symbol, abbreviation, singular, plural);
198 }
199
200 /**
201  * gtk_unit_get_deletion_flag:
202  * @unit: The unit you want to know the @deletion_flag of.
203  *
204  * Returns: The unit's @deletion_flag.
205  **/
206 gboolean
207 gtk_unit_get_deletion_flag (GtkCMUnit unit)
208 {
209   g_return_val_if_fail (_gtk_unit_vtable.unit_get_deletion_flag != NULL, FALSE);
210
211   return _gtk_unit_vtable.unit_get_deletion_flag (unit);
212 }
213
214 /**
215  * gtk_unit_set_deletion_flag:
216  * @unit: The unit you want to set the @deletion_flag for.
217  * @deletion_flag: The new deletion_flag.
218  *
219  * Sets a #GtkCMUnit's @deletion_flag. If the @deletion_flag of a unit is
220  * %TRUE when GTK exits, this unit will not be saved in the users's
221  * "unitrc" file.
222  *
223  * Trying to change the @deletion_flag of a built-in unit will be silently
224  * ignored.
225  **/
226 void
227 gtk_unit_set_deletion_flag (GtkCMUnit unit,
228                              gboolean deletion_flag)
229 {
230   g_return_if_fail (_gtk_unit_vtable.unit_set_deletion_flag != NULL);
231
232   _gtk_unit_vtable.unit_set_deletion_flag (unit, deletion_flag);
233 }
234
235 /**
236  * gtk_unit_get_factor:
237  * @unit: The unit you want to know the factor of.
238  *
239  * A #GtkCMUnit's @factor is defined to be:
240  *
241  * distance_in_units == (@factor * distance_in_inches)
242  *
243  * Returns 0 for @unit == CM_UNIT_PIXEL.
244  *
245  * Returns: The unit's factor.
246  **/
247 gdouble
248 gtk_unit_get_factor (GtkCMUnit unit)
249 {
250   g_return_val_if_fail (_gtk_unit_vtable.unit_get_factor != NULL, 1.0);
251
252   return _gtk_unit_vtable.unit_get_factor (unit);
253 }
254
255 /**
256  * gtk_unit_get_digits:
257  * @unit: The unit you want to know the digits.
258  *
259  * Returns the number of digits an entry field should provide to get
260  * approximately the same accuracy as an inch input field with two digits.
261  *
262  * Returns 0 for @unit == CM_UNIT_PIXEL.
263  *
264  * Returns: The suggested number of digits.
265  **/
266 gint
267 gtk_unit_get_digits (GtkCMUnit unit)
268 {
269   g_return_val_if_fail (_gtk_unit_vtable.unit_get_digits != NULL, 2);
270
271   return _gtk_unit_vtable.unit_get_digits (unit);
272 }
273
274 /**
275  * gtk_unit_get_identifier:
276  * @unit: The unit you want to know the identifier of.
277  *
278  * This is an unstranslated string and must not be changed or freed.
279  *
280  * Returns: The unit's identifier.
281  **/
282 const gchar *
283 gtk_unit_get_identifier (GtkCMUnit unit)
284 {
285   g_return_val_if_fail (_gtk_unit_vtable.unit_get_identifier != NULL, NULL);
286
287   return _gtk_unit_vtable.unit_get_identifier (unit);
288 }
289
290 /**
291  * gtk_unit_get_symbol:
292  * @unit: The unit you want to know the symbol of.
293  *
294  * This is e.g. "''" for UNIT_INCH.
295  *
296  * NOTE: This string must not be changed or freed.
297  *
298  * Returns: The unit's symbol.
299  **/
300 const gchar *
301 gtk_unit_get_symbol (GtkCMUnit unit)
302 {
303   g_return_val_if_fail (_gtk_unit_vtable.unit_get_symbol != NULL, NULL);
304
305   return _gtk_unit_vtable.unit_get_symbol (unit);
306 }
307
308 /**
309  * gtk_unit_get_abbreviation:
310  * @unit: The unit you want to know the abbreviation of.
311  *
312  * For built-in units, this function returns the translated abbreviation
313  * of the unit.
314  *
315  * NOTE: This string must not be changed or freed.
316  *
317  * Returns: The unit's abbreviation.
318  **/
319 const gchar *
320 gtk_unit_get_abbreviation (GtkCMUnit unit)
321 {
322   g_return_val_if_fail (_gtk_unit_vtable.unit_get_abbreviation != NULL, NULL);
323
324   return _gtk_unit_vtable.unit_get_abbreviation (unit);
325 }
326
327 /**
328  * gtk_unit_get_singular:
329  * @unit: The unit you want to know the singular form of.
330  *
331  * For built-in units, this function returns the translated singular form
332  * of the unit's name.
333  *
334  * NOTE: This string must not be changed or freed.
335  *
336  * Returns: The unit's singular form.
337  **/
338 const gchar *
339 gtk_unit_get_singular (GtkCMUnit unit)
340 {
341   g_return_val_if_fail (_gtk_unit_vtable.unit_get_singular != NULL, NULL);
342
343   return _gtk_unit_vtable.unit_get_singular (unit);
344 }
345
346 /**
347  * gtk_unit_get_plural:
348  * @unit: The unit you want to know the plural form of.
349  *
350  * For built-in units, this function returns the translated plural form
351  * of the unit's name.
352  *
353  * NOTE: This string must not be changed or freed.
354  *
355  * Returns: The unit's plural form.
356  **/
357 const gchar *
358 gtk_unit_get_plural (GtkCMUnit unit)
359 {
360   g_return_val_if_fail (_gtk_unit_vtable.unit_get_plural != NULL, NULL);
361
362   return _gtk_unit_vtable.unit_get_plural (unit);
363 }
364
365 static gint
366 print (gchar       *buf,
367        gint         len,
368        gint         start,
369        const gchar *fmt,
370        ...)
371 {
372   va_list args;
373   gint printed;
374
375   va_start (args, fmt);
376
377   printed = g_vsnprintf (buf + start, len - start, fmt, args);
378   if (printed < 0)
379     printed = len - start;
380
381   va_end (args);
382
383   return printed;
384 }
385
386 /**
387  * gtk_unit_format_string:
388  * @format: A printf-like format string which is used to create the unit
389  *          string.
390  * @unit:   A unit.
391  *
392  * The @format string supports the following percent expansions:
393  *
394  * <informaltable pgwide="1" frame="none" role="enum">
395  *   <tgroup cols="2"><colspec colwidth="1*"/><colspec colwidth="8*"/>
396  *     <tbody>
397  *       <row>
398  *         <entry>% f</entry>
399  *         <entry>Factor (how many units make up an inch)</entry>
400  *        </row>
401  *       <row>
402  *         <entry>% y</entry>
403  *         <entry>Symbol (e.g. "''" for CM_UNIT_INCH)</entry>
404  *       </row>
405  *       <row>
406  *         <entry>% a</entry>
407  *         <entry>Abbreviation</entry>
408  *       </row>
409  *       <row>
410  *         <entry>% s</entry>
411  *         <entry>Singular</entry>
412  *       </row>
413  *       <row>
414  *         <entry>% p</entry>
415  *         <entry>Plural</entry>
416  *       </row>
417  *       <row>
418  *         <entry>%%</entry>
419  *         <entry>Literal percent</entry>
420  *       </row>
421  *     </tbody>
422  *   </tgroup>
423  * </informaltable>
424  *
425  * Returns: A newly allocated string with above percent expressions
426  *          replaced with the resp. strings for @unit.
427  *
428  * Since: GTK 2.8
429  **/
430 gchar *
431 gtk_unit_format_string (const gchar *format,
432                          GtkCMUnit     unit)
433 {
434   gchar buffer[1024];
435   gint  i = 0;
436
437   g_return_val_if_fail (format != NULL, NULL);
438   g_return_val_if_fail (unit == CM_UNIT_PERCENT ||
439                         (unit >= CM_UNIT_PIXEL &&
440                          unit < gtk_unit_get_number_of_units ()), NULL);
441
442   while (i < (sizeof (buffer) - 1) && *format)
443     {
444       switch (*format)
445         {
446         case '%':
447           format++;
448           switch (*format)
449             {
450             case 0:
451               g_warning ("%s: unit-menu-format string ended within %%-sequence",
452                          G_STRFUNC);
453               break;
454
455             case '%':
456               buffer[i++] = '%';
457               break;
458
459             case 'f': /* factor (how many units make up an inch) */
460               i += print (buffer, sizeof (buffer), i, "%f",
461                           gtk_unit_get_factor (unit));
462               break;
463
464             case 'y': /* symbol ("''" for inch) */
465               i += print (buffer, sizeof (buffer), i, "%s",
466                           gtk_unit_get_symbol (unit));
467               break;
468
469             case 'a': /* abbreviation */
470               i += print (buffer, sizeof (buffer), i, "%s",
471                           gtk_unit_get_abbreviation (unit));
472               break;
473
474             case 's': /* singular */
475               i += print (buffer, sizeof (buffer), i, "%s",
476                           gtk_unit_get_singular (unit));
477               break;
478
479             case 'p': /* plural */
480               i += print (buffer, sizeof (buffer), i, "%s",
481                           gtk_unit_get_plural (unit));
482               break;
483
484             default:
485               g_warning ("%s: unit-menu-format contains unknown format "
486                          "sequence '%%%c'", G_STRFUNC, *format);
487               break;
488             }
489           break;
490
491         default:
492           buffer[i++] = *format;
493           break;
494         }
495
496       format++;
497     }
498
499   buffer[MIN (i, sizeof (buffer) - 1)] = 0;
500
501   return g_strdup (buffer);
502 }
503
504 /*
505  * GTK_TYPE_PARAM_UNIT
506  */
507
508 #define GTK_PARAM_SPEC_UNIT(pspec) (G_TYPE_CHECK_INSTANCE_CAST ((pspec), GTK_TYPE_PARAM_UNIT, GtkParamSpecUnit))
509
510 typedef struct _GtkParamSpecUnit GtkParamSpecUnit;
511
512 struct _GtkParamSpecUnit
513 {
514   GParamSpecInt parent_instance;
515
516   gboolean      allow_percent;
517 };
518
519 static void      gtk_param_unit_class_init     (GParamSpecClass *class);
520 static gboolean  gtk_param_unit_value_validate (GParamSpec      *pspec,
521                                                  GValue          *value);
522
523 /**
524  * gtk_param_unit_get_type:
525  *
526  * Reveals the object type
527  *
528  * Returns: the #GType for a unit param object
529  *
530  * Since: GTK 2.4
531  **/
532 GType
533 gtk_param_unit_get_type (void)
534 {
535   static GType spec_type = 0;
536
537   if (! spec_type)
538     {
539       const GTypeInfo type_info =
540       {
541         sizeof (GParamSpecClass),
542         NULL, NULL,
543         (GClassInitFunc) gtk_param_unit_class_init,
544         NULL, NULL,
545         sizeof (GtkParamSpecUnit),
546         0, NULL, NULL
547       };
548
549       spec_type = g_type_register_static (G_TYPE_PARAM_INT,
550                                           "GtkParamUnit",
551                                           &type_info, 0);
552     }
553
554   return spec_type;
555 }
556
557 static void
558 gtk_param_unit_class_init (GParamSpecClass *class)
559 {
560   class->value_type     = GTK_TYPE_UNIT;
561   class->value_validate = gtk_param_unit_value_validate;
562 }
563
564 static gboolean
565 gtk_param_unit_value_validate (GParamSpec *pspec,
566                                 GValue     *value)
567 {
568   GParamSpecInt     *ispec = G_PARAM_SPEC_INT (pspec);
569   GtkParamSpecUnit *uspec = GTK_PARAM_SPEC_UNIT (pspec);
570   gint               oval  = value->data[0].v_int;
571
572   if (uspec->allow_percent && value->data[0].v_int != CM_UNIT_PERCENT) {
573       value->data[0].v_int = CLAMP (value->data[0].v_int,
574                                     ispec->minimum,
575                                     gtk_unit_get_number_of_units () - 1);
576   }
577
578   return value->data[0].v_int != oval;
579 }
580
581 /**
582  * gtk_param_spec_unit:
583  * @name:          Canonical name of the param
584  * @nick:          Nickname of the param
585  * @blurb:         Brief desciption of param.
586  * @allow_pixels:  Whether "pixels" is an allowed unit.
587  * @allow_percent: Whether "perecent" is an allowed unit.
588  * @default_value: Unit to use if none is assigned.
589  * @flags:         a combination of #GParamFlags
590  *
591  * Creates a param spec to hold a units param.
592  * See g_param_spec_internal() for more information.
593  *
594  * Returns: a newly allocated #GParamSpec instance
595  *
596  * Since: GTK 2.4
597  **/
598 GParamSpec *
599 gtk_param_spec_unit (const gchar *name,
600                       const gchar *nick,
601                       const gchar *blurb,
602                       gboolean     allow_pixels,
603                       gboolean     allow_percent,
604                       GtkCMUnit     default_value,
605                       GParamFlags  flags)
606 {
607   GtkParamSpecUnit *pspec;
608   GParamSpecInt     *ispec;
609
610   pspec = g_param_spec_internal (GTK_TYPE_PARAM_UNIT,
611                                  name, nick, blurb, flags);
612
613   ispec = G_PARAM_SPEC_INT (pspec);
614
615   ispec->default_value = default_value;
616   ispec->minimum       = allow_pixels ? CM_UNIT_PIXEL : CM_UNIT_INCH;
617   ispec->maximum       = CM_UNIT_PERCENT - 1;
618
619   pspec->allow_percent = allow_percent;
620
621   return G_PARAM_SPEC (pspec);
622 }
623
624 /**
625  * gtk_pixels_to_units:
626  * @pixels:     value in pixels
627  * @unit:       unit to convert to
628  * @resolution: resloution in DPI
629  *
630  * Converts a @value specified in pixels to @unit.
631  *
632  * Returns: @pixels converted to units.
633  *
634  * Since: GTK 2.8
635  **/
636 gdouble
637 gtk_pixels_to_units (gdouble  pixels,
638                       GtkCMUnit unit,
639                       gdouble  resolution)
640 {
641   if (unit == CM_UNIT_PIXEL)
642     return pixels;
643
644   return pixels * gtk_unit_get_factor (unit) / resolution;
645 }
646
647 /**
648  * gtk_units_to_pixels:
649  * @value:      value in units
650  * @unit:       unit of @value
651  * @resolution: resloution in DPI
652  *
653  * Converts a @value specified in @unit to pixels.
654  *
655  * Returns: @value converted to pixels.
656  *
657  * Since: GTK 2.8
658  **/
659 gdouble
660 gtk_units_to_pixels (gdouble  value,
661                       GtkCMUnit unit,
662                       gdouble  resolution)
663 {
664   if (unit == CM_UNIT_PIXEL)
665     return value;
666
667   return value * resolution / gtk_unit_get_factor (unit);
668 }
669
670 /**
671  * gtk_units_to_points:
672  * @value:      value in units
673  * @unit:       unit of @value
674  * @resolution: resloution in DPI
675  *
676  * Converts a @value specified in @unit to points.
677  *
678  * Returns: @value converted to points.
679  *
680  * Since: GTK 2.8
681  **/
682 gdouble
683 gtk_units_to_points (gdouble  value,
684                       GtkCMUnit unit,
685                       gdouble  resolution)
686 {
687   if (unit == CM_UNIT_POINT)
688     return value;
689
690   if (unit == CM_UNIT_PIXEL)
691     return (value * gtk_unit_get_factor (CM_UNIT_POINT) / resolution);
692
693   return (value *
694           gtk_unit_get_factor (CM_UNIT_POINT) / gtk_unit_get_factor (unit));
695 }