diff options
| author | Jabiertxof <jtx@jtx> | 2016-12-16 12:00:49 +0000 |
|---|---|---|
| committer | Jabiertxof <jtx@jtx> | 2016-12-16 12:00:49 +0000 |
| commit | 4446366fd075fb801420da520848c774b8ac4254 (patch) | |
| tree | c2fc74dabefc43fd586aaf51405bebc698d7ba94 | |
| parent | Fixing nested mirrors (diff) | |
| parent | Fix bug where conical gradient drawn in wrong arc. (diff) | |
| download | inkscape-4446366fd075fb801420da520848c774b8ac4254.tar.gz inkscape-4446366fd075fb801420da520848c774b8ac4254.zip | |
Update to trunk
(bzr r15295.1.23)
| -rw-r--r-- | share/extensions/dpiswitcher.py | 371 | ||||
| -rw-r--r-- | src/desktop-style.cpp | 11 | ||||
| -rw-r--r-- | src/file.cpp | 270 | ||||
| -rw-r--r-- | src/sp-item-group.cpp | 5 | ||||
| -rw-r--r-- | src/sp-mesh-array.cpp | 2 | ||||
| -rw-r--r-- | src/ui/tools/tweak-tool.cpp | 3 | ||||
| -rw-r--r-- | src/widgets/text-toolbar.cpp | 48 | ||||
| -rw-r--r-- | src/widgets/toolbox.cpp | 1 |
8 files changed, 559 insertions, 152 deletions
diff --git a/share/extensions/dpiswitcher.py b/share/extensions/dpiswitcher.py index 46dad5ee5..317616db5 100644 --- a/share/extensions/dpiswitcher.py +++ b/share/extensions/dpiswitcher.py @@ -1,10 +1,11 @@ #!/usr/bin/env python ''' -This extension scale or reduce a document to fit diferent SVG DPI -90/96- +This extension scales a document to fit different SVG DPI -90/96- Copyright (C) 2012 Jabiertxo Arraiza, jabier.arraiza@marker.es +Copyright (C) 2016 su_v, <suv-sf@users.sf.net> -Version 0.5 - DPI Switcher +Version 0.6 - DPI Switcher This program is free software; you can redistribute it and/or modify it under the terms of the GNU General Public License as published by @@ -19,22 +20,40 @@ GNU General Public License for more details. You should have received a copy of the GNU General Public License along with this program; if not, write to the Free Software Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA + + +Changes since v0.5: + - transform all top-level containers and graphics elements + - support scientific notation in SVG lengths + - fix scaling with existing matrix() (use functions from simpletransform.py) + - support different units for document width, height attributes + - improve viewBox support (syntax, offset) + - support common cases of text-put-on-path in SVG root + - support common cases of <use> references in SVG root + - examples from http://tavmjong.free.fr/INKSCAPE/UNITS/ tested + +TODO: + - check grids/guides created with 0.91: + http://tavmjong.free.fr/INKSCAPE/UNITS/units_mm_nv_90dpi.svg + - check <symbol> instances + - check more <use> and text-on-path cases (reverse scaling needed?) + - scale perspective of 3dboxes + ''' # standard libraries import sys import re import string +import math from lxml import etree # local libraries import inkex +import simpletransform +import simplestyle # globals -REFERENCED_CONTAINERS = [ - # These container elements - which may be referenced by other - # elements - do not need to be scaled directly. The referencing - # elements will be either insided scaled containers or scaled - # directly as graphics elements in SVG root. +SKIP_CONTAINERS = [ 'defs', 'glyph', 'marker', @@ -44,15 +63,11 @@ REFERENCED_CONTAINERS = [ 'symbol', ] CONTAINER_ELEMENTS = [ - # These element types have graphics elements and other container - # elements as child elements. They need to be scaled if in SVG root. 'a', 'g', 'switch', ] GRAPHICS_ELEMENTS = [ - # These element types cause graphics to be drawn. They need to be - # scaled if in SVG root. 'circle', 'ellipse', 'image', @@ -64,14 +79,118 @@ GRAPHICS_ELEMENTS = [ 'text', 'use', ] -# FIXME: instances and referenced elements -# If for example a referenced element in SVG root is directly scaled, -# and its instance (referencing element e.g. <use>) is inside a scaled -# top-level container, the instance in the end will be rendered at an -# incorrect scale relative to the viewport (page area) and the other -# drawing content. Another unsupported case is both the referenced -# element and the instance in SVG root: the clone will in the end be -# rendered with the scale factor applied twice. + +def is_3dbox(element): + """Check whether element is an Inkscape 3dbox type.""" + return element.get(inkex.addNS('type', 'sodipodi')) == 'inkscape:box3d' + + +def is_use(element): + """Check whether element is of type <text>.""" + return element.tag == inkex.addNS('use', 'svg') + + +def is_text(element): + """Check whether element is of type <text>.""" + return element.tag == inkex.addNS('text', 'svg') + + +def is_text_on_path(element): + """Check whether text element is put on a path.""" + if is_text(element): + text_path = element.find(inkex.addNS('textPath', 'svg')) + if text_path is not None and len(text_path): + return True + return False + + +def is_sibling(element1, element2): + """Check whether element1 and element2 are siblings of same parent.""" + return element2 in element1.getparent() + + +def is_in_defs(doc, element): + """Check whether element is in defs.""" + if element is not None: + defs = doc.find('defs', namespaces=inkex.NSS) + if defs is not None: + return linked_node in defs.iterdescendants() + return False + + +def get_linked(doc, element): + """Return linked element or None.""" + if element is not None: + href = element.get(inkex.addNS('href', 'xlink'), None) + if href is not None: + linked_id = href[href.find('#')+1:] + path = '//*[@id="%s"]' % linked_id + el_list = doc.xpath(path, namespaces=inkex.NSS) + if isinstance(el_list, list) and len(el_list): + return el_list[0] + else: + return None + + +def check_3dbox(svg, element, scale_x, scale_y): + """Check transformation for 3dbox element.""" + skip = False + if skip: + # 3dbox elements ignore preserved transforms + # FIXME: manually update geometry of 3dbox? + pass + return skip + + +def check_text_on_path(svg, element, scale_x, scale_y): + """Check whether to skip scaling a text put on a path.""" + skip = False + path = get_linked(svg, element.find(inkex.addNS('textPath', 'svg'))) + if not is_in_defs(svg, path): + if is_sibling(element, path): + # skip common element scaling if both text and path are siblings + skip = True + # scale offset + if 'transform' in element.attrib: + mat = simpletransform.parseTransform(element.get('transform')) + mat[0][2] *= scale_x + mat[1][2] *= scale_y + element.set('transform', simpletransform.formatTransform(mat)) + # scale font size + mat = simpletransform.parseTransform( + 'scale({},{})'.format(scale_x, scale_y)) + det = abs(mat[0][0]*mat[1][1] - mat[0][1]*mat[1][0]) + descrim = math.sqrt(abs(det)) + prop = 'font-size' + # outer text + sdict = simplestyle.parseStyle(element.get('style')) + if prop in sdict: + sdict[prop] = float(sdict[prop]) * descrim + element.set('style', simplestyle.formatStyle(sdict)) + # inner tspans + for child in element.iterdescendants(): + if child.tag == inkex.addNS('tspan', 'svg'): + sdict = simplestyle.parseStyle(child.get('style')) + if prop in sdict: + sdict[prop] = float(sdict[prop]) * descrim + child.set('style', simplestyle.formatStyle(sdict)) + return skip + + +def check_use(svg, element, scale_x, scale_y): + """Check whether to skip scaling an instanciated element (<use>).""" + skip = False + path = get_linked(svg, element) + if not is_in_defs(svg, path): + if is_sibling(element, path): + skip = True + # scale offset + if 'transform' in element.attrib: + mat = simpletransform.parseTransform(element.get('transform')) + mat[0][2] *= scale_x + mat[1][2] *= scale_y + element.set('transform', simpletransform.formatTransform(mat)) + return skip class DPISwitcher(inkex.Effect): @@ -89,106 +208,140 @@ class DPISwitcher(inkex.Effect): self.units = "px" self.unitExponent = 1.0 + # dictionaries of unit to user unit conversion factors + __uuconvLegacy = { + 'in': 90.0, + 'pt': 1.25, + 'px': 1.0, + 'mm': 3.5433070866, + 'cm': 35.433070866, + 'm': 3543.3070866, + 'km': 3543307.0866, + 'pc': 15.0, + 'yd': 3240.0, + 'ft': 1080.0, + } + __uuconv = { + 'in': 96.0, + 'pt': 1.33333333333, + 'px': 1.0, + 'mm': 3.77952755913, + 'cm': 37.7952755913, + 'm': 3779.52755913, + 'km': 3779527.55913, + 'pc': 16.0, + 'yd': 3456.0, + 'ft': 1152.0, + } + + def parse_length(self, length, percent=False): + """Parse SVG length.""" + if self.options.switcher == "0": # dpi90to96 + known_units = self.__uuconvLegacy.keys() + else: # dpi96to90 + known_units = self.__uuconv.keys() + if percent: + unitmatch = re.compile('(%s)$' % '|'.join(known_units + ['%'])) + else: + unitmatch = re.compile('(%s)$' % '|'.join(known_units)) + param = re.compile(r'(([-+]?[0-9]+(\.[0-9]*)?|[-+]?\.[0-9]+)([eE][-+]?[0-9]+)?)') + p = param.match(length) + u = unitmatch.search(length) + val = 100 # fallback: assume default length of 100 + unit = 'px' # fallback: assume 'px' unit + if p: + val = float(p.string[p.start():p.end()]) + if u: + unit = u.string[u.start():u.end()] + return (val, unit) + + def convert_length(self, val, unit): + """Convert length to self.units if unit differs.""" + doc_unit = self.units or 'px' + if unit != doc_unit: + if self.options.switcher == "0": # dpi90to96 + val_px = val * self.__uuconvLegacy[unit] + val = val_px / (self.__uuconvLegacy[doc_unit] / self.__uuconvLegacy['px']) + unit = doc_unit + else: # dpi96to90 + val_px = val * self.__uuconv[unit] + val = val_px / (self.__uuconv[doc_unit] / self.__uuconv['px']) + unit = doc_unit + return (val, unit) + + def check_attr_unit(self, element, attr, unit_list): + """Check unit of attribute value, match to units in *unit_list*.""" + if attr in element.attrib: + unit = self.parse_length(element.get(attr), percent=True)[1] + return unit in unit_list + + def scale_attr_val(self, element, attr, unit_list, factor): + """Scale attribute value if unit matches one in *unit_list*.""" + if attr in element.attrib: + val, unit = self.parse_length(element.get(attr), percent=True) + if unit in unit_list: + element.set(attr, '{}{}'.format(val * factor, unit)) + def scaleRoot(self, svg): - widthNumber = re.sub("[a-zA-Z]", "", svg.get('width')) - heightNumber = re.sub("[a-zA-Z]", "", svg.get('height')) - widthDoc = str(float(widthNumber) * self.factor_a * self.unitExponent) - heightDoc = str(float(heightNumber) * self.factor_a * self.unitExponent) - if svg.get('viewBox'): - widthNumber = svg.get('viewBox').split(" ")[2] - heightNumber = svg.get('viewBox').split(" ")[3] + """Scale all top-level elements in SVG root.""" + + # update viewport + widthNumber = self.parse_length(svg.get('width'))[0] + heightNumber = self.convert_length(*self.parse_length(svg.get('height')))[0] + widthDoc = widthNumber * self.factor_a * self.unitExponent + heightDoc = heightNumber * self.factor_a * self.unitExponent + if svg.get('height'): - svg.set('height', heightDoc) + svg.set('height', str(heightDoc)) if svg.get('width'): - svg.set('width', widthDoc) + svg.set('width', str(widthDoc)) + + # update viewBox if svg.get('viewBox'): - svg.set('viewBox',"0 0 " + str(float(widthNumber) * self.factor_a) + " " + str(float(heightNumber) * self.factor_a)) + viewboxstring = re.sub(' +|, +|,',' ', svg.get('viewBox')) + viewboxlist = [float(i) for i in viewboxstring.strip().split(' ', 4)] + svg.set('viewBox','{} {} {} {}'.format(*[(val * self.factor_a) for val in viewboxlist])) + + # update guides, grids if self.options.switcher == "1": + # FIXME: dpi96to90 only? self.scaleGuides(svg) self.scaleGrid(svg) + for element in svg: # iterate all top-level elements of SVGRoot - box3DSide = element.get(inkex.addNS('box3dsidetype', 'inkscape')) - if box3DSide: - continue - uri, tag = element.tag.split("}") + + # init variables + tag = etree.QName(element).localname width_scale = self.factor_a height_scale = self.factor_a - if tag in GRAPHICS_ELEMENTS or tag in CONTAINER_ELEMENTS: - if element.get('width') is not None and \ - (re.sub("[0-9]*\.?[0-9]", "", element.get('width')) == "%" or \ - re.sub("[0-9]*\.?[0-9]", "", element.get('width')) == "px"): - width_scale = 1.0; - if element.get('height') is not None and \ - (re.sub("[0-9]*\.?[0-9]", "", element.get('height')) == "%" or \ - re.sub("[0-9]*\.?[0-9]", "", element.get('height')) == "px"): - height_scale = 1.0; - if element.get('x') is not None and \ - re.sub("[0-9]*\.?[0-9]", "", element.get('x')) == "%": - xpos = str(float(element.get('x').replace('%','')) * self.factor_b) + '%' - element.set('x', xpos) - if element.get('y') is not None and \ - re.sub("[0-9]*\.?[0-9]", "", element.get('y')) == "%": - ypos = str(float(element.get('y').replace('%','')) * self.factor_b) + '%' - element.set('y', ypos) - if element.get('transform'): - if "matrix" in str(element.get('transform')) and width_scale != 1.0: - result = re.sub(r".*?matrix( \(|\()(.*?)\)", self.matrixElement, str(element.get('transform'))) - element.set('transform', result) - if "scale" in str(element.get('transform')) and width_scale != 1.0: - result = re.sub(r".*?scale( \(|\()(.*?)\)", self.scaleElement, str(element.get('transform'))) - element.set('transform', result) - if "translate" in str(element.get('transform')) and width_scale != 1.0: - result = re.sub(r".*?translate( \(|\()(.*?)\)", self.translateElement, str(element.get('transform'))) - element.set('transform', result) - if "skew" in str(element.get('transform')) and width_scale != 1.0: - result = re.sub(r".*?skew( \(|\()(.*?)\)", self.skewElement, str(element.get('transform'))) - element.set('transform', result) - if "scale" not in str(element.get('transform')) and "matrix" not in str(element.get('transform')): - element.set('transform', str(element.get('transform')) + "scale(" + str( width_scale) + ", " + str(height_scale) + ")") - else: - element.set('transform', "scale(" + str(width_scale) + ", " + str(height_scale) + ")") - #a dictionary of unit to user unit conversion factors - __uuconv = {'in':96.0, 'pt':1.33333333333, 'px':1.0, 'mm':3.77952755913, 'cm':37.7952755913, - 'm':3779.52755913, 'km':3779527.55913, 'pc':16.0, 'yd':3456.0 , 'ft':1152.0} - - __uuconvLegacy = {'in':90.0, 'pt':1.25, 'px':1, 'mm':3.5433070866, 'cm':35.433070866, 'm':3543.3070866, - 'km':3543307.0866, 'pc':15.0, 'yd':3240 , 'ft':1080} + if tag in GRAPHICS_ELEMENTS or tag in CONTAINER_ELEMENTS: - def scaleElement(self, m): - scaleVal = m.group(2).replace(" ","") - total = scaleVal.count(',') - if total == 1: - scaleVal = scaleVal.split(",") - return "matrix(" + str(float(scaleVal[0]) * self.factor_a) + ",0,0," + str(float(scaleVal[1]) * self.factor_a) + ",0,0)" - else: - return "matrix(" + str(float(scaleVal) * self.factor_a) + ",0,0," + str(float(scaleVal) * self.factor_a) + ",0,0)" + # test for specific elements to skip from scaling + if is_3dbox(element): + if check_3dbox(svg, element, width_scale, height_scale): + continue + if is_text_on_path(element): + if check_text_on_path(svg, element, width_scale, height_scale): + continue + if is_use(element): + if check_use(svg, element, width_scale, height_scale): + continue + # relative units ('%') in presentation attributes + for attr in ['width', 'height']: + self.scale_attr_val(element, attr, ['%'], 1.0 / self.factor_a) + for attr in ['x', 'y']: + self.scale_attr_val(element, attr, ['%'], 1.0 / self.factor_a) - def translateElement(self, m): - translateVal = m.group(2).replace(" ","") - total = translateVal.count(',') - if total == 1: - translateVal = translateVal.split(",") - return "matrix(" + str(self.factor_a) + ",0,0," + str(self.factor_a) + "," + str(float(translateVal[0]) * self.factor_a) + "," + str(float(translateVal[1]) * self.factor_a) + ")" - else: - return "matrix(" + str(self.factor_a) + ",0,0," + str(self.factor_a) + "," + str(float(translateVal) * self.factor_a) + "," + str(float(translateVal) * self.factor_a) + ")" - - def skewElement(self, m): - skeweVal = m.group(2).replace(" ","") - total = skewVal.count(',') - if total == 1: - skeweVal = skewVal.split(",") - return "skew(" + str(float(skewVal[0]) * self.factor_a) + "," + str(float(skewVal[1]) * self.factor_a) + ") matrix(" + str(self.factor_a) + ",0,0," + str(self.factor_a) + ",0,0)" - else: - return "skew(" + str(float(skewVal) * self.factor_a) + ") matrix(" + str(self.factor_a) + ",0,0," + str(self.factor_a) + ",0,0)" + # set preserved transforms on top-level elements + if width_scale != 1.0 and height_scale != 1.0: + mat = simpletransform.parseTransform( + 'scale({},{})'.format(width_scale, height_scale)) + simpletransform.applyTransformToNode(mat, element) - def matrixElement(self, m): - matrixVal = m.group(2).replace(" ","") - total = matrixVal.count(',') - matrixVal = matrixVal.split(",") - if total == 5: - return "matrix(" + str(float(matrixVal[0]) * self.factor_a) + "," + matrixVal[1] + "," + matrixVal[2] + "," + str(float(matrixVal[3]) * self.factor_a) + "," + str(float(matrixVal[4]) * self.factor_a) + "," + str(float(matrixVal[5]) * self.factor_a) + ")" + def scaleElement(self, m): + pass # TODO: optionally scale graphics elements only? def scaleGuides(self, svg): xpathStr = '//sodipodi:guide' @@ -255,7 +408,7 @@ class DPISwitcher(inkex.Effect): self.factor_b = 90.0/96.0 namedview = svg.find(inkex.addNS('namedview', 'sodipodi')) namedview.set(inkex.addNS('document-units', 'inkscape'), "px") - self.units = re.sub("[0-9]*\.?[0-9]", "", svg.get('width')) + self.units = self.parse_length(svg.get('width'))[1] if self.units and self.units <> "px" and self.units <> "" and self.units <> "%": if self.options.switcher == "0": self.unitExponent = 1.0/(self.factor_a/self.__uuconv[self.units]) @@ -264,5 +417,9 @@ class DPISwitcher(inkex.Effect): self.scaleRoot(svg); sys.stdout = saveout -effect = DPISwitcher() -effect.affect() + +if __name__ == '__main__': + effect = DPISwitcher() + effect.affect() + +# vim: expandtab shiftwidth=4 tabstop=8 softtabstop=4 fileencoding=utf-8 textwidth=99 diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index dee36d681..4c07c76ea 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -209,7 +209,7 @@ sp_desktop_set_style(Inkscape::ObjectSet *set, SPDesktop *desktop, SPCSSAttr *cs if (!change) return; -// 2. Emit signal... See desktop->connectStyleSet in text-tool, tweak-tool, and gradient-drag. +// 2. Emit signal... See desktop->connectSetStyle in text-tool, tweak-tool, and gradient-drag. bool intercepted = desktop->_set_style_signal.emit(css); /** \todo @@ -1045,6 +1045,7 @@ objects_query_fontnumbers (const std::vector<SPItem*> &objects, SPStyle *style_r bool lineheight_normal = false; bool lineheight_unit_proportional = false; bool lineheight_unit_absolute = false; + bool lineheight_set = false; // Set true if any object has lineheight set. double size_prev = 0; double letterspacing_prev = 0; @@ -1130,6 +1131,9 @@ objects_query_fontnumbers (const std::vector<SPItem*> &objects, SPStyle *style_r lineheight_normal = false; lineheight += lineheight_current * doc_scale; } + if (style->line_height.set) { + lineheight_set = true; + } if ((size_prev != 0 && style->font_size.computed != size_prev) || (letterspacing_prev != 0 && style->letter_spacing.computed != letterspacing_prev) || @@ -1205,6 +1209,9 @@ objects_query_fontnumbers (const std::vector<SPItem*> &objects, SPStyle *style_r } } + // Used by text toolbar unset 'line-height' + style_res->line_height.set = lineheight_set; + if (texts > 1) { if (different || different_lineheight) { return QUERY_STYLE_MULTIPLE_AVERAGED; @@ -1907,7 +1914,7 @@ sp_desktop_query_style_from_list (const std::vector<SPItem*> &list, SPStyle *sty int sp_desktop_query_style(SPDesktop *desktop, SPStyle *style, int property) { - // Used by text tool and in gradient dragging + // Used by text tool and in gradient dragging. See connectQueryStyle. int ret = desktop->_query_style_signal.emit(style, property); if (ret != QUERY_STYLE_NOTHING) diff --git a/src/file.cpp b/src/file.cpp index 55089209a..8f283e1f8 100644 --- a/src/file.cpp +++ b/src/file.cpp @@ -66,6 +66,10 @@ // For updating old Inkscape SVG files #include "display/canvas-grid.h" #include "sp-guide.h" +#include "selection-chemistry.h" +#include "persp3d.h" +#include "proj_pt.h" +#include "ui/shape-editor.h" #include <gtkmm.h> @@ -353,11 +357,13 @@ bool sp_file_open(const Glib::ustring &uri, bool need_fix_units = false; bool need_fix_guides = false; bool need_fix_grid_mm = false; - bool is_extension = false; + bool need_fix_box3d = false; + bool did_scaling = false; // Check if potentially need viewbox or unit fix switch (root->width.unit) { case SP_CSS_UNIT_PC: + case SP_CSS_UNIT_PT: case SP_CSS_UNIT_MM: case SP_CSS_UNIT_CM: case SP_CSS_UNIT_IN: @@ -366,13 +372,19 @@ bool sp_file_open(const Glib::ustring &uri, case SP_CSS_UNIT_NONE: case SP_CSS_UNIT_PX: need_fix_units = true; - default: break; + case SP_CSS_UNIT_EM: + case SP_CSS_UNIT_EX: + case SP_CSS_UNIT_PERCENT: // OK + break; + default: + std::cerr << "sp_file_open: Unhandled width unit!" << std::endl; } switch (root->height.unit) { case SP_CSS_UNIT_PC: + case SP_CSS_UNIT_PT: case SP_CSS_UNIT_MM: case SP_CSS_UNIT_CM: case SP_CSS_UNIT_IN: @@ -381,14 +393,21 @@ bool sp_file_open(const Glib::ustring &uri, case SP_CSS_UNIT_NONE: case SP_CSS_UNIT_PX: need_fix_units = true; - default: break; + case SP_CSS_UNIT_EM: + case SP_CSS_UNIT_EX: + case SP_CSS_UNIT_PERCENT: // OK + break; + default: + std::cerr << "sp_file_open: Unhandled height unit!" << std::endl; } // std::cout << "Absolute SVG units in root? " << (need_fix_viewbox?"true":"false") << std::endl; // std::cout << "User units in root? " << (need_fix_units ?"true":"false") << std::endl; + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + if (!root->viewBox_set && need_fix_viewbox) { Glib::ustring msg = _( @@ -401,31 +420,37 @@ bool sp_file_open(const Glib::ustring &uri, Gtk::Label info; info.set_markup(msg.c_str()); info.show(); - scaleDialog.get_content_area()->pack_start(info, false, false, 20); + Gtk::CheckButton backupButton( _("Create backup file (in same directory).") ); - backupButton.set_active(); + bool backup = prefs->getBool("/options/dpifixbackup", true); + backupButton.set_active( backup ); backupButton.show(); - scaleDialog.get_content_area()->pack_start(backupButton, false, false, 20); - scaleDialog.add_button("Set 'viewBox'", 1); - scaleDialog.add_button("Scale elements", 2); - scaleDialog.add_button("Ignore", 3); + + scaleDialog.add_button(_("Set 'viewBox'"), 1); + scaleDialog.add_button(_("Scale elements"), 2); + scaleDialog.add_button(_("Ignore"), 3); + scaleDialog.add_button("Scale test - group", 4); + scaleDialog.add_button("Scale test - children", 5); gint response = scaleDialog.run(); - bool backup = backupButton.get_active(); + backup = backupButton.get_active(); + prefs->setBool("/options/dpifixbackup", backup); + + if ( backup && response != 3) { + sp_file_save_backup( uri ); + } + if (response == 1) { - if (backup) { - sp_file_save_backup( uri ); - } + doc->setViewBox(Geom::Rect::from_xywh( 0, 0, doc->getWidth().value("px") * ratio, doc->getHeight().value("px") * ratio)); + } else if (response == 2 ) { - if (backup) { - sp_file_save_backup( uri ); - } + std::list<Inkscape::Extension::Effect *> effects; Inkscape::Extension::db.get_effect_list(effects); std::list<Inkscape::Extension::Effect *>::iterator it = effects.begin(); @@ -442,12 +467,65 @@ bool sp_file_open(const Glib::ustring &uri, if (!did) { std::cerr << "sp_file_open: Failed to find dpi90to96 extension." << std::endl; } - is_extension = true; + did_scaling = true; + + } else if (response == 4) { + + // Save preferences + bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive",true); + bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true); + + prefs->setBool("/options/kbselection/onlysensitive", false); + prefs->setBool("/options/kbselection/onlyvisible", false); + + Inkscape::Selection *selection = desktop->getSelection(); + Inkscape::SelectionHelper::selectAllInAll( desktop ); + selection->group(); + SPItem * group = selection->singleItem(); + if (group) { + group->setAttribute("transform","scale(1.06666667,1.06666667)"); + } else { + std::cerr << "sp_file_open: Failed to get group!" << std::endl; + } + selection->clear(); + selection->add( group ); + selection->ungroup(); + selection->clear(); + + prefs->setBool("/options/kbselection/onlysensitive", onlysensitive); + prefs->setBool("/options/kbselection/onlyvisible", onlyvisible ); + + did_scaling = true; + + } else if (response == 5) { + + // Save preferences + bool transform_stroke = prefs->getBool("/options/transform/stroke", true); + bool transform_rectcorners = prefs->getBool("/options/transform/rectcorners", true); + bool transform_pattern = prefs->getBool("/options/transform/pattern", true); + bool transform_gradient = prefs->getBool("/options/transform/gradient", true); + + prefs->setBool("/options/transform/stroke", true); + prefs->setBool("/options/transform/rectcorners", true); + prefs->setBool("/options/transform/pattern", true); + prefs->setBool("/options/transform/gradient", true); + + Inkscape::UI::ShapeEditor::blockSetItem(true); + doc->getRoot()->scaleChildItemsRec(Geom::Scale(1/ratio),Geom::Point(0, 0), false); + Inkscape::UI::ShapeEditor::blockSetItem(false); + + // Restore preferences + prefs->setBool("/options/transform/stroke", transform_stroke); + prefs->setBool("/options/transform/rectcorners", transform_rectcorners); + prefs->setBool("/options/transform/pattern", transform_pattern); + prefs->setBool("/options/transform/gradient", transform_gradient); } + + need_fix_box3d = true; need_fix_guides = true; // Always fix guides } - if (need_fix_units) { + else if (need_fix_units) { Glib::ustring msg = ( "Old Inkscape files use 1in == 90px. CSS requires 1in == 96px.\n" "Drawings meant to match a physical size (e.g. Letter or A4)\n" @@ -462,19 +540,27 @@ bool sp_file_open(const Glib::ustring &uri, scaleDialog.get_content_area()->pack_start(info, false, false, 20); Gtk::CheckButton backupButton( _("Create backup file (in same directory).") ); - scaleDialog.get_content_area()->pack_start(backupButton, false, false, 20); + bool backup = prefs->getBool("/options/dpifixbackup", true); + backupButton.set_active( backup ); backupButton.show(); + scaleDialog.get_content_area()->pack_start(backupButton, false, false, 20); - scaleDialog.add_button("Set 'viewBox'", 1); - scaleDialog.add_button("Scale elements", 2); - scaleDialog.add_button("Ignore", 3); + scaleDialog.add_button(_("Set 'viewBox'"), 1); + scaleDialog.add_button(_("Scale elements"), 2); + scaleDialog.add_button(_("Ignore"), 3); + scaleDialog.add_button("Scale test - group", 4); + scaleDialog.add_button("Scale test - children", 5); gint response = scaleDialog.run(); - bool backup = backupButton.get_active(); + backup = backupButton.get_active(); + prefs->setBool("/options/dpifixbackup", backup); + + if ( backup && response != 3) { + sp_file_save_backup( uri ); + } + if (response == 1) { - if (backup) { - sp_file_save_backup( uri ); - } + if (!root->viewBox_set) { doc->setViewBox(Geom::Rect::from_xywh( 0, 0, @@ -488,10 +574,10 @@ bool sp_file_open(const Glib::ustring &uri, doc->setWidthAndHeight( width, height, false ); need_fix_guides = true; // Only fix guides if drawing scaled + need_fix_box3d = true; + } else if (response == 2) { - if (backup) { - sp_file_save_backup( uri ); - } + std::list<Inkscape::Extension::Effect *> effects; Inkscape::Extension::db.get_effect_list(effects); std::list<Inkscape::Extension::Effect *>::iterator it = effects.begin(); @@ -509,14 +595,94 @@ bool sp_file_open(const Glib::ustring &uri, std::cerr << "sp_file_open: Failed to find dpi90to96 extension." << std::endl; } need_fix_guides = true; // Only fix guides if drawing scaled - is_extension = true; + did_scaling = true; + + } else if (response == 4) { + + Inkscape::Util::Quantity width = + Inkscape::Util::Quantity(doc->getWidth().value("px")/ratio, "px" ); + Inkscape::Util::Quantity height = + Inkscape::Util::Quantity(doc->getHeight().value("px")/ratio,"px" ); + doc->setWidthAndHeight( width, height, false ); + + if (!root->viewBox_set) { + + // Save preferences + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool onlysensitive = prefs->getBool("/options/kbselection/onlysensitive",true); + bool onlyvisible = prefs->getBool("/options/kbselection/onlyvisible", true); + + prefs->setBool("/options/kbselection/onlysensitive", false); + prefs->setBool("/options/kbselection/onlyvisible", false); + + Inkscape::Selection *selection = desktop->getSelection(); + Inkscape::SelectionHelper::selectAllInAll( desktop ); + selection->group(); + SPItem * group = selection->singleItem(); + if (group) { + group->setAttribute("transform","scale(1.06666667,1.06666667)"); + } else { + std::cerr << "sp_file_open: Failed to get group!" << std::endl; + } + selection->clear(); + selection->add( group ); + selection->ungroup(); + selection->clear(); + + prefs->setBool("/options/kbselection/onlysensitive", onlysensitive); + prefs->setBool("/options/kbselection/onlyvisible", onlyvisible ); + + did_scaling = true; + } + + need_fix_box3d = true; + need_fix_guides = true; // Only fix guides if drawing scaled + + } else if (response == 5) { + + Inkscape::Util::Quantity width = + Inkscape::Util::Quantity(doc->getWidth().value("px")/ratio, "px" ); + Inkscape::Util::Quantity height = + Inkscape::Util::Quantity(doc->getHeight().value("px")/ratio,"px" ); + doc->setWidthAndHeight( width, height, false ); + + if (!root->viewBox_set) { + + // Save preferences + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + bool transform_stroke = prefs->getBool("/options/transform/stroke", true); + bool transform_rectcorners = prefs->getBool("/options/transform/rectcorners", true); + bool transform_pattern = prefs->getBool("/options/transform/pattern", true); + bool transform_gradient = prefs->getBool("/options/transform/gradient", true); + + prefs->setBool("/options/transform/stroke", true); + prefs->setBool("/options/transform/rectcorners", true); + prefs->setBool("/options/transform/pattern", true); + prefs->setBool("/options/transform/gradient", true); + + Inkscape::UI::ShapeEditor::blockSetItem(true); + doc->getRoot()->scaleChildItemsRec(Geom::Scale(1/ratio),Geom::Point(0, 0), false); + Inkscape::UI::ShapeEditor::blockSetItem(false); + + // Restore preferences + prefs->setBool("/options/transform/stroke", transform_stroke); + prefs->setBool("/options/transform/rectcorners", transform_rectcorners); + prefs->setBool("/options/transform/pattern", transform_pattern); + prefs->setBool("/options/transform/gradient", transform_gradient); + + did_scaling = true; + } + + need_fix_box3d = true; + need_fix_guides = true; // Only fix guides if drawing scaled + } else { // Ignore need_fix_grid_mm = true; } } - // Fix guides and grids + // Fix guides and grids and perspective for (SPObject *child = root->firstChild() ; child; child = child->getNext() ) { SPNamedView *nv = dynamic_cast<SPNamedView *>(child); if (nv) { @@ -555,21 +721,53 @@ bool sp_file_open(const Glib::ustring &uri, } } else { if (need_fix_guides) { - // HACK: Scaling the document does not seem to cause - // grids defined in document units to be updated. - // This forces an update. - if(is_extension){ + if(did_scaling){ xy->Scale( Geom::Scale(ratio,ratio).inverse() ); } else { + // HACK: Scaling the document does not seem to cause + // grids defined in document units to be updated. + // This forces an update. xy->Scale( Geom::Scale(1,1) ); } } } } } + } // If SPNamedView + + SPDefs *defs = dynamic_cast<SPDefs *>(child); + if (defs && need_fix_box3d) { + for (SPObject *child = defs->firstChild() ; child; child = child->getNext() ) { + Persp3D* persp3d = dynamic_cast<Persp3D *>(child); + if (persp3d) { + std::vector<Glib::ustring> tokens; + + const gchar* vp_x = persp3d->getAttribute("inkscape:vp_x"); + const gchar* vp_y = persp3d->getAttribute("inkscape:vp_y"); + const gchar* vp_z = persp3d->getAttribute("inkscape:vp_z"); + const gchar* vp_o = persp3d->getAttribute("inkscape:persp3d-origin"); + // std::cout << "Found Persp3d: " + // << " vp_x: " << vp_x + // << " vp_y: " << vp_y + // << " vp_z: " << vp_z << std::endl; + Proj::Pt2 pt_x (vp_x); + Proj::Pt2 pt_y (vp_y); + Proj::Pt2 pt_z (vp_z); + Proj::Pt2 pt_o (vp_o); + pt_x = pt_x * (1.0/ratio); + pt_y = pt_y * (1.0/ratio); + pt_z = pt_z * (1.0/ratio); + pt_o = pt_o * (1.0/ratio); + persp3d->setAttribute("inkscape:vp_x",pt_x.coord_string()); + persp3d->setAttribute("inkscape:vp_y",pt_y.coord_string()); + persp3d->setAttribute("inkscape:vp_z",pt_z.coord_string()); + persp3d->setAttribute("inkscape:persp3d-origin",pt_o.coord_string()); + } + } } - } // Look for SPNamedView loop + } // Look for SPNamedView and SPDefs loop + // desktop->getDocument()->ensureUpToDate(); // Does not update box3d! DocumentUndo::done(desktop->getDocument(), SP_VERB_NONE, _("Update Document")); } // If old Inkscape version diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index 96dcdbe30..7b2507b5e 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -584,12 +584,13 @@ sp_item_group_ungroup (SPGroup *group, std::vector<SPItem*> &children, bool do_d SPText * text = dynamic_cast<SPText *>(citem); if (text) { //this causes a change in text-on-path appearance when there is a non-conformal transform, see bug #1594565 - double scale = (ctrans.expansionX() + ctrans.expansionY()) / 2.0; SPTextPath * text_path = dynamic_cast<SPTextPath *>(text->firstChild()); if (!text_path) { nrepr->setAttribute("transform", affinestr); } else { - sp_recursive_scale_text_size(nrepr, scale); + // The following breaks roundtripping group -> ungroup + // double scale = (ctrans.expansionX() + ctrans.expansionY()) / 2.0; + // sp_recursive_scale_text_size(nrepr, scale); Geom::Affine ttrans = ctrans.inverse() * SP_ITEM(text)->transform * ctrans; gchar *affinestr = sp_svg_transform_write(ttrans); nrepr->setAttribute("transform", affinestr); diff --git a/src/sp-mesh-array.cpp b/src/sp-mesh-array.cpp index b522d577b..f192d0e44 100644 --- a/src/sp-mesh-array.cpp +++ b/src/sp-mesh-array.cpp @@ -1198,7 +1198,7 @@ void SPMeshNodeArray::create( SPMeshGradient *mg, SPItem *item, Geom::OptRect bb ry = arc->ry.computed; start = arc->start; end = arc->end; - if( end == start ) { + if( end <= start ) { end += 2.0 * M_PI; } } diff --git a/src/ui/tools/tweak-tool.cpp b/src/ui/tools/tweak-tool.cpp index 56939cc30..ff5d623c2 100644 --- a/src/ui/tools/tweak-tool.cpp +++ b/src/ui/tools/tweak-tool.cpp @@ -1084,7 +1084,8 @@ sp_tweak_dilate (TweakTool *tc, Geom::Point event_p, Geom::Point p, Geom::Point double move_force = get_move_force(tc); double color_force = MIN(sqrt(path_force)/20.0, 1); - auto items= selection->items(); +// auto items= selection->items(); + std::vector<SPItem*> items(selection->items().begin(), selection->items().end()); for(auto i=items.begin();i!=items.end(); ++i){ SPItem *item = *i; diff --git a/src/widgets/text-toolbar.cpp b/src/widgets/text-toolbar.cpp index 847ebd8c1..784c467f1 100644 --- a/src/widgets/text-toolbar.cpp +++ b/src/widgets/text-toolbar.cpp @@ -239,7 +239,7 @@ static void sp_text_fontsize_value_changed( Ink_ComboBoxEntry_Action *act, GObje if (dynamic_cast<SPText *>(*i) || dynamic_cast<SPFlowtext *>(*i)) { SPItem *item = *i; - // Scale by inverse of accumulated paraent transform + // Scale by inverse of accumulated parent transform SPCSSAttr *css_set = sp_repr_css_attr_new(); sp_repr_css_merge(css_set, css); Geom::Affine const local(item->i2doc_affine()); @@ -321,6 +321,29 @@ static void sp_text_outer_style_changed( InkToggleAction*act, GObject *tbl ) sp_text_toolbox_selection_changed( NULL, tbl ); } +// Unset line height on selection's inner text objects (tspan, etc.). +static void sp_text_lineheight_unset_changed( InkToggleAction*act, GObject *tbl ) +{ + // quit if run by the _changed callbacks + if (g_object_get_data(G_OBJECT(tbl), "freeze")) { + return; + } + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(TRUE) ); + + SPCSSAttr *css = sp_repr_css_attr_new(); + sp_repr_css_unset_property(css, "line-height"); + + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + sp_desktop_set_style (desktop, css); + + sp_repr_css_attr_unref(css); + + DocumentUndo::done(desktop->getDocument(), SP_VERB_CONTEXT_TEXT, + _("Text: Unset line height.")); + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + // Handles both Superscripts and Subscripts static void sp_text_script_changed( InkToggleAction* act, GObject *tbl ) { @@ -599,7 +622,7 @@ static void sp_text_lineheight_value_changed( GtkAdjustment *adj, GObject *tbl ) if (dynamic_cast<SPText *>(*i) || dynamic_cast<SPFlowtext *>(*i)) { SPItem *item = *i; - // Scale by inverse of accumulated paraent transform + // Scale by inverse of accumulated parent transform SPCSSAttr *css_set = sp_repr_css_attr_new(); sp_repr_css_merge(css_set, css); Geom::Affine const local(item->i2doc_affine()); @@ -1405,7 +1428,13 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/ } // Save unit so we can do convertions between new/old units. g_object_set_data( tbl, "lineheight_unit", GINT_TO_POINTER(line_height_unit)); - + + // Enable and turn on only if selection includes an object with line height set. + InkToggleAction* lineHeightUnset = + INK_TOGGLE_ACTION( g_object_get_data( tbl, "TextLineHeightUnsetAction")); + gtk_action_set_sensitive(GTK_ACTION(lineHeightUnset), query.line_height.set ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(lineHeightUnset), query.line_height.set ); + // Word spacing double wordSpacing; if (query.word_spacing.normal) wordSpacing = 0.0; @@ -2100,6 +2129,19 @@ void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObje g_object_set( G_OBJECT(eact), "iconId", "text_rotation", NULL ); } + /* Text line height unset */ + { + InkToggleAction* act = ink_toggle_action_new( "TextLineHeightUnsetAction", // Name + _("Unset line height"), // Label + _("If enabled, line height is set on part of selection. Click to unset."), + INKSCAPE_ICON("paint-unknown"), + secondarySize ); // Icon size + gtk_action_group_add_action( mainActions, GTK_ACTION( act ) ); + g_signal_connect_after( G_OBJECT(act), "toggled", G_CALLBACK(sp_text_lineheight_unset_changed), holder ); + gtk_toggle_action_set_active( GTK_TOGGLE_ACTION(act), prefs->getBool("/tools/text/line_height_unset", false) ); + g_object_set_data( holder, "TextLineHeightUnsetAction", act ); + } + /* Text outer style */ { InkToggleAction* act = ink_toggle_action_new( "TextOuterStyleAction", // Name diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp index 1f6cb136c..a3db3c33d 100644 --- a/src/widgets/toolbox.cpp +++ b/src/widgets/toolbox.cpp @@ -514,6 +514,7 @@ static gchar const * ui_descr = " <toolitem action='TextFontSizeAction' />" " <toolitem action='TextLineHeightAction' />" " <toolitem action='TextLineHeightUnitsAction' />" + " <toolitem action='TextLineHeightUnsetAction' />" " <separator />" " <toolitem action='TextAlignAction' />" " <separator />" |
