gimpunit.c 17 KB

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