18#include <unordered_map>
20#include <glibmm/regex.h>
21#include <glibmm/fileutils.h>
22#include <glibmm/markup.h>
40#define MAKE_UNIT_CODE(a, b) \
41 ((((unsigned)(a) & 0xdf) << 8) | ((unsigned)(b) & 0xdf))
44 UNIT_CODE_PX = MAKE_UNIT_CODE(
'p',
'x'),
45 UNIT_CODE_PT = MAKE_UNIT_CODE(
'p',
't'),
46 UNIT_CODE_PC = MAKE_UNIT_CODE(
'p',
'c'),
47 UNIT_CODE_MM = MAKE_UNIT_CODE(
'm',
'm'),
48 UNIT_CODE_CM = MAKE_UNIT_CODE(
'c',
'm'),
49 UNIT_CODE_IN = MAKE_UNIT_CODE(
'i',
'n'),
50 UNIT_CODE_EM = MAKE_UNIT_CODE(
'e',
'm'),
51 UNIT_CODE_EX = MAKE_UNIT_CODE(
'e',
'x'),
52 UNIT_CODE_PERCENT = MAKE_UNIT_CODE(
'%',0)
56inline unsigned make_unit_code(
char const *str) {
57 if (!str || str[0] == 0)
return 0;
58 return MAKE_UNIT_CODE(str[0], str[1]);
63unsigned const svg_length_lookup[] = {
79typedef std::unordered_map<unsigned, SVGLength::Unit> UnitCodeLookup;
81UnitCodeLookup make_unit_code_lookup()
84 for (
unsigned i = 1; i < G_N_ELEMENTS(svg_length_lookup); ++i) {
90UnitCodeLookup
const unit_code_lookup = make_unit_code_lookup();
94typedef std::unordered_map<Glib::ustring, Inkscape::Util::UnitType> TypeMap;
98TypeMap make_type_map()
110TypeMap
const type_map = make_type_map();
117class UnitParser :
public Glib::Markup::Parser
120 typedef Glib::Markup::Parser::AttributeMap AttrMap;
121 typedef Glib::Markup::ParseContext Ctx;
123 UnitParser(UnitTable *table);
124 ~UnitParser()
override =
default;
127 void on_start_element(Ctx &ctx, Glib::ustring
const &
name, AttrMap
const &attrs)
override;
128 void on_end_element(Ctx &ctx, Glib::ustring
const &
name)
override;
129 void on_text(Ctx &ctx, Glib::ustring
const &text)
override;
138UnitParser::UnitParser(UnitTable *table) :
160 Glib::ustring name_plural,
162 Glib::ustring description)
166 , name_plural(
std::move(name_plural))
167 , abbr(
std::move(abbr))
168 , description(
std::move(description))
170 g_return_if_fail(
factor <= 0);
180 int factor_digits = int(log10(
factor));
181 if (factor_digits < 0) {
182 g_warning(
"factor = %f, factor_digits = %d",
factor, factor_digits);
183 g_warning(
"factor_digits < 0 - returning 0");
186 return factor_digits;
216 char const *astr =
abbr.c_str();
217 unsigned code = make_unit_code(astr);
219 UnitCodeLookup::const_iterator u = unit_code_lookup.find(code);
220 if (u != unit_code_lookup.end()) {
230 return from_dist * to->
factor;
257 load(get_filename(UIS,
"units.xml",
false,
true));
278 UnitCodeMap::const_iterator f =
_unit_map.find(make_unit_code(abbr));
280 return &(*f->second);
287 return getUnit(unit_abbr.c_str());
295 UnitCodeMap::const_iterator f =
_unit_map.find(svg_length_lookup[u]);
297 return &(*f->second);
304 const double eps = factor * 0.01;
306 UnitCodeMap::const_iterator cit =
_unit_map.begin();
308 if (cit->second->type == type) {
326 Glib::MatchInfo match_info;
330 Glib::RefPtr<Glib::Regex> value_regex = Glib::Regex::create(
"[-+]*[\\d+]*[\\.,]*[\\d+]*[eE]*[-+]*\\d+");
331 if (value_regex->match(q, match_info)) {
332 std::istringstream tmp_v(match_info.fetch(0).raw());
335 int start_pos, end_pos;
336 match_info.fetch_pos(0, end_pos, start_pos);
337 end_pos = q.size() - start_pos;
338 Glib::ustring u = q.substr(start_pos, end_pos);
342 Glib::RefPtr<Glib::Regex> unit_regex = Glib::Regex::create(
"[A-z%]+");
343 if (unit_regex->match(u, match_info)) {
344 abbr = match_info.fetch(0);
371 UnitCodeMap::const_iterator iter =
_unit_map.find(make_unit_code(unit.c_str()));
379 if (iter.second->type == type) {
380 submap.insert(UnitMap::value_type(iter.second->abbr, *iter.second));
393 UnitParser uparser(
this);
394 Glib::Markup::ParseContext ctx(uparser);
397 Glib::ustring unitfile = Glib::file_get_contents(filename);
400 }
catch (Glib::FileError
const &e) {
401 g_warning(
"Units file %s is missing: %s\n", filename.c_str(), e.what());
403 }
catch (Glib::MarkupError
const &e) {
404 g_warning(
"Problem loading units file '%s': %s\n", filename.c_str(), e.what());
424void UnitParser::on_start_element(Ctx &, Glib::ustring
const &
name, AttrMap
const &attrs)
426 if (
name ==
"unit") {
432 AttrMap::const_iterator f;
433 if ((f = attrs.find(
"type")) != attrs.end()) {
434 Glib::ustring type = f->second;
435 TypeMap::const_iterator tf = type_map.find(type);
436 if (tf != type_map.end()) {
437 unit.type = tf->second;
439 g_warning(
"Skipping unknown unit type '%s'.\n", type.c_str());
443 if ((f = attrs.find(
"pri")) != attrs.end()) {
444 primary = (f->second[0] ==
'y' || f->second[0] ==
'Y');
449void UnitParser::on_text(Ctx &ctx, Glib::ustring
const &text)
451 Glib::ustring element = ctx.get_element();
452 if (element ==
"name") {
454 }
else if (element ==
"plural") {
455 unit.name_plural = text;
456 }
else if (element ==
"abbr") {
458 }
else if (element ==
"factor") {
460 unit.factor = g_ascii_strtod(text.c_str(),
nullptr);
461 }
else if (element ==
"description") {
462 unit.description = text;
466void UnitParser::on_end_element(Ctx &, Glib::ustring
const &
name)
468 if (
name ==
"unit" && !skip) {
469 tbl->addUnit(unit, primary);
479 : unit(
UnitTable::get().getUnit(u.c_str()))
508 return value(u.c_str());
527 return from->
convert(from_dist, to);
549 g_warning(
"Incompatible units");
bool compatibleWith(Unit const *u) const
Checks if a quantity is compatible with the specified unit.
Quantity(double q, Unit const *u)
Initialize a quantity.
double value(Unit const *u) const
Return the quantity's value in the specified unit.
Glib::ustring string() const
bool operator==(Quantity const &other) const
bool operator<(Quantity const &rhs) const
Comparison operators.
static double convert(double from_dist, Unit const *from, Unit const *to)
Convert distances.
Unit const * findUnit(double factor, UnitType type) const
Try to find a unit based on its conversion factor to the primary.
Glib::ustring primary(UnitType type) const
Returns the default unit abbr for the given type.
Quantity parseQuantity(Glib::ustring const &q) const
Retrieve a quantity based on its string identifier.
std::unordered_map< Glib::ustring, Unit > UnitMap
UnitMap units(UnitType type) const
Provides an iterable list of items in the given unit table.
bool load(std::string const &filename)
Load units from an XML file.
void addUnit(Unit const &u, bool primary)
Add a new unit to the table.
bool hasUnit(Glib::ustring const &name) const
Remove a unit definition from the given unit type table * / DISABLED, unsafe with the current passing...
Glib::ustring _primary_unit[UNIT_TYPE_QTY]
Unit const * getUnit(Glib::ustring const &name) const
Retrieve a given unit based on its string identifier.
UnitTable()
Initializes the unit tables and identifies the primary unit types.
double convert(double from_dist, Unit const *to) const
Convert value from this unit.
int defaultDigits() const
Returns the suggested precision to use for displaying numbers of this unit.
bool compatibleWith(Unit const *u) const
Checks if a unit is compatible with the specified unit.
int svgUnit() const
Get SVG unit code.
bool operator==(Unit const &other) const
Check if units are equal.
Integral and real coordinate types and some basic utilities.
bool are_near(Affine const &a1, Affine const &a2, Coord eps=EPSILON)
Miscellaneous supporting code.
@ UNIT_TYPE_DIMENSIONLESS
Glib::ustring format_classic(T const &... args)
Helper class to stream background task notifications as a series of messages.
TODO: insert short description here.
Inkscape::IO::Resource - simple resource API.
TODO: insert short description here.