448f60302ddc1b5a0f3e561c7856ef95df47288f
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 <glibmm/i18n.h>
24 #include "unit-constants.h"
25 #include "svg/svg-length.h"
27 /* todo: use some fancy unit program */
29 /* The order determines the order of the list returned by sp_unit_get_list.
30 * (It can also affect string lookups if there are any duplicates in the
31 * current locale... hopefully none.) If you re-order this list, then you must
32 * also re-order the SPUnitId enum values accordingly. Run `make check' (which
33 * calls sp_unit_table_sane) to ensure that the two are in sync.
34 */
35 SPUnit const sp_units[] = {
36 {SP_UNIT_SCALE, SP_UNIT_DIMENSIONLESS, 1.0, NONE, SVGLength::NONE, N_("Unit"), "", N_("Units"), ""},
37 {SP_UNIT_PT, SP_UNIT_ABSOLUTE, PX_PER_PT, SP_PT, SVGLength::PT, N_("Point"), N_("pt"), N_("Points"), N_("Pt")},
38 {SP_UNIT_PX, SP_UNIT_DEVICE, PX_PER_PX, SP_PX, SVGLength::PX, N_("Pixel"), N_("px"), N_("Pixels"), N_("Px")},
39 /* You can add new elements from this point forward */
40 {SP_UNIT_PERCENT, SP_UNIT_DIMENSIONLESS, 0.01, NONE, SVGLength::PERCENT, N_("Percent"), N_("%"), N_("Percents"), N_("%")},
41 {SP_UNIT_MM, SP_UNIT_ABSOLUTE, PX_PER_MM, SP_MM, SVGLength::MM, N_("Millimeter"), N_("mm"), N_("Millimeters"), N_("mm")},
42 {SP_UNIT_CM, SP_UNIT_ABSOLUTE, PX_PER_CM, SP_CM, SVGLength::CM, N_("Centimeter"), N_("cm"), N_("Centimeters"), N_("cm")},
43 {SP_UNIT_M, SP_UNIT_ABSOLUTE, PX_PER_M, SP_M, SVGLength::NONE, N_("Meter"), N_("m"), N_("Meters"), N_("m")}, // no svg_unit
44 {SP_UNIT_IN, SP_UNIT_ABSOLUTE, PX_PER_IN, SP_IN, SVGLength::INCH, N_("Inch"), N_("in"), N_("Inches"), N_("in")},
45 /* Volatiles do not have default, so there are none here */
46 // TRANSLATORS: for info, see http://www.w3.org/TR/REC-CSS2/syndata.html#length-units
47 {SP_UNIT_EM, SP_UNIT_VOLATILE, 1.0, NONE, SVGLength::EM, N_("Em square"), N_("em"), N_("Em squares"), N_("em")},
48 // TRANSLATORS: for info, see http://www.w3.org/TR/REC-CSS2/syndata.html#length-units
49 {SP_UNIT_EX, SP_UNIT_VOLATILE, 1.0, NONE, SVGLength::EX, N_("Ex square"), N_("ex"), N_("Ex squares"), N_("ex")},
50 };
52 #define sp_num_units G_N_ELEMENTS(sp_units)
54 SPUnit const *
55 sp_unit_get_by_abbreviation(gchar const *abbreviation)
56 {
57 g_return_val_if_fail(abbreviation != NULL, NULL);
59 for (unsigned i = 0 ; i < sp_num_units ; i++) {
60 if (!g_strcasecmp(abbreviation, sp_units[i].abbr)) return &sp_units[i];
61 if (!g_strcasecmp(abbreviation, sp_units[i].abbr_plural)) return &sp_units[i];
62 }
64 return NULL;
65 }
67 gchar const *
68 sp_unit_get_abbreviation(SPUnit const *unit)
69 {
70 g_return_val_if_fail(unit != NULL, NULL);
72 return unit->abbr;
73 }
75 gchar const *
76 sp_unit_get_plural (SPUnit const *unit)
77 {
78 g_return_val_if_fail(unit != NULL, NULL);
80 return unit->plural;
81 }
83 SPMetric
84 sp_unit_get_metric(SPUnit const *unit)
85 {
86 g_return_val_if_fail(unit != NULL, NONE);
88 return unit->metric;
89 }
91 guint
92 sp_unit_get_svg_unit(SPUnit const *unit)
93 {
94 g_return_val_if_fail(unit != NULL, NONE);
96 return unit->svg_unit;
97 }
99 GSList *
100 sp_unit_get_list(guint bases)
101 {
102 g_return_val_if_fail((bases & ~SP_UNITS_ALL) == 0, NULL);
104 GSList *units = NULL;
105 for (unsigned i = sp_num_units ; i--; ) {
106 if (bases & sp_units[i].base) {
107 units = g_slist_prepend(units, (gpointer) &sp_units[i]);
108 }
109 }
111 return units;
112 }
114 void
115 sp_unit_free_list(GSList *units)
116 {
117 g_slist_free(units);
118 }
120 /* These are pure utility */
121 /* Return TRUE if conversion is possible */
122 gboolean
123 sp_convert_distance(gdouble *distance, SPUnit const *from, SPUnit const *to)
124 {
125 g_return_val_if_fail(distance != NULL, FALSE);
126 g_return_val_if_fail(from != NULL, FALSE);
127 g_return_val_if_fail(to != NULL, FALSE);
129 if (from == to) return TRUE;
130 if ((from->base == SP_UNIT_DIMENSIONLESS) || (to->base == SP_UNIT_DIMENSIONLESS)) {
131 *distance = *distance * from->unittobase / to->unittobase;
132 return TRUE;
133 }
134 if ((from->base == SP_UNIT_VOLATILE) || (to->base == SP_UNIT_VOLATILE)) return FALSE;
136 if ((from->base == to->base)
137 || (from->base == SP_UNIT_DEVICE) && (to->base == SP_UNIT_ABSOLUTE)
138 || (from->base == SP_UNIT_ABSOLUTE) && (to->base == SP_UNIT_DEVICE))
139 {
140 *distance = *distance * from->unittobase / to->unittobase;
141 return TRUE;
142 }
144 return FALSE;
145 }
147 /** @param devicetransform for device units. */
148 /* TODO: Remove the ctmscale parameter given that we no longer have SP_UNIT_USERSPACE. */
149 gdouble
150 sp_convert_distance_full(gdouble const from_dist, SPUnit const &from, SPUnit const &to)
151 {
152 if (&from == &to) {
153 return from_dist;
154 }
155 if (from.base == to.base) {
156 gdouble ret = from_dist;
157 bool const succ = sp_convert_distance(&ret, &from, &to);
158 g_assert(succ);
159 return ret;
160 }
161 if ((from.base == SP_UNIT_DIMENSIONLESS)
162 || (to.base == SP_UNIT_DIMENSIONLESS))
163 {
164 return from_dist * from.unittobase / to.unittobase;
165 }
166 g_return_val_if_fail(((from.base != SP_UNIT_VOLATILE)
167 && (to.base != SP_UNIT_VOLATILE)),
168 from_dist);
170 gdouble absolute;
171 switch (from.base) {
172 case SP_UNIT_ABSOLUTE:
173 case SP_UNIT_DEVICE:
174 absolute = from_dist * from.unittobase;
175 break;
176 default:
177 g_warning("file %s: line %d: Illegal unit (base 0x%x)", __FILE__, __LINE__, from.base);
178 return from_dist;
179 }
181 gdouble ret;
182 switch (to.base) {
183 default:
184 g_warning("file %s: line %d: Illegal unit (base 0x%x)", __FILE__, __LINE__, to.base);
185 /* FALL-THROUGH */
186 case SP_UNIT_ABSOLUTE:
187 case SP_UNIT_DEVICE:
188 ret = absolute / to.unittobase;
189 break;
190 }
192 return ret;
193 }
195 /* Some more convenience */
197 gdouble
198 sp_units_get_pixels(gdouble const units, SPUnit const &unit)
199 {
200 if (unit.base == SP_UNIT_ABSOLUTE || unit.base == SP_UNIT_DEVICE) {
201 return units * unit.unittobase;
202 } else {
203 g_warning("Different unit bases: No exact unit conversion available");
204 return units * unit.unittobase;
205 }
206 }
208 gdouble
209 sp_pixels_get_units(gdouble const pixels, SPUnit const &unit)
210 {
211 if (unit.base == SP_UNIT_ABSOLUTE || unit.base == SP_UNIT_DEVICE) {
212 return pixels / unit.unittobase;
213 } else {
214 g_warning("Different unit bases: No exact unit conversion available");
215 return pixels / unit.unittobase;
216 }
217 }
219 bool
220 sp_units_table_sane()
221 {
222 for (unsigned i = 0; i < G_N_ELEMENTS(sp_units); ++i) {
223 if (unsigned(sp_units[i].unit_id) != i) {
224 return false;
225 }
226 }
227 return true;
228 }
230 /** Converts angle (in deg) to compass display */
231 double
232 angle_to_compass(double angle)
233 {
234 double ret = 90 - angle;
235 if (ret < 0)
236 ret = 360 + ret;
237 return ret;
238 }
240 /** Converts angle (in deg) to compass display */
241 double
242 angle_from_compass(double angle)
243 {
244 double ret = 90 - angle;
245 if (ret > 180)
246 ret = ret - 180;
247 return ret;
248 }
251 /*
252 Local Variables:
253 mode:c++
254 c-file-style:"stroustrup"
255 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
256 indent-tabs-mode:nil
257 fill-column:99
258 End:
259 */
260 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :