diff options
| author | Jabier Arraiza Cenoz <jabier.arraiza@marker.es> | 2016-04-08 13:47:33 +0000 |
|---|---|---|
| committer | jabiertxof <info@marker.es> | 2016-04-08 13:47:33 +0000 |
| commit | 1106ff9eeb561af9216563e3eb7422088fac4cf5 (patch) | |
| tree | 8dc88ec1211b985e18c86835196d45e124d8cfe4 /src | |
| parent | update to trunk (diff) | |
| parent | Bug #1552765 fixed Break Apart dont handle well stroke with in documents diff... (diff) | |
| download | inkscape-1106ff9eeb561af9216563e3eb7422088fac4cf5.tar.gz inkscape-1106ff9eeb561af9216563e3eb7422088fac4cf5.zip | |
update to trunk
(bzr r13645.1.125)
Diffstat (limited to 'src')
48 files changed, 1088 insertions, 644 deletions
diff --git a/src/2geom/sbasis-to-bezier.cpp b/src/2geom/sbasis-to-bezier.cpp index 8a18cfd4a..64c07f35e 100644 --- a/src/2geom/sbasis-to-bezier.cpp +++ b/src/2geom/sbasis-to-bezier.cpp @@ -197,6 +197,8 @@ void sbasis_to_cubic_bezier (std::vector<Point> & bz, D2<SBasis> const& sb) } sbasis_to_bezier(bz, sb, 4); // zeroth-order estimate + if ((sb[X].size() < 3) && (sb[Y].size() < 3)) + return; // cubic bezier estimate is exact Geom::ConvexHull bezhull(bz); // calculate first derivatives of x and y wrt t diff --git a/src/desktop-style.cpp b/src/desktop-style.cpp index d10c75cd8..7f9b46c7d 100644 --- a/src/desktop-style.cpp +++ b/src/desktop-style.cpp @@ -1036,20 +1036,24 @@ int objects_query_fontnumbers (const std::vector<SPItem*> &objects, SPStyle *style_res) { bool different = false; + bool different_lineheight = false; + bool different_lineheight_unit = false; double size = 0; double letterspacing = 0; double wordspacing = 0; - double linespacing = 0; + double lineheight = 0; bool letterspacing_normal = false; bool wordspacing_normal = false; - bool linespacing_normal = false; + bool lineheight_normal = false; + bool lineheight_unit_proportional = false; + bool lineheight_unit_absolute = false; double size_prev = 0; double letterspacing_prev = 0; double wordspacing_prev = 0; - double linespacing_prev = 0; - int linespacing_unit = 0; + double lineheight_prev = 0; + int lineheight_unit_prev = -1; int texts = 0; int no_size = 0; @@ -1069,7 +1073,12 @@ objects_query_fontnumbers (const std::vector<SPItem*> &objects, SPStyle *style_r texts ++; SPItem *item = dynamic_cast<SPItem *>(obj); g_assert(item != NULL); - double dummy = style->font_size.computed * Geom::Affine(item->i2dt_affine()).descrim(); + + // Quick way of getting document scale. Should be same as: + // item->document->getDocumentScale().Affine().descrim() + double doc_scale = Geom::Affine(item->i2dt_affine()).descrim(); + + double dummy = style->font_size.computed * doc_scale; if (!IS_NAN(dummy)) { size += dummy; /// \todo FIXME: we assume non-% units here } else { @@ -1081,7 +1090,7 @@ objects_query_fontnumbers (const std::vector<SPItem*> &objects, SPStyle *style_r letterspacing_normal = true; } } else { - letterspacing += style->letter_spacing.computed * Geom::Affine(item->i2dt_affine()).descrim(); /// \todo FIXME: we assume non-% units here + letterspacing += style->letter_spacing.computed * doc_scale;; /// \todo FIXME: we assume non-% units here letterspacing_normal = false; } @@ -1090,40 +1099,60 @@ objects_query_fontnumbers (const std::vector<SPItem*> &objects, SPStyle *style_r wordspacing_normal = true; } } else { - wordspacing += style->word_spacing.computed * Geom::Affine(item->i2dt_affine()).descrim(); /// \todo FIXME: we assume non-% units here + wordspacing += style->word_spacing.computed * doc_scale; /// \todo FIXME: we assume non-% units here wordspacing_normal = false; } - double linespacing_current; + // If all line spacing units the same, use that (average line spacing). + // Else if all line spacings absolute, use 'px' (average line spacing). + // Else if all line spacings proportional, use % (average line spacing). + // Else use default. + double lineheight_current; + int lineheight_unit_current; if (style->line_height.normal) { - linespacing_current = Inkscape::Text::Layout::LINE_HEIGHT_NORMAL; - if (!different && (linespacing_prev == 0 || linespacing_prev == linespacing_current)) - linespacing_normal = true; - } else if (style->line_height.unit == SP_CSS_UNIT_PERCENT || style->font_size.computed == 0) { - linespacing_current = style->line_height.value; - linespacing_normal = false; + lineheight_current = Inkscape::Text::Layout::LINE_HEIGHT_NORMAL; + lineheight_unit_current = SP_CSS_UNIT_NONE; + if (!different_lineheight && + (lineheight_prev == 0 || lineheight_prev == lineheight_current)) + lineheight_normal = true; + } else if (style->line_height.unit == SP_CSS_UNIT_NONE || + style->line_height.unit == SP_CSS_UNIT_PERCENT || + style->line_height.unit == SP_CSS_UNIT_EM || + style->line_height.unit == SP_CSS_UNIT_EX || + style->font_size.computed == 0) { + lineheight_current = style->line_height.value; + lineheight_unit_current = style->line_height.unit; + lineheight_unit_proportional = true; + lineheight_normal = false; + lineheight += lineheight_current; } else { - linespacing_current = style->line_height.computed; - linespacing_normal = false; + // Always 'px' internally + lineheight_current = style->line_height.computed; + lineheight_unit_current = style->line_height.unit; + lineheight_unit_absolute = true; + lineheight_normal = false; + lineheight += lineheight_current * doc_scale; } - if (linespacing_unit == 0) { - linespacing_unit = style->line_height.unit; - } else if (linespacing_unit != style->line_height.unit) { - linespacing_unit = SP_CSS_UNIT_PERCENT; - } - linespacing += linespacing_current; if ((size_prev != 0 && style->font_size.computed != size_prev) || (letterspacing_prev != 0 && style->letter_spacing.computed != letterspacing_prev) || - (wordspacing_prev != 0 && style->word_spacing.computed != wordspacing_prev) || - (linespacing_prev != 0 && linespacing_current != linespacing_prev)) { + (wordspacing_prev != 0 && style->word_spacing.computed != wordspacing_prev)) { different = true; } + if (lineheight_prev != 0 && lineheight_current != lineheight_prev) { + different_lineheight = true; + } + + if (lineheight_unit_prev != -1 && lineheight_unit_current != lineheight_unit_prev) { + different_lineheight_unit = true; + } + size_prev = style->font_size.computed; letterspacing_prev = style->letter_spacing.computed; wordspacing_prev = style->word_spacing.computed; - linespacing_prev = linespacing_current; + lineheight_prev = lineheight_current; + lineheight_unit_prev = lineheight_unit_current; // FIXME: we must detect MULTIPLE_DIFFERENT for these too style_res->text_anchor.computed = style->text_anchor.computed; @@ -1139,7 +1168,7 @@ objects_query_fontnumbers (const std::vector<SPItem*> &objects, SPStyle *style_r } letterspacing /= texts; wordspacing /= texts; - linespacing /= texts; + lineheight /= texts; } style_res->font_size.computed = size; @@ -1151,13 +1180,36 @@ objects_query_fontnumbers (const std::vector<SPItem*> &objects, SPStyle *style_r style_res->word_spacing.normal = wordspacing_normal; style_res->word_spacing.computed = wordspacing; - style_res->line_height.normal = linespacing_normal; - style_res->line_height.computed = linespacing; - style_res->line_height.value = linespacing; - style_res->line_height.unit = linespacing_unit; + style_res->line_height.normal = lineheight_normal; + style_res->line_height.computed = lineheight; + style_res->line_height.value = lineheight; + if (different_lineheight_unit) { + if (lineheight_unit_absolute && !lineheight_unit_proportional) { + // Mixture of absolute units + style_res->line_height.unit = SP_CSS_UNIT_PX; + } else { + // Mixture of relative units + style_res->line_height.unit = SP_CSS_UNIT_PERCENT; + } + if (lineheight_unit_absolute && lineheight_unit_proportional) { + // Mixed types of units, fallback to default + style_res->line_height.computed = Inkscape::Text::Layout::LINE_HEIGHT_NORMAL * 100.0; + style_res->line_height.value = Inkscape::Text::Layout::LINE_HEIGHT_NORMAL * 100.0; + } + } else { + // Same units. + if (lineheight_unit_prev != -1) { + style_res->line_height.unit = lineheight_unit_prev; + } else { + // No text object... use default. + style_res->line_height.unit = SP_CSS_UNIT_NONE; + style_res->line_height.computed = Inkscape::Text::Layout::LINE_HEIGHT_NORMAL; + style_res->line_height.value = Inkscape::Text::Layout::LINE_HEIGHT_NORMAL; + } + } if (texts > 1) { - if (different) { + if (different || different_lineheight) { return QUERY_STYLE_MULTIPLE_AVERAGED; } else { return QUERY_STYLE_MULTIPLE_SAME; diff --git a/src/display/drawing-text.cpp b/src/display/drawing-text.cpp index a3ca7173a..f0d83abfd 100644 --- a/src/display/drawing-text.cpp +++ b/src/display/drawing-text.cpp @@ -100,14 +100,16 @@ unsigned DrawingGlyphs::_updateItem(Geom::IntRect const &/*area*/, UpdateContext above and below the max/min y positions of the letters to place the text decorations.*/ Geom::Rect b; - if(_drawable){ - Geom::OptRect tiltb = bounds_exact(*_font->PathVector(_glyph)); - Geom::Rect bigbox(Geom::Point(tiltb->left(),-_dsc*scale_bigbox*1.1),Geom::Point(tiltb->right(),_asc*scale_bigbox*1.1)); - b = bigbox * ctx.ctm; + if (_drawable) { + Geom::OptRect tiltb = bounds_exact(*_font->PathVector(_glyph)); + if (tiltb) { + Geom::Rect bigbox(Geom::Point(tiltb->left(),-_dsc*scale_bigbox*1.1),Geom::Point(tiltb->right(),_asc*scale_bigbox*1.1)); + b = bigbox * ctx.ctm; + } } - else { // Fallback, spaces mostly - Geom::Rect bigbox(Geom::Point(0.0, -_dsc*scale_bigbox*1.1),Geom::Point(_width*scale_bigbox, _asc*scale_bigbox*1.1)); - b = bigbox * ctx.ctm; + if (b.hasZeroArea()) { // Fallback, spaces mostly + Geom::Rect bigbox(Geom::Point(0.0, -_dsc*scale_bigbox*1.1),Geom::Point(_width*scale_bigbox, _asc*scale_bigbox*1.1)); + b = bigbox * ctx.ctm; } /* diff --git a/src/display/sp-canvas-item.h b/src/display/sp-canvas-item.h index 66cd03dd9..00edb4dee 100644 --- a/src/display/sp-canvas-item.h +++ b/src/display/sp-canvas-item.h @@ -62,6 +62,7 @@ struct SPCanvasItem { Geom::Rect bounds; Geom::Affine xform; + int ctrlResize; Inkscape::ControlType ctrlType; Inkscape::ControlFlags ctrlFlags; diff --git a/src/display/sp-canvas.cpp b/src/display/sp-canvas.cpp index d17271752..81ea7d142 100644 --- a/src/display/sp-canvas.cpp +++ b/src/display/sp-canvas.cpp @@ -360,6 +360,7 @@ static void sp_canvas_item_init(SPCanvasItem *item) { item->xform = Geom::Affine(Geom::identity()); + item->ctrlResize = 0; item->ctrlType = Inkscape::CTRL_TYPE_UNKNOWN; item->ctrlFlags = Inkscape::CTRL_FLAG_NORMAL; diff --git a/src/extension/dbus/document-interface.cpp b/src/extension/dbus/document-interface.cpp index d64bdbc5c..121a49a25 100644 --- a/src/extension/dbus/document-interface.cpp +++ b/src/extension/dbus/document-interface.cpp @@ -1,7 +1,7 @@ /* * This is where the implementation of the DBus based document API lives. * All the methods in here (except in the helper section) are - * designed to be called remotly via DBus. application-interface.cpp + * designed to be called remotely via DBus. application-interface.cpp * has the methods used to connect to the bus and get a document instance. * * Documentation for these methods is in document-interface.xml diff --git a/src/extension/implementation/implementation.h b/src/extension/implementation/implementation.h index f6f933aaf..1232ae0c8 100644 --- a/src/extension/implementation/implementation.h +++ b/src/extension/implementation/implementation.h @@ -18,7 +18,7 @@ #include <2geom/forward.h> namespace Gtk { - class Widget; + class Widget; } class SPDocument; @@ -33,7 +33,7 @@ class View; } // namespace UI namespace XML { - class Node; + class Node; } // namespace XML namespace Extension { @@ -51,18 +51,18 @@ namespace Implementation { */ class ImplementationDocumentCache { - /** + /** * The document that this instance is working on. */ - Inkscape::UI::View::View * _view; + Inkscape::UI::View::View * _view; public: - ImplementationDocumentCache (Inkscape::UI::View::View * view) : - _view(view) - { - return; - }; - virtual ~ImplementationDocumentCache ( ) { return; }; - Inkscape::UI::View::View const * view ( ) { return _view; }; + ImplementationDocumentCache (Inkscape::UI::View::View * view) : + _view(view) + { + return; + }; + virtual ~ImplementationDocumentCache ( ) { return; }; + Inkscape::UI::View::View const * view ( ) { return _view; }; }; /** @@ -116,7 +116,7 @@ public: // ----- Effect functions ----- /** Find out information about the file. */ virtual Gtk::Widget * prefs_effect(Inkscape::Extension::Effect *module, - Inkscape::UI::View::View *view, + Inkscape::UI::View::View *view, sigc::signal<void> *changeSignal, ImplementationDocumentCache *docCache); virtual void effect(Inkscape::Extension::Effect * /*module*/, diff --git a/src/extension/implementation/script.cpp b/src/extension/implementation/script.cpp index 4cb0c9b73..9aaf4b952 100644 --- a/src/extension/implementation/script.cpp +++ b/src/extension/implementation/script.cpp @@ -152,7 +152,7 @@ Script::Script() : } /** - * brief Destructor + * \brief Destructor */ Script::~Script() { @@ -232,11 +232,7 @@ bool Script::check_existence(const std::string &command) //Don't search when it is an absolute path. */ if (Glib::path_is_absolute(command)) { - if (Glib::file_test(command, Glib::FILE_TEST_EXISTS)) { - return true; - } else { - return false; - } + return Glib::file_test(command, Glib::FILE_TEST_EXISTS); } // First search in the current directory @@ -280,9 +276,9 @@ bool Script::check_existence(const std::string &command) /** \return none - \brief This function 'loads' an extention, basically it determines - the full command for the extention and stores that. - \param module The extention to be loaded. + \brief This function 'loads' an extension, basically it determines + the full command for the extension and stores that. + \param module The extension to be loaded. The most difficult part about this function is finding the actual command through all of the Reprs. Basically it is hidden down a @@ -292,7 +288,7 @@ bool Script::check_existence(const std::string &command) At that point all of the loops are exited, and there is an if statement to make sure they didn't exit because of not finding - the command. If that's the case, the extention doesn't get loaded + the command. If that's the case, the extension doesn't get loaded and should error out at a higher level. */ @@ -545,17 +541,17 @@ SPDocument *Script::open(Inkscape::Extension::Input *module, /** \return none - \brief This function uses an extention to save a document. It first + \brief This function uses an extension to save a document. It first creates an SVG file of the document, and then runs it through the script. - \param module Extention to be used + \param module Extension to be used \param doc Document to be saved \param filename The name to save the final file as \return false in case of any failure writing the file, otherwise true Well, at some point people need to save - it is really what makes the entire application useful. And, it is possible that someone - would want to use an extetion for this, so we need a function to + would want to use an extension for this, so we need a function to do that eh? First things first, the document is saved to a temporary file that @@ -563,7 +559,7 @@ SPDocument *Script::open(Inkscape::Extension::Input *module, ink_ext_ as a prefix. Don't worry, this file gets deleted at the end of the function. - After we have the SVG file, then extention_execute is called with + After we have the SVG file, then Script::execute is called with the temporary file name and the final output filename. This should put the output of the script into the final output file. We then delete the temporary file. @@ -1123,7 +1119,45 @@ int Script::execute (const std::list<std::string> &in_command, } +void Script::file_listener::init(int fd, Glib::RefPtr<Glib::MainLoop> main) { + _channel = Glib::IOChannel::create_from_fd(fd); + _channel->set_encoding(); + _conn = main->get_context()->signal_io().connect(sigc::mem_fun(*this, &file_listener::read), _channel, Glib::IO_IN | Glib::IO_HUP | Glib::IO_ERR); + _main_loop = main; + + return; +} +bool Script::file_listener::read(Glib::IOCondition condition) { + if (condition != Glib::IO_IN) { + _main_loop->quit(); + return false; + } + + Glib::IOStatus status; + Glib::ustring out; + status = _channel->read_line(out); + _string += out; + + if (status != Glib::IO_STATUS_NORMAL) { + _main_loop->quit(); + _dead = true; + return false; + } + + return true; +} + +bool Script::file_listener::toFile(const Glib::ustring &name) { + try { + Glib::RefPtr<Glib::IOChannel> stdout_file = Glib::IOChannel::create_from_file(name, "w"); + stdout_file->set_encoding(); + stdout_file->write(_string); + } catch (Glib::FileError &e) { + return false; + } + return true; +} } // namespace Implementation } // namespace Extension diff --git a/src/extension/implementation/script.h b/src/extension/implementation/script.h index 4cf33c989..684719895 100644 --- a/src/extension/implementation/script.h +++ b/src/extension/implementation/script.h @@ -85,49 +85,10 @@ private: }; bool isDead () { return _dead; } - - // TODO move these definitions into script.cpp - void init (int fd, Glib::RefPtr<Glib::MainLoop> main) { - _channel = Glib::IOChannel::create_from_fd(fd); - _channel->set_encoding(); - _conn = main->get_context()->signal_io().connect(sigc::mem_fun(*this, &file_listener::read), _channel, Glib::IO_IN | Glib::IO_HUP | Glib::IO_ERR); - _main_loop = main; - - return; - }; - - bool read (Glib::IOCondition condition) { - if (condition != Glib::IO_IN) { - _main_loop->quit(); - return false; - } - - Glib::IOStatus status; - Glib::ustring out; - status = _channel->read_line(out); - _string += out; - - if (status != Glib::IO_STATUS_NORMAL) { - _main_loop->quit(); - _dead = true; - return false; - } - - return true; - }; - + void init(int fd, Glib::RefPtr<Glib::MainLoop> main); + bool read(Glib::IOCondition condition); Glib::ustring string (void) { return _string; }; - - bool toFile (const Glib::ustring &name) { - try { - Glib::RefPtr<Glib::IOChannel> stdout_file = Glib::IOChannel::create_from_file(name, "w"); - stdout_file->set_encoding(); - stdout_file->write(_string); - } catch (Glib::FileError &e) { - return false; - } - return true; - }; + bool toFile(const Glib::ustring &name); }; int execute (const std::list<std::string> &in_command, diff --git a/src/extension/init.cpp b/src/extension/init.cpp index c16a5a899..af7af2cb1 100644 --- a/src/extension/init.cpp +++ b/src/extension/init.cpp @@ -1,6 +1,6 @@ /* * This is what gets executed to initialize all of the modules. For - * the internal modules this invovles executing their initialization + * the internal modules this involves executing their initialization * functions, for external ones it involves reading their .spmodule * files and bringing them into Sodipodi. * diff --git a/src/extension/internal/cdr-input.cpp b/src/extension/internal/cdr-input.cpp index f4789a08f..a26af2078 100644 --- a/src/extension/internal/cdr-input.cpp +++ b/src/extension/internal/cdr-input.cpp @@ -41,28 +41,18 @@ #endif #include <gtkmm/alignment.h> -#include <gtkmm/comboboxtext.h> -#include <gtkmm/drawingarea.h> -#include <gtkmm/frame.h> -#include <gtkmm/scale.h> +#include <gtkmm/spinbutton.h> #include "extension/system.h" #include "extension/input.h" -#include "document.h" +#include "document.h" #include "document-private.h" -#include "document-undo.h" #include "inkscape.h" #include "ui/dialog-events.h" -#include <gtk/gtk.h> -#include "ui/widget/spinbutton.h" -#include "ui/widget/frame.h" #include <glibmm/i18n.h> -#include <gdkmm/general.h> - -#include "svg-view.h" #include "svg-view-widget.h" #include "util/units.h" @@ -82,108 +72,99 @@ public: void getImportSettings(Inkscape::XML::Node *prefs); private: - void _setPreviewPage(unsigned page); + void _setPreviewPage(); // Signal handlers -#if !WITH_GTKMM_3_0 - bool _onExposePreview(GdkEventExpose *event); -#endif - void _onPageNumberChanged(); + void _onSpinButtonPress(GdkEventButton* button_event); + void _onSpinButtonRelease(GdkEventButton* button_event); + class Gtk::VBox * vbox1; + class Gtk::Widget * _previewArea; class Gtk::Button * cancelbutton; class Gtk::Button * okbutton; class Gtk::Label * _labelSelect; - class Inkscape::UI::Widget::SpinButton * _pageNumberSpin; class Gtk::Label * _labelTotalPages; - class Gtk::VBox * vbox1; - class Gtk::VBox * vbox2; - class Gtk::Widget * _previewArea; + class Gtk::SpinButton * _pageNumberSpin; - const std::vector<RVNGString> &_vec; // Document to be imported - unsigned _current_page; // Current selected page - int _preview_width, _preview_height; // Size of the preview area + const std::vector<RVNGString> &_vec; // Document to be imported + unsigned _current_page; // Current selected page + bool _spinning; // whether SpinButton is pressed (i.e. we're "spinning") }; CdrImportDialog::CdrImportDialog(const std::vector<RVNGString> &vec) - : _vec(vec), _current_page(1) + : _vec(vec), _current_page(1), _spinning(false) { int num_pages = _vec.size(); if ( num_pages <= 1 ) return; - cancelbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-cancel"))); - okbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-ok"))); - _labelSelect = Gtk::manage(new class Gtk::Label(_("Select page:"))); - // Page number + // Dialog settings + this->set_title(_("Page Selector")); + this->set_modal(true); + sp_transientize(GTK_WIDGET(this->gobj())); //Make transient + this->property_window_position().set_value(Gtk::WIN_POS_NONE); + this->set_resizable(true); + this->property_destroy_with_parent().set_value(false); + + // Preview area + _previewArea = Gtk::manage(new class Gtk::VBox()); + vbox1 = Gtk::manage(new class Gtk::VBox()); + vbox1->pack_start(*_previewArea, Gtk::PACK_EXPAND_WIDGET, 0); #if WITH_GTKMM_3_0 - Glib::RefPtr<Gtk::Adjustment> _pageNumberSpin_adj = Gtk::Adjustment::create(1, 1, _vec.size(), 1, 10, 0); - _pageNumberSpin = Gtk::manage(new Inkscape::UI::Widget::SpinButton(_pageNumberSpin_adj, 1, 1)); + this->get_content_area()->pack_start(*vbox1); #else - Gtk::Adjustment *_pageNumberSpin_adj = Gtk::manage( - new class Gtk::Adjustment(1, 1, _vec.size(), 1, 10, 0)); - _pageNumberSpin = Gtk::manage(new class Inkscape::UI::Widget::SpinButton(*_pageNumberSpin_adj, 1, 1)); + this->get_vbox()->pack_start(*vbox1); #endif - _labelTotalPages = Gtk::manage(new class Gtk::Label()); - gchar *label_text = g_strdup_printf(_("out of %i"), num_pages); - _labelTotalPages->set_label(label_text); - g_free(label_text); - vbox1 = Gtk::manage(new class Gtk::VBox(false, 4)); - SPDocument *doc = SPDocument::createNewDocFromMem(_vec[0].cstr(), strlen(_vec[0].cstr()), 0); - _previewArea = Glib::wrap(sp_svg_view_widget_new(doc)); - - vbox2 = Gtk::manage(new class Gtk::VBox(false, 4)); - cancelbutton->set_can_focus(); - cancelbutton->set_can_default(); - cancelbutton->set_relief(Gtk::RELIEF_NORMAL); - okbutton->set_can_focus(); - okbutton->set_can_default(); - okbutton->set_relief(Gtk::RELIEF_NORMAL); - this->get_action_area()->property_layout_style().set_value(Gtk::BUTTONBOX_END); + // CONTROLS + + // Buttons + cancelbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-cancel"))); + okbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-ok"))); + + // Labels + _labelSelect = Gtk::manage(new class Gtk::Label(_("Select page:"))); + _labelTotalPages = Gtk::manage(new class Gtk::Label()); _labelSelect->set_line_wrap(false); _labelSelect->set_use_markup(false); _labelSelect->set_selectable(false); - _pageNumberSpin->set_can_focus(); - _pageNumberSpin->set_update_policy(Gtk::UPDATE_ALWAYS); - _pageNumberSpin->set_numeric(true); - _pageNumberSpin->set_digits(0); - _pageNumberSpin->set_wrap(false); _labelTotalPages->set_line_wrap(false); _labelTotalPages->set_use_markup(false); _labelTotalPages->set_selectable(false); - vbox2->pack_start(*_previewArea, Gtk::PACK_SHRINK, 0); + gchar *label_text = g_strdup_printf(_("out of %i"), num_pages); + _labelTotalPages->set_label(label_text); + g_free(label_text); + + // Adjustment + spinner #if WITH_GTKMM_3_0 - this->get_content_area()->set_homogeneous(false); - this->get_content_area()->set_spacing(0); - this->get_content_area()->pack_start(*vbox2); + Glib::RefPtr<Gtk::Adjustment> _pageNumberSpin_adj = Gtk::Adjustment::create(1, 1, _vec.size(), 1, 10, 0); + _pageNumberSpin = Gtk::manage(new Gtk::SpinButton(_pageNumberSpin_adj, 1, 0)); #else - this->get_vbox()->set_homogeneous(false); - this->get_vbox()->set_spacing(0); - this->get_vbox()->pack_start(*vbox2); + Gtk::Adjustment *_pageNumberSpin_adj = Gtk::manage(new class Gtk::Adjustment(1, 1, _vec.size(), 1, 10, 0)); + _pageNumberSpin = Gtk::manage(new Gtk::SpinButton(*_pageNumberSpin_adj, 1, 0)); #endif - this->set_title(_("Page Selector")); - this->set_modal(true); - sp_transientize(GTK_WIDGET(this->gobj())); //Make transient - this->property_window_position().set_value(Gtk::WIN_POS_NONE); - this->set_resizable(true); - this->property_destroy_with_parent().set_value(false); + _pageNumberSpin->set_can_focus(); + _pageNumberSpin->set_update_policy(Gtk::UPDATE_ALWAYS); + _pageNumberSpin->set_numeric(true); + _pageNumberSpin->set_wrap(false); + + this->get_action_area()->property_layout_style().set_value(Gtk::BUTTONBOX_END); this->get_action_area()->add(*_labelSelect); - this->add_action_widget(*_pageNumberSpin, -7); + this->add_action_widget(*_pageNumberSpin, Gtk::RESPONSE_ACCEPT); this->get_action_area()->add(*_labelTotalPages); - this->add_action_widget(*cancelbutton, -6); - this->add_action_widget(*okbutton, -5); - cancelbutton->show(); - okbutton->show(); - _labelSelect->show(); - _pageNumberSpin->show(); - _labelTotalPages->show(); - vbox1->show(); - _previewArea->show(); - vbox2->show(); + this->add_action_widget(*cancelbutton, Gtk::RESPONSE_CANCEL); + this->add_action_widget(*okbutton, Gtk::RESPONSE_OK); + + // Show all widgets in dialog + this->show_all(); // Connect signals - _pageNumberSpin_adj->signal_value_changed().connect(sigc::mem_fun(*this, &CdrImportDialog::_onPageNumberChanged)); + _pageNumberSpin->signal_value_changed().connect(sigc::mem_fun(*this, &CdrImportDialog::_onPageNumberChanged)); + _pageNumberSpin->signal_button_press_event().connect_notify(sigc::mem_fun(*this, &CdrImportDialog::_onSpinButtonPress)); + _pageNumberSpin->signal_button_release_event().connect_notify(sigc::mem_fun(*this, &CdrImportDialog::_onSpinButtonRelease)); + + _setPreviewPage(); } CdrImportDialog::~CdrImportDialog() {} @@ -193,7 +174,7 @@ bool CdrImportDialog::showDialog() show(); gint b = run(); hide(); - if ( b == Gtk::RESPONSE_OK ) { + if (b == Gtk::RESPONSE_OK || b == Gtk::RESPONSE_ACCEPT) { return TRUE; } else { return FALSE; @@ -209,22 +190,34 @@ void CdrImportDialog::_onPageNumberChanged() { unsigned page = static_cast<unsigned>(_pageNumberSpin->get_value_as_int()); _current_page = CLAMP(page, 1U, _vec.size()); - _setPreviewPage(_current_page); + _setPreviewPage(); +} + +void CdrImportDialog::_onSpinButtonPress(GdkEventButton* /*button_event*/) +{ + _spinning = true; +} + +void CdrImportDialog::_onSpinButtonRelease(GdkEventButton* /*button_event*/) +{ + _spinning = false; + _setPreviewPage(); } /** * \brief Renders the given page's thumbnail */ -void CdrImportDialog::_setPreviewPage(unsigned page) +void CdrImportDialog::_setPreviewPage() { - SPDocument *doc = SPDocument::createNewDocFromMem(_vec[page-1].cstr(), strlen(_vec[page-1].cstr()), 0); + if (_spinning) { + return; + } + + SPDocument *doc = SPDocument::createNewDocFromMem(_vec[_current_page-1].cstr(), strlen(_vec[_current_page-1].cstr()), 0); Gtk::Widget * tmpPreviewArea = Glib::wrap(sp_svg_view_widget_new(doc)); std::swap(_previewArea, tmpPreviewArea); - if (tmpPreviewArea) { - _previewArea->set_size_request( tmpPreviewArea->get_width(), tmpPreviewArea->get_height() ); - delete tmpPreviewArea; - } - vbox2->pack_start(*_previewArea, Gtk::PACK_SHRINK, 0); + delete tmpPreviewArea; + vbox1->pack_start(*_previewArea, Gtk::PACK_EXPAND_WIDGET, 0); _previewArea->show_now(); } diff --git a/src/extension/internal/vsd-input.cpp b/src/extension/internal/vsd-input.cpp index 7fd0d363b..a3d4aad37 100644 --- a/src/extension/internal/vsd-input.cpp +++ b/src/extension/internal/vsd-input.cpp @@ -40,33 +40,24 @@ typedef libvisio::VSDStringVector RVNGStringVector; #endif - #include <gtkmm/alignment.h> -#include <gtkmm/comboboxtext.h> -#include <gtkmm/drawingarea.h> -#include <gtkmm/frame.h> -#include <gtkmm/scale.h> +#include <gtkmm/spinbutton.h> #include "extension/system.h" #include "extension/input.h" -#include "document.h" +#include "document.h" #include "document-private.h" -#include "document-undo.h" #include "inkscape.h" -#include "util/units.h" #include "ui/dialog-events.h" -#include <gtk/gtk.h> -#include "ui/widget/spinbutton.h" -#include "ui/widget/frame.h" #include <glibmm/i18n.h> -#include <gdkmm/general.h> - -#include "svg-view.h" #include "svg-view-widget.h" + +#include "util/units.h" + namespace Inkscape { namespace Extension { namespace Internal { @@ -82,108 +73,101 @@ public: void getImportSettings(Inkscape::XML::Node *prefs); private: - void _setPreviewPage(unsigned page); + void _setPreviewPage(); // Signal handlers -#if !WITH_GTKMM_3_0 - bool _onExposePreview(GdkEventExpose *event); -#endif - void _onPageNumberChanged(); + void _onSpinButtonPress(GdkEventButton* button_event); + void _onSpinButtonRelease(GdkEventButton* button_event); + class Gtk::VBox * vbox1; + class Gtk::Widget * _previewArea; class Gtk::Button * cancelbutton; class Gtk::Button * okbutton; class Gtk::Label * _labelSelect; - class Inkscape::UI::Widget::SpinButton * _pageNumberSpin; class Gtk::Label * _labelTotalPages; - class Gtk::VBox * vbox1; - class Gtk::VBox * vbox2; - class Gtk::Widget * _previewArea; + class Gtk::SpinButton * _pageNumberSpin; - const std::vector<RVNGString> &_vec; // Document to be imported - unsigned _current_page; // Current selected page - int _preview_width, _preview_height; // Size of the preview area + const std::vector<RVNGString> &_vec; // Document to be imported + unsigned _current_page; // Current selected page + bool _spinning; // whether SpinButton is pressed (i.e. we're "spinning") }; VsdImportDialog::VsdImportDialog(const std::vector<RVNGString> &vec) - : _vec(vec), _current_page(1) + : _vec(vec), _current_page(1), _spinning(false) { int num_pages = _vec.size(); if ( num_pages <= 1 ) return; - cancelbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-cancel"))); - okbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-ok"))); - _labelSelect = Gtk::manage(new class Gtk::Label(_("Select page:"))); - // Page number + + // Dialog settings + this->set_title(_("Page Selector")); + this->set_modal(true); + sp_transientize(GTK_WIDGET(this->gobj())); //Make transient + this->property_window_position().set_value(Gtk::WIN_POS_NONE); + this->set_resizable(true); + this->property_destroy_with_parent().set_value(false); + + // Preview area + _previewArea = Gtk::manage(new class Gtk::VBox()); + vbox1 = Gtk::manage(new class Gtk::VBox()); + vbox1->pack_start(*_previewArea, Gtk::PACK_EXPAND_WIDGET, 0); #if WITH_GTKMM_3_0 - Glib::RefPtr<Gtk::Adjustment> _pageNumberSpin_adj = Gtk::Adjustment::create(1, 1, _vec.size(), 1, 10, 0); - _pageNumberSpin = Gtk::manage(new Inkscape::UI::Widget::SpinButton(_pageNumberSpin_adj, 1, 1)); + this->get_content_area()->pack_start(*vbox1); #else - Gtk::Adjustment *_pageNumberSpin_adj = Gtk::manage( - new class Gtk::Adjustment(1, 1, _vec.size(), 1, 10, 0)); - _pageNumberSpin = Gtk::manage(new class Inkscape::UI::Widget::SpinButton(*_pageNumberSpin_adj, 1, 1)); + this->get_vbox()->pack_start(*vbox1); #endif - _labelTotalPages = Gtk::manage(new class Gtk::Label()); - gchar *label_text = g_strdup_printf(_("out of %i"), num_pages); - _labelTotalPages->set_label(label_text); - g_free(label_text); - vbox1 = Gtk::manage(new class Gtk::VBox(false, 4)); - SPDocument *doc = SPDocument::createNewDocFromMem(_vec[0].cstr(), strlen(_vec[0].cstr()), 0); - _previewArea = Glib::wrap(sp_svg_view_widget_new(doc)); - - vbox2 = Gtk::manage(new class Gtk::VBox(false, 4)); - cancelbutton->set_can_focus(); - cancelbutton->set_can_default(); - cancelbutton->set_relief(Gtk::RELIEF_NORMAL); - okbutton->set_can_focus(); - okbutton->set_can_default(); - okbutton->set_relief(Gtk::RELIEF_NORMAL); - this->get_action_area()->property_layout_style().set_value(Gtk::BUTTONBOX_END); + + // CONTROLS + + // Buttons + cancelbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-cancel"))); + okbutton = Gtk::manage(new class Gtk::Button(Gtk::StockID("gtk-ok"))); + + // Labels + _labelSelect = Gtk::manage(new class Gtk::Label(_("Select page:"))); + _labelTotalPages = Gtk::manage(new class Gtk::Label()); _labelSelect->set_line_wrap(false); _labelSelect->set_use_markup(false); _labelSelect->set_selectable(false); - _pageNumberSpin->set_can_focus(); - _pageNumberSpin->set_update_policy(Gtk::UPDATE_ALWAYS); - _pageNumberSpin->set_numeric(true); - _pageNumberSpin->set_digits(0); - _pageNumberSpin->set_wrap(false); _labelTotalPages->set_line_wrap(false); _labelTotalPages->set_use_markup(false); _labelTotalPages->set_selectable(false); - vbox2->pack_start(*_previewArea, Gtk::PACK_SHRINK, 0); + gchar *label_text = g_strdup_printf(_("out of %i"), num_pages); + _labelTotalPages->set_label(label_text); + g_free(label_text); + + // Adjustment + spinner #if WITH_GTKMM_3_0 - this->get_content_area()->set_homogeneous(false); - this->get_content_area()->set_spacing(0); - this->get_content_area()->pack_start(*vbox2); + Glib::RefPtr<Gtk::Adjustment> _pageNumberSpin_adj = Gtk::Adjustment::create(1, 1, _vec.size(), 1, 10, 0); + _pageNumberSpin = Gtk::manage(new Gtk::SpinButton(_pageNumberSpin_adj, 1, 0)); #else - this->get_vbox()->set_homogeneous(false); - this->get_vbox()->set_spacing(0); - this->get_vbox()->pack_start(*vbox2); + Gtk::Adjustment *_pageNumberSpin_adj = Gtk::manage(new class Gtk::Adjustment(1, 1, _vec.size(), 1, 10, 0)); + _pageNumberSpin = Gtk::manage(new Gtk::SpinButton(*_pageNumberSpin_adj, 1, 0)); #endif - this->set_title(_("Page Selector")); - this->set_modal(true); - sp_transientize(GTK_WIDGET(this->gobj())); //Make transient - this->property_window_position().set_value(Gtk::WIN_POS_NONE); - this->set_resizable(true); - this->property_destroy_with_parent().set_value(false); + _pageNumberSpin->set_can_focus(); + _pageNumberSpin->set_update_policy(Gtk::UPDATE_ALWAYS); + _pageNumberSpin->set_numeric(true); + _pageNumberSpin->set_wrap(false); + + this->get_action_area()->property_layout_style().set_value(Gtk::BUTTONBOX_END); this->get_action_area()->add(*_labelSelect); - this->add_action_widget(*_pageNumberSpin, -7); + this->add_action_widget(*_pageNumberSpin, Gtk::RESPONSE_ACCEPT); this->get_action_area()->add(*_labelTotalPages); - this->add_action_widget(*cancelbutton, -6); - this->add_action_widget(*okbutton, -5); - cancelbutton->show(); - okbutton->show(); - _labelSelect->show(); - _pageNumberSpin->show(); - _labelTotalPages->show(); - vbox1->show(); - _previewArea->show(); - vbox2->show(); + this->add_action_widget(*cancelbutton, Gtk::RESPONSE_CANCEL); + this->add_action_widget(*okbutton, Gtk::RESPONSE_OK); + + // Show all widgets in dialog + this->show_all(); // Connect signals - _pageNumberSpin_adj->signal_value_changed().connect(sigc::mem_fun(*this, &VsdImportDialog::_onPageNumberChanged)); + _pageNumberSpin->signal_value_changed().connect(sigc::mem_fun(*this, &VsdImportDialog::_onPageNumberChanged)); + _pageNumberSpin->signal_button_press_event().connect_notify(sigc::mem_fun(*this, &VsdImportDialog::_onSpinButtonPress)); + _pageNumberSpin->signal_button_release_event().connect_notify(sigc::mem_fun(*this, &VsdImportDialog::_onSpinButtonRelease)); + + _setPreviewPage(); } VsdImportDialog::~VsdImportDialog() {} @@ -193,7 +177,7 @@ bool VsdImportDialog::showDialog() show(); gint b = run(); hide(); - if ( b == Gtk::RESPONSE_OK ) { + if (b == Gtk::RESPONSE_OK || b == Gtk::RESPONSE_ACCEPT) { return TRUE; } else { return FALSE; @@ -209,22 +193,34 @@ void VsdImportDialog::_onPageNumberChanged() { unsigned page = static_cast<unsigned>(_pageNumberSpin->get_value_as_int()); _current_page = CLAMP(page, 1U, _vec.size()); - _setPreviewPage(_current_page); + _setPreviewPage(); +} + +void VsdImportDialog::_onSpinButtonPress(GdkEventButton* /*button_event*/) +{ + _spinning = true; +} + +void VsdImportDialog::_onSpinButtonRelease(GdkEventButton* /*button_event*/) +{ + _spinning = false; + _setPreviewPage(); } /** * \brief Renders the given page's thumbnail */ -void VsdImportDialog::_setPreviewPage(unsigned page) +void VsdImportDialog::_setPreviewPage() { - SPDocument *doc = SPDocument::createNewDocFromMem(_vec[page-1].cstr(), strlen(_vec[page-1].cstr()), 0); + if (_spinning) { + return; + } + + SPDocument *doc = SPDocument::createNewDocFromMem(_vec[_current_page-1].cstr(), strlen(_vec[_current_page-1].cstr()), 0); Gtk::Widget * tmpPreviewArea = Glib::wrap(sp_svg_view_widget_new(doc)); std::swap(_previewArea, tmpPreviewArea); - if (tmpPreviewArea) { - _previewArea->set_size_request( tmpPreviewArea->get_width(), tmpPreviewArea->get_height() ); - delete tmpPreviewArea; - } - vbox2->pack_start(*_previewArea, Gtk::PACK_SHRINK, 0); + delete tmpPreviewArea; + vbox1->pack_start(*_previewArea, Gtk::PACK_EXPAND_WIDGET, 0); _previewArea->show_now(); } @@ -282,12 +278,11 @@ SPDocument *VsdInput::open(Inkscape::Extension::Input * /*mod*/, const gchar * u } SPDocument * doc = SPDocument::createNewDocFromMem(tmpSVGOutput[page_num-1].cstr(), strlen(tmpSVGOutput[page_num-1].cstr()), TRUE); - + // Set viewBox if it doesn't exist - if (!doc->getRoot()->viewBox_set) { + if (doc && !doc->getRoot()->viewBox_set) { doc->setViewBox(Geom::Rect::from_xywh(0, 0, doc->getWidth().value(doc->getDisplayUnit()), doc->getHeight().value(doc->getDisplayUnit()))); } - return doc; } diff --git a/src/extension/output.cpp b/src/extension/output.cpp index 8de5583c7..83f0fed2f 100644 --- a/src/extension/output.cpp +++ b/src/extension/output.cpp @@ -192,8 +192,7 @@ Output::prefs (void) delete dialog; - if (response == Gtk::RESPONSE_OK) return true; - return false; + return (response == Gtk::RESPONSE_OK); } /** diff --git a/src/libnrtype/Layout-TNG.cpp b/src/libnrtype/Layout-TNG.cpp index ec488b584..8b0889188 100644 --- a/src/libnrtype/Layout-TNG.cpp +++ b/src/libnrtype/Layout-TNG.cpp @@ -14,7 +14,7 @@ namespace Inkscape { namespace Text { const gunichar Layout::UNICODE_SOFT_HYPHEN = 0x00AD; -const double Layout::LINE_HEIGHT_NORMAL = 125; +const double Layout::LINE_HEIGHT_NORMAL = 1.25; Layout::Layout() : _input_truncated(0), diff --git a/src/livarot/PathOutline.cpp b/src/livarot/PathOutline.cpp index e146bb908..1c42301da 100644 --- a/src/livarot/PathOutline.cpp +++ b/src/livarot/PathOutline.cpp @@ -471,8 +471,13 @@ void Path::SubContractOutline(int off, int num_pd, // test de nullité du segment if (IsNulCurve (descr_cmd, curD, curX)) { - stTgt = dest->descr_cmd.size() ? Geom::Point(1, 0) : Geom::Point(-1, 0); // reverse direction - enTgt = stTgt; + if (descr_cmd.size() == 2) { // single point, see LP Bug 1006666 + stTgt = dest->descr_cmd.size() ? Geom::Point(1, 0) : Geom::Point(-1, 0); // reverse direction + enTgt = stTgt; + } else { + curP++; + continue; + } } stNor=stTgt.cw(); enNor=enTgt.cw(); diff --git a/src/live_effects/effect.cpp b/src/live_effects/effect.cpp index 38d59a43a..c6ecba30a 100644 --- a/src/live_effects/effect.cpp +++ b/src/live_effects/effect.cpp @@ -110,7 +110,6 @@ const Util::EnumData<EffectType> LPETypeData[] = { {PATH_LENGTH, N_("Path length"), "path_length"}, {PERP_BISECTOR, N_("Perpendicular bisector"), "perp_bisector"}, {PERSPECTIVE_PATH, N_("Perspective path"), "perspective_path"}, - {COPY_ROTATE, N_("Rotate copies"), "copy_rotate"}, {RECURSIVE_SKELETON, N_("Recursive skeleton"), "recursive_skeleton"}, {TANGENT_TO_CURVE, N_("Tangent to curve"), "tangent_to_curve"}, {TEXT_LABEL, N_("Text label"), "text_label"}, @@ -145,6 +144,7 @@ const Util::EnumData<EffectType> LPETypeData[] = { {BSPLINE, N_("BSpline"), "bspline"}, {JOIN_TYPE, N_("Join type"), "join_type"}, {TAPER_STROKE, N_("Taper stroke"), "taper_stroke"}, + {COPY_ROTATE, N_("Rotate copies"), "copy_rotate"}, /* Ponyscape -> Inkscape 0.92*/ {ATTACH_PATH, N_("Attach path"), "attach_path"}, {FILL_BETWEEN_STROKES, N_("Fill between strokes"), "fill_between_strokes"}, @@ -467,6 +467,10 @@ void Effect::doBeforeEffect_impl(SPLPEItem const* lpeitem) pathvector_before_effect = sp_curve->get_pathvector(); } doBeforeEffect(lpeitem); + if (apply_to_clippath_and_mask && SP_IS_GROUP(sp_lpe_item)) { + sp_lpe_item->apply_to_clippath(sp_lpe_item); + sp_lpe_item->apply_to_mask(sp_lpe_item); + } } /** diff --git a/src/live_effects/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp index 8dfaf7525..efea76039 100644 --- a/src/live_effects/lpe-copy_rotate.cpp +++ b/src/live_effects/lpe-copy_rotate.cpp @@ -5,7 +5,7 @@ * Authors: * Maximilian Albert <maximilian.albert@gmail.com> * Johan Engelen <j.b.c.engelen@alumnus.utwente.nl> - * + * Jabiertxo Arraiza Cenoz <jabier.arraiza@marker.es> * Copyright (C) Authors 2007-2012 * * Released under GNU GPL, read the file 'COPYING' for more information @@ -13,7 +13,8 @@ #include <glibmm/i18n.h> #include <gdk/gdk.h> - +#include <2geom/path-intersection.h> +#include <2geom/sbasis-to-bezier.h> #include "live_effects/lpe-copy_rotate.h" #include <2geom/path.h> #include <2geom/transforms.h> @@ -41,22 +42,31 @@ public: virtual Geom::Point knot_get() const; }; -class KnotHolderEntityOrigin : public LPEKnotHolderEntity { -public: - KnotHolderEntityOrigin(LPECopyRotate *effect) : LPEKnotHolderEntity(effect) {}; - virtual void knot_set(Geom::Point const &p, Geom::Point const &origin, guint state); - virtual Geom::Point knot_get() const; -}; - } // namespace CR +bool +pointInTriangle(Geom::Point const &p, Geom::Point const &p1, Geom::Point const &p2, Geom::Point const &p3) +{ + //http://totologic.blogspot.com.es/2014/01/accurate-point-in-triangle-test.html + using Geom::X; + using Geom::Y; + double denominator = (p1[X]*(p2[Y] - p3[Y]) + p1[Y]*(p3[X] - p2[X]) + p2[X]*p3[Y] - p2[Y]*p3[X]); + double t1 = (p[X]*(p3[Y] - p1[Y]) + p[Y]*(p1[X] - p3[X]) - p1[X]*p3[Y] + p1[Y]*p3[X]) / denominator; + double t2 = (p[X]*(p2[Y] - p1[Y]) + p[Y]*(p1[X] - p2[X]) - p1[X]*p2[Y] + p1[Y]*p2[X]) / -denominator; + double s = t1 + t2; + + return 0 <= t1 && t1 <= 1 && 0 <= t2 && t2 <= 1 && s <= 1; +} + + LPECopyRotate::LPECopyRotate(LivePathEffectObject *lpeobject) : Effect(lpeobject), origin(_("Origin"), _("Origin of the rotation"), "origin", &wr, this, "Adjust the origin of the rotation"), starting_angle(_("Starting:"), _("Angle of the first copy"), "starting_angle", &wr, this, 0.0), - rotation_angle(_("Rotation angle:"), _("Angle between two successive copies"), "rotation_angle", &wr, this, 30.0), - num_copies(_("Number of copies:"), _("Number of copies of the original path"), "num_copies", &wr, this, 5), - copiesTo360(_("360º Copies"), _("No rotation angle, fixed to 360º"), "copiesTo360", &wr, this, true), + rotation_angle(_("Rotation angle:"), _("Angle between two successive copies"), "rotation_angle", &wr, this, 60.0), + num_copies(_("Number of copies:"), _("Number of copies of the original path"), "num_copies", &wr, this, 6), + copies_to_360(_("360º Copies"), _("No rotation angle, fixed to 360º"), "copies_to_360", &wr, this, true), + fuse_paths(_("Fuse paths"), _("Fuse paths by helper line, use fill-rule: evenodd for best result"), "fuse_paths", &wr, this, false), dist_angle_handle(100.0) { show_orig_path = true; @@ -64,12 +74,13 @@ LPECopyRotate::LPECopyRotate(LivePathEffectObject *lpeobject) : apply_to_clippath_and_mask = true; // register all your parameters here, so Inkscape knows which parameters this effect has: - registerParameter(&copiesTo360); + registerParameter(&copies_to_360); + registerParameter(&fuse_paths); registerParameter(&starting_angle); registerParameter(&rotation_angle); registerParameter(&num_copies); registerParameter(&origin); - + num_copies.param_make_integer(true); num_copies.param_set_range(0, 1000); } @@ -93,15 +104,46 @@ LPECopyRotate::doOnApply(SPLPEItem const* lpeitem) dir = unit_vector(B - A); } +void +LPECopyRotate::transform_multiply(Geom::Affine const& postmul, bool set) +{ + if(fuse_paths) { + Geom::Coord angle = Geom::deg_from_rad(atan(-postmul[1]/postmul[0])); + angle += starting_angle; + starting_angle.param_set_value(angle); + } + // cycle through all parameters. Most parameters will not need transformation, but path and point params do. + + for (std::vector<Parameter *>::iterator it = param_vector.begin(); it != param_vector.end(); ++it) { + Parameter * param = *it; + param->param_transform_multiply(postmul, set); + } +} void LPECopyRotate::doBeforeEffect (SPLPEItem const* lpeitem) { using namespace Geom; original_bbox(lpeitem); - if(copiesTo360 ){ + if (copies_to_360) { rotation_angle.param_set_value(360.0/(double)num_copies); - } + } + if (fuse_paths && rotation_angle * num_copies > 360 && rotation_angle > 0) { + num_copies.param_set_value(floor(360/rotation_angle)); + } + if (fuse_paths && copies_to_360) { + num_copies.param_set_increments(2,2); + if ((int)num_copies%2 !=0) { + num_copies.param_set_value(num_copies+1); + rotation_angle.param_set_value(360.0/(double)num_copies); + } + } else { + num_copies.param_set_increments(1,1); + } + + if (dist_angle_handle < 1.0) { + dist_angle_handle = 1.0; + } A = Point(boundingbox_X.min(), boundingbox_Y.middle()); B = Point(boundingbox_X.middle(), boundingbox_Y.middle()); dir = unit_vector(B - A); @@ -109,27 +151,251 @@ LPECopyRotate::doBeforeEffect (SPLPEItem const* lpeitem) // likely due to SVG's choice of coordinate system orientation (max) start_pos = origin + dir * Rotate(-rad_from_deg(starting_angle)) * dist_angle_handle; rot_pos = origin + dir * Rotate(-rad_from_deg(rotation_angle+starting_angle)) * dist_angle_handle; - if(copiesTo360 ){ + if ( fuse_paths || copies_to_360 ) { rot_pos = origin; } + SPLPEItem * item = const_cast<SPLPEItem*>(lpeitem); + item->apply_to_clippath(item); + item->apply_to_mask(item); } +void +LPECopyRotate::split(Geom::PathVector &path_on, Geom::Path const ÷r) +{ + Geom::PathVector tmp_path; + double time_start = 0.0; + Geom::Path original = path_on[0]; + int position = 0; + Geom::Crossings cs = crossings(original,divider); + std::vector<double> crossed; + for(unsigned int i = 0; i < cs.size(); i++) { + crossed.push_back(cs[i].ta); + } + std::sort(crossed.begin(), crossed.end()); + for (unsigned int i = 0; i < crossed.size(); i++) { + double time_end = crossed[i]; + if (time_start == time_end || time_end - time_start < Geom::EPSILON) { + continue; + } + Geom::Path portion_original = original.portion(time_start,time_end); + if (!portion_original.empty()) { + Geom::Point side_checker = portion_original.pointAt(0.0001); + position = Geom::sgn(Geom::cross(divider[1].finalPoint() - divider[0].finalPoint(), side_checker - divider[0].finalPoint())); + if (rotation_angle != 180) { + position = pointInTriangle(side_checker, divider.initialPoint(), divider[0].finalPoint(), divider[1].finalPoint()); + } + if (position == 1) { + tmp_path.push_back(portion_original); + } + portion_original.clear(); + time_start = time_end; + } + } + position = Geom::sgn(Geom::cross(divider[1].finalPoint() - divider[0].finalPoint(), original.finalPoint() - divider[0].finalPoint())); + if (rotation_angle != 180) { + position = pointInTriangle(original.finalPoint(), divider.initialPoint(), divider[0].finalPoint(), divider[1].finalPoint()); + } + if (cs.size() > 0 && position == 1) { + Geom::Path portion_original = original.portion(time_start, original.size()); + if(!portion_original.empty()){ + if (!original.closed()) { + tmp_path.push_back(portion_original); + } else { + if (tmp_path.size() > 0 && tmp_path[0].size() > 0 ) { + portion_original.setFinal(tmp_path[0].initialPoint()); + portion_original.append(tmp_path[0]); + tmp_path[0] = portion_original; + } else { + tmp_path.push_back(portion_original); + } + } + portion_original.clear(); + } + } + if (cs.size()==0 && position == 1) { + tmp_path.push_back(original); + } + path_on = tmp_path; +} + +void +LPECopyRotate::setFusion(Geom::PathVector &path_on, Geom::Path divider, double size_divider) +{ + split(path_on,divider); + Geom::PathVector tmp_path; + Geom::Affine pre = Geom::Translate(-origin); + for (Geom::PathVector::const_iterator path_it = path_on.begin(); path_it != path_on.end(); ++path_it) { + Geom::Path original = *path_it; + if (path_it->empty()) { + continue; + } + Geom::PathVector tmp_path_helper; + Geom::Path append_path = original; + + for (int i = 0; i < num_copies; ++i) { + Geom::Rotate rot(-Geom::rad_from_deg(rotation_angle * (i))); + Geom::Affine m = pre * rot * Geom::Translate(origin); + if (i%2 != 0) { + Geom::Point A = (Geom::Point)origin; + Geom::Point B = origin + dir * Geom::Rotate(-Geom::rad_from_deg((rotation_angle*i)+starting_angle)) * size_divider; + Geom::Translate m1(A[0], A[1]); + double hyp = Geom::distance(A, B); + double c = (B[0] - A[0]) / hyp; // cos(alpha) + double s = (B[1] - A[1]) / hyp; // sin(alpha) + + Geom::Affine m2(c, -s, s, c, 0.0, 0.0); + Geom::Scale sca(1.0, -1.0); + + Geom::Affine tmp_m = m1.inverse() * m2; + m = tmp_m; + m = m * sca; + m = m * m2.inverse(); + m = m * m1; + } else { + append_path = original; + } + append_path *= m; + if (tmp_path_helper.size() > 0) { + if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(), append_path.finalPoint())) { + Geom::Path tmp_append = append_path.reversed(); + tmp_append.setInitial(tmp_path_helper[tmp_path_helper.size()-1].finalPoint()); + tmp_path_helper[tmp_path_helper.size()-1].append(tmp_append); + } else if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].initialPoint(), append_path.initialPoint())) { + Geom::Path tmp_append = append_path; + tmp_path_helper[tmp_path_helper.size()-1] = tmp_path_helper[tmp_path_helper.size()-1].reversed(); + tmp_append.setInitial(tmp_path_helper[tmp_path_helper.size()-1].finalPoint()); + tmp_path_helper[tmp_path_helper.size()-1].append(tmp_append); + } else if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(), append_path.initialPoint())) { + Geom::Path tmp_append = append_path; + tmp_append.setInitial(tmp_path_helper[tmp_path_helper.size()-1].finalPoint()); + tmp_path_helper[tmp_path_helper.size()-1].append(tmp_append); + } else if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].initialPoint(), append_path.finalPoint())) { + Geom::Path tmp_append = append_path.reversed(); + tmp_path_helper[tmp_path_helper.size()-1] = tmp_path_helper[tmp_path_helper.size()-1].reversed(); + tmp_append.setInitial(tmp_path_helper[tmp_path_helper.size()-1].finalPoint()); + tmp_path_helper[tmp_path_helper.size()-1].append(tmp_append); + } else if (Geom::are_near(tmp_path_helper[0].finalPoint(), append_path.finalPoint())) { + Geom::Path tmp_append = append_path.reversed(); + tmp_append.setInitial(tmp_path_helper[0].finalPoint()); + tmp_path_helper[0].append(tmp_append); + } else if (Geom::are_near(tmp_path_helper[0].initialPoint(), append_path.initialPoint())) { + Geom::Path tmp_append = append_path; + tmp_path_helper[0] = tmp_path_helper[0].reversed(); + tmp_append.setInitial(tmp_path_helper[0].finalPoint()); + tmp_path_helper[0].append(tmp_append); + } else { + tmp_path_helper.push_back(append_path); + } + if ( Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(),tmp_path_helper[tmp_path_helper.size()-1].initialPoint())) { + tmp_path_helper[tmp_path_helper.size()-1].close(); + } + } else { + tmp_path_helper.push_back(append_path); + } + } + if (tmp_path_helper.size() > 0) { + tmp_path_helper[tmp_path_helper.size()-1] = tmp_path_helper[tmp_path_helper.size()-1]; + tmp_path_helper[0] = tmp_path_helper[0]; + if (rotation_angle * num_copies != 360) { + Geom::Ray base_a(divider.pointAt(1),divider.pointAt(0)); + double diagonal = Geom::distance(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max())); + Geom::Rect bbox(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max())); + double size_divider = Geom::distance(origin,bbox) + (diagonal * 2); + Geom::Point base_point = origin + dir * Geom::Rotate(-Geom::rad_from_deg((rotation_angle * num_copies) + starting_angle)) * size_divider; + Geom::Ray base_b(divider.pointAt(1), base_point); + if (Geom::are_near(tmp_path_helper[0].initialPoint(),base_a) && + Geom::are_near(tmp_path_helper[0].finalPoint(),base_a)) + { + tmp_path_helper[0].close(); + if (tmp_path_helper.size() > 1) { + tmp_path_helper[tmp_path_helper.size()-1].close(); + } + } else if (Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].initialPoint(),base_b) && + Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(),base_b)) + { + tmp_path_helper[0].close(); + if (tmp_path_helper.size() > 1) { + tmp_path_helper[tmp_path_helper.size()-1].close(); + } + } else if ((Geom::are_near(tmp_path_helper[0].initialPoint(),base_a) && + Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(),base_b)) || + (Geom::are_near(tmp_path_helper[0].initialPoint(),base_b) && + Geom::are_near(tmp_path_helper[tmp_path_helper.size()-1].finalPoint(),base_a))) + { + Geom::Path close_path = Geom::Path(tmp_path_helper[tmp_path_helper.size()-1].finalPoint()); + close_path.appendNew<Geom::LineSegment>((Geom::Point)origin); + close_path.appendNew<Geom::LineSegment>(tmp_path_helper[0].initialPoint()); + tmp_path_helper[0].append(close_path); + } + } + + if (Geom::are_near(tmp_path_helper[0].finalPoint(),tmp_path_helper[0].initialPoint())) { + tmp_path_helper[0].close(); + } + } + tmp_path.insert(tmp_path.end(), tmp_path_helper.begin(), tmp_path_helper.end()); + tmp_path_helper.clear(); + } + path_on = tmp_path; + tmp_path.clear(); +} Geom::Piecewise<Geom::D2<Geom::SBasis> > LPECopyRotate::doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in) { using namespace Geom; - if(num_copies == 1){ + if (num_copies == 1 && !fuse_paths) { return pwd2_in; } + double diagonal = Geom::distance(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max())); + Geom::Rect bbox(Geom::Point(boundingbox_X.min(),boundingbox_Y.min()),Geom::Point(boundingbox_X.max(),boundingbox_Y.max())); + double size_divider = Geom::distance(origin,bbox) + (diagonal * 2); + Geom::Point line_start = origin + dir * Rotate(-rad_from_deg(starting_angle)) * size_divider; + Geom::Point line_end = origin + dir * Rotate(-rad_from_deg(rotation_angle + starting_angle)) * size_divider; + //Note:: beter way to do this + //Whith AppendNew have problems whith the crossing order + Geom::Path divider = Geom::Path(line_start); + divider.appendNew<Geom::LineSegment>((Geom::Point)origin); + divider.appendNew<Geom::LineSegment>(line_end); Piecewise<D2<SBasis> > output; Affine pre = Translate(-origin) * Rotate(-rad_from_deg(starting_angle)); - for (int i = 0; i < num_copies; ++i) { - Rotate rot(-rad_from_deg(rotation_angle * i)); - Affine t = pre * rot * Translate(origin); - output.concat(pwd2_in * t); + if (fuse_paths) { + Geom::PathVector path_out; + Geom::PathVector tmp_path; + PathVector const original_pathv = path_from_piecewise(remove_short_cuts(pwd2_in, 0.1), 0.001); + for (Geom::PathVector::const_iterator path_it = original_pathv.begin(); path_it != original_pathv.end(); ++path_it) { + if (path_it->empty()) { + continue; + } + bool end_open = false; + if (path_it->closed()) { + const Geom::Curve &closingline = path_it->back_closed(); + if (!are_near(closingline.initialPoint(), closingline.finalPoint())) { + end_open = true; + } + } + Geom::Path original = (Geom::Path)(*path_it); + if (end_open && path_it->closed()) { + original.close(false); + original.appendNew<Geom::LineSegment>( original.initialPoint() ); + original.close(true); + } + tmp_path.push_back(original); + setFusion(tmp_path, divider, size_divider); + path_out.insert(path_out.end(), tmp_path.begin(), tmp_path.end()); + tmp_path.clear(); + } + if (path_out.size()>0) { + output = paths_to_pw(path_out); + } + } else { + for (int i = 0; i < num_copies; ++i) { + Rotate rot(-rad_from_deg(rotation_angle * i)); + Affine t = pre * rot * Translate(origin); + output.concat(pwd2_in * t); + } } return output; } @@ -148,8 +414,16 @@ LPECopyRotate::addCanvasIndicators(SPLPEItem const */*lpeitem*/, std::vector<Geo hp_vec.push_back(pathv); } +void +LPECopyRotate::resetDefaults(SPItem const* item) +{ + Effect::resetDefaults(item); + original_bbox(SP_LPE_ITEM(item)); +} -void LPECopyRotate::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) { +void +LPECopyRotate::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *desktop, SPItem *item) +{ { KnotHolderEntity *e = new CR::KnotHolderEntityStartingAngle(this); e->create( desktop, item, knotholder, Inkscape::CTRL_TYPE_UNKNOWN, @@ -162,13 +436,6 @@ void LPECopyRotate::addKnotHolderEntities(KnotHolder *knotholder, SPDesktop *des _("Adjust the rotation angle")); knotholder->add(e); } -} - -void -LPECopyRotate::resetDefaults(SPItem const* item) -{ - Effect::resetDefaults(item); - original_bbox(SP_LPE_ITEM(item)); }; namespace CR { diff --git a/src/live_effects/lpe-copy_rotate.h b/src/live_effects/lpe-copy_rotate.h index 9392026a7..87af867df 100644 --- a/src/live_effects/lpe-copy_rotate.h +++ b/src/live_effects/lpe-copy_rotate.h @@ -22,24 +22,22 @@ namespace Inkscape { namespace LivePathEffect { namespace CR { - // we need a separate namespace to avoid clashes with LPEPerpBisector - class KnotHolderEntityStartingAngle; - class KnotHolderEntityRotationAngle; +// we need a separate namespace to avoid clashes with LPEPerpBisector +class KnotHolderEntityStartingAngle; +class KnotHolderEntityRotationAngle; } class LPECopyRotate : public Effect, GroupBBoxEffect { public: LPECopyRotate(LivePathEffectObject *lpeobject); virtual ~LPECopyRotate(); - virtual void doOnApply (SPLPEItem const* lpeitem); - virtual Geom::Piecewise<Geom::D2<Geom::SBasis> > doEffect_pwd2 (Geom::Piecewise<Geom::D2<Geom::SBasis> > const & pwd2_in); - virtual void doBeforeEffect (SPLPEItem const* lpeitem); - + virtual void setFusion(Geom::PathVector &path_in, Geom::Path divider, double sizeDivider); + virtual void split(Geom::PathVector &path_in, Geom::Path const ÷r); virtual void resetDefaults(SPItem const* item); - + virtual void transform_multiply(Geom::Affine const& postmul, bool set); /* the knotholder entity classes must be declared friends */ friend class CR::KnotHolderEntityStartingAngle; friend class CR::KnotHolderEntityRotationAngle; @@ -53,16 +51,14 @@ private: ScalarParam starting_angle; ScalarParam rotation_angle; ScalarParam num_copies; - BoolParam copiesTo360; - + BoolParam copies_to_360; + BoolParam fuse_paths; Geom::Point A; Geom::Point B; Geom::Point dir; - Geom::Point start_pos; Geom::Point rot_pos; double dist_angle_handle; - LPECopyRotate(const LPECopyRotate&); LPECopyRotate& operator=(const LPECopyRotate&); }; diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp index e0369e662..7ea1d465c 100644 --- a/src/live_effects/parameter/path.cpp +++ b/src/live_effects/parameter/path.cpp @@ -294,7 +294,12 @@ void PathParam::set_new_value (Geom::PathVector const &newpath, bool write_to_svg) { remove_link(); - _pathvector = newpath; + if (newpath.empty()) { + param_set_and_write_default(); + return; + } else { + _pathvector = newpath; + } must_recalculate_pwd2 = true; if (write_to_svg) { diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp index 15d3f0f99..1a345b565 100644 --- a/src/path-chemistry.cpp +++ b/src/path-chemistry.cpp @@ -1,4 +1,4 @@ -/* + /* * Here are handlers for modifying selections, specific to paths * * Authors: @@ -217,7 +217,6 @@ sp_selected_path_break_apart(SPDesktop *desktop, bool skip_undo) if (curve == NULL) { continue; } - did = true; Inkscape::XML::Node *parent = item->getRepr()->parent(); @@ -228,16 +227,10 @@ sp_selected_path_break_apart(SPDesktop *desktop, bool skip_undo) gchar *style = g_strdup(item->getRepr()->attribute("style")); // XML Tree being used directly here while it shouldn't be... gchar *path_effect = g_strdup(item->getRepr()->attribute("inkscape:path-effect")); - - Geom::PathVector apv = curve->get_pathvector() * path->transform; - - curve->unref(); - + Geom::Affine transform = path->transform; // it's going to resurrect as one of the pieces, so we delete without advertisement item->deleteObject(false); - curve = new SPCurve(apv); - g_assert(curve != NULL); GSList *list = curve->split(); @@ -258,7 +251,8 @@ sp_selected_path_break_apart(SPDesktop *desktop, bool skip_undo) else repr->setAttribute("d", str); g_free(str); - + repr->setAttribute("transform", sp_svg_transform_write(transform)); + // add the new repr to the parent parent->appendChild(repr); diff --git a/src/sp-lpe-item.cpp b/src/sp-lpe-item.cpp index e2afbb55b..fdc2949d5 100644 --- a/src/sp-lpe-item.cpp +++ b/src/sp-lpe-item.cpp @@ -209,7 +209,7 @@ Inkscape::XML::Node* SPLPEItem::write(Inkscape::XML::Document *xml_doc, Inkscape /** * returns true when LPE was successful. */ -bool SPLPEItem::performPathEffect(SPCurve *curve, bool clip_paths) { +bool SPLPEItem::performPathEffect(SPCurve *curve, bool is_clip_or_mask) { if (!this) { return false; } @@ -217,7 +217,6 @@ bool SPLPEItem::performPathEffect(SPCurve *curve, bool clip_paths) { if (!curve) { return false; } - bool apply_to_clippath_and_mask = false; if (this->hasPathEffect() && this->pathEffectsEnabled()) { for (PathEffectList::iterator it = this->path_effect_list->begin(); it != this->path_effect_list->end(); ++it) { @@ -237,17 +236,13 @@ bool SPLPEItem::performPathEffect(SPCurve *curve, bool clip_paths) { g_warning("SPLPEItem::performPathEffect - lpeobj with invalid lpe in the stack!"); return false; } - if (lpe->isVisible()) { - if(lpe->apply_to_clippath_and_mask){ - apply_to_clippath_and_mask = true; - } if (lpe->acceptsNumClicks() > 0 && !lpe->isReady()) { // if the effect expects mouse input before being applied and the input is not finished // yet, we don't alter the path return false; } - if (clip_paths || lpe->apply_to_clippath_and_mask) { + if (!is_clip_or_mask || (is_clip_or_mask && lpe->apply_to_clippath_and_mask)) { // Groups have their doBeforeEffect called elsewhere if (!SP_IS_GROUP(this)) { lpe->doBeforeEffect_impl(this); @@ -270,10 +265,10 @@ bool SPLPEItem::performPathEffect(SPCurve *curve, bool clip_paths) { } } } - } - if(apply_to_clippath_and_mask && clip_paths){ - this->apply_to_clippath((SPItem *)this); - this->apply_to_mask((SPItem *)this); + if(!SP_IS_GROUP(this) && !is_clip_or_mask){ + this->apply_to_clippath(this); + this->apply_to_mask(this); + } } return true; } @@ -698,10 +693,10 @@ SPLPEItem::apply_to_clip_or_mask(SPItem *clip_mask, SPItem *item) try { if(SP_IS_GROUP(this)){ c->transform(i2anc_affine(SP_GROUP(item), SP_GROUP(this))); - success = this->performPathEffect(c, false); + success = this->performPathEffect(c, true); c->transform(i2anc_affine(SP_GROUP(item), SP_GROUP(this)).inverse()); } else { - success = this->performPathEffect(c, false); + success = this->performPathEffect(c, true); } } catch (std::exception & e) { g_warning("Exception during LPE execution. \n %s", e.what()); diff --git a/src/sp-lpe-item.h b/src/sp-lpe-item.h index d5e868b2e..9e5cb3329 100644 --- a/src/sp-lpe-item.h +++ b/src/sp-lpe-item.h @@ -69,7 +69,7 @@ public: virtual void update_patheffect(bool write); - bool performPathEffect(SPCurve *curve, bool clip_paths = true); + bool performPathEffect(SPCurve *curve, bool is_clip_or_mask = false); bool pathEffectsEnabled() const; bool hasPathEffect() const; diff --git a/src/sp-offset.cpp b/src/sp-offset.cpp index 7c3d0bd03..d84bdbdd3 100644 --- a/src/sp-offset.cpp +++ b/src/sp-offset.cpp @@ -83,7 +83,9 @@ static void sp_offset_source_modified (SPObject *iSource, guint flags, SPItem *i // fast is not mathematically correct, because computing the offset of a single // cubic bezier patch is not trivial; in particular, there are problems with holes // reappearing in offset when the radius becomes too large -static bool use_slow_but_correct_offset_method=true; +//TODO: need fix for bug: #384688 with fix released in r.14156 +//but reverted because bug #1507049 seems has more priority. +static bool use_slow_but_correct_offset_method = false; SPOffset::SPOffset() : SPShape() { this->rad = 1.0; diff --git a/src/sp-text.cpp b/src/sp-text.cpp index 4a5b1b1d6..6ae1c4fba 100644 --- a/src/sp-text.cpp +++ b/src/sp-text.cpp @@ -302,6 +302,15 @@ Inkscape::XML::Node *SPText::write(Inkscape::XML::Document *xml_doc, Inkscape::X this->attributes.writeTo(repr); this->rebuildLayout(); // copied from update(), see LP Bug 1339305 + // deprecated attribute, but keep it around for backwards compatibility + if (this->style->line_height.set && !this->style->line_height.inherit && !this->style->line_height.normal && this->style->line_height.unit == SP_CSS_UNIT_PERCENT) { + Inkscape::SVGOStringStream os; + os << (this->style->line_height.value * 100.0) << "%"; + this->getRepr()->setAttribute("sodipodi:linespacing", os.str().c_str()); + } else { + this->getRepr()->setAttribute("sodipodi:linespacing", NULL); + } + // SVG 2 Auto-wrapped text if( this->width.computed > 0.0 ) { sp_repr_set_svg_double(repr, "width", this->width.computed); @@ -636,6 +645,13 @@ void SPText::_adjustFontsizeRecursive(SPItem *item, double ex, bool is_root) style->font_size.computed *= ex; style->letter_spacing.computed *= ex; style->word_spacing.computed *= ex; + if (style->line_height.unit != SP_CSS_UNIT_NONE && + style->line_height.unit != SP_CSS_UNIT_PERCENT && + style->line_height.unit != SP_CSS_UNIT_EM && + style->line_height.unit != SP_CSS_UNIT_EX) { + // No unit on 'line-height' property has special behavior. + style->line_height.computed *= ex; + } item->updateRepr(); } @@ -819,8 +835,8 @@ void TextTagAttributes::setFirstXY(Geom::Point &point) attributes.x.resize(1, zero_length); if (attributes.y.empty()) attributes.y.resize(1, zero_length); - attributes.x[0].computed = point[Geom::X]; - attributes.y[0].computed = point[Geom::Y]; + attributes.x[0] = point[Geom::X]; + attributes.y[0] = point[Geom::Y]; } void TextTagAttributes::mergeInto(Inkscape::Text::Layout::OptionalTextTagAttrs *output, Inkscape::Text::Layout::OptionalTextTagAttrs const &parent_attrs, unsigned parent_attrs_offset, bool copy_xy, bool copy_dxdyrotate) const diff --git a/src/style.cpp b/src/style.cpp index 99beaed22..c24818f2a 100644 --- a/src/style.cpp +++ b/src/style.cpp @@ -113,7 +113,7 @@ SPStyle::SPStyle(SPDocument *document_in, SPObject *object_in) : font_weight( "font-weight", enum_font_weight, SP_CSS_FONT_WEIGHT_NORMAL, SP_CSS_FONT_WEIGHT_400 ), font_stretch( "font-stretch", enum_font_stretch, SP_CSS_FONT_STRETCH_NORMAL ), font_size(), - line_height( "line-height", 125 ), // SPILengthOrNormal + line_height( "line-height", 1.25 ), // SPILengthOrNormal font_family( "font-family", "sans-serif" ), // SPIString w/default font(), // SPIFont font_specification( "-inkscape-font-specification" ), // SPIString @@ -1510,7 +1510,8 @@ gchar const * sp_style_get_css_unit_string(int unit) { // specify px by default, see inkscape bug 1221626, mozilla bug 234789 - + // This is a problematic fix as some properties (e.g. 'line-height') have + // different behaviour if there is no unit. switch (unit) { case SP_CSS_UNIT_NONE: return "px"; @@ -1899,8 +1900,9 @@ sp_css_attr_scale_property_single(SPCSSAttr *css, gchar const *property, if (w == units) {// nothing converted, non-numeric value return; } - if (only_with_units && (units == NULL || *units == '\0' || *units == '%')) { + if (only_with_units && (units == NULL || *units == '\0' || *units == '%' || *units == 'e')) { // only_with_units, but no units found, so do nothing. + // 'e' matches 'em' or 'ex' return; } Inkscape::CSSOStringStream os; @@ -1957,7 +1959,7 @@ sp_css_attr_scale(SPCSSAttr *css, double ex) sp_css_attr_scale_property_single(css, "kerning", ex); sp_css_attr_scale_property_single(css, "letter-spacing", ex); sp_css_attr_scale_property_single(css, "word-spacing", ex); - //sp_css_attr_scale_property_single(css, "line-height", ex, true); + sp_css_attr_scale_property_single(css, "line-height", ex, true); return css; } diff --git a/src/svg/svg-length-test.h b/src/svg/svg-length-test.h index 0dac4854a..e73211ade 100644 --- a/src/svg/svg-length-test.h +++ b/src/svg/svg-length-test.h @@ -102,10 +102,7 @@ public: for ( int i = (static_cast<int>(SVGLength::NONE) + 1); i <= static_cast<int>(SVGLength::LAST_UNIT); i++ ) { SVGLength::Unit target = static_cast<SVGLength::Unit>(i); // PX is a special case where we don't have a unit string - // FOOT and MITRE are not CSS/SVG Units - if ( (target != SVGLength::PX) && - (target != SVGLength::FOOT) && - (target != SVGLength::MITRE) ) { + if ( (target != SVGLength::PX) ) { gchar const* val = sp_svg_length_get_css_units(target); TSM_ASSERT_DIFFERS(i, val, ""); } diff --git a/src/svg/svg-length.cpp b/src/svg/svg-length.cpp index cd995582d..d22da69cd 100644 --- a/src/svg/svg-length.cpp +++ b/src/svg/svg-length.cpp @@ -411,14 +411,6 @@ So after the number, the string does not necessarily have a \0 or a unit, it mig *computed = Inkscape::Util::Quantity::convert(v, "in", "px"); } break; - case UVAL('f','t'): - if (unit) { - *unit = SVGLength::FOOT; - } - if (computed) { - *computed = Inkscape::Util::Quantity::convert(v, "ft", "px"); - } - break; case UVAL('e','m'): if (unit) { *unit = SVGLength::EM; @@ -495,12 +487,6 @@ void SVGLength::set(SVGLength::Unit u, float v) case INCH: hack = "pt"; break; - case FOOT: - hack = "pt"; - break; - case MITRE: - hack = "m"; - break; default: break; } @@ -572,8 +558,6 @@ gchar const *sp_svg_length_get_css_units(SVGLength::Unit unit) case SVGLength::MM: return "mm"; case SVGLength::CM: return "cm"; case SVGLength::INCH: return "in"; - case SVGLength::FOOT: return ""; // Not in SVG/CSS specification. - case SVGLength::MITRE: return ""; // Not in SVG/CSS specification. case SVGLength::EM: return "em"; case SVGLength::EX: return "ex"; case SVGLength::PERCENT: return "%"; @@ -590,10 +574,6 @@ std::string sp_svg_length_write_with_units(SVGLength const &length) Inkscape::SVGOStringStream os; if (length.unit == SVGLength::PERCENT) { os << 100*length.value << sp_svg_length_get_css_units(length.unit); - } else if (length.unit == SVGLength::FOOT) { - os << 12*length.value << sp_svg_length_get_css_units(SVGLength::INCH); - } else if (length.unit == SVGLength::MITRE) { - os << 100*length.value << sp_svg_length_get_css_units(SVGLength::CM); } else { os << length.value << sp_svg_length_get_css_units(length.unit); } diff --git a/src/svg/svg-length.h b/src/svg/svg-length.h index 2aaf248b1..bd3435ca6 100644 --- a/src/svg/svg-length.h +++ b/src/svg/svg-length.h @@ -27,8 +27,6 @@ public: MM, CM, INCH, - FOOT, - MITRE, EM, EX, PERCENT, diff --git a/src/ui/clipboard.cpp b/src/ui/clipboard.cpp index f04d8a591..f0dc33740 100644 --- a/src/ui/clipboard.cpp +++ b/src/ui/clipboard.cpp @@ -759,7 +759,7 @@ void ClipboardManagerImpl::_copySelection(Inkscape::Selection *selection) void ClipboardManagerImpl::_copyUsedDefs(SPItem *item) { SPUse *use=dynamic_cast<SPUse *>(item); - if(use){ + if (use && use->get_original()) { if(cloned_elements.insert(use->get_original()).second) _copyUsedDefs(use->get_original()); } diff --git a/src/ui/control-manager.cpp b/src/ui/control-manager.cpp index cedaea405..a2c977533 100644 --- a/src/ui/control-manager.cpp +++ b/src/ui/control-manager.cpp @@ -54,9 +54,6 @@ ControlFlags& operator ^=(ControlFlags &lhs, ControlFlags rhs) } // namespace -#define FILL_COLOR_NORMAL 0xffffff7f -#define FILL_COLOR_MOUSEOVER 0xff0000ff - // Default color for line: #define LINE_COLOR_PRIMARY 0x0000ff7f #define LINE_COLOR_SECONDARY 0xff00007f @@ -83,6 +80,8 @@ public: bool setControlType(SPCanvasItem *item, ControlType type); + bool setControlResize(SPCanvasItem *item, int ctrlResize); + void setSelected(SPCanvasItem *item, bool selected); private: @@ -108,12 +107,13 @@ private: ControlManager &_manager; sigc::signal<void> _sizeChangedSignal; PrefListener _prefHook; - int _size; + int _size; // Size from the grabsize preference + int _resize; // Way size should change from grabsize std::vector<SPCanvasItem *> _itemList; std::map<Inkscape::ControlType, std::vector<int> > _sizeTable; std::map<Inkscape::ControlType, GType> _typeTable; std::map<Inkscape::ControlType, SPCtrlShapeType> _ctrlToShape; - std::set<Inkscape::ControlType> _sizeChangers; + std::set<Inkscape::ControlType> _resizeOnSelect; }; ControlManagerImpl::ControlManagerImpl(ControlManager &manager) : @@ -121,6 +121,7 @@ ControlManagerImpl::ControlManagerImpl(ControlManager &manager) : _sizeChangedSignal(), _prefHook(*this), _size(3), + _resize(3), _itemList(), _sizeTable() { @@ -153,10 +154,10 @@ ControlManagerImpl::ControlManagerImpl(ControlManager &manager) : // ------- - _sizeChangers.insert(CTRL_TYPE_NODE_AUTO); - _sizeChangers.insert(CTRL_TYPE_NODE_CUSP); - _sizeChangers.insert(CTRL_TYPE_NODE_SMOOTH); - _sizeChangers.insert(CTRL_TYPE_NODE_SYMETRICAL); + _resizeOnSelect.insert(CTRL_TYPE_NODE_AUTO); + _resizeOnSelect.insert(CTRL_TYPE_NODE_CUSP); + _resizeOnSelect.insert(CTRL_TYPE_NODE_SMOOTH); + _resizeOnSelect.insert(CTRL_TYPE_NODE_SYMETRICAL); // ------- @@ -234,7 +235,7 @@ SPCanvasItem *ControlManagerImpl::createControl(SPCanvasGroup *parent, ControlTy item = sp_canvas_item_new(parent, SP_TYPE_CTRL, "size", targetSize, "filled", 1, - "fill_color", FILL_COLOR_NORMAL, + "fill_color", 0xffffff7f, "stroked", 1, "stroke_color", 0x000000ff, NULL); @@ -284,11 +285,8 @@ sigc::connection ControlManagerImpl::connectCtrlSizeChanged(const sigc::slot<voi void ControlManagerImpl::updateItem(SPCanvasItem *item) { if (item) { - double target = _sizeTable[item->ctrlType][_size - 1]; + double target = _sizeTable[item->ctrlType][_size - 1] + item->ctrlResize; - if (_sizeChangers.count(item->ctrlType) && _manager.isSelected(item)) { - target += 2; - } g_object_set(item, "size", target, NULL); sp_canvas_item_request_update(item); @@ -303,11 +301,9 @@ bool ControlManagerImpl::setControlType(SPCanvasItem *item, ControlType type) accepted = true; } else if (item) { if (_ctrlToShape.count(type) && (_typeTable[type] == _typeTable[item->ctrlType])) { // compatible? - double targetSize = _sizeTable[type][_size - 1]; - if (_manager.isSelected(item) && _sizeChangers.count(item->ctrlType)) { - targetSize += 2.0; - } + double targetSize = _sizeTable[type][_size - 1] + item->ctrlResize; SPCtrlShapeType targetShape = _ctrlToShape[type]; + g_object_set(item, "shape", targetShape, "size", targetSize, NULL); item->ctrlType = type; accepted = true; @@ -317,17 +313,28 @@ bool ControlManagerImpl::setControlType(SPCanvasItem *item, ControlType type) return accepted; } +bool ControlManagerImpl::setControlResize(SPCanvasItem *item, int ctrlResize) +{ + if(item) { + item->ctrlResize = ctrlResize; + double targetSize = _sizeTable[item->ctrlType][_size - 1] + item->ctrlResize; + g_object_set(item, "size", targetSize, NULL); + return true; + } + return false; +} void ControlManagerImpl::setSelected(SPCanvasItem *item, bool selected) { if (_manager.isSelected(item) != selected) { item->ctrlFlags ^= CTRL_FLAG_SELECTED; // toggle, since we know it is different - // TODO refresh colors - double targetSize = _sizeTable[item->ctrlType][_size - 1]; - if (selected && _sizeChangers.count(item->ctrlType)) { - targetSize += 2.0; + if (selected && _resizeOnSelect.count(item->ctrlType)) { + item->ctrlResize = 2; } + + // TODO refresh colors + double targetSize = _sizeTable[item->ctrlType][_size - 1] + _resize; g_object_set(item, "size", targetSize, NULL); } } @@ -431,6 +438,11 @@ bool ControlManager::setControlType(SPCanvasItem *item, ControlType type) return _impl->setControlType(item, type); } +bool ControlManager::setControlResize(SPCanvasItem *item, int ctrlResize) +{ + return _impl->setControlResize(item, ctrlResize); +} + bool ControlManager::isActive(SPCanvasItem *item) const { return (item->ctrlFlags & CTRL_FLAG_ACTIVE) != 0; diff --git a/src/ui/control-manager.h b/src/ui/control-manager.h index 964ad0a29..3f090d0bd 100644 --- a/src/ui/control-manager.h +++ b/src/ui/control-manager.h @@ -63,6 +63,8 @@ public: bool setControlType(SPCanvasItem *item, ControlType type); + bool setControlResize(SPCanvasItem *item, int ctrlResize); + bool isActive(SPCanvasItem *item) const; void setActive(SPCanvasItem *item, bool active); diff --git a/src/ui/dialog/aboutbox.cpp b/src/ui/dialog/aboutbox.cpp index 81f48e6ef..b653a630d 100644 --- a/src/ui/dialog/aboutbox.cpp +++ b/src/ui/dialog/aboutbox.cpp @@ -120,10 +120,22 @@ AboutBox::AboutBox() : Gtk::Dialog(_("About Inkscape")) { label->set_selectable(true); label->show(); + Gtk::Label *link = new Gtk::Label(); + const gchar *website_link = + "<a href=\"https://www.inkscape.org\"> https://www.inkscape.org</a>"; + + link->set_markup(website_link); + link->set_alignment(Gtk::ALIGN_END); + link->set_padding(5,5); + link->set_selectable(true); + link->show(); + #if WITH_GTKMM_3_0 get_content_area()->pack_start(*manage(label), false, false); + get_content_area()->pack_start(*manage(link), false, false); #else get_vbox()->pack_start(*manage(label), false, false); + get_vbox()->pack_start(*manage(link), false, false); #endif Gtk::Requisition requisition; diff --git a/src/ui/draw-anchor.cpp b/src/ui/draw-anchor.cpp index 6b9a88ed7..c3bc5676d 100644 --- a/src/ui/draw-anchor.cpp +++ b/src/ui/draw-anchor.cpp @@ -78,6 +78,7 @@ SPDrawAnchor *sp_draw_anchor_test(SPDrawAnchor *anchor, Geom::Point w, bool acti if ( activate && ( Geom::LInfty( w - anchor->dc->getDesktop().d2w(anchor->dp) ) <= (ctrl->box.width() / 2.0) ) ) { if (!anchor->active) { + ControlManager::getManager().setControlResize(anchor->ctrl, 4); g_object_set(anchor->ctrl, "fill_color", FILL_COLOR_MOUSEOVER, NULL); anchor->active = TRUE; } @@ -85,9 +86,11 @@ SPDrawAnchor *sp_draw_anchor_test(SPDrawAnchor *anchor, Geom::Point w, bool acti } if (anchor->active) { + ControlManager::getManager().setControlResize(anchor->ctrl, 0); g_object_set(anchor->ctrl, "fill_color", FILL_COLOR_NORMAL, NULL); anchor->active = FALSE; } + return NULL; } diff --git a/src/ui/interface.cpp b/src/ui/interface.cpp index 69b229519..531aa728d 100644 --- a/src/ui/interface.cpp +++ b/src/ui/interface.cpp @@ -1786,7 +1786,7 @@ void ContextMenu::MakeItemMenu (void) /* Group */ mi = Gtk::manage(new Gtk::MenuItem(_("_Group"), 1)); mi->signal_activate().connect(sigc::mem_fun(*this, &ContextMenu::ActivateGroup)); - if (_desktop->selection->isEmpty() || _desktop->selection->single()) { + if (_desktop->selection->isEmpty()) { mi->set_sensitive(FALSE); } else { mi->set_sensitive(TRUE); diff --git a/src/ui/selected-color.cpp b/src/ui/selected-color.cpp index 8c37ee7e0..846d50a5b 100644 --- a/src/ui/selected-color.cpp +++ b/src/ui/selected-color.cpp @@ -139,7 +139,6 @@ void SelectedColor::setHeld(bool held) { if (released) { signal_released.emit(); - signal_changed.emit(); } _updating = false; } diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp index 4d28594c1..928355bc8 100644 --- a/src/ui/tool/path-manipulator.cpp +++ b/src/ui/tool/path-manipulator.cpp @@ -1485,7 +1485,6 @@ void PathManipulator::_getGeometry() void PathManipulator::_setGeometry() { using namespace Inkscape::LivePathEffect; - if (empty()) return; if (!_lpe_key.empty()) { // copied from nodepath.cpp @@ -1498,6 +1497,7 @@ void PathManipulator::_setGeometry() LIVEPATHEFFECT(_path)->requestModified(SP_OBJECT_MODIFIED_FLAG); } } else { + if (empty()) return; //XML Tree being used here directly while it shouldn't be. if (_path->getRepr()->attribute("inkscape:original-d")) _path->set_original_curve(_spcurve, false, false); diff --git a/src/ui/tools/pen-tool.cpp b/src/ui/tools/pen-tool.cpp index 2ed366a7d..18af8e105 100644 --- a/src/ui/tools/pen-tool.cpp +++ b/src/ui/tools/pen-tool.cpp @@ -1220,7 +1220,18 @@ bool PenTool::_handleKeyPress(GdkEvent *event) { case GDK_KEY_KP_Enter: if (this->npoints != 0) { this->ea = NULL; // unset end anchor if set (otherwise crashes) - this->_finish(false); + if(MOD__SHIFT_ONLY(event)) { + // All this is needed to stop the last control + // point dispeating and stop making an n-1 shape. + Geom::Point const p(0, 0); + if(this->red_curve->is_empty()) { + this->red_curve->moveto(p); + } + this->_finishSegment(p, 0); + this->_finish(true); + } else { + this->_finish(false); + } ret = true; } break; @@ -1783,12 +1794,12 @@ void PenTool::_setSubsequentPoint(Geom::Point const p, bool statusbar, guint sta if (statusbar) { gchar *message = is_curve ? - _("<b>Curve segment</b>: angle %3.2f°, distance %s; with <b>Ctrl</b> to snap angle, <b>Enter</b> to finish the path" ): - _("<b>Line segment</b>: angle %3.2f°, distance %s; with <b>Ctrl</b> to snap angle, <b>Enter</b> to finish the path"); + _("<b>Curve segment</b>: angle %3.2f°, distance %s; with <b>Ctrl</b> to snap angle, <b>Enter</b> or <b>Shift+Enter</b> to finish the path" ): + _("<b>Line segment</b>: angle %3.2f°, distance %s; with <b>Ctrl</b> to snap angle, <b>Enter</b> or <b>Shift+Enter</b> to finish the path"); if(this->spiro || this->bspline){ message = is_curve ? - _("<b>Curve segment</b>: angle %3.2f°, distance %s; with <b>Shift+Click</b> make a cusp node, <b>Enter</b> to finish the path" ): - _("<b>Line segment</b>: angle %3.2f°, distance %s; with <b>Shift+Click</b> make a cusp node, <b>Enter</b> to finish the path"); + _("<b>Curve segment</b>: angle %3.2f°, distance %s; with <b>Shift+Click</b> make a cusp node, <b>Enter</b> or <b>Shift+Enter</b> to finish the path" ): + _("<b>Line segment</b>: angle %3.2f°, distance %s; with <b>Shift+Click</b> make a cusp node, <b>Enter</b> or <b>Shift+Enter</b> to finish the path"); } this->_setAngleDistanceStatusMessage(p, 0, message); } diff --git a/src/ui/widget/color-wheel-selector.cpp b/src/ui/widget/color-wheel-selector.cpp index ed3400bb5..22c616325 100644 --- a/src/ui/widget/color-wheel-selector.cpp +++ b/src/ui/widget/color-wheel-selector.cpp @@ -245,22 +245,24 @@ void ColorWheelSelector::_wheelChanged(GimpColorWheel *wheel, ColorWheelSelector guint32 mid = color.toRGBA32(0x7f); guint32 end = color.toRGBA32(0xff); + wheelSelector->_updating = true; wheelSelector->_slider->setColors(start, mid, end); - wheelSelector->_color.preserveICC(); wheelSelector->_color.setHeld(gimp_color_wheel_is_adjusting(wheel)); wheelSelector->_color.setColor(color); + wheelSelector->_updating = false; } void ColorWheelSelector::_updateDisplay() { + if(_updating) { return; } + #ifdef DUMP_CHANGE_INFO g_message("ColorWheelSelector::_colorChanged( this=%p, %f, %f, %f, %f)", this, _color.color().v.c[0], _color.color().v.c[1], _color.color().v.c[2], alpha); #endif - bool oldval = _updating; _updating = true; { float hsv[3] = { 0, 0, 0 }; @@ -276,7 +278,7 @@ void ColorWheelSelector::_updateDisplay() ColorScales::setScaled(_alpha_adjustment->gobj(), _color.alpha()); - _updating = oldval; + _updating = false; } diff --git a/src/ui/widget/gimpcolorwheel.c b/src/ui/widget/gimpcolorwheel.c index f632331d8..c857cfa8a 100644 --- a/src/ui/widget/gimpcolorwheel.c +++ b/src/ui/widget/gimpcolorwheel.c @@ -1412,6 +1412,10 @@ gimp_color_wheel_set_color (GimpColorWheel *wheel, priv = wheel->priv; + if(h == 0.0 && s == 0.0) { + h = priv->h; + } + priv->h = h; priv->s = s; priv->v = v; diff --git a/src/ui/widget/preferences-widget.cpp b/src/ui/widget/preferences-widget.cpp index e906762e3..d56506d62 100644 --- a/src/ui/widget/preferences-widget.cpp +++ b/src/ui/widget/preferences-widget.cpp @@ -468,12 +468,8 @@ ZoomCorrRuler::on_draw(const Cairo::RefPtr<Cairo::Context>& cr) { Glib::ustring abbr = prefs->getString("/options/zoomcorrection/unit"); if (abbr == "cm") { draw_marks(cr, 0.1, 10); - } else if (abbr == "ft") { - draw_marks(cr, 1/12.0, 12); } else if (abbr == "in") { draw_marks(cr, 0.25, 4); - } else if (abbr == "m") { - draw_marks(cr, 1/10.0, 10); } else if (abbr == "mm") { draw_marks(cr, 10, 10); } else if (abbr == "pc") { diff --git a/src/ui/widget/unit-tracker.h b/src/ui/widget/unit-tracker.h index 0fe5bda80..8fa9ff304 100644 --- a/src/ui/widget/unit-tracker.h +++ b/src/ui/widget/unit-tracker.h @@ -42,8 +42,8 @@ public: Inkscape::Util::Unit const * getActiveUnit() const; void addUnit(Inkscape::Util::Unit const *u); - void prependUnit(Inkscape::Util::Unit const *u); void addAdjustment(GtkAdjustment *adj); + void prependUnit(Inkscape::Util::Unit const *u); void setFullVal(GtkAdjustment *adj, gdouble val); GtkAction *createAction(gchar const *name, gchar const *label, gchar const *tooltip); diff --git a/src/util/units.cpp b/src/util/units.cpp index 2e7a3b1d2..cf4bfd146 100644 --- a/src/util/units.cpp +++ b/src/util/units.cpp @@ -81,21 +81,7 @@ unsigned const svg_length_lookup[] = { UNIT_CODE_PERCENT }; -/* From SP_CSS_UNIT_* to unit */ -unsigned const sp_css_unit_lookup[] = { - 0, - UNIT_CODE_PX, - UNIT_CODE_PT, - UNIT_CODE_PC, - UNIT_CODE_MM, - UNIT_CODE_CM, - UNIT_CODE_IN, - UNIT_CODE_EM, - UNIT_CODE_EX, - UNIT_CODE_PERCENT - // UNIT_CODE_FT Missing, - // UNIT_CODE_MT Missing, -}; + // maps unit codes obtained from their abbreviations to their SVGLength unit indexes typedef INK_UNORDERED_MAP<unsigned, SVGLength::Unit> UnitCodeLookup; @@ -227,10 +213,6 @@ bool Unit::compatibleWith(Glib::ustring const &u) const { return compatibleWith(unit_table.getUnit(u)); } -bool Unit::compatibleWith(char const *u) const -{ - return compatibleWith(unit_table.getUnit(u)); -} bool Unit::operator==(Unit const &other) const { @@ -273,6 +255,8 @@ double Unit::convert(double from_dist, char const *to) const return convert(from_dist, unit_table.getUnit(to)); } + + Unit UnitTable::_empty_unit; UnitTable::UnitTable() @@ -323,19 +307,6 @@ Unit const *UnitTable::getUnit(SVGLength::Unit u) const } return &_empty_unit; } -/* SP_CSS_UNIT lookup */ -Unit const *UnitTable::getUnit(unsigned int u) const -{ - if (u == 0 || u > 9) { - return &_empty_unit; - } - - UnitCodeMap::const_iterator f = _unit_map.find(sp_css_unit_lookup[u]); - if (f != _unit_map.end()) { - return &(*f->second); - } - return &_empty_unit; -} Unit const *UnitTable::findUnit(double factor, UnitType type) const { diff --git a/src/util/units.h b/src/util/units.h index a840a37ec..fa70058ba 100644 --- a/src/util/units.h +++ b/src/util/units.h @@ -152,9 +152,6 @@ public: /** Retrieve a given unit based on its SVGLength unit */ Unit const *getUnit(SVGLength::Unit u) const; - - /** Retrieve a given unit based on its SP_CSS_UNIT */ - Unit const *getUnit(unsigned int u) const; /** Retrieve a quantity based on its string identifier */ Quantity parseQuantity(Glib::ustring const &q) const; diff --git a/src/verbs.cpp b/src/verbs.cpp index a78bde2f7..7b128c172 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -952,10 +952,6 @@ void EditVerb::perform(SPAction *action, void *data) g_return_if_fail(ensure_desktop_valid(action)); SPDesktop *dt = sp_action_get_desktop(action); - SPDocument *doc = dt->getDocument(); - - Inkscape::XML::Node *repr = dt->namedview->getRepr(); - switch (reinterpret_cast<std::size_t>(data)) { case SP_VERB_EDIT_UNDO: sp_undo(dt, dt->getDocument()); @@ -2949,7 +2945,7 @@ Verb *Verb::_base_verbs[] = { new DialogVerb(SP_VERB_DIALOG_TAGS, "DialogTags", N_("Selection se_ts..."), N_("View Tags"), INKSCAPE_ICON("edit-select-all-layers")), new DialogVerb(SP_VERB_DIALOG_LIVE_PATH_EFFECT, "DialogLivePathEffect", N_("Path E_ffects ..."), - N_("Manage, edit, and apply path effects"), NULL), + N_("Manage, edit, and apply path effects"), INKSCAPE_ICON("dialog-path-effects")), new DialogVerb(SP_VERB_DIALOG_FILTER_EFFECTS, "DialogFilterEffects", N_("Filter _Editor..."), N_("Manage, edit, and apply SVG filters"), INKSCAPE_ICON("dialog-filters")), new DialogVerb(SP_VERB_DIALOG_SVG_FONTS, "DialogSVGFonts", N_("SVG Font Editor..."), diff --git a/src/widgets/select-toolbar.cpp b/src/widgets/select-toolbar.cpp index 3cd6c0e28..9851b0606 100644 --- a/src/widgets/select-toolbar.cpp +++ b/src/widgets/select-toolbar.cpp @@ -437,58 +437,58 @@ void sp_select_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GOb // four spinbuttons eact = create_adjustment_action( - /* name= */ "XAction", - /* label= */ C_("Select toolbar", "X position"), - /* shortLabel= */ C_("Select toolbar", "X:"), - /* tooltip= */ C_("Select toolbar", "Horizontal coordinate of selection"), - /* path= */ "/tools/select/X", - /* def(default) */ 0.0, - /* focusTarget= */ GTK_WIDGET(desktop->canvas), - /* dataKludge= */ G_OBJECT(spw), - /* altx, altx_mark */ TRUE, "altx", - /* lower, uppper, step, page */ -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP, - /* descrLabels, descrValues, descrCount */ 0, 0, 0, - /* callback= */ sp_object_layout_any_value_changed, - /* unit_tracker= */ tracker, - /* climb, digits, factor */ SPIN_STEP, 3, 1); + "XAction", /* name */ + C_("Select toolbar", "X position"), /* label */ + C_("Select toolbar", "X:"), /* shortLabel */ + C_("Select toolbar", "Horizontal coordinate of selection"), /* tooltip */ + "/tools/select/X", /* path */ + 0.0, /* def(default) */ + GTK_WIDGET(desktop->canvas), /* focusTarget */ + G_OBJECT(spw), /* dataKludge */ + TRUE, "altx", /* altx, altx_mark */ + -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP, /* lower, uppper, step, page */ + 0, 0, 0, /* descrLabels, descrValues, descrCount */ + sp_object_layout_any_value_changed, /* callback */ + tracker, /* unit_tracker */ + SPIN_STEP, 3, 1); /* climb, digits, factor */ gtk_action_group_add_action( selectionActions, GTK_ACTION(eact) ); contextActions->push_back( GTK_ACTION(eact) ); eact = create_adjustment_action( - /* name= */ "YAction", - /* label= */ C_("Select toolbar", "Y position"), - /* shortLabel= */ C_("Select toolbar", "Y:"), - /* tooltip= */ C_("Select toolbar", "Vertical coordinate of selection"), - /* path= */ "/tools/select/Y", - /* def(default) */ 0.0, - /* focusTarget= */ GTK_WIDGET(desktop->canvas), - /* dataKludge= */ G_OBJECT(spw), - /* altx, altx_mark */ TRUE, "altx", - /* lower, uppper, step, page */ -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP, - /* descrLabels, descrValues, descrCount */ 0, 0, 0, - /* callback= */ sp_object_layout_any_value_changed, - /* unit_tracker= */ tracker, - /* climb, digits, factor */ SPIN_STEP, 3, 1); + "YAction", /* name */ + C_("Select toolbar", "Y position"), /* label */ + C_("Select toolbar", "Y:"), /* shortLabel */ + C_("Select toolbar", "Vertical coordinate of selection"), /* tooltip */ + "/tools/select/Y", /* path */ + 0.0, /* def(default) */ + GTK_WIDGET(desktop->canvas), /* focusTarget */ + G_OBJECT(spw), /* dataKludge */ + TRUE, "altx", /* altx, altx_mark */ + -1e6, 1e6, SPIN_STEP, SPIN_PAGE_STEP, /* lower, uppper, step, page */ + 0, 0, 0, /* descrLabels, descrValues, descrCount */ + sp_object_layout_any_value_changed, /* callback */ + tracker, /* unit_tracker */ + SPIN_STEP, 3, 1); /* climb, digits, factor */ gtk_action_group_add_action( selectionActions, GTK_ACTION(eact) ); contextActions->push_back( GTK_ACTION(eact) ); eact = create_adjustment_action( - /* name= */ "WidthAction", - /* label= */ C_("Select toolbar", "Width"), - /* shortLabel= */ C_("Select toolbar", "W:"), - /* tooltip= */ C_("Select toolbar", "Width of selection"), - /* path= */ "/tools/select/width", - /* def(default) */ 0.0, - /* focusTarget= */ GTK_WIDGET(desktop->canvas), - /* dataKludge= */ G_OBJECT(spw), - /* altx, altx_mark */ TRUE, "altx", - /* lower, uppper, step, page */ 0.0, 1e6, SPIN_STEP, SPIN_PAGE_STEP, - /* descrLabels, descrValues, descrCount */ 0, 0, 0, - /* callback= */ sp_object_layout_any_value_changed, - /* unit_tracker= */ tracker, - /* climb, digits, factor */ SPIN_STEP, 3, 1); + "WidthAction", /* name */ + C_("Select toolbar", "Width"), /* label */ + C_("Select toolbar", "W:"), /* shortLabel */ + C_("Select toolbar", "Width of selection"), /* tooltip */ + "/tools/select/width", /* path */ + 0.0, /* def(default) */ + GTK_WIDGET(desktop->canvas), /* focusTarget */ + G_OBJECT(spw), /* dataKludge */ + TRUE, "altx", /* altx, altx_mark */ + 0.0, 1e6, SPIN_STEP, SPIN_PAGE_STEP, /* lower, uppper, step, page */ + 0, 0, 0, /* descrLabels, descrValues, descrCount */ + sp_object_layout_any_value_changed, /* callback */ + tracker, /* unit_tracker */ + SPIN_STEP, 3, 1); /* climb, digits, factor */ gtk_action_group_add_action( selectionActions, GTK_ACTION(eact) ); contextActions->push_back( GTK_ACTION(eact) ); @@ -507,20 +507,21 @@ void sp_select_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GOb } eact = create_adjustment_action( - /* name= */ "HeightAction", - /* label= */ C_("Select toolbar", "Height"), - /* shortLabel= */ C_("Select toolbar", "H:"), - /* tooltip= */ C_("Select toolbar", "Height of selection"), - /* path= */ "/tools/select/height", - /* def(default) */ 0.0, - /* focusTarget= */ GTK_WIDGET(desktop->canvas), - /* dataKludge= */ G_OBJECT(spw), - /* altx, altx_mark */ TRUE, "altx", - /* lower, uppper, step, page */ 0.0, 1e6, SPIN_STEP, SPIN_PAGE_STEP, - /* descrLabels, descrValues, descrCount */ 0, 0, 0, - /* callback= */ sp_object_layout_any_value_changed, - /* unit_tracker= */ tracker, - /* climb, digits, factor */ SPIN_STEP, 3, 1); + "HeightAction", /* name */ + C_("Select toolbar", "Height"), /* label */ + C_("Select toolbar", "H:"), /* shortLabel */ + C_("Select toolbar", "Height of selection"), /* tooltip */ + "/tools/select/height", /* path */ + 0.0, /* def(default) */ + GTK_WIDGET(desktop->canvas), /* focusTarget */ + G_OBJECT(spw), /* dataKludge */ + TRUE, "altx", /* altx, altx_mark */ + 0.0, 1e6, SPIN_STEP, SPIN_PAGE_STEP, /* lower, uppper, step, page */ + 0, 0, 0, /* descrLabels, descrValues, descrCount */ + sp_object_layout_any_value_changed, /* callback */ + tracker, /* unit_tracker */ + SPIN_STEP, 3, 1); /* climb, digits, factor */ + gtk_action_group_add_action( selectionActions, GTK_ACTION(eact) ); contextActions->push_back( GTK_ACTION(eact) ); diff --git a/src/widgets/swatch-selector.cpp b/src/widgets/swatch-selector.cpp index 6f2807255..b9cce1d19 100644 --- a/src/widgets/swatch-selector.cpp +++ b/src/widgets/swatch-selector.cpp @@ -37,10 +37,11 @@ SwatchSelector::SwatchSelector() : color_selector->show(); pack_start(*color_selector); - _selected_color.signal_grabbed.connect(sigc::mem_fun(this, &SwatchSelector::_grabbedCb)); - _selected_color.signal_dragged.connect(sigc::mem_fun(this, &SwatchSelector::_draggedCb)); - _selected_color.signal_released.connect(sigc::mem_fun(this, &SwatchSelector::_releasedCb)); - _selected_color.signal_changed.connect(sigc::mem_fun(this, &SwatchSelector::_changedCb)); + //_selected_color.signal_grabbed.connect(sigc::mem_fun(this, &SwatchSelector::_grabbedCb)); + _selected_color.signal_dragged.connect(sigc::mem_fun(this, &SwatchSelector::_changedCb)); + _selected_color.signal_released.connect(sigc::mem_fun(this, &SwatchSelector::_changedCb)); + // signal_changed doesn't get called if updating shape with colour. + //_selected_color.signal_changed.connect(sigc::mem_fun(this, &SwatchSelector::_changedCb)); } SwatchSelector::~SwatchSelector() @@ -53,45 +54,6 @@ SPGradientSelector *SwatchSelector::getGradientSelector() return _gsel; } -void SwatchSelector::_grabbedCb() -{ -} - -void SwatchSelector::_draggedCb() -{ - // if (data) { - //SwatchSelector *swsel = reinterpret_cast<SwatchSelector*>(data); - - // TODO might have to block cycles - - // Copied from gradient-vector.cpp, but does not appear to cause visible changes: - /* - if (swsel->_gsel) { - SPGradient *gradient = swsel->_gsel->getVector(); - SPGradient *ngr = sp_gradient_ensure_vector_normalized(gradient); - if (ngr != gradient) { - // Our master gradient has changed - // TODO replace with proper - sp_gradient_vector_widget_load_gradient(GTK_WIDGET(swsel->_gsel), ngr); - } - - sp_gradient_ensure_vector(ngr); - - - SPStop* stop = ngr->getFirstStop(); - if (stop) { - swsel->_csel->base->getColorAlpha(stop->specified_color, &stop->opacity); - stop->currentColor = false; - // TODO push refresh - } - } - */ - // } -} - -void SwatchSelector::_releasedCb() -{ -} - void SwatchSelector::_changedCb() { if (_updating_color) { diff --git a/src/widgets/text-toolbar.cpp b/src/widgets/text-toolbar.cpp index 60e932338..e71c911bd 100644 --- a/src/widgets/text-toolbar.cpp +++ b/src/widgets/text-toolbar.cpp @@ -62,9 +62,10 @@ using Inkscape::DocumentUndo; using Inkscape::UI::ToolboxFactory; using Inkscape::UI::PrefPusher; -using Inkscape::UI::Widget::UnitTracker; using Inkscape::Util::Unit; +using Inkscape::Util::Quantity; using Inkscape::Util::unit_table; +using Inkscape::UI::Widget::UnitTracker; //#define DEBUG_TEXT @@ -509,48 +510,54 @@ static void sp_text_align_mode_changed( EgeSelectOneAction *act, GObject *tbl ) static void sp_text_lineheight_value_changed( GtkAdjustment *adj, GObject *tbl ) { - UnitTracker *tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(tbl, "tracker")); - - if ( !tracker || tracker->isUpdating() || g_object_get_data(tbl, "freeze")) { - /* - * When only units are being changed, don't treat changes - * to adjuster values as object changes. - * or quit if run by the _changed callbacks - */ + // 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) ); - // At the moment this handles only numerical values (i.e. no percent). - // Set css line height. - SPCSSAttr *css = sp_repr_css_attr_new (); - Inkscape::CSSOStringStream osfs; - - gdouble value = gtk_adjustment_get_value(adj); + // Get user selected unit and save as preference + UnitTracker *tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(tbl, "tracker")); Unit const *unit = tracker->getActiveUnit(); + g_return_if_fail(unit != NULL); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + + // This nonsense is to get SP_CSS_UNIT_xx value corresponding to unit so + // we can save it (allows us to adjust line height value when unit changes). + SPILength temp_length; + Inkscape::CSSOStringStream temp_stream; + temp_stream << 1 << unit->abbr; + temp_length.read(temp_stream.str().c_str()); + prefs->setInt("/tools/text/lineheight/display_unit", temp_length.unit); + g_object_set_data( tbl, "lineheight_unit", GINT_TO_POINTER(temp_length.unit)); - // Value can only be in px or percent or naked pc (e.g. 0.7 for 70%) - if (unit->abbr != "%") { - value = unit->convert(value, "px"); - unit = unit_table.getUnit("px"); - } - osfs << value << unit->abbr; + // Set css line height. + SPCSSAttr *css = sp_repr_css_attr_new (); + Inkscape::CSSOStringStream osfs; + // We should handle unitless values as well as 'em' and 'ex' + if ((unit->abbr) == "em" || unit->abbr == "ex" || unit->abbr == "%") { + osfs << gtk_adjustment_get_value(adj) << unit->abbr; + } else { + // Inside SVG file, always use "px" for absolute units. + osfs << Quantity::convert(gtk_adjustment_get_value(adj), unit, "px") << "px"; + } sp_repr_css_set_property (css, "line-height", osfs.str().c_str()); + // Apply line-height to selected objects. SPDesktop *desktop = SP_ACTIVE_DESKTOP; sp_desktop_set_style (desktop, css, true, false); - // Until deprecated sodipodi:linespacing purged: + // Only need to save for undo if a text item has been changed. Inkscape::Selection *selection = desktop->getSelection(); bool modmade = false; std::vector<SPItem*> itemlist=selection->itemList(); for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end(); ++i){ if (SP_IS_TEXT (*i)) { - (*i)->getRepr()->setAttribute("sodipodi:linespacing", sp_repr_css_property (css, "line-height", NULL)); modmade = true; } } @@ -576,6 +583,156 @@ static void sp_text_lineheight_value_changed( GtkAdjustment *adj, GObject *tbl ) g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); } + +static void sp_text_lineheight_unit_changed( gpointer /* */, 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) ); + + // Get old saved unit + int old_unit = GPOINTER_TO_INT( g_object_get_data(tbl, "lineheight_unit")); + + // Get user selected unit and save as preference + UnitTracker *tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(tbl, "tracker")); + Unit const *unit = tracker->getActiveUnit(); + g_return_if_fail(unit != NULL); + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + + // This nonsense is to get SP_CSS_UNIT_xx value corresponding to unit. + SPILength temp_length; + Inkscape::CSSOStringStream temp_stream; + temp_stream << 1 << unit->abbr; + temp_length.read(temp_stream.str().c_str()); + prefs->setInt("/tools/text/lineheight/display_unit", temp_length.unit); + g_object_set_data( tbl, "lineheight_unit", GINT_TO_POINTER(temp_length.unit)); + + // Read current line height value + EgeAdjustmentAction *line_height_act = + reinterpret_cast<EgeAdjustmentAction *>(g_object_get_data(tbl, "TextLineHeightAction")); + GtkAdjustment *line_height_adj = ege_adjustment_action_get_adjustment( line_height_act ); + double line_height = gtk_adjustment_get_value(line_height_adj); + + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + Inkscape::Selection *selection = desktop->getSelection(); + std::vector<SPItem*> itemlist=selection->itemList(); + + // Convert between units + if ((unit->abbr) == "em" && old_unit == SP_CSS_UNIT_EX) { + line_height *= 0.5; + } else if ((unit->abbr) == "ex" && old_unit == SP_CSS_UNIT_EM) { + line_height *= 2.0; + } else if ((unit->abbr) == "em" && old_unit == SP_CSS_UNIT_PERCENT) { + line_height /= 100.0; + } else if ((unit->abbr) == "%" && old_unit == SP_CSS_UNIT_EM) { + line_height *= 100; + } else if ((unit->abbr) == "ex" && old_unit == SP_CSS_UNIT_PERCENT) { + line_height /= 50.0; + } else if ((unit->abbr) == "%" && old_unit == SP_CSS_UNIT_EX) { + line_height *= 50; + } else if ((unit->abbr) == "%" || (unit->abbr) == "em" || (unit->abbr) == "ex") { + // Convert absolute to relative... for the moment use average font-size + double font_size = 0; + int count = 0; + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end(); ++i){ + if (SP_IS_TEXT (*i)) { + double doc_scale = Geom::Affine((*i)->i2dt_affine()).descrim(); + font_size += (*i)->style->font_size.computed * doc_scale; + ++count; + } + } + if (count > 0) { + font_size /= count; + } else { + font_size = 20; + } + line_height = Quantity::convert(line_height, sp_style_get_css_unit_string(old_unit), "px"); + if (font_size > 0) { + line_height /= font_size; + } + if ((unit->abbr) == "%") { + line_height *= 100; + } else if ((unit->abbr) == "ex") { + line_height *= 2; + } + } else if (old_unit==SP_CSS_UNIT_PERCENT || old_unit==SP_CSS_UNIT_EM || old_unit==SP_CSS_UNIT_EX) { + // Convert relative to absolute... for the moment use average font-size + double font_size = 0; + int count = 0; + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end(); ++i){ + if (SP_IS_TEXT (*i)) { + double doc_scale = Geom::Affine((*i)->i2dt_affine()).descrim(); + font_size += (*i)->style->font_size.computed * doc_scale; + ++count; + } + } + if (count > 0) { + font_size /= count; + } else { + font_size = 20; + } + + if (old_unit == SP_CSS_UNIT_PERCENT) { + line_height /= 100.0; + } else if (old_unit == SP_CSS_UNIT_EX) { + line_height /= 2.0; + } + line_height *= font_size; + line_height = Quantity::convert(line_height, "px", unit); + } else { + // Convert between different absolute units (only used in GUI) + line_height = Quantity::convert(line_height, sp_style_get_css_unit_string(old_unit), unit); + } + + // Set css line height. + SPCSSAttr *css = sp_repr_css_attr_new (); + Inkscape::CSSOStringStream osfs; + // We should handle unitless values as well as 'em' and 'ex' + if ((unit->abbr) == "em" || unit->abbr == "ex" || unit->abbr == "%") { + osfs << line_height << unit->abbr; + } else { + osfs << Quantity::convert(line_height, unit, "px") << "px"; + } + sp_repr_css_set_property (css, "line-height", osfs.str().c_str()); + + // Update GUI with line_height value. + gtk_adjustment_set_value(line_height_adj, line_height); + + // Apply line-height to selected objects. + sp_desktop_set_style (desktop, css, true, false); + + // Only need to save for undo if a text item has been changed. + bool modmade = false; + for(std::vector<SPItem*>::const_iterator i=itemlist.begin();i!=itemlist.end(); ++i){ + if (SP_IS_TEXT (*i)) { + modmade = true; + } + } + + // Save for undo + if(modmade) { + DocumentUndo::maybeDone(SP_ACTIVE_DESKTOP->getDocument(), "ttb:line-height", SP_VERB_NONE, + _("Text: Change line-height unit")); + } + + // If no selected objects, set default. + SPStyle query(SP_ACTIVE_DOCUMENT); + int result_numbers = + sp_desktop_query_style (SP_ACTIVE_DESKTOP, &query, QUERY_STYLE_PROPERTY_FONTNUMBERS); + if (result_numbers == QUERY_STYLE_NOTHING) + { + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + prefs->mergeStyle("/tools/text/style", css); + } + + sp_repr_css_attr_unref (css); + + g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); +} + + static void sp_text_wordspacing_value_changed( GtkAdjustment *adj, GObject *tbl ) { // quit if run by the _changed callbacks @@ -1086,6 +1243,7 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/ { activeButton = 3; } else { + // This should take 'direction' into account if (query.text_anchor.computed == SP_CSS_TEXT_ANCHOR_START) activeButton = 0; if (query.text_anchor.computed == SP_CSS_TEXT_ANCHOR_MIDDLE) activeButton = 1; if (query.text_anchor.computed == SP_CSS_TEXT_ANCHOR_END) activeButton = 2; @@ -1093,36 +1251,58 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/ ege_select_one_action_set_active( textAlignAction, activeButton ); - // Line height (spacing) + // Line height (spacing) and line height unit double height; - - Unit const *lh_unit; - UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) ); - + int line_height_unit = -1; if (query.line_height.normal) { - lh_unit = unit_table.getUnit("%"); - height = Inkscape::Text::Layout::LINE_HEIGHT_NORMAL * 100; - } else if (query.line_height.unit == SP_CSS_UNIT_PERCENT) { - lh_unit = unit_table.getUnit("%"); - height = query.line_height.value * 100; + height = Inkscape::Text::Layout::LINE_HEIGHT_NORMAL; + line_height_unit = SP_CSS_UNIT_NONE; } else { - //Unit const *active = tracker->getActiveUnit(); - // This allows us to show the unit stored to the user, but right now - // it's always px (because Tav said other units are broken/2016) - lh_unit = unit_table.getUnit(query.line_height.unit); - height = query.line_height.computed; + height = query.line_height.value; + line_height_unit = query.line_height.unit; } - // Set before value is set - tracker->setActiveUnit(lh_unit); + switch (line_height_unit) { + case SP_CSS_UNIT_NONE: + // tracker can't show no unit... use 'em' + line_height_unit = SP_CSS_UNIT_EM; + case SP_CSS_UNIT_EM: + case SP_CSS_UNIT_EX: + break; + case SP_CSS_UNIT_PERCENT: + height *= 100.0; // Inkscape store % as fraction in .value + break; + case SP_CSS_UNIT_PX: + // If unit is set to 'px', use the preferred display unit (if absolute). + line_height_unit = + prefs->getInt("/tools/text/lineheight/display_unit", SP_CSS_UNIT_PT); + if (line_height_unit != SP_CSS_UNIT_EM && + line_height_unit != SP_CSS_UNIT_EX && + line_height_unit != SP_CSS_UNIT_PERCENT) { + height = + Quantity::convert(height, "px", sp_style_get_css_unit_string(line_height_unit)); + } else { + line_height_unit = SP_CSS_UNIT_PX; + } + break; + default: + // If unit has been set by an external program to something other than 'px', use + // that unit. But height is average of computed values (px) so we need to convert + // back. + height = + Quantity::convert(height, "px", sp_style_get_css_unit_string(line_height_unit)); + } GtkAction* lineHeightAction = GTK_ACTION( g_object_get_data( tbl, "TextLineHeightAction" ) ); GtkAdjustment *lineHeightAdjustment = ege_adjustment_action_get_adjustment(EGE_ADJUSTMENT_ACTION( lineHeightAction )); gtk_adjustment_set_value( lineHeightAdjustment, height ); - height = gtk_adjustment_get_value( lineHeightAdjustment ); - + UnitTracker* tracker = reinterpret_cast<UnitTracker*>( g_object_get_data( tbl, "tracker" ) ); + tracker->setActiveUnitByAbbr(sp_style_get_css_unit_string(line_height_unit)); + // Save unit so we can do convertions between new/old units. + g_object_set_data( tbl, "lineheight_unit", GINT_TO_POINTER(line_height_unit)); + // Word spacing double wordSpacing; if (query.word_spacing.normal) wordSpacing = 0.0; @@ -1265,7 +1445,6 @@ static void sp_text_toolbox_selection_changed(Inkscape::Selection */*selection*/ #endif g_object_set_data( tbl, "freeze", GINT_TO_POINTER(FALSE) ); - } static void sp_text_toolbox_selection_modified(Inkscape::Selection *selection, guint /*flags*/, GObject *tbl) @@ -1324,15 +1503,6 @@ static void sp_text_toolbox_select_cb( GtkEntry* entry, GtkEntryIconPosition /*p static void text_toolbox_watch_ec(SPDesktop* dt, Inkscape::UI::Tools::ToolBase* ec, GObject* holder); -static void destroy_tracker( GObject* obj, gpointer /*user_data*/ ) -{ - UnitTracker *tracker = reinterpret_cast<UnitTracker*>(g_object_get_data(obj, "tracker")); - if ( tracker ) { - delete tracker; - g_object_set_data( obj, "tracker", 0 ); - } -} - // Define all the "widgets" in the toolbar. void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObject* holder) { @@ -1625,47 +1795,52 @@ void sp_text_toolbox_prep(SPDesktop *desktop, GtkActionGroup* mainActions, GObje g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_text_orientation_changed), holder ); } + /* Line height unit tracker */ + UnitTracker* tracker = new UnitTracker(Inkscape::Util::UNIT_TYPE_LINEAR); + tracker->addUnit(unit_table.getUnit("%")); + tracker->addUnit(unit_table.getUnit("em")); + tracker->addUnit(unit_table.getUnit("ex")); + // tracker->addUnit(unit_table.getUnit("None")); + tracker->setActiveUnit(unit_table.getUnit("%")); + g_object_set_data( holder, "tracker", tracker ); + /* Line height */ { // Drop down menu gchar const* labels[] = {_("Smaller spacing"), 0, 0, 0, 0, C_("Text tool", "Normal"), 0, 0, 0, 0, 0, _("Larger spacing")}; gdouble values[] = { 0.5, 0.6, 0.7, 0.8, 0.9, 1.0, 1.1, 1,2, 1.3, 1.4, 1.5, 2.0}; - // Add the units menu. - UnitTracker* tracker = new UnitTracker(Inkscape::Util::UNIT_TYPE_LINEAR); - tracker->prependUnit(unit_table.getUnit("%")); - - g_object_set_data( holder, "tracker", tracker ); - g_signal_connect( holder, "destroy", G_CALLBACK(destroy_tracker), holder ); - EgeAdjustmentAction *eact = create_adjustment_action( "TextLineHeightAction", /* name */ _("Line Height"), /* label */ _("Line:"), /* short label */ - _("Spacing between baselines"), /* tooltip */ + _("Spacing between baselines (times font size)"), /* tooltip */ "/tools/text/lineheight", /* preferences path */ - 125, /* default */ + 0.0, /* default */ GTK_WIDGET(desktop->canvas), /* focusTarget */ holder, /* dataKludge */ FALSE, /* set alt-x keyboard shortcut? */ NULL, /* altx_mark */ - 0.0, 1e6, 1.0, 10.0, /* lower, upper, step (arrow up/down), page up/down */ + 0.0, 1000.0, 1.0, 10.0, /* lower, upper, step (arrow up/down), page up/down */ labels, values, G_N_ELEMENTS(labels), /* drop down menu */ sp_text_lineheight_value_changed, /* callback */ - tracker, /* unit tracker */ - 1.0, /* step (used?) */ + NULL, // tracker, /* unit tracker */ + 0.1, /* step (used?) */ 2, /* digits to show */ 1.0 /* factor (multiplies default) */ ); + //tracker->addAdjustment( ege_adjustment_action_get_adjustment(eact) ); gtk_action_group_add_action( mainActions, GTK_ACTION(eact) ); gtk_action_set_sensitive( GTK_ACTION(eact), TRUE ); g_object_set_data( holder, "TextLineHeightAction", eact ); g_object_set( G_OBJECT(eact), "iconId", "text_line_spacing", NULL ); + } - GtkAction* act = tracker->createAction( "TextLineHeightUnitAction", _("Units"), ("") ); + /* Line height units */ + { + GtkAction* act = tracker->createAction( "TextLineHeightUnitsAction", _("Units"), ("") ); gtk_action_group_add_action( mainActions, act ); - g_object_set_data( holder, "TextLineHeightUnitAction", act ); - + g_signal_connect_after( G_OBJECT(act), "changed", G_CALLBACK(sp_text_lineheight_unit_changed), holder ); } /* Word spacing */ diff --git a/src/widgets/toolbox.cpp b/src/widgets/toolbox.cpp index f4d7ebf25..3389f82f9 100644 --- a/src/widgets/toolbox.cpp +++ b/src/widgets/toolbox.cpp @@ -516,7 +516,7 @@ static gchar const * ui_descr = " <toolitem action='TextSubscriptAction' />" " <separator />" " <toolitem action='TextLineHeightAction' />" - " <toolitem action='TextLineHeightUnitAction' />" + " <toolitem action='TextLineHeightUnitsAction' />" " <toolitem action='TextLetterSpacingAction' />" " <toolitem action='TextWordSpacingAction' />" " <toolitem action='TextDxAction' />" @@ -1126,7 +1126,7 @@ EgeAdjustmentAction * create_adjustment_action( gchar const *name, if (unit_tracker) { unit_tracker->addAdjustment(adj); - } + } // Using a cast just to make sure we pass in the right kind of function pointer g_object_set( G_OBJECT(act), "tool-post", static_cast<EgeWidgetFixup>(sp_set_font_size_smaller), NULL ); |
