From: Krzysztof Kosiński Date: Sat, 5 Dec 2009 02:48:07 +0000 (+0100) Subject: Fix mask editing behavior on undo and outline display for masks/clips; X-Git-Url: https://git.tokkee.org/?a=commitdiff_plain;h=c635a682d950f1421ca59bdb63e2bf83db697ad3;p=inkscape.git Fix mask editing behavior on undo and outline display for masks/clips; prepare to fix LPE path parameters --- diff --git a/src/ui/tool/multi-path-manipulator.cpp b/src/ui/tool/multi-path-manipulator.cpp index 6b245702a..7c539f6b9 100644 --- a/src/ui/tool/multi-path-manipulator.cpp +++ b/src/ui/tool/multi-path-manipulator.cpp @@ -16,6 +16,7 @@ #include "desktop-handles.h" #include "document.h" #include "message-stack.h" +#include "preferences.h" #include "sp-path.h" #include "ui/tool/control-point-selection.h" #include "ui/tool/event-utils.h" @@ -130,36 +131,48 @@ void MultiPathManipulator::cleanup() } } -void MultiPathManipulator::setItems(std::map > const &items) +void MultiPathManipulator::setItems(std::set const &s) { - typedef std::map > TransMap; - typedef std::set ItemSet; - ItemSet to_remove, to_add, current, new_items; - - for (MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) { - current.insert(i->first); - } - for (TransMap::const_iterator i = items.begin(); i != items.end(); ++i) { - new_items.insert(i->first); + std::set shapes(s); + + // iterate over currently edited items, modifying / removing them as necessary + for (MapType::iterator i = _mmap.begin(); i != _mmap.end();) { + std::set::iterator si = shapes.find(i->first); + if (si == shapes.end()) { + // This item is no longer supposed to be edited - remove its manipulator + _mmap.erase(i++); + } else { + ShapeRecord const &sr = i->first; + ShapeRecord const &sr_new = *si; + // if the shape record differs, replace the key only and modify other values + if (sr.edit_transform != sr_new.edit_transform || + sr.role != sr_new.role) + { + boost::shared_ptr hold(i->second); + if (sr.edit_transform != sr_new.edit_transform) + hold->setControlsTransform(sr_new.edit_transform); + if (sr.role != sr_new.role) { + //hold->setOutlineColor(_getOutlineColor(sr_new.role)); + } + _mmap.erase(sr); + _mmap.insert(std::make_pair(sr_new, hold)); + } + shapes.erase(si); // remove the processed record + ++i; + } } - std::set_difference(current.begin(), current.end(), new_items.begin(), new_items.end(), - std::inserter(to_remove, to_remove.end())); - std::set_difference(new_items.begin(), new_items.end(), current.begin(), current.end(), - std::inserter(to_add, to_add.end())); - - for (ItemSet::iterator i = to_remove.begin(); i != to_remove.end(); ++i) { - _mmap.erase(*i); - } - for (ItemSet::iterator i = to_add.begin(); i != to_add.end(); ++i) { - boost::shared_ptr pm; - TransMap::const_iterator f = items.find(*i); - pm.reset(new PathManipulator(_path_data, *i, f->second.first, f->second.second)); - pm->showHandles(_show_handles); - pm->showOutline(_show_outline); - pm->showPathDirection(_show_path_direction); - _mmap.insert(std::make_pair(*i, pm)); + // add newly selected items + for (std::set::iterator i = shapes.begin(); i != shapes.end(); ++i) { + ShapeRecord const &r = *i; + if (!SP_IS_PATH(r.item)) continue; + boost::shared_ptr newpm(new PathManipulator(_path_data, (SPPath*) r.item, + r.edit_transform, _getOutlineColor(r.role))); + newpm->showHandles(_show_handles); + // always show outlines for clips and masks + newpm->showOutline(_show_outline || r.role != SHAPE_ROLE_NORMAL); + newpm->showPathDirection(_show_path_direction); + _mmap.insert(std::make_pair(r, newpm)); } } @@ -369,7 +382,10 @@ void MultiPathManipulator::move(Geom::Point const &delta) void MultiPathManipulator::showOutline(bool show) { - invokeForAll(&PathManipulator::showOutline, show); + for (MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) { + // always show outlines for clipping paths and masks + i->second->showOutline(show || i->first.role != SHAPE_ROLE_NORMAL); + } _show_outline = show; } @@ -385,6 +401,13 @@ void MultiPathManipulator::showPathDirection(bool show) _show_path_direction = show; } +void MultiPathManipulator::updateOutlineColors() +{ + //for (MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) { + // i->second->setOutlineColor(_getOutlineColor(i->first.role)); + //} +} + bool MultiPathManipulator::event(GdkEvent *event) { switch (event->type) { @@ -553,6 +576,22 @@ void MultiPathManipulator::_doneWithCleanup(gchar const *reason) { _changed.unblock(); } +guint32 MultiPathManipulator::_getOutlineColor(ShapeRole role) +{ + Inkscape::Preferences *prefs = Inkscape::Preferences::get(); + switch(role) { + case SHAPE_ROLE_CLIPPING_PATH: + return prefs->getColor("/tools/nodes/clipping_path_color", 0x00ff00ff); + case SHAPE_ROLE_MASK: + return prefs->getColor("/tools/nodes/mask_color", 0x0000ffff); + case SHAPE_ROLE_LPE_PARAM: + return prefs->getColor("/tools/nodes/lpe_param_color", 0xb700ffff); + case SHAPE_ROLE_NORMAL: + default: + return prefs->getColor("/tools/nodes/outline_color", 0xff0000ff); + } +} + } // namespace UI } // namespace Inkscape diff --git a/src/ui/tool/multi-path-manipulator.h b/src/ui/tool/multi-path-manipulator.h index 89c86b019..b66451ad3 100644 --- a/src/ui/tool/multi-path-manipulator.h +++ b/src/ui/tool/multi-path-manipulator.h @@ -14,9 +14,10 @@ #include #include "display/display-forward.h" #include "forward.h" +#include "ui/tool/commit-events.h" #include "ui/tool/manipulator.h" #include "ui/tool/node-types.h" -#include "ui/tool/commit-events.h" +#include "ui/tool/shape-record.h" struct SPCanvasGroup; @@ -40,7 +41,8 @@ public: bool empty() { return _mmap.empty(); } unsigned size() { return _mmap.empty(); } // TODO fix this garbage! - void setItems(std::map > const &items); + void setItems(std::set const &); + //std::map > const &items); void clear() { _mmap.clear(); } void cleanup(); @@ -71,12 +73,12 @@ public: void showOutline(bool show); void showHandles(bool show); void showPathDirection(bool show); - void setOutlineTransform(SPPath *item, Geom::Matrix const &t); + void updateOutlineColors(); sigc::signal signal_coords_changed; private: - typedef std::pair > MapPair; - typedef std::map > MapType; + typedef std::pair > MapPair; + typedef std::map > MapType; template void invokeForAll(R (PathManipulator::*method)()) { @@ -106,7 +108,7 @@ private: void _commit(CommitEvent cps); void _done(gchar const *); void _doneWithCleanup(gchar const *); - void _storeClipMaskItems(SPObject *obj, std::set &, bool); + guint32 _getOutlineColor(ShapeRole role); MapType _mmap; PathSharedData const &_path_data; diff --git a/src/ui/tool/node-tool.cpp b/src/ui/tool/node-tool.cpp index a57057c92..31c722744 100644 --- a/src/ui/tool/node-tool.cpp +++ b/src/ui/tool/node-tool.cpp @@ -32,6 +32,7 @@ #include "ui/tool/multi-path-manipulator.h" #include "ui/tool/path-manipulator.h" #include "ui/tool/selector.h" +#include "ui/tool/shape-record.h" #include "pixmaps/cursor-node.xpm" #include "pixmaps/cursor-node-d.xpm" @@ -108,6 +109,7 @@ void ink_node_tool_init(InkNodeTool *nt) event_context->hot_y = 1; new (&nt->_selection_changed_connection) sigc::connection(); + new (&nt->_selection_modified_connection) sigc::connection(); new (&nt->_mouseover_changed_connection) sigc::connection(); //new (&nt->_mgroup) Inkscape::UI::ManipulatorGroup(nt->desktop); new (&nt->_selected_nodes) CSelPtr(); @@ -123,6 +125,7 @@ void ink_node_tool_dispose(GObject *object) nt->enableGrDrag(false); nt->_selection_changed_connection.disconnect(); + nt->_selection_modified_connection.disconnect(); nt->_mouseover_changed_connection.disconnect(); nt->_multipath.~MultiPathPtr(); nt->_selected_nodes.~CSelPtr(); @@ -138,6 +141,7 @@ void ink_node_tool_dispose(GObject *object) nt->_path_data.~PathSharedDataPtr(); nt->_selection_changed_connection.~connection(); + nt->_selection_modified_connection.~connection(); nt->_mouseover_changed_connection.~connection(); if (nt->_node_message_context) { @@ -183,6 +187,12 @@ void ink_node_tool_setup(SPEventContext *ec) sigc::bind<0>( sigc::ptr_fun(&ink_node_tool_selection_changed), nt)); + nt->_selection_modified_connection.disconnect(); + nt->_selection_modified_connection = + selection->connectModified( + sigc::hide(sigc::bind<0>( + sigc::ptr_fun(&ink_node_tool_selection_changed), + nt))); nt->_mouseover_changed_connection.disconnect(); nt->_mouseover_changed_connection = Inkscape::UI::ControlPoint::signal_mouseover_change.connect( @@ -298,6 +308,36 @@ void store_clip_mask_items(SPItem *clipped, SPObject *obj, std::map &s) +{ + using namespace Inkscape::UI; + if (!obj) return; + if (role != SHAPE_ROLE_NORMAL && (SP_IS_GROUP(obj) || SP_IS_OBJECTGROUP(obj))) { + for (SPObject *c = obj->children; c; c = c->next) { + gather_items(nt, base, c, role, s); + } + } else if (SP_IS_ITEM(obj)) { + SPItem *item = static_cast(obj); + ShapeRecord r; + r.item = item; + // TODO add support for objectBoundingBox + r.edit_transform = base ? sp_item_i2doc_affine(base) : Geom::identity(); + r.role = role; + r.edit_original = false; + if (s.insert(r).second) { + // this item was encountered the first time + if (nt->edit_clipping_paths && item->clip_ref) { + gather_items(nt, item, item->clip_ref->getObject(), SHAPE_ROLE_CLIPPING_PATH, s); + } + if (nt->edit_masks && item->mask_ref) { + gather_items(nt, item, item->mask_ref->getObject(), SHAPE_ROLE_MASK, s); + } + } + } +} + struct IsPath { bool operator()(SPItem *i) const { return SP_IS_PATH(i); } }; @@ -305,41 +345,28 @@ struct IsPath { void ink_node_tool_selection_changed(InkNodeTool *nt, Inkscape::Selection *sel) { using namespace Inkscape::UI; + + std::set shapes; + // TODO this is ugly!!! - typedef std::map > TransMap; - typedef std::map > PathMap; + //typedef std::map > TransMap; + //typedef std::map > PathMap; GSList const *ilist = sel->itemList(); - TransMap items; - Inkscape::Preferences *prefs = Inkscape::Preferences::get(); for (GSList *i = const_cast(ilist); i; i = i->next) { SPObject *obj = static_cast(i->data); if (SP_IS_ITEM(obj)) { - items.insert(std::make_pair(SP_ITEM(obj), - std::make_pair(Geom::identity(), - prefs->getColor("/tools/nodes/outline_color", 0xff0000ff)))); - if (nt->edit_clipping_paths && SP_ITEM(i->data)->clip_ref) { - store_clip_mask_items(SP_ITEM(i->data), - SP_OBJECT(SP_ITEM(i->data)->clip_ref->getObject()), items, - nt->desktop->dt2doc(), - prefs->getColor("/tools/nodes/clipping_path_color", 0x00ff00ff)); - } - if (nt->edit_masks && SP_ITEM(i->data)->mask_ref) { - store_clip_mask_items(SP_ITEM(i->data), - SP_OBJECT(SP_ITEM(i->data)->mask_ref->getObject()), items, - nt->desktop->dt2doc(), - prefs->getColor("/tools/nodes/mask_color", 0x0000ffff)); - } + gather_items(nt, NULL, static_cast(obj), SHAPE_ROLE_NORMAL, shapes); } } // ugly hack: set the first editable non-path item for knotholder // maybe use multiple ShapeEditors for now, to allow editing many shapes at once? bool something_set = false; - for (TransMap::iterator i = items.begin(); i != items.end(); ++i) { - SPItem *obj = i->first; - if (SP_IS_SHAPE(obj) && !SP_IS_PATH(obj)) { - nt->shape_editor->set_item(obj, SH_KNOTHOLDER); + for (std::set::iterator i = shapes.begin(); i != shapes.end(); ++i) { + ShapeRecord const &r = *i; + if (SP_IS_SHAPE(r.item) && !SP_IS_PATH(r.item)) { + nt->shape_editor->set_item(r.item, SH_KNOTHOLDER); something_set = true; break; } @@ -347,16 +374,8 @@ void ink_node_tool_selection_changed(InkNodeTool *nt, Inkscape::Selection *sel) if (!something_set) { nt->shape_editor->unset_item(SH_KNOTHOLDER); } - - PathMap p; - for (TransMap::iterator i = items.begin(); i != items.end(); ++i) { - if (SP_IS_PATH(i->first)) { - p.insert(std::make_pair(SP_PATH(i->first), - std::make_pair(i->second.first, i->second.second))); - } - } - nt->_multipath->setItems(p); + nt->_multipath->setItems(shapes); ink_node_tool_update_tip(nt, NULL); nt->desktop->updateNow(); } diff --git a/src/ui/tool/node-tool.h b/src/ui/tool/node-tool.h index f47ea0ccb..65b16ff72 100644 --- a/src/ui/tool/node-tool.h +++ b/src/ui/tool/node-tool.h @@ -46,6 +46,7 @@ struct InkNodeTool : public SPEventContext { sigc::connection _selection_changed_connection; sigc::connection _mouseover_changed_connection; + sigc::connection _selection_modified_connection; Inkscape::MessageContext *_node_message_context; SPItem *flashed_item; Inkscape::Display::TemporaryItem *flash_tempitem; diff --git a/src/ui/tool/path-manipulator.cpp b/src/ui/tool/path-manipulator.cpp index ef8572330..e9ec78b2e 100644 --- a/src/ui/tool/path-manipulator.cpp +++ b/src/ui/tool/path-manipulator.cpp @@ -690,6 +690,18 @@ void PathManipulator::showPathDirection(bool show) _updateOutline(); } +void PathManipulator::setControlsTransform(Geom::Matrix const &tnew) +{ + Geom::Matrix delta = _i2d_transform.inverse() * _edit_transform.inverse() * tnew * _i2d_transform; + _edit_transform = tnew; + for (SubpathList::iterator i = _subpaths.begin(); i != _subpaths.end(); ++i) { + for (NodeList::iterator j = (*i)->begin(); j != (*i)->end(); ++j) { + j->transform(delta); + } + } + _createGeometryFromControlPoints(); +} + /** Insert a node in the segment beginning with the supplied iterator, * at the given time value */ NodeList::iterator PathManipulator::subdivideSegment(NodeList::iterator first, double t) diff --git a/src/ui/tool/path-manipulator.h b/src/ui/tool/path-manipulator.h index 9ed9e4fb6..01a2b6cbf 100644 --- a/src/ui/tool/path-manipulator.h +++ b/src/ui/tool/path-manipulator.h @@ -80,7 +80,7 @@ public: void showOutline(bool show); void showHandles(bool show); void showPathDirection(bool show); - void setOutlineTransform(Geom::Matrix const &); + void setControlsTransform(Geom::Matrix const &); NodeList::iterator subdivideSegment(NodeList::iterator after, double t); diff --git a/src/ui/tool/shape-record.h b/src/ui/tool/shape-record.h new file mode 100644 index 000000000..cc2f8be40 --- /dev/null +++ b/src/ui/tool/shape-record.h @@ -0,0 +1,56 @@ +/** @file + * Structures that store data needed for shape editing which are not contained + * directly in the XML node + */ +/* Authors: + * Krzysztof Kosiński + * + * Copyright (C) 2009 Authors + * Released under GNU GPL, read the file 'COPYING' for more information + */ + +#ifndef SEEN_UI_TOOL_SHAPE_RECORD_H +#define SEEN_UI_TOOL_SHAPE_RECORD_H + +#include +#include <2geom/matrix.h> + +class SPItem; +namespace Inkscape { +namespace UI { + +/** Role of the shape in the drawing - affects outline display and color */ +enum ShapeRole { + SHAPE_ROLE_NORMAL, + SHAPE_ROLE_CLIPPING_PATH, + SHAPE_ROLE_MASK, + SHAPE_ROLE_LPE_PARAM // implies edit_original set to true in ShapeRecord +}; + +struct ShapeRecord : + public boost::totally_ordered +{ + SPItem *item; // SP node for the edited shape + Geom::Matrix edit_transform; // how to transform controls - used for clipping paths and masks + ShapeRole role; + bool edit_original; // whether to use original-d instead of d for editing + + inline bool operator==(ShapeRecord const &o) const { return item == o.item; } + inline bool operator<(ShapeRecord const &o) const { return item < o.item; } +}; + +} // namespace UI +} // namespace Inkscape + +#endif + +/* + Local Variables: + mode:c++ + c-file-style:"stroustrup" + c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +)) + indent-tabs-mode:nil + fill-column:99 + End: +*/ +// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:encoding=utf-8:textwidth=99 :