20#include <glibmm/i18n.h>
21#include <glibmm/quark.h>
22#include <glibmm/value.h>
23#include <giomm/simpleactiongroup.h>
25#include <gtkmm/builder.h>
26#include <gtkmm/button.h>
27#include <gtkmm/combobox.h>
28#include <gtkmm/dragsource.h>
29#include <gtkmm/droptarget.h>
30#include <gtkmm/expander.h>
31#include <gtkmm/gestureclick.h>
32#include <gtkmm/image.h>
33#include <gtkmm/label.h>
34#include <gtkmm/listbox.h>
35#include <gtkmm/liststore.h>
36#include <gtkmm/menubutton.h>
37#include <gtkmm/searchentry2.h>
38#include <gtkmm/spinbutton.h>
39#include <gtkmm/widgetpaintable.h>
40#include <sigc++/adaptors/bind.h>
41#include <sigc++/adaptors/hide.h>
42#include <sigc++/functors/mem_fun.h>
77static constexpr auto favs_path =
"/dialogs/livepatheffect/favs";
83 return favlist.find(effect) != favlist.npos;
92 favlist.append(effect).append(
";");
103 auto const pos = favlist.find(effect);
104 if (pos == favlist.npos)
return;
106 favlist.erase(pos, effect.length());
113 bool experimental = prefs->
getBool(
"/dialogs/livepatheffect/showexperimental",
false);
114 if (experimental != _experimental) {
115 _experimental = experimental;
150 :
DialogBase(
"/dialogs/livepatheffect",
"LivePathEffect"),
152 LPEListBox(
get_widget<
Gtk::ListBox>(_builder,
"LPEListBox")),
153 _LPEContainer(
get_widget<
Gtk::Box>(_builder,
"LPEContainer")),
154 _LPEAddContainer(
get_widget<
Gtk::Box>(_builder,
"LPEAddContainer")),
155 _LPEParentBox(
get_widget<
Gtk::ListBox>(_builder,
"LPEParentBox")),
156 _LPECurrentItem(
get_widget<
Gtk::Box>(_builder,
"LPECurrentItem")),
157 _LPESelectionInfo(
get_widget<
Gtk::Label>(_builder,
"LPESelectionInfo")),
158 converter(
Inkscape::LivePathEffect::LPETypeConverter)
161 auto const click = Gtk::GestureClick::create();
162 click->signal_pressed().connect([
this](
auto &&...) {
dnd =
false; });
188 bool const has_clip,
bool const has_mask)
209void align(Gtk::Widget *top,
int const spinbutton_width_chars)
211 auto box =
dynamic_cast<Gtk::Box*
>(top);
216 auto for_child_n = [=](
int child_index,
const std::function<void (Gtk::Widget*)>& action) {
218 auto const container =
dynamic_cast<Gtk::Box *
>(
child);
219 if (!container)
continue;
221 container->set_spacing(2);
223 if (child_index < children.size()) {
224 action(children[child_index]);
231 for_child_n(0, [&](Gtk::Widget*
child){
232 if (
auto label =
dynamic_cast<Gtk::Label*
>(
child)) {
233 label->set_xalign(0);
234 int label_width = 0, dummy = 0;
235 label->measure(Gtk::Orientation::HORIZONTAL, -1, dummy, label_width, dummy, dummy);
236 if (label_width > max_width) {
237 max_width = label_width;
242 for_child_n(0, [=](Gtk::Widget*
child) {
243 if (
auto label =
dynamic_cast<Gtk::Label*
>(
child)) {
244 label->set_size_request(max_width);
249 int button_width = 0;
250 for_child_n(1, [&](Gtk::Widget*
child) {
251 if (
auto spin =
dynamic_cast<Gtk::SpinButton*
>(
child)) {
253 spin->set_width_chars(spinbutton_width_chars);
255 spin->measure(Gtk::Orientation::HORIZONTAL, -1, dummy, button_width, dummy, dummy);
259 int combo_size = button_width > 0 ? button_width : 50;
260 for_child_n(1, [=](Gtk::Widget*
child) {
261 if (
auto combo =
dynamic_cast<Gtk::ComboBox*
>(
child)) {
262 combo->set_size_request(combo_size);
277 auto &
image =
dynamic_cast<Gtk::Image &
>(*button.get_child());
278 auto const icon_name =
visible ?
"object-visible-symbolic" :
"object-hidden-symbolic";
279 image.set_from_icon_name(icon_name);
301 !
visible ? _(
"Deactivate path effect") : _(
"Activate path effect"),
302 INKSCAPE_ICON(
"dialog-path-effects"));
306 static const std::map<Inkscape::LivePathEffect::LPECategory, Glib::ustring> category_names = {
314 return category_names.at(category);
317struct LivePathEffectEditor::LPEMetadata final {
320 Glib::ustring
label, icon_name, tooltip;
326 std::vector<LPEMetadata> &&lpes)
339 auto const tie = [](LPEMetadata
const &lpe){
return std::tie(lpe.category, lpe.label); };
340 std::sort(lpes.begin(), lpes.end(), [=](
auto &l,
auto &r){ return tie(l) < tie(r); });
341 for (
auto const &lpe : lpes) {
343 auto const type = lpe.type;
344 int const id =
static_cast<int>(type);
345 auto const menuitem =
builder.add_item(lpe.label, lpe.category, lpe.tooltip, lpe.icon_name,
346 lpe.sensitive,
true, [=,
this]{
onAdd(type); });
347 menuitem->signal_query_tooltip().connect([lpe,
id,
this](
int x,
int y,
bool kbd,
const Glib::RefPtr<Gtk::Tooltip>& tooltipw){
356 std::sort(lpes.begin(), lpes.end(), [=](
auto &l,
auto &r){ return l.label < r.label; });
357 for (
auto const &lpe: lpes) {
359 int const id =
static_cast<int>(lpe.type);
360 Glib::ustring untranslated_label = converter.get_label(lpe.type);
361 Glib::ustring untranslated_description = converter.get_description(lpe.type);
362 Glib::ustring search = Glib::ustring::compose(
"%1_%2", untranslated_label, untranslated_description);
363 if (lpe.label != untranslated_label) {
364 search = Glib::ustring::compose(
"%1_%2_%3", search, lpe.label, _(converter.get_description(lpe.type).c_str()));
366 popup.add_to_completion_list(
id, lpe.label , lpe.icon_name + (symbolic ?
"-symbolic" :
""), search);
371 menu.add_css_class(
"symbolic");
376 Glib::ustring
const &untranslated_label)
378 Glib::ustring tooltip = _(converter.get_description(type).c_str());
379 if (tooltip != untranslated_label) {
381 tooltip = Glib::ustring::compose(
"[%1] %2", untranslated_label, tooltip);
387LivePathEffectEditor::setMenu()
393 _reload_menu =
false;
395 auto shape = cast<SPShape>(current_lpeitem);
396 auto path = cast<SPPath>(current_lpeitem);
397 auto group = cast<SPGroup>(current_lpeitem);
398 bool has_clip = current_lpeitem && (current_lpeitem->getClipObject() !=
nullptr);
399 bool has_mask = current_lpeitem && (current_lpeitem->getMaskObject() !=
nullptr);
401 Glib::ustring item_type;
408 }
else if (_current_use) {
412 if (!(
sp_set_experimental(_experimental) || _item_type != item_type || has_clip != _has_clip || has_mask != _has_mask)) {
415 _item_type = item_type;
416 _has_clip = has_clip;
417 _has_mask = has_mask;
421 auto lpes = std::vector<LPEMetadata>{};
422 lpes.reserve(converter._length);
423 for (
int i = 0; i < static_cast<int>(converter._length); ++i) {
424 auto const *
const data = &converter.data(i);
425 auto const &type =
data->id;
426 auto const &untranslated_label = converter.get_label(type);
428 auto category = converter.get_category(type);
437 Glib::ustring
label = g_dpgettext2(0,
"path effect", untranslated_label.c_str());
438 auto const &icon = converter.get_icon(type);
439 auto tooltip = get_tooltip(type, untranslated_label);
440 auto const sensitive = can_apply(type, item_type, has_clip, has_mask);
441 lpes.push_back({type, category, std::move(
label), icon, std::move(tooltip), sensitive});
444 add_lpes(_lpes_popup, symbolic, std::move(lpes));
449 selection_changed_lock =
true;
450 Glib::ustring
key = converter.get_key(etype);
453 current_lpeitem = fromclone;
454 _current_use =
nullptr;
455 if (
key ==
"clone_original") {
457 selection_changed_lock =
false;
458 DocumentUndo::done(getDocument(), _(
"Create and apply path effect"), INKSCAPE_ICON(
"dialog-path-effects"));
462 selection_changed_lock =
false;
463 if (current_lpeitem) {
465 current_lpeitem->getCurrentLPE()->refresh_widgets =
true;
466 DocumentUndo::done(getDocument(), _(
"Create and apply path effect"), INKSCAPE_ICON(
"dialog-path-effects"));
471LivePathEffectEditor::selection_info()
473 auto selection = getSelection();
474 SPItem * selected =
nullptr;
475 _LPESelectionInfo.set_visible(
false);
476 if (selection && (selected = selection->singleItem()) ) {
478 if (is<SPText>(selected) || is<SPFlowtext>(selected)) {
479 _LPESelectionInfo.set_text(_(
"Text objects do not support Live Path Effects"));
480 _LPESelectionInfo.set_visible(
true);
482 Glib::ustring labeltext = _(
"Convert text to paths");
483 auto const selectbutton = Gtk::make_managed<Gtk::Button>();
484 auto const boxc = Gtk::make_managed<Gtk::Box>();
485 auto const lbl = Gtk::make_managed<Gtk::Label>(labeltext);
489 type->set_margin_start(4);
490 type->set_margin_end(4);
491 selectbutton->set_child(*boxc);
492 selectbutton->signal_clicked().connect([=](){
493 selection->toCurves();
495 _LPEParentBox.append(*selectbutton);
497 Glib::ustring labeltext2 = _(
"Clone");
498 auto const selectbutton2 = Gtk::make_managed<Gtk::Button>();
499 auto const boxc2 = Gtk::make_managed<Gtk::Box>();
500 auto const lbl2 = Gtk::make_managed<Gtk::Label>(labeltext2);
504 type2->set_margin_start(4);
505 type2->set_margin_end(4);
506 selectbutton2->set_child(*boxc2);
507 selectbutton2->signal_clicked().connect([=](){
510 _LPEParentBox.append(*selectbutton2);
511 }
else if (!is<SPLPEItem>(selected) && !is<SPUse>(selected)) {
512 _LPESelectionInfo.set_text(_(
"Select a path, shape, clone or group"));
513 _LPESelectionInfo.set_visible(
true);
515 if (selected->
getId()) {
516 Glib::ustring labeltext = selected->
label() ? selected->
label() : selected->
getId();
517 auto const boxc = Gtk::make_managed<Gtk::Box>();
518 auto const lbl = Gtk::make_managed<Gtk::Label>(labeltext);
519 lbl->set_ellipsize(Pango::EllipsizeMode::END);
523 _LPECurrentItem.append(*boxc);
525 _LPESelectionInfo.set_visible(
false);
527 std::vector<std::pair <Glib::ustring, Glib::ustring> > newrootsatellites;
532 lpe = lpeobj->get_lpe();
535 const Glib::ustring
label = _(converter.get_label(lpe->
effectType()).c_str());
536 Glib::ustring labeltext = Glib::ustring::compose(_(
"Select %1 with %2 LPE"),
root.first,
label);
538 if (lpeitem && lpeitem->getLPEIndex(lpe) != Glib::ustring::npos) {
539 newrootsatellites.emplace_back(
root.first,
root.second);
540 auto const selectbutton = Gtk::make_managed<Gtk::Button>();
541 auto const boxc = Gtk::make_managed<Gtk::Box>();
542 auto const lbl = Gtk::make_managed<Gtk::Label>(labeltext);
546 type->set_margin_start(4);
547 type->set_margin_end(4);
548 selectbutton->set_child(*boxc);
549 selectbutton->signal_clicked().connect([=](){
550 selection->set(lpeitem);
552 _LPEParentBox.append(*selectbutton);
557 _LPEParentBox.set_visible(
true);
558 _LPECurrentItem.set_visible(
true);
560 }
else if (!selection || selection->isEmpty()) {
561 _LPESelectionInfo.set_text(_(
"Select a path, shape, clone or group"));
562 _LPESelectionInfo.set_visible(
true);
563 }
else if (selection->size() > 1) {
564 _LPESelectionInfo.set_text(_(
"Select only one path, shape, clone or group"));
565 _LPESelectionInfo.set_visible(
true);
573 if ( sel && !sel->
isEmpty() ) {
576 auto lpeitem = cast<SPLPEItem>(
item);
577 _current_use = cast<SPUse>(
item);
579 lpeitem->update_satellites();
580 current_lpeitem = lpeitem;
581 _LPEAddContainer.set_sensitive(
true);
582 effect_list_reload(lpeitem);
584 }
else if (_current_use) {
586 _LPEAddContainer.set_sensitive(
true);
592 _current_use =
nullptr;
593 current_lpeitem =
nullptr;
594 _LPEAddContainer.set_sensitive(
false);
600LivePathEffectEditor::move_list(
int const origin,
int const dest)
604 if ( sel && !sel->
isEmpty() ) {
607 auto lpeitem = cast<SPLPEItem>(
item);
609 lpeitem->movePathEffect(
origin, dest);
616LivePathEffectEditor::showParams(
LPEExpander const &expanderdata,
bool const changed)
623 if (effectwidget && !lpe->
refresh_widgets && expanderdata == current_lperef && !changed) {
628 current_lperef.first->unset_child();
629 effectwidget =
nullptr;
635 auto const label = Gtk::make_managed<Gtk::Label>(
"", Gtk::Align::START, Gtk::Align::CENTER);
636 label->set_markup(_(
"<small>Without parameters</small>"));
637 label->set_margin_top(5);
638 label->set_margin_bottom(5);
639 label->set_margin_start(5);
640 effectwidget =
label;
643 expanderdata.first->set_child(*effectwidget);
649 current_lperef = std::make_pair(
nullptr,
nullptr);
652 current_lperef = std::make_pair(
nullptr,
nullptr);
657LivePathEffectEditor::on_drop(Gtk::Widget &widget,
658 Glib::ValueBase
const &value,
int pos_target)
662 int const pos_source =
static_cast<Glib::Value<int>
const &
>(value).get();
664 if (pos_target == pos_source) {
668 if (pos_source > pos_target) {
669 if (widget.has_css_class(
"after")) {
672 }
else if (pos_source < pos_target) {
673 if (widget.has_css_class(
"before")) {
678 Gtk::Widget *source = LPEListBox.get_row_at_index(pos_source);
680 if (source == &widget) {
684 g_object_ref(source->gobj());
685 LPEListBox.remove(*source);
686 LPEListBox.insert(*source, pos_target);
687 g_object_unref(source->gobj());
689 move_list(pos_source,pos_target);
697 widget.remove_css_class(
"after" );
698 widget.add_css_class (
"before");
700 widget.remove_css_class(
"before");
701 widget.add_css_class (
"after" );
709LivePathEffectEditor::effect_list_reload(
SPLPEItem *lpeitem)
712 _LPEExpanders.clear();
715 Gtk::Expander *LPEExpanderCurrent =
nullptr;
717 int const total =
static_cast<int>(effectlist.size());
720 auto const target = Gtk::DropTarget::create(Glib::Value<int>::value_type(), Gdk::DragAction::MOVE);
721 _LPEContainer.add_controller(target);
723 target->signal_drop().connect([
this](Glib::ValueBase
const &value,
double ,
double const y)
725 if (!dnd)
return false;
728 bool const accepted = on_drop(_LPEContainer, value, pos_target);
733 target->signal_motion().connect([
this](
double ,
double const y)
736 return Gdk::DragAction::MOVE;
740 Gtk::Button *LPEDrag =
nullptr;
742 for (
auto const &lperef: effectlist) {
743 if (!lperef->lpeobject)
continue;
745 auto const lpe = lperef->lpeobject->get_lpe();
752 auto LPENameLabel = &get_widget<Gtk::Label> (
builder,
"LPENameLabel");
753 auto LPEHide = &get_widget<Gtk::Button> (
builder,
"LPEHide");
754 auto LPEIconImage = &get_widget<Gtk::Image> (
builder,
"LPEIconImage");
755 auto LPEExpanderBox = &get_widget<Gtk::Box> (
builder,
"LPEExpanderBox");
756 auto LPEEffect = &get_widget<Gtk::Box> (
builder,
"LPEEffect");
758 auto LPEOpenExpander = &get_widget<Gtk::Box> (
builder,
"LPEOpenExpander");
759 auto LPEErase = &get_widget<Gtk::Button> (
builder,
"LPEErase");
760 LPEDrag = &get_widget<Gtk::Button> (
builder,
"LPEDrag");
762 LPEDrag->set_tooltip_text(_(
"Drag to change position in path effects stack"));
767 auto const effectype = lpe->effectType();
768 int const id =
static_cast<int>(effectype);
769 auto const &untranslated_label = converter.get_label(effectype);
770 auto const &icon = converter.get_icon(effectype);
771 auto const tooltip = get_tooltip(effectype, untranslated_label);
773 LPEIconImage->set_from_icon_name(icon);
775 bool const visible = g_strcmp0(lpe->getRepr()->attribute(
"is_visible"),
"true") == 0;
779 LPEListBox.append(*LPEEffect);
781 LPEDrag->set_name(Glib::ustring::compose(
"drag_%1",
counter));
783 LPEExpanderBox->signal_query_tooltip().connect([=,
this](
int x,
int y,
bool kbd,
const Glib::RefPtr<Gtk::Tooltip>& tooltipw){
788 add_item_actions(lperef, untranslated_label, get_widget<Gtk::MenuButton>(
builder,
"LPEEffectMenuButton"),
792 auto const source = Gtk::DragSource::create();
793 source->set_actions(Gdk::DragAction::MOVE);
794 LPEDrag->add_controller(source);
797 LPEEffect->add_css_class(
"drag-icon");
798 source->set_icon(Gtk::WidgetPaintable::create(*LPEEffect), 0, 0);
799 LPEEffect->remove_css_class(
"drag-icon");
801 source->signal_drag_begin().connect([
this](Glib::RefPtr<Gdk::Drag>
const &){
805 auto row =
dynamic_cast<Gtk::ListBoxRow *
>(LPEEffect->get_parent());
808 source->signal_prepare().connect([=](
double,
double)
810 Glib::Value<int> value;
811 value.init(G_TYPE_INT);
812 value.set(row->get_index());
813 return Gdk::ContentProvider::create(value);
816 source->signal_drag_end().connect([
this](Glib::RefPtr<Gdk::Drag>
const &,
bool)
821 auto const target = Gtk::DropTarget::create(Glib::Value<int>::value_type(), Gdk::DragAction::MOVE);
822 row->add_controller(target);
824 target->signal_drop().connect([=,
this](Glib::ValueBase
const &value,
double,
double)
826 if (!dnd)
return false;
828 bool const accepted = on_drop(*row, value, row->get_index());
833 target->signal_motion().connect([=](
double ,
double const y)
835 int const half = row->get_allocated_height() / 2;
837 return Gdk::DragAction::MOVE;
841 LPEEffect->set_name(
"LPEEffectItem");
842 LPENameLabel->set_label(g_dpgettext2(
nullptr,
"path effect",
843 lperef->lpeobject->get_lpe()->getName().c_str()));
845 LPEExpander->property_expanded().signal_changed().connect(sigc::bind(
846 sigc::mem_fun(*
this, &LivePathEffectEditor::expanded_notify),
LPEExpander));
848 auto const expander_click = Gtk::GestureClick::create();
849 expander_click->set_button(1);
850 expander_click->signal_pressed().connect([
this,
LPEExpander, &expander_click = *expander_click](
auto &&...) {
852 expander_click.set_state(Gtk::EventSequenceState::CLAIMED);
854 LPEOpenExpander->add_controller(expander_click);
856 LPEHide->signal_clicked().connect(sigc::bind(sigc::mem_fun(*
this, &LivePathEffectEditor::toggleVisible), lpe, LPEHide));
857 LPEErase->signal_clicked().connect([=,
this](){ removeEffect(
LPEExpander);});
859 auto const drag_click = Gtk::GestureClick::create();
860 drag_click->signal_pressed().connect([
this](
int,
double x,
double y) {
864 LPEDrag->add_controller(drag_click);
867 LPEDrag->set_cursor(
"grab");
872 LPEDrag->set_visible(
false);
873 LPEDrag->set_tooltip_text(
"");
876 if (LPEExpanderCurrent) {
877 _LPESelectionInfo.set_visible(
false);
878 LPEExpanderCurrent->set_expanded(
true);
879 if (
auto const current_window =
dynamic_cast<Gtk::Window *
>(LPEExpanderCurrent->get_root())) {
880 current_window->set_focus(*LPEExpanderCurrent);
887void LivePathEffectEditor::expanded_notify(Gtk::Expander *expander) {
893 _freezeexpander =
false;
896 if (_freezeexpander) {
897 _freezeexpander =
false;
902 _freezeexpander =
true;
903 expander->set_expanded(!expander->get_expanded());
909 if (expander->get_expanded()) {
910 for (
auto const &
w : _LPEExpanders) {
911 if (
w.first == expander) {
912 w.first->set_expanded(
true);
913 w.first->get_parent()->get_parent()->get_parent()->set_name(
"currentlpe");
915 current_lpeitem->setCurrentPathEffect(
w.second);
918 w.first->set_expanded(
false);
919 w.first->get_parent()->get_parent()->get_parent()->set_name(
"unactive_lpe");
924 auto selection = SP_ACTIVE_DESKTOP->getSelection();
925 if (selection && current_lpeitem && !selection->isEmpty()) {
926 selection_changed_lock =
true;
928 selection->add(current_lpeitem);
930 selection_changed_lock =
false;
939 current_lpeitem->setCurrentPathEffect(lperef);
940 current_lpeitem = current_lpeitem->flattenCurrentPathEffect();
941 _current_use =
nullptr;
942 auto selection = getSelection();
943 if (selection && selection->isEmpty() ) {
944 selection->add(current_lpeitem);
946 DocumentUndo::done(getDocument(), _(
"Flatten path effect(s)"), INKSCAPE_ICON(
"dialog-path-effects"));
951LivePathEffectEditor::removeEffect(Gtk::Expander * expander) {
952 bool reload = current_lperef.first != expander;
953 auto current_lperef_tmp = current_lperef;
954 for (
auto const &
w : _LPEExpanders) {
955 if (
w.first == expander) {
956 current_lpeitem->setCurrentPathEffect(
w.second);
957 current_lpeitem = current_lpeitem->removeCurrentPathEffect(
false);
958 _current_use =
nullptr;
962 if (current_lpeitem && current_lpeitem->getParentGroup() !=
nullptr) {
964 current_lpeitem->setCurrentPathEffect(current_lperef_tmp.second);
966 effect_list_reload(current_lpeitem);
968 DocumentUndo::done(getDocument(), _(
"Remove path effect"), INKSCAPE_ICON(
"dialog-path-effects"));
975LivePathEffectEditor::clear_lpe_list()
981 _LPEExpanders.clear();
982 current_lperef = std::make_pair(
nullptr,
nullptr);
987 auto selection = getSelection();
988 if (!(selection && !selection->isEmpty())) {
992 auto use = cast<SPUse>(selection->singleItem());
1003 if (!(is<SPShape>(
orig) || is<SPGroup>(
orig) || is<SPText>(
orig))) {
1008 selection->set(
orig);
1012 auto transform_use = use->get_root_transform();
1013 use->deleteObject(
false);
1017 selection->cloneOriginalPathLPE(
true,
true,
true);
1019 SPItem *new_item = selection->singleItem();
1021 if (new_item && (new_item !=
orig)) {
1032 auto *lpeitem = cast<SPLPEItem>(new_item);
1048template <
typename Method,
typename ...Args>
1049static void add_action(Glib::RefPtr<Gio::SimpleActionGroup>
const &group,
1050 Glib::ustring
const &
name,
bool const enable,
1053 auto slot = sigc::hide_return(sigc::bind(sigc::mem_fun(self, method), std::move(args)...));
1054 auto const action = group->add_action(
name, std::move(slot));
1055 action->set_enabled(enable);
1059 Glib::ustring
const &untranslated_label,
1061 bool const is_first,
bool const is_last)
1064 auto const has_defs = lperef->lpeobject->get_lpe()->hasDefaultParameters();
1065 auto const has_fav =
sp_has_fav(untranslated_label);
1066 auto group = Gio::SimpleActionGroup::create();
1067 add_action(group,
"duplicate" ,
true , *
this , &Self::do_item_action_undoable, lperef,
1069 add_action(group,
"move-up" , !is_first, *
this , &Self::do_item_action_undoable, lperef,
1071 add_action(group,
"move-down" , !is_last , *
this , &Self::do_item_action_undoable, lperef,
1073 add_action(group,
"flatten" ,
true , *
this , &Self::lpeFlatten , lperef);
1074 add_action(group,
"set-def" , !has_defs, *
this , &Self::do_item_action_defaults, lperef,
1076 add_action(group,
"forget-def", has_defs, *
this , &Self::do_item_action_defaults, lperef,
1078 add_action(group,
"set-fav" , !has_fav , *
this , &Self::do_item_action_favorite, lperef,
1079 untranslated_label , std::ref(
item) ,
true );
1080 add_action(group,
"unset-fav" , has_fav , *
this , &Self::do_item_action_favorite, lperef,
1081 untranslated_label , std::ref(
item) ,
false );
1086void LivePathEffectEditor::enable_item_action(Gtk::Widget &
item,
1087 Glib::ustring
const &
action_name,
bool const enabled)
1091 auto &simple_group = *
static_cast<Gio::SimpleActionGroup *
>(
data);
1092 auto const action = simple_group.lookup_action(
action_name);
1093 auto const simple_action = std::dynamic_pointer_cast<Gio::SimpleAction>(action);
1094 g_assert(simple_action);
1095 simple_action->set_enabled(enabled);
1098void LivePathEffectEditor::enable_fav_actions(Gtk::Widget &
item,
bool const has_fav)
1100 enable_item_action(
item,
"set-fav" , !has_fav);
1101 enable_item_action(
item,
"unset-fav", has_fav);
1106 Glib::ustring const &description)
1117 (lperef->lpeobject->get_lpe()->*method)();
1122 Glib::ustring
const &untranslated_label,
1123 Gtk::Widget &
item,
bool const has_fav)
uint32_t toRGBA(double opacity=1.0) const
Return an sRGB conversion of the color in RGBA int32 format.
RAII-style mechanism for creating a temporary undo-insensitive context.
static void done(SPDocument *document, Glib::ustring const &event_description, Glib::ustring const &undo_icon, unsigned int object_modified_tag=0)
virtual void doOnVisibilityToggled(SPLPEItem const *lpeitem)
gint spinbutton_width_chars
virtual Gtk::Widget * newWidget()
This creates a managed widget.
static void createAndApply(const char *name, SPDocument *doc, SPItem *item)
Inkscape::XML::Node * getRepr()
void setDefaultParameters()
Set this LPE defaults.
EffectType effectType() const
void resetDefaultParameters()
Reset this LPE defaults.
bool get_on_path(const E id) const
bool get_on_shape(const E id) const
bool get_on_group(const E id) const
bool isEmpty()
Returns true if no items are selected.
SPItem * singleItem()
Returns a single selected item.
Preference storage class.
bool getBool(Glib::ustring const &pref_path, bool def=false)
Retrieve a Boolean value.
Glib::ustring getString(Glib::ustring const &pref_path, Glib::ustring const &def="")
Retrieve an UTF-8 string.
static Preferences * get()
Access the singleton Preferences object.
void setString(Glib::ustring const &pref_path, Glib::ustring const &value)
Set an UTF-8 string value.
The set of selected SPObjects for a given document and layer model.
DialogBase is the base class for the dialog system.
SPDocument * getDocument() const
virtual void focus_dialog()
void do_item_action_favorite(PathEffectSharedPtr const &lpreref, Glib::ustring const &untranslated_label, Gtk::Widget &item, bool has_fav)
SPLPEItem * current_lpeitem
bool can_apply(LivePathEffect::EffectType, Glib::ustring const &item_type, bool has_clip, bool has_mask)
bool selection_changed_lock
void effect_list_reload(SPLPEItem *lpeitem)
PathEffectList effectlist
Gtk::Box & _LPEAddContainer
void onAdd(Inkscape::LivePathEffect::EffectType etype)
void do_item_action_defaults(PathEffectSharedPtr const &lpreref, void(LivePathEffect::Effect::*const method)())
LPEExpander current_lperef
void onSelectionChanged(Inkscape::Selection *selection)
void enable_fav_actions(Gtk::Widget &item, bool has_fav)
void selectionChanged(Inkscape::Selection *selection) final
Inkscape::UI::Widget::CompletionPopup _lpes_popup
~LivePathEffectEditor() final
void add_lpes(UI::Widget::CompletionPopup &, bool symbolic, std::vector< LPEMetadata > &&lpes)
void toggleVisible(Inkscape::LivePathEffect::Effect *lpe, Gtk::Button *visbutton)
void selectionModified(Inkscape::Selection *selection, unsigned flags) final
LivePathEffectEditor()
Constructor.
void focus_dialog() override
std::pair< Gtk::Expander *, PathEffectSharedPtr > LPEExpander
const LivePathEffect::EnumEffectDataConverter< LivePathEffect::EffectType > & converter
void showParams(LPEExpander const &expanderdata, bool changed)
void setAttribute(Util::const_char_ptr key, Util::const_char_ptr value)
Change an attribute of this node.
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
Inkscape::LivePathEffect::Effect * get_lpe()
SPObject * getObjectById(std::string const &id) const
Base class for visual SVG elements.
std::vector< std::pair< Glib::ustring, Glib::ustring > > rootsatellites
virtual Inkscape::Colors::Color highlight_color() const
virtual const char * typeName() const
The item's type name, not node tag name.
void doWriteTransform(Geom::Affine const &transform, Geom::Affine const *adv=nullptr, bool compensate=true)
Set a new transform on an object.
void duplicateCurrentPathEffect()
void downCurrentPathEffect()
Inkscape::LivePathEffect::Effect * getCurrentLPE()
void upCurrentPathEffect()
PathEffectList getEffectList()
bool setCurrentPathEffect(PathEffectSharedPtr const &lperef)
char const * label() const
Gets the author-visible label property for the object or a default if no label is defined.
void setAttribute(Inkscape::Util::const_char_ptr key, Inkscape::Util::const_char_ptr value)
char const * getId() const
Returns the objects current ID string.
void requestDisplayUpdate(unsigned int flags)
Queues an deferred update of this object's display.
Utilities to more easily use Gtk::EventController & subclasses like Gesture.
static char const *const current
Macro for icon names used in Inkscape.
std::unique_ptr< Magick::Image > image
A dialog for Live Path Effects (LPE)
Affine identity()
Create an identity matrix.
const Glib::ustring & get_category_name(EffectCategory category)
static bool sp_has_fav(Glib::ustring const &effect)
static constexpr auto item_action_group_name
static void sp_add_fav(Glib::ustring const &effect)
static constexpr auto favs_path
static void sp_remove_fav(Glib::ustring effect)
static void set_visible_icon(Gtk::Button &button, bool const visible)
void align(Gtk::Widget *top, int const spinbutton_width_chars)
static void add_action(Glib::RefPtr< Gio::SimpleActionGroup > const &group, Glib::ustring const &name, bool const enable, LivePathEffectEditor &self, Method const method, Args ...args)
static const auto item_action_group_quark
static void update_before_after_classes(Gtk::Widget &widget, bool const before)
bool sp_set_experimental(bool &_experimental)
void remove_all_children(Widget &widget)
For each child in get_children(widget), call widget.remove(*child). May not cause delete child!
std::vector< Gtk::Widget * > get_children(Gtk::Widget &widget)
Get a vector of the widgetʼs children, from get_first_child() through each get_next_sibling().
W & get_widget(const Glib::RefPtr< Gtk::Builder > &builder, const char *id)
Gtk::Image * get_shape_image(Glib::ustring const &shape_type, std::uint32_t const rgba_color, Gtk::IconSize const icon_size)
As get_shape_icon(), but returns a ready-made, managed Image having that icon name & CSS class.
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.
Glib::RefPtr< Gtk::Builder > create_builder(const char *filename)
auto to_opt(char const *s)
auto to_cstr(std::optional< std::string > const &s)
Helper class to stream background task notifications as a series of messages.
static void append(std::vector< T > &target, std::vector< T > &&source)
static cairo_user_data_key_t key
Helpers for using Gtk::Boxes, encapsulating large changes between GTK3 & GTK4.
Inkscape::IO::Resource - simple resource API.
TODO: insert short description here.
void sp_lpe_item_update_patheffect(SPLPEItem *lpeitem, bool wholetree, bool write, bool with_satellites)
Calls any registered handlers for the update_patheffect action.
Base class for live path effect items.
std::shared_ptr< Inkscape::LivePathEffect::LPEObjectReference > PathEffectSharedPtr
TODO: insert short description here.
Glib::RefPtr< Gtk::Builder > builder