From 66e9382175c3fb844d19b23f9d278a603f527d5e Mon Sep 17 00:00:00 2001 From: chr Date: Thu, 18 May 2017 19:58:59 +0200 Subject: bugfix crash while moving objects sp_svg_transform_write can return NULL and Glib::ustring blows up: terminate called after throwing an instance of 'std::logic_error' what(): basic_string::_S_construct null not valid #0 0x00007fffed6ec067 in raise () from /lib/x86_64-linux-gnu/libc.so.6 #1 0x00007fffed6ed448 in abort () from /lib/x86_64-linux-gnu/libc.so.6 #2 0x00007fffedac2b3d in __gnu_cxx::__verbose_terminate_handler() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 #3 0x00007fffedac0bb6 in ?? () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 #4 0x00007fffedac0c01 in std::terminate() () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 #5 0x00007fffedac0e19 in __cxa_throw () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 #6 0x00007fffedb168b6 in std::__throw_logic_error(char const*) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 #7 0x00007ffff76e83d5 in char* std::string::_S_construct(char const*, char const*, std::allocator const&, std::forward_iterator_tag) () from /usr/bin/../lib/inkscape/libinkscape_base.so #8 0x00007fffedb22c46 in std::basic_string, std::allocator >::basic_string(char const*, std::allocator const&) () from /usr/lib/x86_64-linux-gnu/libstdc++.so.6 #9 0x00007ffff036055e in Glib::ustring::ustring(char const*) () from /usr/lib/x86_64-linux-gnu/libglibmm-2.4.so.1 #10 0x00007ffff75650e3 in SPPattern::transform_multiply(Geom::Affine, bool) () from /usr/bin/../lib/inkscape/libinkscape_base.so #11 0x00007ffff753d862 in SPItem::adjust_pattern(Geom::Affine const&, bool, PatternTransform) () from /usr/bin/../lib/inkscape/libinkscape_base.so #12 0x00007ffff7562897 in SPPath::set_transform(Geom::Affine const&) () from /usr/bin/../lib/inkscape/libinkscape_base.so (bzr r15698.1.1) --- src/sp-pattern.cpp | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) (limited to 'src') diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index 377c035fc..fcfdf552e 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -372,8 +372,9 @@ void SPPattern::transform_multiply(Geom::Affine postmul, bool set) } _pattern_transform_set = true; - Glib::ustring c = sp_svg_transform_write(_pattern_transform); + gchar *c = sp_svg_transform_write(_pattern_transform); getRepr()->setAttribute("patternTransform", c); + g_free(c); } const gchar *SPPattern::produce(const std::vector &reprs, Geom::Rect bounds, @@ -390,7 +391,7 @@ const gchar *SPPattern::produce(const std::vector &reprs, sp_repr_set_svg_double(repr, "height", bounds.dimensions()[Geom::Y]); //TODO: Maybe is better handle it in sp_svg_transform_write if(transform != Geom::Affine()){ - Glib::ustring t = sp_svg_transform_write(transform); + gchar *t = sp_svg_transform_write(transform); repr->setAttribute("patternTransform", t); } defsrepr->appendChild(repr); -- cgit v1.2.3 From 6c05c1c14cb8d29fb06d6779ec9817615c518ab5 Mon Sep 17 00:00:00 2001 From: chr Date: Thu, 18 May 2017 19:58:59 +0200 Subject: fix a brunch of memory leaks (bzr r15698.1.2) --- src/live_effects/lpe-bspline.cpp | 1 + src/live_effects/parameter/path.cpp | 3 ++- src/path-chemistry.cpp | 3 ++- src/selection-chemistry.cpp | 7 +++++-- src/sp-item-group.cpp | 1 + src/sp-pattern.cpp | 1 + 6 files changed, 12 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/live_effects/lpe-bspline.cpp b/src/live_effects/lpe-bspline.cpp index 5c227e68a..dbd67beda 100644 --- a/src/live_effects/lpe-bspline.cpp +++ b/src/live_effects/lpe-bspline.cpp @@ -168,6 +168,7 @@ void LPEBSpline::changeWeight(double weight_ammount) doBSplineFromWidget(curve, weight_ammount/100.0); gchar *str = sp_svg_write_path(curve->get_pathvector()); path->getRepr()->setAttribute("inkscape:original-d", str); + g_free(str); } } diff --git a/src/live_effects/parameter/path.cpp b/src/live_effects/parameter/path.cpp index aa87508ab..6e90c9279 100644 --- a/src/live_effects/parameter/path.cpp +++ b/src/live_effects/parameter/path.cpp @@ -245,8 +245,9 @@ PathParam::param_editOncanvas(SPItem *item, SPDesktop * dt) r.lpe_key = param_key; Geom::PathVector stored_pv = _pathvector; param_write_to_repr("M0,0 L1,0"); - const char *svgd = sp_svg_write_path(stored_pv); + gchar *svgd = sp_svg_write_path(stored_pv); param_write_to_repr(svgd); + g_free(svgd); } else { r.item = ref.getObject(); } diff --git a/src/path-chemistry.cpp b/src/path-chemistry.cpp index b66bcf368..7840c4ca8 100644 --- a/src/path-chemistry.cpp +++ b/src/path-chemistry.cpp @@ -255,8 +255,9 @@ ObjectSet::breakApart(bool skip_undo) repr->setAttribute("inkscape:original-d", str); else repr->setAttribute("d", str); + str = sp_svg_transform_write(transform); + repr->setAttribute("transform", 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/selection-chemistry.cpp b/src/selection-chemistry.cpp index 5d585ab5d..39846ba2c 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -3175,8 +3175,11 @@ void ObjectSet::toSymbol() the_parent_repr->appendChild(clone); if( single_group && transform.isTranslation() ) { - if( !transform.isIdentity() ) - clone->setAttribute("transform", sp_svg_transform_write( transform )); + if( !transform.isIdentity() ) { + gchar *c = sp_svg_transform_write( transform ); + clone->setAttribute("transform", c); + g_free(c); + } } // Change selection to new element. diff --git a/src/sp-item-group.cpp b/src/sp-item-group.cpp index f2c0d2f2c..88b2bb1f9 100644 --- a/src/sp-item-group.cpp +++ b/src/sp-item-group.cpp @@ -594,6 +594,7 @@ sp_item_group_ungroup (SPGroup *group, std::vector &children, bool do_d Geom::Affine ttrans = ctrans.inverse() * SP_ITEM(text)->transform * ctrans; gchar *affinestr = sp_svg_transform_write(ttrans); nrepr->setAttribute("transform", affinestr); + g_free(affinestr); } } else { nrepr->setAttribute("transform", affinestr); diff --git a/src/sp-pattern.cpp b/src/sp-pattern.cpp index fcfdf552e..1e198506b 100644 --- a/src/sp-pattern.cpp +++ b/src/sp-pattern.cpp @@ -393,6 +393,7 @@ const gchar *SPPattern::produce(const std::vector &reprs, if(transform != Geom::Affine()){ gchar *t = sp_svg_transform_write(transform); repr->setAttribute("patternTransform", t); + g_free(t); } defsrepr->appendChild(repr); const gchar *pat_id = repr->attribute("id"); -- cgit v1.2.3 From ff2d6ce5f8ed0d8fb9bcf014d9c00c4e71b83e5b Mon Sep 17 00:00:00 2001 From: chr Date: Thu, 18 May 2017 19:58:59 +0200 Subject: stroke-style: fix preloading no-marker speed up inkscape startup (bzr r15698.1.3) --- src/widgets/stroke-marker-selector.cpp | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/widgets/stroke-marker-selector.cpp b/src/widgets/stroke-marker-selector.cpp index b0c23a88c..3f81bef5c 100644 --- a/src/widgets/stroke-marker-selector.cpp +++ b/src/widgets/stroke-marker-selector.cpp @@ -54,8 +54,13 @@ MarkerComboBox::MarkerComboBox(gchar const *id, int l) : set_cell_data_func(image_renderer, sigc::mem_fun(*this, &MarkerComboBox::prepareImageRenderer)); gtk_combo_box_set_row_separator_func(GTK_COMBO_BOX(gobj()), MarkerComboBox::separator_cb, NULL, NULL); + Glib::ustring no_marker("no-marker"); + Glib::RefPtr iconTheme = Gtk::IconTheme::get_default(); + if (!iconTheme->has_icon(no_marker)) { + Inkscape::queueIconPrerender( INKSCAPE_ICON(no_marker.data()), Inkscape::ICON_SIZE_SMALL_TOOLBAR ); + } empty_image = new Gtk::Image( Glib::wrap( - sp_pixbuf_new( Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON("no-marker") ) ) ); + sp_pixbuf_new( Inkscape::ICON_SIZE_SMALL_TOOLBAR, INKSCAPE_ICON(no_marker.data()) ) ) ); sandbox = ink_markers_preview_doc (); desktop = SP_ACTIVE_DESKTOP; @@ -71,6 +76,7 @@ MarkerComboBox::MarkerComboBox(gchar const *id, int l) : MarkerComboBox::~MarkerComboBox() { delete combo_id; delete sandbox; + delete empty_image; if (doc) { modified_connection.disconnect(); @@ -393,7 +399,7 @@ void MarkerComboBox::add_markers (GSList *marker_list, SPDocument *source, gbool gchar const *markid = repr->attribute("inkscape:stockid") ? repr->attribute("inkscape:stockid") : repr->attribute("id"); // generate preview - Gtk::Image *prv = create_marker_image (22, repr->attribute("id"), source, drawing, visionkey); + Gtk::Image *prv = create_marker_image (24, repr->attribute("id"), source, drawing, visionkey); prv->show(); // Add history before separator, others after @@ -424,14 +430,14 @@ void MarkerComboBox::update_marker_image(gchar const *mname) { gchar *cache_name = g_strconcat(combo_id, mname, NULL); - Glib::ustring key = svg_preview_cache.cache_key(doc->getURI(), cache_name, 22); + Glib::ustring key = svg_preview_cache.cache_key(doc->getURI(), cache_name, 24); g_free (cache_name); svg_preview_cache.remove_preview_from_cache(key); Inkscape::Drawing drawing; unsigned const visionkey = SPItem::display_key_new(1); drawing.setRoot(sandbox->getRoot()->invoke_show(drawing, visionkey, SP_ITEM_SHOW_DISPLAY)); - Gtk::Image *prv = create_marker_image(22, mname, doc, drawing, visionkey); + Gtk::Image *prv = create_marker_image(24, mname, doc, drawing, visionkey); if (prv) { prv->show(); } -- cgit v1.2.3 From 3329985ec81c08006b6a5fe7c9fe0b81d956ad3f Mon Sep 17 00:00:00 2001 From: chr Date: Thu, 18 May 2017 19:58:59 +0200 Subject: object manager panel: fix clip/mask icons missing icon delayed inkscape startup of about 3-5 seconds (bzr r15698.1.4) --- src/ui/dialog/objects.cpp | 10 ++++++++-- src/ui/widget/clipmaskicon.cpp | 24 ++++++++++++------------ src/ui/widget/clipmaskicon.h | 4 ++-- 3 files changed, 22 insertions(+), 16 deletions(-) (limited to 'src') diff --git a/src/ui/dialog/objects.cpp b/src/ui/dialog/objects.cpp index c7c696cdc..6b28c3b2f 100644 --- a/src/ui/dialog/objects.cpp +++ b/src/ui/dialog/objects.cpp @@ -350,7 +350,10 @@ void ObjectsPanel::_addObject(SPObject* obj, Gtk::TreeModel::Row* parentRow) row[_model->_colLocked] = !item->isSensitive(); row[_model->_colType] = group ? (group->layerMode() == SPGroup::LAYER ? 2 : 1) : 0; row[_model->_colHighlight] = item->isHighlightSet() ? item->highlight_color() : item->highlight_color() & 0xffffff00; - row[_model->_colClipMask] = item->clip_ref && item->clip_ref->getObject() ? 1 : (item->mask_ref && item->mask_ref->getObject() ? 2 : 0); + row[_model->_colClipMask] = item ? ( + (item->clip_ref && item->clip_ref->getObject() ? 1 : 0) | + (item->mask_ref && item->mask_ref->getObject() ? 2 : 0) + ) : 0; //row[_model->_colInsertOrder] = group ? (group->insertBottom() ? 2 : 1) : 0; //If our parent object is a group and it's expanded, expand the tree @@ -413,7 +416,10 @@ bool ObjectsPanel::_checkForUpdated(const Gtk::TreeIter& iter, SPObject* obj) row[_model->_colLocked] = item ? !item->isSensitive() : false; row[_model->_colType] = group ? (group->layerMode() == SPGroup::LAYER ? 2 : 1) : 0; row[_model->_colHighlight] = item ? (item->isHighlightSet() ? item->highlight_color() : item->highlight_color() & 0xffffff00) : 0; - row[_model->_colClipMask] = item ? (item->clip_ref && item->clip_ref->getObject() ? 1 : (item->mask_ref && item->mask_ref->getObject() ? 2 : 0)) : 0; + row[_model->_colClipMask] = item ? ( + (item->clip_ref && item->clip_ref->getObject() ? 1 : 0) | + (item->mask_ref && item->mask_ref->getObject() ? 2 : 0) + ) : 0; //row[_model->_colInsertOrder] = group ? (group->insertBottom() ? 2 : 1) : 0; return true; diff --git a/src/ui/widget/clipmaskicon.cpp b/src/ui/widget/clipmaskicon.cpp index 4f791042a..a1e3eaf82 100644 --- a/src/ui/widget/clipmaskicon.cpp +++ b/src/ui/widget/clipmaskicon.cpp @@ -27,13 +27,13 @@ namespace Widget { ClipMaskIcon::ClipMaskIcon() : Glib::ObjectBase(typeid(ClipMaskIcon)), Gtk::CellRendererPixbuf(), - _pixClipName(INKSCAPE_ICON("path-intersection")), - _pixInverseName(INKSCAPE_ICON("path-difference")), - _pixMaskName(INKSCAPE_ICON("mask-intersection")), + _pixClipName(INKSCAPE_ICON("path-cut")), + _pixMaskName(INKSCAPE_ICON("path-difference")), + _pixBothName(INKSCAPE_ICON("bitmap-trace")), _property_active(*this, "active", 0), _property_pixbuf_clip(*this, "pixbuf_on", Glib::RefPtr(0)), - _property_pixbuf_inverse(*this, "pixbuf_on", Glib::RefPtr(0)), - _property_pixbuf_mask(*this, "pixbuf_off", Glib::RefPtr(0)) + _property_pixbuf_mask(*this, "pixbuf_off", Glib::RefPtr(0)), + _property_pixbuf_both(*this, "pixbuf_on", Glib::RefPtr(0)) { property_mode() = Gtk::CELL_RENDERER_MODE_ACTIVATABLE; @@ -43,22 +43,22 @@ ClipMaskIcon::ClipMaskIcon() : if (!icon_theme->has_icon(_pixClipName)) { Inkscape::queueIconPrerender( INKSCAPE_ICON(_pixClipName.data()), Inkscape::ICON_SIZE_DECORATION ); } - if (!icon_theme->has_icon(_pixInverseName)) { - Inkscape::queueIconPrerender( INKSCAPE_ICON(_pixInverseName.data()), Inkscape::ICON_SIZE_DECORATION ); - } if (!icon_theme->has_icon(_pixMaskName)) { Inkscape::queueIconPrerender( INKSCAPE_ICON(_pixMaskName.data()), Inkscape::ICON_SIZE_DECORATION ); } + if (!icon_theme->has_icon(_pixBothName)) { + Inkscape::queueIconPrerender( INKSCAPE_ICON(_pixBothName.data()), Inkscape::ICON_SIZE_DECORATION ); + } if (icon_theme->has_icon(_pixClipName)) { _property_pixbuf_clip = icon_theme->load_icon(_pixClipName, phys, (Gtk::IconLookupFlags)0); } - if (icon_theme->has_icon(_pixInverseName)) { - _property_pixbuf_inverse = icon_theme->load_icon(_pixInverseName, phys, (Gtk::IconLookupFlags)0); - } if (icon_theme->has_icon(_pixMaskName)) { _property_pixbuf_mask = icon_theme->load_icon(_pixMaskName, phys, (Gtk::IconLookupFlags)0); } + if (icon_theme->has_icon(_pixBothName)) { + _property_pixbuf_both = icon_theme->load_icon(_pixBothName, phys, (Gtk::IconLookupFlags)0); + } property_pixbuf() = Glib::RefPtr(0); } @@ -108,7 +108,7 @@ void ClipMaskIcon::render_vfunc( const Cairo::RefPtr& cr, property_pixbuf() = _property_pixbuf_mask; break; case 3: - property_pixbuf() = _property_pixbuf_inverse; + property_pixbuf() = _property_pixbuf_both; break; default: property_pixbuf() = Glib::RefPtr(0); diff --git a/src/ui/widget/clipmaskicon.h b/src/ui/widget/clipmaskicon.h index 0d149edb8..deb4554df 100644 --- a/src/ui/widget/clipmaskicon.h +++ b/src/ui/widget/clipmaskicon.h @@ -58,13 +58,13 @@ private: int phys; Glib::ustring _pixClipName; - Glib::ustring _pixInverseName; Glib::ustring _pixMaskName; + Glib::ustring _pixBothName; Glib::Property _property_active; Glib::Property< Glib::RefPtr > _property_pixbuf_clip; - Glib::Property< Glib::RefPtr > _property_pixbuf_inverse; Glib::Property< Glib::RefPtr > _property_pixbuf_mask; + Glib::Property< Glib::RefPtr > _property_pixbuf_both; }; -- cgit v1.2.3 From a3789bc9a1739f158a023ff34d7e647e697f606e Mon Sep 17 00:00:00 2001 From: chr Date: Thu, 18 May 2017 19:58:59 +0200 Subject: ObjectsPanel: Polish collapse/expand behaviour (bzr r15698.1.5) --- src/ui/dialog/objects.cpp | 12 ++++++++---- src/ui/dialog/objects.h | 2 +- 2 files changed, 9 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/ui/dialog/objects.cpp b/src/ui/dialog/objects.cpp index 6b28c3b2f..db937a6a8 100644 --- a/src/ui/dialog/objects.cpp +++ b/src/ui/dialog/objects.cpp @@ -360,6 +360,7 @@ void ObjectsPanel::_addObject(SPObject* obj, Gtk::TreeModel::Row* parentRow) if (SP_IS_GROUP(obj) && SP_GROUP(obj)->expanded()) { _tree.expand_to_path( _store->get_path(iter) ); + _tree.collapse_row( _store->get_path(iter) ); } //Add an object watcher to the item @@ -479,13 +480,13 @@ void ObjectsPanel::_objectsSelected( Selection *sel ) { _setCompositingValues(item); setOpacity = false; } - _store->foreach(sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_checkForSelected), item, (*i)==items.back())); + _store->foreach(sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_checkForSelected), item, (*i)==items.back(), false)); } if (!item) { if (_desktop->currentLayer() && SP_IS_ITEM(_desktop->currentLayer())) { item = SP_ITEM(_desktop->currentLayer()); _setCompositingValues(item); - _store->foreach(sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_checkForSelected), item, true)); + _store->foreach(sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_checkForSelected), item, true, true)); } } _selectedConnection.unblock(); @@ -551,7 +552,7 @@ void ObjectsPanel::_setCompositingValues(SPItem *item) * @param scrollto Whether to scroll to the item * @return Whether to continue searching the tree */ -bool ObjectsPanel::_checkForSelected(const Gtk::TreePath &path, const Gtk::TreeIter& iter, SPItem* item, bool scrollto) +bool ObjectsPanel::_checkForSelected(const Gtk::TreePath &path, const Gtk::TreeIter& iter, SPItem* item, bool scrollto, bool expand) { bool stopGoing = false; @@ -560,13 +561,16 @@ bool ObjectsPanel::_checkForSelected(const Gtk::TreePath &path, const Gtk::TreeI { //We found the item! Expand to the path and select it in the tree. _tree.expand_to_path( path ); + if (!expand) + // but don't expand itself, just the path + _tree.collapse_row(path); Glib::RefPtr select = _tree.get_selection(); select->select(iter); if (scrollto) { //Scroll to the item in the tree - _tree.scroll_to_row(path); + _tree.scroll_to_row(path, 0.5); } stopGoing = true; diff --git a/src/ui/dialog/objects.h b/src/ui/dialog/objects.h index 018f9191f..995f8c37f 100644 --- a/src/ui/dialog/objects.h +++ b/src/ui/dialog/objects.h @@ -216,7 +216,7 @@ private: bool _checkForUpdated(const Gtk::TreeIter& iter, SPObject* obj); void _objectsSelected(Selection *sel); - bool _checkForSelected(const Gtk::TreePath& path, const Gtk::TreeIter& iter, SPItem* item, bool scrollto); + bool _checkForSelected(const Gtk::TreePath& path, const Gtk::TreeIter& iter, SPItem* item, bool scrollto, bool expand); void _objectsChanged(SPObject *obj); void _addObject( SPObject* obj, Gtk::TreeModel::Row* parentRow ); -- cgit v1.2.3 From eef4186179740fbeba18c6bb2c845b4f98dc2104 Mon Sep 17 00:00:00 2001 From: chr Date: Thu, 18 May 2017 19:58:59 +0200 Subject: object panel: don't scroll to layer when leaving object group don't jump too much around in the list (bzr r15698.1.6) --- src/ui/dialog/objects.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'src') diff --git a/src/ui/dialog/objects.cpp b/src/ui/dialog/objects.cpp index db937a6a8..c624a8435 100644 --- a/src/ui/dialog/objects.cpp +++ b/src/ui/dialog/objects.cpp @@ -486,7 +486,7 @@ void ObjectsPanel::_objectsSelected( Selection *sel ) { if (_desktop->currentLayer() && SP_IS_ITEM(_desktop->currentLayer())) { item = SP_ITEM(_desktop->currentLayer()); _setCompositingValues(item); - _store->foreach(sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_checkForSelected), item, true, true)); + _store->foreach(sigc::bind( sigc::mem_fun(*this, &ObjectsPanel::_checkForSelected), item, false, true)); } } _selectedConnection.unblock(); -- cgit v1.2.3 From dc80e5d0bf82f005628881134b929aa4838308d5 Mon Sep 17 00:00:00 2001 From: chr Date: Tue, 23 May 2017 21:48:22 +0200 Subject: selection chemistry: implement z-stack order Bug #1395452 "raise and lower objects" used to stack objects above/below the next overlapping object, which makes it impossible to change the z-order of objects that don't overlap. Fixes also the object manager panel Conflicts: src/selection-chemistry.cpp src/selection-chemistry.h src/sp-item.cpp (bzr r15698.1.7) --- src/object-set.h | 2 ++ src/selection-chemistry.cpp | 39 +++++++++++++++++++++++++++++++++++++++ src/sp-item.cpp | 8 ++++++-- src/sp-item.h | 4 ++-- src/ui/dialog/objects.cpp | 12 ++++++------ src/verbs.cpp | 14 ++++++++++++++ src/verbs.h | 2 ++ 7 files changed, 71 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/object-set.h b/src/object-set.h index 02259824c..82d2988c7 100644 --- a/src/object-set.h +++ b/src/object-set.h @@ -377,8 +377,10 @@ public: //z-order management //in selection-chemistry.cpp + void stackUp(bool skip_undo = false); void raise(bool skip_undo = false); void raiseToTop(bool skip_undo = false); + void stackDown(bool skip_undo = false); void lower(bool skip_undo = false); void lowerToBottom(bool skip_undo = false); void toNextLayer(bool skip_undo = false); diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 39846ba2c..7d5d921b0 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -1140,6 +1140,45 @@ void ObjectSet::lowerToBottom(bool skip_undo){ } } +void ObjectSet::stackUp(bool skip_undo) { + if (isEmpty()) { + selection_display_message(desktop(), Inkscape::WARNING_MESSAGE, _("Select object(s) to stack up.")); + return; + } + + std::vector selection(items().begin(), items().end()); + sort(selection.begin(), selection.end(), sp_item_repr_compare_position_bool); + + for (auto item: selection | boost::adaptors::reversed) { + if (!item->raiseOne()) // stop if top was reached + break; + } + + if(document() && !skip_undo) + DocumentUndo::done(document(), SP_VERB_SELECTION_STACK_UP, + //TRANSLATORS: undo history: "stack up" means to raise an object of its ordinal position by 1 + C_("Undo action", "stack up")); +} + +void ObjectSet::stackDown(bool skip_undo) { + if (isEmpty()) { + selection_display_message(desktop(), Inkscape::WARNING_MESSAGE, _("Select object(s) to stack down.")); + return; + } + + std::vector selection(items().begin(), items().end()); + sort(selection.begin(), selection.end(), sp_item_repr_compare_position_bool); + + for (auto item: selection) { + if (!item->lowerOne()) // stop if bottom was reached + break; + } + + if(document() && !skip_undo) + DocumentUndo::done(document(), SP_VERB_SELECTION_STACK_DOWN, + //TRANSLATORS: undo history: "stack down" means to lower an object of its ordinal position by 1 + C_("Undo action", "stack down")); +} void sp_undo(SPDesktop *desktop, SPDocument *) diff --git a/src/sp-item.cpp b/src/sp-item.cpp index e2f678957..368f8896c 100644 --- a/src/sp-item.cpp +++ b/src/sp-item.cpp @@ -306,15 +306,17 @@ void SPItem::raiseToTop() { } } -void SPItem::raiseOne() { +bool SPItem::raiseOne() { auto next_higher = std::find_if(++parent->children.iterator_to(*this), parent->children.end(), &is_item); if (next_higher != parent->children.end()) { Inkscape::XML::Node *ref = next_higher->getRepr(); getRepr()->parent()->changeOrder(getRepr(), ref); + return true; } + return false; } -void SPItem::lowerOne() { +bool SPItem::lowerOne() { using Inkscape::Algorithms::find_last_if; auto next_lower = find_last_if(parent->children.begin(), parent->children.iterator_to(*this), &is_item); @@ -325,7 +327,9 @@ void SPItem::lowerOne() { ref = next_lower->getRepr(); } getRepr()->parent()->changeOrder(getRepr(), ref); + return true; } + return false; } void SPItem::lowerToBottom() { diff --git a/src/sp-item.h b/src/sp-item.h index a03bab9f3..c4d353a1d 100644 --- a/src/sp-item.h +++ b/src/sp-item.h @@ -212,8 +212,8 @@ public: Geom::Affine getRelativeTransform(SPObject const *obj) const; - void raiseOne(); - void lowerOne(); + bool raiseOne(); + bool lowerOne(); void raiseToTop(); void lowerToBottom(); diff --git a/src/ui/dialog/objects.cpp b/src/ui/dialog/objects.cpp index c624a8435..55a944afb 100644 --- a/src/ui/dialog/objects.cpp +++ b/src/ui/dialog/objects.cpp @@ -722,14 +722,14 @@ bool ObjectsPanel::_handleKeyEvent(GdkEventKey *event) case GDK_KEY_Page_Up: { //Move item(s) up in containing group/layer - int ch = event->state & GDK_SHIFT_MASK ? SP_VERB_LAYER_MOVE_TO_NEXT : SP_VERB_SELECTION_RAISE; + int ch = event->state & GDK_SHIFT_MASK ? SP_VERB_LAYER_MOVE_TO_NEXT : SP_VERB_SELECTION_STACK_UP; _fireAction( empty ? SP_VERB_LAYER_RAISE : ch ); break; } case GDK_KEY_Page_Down: { //Move item(s) down in containing group/layer - int ch = event->state & GDK_SHIFT_MASK ? SP_VERB_LAYER_MOVE_TO_PREV : SP_VERB_SELECTION_LOWER; + int ch = event->state & GDK_SHIFT_MASK ? SP_VERB_LAYER_MOVE_TO_PREV : SP_VERB_SELECTION_STACK_DOWN; _fireAction( empty ? SP_VERB_LAYER_LOWER : ch ); break; } @@ -1182,7 +1182,7 @@ bool ObjectsPanel::_executeAction() } else { - _fireAction( SP_VERB_SELECTION_RAISE ); + _fireAction( SP_VERB_SELECTION_STACK_UP ); } } break; @@ -1194,7 +1194,7 @@ bool ObjectsPanel::_executeAction() } else { - _fireAction( SP_VERB_SELECTION_LOWER ); + _fireAction( SP_VERB_SELECTION_STACK_DOWN ); } } break; @@ -1903,8 +1903,8 @@ ObjectsPanel::ObjectsPanel() : _popupMenu.append(*Gtk::manage(new Gtk::SeparatorMenuItem())); - _watchingNonTop.push_back( &_addPopupItem( targetDesktop, SP_VERB_SELECTION_RAISE, "gtk-go-up", _("Up"), (int)BUTTON_UP ) ); - _watchingNonBottom.push_back( &_addPopupItem( targetDesktop, SP_VERB_SELECTION_LOWER, "gtk-go-down", _("Down"), (int)BUTTON_DOWN ) ); + _watchingNonTop.push_back( &_addPopupItem( targetDesktop, SP_VERB_SELECTION_STACK_UP, "gtk-go-up", _("Up"), (int)BUTTON_UP ) ); + _watchingNonBottom.push_back( &_addPopupItem( targetDesktop, SP_VERB_SELECTION_STACK_DOWN, "gtk-go-down", _("Down"), (int)BUTTON_DOWN ) ); _popupMenu.append(*Gtk::manage(new Gtk::SeparatorMenuItem())); diff --git a/src/verbs.cpp b/src/verbs.cpp index b7b6da340..22ded60b3 100644 --- a/src/verbs.cpp +++ b/src/verbs.cpp @@ -1179,6 +1179,12 @@ void SelectionVerb::perform(SPAction *action, void *data) case SP_VERB_SELECTION_LOWER: selection->lower(); break; + case SP_VERB_SELECTION_STACK_UP: + selection->stackUp(); + break; + case SP_VERB_SELECTION_STACK_DOWN: + selection->stackDown(); + break; case SP_VERB_SELECTION_GROUP: selection->group(); break; @@ -2685,6 +2691,14 @@ Verb *Verb::_base_verbs[] = { N_("Raise selection one step"), INKSCAPE_ICON("selection-raise")), new SelectionVerb(SP_VERB_SELECTION_LOWER, "SelectionLower", N_("_Lower"), N_("Lower selection one step"), INKSCAPE_ICON("selection-lower")), + + + new SelectionVerb(SP_VERB_SELECTION_STACK_UP, "SelectionStackUp", N_("_Stack up"), + N_("Stack selection one step up"), INKSCAPE_ICON("layer-raise")), + new SelectionVerb(SP_VERB_SELECTION_STACK_DOWN, "SelectionStackDown", N_("_Stack down"), + N_("Stack selection one step down"), INKSCAPE_ICON("layer-lower")), + + new SelectionVerb(SP_VERB_SELECTION_GROUP, "SelectionGroup", N_("_Group"), N_("Group selected objects"), INKSCAPE_ICON("object-group")), new SelectionVerb(SP_VERB_SELECTION_UNGROUP, "SelectionUnGroup", N_("_Ungroup"), diff --git a/src/verbs.h b/src/verbs.h index 6846f1f40..a383bc365 100644 --- a/src/verbs.h +++ b/src/verbs.h @@ -116,6 +116,8 @@ enum { SP_VERB_SELECTION_TO_BACK, SP_VERB_SELECTION_RAISE, SP_VERB_SELECTION_LOWER, + SP_VERB_SELECTION_STACK_UP, + SP_VERB_SELECTION_STACK_DOWN, SP_VERB_SELECTION_GROUP, SP_VERB_SELECTION_UNGROUP, SP_VERB_SELECTION_UNGROUP_POP_SELECTION, -- cgit v1.2.3 From 7c3f279bbfbd14530476de89ad9725d32ed28fcf Mon Sep 17 00:00:00 2001 From: chr Date: Tue, 23 May 2017 21:48:26 +0200 Subject: object panel: search function blocks too many keystrokes use ctrl+f to use search Issue: select object in the object panel, focus stays on that widget. Press "3" (zoom to object) used to open the search function. (bzr r15698.1.8) --- src/ui/dialog/objects.cpp | 2 ++ 1 file changed, 2 insertions(+) (limited to 'src') diff --git a/src/ui/dialog/objects.cpp b/src/ui/dialog/objects.cpp index 55a944afb..003821796 100644 --- a/src/ui/dialog/objects.cpp +++ b/src/ui/dialog/objects.cpp @@ -1744,6 +1744,8 @@ ObjectsPanel::ObjectsPanel() : //Set the expander and search columns _tree.set_expander_column( *_tree.get_column(nameColNum) ); _tree.set_search_column(_model->_colLabel); + // use ctrl+f to start search + _tree.set_enable_search(false); //Set up the tree selection _tree.get_selection()->set_mode(Gtk::SELECTION_MULTIPLE); -- cgit v1.2.3 From 297d0a6bd45eb41e5105e1d06fc0ae4930e49e79 Mon Sep 17 00:00:00 2001 From: chr Date: Tue, 23 May 2017 21:48:27 +0200 Subject: object panel: don't block F2 key, use return to edit cell (bzr r15698.1.9) --- src/ui/dialog/objects.cpp | 12 +++++++----- 1 file changed, 7 insertions(+), 5 deletions(-) (limited to 'src') diff --git a/src/ui/dialog/objects.cpp b/src/ui/dialog/objects.cpp index 003821796..95302387f 100644 --- a/src/ui/dialog/objects.cpp +++ b/src/ui/dialog/objects.cpp @@ -698,17 +698,19 @@ bool ObjectsPanel::_handleKeyEvent(GdkEventKey *event) switch (Inkscape::UI::Tools::get_group0_keyval(event)) { case GDK_KEY_Return: case GDK_KEY_KP_Enter: - case GDK_KEY_F2: { - Gtk::TreeModel::iterator iter = _tree.get_selection()->get_selected(); - if (iter && !_text_renderer->property_editable()) { + Gtk::TreeModel::Path path; + Gtk::TreeViewColumn *focus_column = 0; + + _tree.get_cursor(path, focus_column); + if (focus_column == _name_column && !_text_renderer->property_editable()) { //Rename item - Gtk::TreeModel::Path *path = new Gtk::TreeModel::Path(iter); _text_renderer->property_editable() = true; - _tree.set_cursor(*path, *_name_column, true); + _tree.set_cursor(path, *_name_column, true); grab_focus(); return true; } + return false; } break; case GDK_KEY_Home: -- cgit v1.2.3 From b19af6efc276f4837407c4c1d14504f8b190fb2d Mon Sep 17 00:00:00 2001 From: chr Date: Tue, 23 May 2017 21:48:27 +0200 Subject: opject panel: rework shotcuts: let the user decide This implemetation respect the users action shortcuts, handled in this order: 1) Two hardcoded keystrokes: * crtl+f engage search on tree view * esc: defocus: next keystrokes goes to desktop 2) Try to invoke user defined shortcut action 3) RETURN-key: activate action of selected column currently works on the name-column only 4) shortcut goes to Treeview For the testers: The new verbs "stack up/down" are not bound to keystrokes. Set them up as you like via preferences / interface / keyboard shortcuts / selection / stack up and down Try keystrokes with focus on desktop, on object-panel and compare with layer-panel: PageUp/Down + - shift, ctrl esc esc arrow esc arrow ctrl+f V, H - may(!) flip objects ctrl+a (!) ! invert selection Beside user definable keystrokes, there are some hardcoded: arrow-up/down + shift,ctrl [ ] - rotate objects - not user defined actions, so does not work in panel focus / * also keypad / * is usually fold/unfold tree but * actually selects the "star tool", which can be disabled if you don't like that Conflicts: src/ui/dialog/objects.cpp (bzr r15698.1.10) --- src/ui/dialog/objects.cpp | 63 +++++++++++++++++++++++++++-------------------- 1 file changed, 36 insertions(+), 27 deletions(-) (limited to 'src') diff --git a/src/ui/dialog/objects.cpp b/src/ui/dialog/objects.cpp index 95302387f..61ce3ada3 100644 --- a/src/ui/dialog/objects.cpp +++ b/src/ui/dialog/objects.cpp @@ -30,6 +30,7 @@ #include "helper/action.h" #include "inkscape.h" #include "layer-manager.h" +#include "shortcuts.h" #include "sp-clippath.h" #include "sp-mask.h" #include "sp-root.h" @@ -692,7 +693,41 @@ void ObjectsPanel::_setLockedIter( const Gtk::TreeModel::iterator& iter, const b */ bool ObjectsPanel::_handleKeyEvent(GdkEventKey *event) { + if (!_desktop) + return false; + + unsigned int shortcut; + shortcut = Inkscape::UI::Tools::get_group0_keyval(event) | + ( event->state & GDK_SHIFT_MASK ? + SP_SHORTCUT_SHIFT_MASK : 0 ) | + ( event->state & GDK_CONTROL_MASK ? + SP_SHORTCUT_CONTROL_MASK : 0 ) | + ( event->state & GDK_MOD1_MASK ? + SP_SHORTCUT_ALT_MASK : 0 ); + + switch (shortcut) { + // how to get users key binding for the action “start-interactive-search” ?? + // ctrl+f is just the default + case GDK_KEY_f | SP_SHORTCUT_CONTROL_MASK: + return false; + break; + // shall we slurp ctrl+w to close panel? + + // defocus: + case GDK_KEY_Escape: + if (_desktop->canvas) { + gtk_widget_grab_focus (GTK_WIDGET(_desktop->canvas)); + return true; + } + break; + } + // invoke user defined shortcuts first + bool done = sp_shortcut_invoke(shortcut, _desktop); + if (done) + return true; + + // handle events for the treeview bool empty = _desktop->selection->isEmpty(); switch (Inkscape::UI::Tools::get_group0_keyval(event)) { @@ -711,36 +746,10 @@ bool ObjectsPanel::_handleKeyEvent(GdkEventKey *event) return true; } return false; - } - break; - case GDK_KEY_Home: - //Move item(s) to top of containing group/layer - _fireAction( empty ? SP_VERB_LAYER_TO_TOP : SP_VERB_SELECTION_TO_FRONT ); - break; - case GDK_KEY_End: - //Move item(s) to bottom of containing group/layer - _fireAction( empty ? SP_VERB_LAYER_TO_BOTTOM : SP_VERB_SELECTION_TO_BACK ); - break; - case GDK_KEY_Page_Up: - { - //Move item(s) up in containing group/layer - int ch = event->state & GDK_SHIFT_MASK ? SP_VERB_LAYER_MOVE_TO_NEXT : SP_VERB_SELECTION_STACK_UP; - _fireAction( empty ? SP_VERB_LAYER_RAISE : ch ); break; } - case GDK_KEY_Page_Down: - { - //Move item(s) down in containing group/layer - int ch = event->state & GDK_SHIFT_MASK ? SP_VERB_LAYER_MOVE_TO_PREV : SP_VERB_SELECTION_STACK_DOWN; - _fireAction( empty ? SP_VERB_LAYER_LOWER : ch ); - break; - } - - //TODO: Handle Ctrl-A, etc. - default: - return false; } - return true; + return false; } /** -- cgit v1.2.3 From 603492342f7dc248e131d783af2606e6bcf6324f Mon Sep 17 00:00:00 2001 From: chr Date: Tue, 23 May 2017 21:48:27 +0200 Subject: bugfix: change active layer note: the actions "LayerNext"/"LayerPrev" (ctrl+pageup/down) never clear the selection, they ignore the user setting "clear selection on layer change" So the object panel will only change if there is no selection! (bzr r15698.1.11) --- src/ui/dialog/objects.cpp | 8 ++++++++ src/ui/dialog/objects.h | 3 +++ 2 files changed, 11 insertions(+) (limited to 'src') diff --git a/src/ui/dialog/objects.cpp b/src/ui/dialog/objects.cpp index 61ce3ada3..fd78fec90 100644 --- a/src/ui/dialog/objects.cpp +++ b/src/ui/dialog/objects.cpp @@ -309,11 +309,13 @@ void ObjectsPanel::_objectsChanged(SPObject */*obj*/) SPRoot* root = document->getRoot(); if ( root ) { _selectedConnection.block(); + _documentChangedCurrentLayer.block(); //Clear the tree store _store->clear(); //Add all items recursively _addObject( root, 0 ); _selectedConnection.unblock(); + _documentChangedCurrentLayer.unblock(); //Set the tree selection _objectsSelected(_desktop->selection); //Handle button sensitivity @@ -588,6 +590,7 @@ void ObjectsPanel::_pushTreeSelectionToCurrent() if ( _desktop && _desktop->currentRoot() ) { //block connections for selection and compositing values to prevent interference _selectionChangedConnection.block(); + _documentChangedCurrentLayer.block(); //Clear the selection and then iterate over the tree selection, pushing each item to the desktop _desktop->selection->clear(); @@ -595,6 +598,7 @@ void ObjectsPanel::_pushTreeSelectionToCurrent() _tree.get_selection()->selected_foreach_iter( sigc::bind(sigc::mem_fun(*this, &ObjectsPanel::_selected_row_callback), &setOpacity)); //unblock connections _selectionChangedConnection.unblock(); + _documentChangedCurrentLayer.unblock(); _checkTreeSelection(); } @@ -2056,6 +2060,7 @@ void ObjectsPanel::setDesktop( SPDesktop* desktop ) if ( desktop != _desktop ) { _documentChangedConnection.disconnect(); + _documentChangedCurrentLayer.disconnect(); _selectionChangedConnection.disconnect(); if ( _desktop ) { _desktop = 0; @@ -2065,6 +2070,9 @@ void ObjectsPanel::setDesktop( SPDesktop* desktop ) if ( _desktop ) { //Connect desktop signals _documentChangedConnection = _desktop->connectDocumentReplaced( sigc::mem_fun(*this, &ObjectsPanel::setDocument)); + + _documentChangedCurrentLayer = _desktop->connectCurrentLayerChanged( sigc::mem_fun(*this, &ObjectsPanel::_objectsChanged)); + _selectionChangedConnection = _desktop->selection->connectChanged( sigc::mem_fun(*this, &ObjectsPanel::_objectsSelected)); setDocument(_desktop, _desktop->doc()); diff --git a/src/ui/dialog/objects.h b/src/ui/dialog/objects.h index 995f8c37f..21305669e 100644 --- a/src/ui/dialog/objects.h +++ b/src/ui/dialog/objects.h @@ -77,6 +77,9 @@ private: //Connection for when the document changes sigc::connection _documentChangedConnection; + //Connection for when the active layer changes + sigc::connection _documentChangedCurrentLayer; + //Connection for when the active selection in the document changes sigc::connection _selectionChangedConnection; -- cgit v1.2.3 From 71f7e26f4a6714fe1d3b6a72f61c481c3e1f52a0 Mon Sep 17 00:00:00 2001 From: chr Date: Tue, 23 May 2017 21:48:27 +0200 Subject: fix a brunch of memory leaks pt.2 I'd like to see the crappy API fixed, to avoid this stupid mistakes. (bzr r15698.1.12) --- src/live_effects/lpe-clone-original.cpp | 12 +++++++++--- src/live_effects/lpe-copy_rotate.cpp | 4 +++- src/live_effects/lpe-measure-line.cpp | 11 +++++++---- src/live_effects/lpe-mirror_symmetry.cpp | 4 +++- src/svg/svg-affine-test.h | 4 +++- 5 files changed, 25 insertions(+), 10 deletions(-) (limited to 'src') diff --git a/src/live_effects/lpe-clone-original.cpp b/src/live_effects/lpe-clone-original.cpp index d97a990af..31bf0e270 100644 --- a/src/live_effects/lpe-clone-original.cpp +++ b/src/live_effects/lpe-clone-original.cpp @@ -138,10 +138,14 @@ LPECloneOriginal::cloneAttrbutes(SPObject *origin, SPObject *dest, bool live, co dest_affine *= Geom::Translate(preserve_affine.translation()); affine_previous = preserve_affine; preserve_affine = Geom::identity(); - SP_ITEM(dest)->getRepr()->setAttribute("transform",sp_svg_transform_write(dest_affine)); + gchar * str = sp_svg_transform_write(dest_affine); + SP_ITEM(dest)->getRepr()->setAttribute("transform", str); + g_free(str); } } else { - SP_ITEM(dest)->getRepr()->setAttribute("transform",sp_svg_transform_write(affine_origin)); + gchar * str = sp_svg_transform_write(affine_origin); + SP_ITEM(dest)->getRepr()->setAttribute("transform", str); + g_free(str); } } else if ( shape_dest && shape_origin && live && (std::strcmp(attribute, "d") == 0)) { SPCurve *c = NULL; @@ -176,7 +180,9 @@ LPECloneOriginal::cloneAttrbutes(SPObject *origin, SPObject *dest, bool live, co c->set_pathvector(c_pv); if (!path_origin) { shape_dest->setCurveInsync(c, TRUE); - dest->getRepr()->setAttribute(attribute, sp_svg_write_path(c_pv)); + gchar *str = sp_svg_write_path(c_pv); + dest->getRepr()->setAttribute(attribute, str); + g_free(str); } else { shape_dest->setCurve(c, TRUE); } diff --git a/src/live_effects/lpe-copy_rotate.cpp b/src/live_effects/lpe-copy_rotate.cpp index f8be0f2a5..e80ad80cb 100644 --- a/src/live_effects/lpe-copy_rotate.cpp +++ b/src/live_effects/lpe-copy_rotate.cpp @@ -274,7 +274,9 @@ LPECopyRotate::toItem(Geom::Affine transform, size_t i, bool reset) Inkscape::GC::release(phantom); } cloneD(SP_OBJECT(sp_lpe_item), elemref, true, reset); - elemref->getRepr()->setAttribute("transform" , sp_svg_transform_write(transform)); + gchar *str = sp_svg_transform_write(transform); + elemref->getRepr()->setAttribute("transform" , str); + g_free(str); SP_ITEM(elemref)->setHidden(false); if (elemref->parent != container) { Inkscape::XML::Node *copy = phantom->duplicate(xml_doc); diff --git a/src/live_effects/lpe-measure-line.cpp b/src/live_effects/lpe-measure-line.cpp index 892744462..f7892cbe7 100644 --- a/src/live_effects/lpe-measure-line.cpp +++ b/src/live_effects/lpe-measure-line.cpp @@ -260,7 +260,7 @@ LPEMeasureLine::createTextLabel(Geom::Point pos, double length, Geom::Coord angl rtspan = xml_doc->createElement("svg:tspan"); rtspan->setAttribute("sodipodi:role", "line"); } - const char * transform; + gchar * transform; Geom::Affine affine = Geom::Affine(Geom::Translate(pos).inverse()); angle = std::fmod(angle, 2*M_PI); if (angle < 0) angle += 2*M_PI; @@ -276,6 +276,7 @@ LPEMeasureLine::createTextLabel(Geom::Point pos, double length, Geom::Coord angl transform = NULL; } rtext->setAttribute("transform", transform); + g_free(transform); SPCSSAttr *css = sp_repr_css_attr_new(); sp_repr_css_attr_add_from_string(css, anotation_format.param_getSVGValue()); Inkscape::FontLister *fontlister = Inkscape::FontLister::get_instance(); @@ -317,7 +318,7 @@ LPEMeasureLine::createTextLabel(Geom::Point pos, double length, Geom::Coord angl g_snprintf(length_str, 64, "%.*f", (int)precision, length); setlocale (LC_NUMERIC, oldlocale); g_free (oldlocale); - Glib::ustring label_value = Glib::ustring(format.param_getSVGValue()); + Glib::ustring label_value(format.param_getSVGValue()); size_t s = label_value.find(Glib::ustring("{measure}"),0); if(s < label_value.length()) { label_value.replace(s,s+9,length_str); @@ -413,17 +414,19 @@ LPEMeasureLine::createLine(Geom::Point start,Geom::Point end, const char * id, b } line = elemref->getRepr(); - const char * line_str = sp_svg_write_path( line_pathv ); + gchar * line_str = sp_svg_write_path( line_pathv ); line->setAttribute("d" , line_str); line->setAttribute("transform", NULL); + g_free(line_str); } else { if (remove) { return; } line = xml_doc->createElement("svg:path"); line->setAttribute("id", id); - const char * line_str = sp_svg_write_path( line_pathv ); + gchar * line_str = sp_svg_write_path( line_pathv ); line->setAttribute("d" , line_str); + g_free(line_str); } line->setAttribute("sodipodi:insensitive", "true"); line_pathv.clear(); diff --git a/src/live_effects/lpe-mirror_symmetry.cpp b/src/live_effects/lpe-mirror_symmetry.cpp index 186b97fe3..b1f10c242 100644 --- a/src/live_effects/lpe-mirror_symmetry.cpp +++ b/src/live_effects/lpe-mirror_symmetry.cpp @@ -291,7 +291,9 @@ LPEMirrorSymmetry::toMirror(Geom::Affine transform) Inkscape::GC::release(phantom); } cloneD(SP_OBJECT(sp_lpe_item), elemref, true, true); - elemref->getRepr()->setAttribute("transform" , sp_svg_transform_write(transform)); + gchar *str = sp_svg_transform_write(transform); + elemref->getRepr()->setAttribute("transform" , str); + g_free(str); if (elemref->parent != container) { Inkscape::XML::Node *copy = phantom->duplicate(xml_doc); copy->setAttribute("id", elemref_id); diff --git a/src/svg/svg-affine-test.h b/src/svg/svg-affine-test.h index af670a3a8..829ef8a5a 100644 --- a/src/svg/svg-affine-test.h +++ b/src/svg/svg-affine-test.h @@ -67,7 +67,9 @@ public: void testWriteIdentity() { - TS_ASSERT_EQUALS(sp_svg_transform_write(Geom::identity()) , (void*)0) + gchar str = sp_svg_transform_write(Geom::identity()); + TS_ASSERT_EQUALS(str, NULL); + g_free(str); } void testReadMatrix() -- cgit v1.2.3 From a2e04c5fb43ae6331ac34e6ea809cbb7a0a1136a Mon Sep 17 00:00:00 2001 From: chr Date: Tue, 23 May 2017 21:48:27 +0200 Subject: selection chemistry: cancel if we hit top/bottom avoid unpredictable results in multi selections (bzr r15698.1.13) --- src/selection-chemistry.cpp | 16 ++++++++++++---- 1 file changed, 12 insertions(+), 4 deletions(-) (limited to 'src') diff --git a/src/selection-chemistry.cpp b/src/selection-chemistry.cpp index 7d5d921b0..b3d910700 100644 --- a/src/selection-chemistry.cpp +++ b/src/selection-chemistry.cpp @@ -1150,8 +1150,12 @@ void ObjectSet::stackUp(bool skip_undo) { sort(selection.begin(), selection.end(), sp_item_repr_compare_position_bool); for (auto item: selection | boost::adaptors::reversed) { - if (!item->raiseOne()) // stop if top was reached - break; + if (!item->raiseOne()) { // stop if top was reached + if(document() && !skip_undo) + DocumentUndo::cancel(document()); + selection_display_message(desktop(), Inkscape::WARNING_MESSAGE, _("We hit top.")); + return; + } } if(document() && !skip_undo) @@ -1170,8 +1174,12 @@ void ObjectSet::stackDown(bool skip_undo) { sort(selection.begin(), selection.end(), sp_item_repr_compare_position_bool); for (auto item: selection) { - if (!item->lowerOne()) // stop if bottom was reached - break; + if (!item->lowerOne()) { // stop if bottom was reached + if(document() && !skip_undo) + DocumentUndo::cancel(document()); + selection_display_message(desktop(), Inkscape::WARNING_MESSAGE, _("We hit bottom.")); + return; + } } if(document() && !skip_undo) -- cgit v1.2.3