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_PC, SP_UNIT_ABSOLUTE, PX_PER_PC, SP_PC, SVGLength::PC, N_("Pica"), N_("pc"), N_("Picas"), N_("Pc")},
40 {SP_UNIT_PX, SP_UNIT_DEVICE, PX_PER_PX, SP_PX, SVGLength::PX, N_("Pixel"), N_("px"), N_("Pixels"), N_("Px")},
41 /* You can add new elements from this point forward */
42 {SP_UNIT_PERCENT, SP_UNIT_DIMENSIONLESS, 0.01, NONE, SVGLength::PERCENT, N_("Percent"), N_("%"), N_("Percents"), N_("%")},
43 {SP_UNIT_MM, SP_UNIT_ABSOLUTE, PX_PER_MM, SP_MM, SVGLength::MM, N_("Millimeter"), N_("mm"), N_("Millimeters"), N_("mm")},
44 {SP_UNIT_CM, SP_UNIT_ABSOLUTE, PX_PER_CM, SP_CM, SVGLength::CM, N_("Centimeter"), N_("cm"), N_("Centimeters"), N_("cm")},
45 {SP_UNIT_M, SP_UNIT_ABSOLUTE, PX_PER_M, SP_M, SVGLength::NONE, N_("Meter"), N_("m"), N_("Meters"), N_("m")}, // no svg_unit
46 {SP_UNIT_IN, SP_UNIT_ABSOLUTE, PX_PER_IN, SP_IN, SVGLength::INCH, N_("Inch"), N_("in"), N_("Inches"), N_("in")},
47 {SP_UNIT_FT, SP_UNIT_ABSOLUTE, PX_PER_FT, SP_FT, SVGLength::FOOT, N_("Foot"), N_("ft"), N_("Feet"), N_("ft")},
48 /* Volatiles do not have default, so there are none here */
49 // TRANSLATORS: for info, see http://www.w3.org/TR/REC-CSS2/syndata.html#length-units
50 {SP_UNIT_EM, SP_UNIT_VOLATILE, 1.0, NONE, SVGLength::EM, N_("Em square"), N_("em"), N_("Em squares"), N_("em")},
51 // TRANSLATORS: for info, see http://www.w3.org/TR/REC-CSS2/syndata.html#length-units
52 {SP_UNIT_EX, SP_UNIT_VOLATILE, 1.0, NONE, SVGLength::EX, N_("Ex square"), N_("ex"), N_("Ex squares"), N_("ex")},
53 };
55 #define sp_num_units G_N_ELEMENTS(sp_units)
57 SPUnit const *
58 sp_unit_get_by_abbreviation(gchar const *abbreviation)
59 {
60 g_return_val_if_fail(abbreviation != NULL, NULL);
62 for (unsigned i = 0 ; i < sp_num_units ; i++) {
63 if (!g_strcasecmp(abbreviation, sp_units[i].abbr)) return &sp_units[i];
64 if (!g_strcasecmp(abbreviation, sp_units[i].abbr_plural)) return &sp_units[i];
65 }
67 return NULL;
68 }
70 gchar const *
71 sp_unit_get_abbreviation(SPUnit const *unit)
72 {
73 g_return_val_if_fail(unit != NULL, NULL);
75 return unit->abbr;
76 }
78 gchar const *
79 sp_unit_get_plural (SPUnit const *unit)
80 {
81 g_return_val_if_fail(unit != NULL, NULL);
83 return unit->plural;
84 }
86 SPMetric
87 sp_unit_get_metric(SPUnit const *unit)
88 {
89 g_return_val_if_fail(unit != NULL, NONE);
91 return unit->metric;
92 }
94 guint
95 sp_unit_get_svg_unit(SPUnit const *unit)
96 {
97 g_return_val_if_fail(unit != NULL, NONE);
99 return unit->svg_unit;
100 }
102 GSList *
103 sp_unit_get_list(guint bases)
104 {
105 g_return_val_if_fail((bases & ~SP_UNITS_ALL) == 0, NULL);
107 GSList *units = NULL;
108 for (unsigned i = sp_num_units ; i--; ) {
109 if (bases & sp_units[i].base) {
110 units = g_slist_prepend(units, (gpointer) &sp_units[i]);
111 }
112 }
114 return units;
115 }
117 void
118 sp_unit_free_list(GSList *units)
119 {
120 g_slist_free(units);
121 }
123 /* These are pure utility */
124 /* Return TRUE if conversion is possible */
125 gboolean
126 sp_convert_distance(gdouble *distance, SPUnit const *from, SPUnit const *to)
127 {
128 g_return_val_if_fail(distance != NULL, FALSE);
129 g_return_val_if_fail(from != NULL, FALSE);
130 g_return_val_if_fail(to != NULL, FALSE);
132 if (from == to) return TRUE;
133 if ((from->base == SP_UNIT_DIMENSIONLESS) || (to->base == SP_UNIT_DIMENSIONLESS)) {
134 *distance = *distance * from->unittobase / to->unittobase;
135 return TRUE;
136 }
137 if ((from->base == SP_UNIT_VOLATILE) || (to->base == SP_UNIT_VOLATILE)) return FALSE;
139 if ((from->base == to->base)
140 || ((from->base == SP_UNIT_DEVICE) && (to->base == SP_UNIT_ABSOLUTE))
141 || ((from->base == SP_UNIT_ABSOLUTE) && (to->base == SP_UNIT_DEVICE)))
142 {
143 *distance = *distance * from->unittobase / to->unittobase;
144 return TRUE;
145 }
147 return FALSE;
148 }
150 /** @param devicetransform for device units. */
151 /* TODO: Remove the ctmscale parameter given that we no longer have SP_UNIT_USERSPACE. */
152 gdouble
153 sp_convert_distance_full(gdouble const from_dist, SPUnit const &from, SPUnit const &to)
154 {
155 if (&from == &to) {
156 return from_dist;
157 }
158 if (from.base == to.base) {
159 gdouble ret = from_dist;
160 bool const succ = sp_convert_distance(&ret, &from, &to);
161 g_assert(succ);
162 return ret;
163 }
164 if ((from.base == SP_UNIT_DIMENSIONLESS)
165 || (to.base == SP_UNIT_DIMENSIONLESS))
166 {
167 return from_dist * from.unittobase / to.unittobase;
168 }
169 g_return_val_if_fail(((from.base != SP_UNIT_VOLATILE)
170 && (to.base != SP_UNIT_VOLATILE)),
171 from_dist);
173 gdouble absolute;
174 switch (from.base) {
175 case SP_UNIT_ABSOLUTE:
176 case SP_UNIT_DEVICE:
177 absolute = from_dist * from.unittobase;
178 break;
179 default:
180 g_warning("file %s: line %d: Illegal unit (base 0x%x)", __FILE__, __LINE__, from.base);
181 return from_dist;
182 }
184 gdouble ret;
185 switch (to.base) {
186 default:
187 g_warning("file %s: line %d: Illegal unit (base 0x%x)", __FILE__, __LINE__, to.base);
188 /* FALL-THROUGH */
189 case SP_UNIT_ABSOLUTE:
190 case SP_UNIT_DEVICE:
191 ret = absolute / to.unittobase;
192 break;
193 }
195 return ret;
196 }
198 /* Some more convenience */
200 gdouble
201 sp_units_get_pixels(gdouble const units, SPUnit const &unit)
202 {
203 if (unit.base == SP_UNIT_ABSOLUTE || unit.base == SP_UNIT_DEVICE) {
204 return units * unit.unittobase;
205 } else {
206 g_warning("Different unit bases: No exact unit conversion available");
207 return units * unit.unittobase;
208 }
209 }
211 gdouble
212 sp_pixels_get_units(gdouble const pixels, SPUnit const &unit)
213 {
214 if (unit.base == SP_UNIT_ABSOLUTE || unit.base == SP_UNIT_DEVICE) {
215 return pixels / unit.unittobase;
216 } else {
217 g_warning("Different unit bases: No exact unit conversion available");
218 return pixels / unit.unittobase;
219 }
220 }
222 bool
223 sp_units_table_sane()
224 {
225 for (unsigned i = 0; i < G_N_ELEMENTS(sp_units); ++i) {
226 if (unsigned(sp_units[i].unit_id) != i) {
227 return false;
228 }
229 }
230 return true;
231 }
233 /** Converts angle (in deg) to compass display */
234 double
235 angle_to_compass(double angle)
236 {
237 double ret = 90 - angle;
238 if (ret < 0)
239 ret = 360 + ret;
240 return ret;
241 }
243 /** Converts angle (in deg) to compass display */
244 double
245 angle_from_compass(double angle)
246 {
247 double ret = 90 - angle;
248 if (ret > 180)
249 ret = ret - 180;
250 return ret;
251 }
254 /*
255 Local Variables:
256 mode:c++
257 c-file-style:"stroustrup"
258 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
259 indent-tabs-mode:nil
260 fill-column:99
261 End:
262 */
263 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :