diff options
Diffstat (limited to 'src/live_effects/parameter/satellitearray.cpp')
-rw-r--r-- | src/live_effects/parameter/satellitearray.cpp | 506 |
1 files changed, 506 insertions, 0 deletions
diff --git a/src/live_effects/parameter/satellitearray.cpp b/src/live_effects/parameter/satellitearray.cpp new file mode 100644 index 0000000..6516e1f --- /dev/null +++ b/src/live_effects/parameter/satellitearray.cpp @@ -0,0 +1,506 @@ +// SPDX-License-Identifier: GPL-2.0-or-later +/* + * Copyright (C) Jabiertxof <jabier.arraiza@marker.es> + * this class handle satellites of a lpe as a parameter + * Released under GNU GPL v2+, read the file 'COPYING' for more information. + */ + +#include "live_effects/parameter/satellitearray.h" +#include "live_effects/effect.h" +#include "live_effects/lpeobject.h" +#include "inkscape.h" +#include "ui/clipboard.h" +#include "ui/icon-loader.h" +#include <glibmm/i18n.h> + +namespace Inkscape { + +namespace LivePathEffect { + +class SatelliteArrayParam::ModelColumns : public Gtk::TreeModel::ColumnRecord +{ +public: + ModelColumns() + { + add(_colObject); + add(_colLabel); + add(_colActive); + } + ~ModelColumns() override = default; + + Gtk::TreeModelColumn<Glib::ustring> _colObject; + Gtk::TreeModelColumn<Glib::ustring> _colLabel; + Gtk::TreeModelColumn<bool> _colActive; +}; +SatelliteArrayParam::SatelliteArrayParam(const Glib::ustring &label, const Glib::ustring &tip, const Glib::ustring &key, + Inkscape::UI::Widget::Registry *wr, Effect *effect, bool visible) + : ArrayParam<std::shared_ptr<SatelliteReference>>(label, tip, key, wr, effect) + , _visible(visible) +{ + param_widget_is_visible(_visible); + if (_visible) { + _tree = nullptr; + _scroller = nullptr; + _model = nullptr; + initui(); + oncanvas_editable = true; + } +} + +SatelliteArrayParam::~SatelliteArrayParam() +{ + _vector.clear(); + if (_store.get() && _model) { + delete _model; + } + quit_listening(); +} + +void SatelliteArrayParam::initui() +{ + SPDesktop *desktop = SP_ACTIVE_DESKTOP; + if (!desktop) { + return; + } + if (!_tree) { + _tree = manage(new Gtk::TreeView()); + _model = new ModelColumns(); + _store = Gtk::TreeStore::create(*_model); + _tree->set_model(_store); + + _tree->set_reorderable(true); + _tree->enable_model_drag_dest(Gdk::ACTION_MOVE); + Gtk::CellRendererToggle *_toggle_active = manage(new Gtk::CellRendererToggle()); + int activeColNum = _tree->append_column(_("Active"), *_toggle_active) - 1; + Gtk::TreeViewColumn *col_active = _tree->get_column(activeColNum); + _toggle_active->set_activatable(true); + _toggle_active->signal_toggled().connect(sigc::mem_fun(*this, &SatelliteArrayParam::on_active_toggled)); + col_active->add_attribute(_toggle_active->property_active(), _model->_colActive); + + _text_renderer = manage(new Gtk::CellRendererText()); + int nameColNum = _tree->append_column(_("Name"), *_text_renderer) - 1; + _name_column = _tree->get_column(nameColNum); + _name_column->add_attribute(_text_renderer->property_text(), _model->_colLabel); + + _tree->set_expander_column(*_tree->get_column(nameColNum)); + _tree->set_search_column(_model->_colLabel); + + // quick little hack -- newer versions of gtk gave the item zero space allotment + _scroller = manage(new Gtk::ScrolledWindow()); + _scroller->set_size_request(-1, 120); + + _scroller->add(*_tree); + _scroller->set_policy(Gtk::POLICY_AUTOMATIC, Gtk::POLICY_AUTOMATIC); + //_scroller->set_shadow_type(Gtk::SHADOW_IN); + } + param_readSVGValue(param_getSVGValue().c_str()); +} + +void SatelliteArrayParam::start_listening() +{ + quit_listening(); + for (auto ref : _vector) { + if (ref && ref->isAttached()) { + SPItem *item = dynamic_cast<SPItem *>(ref->getObject()); + if (item) { + linked_connections.emplace_back(item->connectRelease( + sigc::hide(sigc::mem_fun(*this, &SatelliteArrayParam::updatesignal)))); + linked_connections.emplace_back(item->connectModified( + sigc::mem_fun(*this, &SatelliteArrayParam::linked_modified))); + linked_connections.emplace_back(item->connectTransformed( + sigc::hide(sigc::hide(sigc::mem_fun(*this, &SatelliteArrayParam::updatesignal))))); + linked_connections.emplace_back(ref->changedSignal().connect( + sigc::hide(sigc::hide(sigc::mem_fun(*this, &SatelliteArrayParam::updatesignal))))); + } + } + } +} + +void SatelliteArrayParam::linked_modified(SPObject *linked_obj, guint flags) { + if (!param_effect->is_load && param_effect->_lpe_action == LPE_NONE && + flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_CHILD_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG | + SP_OBJECT_VIEWPORT_MODIFIED_FLAG)) + { + param_effect->processObjects(LPE_UPDATE); + } +} + +void SatelliteArrayParam::updatesignal() +{ + if (!param_effect->is_load && param_effect->_lpe_action == LPE_NONE) { + param_effect->processObjects(LPE_UPDATE); + } +} + +void SatelliteArrayParam::quit_listening() +{ + for (auto connexion : linked_connections) { + if (connexion) { + connexion.disconnect(); + } + } + linked_connections.clear(); +}; + +void SatelliteArrayParam::on_active_toggled(const Glib::ustring &item) +{ + int i = 0; + for (auto w : _vector) { + if (w && w->isAttached() && w->getObject()) { + Gtk::TreeModel::Row row = *_store->get_iter(Glib::ustring::format(i)); + Glib::ustring id = w->getObject()->getId() ? w->getObject()->getId() : ""; + if (id == row[_model->_colObject]) { + row[_model->_colActive] = !row[_model->_colActive]; + w->setActive(row[_model->_colActive]); + i++; + break; + } + } + } + auto full = param_getSVGValue(); + param_write_to_repr(full.c_str()); + DocumentUndo::done(param_effect->getSPDoc(), _("Active switched"), ""); +} + +bool SatelliteArrayParam::param_readSVGValue(const gchar *strvalue) +{ + if (strvalue) { + bool changed = !linked_connections.size() || !param_effect->is_load; + if (!ArrayParam::param_readSVGValue(strvalue)) { + return false; + } + auto lpeitems = param_effect->getCurrrentLPEItems(); + if (!lpeitems.size() && !param_effect->is_applied && !param_effect->getSPDoc()->isSeeking()) { + size_t pos = 0; + for (auto w : _vector) { + if (w) { + SPObject * tmp = w->getObject(); + if (tmp) { + SPObject * successor = tmp->_successor; + unlink(tmp); + if (successor) { + link(successor,pos); + } + } + } + pos ++; + } + auto full = param_getSVGValue(); + param_write_to_repr(full.c_str()); + update_satellites(false); + } + if (_store.get()) { + _store->clear(); + for (auto w : _vector) { + if (w) { + Gtk::TreeModel::iterator iter = _store->append(); + Gtk::TreeModel::Row row = *iter; + if (auto obj = w->getObject()) { + row[_model->_colObject] = Glib::ustring(obj->getId()); + row[_model->_colLabel] = obj->label() ? obj->label() : obj->getId(); + row[_model->_colActive] = w->getActive(); + } + } + } + } + if (changed) { + start_listening(); + } + return true; + } + return false; +} + +bool SatelliteArrayParam::_selectIndex(const Gtk::TreeIter &iter, int *i) +{ + if ((*i)-- <= 0) { + _tree->get_selection()->select(iter); + return true; + } + return false; +} + +void SatelliteArrayParam::on_up_button_click() +{ + Gtk::TreeModel::iterator iter = _tree->get_selection()->get_selected(); + if (iter) { + Gtk::TreeModel::Row rowselected = *iter; + int i = 0; + for (auto w : _vector) { + if (w && w->isAttached() && w->getObject()) { + Gtk::TreeModel::Row row = *_store->get_iter(Glib::ustring::format(i)); + if (rowselected == row && i > 0) { + std::swap(_vector[i],_vector[i-1]); + i--; + break; + } + i++; + } + } + auto full = param_getSVGValue(); + param_write_to_repr(full.c_str()); + + DocumentUndo::done(param_effect->getSPDoc(), _("Move item up"), ""); + + _store->foreach_iter(sigc::bind<int *>(sigc::mem_fun(*this, &SatelliteArrayParam::_selectIndex), &i)); + } +} + +void SatelliteArrayParam::on_down_button_click() +{ + Gtk::TreeModel::iterator iter = _tree->get_selection()->get_selected(); + if (iter) { + Gtk::TreeModel::Row rowselected = *iter; + int i = 0; + for (auto w : _vector) { + if (w && w->isAttached() && w->getObject()) { + Gtk::TreeModel::Row row = *_store->get_iter(Glib::ustring::format(i)); + if (rowselected == row && i < _vector.size() - 1) { + std::swap(_vector[i],_vector[i+1]); + i++; + break; + } + i++; + } + } + auto full = param_getSVGValue(); + param_write_to_repr(full.c_str()); + + DocumentUndo::done(param_effect->getSPDoc(), _("Move item down"), ""); + + _store->foreach_iter(sigc::bind<int *>(sigc::mem_fun(*this, &SatelliteArrayParam::_selectIndex), &i)); + } +} + +void SatelliteArrayParam::on_remove_button_click() +{ + Gtk::TreeModel::iterator iter = _tree->get_selection()->get_selected(); + if (iter) { + Gtk::TreeModel::Row row = *iter; + unlink(param_effect->getSPDoc()->getObjectById(row[_model->_colObject])); + + auto full = param_getSVGValue(); + param_write_to_repr(full.c_str()); + + DocumentUndo::done(param_effect->getSPDoc(), _("Remove item"), ""); + } +} + +void SatelliteArrayParam::on_link_button_click() +{ + Inkscape::UI::ClipboardManager *cm = Inkscape::UI::ClipboardManager::get(); + std::vector<Glib::ustring> itemsid; + // Here we ignore auto clipboard group wrapper + std::vector<Glib::ustring> itemsids = cm->getElementsOfType(SP_ACTIVE_DESKTOP, "*", 2); + std::vector<Glib::ustring> containers = cm->getElementsOfType(SP_ACTIVE_DESKTOP, "*", 1); + for (auto item : itemsids) { + bool cont = false; + for (auto citems : containers) { + if (citems == item) { + cont = true; + } + } + if (cont == false) { + itemsid.push_back(item); + } + } + if (itemsid.empty()) { + return; + } + auto hreflist = param_effect->getLPEObj()->hrefList; + if (hreflist.size()) { + SPLPEItem *sp_lpe_item = dynamic_cast<SPLPEItem *>(*hreflist.begin()); + if (sp_lpe_item) { + for (auto itemid : itemsid) { + SPObject *added = param_effect->getSPDoc()->getObjectById(itemid); + if (added && sp_lpe_item != added) { + itemid.insert(itemid.begin(), '#'); + std::shared_ptr<SatelliteReference> satellitereference = + std::make_shared<SatelliteReference>(param_effect->getLPEObj(), _visible); + try { + satellitereference->attach(Inkscape::URI(itemid.c_str())); + satellitereference->setActive(true); + _vector.push_back(satellitereference); + } catch (Inkscape::BadURIException &e) { + g_warning("%s", e.what()); + satellitereference->detach(); + } + } + } + } + } + write_to_SVG(); + DocumentUndo::done(param_effect->getSPDoc(), _("Link itemarray parameter to item"), ""); +} + +Gtk::Widget *SatelliteArrayParam::param_newWidget() +{ + if (!_visible) { + return nullptr; + } + Gtk::Box *vbox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_VERTICAL)); + Gtk::Box *hbox = Gtk::manage(new Gtk::Box(Gtk::ORIENTATION_HORIZONTAL)); + _tree = nullptr; + _scroller = nullptr; + _model = nullptr; + initui(); + vbox->pack_start(*_scroller, Gtk::PACK_EXPAND_WIDGET); + + { // Paste item to link button + Gtk::Image *pIcon = Gtk::manage(sp_get_icon_image("edit-clone", Gtk::ICON_SIZE_BUTTON)); + Gtk::Button *pButton = Gtk::manage(new Gtk::Button()); + pButton->set_relief(Gtk::RELIEF_NONE); + pIcon->show(); + pButton->add(*pIcon); + pButton->show(); + pButton->signal_clicked().connect(sigc::mem_fun(*this, &SatelliteArrayParam::on_link_button_click)); + hbox->pack_start(*pButton, Gtk::PACK_SHRINK); + pButton->set_tooltip_text(_("Link to item")); + } + + { // Remove linked item + Gtk::Image *pIcon = Gtk::manage(sp_get_icon_image("list-remove", Gtk::ICON_SIZE_BUTTON)); + Gtk::Button *pButton = Gtk::manage(new Gtk::Button()); + pButton->set_relief(Gtk::RELIEF_NONE); + pIcon->show(); + pButton->add(*pIcon); + pButton->show(); + pButton->signal_clicked().connect(sigc::mem_fun(*this, &SatelliteArrayParam::on_remove_button_click)); + hbox->pack_start(*pButton, Gtk::PACK_SHRINK); + pButton->set_tooltip_text(_("Remove Item")); + } + + { // Move Down + Gtk::Image *pIcon = Gtk::manage(sp_get_icon_image("go-down", Gtk::ICON_SIZE_BUTTON)); + Gtk::Button *pButton = Gtk::manage(new Gtk::Button()); + pButton->set_relief(Gtk::RELIEF_NONE); + pIcon->show(); + pButton->add(*pIcon); + pButton->show(); + pButton->signal_clicked().connect(sigc::mem_fun(*this, &SatelliteArrayParam::on_down_button_click)); + hbox->pack_end(*pButton, Gtk::PACK_SHRINK); + pButton->set_tooltip_text(_("Move Down")); + } + + { // Move Down + Gtk::Image *pIcon = Gtk::manage(sp_get_icon_image("go-up", Gtk::ICON_SIZE_BUTTON)); + Gtk::Button *pButton = Gtk::manage(new Gtk::Button()); + pButton->set_relief(Gtk::RELIEF_NONE); + pIcon->show(); + pButton->add(*pIcon); + pButton->show(); + pButton->signal_clicked().connect(sigc::mem_fun(*this, &SatelliteArrayParam::on_up_button_click)); + hbox->pack_end(*pButton, Gtk::PACK_SHRINK); + pButton->set_tooltip_text(_("Move Up")); + } + + vbox->pack_end(*hbox, Gtk::PACK_SHRINK); + + vbox->show_all_children(true); + + return vbox; +} + +std::vector<SPObject *> SatelliteArrayParam::param_get_satellites() +{ + std::vector<SPObject *> objs; + for (auto &iter : _vector) { + if (iter && iter->isAttached()) { + SPObject *obj = iter->getObject(); + if (obj) { + objs.push_back(obj); + } + } + } + return objs; +} + +/* + * This function link a satellite writing into XML directly + * @param obj: object to link + * @param obj: position in vector + */ +void SatelliteArrayParam::link(SPObject *obj, size_t pos) +{ + if (obj && obj->getId()) { + Glib::ustring itemid = "#"; + itemid += obj->getId(); + std::shared_ptr<SatelliteReference> satellitereference = + std::make_shared<SatelliteReference>(param_effect->getLPEObj(), _visible); + try { + satellitereference->attach(Inkscape::URI(itemid.c_str())); + if (_visible) { + satellitereference->setActive(true); + } + if (_vector.size() == pos || pos == Glib::ustring::npos) { + _vector.push_back(satellitereference); + } else { + _vector[pos] = satellitereference; + } + } catch (Inkscape::BadURIException &e) { + g_warning("%s", e.what()); + satellitereference->detach(); + } + } +} + +void SatelliteArrayParam::unlink(SPObject *obj) +{ + if (!obj) { + return; + } + gint pos = -1; + for (auto w : _vector) { + pos++; + if (w) { + if (w->getObject() == obj) { + break; + } + } + } + if (pos != -1) { + _vector.erase(_vector.begin() + pos); + _vector.insert(_vector.begin() + pos, nullptr); + } +} + +void SatelliteArrayParam::unlink(std::shared_ptr<SatelliteReference> to) +{ + if (!to) { + return; + } + gint pos = -1; + for (auto w : _vector) { + pos++; + if (w) { + if (w->getObject() == to->getObject()) { + break; + } + + } + } + if (pos != -1) { + _vector.erase(_vector.begin() + pos); + _vector.insert(_vector.begin() + pos, nullptr); + } +} + +void SatelliteArrayParam::clear() +{ + _vector.clear(); +} + +} /* namespace LivePathEffect */ + +} /* namespace Inkscape */ + +/* + 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 : |