1 #define __SP_PAPER_C__
3 /*
4 * SPUnit
5 *
6 * Ported from libgnomeprint
7 *
8 * Authors:
9 * Dirk Luetjens <dirk@luedi.oche.de>
10 * Yves Arrouye <Yves.Arrouye@marin.fdn.fr>
11 * Lauris Kaplinski <lauris@ximian.com>
12 * bulia byak <buliabyak@users.sf.net>
13 *
14 * Copyright 1999-2001 Ximian, Inc. and authors
15 *
16 */
18 #ifdef HAVE_CONFIG_H
19 # include "config.h"
20 #endif
22 #include "helper/units.h"
23 #include <glib.h> // g_assert()
24 #include <glibmm/i18n.h>
25 #include "unit-constants.h"
26 #include "svg/svg-length.h"
28 /* todo: use some fancy unit program */
30 /* The order determines the order of the list returned by sp_unit_get_list.
31 * (It can also affect string lookups if there are any duplicates in the
32 * current locale... hopefully none.) If you re-order this list, then you must
33 * also re-order the SPUnitId enum values accordingly. Run `make check' (which
34 * calls sp_unit_table_sane) to ensure that the two are in sync.
35 */
36 SPUnit const sp_units[] = {
37 {SP_UNIT_SCALE, SP_UNIT_DIMENSIONLESS, 1.0, NONE, SVGLength::NONE, N_("Unit"), "", N_("Units"), ""},
38 {SP_UNIT_PT, SP_UNIT_ABSOLUTE, PX_PER_PT, SP_PT, SVGLength::PT, N_("Point"), N_("pt"), N_("Points"), N_("Pt")},
39 {SP_UNIT_PX, SP_UNIT_DEVICE, PX_PER_PX, SP_PX, SVGLength::PX, N_("Pixel"), N_("px"), N_("Pixels"), N_("Px")},
40 /* You can add new elements from this point forward */
41 {SP_UNIT_PERCENT, SP_UNIT_DIMENSIONLESS, 0.01, NONE, SVGLength::PERCENT, N_("Percent"), N_("%"), N_("Percents"), N_("%")},
42 {SP_UNIT_MM, SP_UNIT_ABSOLUTE, PX_PER_MM, SP_MM, SVGLength::MM, N_("Millimeter"), N_("mm"), N_("Millimeters"), N_("mm")},
43 {SP_UNIT_CM, SP_UNIT_ABSOLUTE, PX_PER_CM, SP_CM, SVGLength::CM, N_("Centimeter"), N_("cm"), N_("Centimeters"), N_("cm")},
44 {SP_UNIT_M, SP_UNIT_ABSOLUTE, PX_PER_M, SP_M, SVGLength::NONE, N_("Meter"), N_("m"), N_("Meters"), N_("m")}, // no svg_unit
45 {SP_UNIT_IN, SP_UNIT_ABSOLUTE, PX_PER_IN, SP_IN, SVGLength::INCH, N_("Inch"), N_("in"), N_("Inches"), N_("in")},
46 /* Volatiles do not have default, so there are none here */
47 // TRANSLATORS: for info, see http://www.w3.org/TR/REC-CSS2/syndata.html#length-units
48 {SP_UNIT_EM, SP_UNIT_VOLATILE, 1.0, NONE, SVGLength::EM, N_("Em square"), N_("em"), N_("Em squares"), N_("em")},
49 // TRANSLATORS: for info, see http://www.w3.org/TR/REC-CSS2/syndata.html#length-units
50 {SP_UNIT_EX, SP_UNIT_VOLATILE, 1.0, NONE, SVGLength::EX, N_("Ex square"), N_("ex"), N_("Ex squares"), N_("ex")},
51 };
53 #define sp_num_units G_N_ELEMENTS(sp_units)
55 SPUnit const *
56 sp_unit_get_by_abbreviation(gchar const *abbreviation)
57 {
58 g_return_val_if_fail(abbreviation != NULL, NULL);
60 for (unsigned i = 0 ; i < sp_num_units ; i++) {
61 if (!g_strcasecmp(abbreviation, sp_units[i].abbr)) return &sp_units[i];
62 if (!g_strcasecmp(abbreviation, sp_units[i].abbr_plural)) return &sp_units[i];
63 }
65 return NULL;
66 }
68 gchar const *
69 sp_unit_get_abbreviation(SPUnit const *unit)
70 {
71 g_return_val_if_fail(unit != NULL, NULL);
73 return unit->abbr;
74 }
76 gchar const *
77 sp_unit_get_plural (SPUnit const *unit)
78 {
79 g_return_val_if_fail(unit != NULL, NULL);
81 return unit->plural;
82 }
84 SPMetric
85 sp_unit_get_metric(SPUnit const *unit)
86 {
87 g_return_val_if_fail(unit != NULL, NONE);
89 return unit->metric;
90 }
92 guint
93 sp_unit_get_svg_unit(SPUnit const *unit)
94 {
95 g_return_val_if_fail(unit != NULL, NONE);
97 return unit->svg_unit;
98 }
100 GSList *
101 sp_unit_get_list(guint bases)
102 {
103 g_return_val_if_fail((bases & ~SP_UNITS_ALL) == 0, NULL);
105 GSList *units = NULL;
106 for (unsigned i = sp_num_units ; i--; ) {
107 if (bases & sp_units[i].base) {
108 units = g_slist_prepend(units, (gpointer) &sp_units[i]);
109 }
110 }
112 return units;
113 }
115 void
116 sp_unit_free_list(GSList *units)
117 {
118 g_slist_free(units);
119 }
121 /* These are pure utility */
122 /* Return TRUE if conversion is possible */
123 gboolean
124 sp_convert_distance(gdouble *distance, SPUnit const *from, SPUnit const *to)
125 {
126 g_return_val_if_fail(distance != NULL, FALSE);
127 g_return_val_if_fail(from != NULL, FALSE);
128 g_return_val_if_fail(to != NULL, FALSE);
130 if (from == to) return TRUE;
131 if ((from->base == SP_UNIT_DIMENSIONLESS) || (to->base == SP_UNIT_DIMENSIONLESS)) {
132 *distance = *distance * from->unittobase / to->unittobase;
133 return TRUE;
134 }
135 if ((from->base == SP_UNIT_VOLATILE) || (to->base == SP_UNIT_VOLATILE)) return FALSE;
137 if ((from->base == to->base)
138 || (from->base == SP_UNIT_DEVICE) && (to->base == SP_UNIT_ABSOLUTE)
139 || (from->base == SP_UNIT_ABSOLUTE) && (to->base == SP_UNIT_DEVICE))
140 {
141 *distance = *distance * from->unittobase / to->unittobase;
142 return TRUE;
143 }
145 return FALSE;
146 }
148 /** @param devicetransform for device units. */
149 /* TODO: Remove the ctmscale parameter given that we no longer have SP_UNIT_USERSPACE. */
150 gdouble
151 sp_convert_distance_full(gdouble const from_dist, SPUnit const &from, SPUnit const &to)
152 {
153 if (&from == &to) {
154 return from_dist;
155 }
156 if (from.base == to.base) {
157 gdouble ret = from_dist;
158 bool const succ = sp_convert_distance(&ret, &from, &to);
159 g_assert(succ);
160 return ret;
161 }
162 if ((from.base == SP_UNIT_DIMENSIONLESS)
163 || (to.base == SP_UNIT_DIMENSIONLESS))
164 {
165 return from_dist * from.unittobase / to.unittobase;
166 }
167 g_return_val_if_fail(((from.base != SP_UNIT_VOLATILE)
168 && (to.base != SP_UNIT_VOLATILE)),
169 from_dist);
171 gdouble absolute;
172 switch (from.base) {
173 case SP_UNIT_ABSOLUTE:
174 case SP_UNIT_DEVICE:
175 absolute = from_dist * from.unittobase;
176 break;
177 default:
178 g_warning("file %s: line %d: Illegal unit (base 0x%x)", __FILE__, __LINE__, from.base);
179 return from_dist;
180 }
182 gdouble ret;
183 switch (to.base) {
184 default:
185 g_warning("file %s: line %d: Illegal unit (base 0x%x)", __FILE__, __LINE__, to.base);
186 /* FALL-THROUGH */
187 case SP_UNIT_ABSOLUTE:
188 case SP_UNIT_DEVICE:
189 ret = absolute / to.unittobase;
190 break;
191 }
193 return ret;
194 }
196 /* Some more convenience */
198 gdouble
199 sp_units_get_pixels(gdouble const units, SPUnit const &unit)
200 {
201 if (unit.base == SP_UNIT_ABSOLUTE || unit.base == SP_UNIT_DEVICE) {
202 return units * unit.unittobase;
203 } else {
204 g_warning("Different unit bases: No exact unit conversion available");
205 return units * unit.unittobase;
206 }
207 }
209 gdouble
210 sp_pixels_get_units(gdouble const pixels, SPUnit const &unit)
211 {
212 if (unit.base == SP_UNIT_ABSOLUTE || unit.base == SP_UNIT_DEVICE) {
213 return pixels / unit.unittobase;
214 } else {
215 g_warning("Different unit bases: No exact unit conversion available");
216 return pixels / unit.unittobase;
217 }
218 }
220 bool
221 sp_units_table_sane()
222 {
223 for (unsigned i = 0; i < G_N_ELEMENTS(sp_units); ++i) {
224 if (unsigned(sp_units[i].unit_id) != i) {
225 return false;
226 }
227 }
228 return true;
229 }
231 /** Converts angle (in deg) to compass display */
232 double
233 angle_to_compass(double angle)
234 {
235 double ret = 90 - angle;
236 if (ret < 0)
237 ret = 360 + ret;
238 return ret;
239 }
241 /** Converts angle (in deg) to compass display */
242 double
243 angle_from_compass(double angle)
244 {
245 double ret = 90 - angle;
246 if (ret > 180)
247 ret = ret - 180;
248 return ret;
249 }
252 /*
253 Local Variables:
254 mode:c++
255 c-file-style:"stroustrup"
256 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
257 indent-tabs-mode:nil
258 fill-column:99
259 End:
260 */
261 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :