talons

Fork of Claws Mail https://www.claws-mail
Log | Files | Refs | README | LICENSE

gtkunit.c (17812B)


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