// SPDX-License-Identifier: GPL-2.0-or-later /** @file * Manipulator - edits something on-canvas */ /* Authors: * Krzysztof KosiƄski * * Copyright (C) 2009 Authors * Released under GNU GPL v2+, read the file 'COPYING' for more information. */ #ifndef SEEN_UI_TOOL_MANIPULATOR_H #define SEEN_UI_TOOL_MANIPULATOR_H #include #include #include #include #include #include #include "ui/tools/tool-base.h" class SPDesktop; namespace Inkscape { namespace UI { class ManipulatorGroup; class ControlPointSelection; /** * @brief Tool component that processes events and does something in response to them. * Note: this class is probably redundant. */ class Manipulator { friend class ManipulatorGroup; public: Manipulator(SPDesktop *d) : _desktop(d) {} virtual ~Manipulator() = default; /// Handle input event. Returns true if handled. virtual bool event(Inkscape::UI::Tools::ToolBase *, GdkEvent *)=0; SPDesktop *const _desktop; }; /** * @brief Tool component that edits something on the canvas using selectable control points. * Note: this class is probably redundant. */ class PointManipulator : public Manipulator, public sigc::trackable { public: PointManipulator(SPDesktop *d, ControlPointSelection &sel) : Manipulator(d) , _selection(sel) {} /// Type of extremum points to add in PathManipulator::insertNodeAtExtremum enum ExtremumType { EXTR_MIN_X = 0, EXTR_MAX_X, EXTR_MIN_Y, EXTR_MAX_Y }; protected: ControlPointSelection &_selection; }; /** Manipulator that aggregates several manipulators of the same type. * The order of invoking events on the member manipulators is undefined. * To make this class more useful, derive from it and add actions that can be performed * on all manipulators in the set. * * This is not used at the moment and is probably useless. */ template class MultiManipulator : public PointManipulator { public: //typedef typename T::ItemType ItemType; typedef typename std::pair > MapPair; typedef typename std::map > MapType; MultiManipulator(SPDesktop *d, ControlPointSelection &sel) : PointManipulator(d, sel) {} void addItem(void *item) { std::shared_ptr m(_createManipulator(item)); _mmap.insert(MapPair(item, m)); } void removeItem(void *item) { _mmap.erase(item); } void clear() { _mmap.clear(); } bool contains(void *item) { return _mmap.find(item) != _mmap.end(); } bool empty() { return _mmap.empty(); } void setItems(std::vector list) { // this function is not called anywhere ... delete ? std::set to_remove; for (typename MapType::iterator mi = _mmap.begin(); mi != _mmap.end(); ++mi) { to_remove.insert(mi->first); } for (auto i:list) { if (_isItemType(i)) { // erase returns the number of items removed // if nothing was removed, it means this item did not have a manipulator - add it if (!to_remove.erase(i)) addItem(i); } } for (auto ri : to_remove) { removeItem(ri); } } /** Invoke a method on all managed manipulators. * Example: * @code m.invokeForAll(&SomeManipulator::someMethod); @endcode */ template void invokeForAll(R (T::*method)()) { for (typename MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) { ((i->second.get())->*method)(); } } template void invokeForAll(R (T::*method)(A), A a) { for (typename MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) { ((i->second.get())->*method)(a); } } template void invokeForAll(R (T::*method)(A const &), A const &a) { for (typename MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) { ((i->second.get())->*method)(a); } } template void invokeForAll(R (T::*method)(A,B), A a, B b) { for (typename MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) { ((i->second.get())->*method)(a, b); } } bool event(Inkscape::UI::Tools::ToolBase *event_context, GdkEvent *event) override { for (typename MapType::iterator i = _mmap.begin(); i != _mmap.end(); ++i) { if ((*i).second->event(event_context, event)) return true; } return false; } protected: virtual T *_createManipulator(void *item) = 0; virtual bool _isItemType(void *item) = 0; MapType _mmap; }; } // 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:fileencoding=utf-8:textwidth=99 :