Inkscape
Vector Graphics Editor
Loading...
Searching...
No Matches
satellitearray.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2/*
3 * Copyright (C) Jabiertxof <jabier.arraiza@marker.es>
4 * this class handle satellites of a lpe as a parameter
5 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
6 */
7
8#include "satellitearray.h"
9
10#include <algorithm>
11#include <string>
12#include <utility>
13#include <glibmm/i18n.h>
14#include <gtkmm/box.h>
15#include <gtkmm/button.h>
16#include <gtkmm/cellrenderertext.h>
17#include <gtkmm/cellrenderertoggle.h>
18#include <gtkmm/image.h>
19#include <gtkmm/scrolledwindow.h>
20#include <gtkmm/treemodel.h>
21#include <gtkmm/treestore.h>
22#include <gtkmm/treeview.h>
23
24#include "inkscape.h"
25#include "selection.h"
26#include "live_effects/effect.h"
28#include "object/sp-lpe-item.h"
29#include "ui/clipboard.h"
30#include "ui/icon-loader.h"
31#include "ui/icon-names.h"
32#include "ui/pack.h"
33
35
36class SatelliteArrayParam::ModelColumns : public Gtk::TreeModel::ColumnRecord
37{
38public:
39 ModelColumns()
40 {
41 add(_colObject);
42 add(_colLabel);
43 add(_colActive);
44 }
45
46 Gtk::TreeModelColumn<Glib::ustring> _colObject;
47 Gtk::TreeModelColumn<Glib::ustring> _colLabel;
48 Gtk::TreeModelColumn<bool> _colActive;
49};
50
51SatelliteArrayParam::SatelliteArrayParam(const Glib::ustring &label, const Glib::ustring &tip, const Glib::ustring &key,
53 : ArrayParam<std::shared_ptr<SatelliteReference>>(label, tip, key, wr, effect)
54 , _visible(visible)
55{
57
58 if (_visible) {
59 initui();
60 oncanvas_editable = true;
61 }
62}
63
65 _vector.clear();
66 if (_store.get() && _model) {
67 _model.reset();
68 }
70}
71
73{
74 SPDesktop *desktop = SP_ACTIVE_DESKTOP;
75 if (!desktop) {
76 return;
77 }
78
79 if (!_tree) {
80 _tree = std::make_unique<Gtk::TreeView>();
81 _model = std::make_unique<ModelColumns>();
82 _store = Gtk::TreeStore::create(*_model);
83 _tree->set_model(_store);
84
85 _tree->set_reorderable(true);
86 _tree->enable_model_drag_dest(Gdk::DragAction::MOVE);
87
88 auto const toggle_active = Gtk::make_managed<Gtk::CellRendererToggle>();
89 int activeColNum = _tree->append_column(_("Active"), *toggle_active) - 1;
90 Gtk::TreeViewColumn *col_active = _tree->get_column(activeColNum);
91 toggle_active->set_activatable(true);
92 toggle_active->signal_toggled().connect(sigc::mem_fun(*this, &SatelliteArrayParam::on_active_toggled));
93 col_active->add_attribute(toggle_active->property_active(), _model->_colActive);
94
95 auto const text_renderer = Gtk::make_managed<Gtk::CellRendererText>();
96 int nameColNum = _tree->append_column(_("Name"), *text_renderer) - 1;
97 auto const name_column = _tree->get_column(nameColNum);
98 name_column->add_attribute(text_renderer->property_text(), _model->_colLabel);
99
100 _tree->set_expander_column(*_tree->get_column(nameColNum));
101 _tree->set_search_column(_model->_colLabel);
102
103 _scroller = std::make_unique<Gtk::ScrolledWindow>();
104 // quick little hack -- newer versions of gtk gave the item zero space allotment
105 _scroller->set_size_request(-1, 120);
106 _scroller->set_child(*_tree);
107 _scroller->set_policy(Gtk::PolicyType::AUTOMATIC, Gtk::PolicyType::AUTOMATIC);
108 }
110}
111
113{
115 for (auto const &ref : _vector) {
116 if (ref && ref->isAttached()) {
117 auto item = cast<SPItem>(ref->getObject());
118 if (item) {
120 sigc::hide(sigc::mem_fun(*this, &SatelliteArrayParam::updatesignal))));
122 sigc::mem_fun(*this, &SatelliteArrayParam::linked_modified)));
124 sigc::hide(sigc::hide(sigc::mem_fun(*this, &SatelliteArrayParam::updatesignal)))));
125 linked_connections.emplace_back(ref->changedSignal().connect(
126 sigc::hide(sigc::hide(sigc::mem_fun(*this, &SatelliteArrayParam::updatesignal)))));
127 }
128 }
129 }
130}
131
132void SatelliteArrayParam::linked_modified(SPObject *linked_obj, guint flags) {
133 if (!_updating && (!SP_ACTIVE_DESKTOP || SP_ACTIVE_DESKTOP->getSelection()->includes(linked_obj)) &&
134 (!param_effect->is_load || ownerlocator || !SP_ACTIVE_DESKTOP ) &&
137 flags & (SP_OBJECT_MODIFIED_FLAG | SP_OBJECT_STYLE_MODIFIED_FLAG |
138 SP_OBJECT_CHILD_MODIFIED_FLAG | SP_OBJECT_VIEWPORT_MODIFIED_FLAG))
139 {
141 }
142}
143
145{
146 if (!_updating &&
147 (!param_effect->is_load || ownerlocator || !SP_ACTIVE_DESKTOP ) &&
149 && param_effect->isReady())
150 {
152 }
153}
154
159
161{
162 int i = 0;
163 for (auto const &w : _vector) {
164 if (w && w->isAttached() && w->getObject()) {
165 auto row = *_store->get_iter(std::to_string(i));
166 Glib::ustring id = w->getObject()->getId() ? w->getObject()->getId() : "";
167 if (id == row.get_value(_model->_colObject)) {
168 auto active = row[_model->_colActive];
169 active = !active;
170 w->setActive(active);
171 i++;
172 break;
173 }
174 }
175 }
176 param_effect->makeUndoDone(_("Active switched"));
177}
178
179bool SatelliteArrayParam::param_readSVGValue(char const * const strvalue)
180{
181 if (strvalue) {
182 bool changed = !linked_connections.size() || !param_effect->is_load;
183 if (!ArrayParam::param_readSVGValue(strvalue)) {
184 return false;
185 }
186 auto lpeitems = param_effect->getCurrrentLPEItems();
187 if (!lpeitems.size() && !param_effect->is_applied && !param_effect->getSPDoc()->isSeeking()) {
188 size_t pos = 0;
189 for (auto const &w : _vector) {
190 if (w) {
191 SPObject * tmp = w->getObject();
192 if (tmp) {
193 SPObject * tmpsuccessor = tmp->_tmpsuccessor;
194 unlink(tmp);
195 if (tmpsuccessor && tmpsuccessor->getId()) {
196 link(tmpsuccessor,pos);
197 }
198 }
199 }
200 pos ++;
201 }
204 }
205 if (_store.get()) {
206 _store->clear();
207 for (auto const &w : _vector) {
208 if (w) {
209 auto const iter = _store->append();
210 Gtk::TreeModel::Row row = *iter;
211 if (auto obj = w->getObject()) {
212 row[_model->_colObject] = Glib::ustring(obj->getId());
213 row[_model->_colLabel] = obj->label() ? obj->label() : obj->getId();
214 row[_model->_colActive] = w->getActive();
215 }
216 }
217 }
218 }
219 if (changed) {
221 }
222 return true;
223 }
224 return false;
225}
226
227bool SatelliteArrayParam::_selectIndex(const Gtk::TreeModel::iterator &iter, int *i)
228{
229 if ((*i)-- <= 0) {
230 _tree->get_selection()->select(iter);
231 return true;
232 }
233 return false;
234}
235
236void SatelliteArrayParam::move_up_down(int const delta, Glib::ustring const &word)
237{
238 auto const iter_selected = _tree->get_selection()->get_selected();
239 if (!iter_selected) return;
240
241 int i = 0;
242 for (auto const &w : _vector) {
243 if (w && w->isAttached() && w->getObject()) {
244 auto const iter = _store->get_iter(std::to_string(i));
245 if (iter_selected == iter && i > 0) {
246 std::swap(_vector[i],_vector[i + delta]);
247 i += delta;
248 break;
249 }
250 i++;
251 }
252 }
253
254 // TRANSLATORS: %1 is the translated version of "up" or "down".
255 param_effect->makeUndoDone(Glib::ustring::compose(_("Move item %1"), word));
256 _store->foreach_iter(sigc::bind(sigc::mem_fun(*this, &SatelliteArrayParam::_selectIndex), &i));
257}
258
260{
261 // TRANSLATORS: This belongs into the sentence 'Move item up'
262 move_up_down(-1, _("up"));
263}
264
266{
267 // TRANSLATORS: This belongs into the sentence 'Move item down'
268 move_up_down(+1, _("down"));
269}
270
272{
273 auto const iter = _tree->get_selection()->get_selected();
274 if (iter) {
275 Gtk::TreeModel::Row row = *iter;
276 unlink(param_effect->getSPDoc()->getObjectById((const Glib::ustring&)(row[_model->_colObject])));
277 param_effect->makeUndoDone(_("Remove item"));
278 }
279}
280
282{
284
285 std::vector<Glib::ustring> itemsid;
286 // Here we ignore auto clipboard group wrapper
287 std::vector<Glib::ustring> itemsids = cm->getElementsOfType(SP_ACTIVE_DESKTOP, "*", 2);
288 std::vector<Glib::ustring> containers = cm->getElementsOfType(SP_ACTIVE_DESKTOP, "*", 1);
289
290 for (auto &&item : std::move(itemsids)) {
291 bool cont = false;
292 for (auto const &citems : containers) {
293 if (citems == item) {
294 cont = true;
295 }
296 }
297 if (!cont) {
298 itemsid.push_back(std::move(item));
299 }
300 }
301
302 if (itemsid.empty()) {
303 return;
304 }
305
306 auto hreflist = param_effect->getLPEObj()->hrefList;
307 if (hreflist.size()) {
308 auto sp_lpe_item = cast<SPLPEItem>(*hreflist.begin());
309 if (sp_lpe_item) {
310 for (auto &&itemid : std::move(itemsid)) {
311 SPObject *added = param_effect->getSPDoc()->getObjectById(itemid);
312 if (added && sp_lpe_item != added) {
313 itemid.insert(itemid.begin(), '#');
314 auto satellitereference =
315 std::make_shared<SatelliteReference>(param_effect->getLPEObj(), _visible);
316 try {
317 satellitereference->attach(Inkscape::URI(itemid.c_str()));
318 satellitereference->setActive(true);
319 _vector.push_back(std::move(satellitereference));
320 } catch (Inkscape::BadURIException &e) {
321 g_warning("%s", e.what());
322 satellitereference->detach();
323 }
324 }
325 }
326 }
327 }
328 param_effect->makeUndoDone(_("Link itemarray parameter to item"));
329}
330
332{
333 if (!_visible) {
334 return nullptr;
335 }
336
337 auto const vbox = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL);
338 auto const hbox = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL);
339
340 _tree.reset();
341 _scroller.reset();
342 _model.reset();
343
344 initui();
345
347
348 { // Paste item to link button
349 auto const pIcon = Gtk::manage(sp_get_icon_image("edit-clone", Gtk::IconSize::NORMAL));
350 auto const pButton = Gtk::make_managed<Gtk::Button>();
351 pButton->set_has_frame(false);
352 pButton->set_child(*pIcon);
353 pButton->signal_clicked().connect(sigc::mem_fun(*this, &SatelliteArrayParam::on_link_button_click));
354 UI::pack_start(*hbox, *pButton, UI::PackOptions::shrink);
355 pButton->set_tooltip_text(_("Link to item"));
356 }
357
358 { // Remove linked item
359 auto const pIcon = Gtk::manage(sp_get_icon_image("list-remove", Gtk::IconSize::NORMAL));
360 auto const pButton = Gtk::make_managed<Gtk::Button>();
361 pButton->set_has_frame(false);
362 pButton->set_child(*pIcon);
363 pButton->signal_clicked().connect(sigc::mem_fun(*this, &SatelliteArrayParam::on_remove_button_click));
364 UI::pack_start(*hbox, *pButton, UI::PackOptions::shrink);
365 pButton->set_tooltip_text(_("Remove Item"));
366 }
367
368 { // Move Down
369 auto const pIcon = Gtk::manage(sp_get_icon_image("go-down", Gtk::IconSize::NORMAL));
370 auto const pButton = Gtk::make_managed<Gtk::Button>();
371 pButton->set_has_frame(false);
372 pButton->set_child(*pIcon);
373 pButton->signal_clicked().connect(sigc::mem_fun(*this, &SatelliteArrayParam::on_down_button_click));
374 UI::pack_end(*hbox, *pButton, UI::PackOptions::shrink);
375 pButton->set_tooltip_text(_("Move Down"));
376 }
377
378 { // Move Down
379 auto const pIcon = Gtk::manage(sp_get_icon_image("go-up", Gtk::IconSize::NORMAL));
380 auto const pButton = Gtk::make_managed<Gtk::Button>();
381 pButton->set_has_frame(false);
382 pButton->set_child(*pIcon);
383 pButton->signal_clicked().connect(sigc::mem_fun(*this, &SatelliteArrayParam::on_up_button_click));
384 UI::pack_end(*hbox, *pButton, UI::PackOptions::shrink);
385 pButton->set_tooltip_text(_("Move Up"));
386 }
387
389
390 return vbox;
391}
392
394{
395 std::vector<SPObject *> objs;
396 for (auto &iter : _vector) {
397 if (iter && iter->isAttached()) {
398 SPObject *obj = iter->getObject();
399 if (obj) {
400 objs.push_back(obj);
401 }
402 }
403 }
404 return objs;
405}
406
407/*
408 * This function link a satellite writing into XML directly
409 * @param obj: object to link
410 * @param obj: position in vector
411 */
413{
414 if (obj && obj->getId()) {
415 Glib::ustring itemid = "#";
416 itemid += obj->getId();
417 auto satellitereference =
418 std::make_shared<SatelliteReference>(param_effect->getLPEObj(), _visible);
419 try {
420 satellitereference->attach(Inkscape::URI(itemid.c_str()));
421 if (_visible) {
422 satellitereference->setActive(true);
423 }
424 if (_vector.size() == pos || pos == Glib::ustring::npos) {
425 _vector.push_back(std::move(satellitereference));
426 } else {
427 _vector[pos] = std::move(satellitereference);
428 }
429 } catch (Inkscape::BadURIException &e) {
430 g_warning("%s", e.what());
431 satellitereference->detach();
432 }
433 }
434}
435
437{
438 if (!obj) {
439 return;
440 }
441
442 auto const it = std::find_if(_vector.begin(), _vector.end(),
443 [=](auto const &w){ return w && w->getObject() == obj; });
444 if (it != _vector.end()) it->reset();
445}
446
447void SatelliteArrayParam::unlink(std::shared_ptr<SatelliteReference> const &to)
448{
449 unlink(to->getObject());
450}
451
453{
454 _vector.clear();
455}
456
457} // namespace Inkscape::LivePathEffect
458
459/*
460 Local Variables:
461 mode:c++
462 c-file-style:"stroustrup"
463 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
464 indent-tabs-mode:nil
465 fill-column:99
466 End:
467*/
468// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4 :
Geom::IntRect visible
Definition canvas.cpp:154
std::vector< std::shared_ptr< SatelliteReference > > _vector
Definition array.h:104
bool param_readSVGValue(char const *const strvalue) override
Definition array.h:56
virtual void processObjects(LPEAction lpe_action)
Definition effect.cpp:1416
std::vector< SPLPEItem * > getCurrrentLPEItems() const
Definition effect.cpp:1187
void makeUndoDone(Glib::ustring message)
Definition effect.cpp:1521
LivePathEffectObject * getLPEObj()
Definition effect.h:151
virtual void param_widget_is_visible(bool is_visible)
Definition parameter.h:69
Inkscape::Display::TemporaryItem * ownerlocator
Definition parameter.h:111
void param_write_to_repr(const char *svgd)
Definition parameter.cpp:52
Glib::RefPtr< Gtk::TreeStore > _store
SatelliteArrayParam(const Glib::ustring &label, const Glib::ustring &tip, const Glib::ustring &key, Inkscape::UI::Widget::Registry *wr, Effect *effect, bool visible)
void on_active_toggled(const Glib::ustring &item)
bool param_readSVGValue(char const *strvalue) override
std::unique_ptr< Gtk::TreeView > _tree
bool _selectIndex(const Gtk::TreeModel::iterator &iter, int *i)
void link(SPObject *to, size_t pos=Glib::ustring::npos)
std::unique_ptr< Gtk::ScrolledWindow > _scroller
std::unique_ptr< ModelColumns > _model
void unlink(std::shared_ptr< SatelliteReference > const &to)
void linked_modified(SPObject *linked_obj, guint flags)
void move_up_down(int delta, Glib::ustring const &word)
std::vector< SPObject * > param_get_satellites() override
std::vector< sigc::scoped_connection > linked_connections
System-wide clipboard manager.
Definition clipboard.h:44
virtual std::vector< Glib::ustring > getElementsOfType(SPDesktop *desktop, gchar const *type="*", gint maxdepth=-1)=0
static ClipboardManager * get()
Represents an URI as per RFC 2396.
Definition uri.h:36
To do: update description of desktop.
Definition desktop.h:149
bool isSeeking() const
Definition document.h:359
SPObject * getObjectById(std::string const &id) const
sigc::connection connectTransformed(sigc::slot< void(Geom::Affine const *, SPItem *)> slot)
Definition sp-item.h:234
SPObject is an abstract base class of all of the document nodes at the SVG document level.
Definition sp-object.h:160
SPObject * _tmpsuccessor
Definition sp-object.h:731
char const * getId() const
Returns the objects current ID string.
sigc::connection connectRelease(sigc::slot< void(SPObject *)> slot)
Connects to the release request signal.
Definition sp-object.h:237
std::list< SPObject * > hrefList
Definition sp-object.h:197
sigc::connection connectModified(sigc::slot< void(SPObject *, unsigned int)> slot)
Connects to the modification notification signal.
Definition sp-object.h:705
System-wide clipboard management - class declaration.
const double w
Definition conic-4.cpp:19
Gtk::Image * sp_get_icon_image(Glib::ustring const &icon_name, int size)
Icon Loader.
Macro for icon names used in Inkscape.
SPItem * item
Glib::ustring label
Live Path Effects code.
void pack_end(Gtk::Box &box, Gtk::Widget &child, bool const expand, bool const fill, unsigned const padding)
Adds child to box, packed with reference to the end of box.
Definition pack.cpp:153
void pack_start(Gtk::Box &box, Gtk::Widget &child, bool const expand, bool const fill, unsigned const padding)
Adds child to box, packed with reference to the start of box.
Definition pack.cpp:141
STL namespace.
static cairo_user_data_key_t key
Helpers for using Gtk::Boxes, encapsulating large changes between GTK3 & GTK4.
Ocnode ** ref
Definition quantize.cpp:32
Base class for live path effect items.
int delta
SPDesktop * desktop