26#include <glibmm/convert.h>
27#include <glibmm/i18n.h>
28#include <glibmm/main.h>
29#include <glibmm/refptr.h>
30#include <glibmm/stringutils.h>
31#include <glibmm/ustring.h>
32#include <gdkmm/display.h>
33#include <gdkmm/general.h>
34#include <gdkmm/rgba.h>
35#include <gdkmm/seat.h>
36#include <gtkmm/button.h>
37#include <gtkmm/checkbutton.h>
38#include <gtkmm/dragsource.h>
39#include <gtkmm/entry.h>
40#include <gtkmm/enums.h>
41#include <gtkmm/eventcontrollermotion.h>
42#include <gtkmm/frame.h>
43#include <gtkmm/gestureclick.h>
44#include <gtkmm/grid.h>
45#include <gtkmm/image.h>
46#include <gtkmm/label.h>
47#include <gtkmm/menubutton.h>
48#include <gtkmm/paned.h>
49#include <gtkmm/popover.h>
50#include <gtkmm/scrolledwindow.h>
51#include <gtkmm/searchentry2.h>
52#include <gtkmm/sizegroup.h>
53#include <gtkmm/snapshot.h>
54#include <gtkmm/textview.h>
55#include <gtkmm/treeviewcolumn.h>
56#include <gtkmm/treeview.h>
57#include <gtkmm/widget.h>
58#include <pangomm/layout.h>
59#include <sigc++/functors/mem_fun.h>
118 else if(is<SPFeBlend>(prim) || is<SPFeComposite>(prim) || is<SPFeDisplacementMap>(prim))
120 else if(is<SPFeMerge>(prim)) {
122 return (
int) (prim->
children.size() + 1);
128class CheckButtonAttr :
public Gtk::CheckButton,
public AttrWidget
131 CheckButtonAttr(
bool def,
const Glib::ustring&
label,
132 Glib::ustring tv, Glib::ustring fv,
133 const SPAttr a,
char* tip_text)
136 _true_val(
std::move(tv)), _false_val(
std::move(fv))
140 set_tooltip_text(tip_text);
144 Glib::ustring get_as_attribute()
const override
146 return get_active() ? _true_val : _false_val;
149 void set_from_attribute(
SPObject* o)
override
155 else if(_false_val == val)
162 const Glib::ustring _true_val, _false_val;
168 SpinButtonAttr(
double lower,
double upper,
double step_inc,
169 double climb_rate,
int digits,
const SPAttr a,
double def,
char* tip_text)
174 set_tooltip_text(tip_text);
176 set_range(lower, upper);
177 set_increments(step_inc, 0);
182 Glib::ustring get_as_attribute()
const override
184 const double val = get_value();
186 if(get_digits() == 0)
187 return Glib::Ascii::dtostr((
int)val);
189 return Glib::Ascii::dtostr(val);
192 void set_from_attribute(
SPObject* o)
override
196 set_value(Glib::Ascii::strtod(val));
203template <
typename T>
class ComboWithTooltip
204 :
public ComboBoxEnum<T>
209 Glib::ustring
const &tip_text = {})
212 this->set_tooltip_text(tip_text);
217class MultiSpinButton :
public Gtk::Box
220 MultiSpinButton(
double lower,
double upper,
double step_inc,
221 double climb_rate,
int digits,
222 std::vector<SPAttr>
const &attrs,
223 std::vector<double>
const &default_values,
224 std::vector<char *>
const &tip_text)
227 g_assert(attrs.size()==default_values.size());
228 g_assert(attrs.size()==tip_text.size());
230 for(
unsigned i = 0; i < attrs.size(); ++i) {
231 unsigned index = attrs.size() - 1 - i;
232 _spins.push_back(Gtk::make_managed<SpinButtonAttr>(lower, upper, step_inc, climb_rate, digits,
235 _spins.back()->set_width_chars(3);
239 std::vector<SpinButtonAttr *>
const &get_spinbuttons()
const
245 std::vector<SpinButtonAttr*> _spins;
249class DualSpinButton :
public Gtk::Box,
public AttrWidget
252 DualSpinButton(
char* def,
double lower,
double upper,
double step_inc,
253 double climb_rate,
int digits,
const SPAttr a,
char* tt1,
char* tt2)
256 _s1(climb_rate, digits), _s2(climb_rate, digits)
259 _s1.set_tooltip_text(tt1);
262 _s2.set_tooltip_text(tt2);
264 _s1.set_range(lower, upper);
265 _s2.set_range(lower, upper);
266 _s1.set_increments(step_inc, 0);
267 _s2.set_increments(step_inc, 0);
287 Glib::ustring get_as_attribute()
const override
289 double v1 = _s1.get_value();
290 double v2 = _s2.get_value();
292 if(_s1.get_digits() == 0) {
297 return Glib::Ascii::dtostr(v1) +
" " + Glib::Ascii::dtostr(v2);
300 void set_from_attribute(
SPObject* o)
override
309 _s1.set_value(
n.getNumber());
310 _s2.set_value(
n.getOptNumber());
317class ColorButton :
public Widget::ColorPicker,
public AttrWidget
320 ColorButton(
unsigned int def,
const SPAttr a,
char* tip_text)
326 set_tooltip_text(tip_text);
331 Glib::ustring get_as_attribute()
const override
336 void set_from_attribute(
SPObject* o)
override
339 if (
auto color = Colors::Color::parse(val)) {
348class EntryAttr :
public Gtk::Entry,
public AttrWidget
351 EntryAttr(
const SPAttr a,
char* tip_text)
357 set_tooltip_text(tip_text);
362 Glib::ustring get_as_attribute()
const override
367 void set_from_attribute(
SPObject* o)
override
379class FilterEffectsDialog::MatrixAttr :
public Gtk::Frame,
public AttrWidget
382 MatrixAttr(
const SPAttr a,
char* tip_text =
nullptr)
385 _model = Gtk::ListStore::create(_columns);
386 _tree.set_model(_model);
387 _tree.set_headers_visible(
false);
390 _tree.set_tooltip_text(tip_text);
394 std::vector<double> get_values()
const
396 std::vector<double> vec;
397 for(
const auto & iter : _model->children()) {
398 for(
unsigned c = 0;
c <
_tree.get_columns().
size(); ++
c)
399 vec.push_back(iter[_columns.cols[
c]]);
404 void set_values(
const std::vector<double>& v)
407 for (
auto &&iter : _model->children()) {
408 for(
unsigned c = 0;
c <
_tree.get_columns().
size(); ++
c) {
411 iter[_columns.cols[
c]] =
v[i];
417 Glib::ustring get_as_attribute()
const override
422 for(
const auto & iter : _model->children()) {
423 for(
unsigned c = 0;
c <
_tree.get_columns().
size(); ++
c) {
424 os << iter[_columns.cols[
c]] <<
" ";
431 void set_from_attribute(
SPObject* o)
override
434 if(is<SPFeConvolveMatrix>(o)) {
435 auto conv = cast<SPFeConvolveMatrix>(o);
437 cols = (int)conv->get_order().getNumber();
440 rows = conv->get_order().optNumIsSet() ? (int)conv->get_order().getOptNumber() : cols;
443 else if(is<SPFeColorMatrix>(o))
448 class MatrixColumns :
public Gtk::TreeModel::ColumnRecord
454 for(
auto & col : cols)
457 std::vector<Gtk::TreeModelColumn<double> > cols;
467 _tree.remove_all_columns();
469 std::vector<gdouble>
const *values =
nullptr;
470 if(is<SPFeColorMatrix>(o))
471 values = &cast<SPFeColorMatrix>(o)->get_values();
472 else if(is<SPFeConvolveMatrix>(o))
473 values = &cast<SPFeConvolveMatrix>(o)->get_kernel_matrix();
478 for(
int i = 0; i < cols; ++i) {
479 _tree.append_column_numeric_editable(
"", _columns.cols[i],
"%.2f");
480 dynamic_cast<Gtk::CellRendererText &
>(*
_tree.get_column_cell_renderer(i))
481 .signal_edited().connect(
482 sigc::mem_fun(*
this, &MatrixAttr::rebind));
486 for(
int r = 0; r < rows; ++r) {
487 Gtk::TreeRow row = *(_model->append());
489 for(
int c = 0;
c < cols; ++
c, ++ndx)
490 row[_columns.cols[
c]] = ndx < (
int)values->size() ? (*values)[ndx] : (r ==
c ? 1 : 0);
495 void rebind(
const Glib::ustring&,
const Glib::ustring&)
504 Glib::RefPtr<Gtk::ListStore> _model;
505 MatrixColumns _columns;
509class FilterEffectsDialog::ColorMatrixValues :
public Gtk::Frame,
public AttrWidget
515 _matrix(
SPAttr::
VALUES, _(
"This matrix determines a linear transform on color space. Each line affects one of the color components. Each column determines how much of each color component from the input is passed to the output. The last column does not depend on input colors, so can be used to adjust a constant component value.")),
518 _label(C_(
"Label",
"None"),
Gtk::
Align::START)
524 _label.set_sensitive(
false);
526 add_css_class(
"flat");
529 void set_from_attribute(
SPObject* o)
override
531 if(is<SPFeColorMatrix>(o)) {
532 auto col = cast<SPFeColorMatrix>(o);
535 switch(col->get_type()) {
537 set_child(_saturation);
538 _saturation.set_from_attribute(o);
543 _angle.set_from_attribute(o);
553 _matrix.set_from_attribute(o);
559 Glib::ustring get_as_attribute()
const override
561 const Widget*
w = get_child();
564 if (
auto attrw =
dynamic_cast<const AttrWidget *
>(
w))
565 return attrw->get_as_attribute();
566 g_assert_not_reached();
572 SpinScale _saturation;
580class FileOrElementChooser :
public Gtk::Box,
public AttrWidget
583 FileOrElementChooser(FilterEffectsDialog& d,
const SPAttr a)
593 _fromFile.set_image_from_icon_name(
"document-open");
594 _fromFile.set_tooltip_text(_(
"Choose image file"));
595 _fromFile.signal_clicked().connect(sigc::mem_fun(*
this, &FileOrElementChooser::select_file));
597 _fromSVGElement.set_label(_(
"SVG Element"));
598 _fromSVGElement.set_tooltip_text(_(
"Use selected SVG element"));
599 _fromSVGElement.signal_clicked().connect(sigc::mem_fun(*
this, &FileOrElementChooser::select_svg_element));
601 _entry.set_width_chars(1);
608 Glib::ustring get_as_attribute()
const override
610 return _entry.get_text();
614 void set_from_attribute(
SPObject* o)
override
618 _entry.set_text(val);
625 void select_svg_element() {
631 std::ostringstream xlikhref;
633 _entry.set_text(xlikhref.str());
639 std::string open_path;
643 auto window = _dialog.getDesktop()->getInkscapeWindow();
645 auto file =
choose_file_open(_(
"Select an image to be used as input."), window, filters, open_path);
652 prefs->
setString(
"/dialogs/open/path", file->get_path());
654 _entry.set_text(file->get_parse_name());
658 Gtk::Button _fromFile;
659 Gtk::Button _fromSVGElement;
660 FilterEffectsDialog &_dialog;
663class FilterEffectsDialog::Settings
666 typedef sigc::slot<void (
const AttrWidget*)> SetAttrSlot;
669 : _dialog(d), _set_attr_slot(
std::move(slot)), _current_type(-1), _max_types(maxtypes)
671 _groups.resize(_max_types);
672 _attrwidgets.resize(_max_types);
673 _size_group = Gtk::SizeGroup::create(Gtk::SizeGroup::Mode::HORIZONTAL);
675 for(
int i = 0; i < _max_types; ++i) {
676 _groups[i] = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::VERTICAL, 3);
683 void show_current_only() {
684 for (
auto& group : _groups) {
685 group->set_visible(
false);
687 auto t = get_current_type();
689 _groups[t]->set_visible(
true);
694 void show_and_update(
const int t,
SPObject* ob)
696 if (t != _current_type) {
699 for (
auto& group : _groups) {
700 group->set_visible(
false);
705 _groups[t]->set_visible(
true);
708 _dialog.set_attrs_locked(
true);
709 for(
auto & i : _attrwidgets[_current_type])
710 i->set_from_attribute(ob);
711 _dialog.set_attrs_locked(
false);
714 int get_current_type()
const
716 return _current_type;
719 void type(
const int t)
726 auto const lbl = Gtk::make_managed<Gtk::Label>(_(
"This SVG filter effect does not require any parameters."));
728 lbl->set_wrap_mode(Pango::WrapMode::WORD);
733 LightSourceControl* add_lightsource();
739 CheckButtonAttr* add_checkbutton(
bool def,
const SPAttr attr,
const Glib::ustring&
label,
740 const Glib::ustring& tv,
const Glib::ustring& fv,
char* tip_text =
nullptr)
742 auto const cb = Gtk::make_managed<CheckButtonAttr>(def,
label, tv, fv, attr, tip_text);
749 ColorButton* add_color(
unsigned int def,
const SPAttr attr,
const Glib::ustring&
label,
char* tip_text =
nullptr)
751 auto const col = Gtk::make_managed<ColorButton>(def, attr, tip_text);
752 add_widget(col,
label);
753 add_attr_widget(col);
758 MatrixAttr* add_matrix(
const SPAttr attr,
const Glib::ustring&
label,
char* tip_text)
760 auto const conv = Gtk::make_managed<MatrixAttr>(attr, tip_text);
761 add_widget(conv,
label);
762 add_attr_widget(conv);
767 ColorMatrixValues* add_colormatrixvalues(
const Glib::ustring&
label)
769 auto const cmv = Gtk::make_managed<ColorMatrixValues>();
770 add_widget(cmv,
label);
771 add_attr_widget(cmv);
776 SpinScale* add_spinscale(
double def,
const SPAttr attr,
const Glib::ustring&
label,
777 const double lo,
const double hi,
const double step_inc,
const double page_inc,
const int digits,
char* tip_text =
nullptr)
779 Glib::ustring tip_text2;
781 tip_text2 = tip_text;
782 auto const spinslider = Gtk::make_managed<SpinScale>(
"", def, lo, hi, step_inc, page_inc, digits, attr, tip_text2);
783 add_widget(spinslider,
label);
784 add_attr_widget(spinslider);
789 DualSpinScale* add_dualspinscale(
const SPAttr attr,
const Glib::ustring&
label,
790 const double lo,
const double hi,
const double step_inc,
791 const double climb,
const int digits,
792 const Glib::ustring tip_text1 =
"",
793 const Glib::ustring tip_text2 =
"")
795 auto const dss = Gtk::make_managed<DualSpinScale>(
"",
"", lo, lo, hi, step_inc, climb, digits, attr, tip_text1, tip_text2);
796 add_widget(dss,
label);
797 add_attr_widget(dss);
802 SpinButtonAttr* add_spinbutton(
double defalt_value,
const SPAttr attr,
const Glib::ustring&
label,
803 const double lo,
const double hi,
const double step_inc,
804 const double climb,
const int digits,
char* tip =
nullptr)
806 auto const sb = Gtk::make_managed<SpinButtonAttr>(lo, hi, step_inc, climb, digits, attr, defalt_value, tip);
807 add_widget(sb,
label);
813 DualSpinButton* add_dualspinbutton(
char* defalt_value,
const SPAttr attr,
const Glib::ustring&
label,
814 const double lo,
const double hi,
const double step_inc,
815 const double climb,
const int digits,
char* tip1 =
nullptr,
char* tip2 =
nullptr)
817 auto const dsb = Gtk::make_managed<DualSpinButton>(defalt_value, lo, hi, step_inc, climb, digits, attr, tip1, tip2);
818 add_widget(dsb,
label);
819 add_attr_widget(dsb);
824 MultiSpinButton* add_multispinbutton(
double def1,
double def2,
const SPAttr attr1,
const SPAttr attr2,
825 const Glib::ustring&
label,
const double lo,
const double hi,
826 const double step_inc,
const double climb,
const int digits,
char* tip1 =
nullptr,
char* tip2 =
nullptr)
828 auto const attrs = std::vector{attr1, attr2};
829 auto const default_values = std::vector{ def1, def2};
830 auto const tips = std::vector{ tip1, tip2};
831 auto const msb = Gtk::make_managed<MultiSpinButton>(lo, hi, step_inc, climb, digits, attrs, default_values, tips);
832 add_widget(msb,
label);
833 for (
auto const i : msb->get_spinbuttons())
838 MultiSpinButton* add_multispinbutton(
double def1,
double def2,
double def3,
const SPAttr attr1,
const SPAttr attr2,
839 const SPAttr attr3,
const Glib::ustring&
label,
const double lo,
840 const double hi,
const double step_inc,
const double climb,
const int digits,
char* tip1 =
nullptr,
char* tip2 =
nullptr,
char* tip3 =
nullptr)
842 auto const attrs = std::vector{attr1, attr2, attr3};
843 auto const default_values = std::vector{ def1, def2, def3};
844 auto const tips = std::vector{ tip1, tip2, tip3};
845 auto const msb = Gtk::make_managed<MultiSpinButton>(lo, hi, step_inc, climb, digits, attrs, default_values, tips);
846 add_widget(msb,
label);
847 for (
auto const i : msb->get_spinbuttons())
855 auto const foech = Gtk::make_managed<FileOrElementChooser>(_dialog, attr);
856 add_widget(foech,
label);
857 add_attr_widget(foech);
862 template <
typename T> ComboWithTooltip<T>* add_combo(T default_value,
const SPAttr attr,
863 const Glib::ustring&
label,
865 const Glib::ustring& tip_text = {})
867 auto const combo = Gtk::make_managed<ComboWithTooltip<T>>(default_value, conv, attr, tip_text);
868 add_widget(combo,
label);
869 add_attr_widget(combo);
874 EntryAttr* add_entry(
const SPAttr attr,
875 const Glib::ustring&
label,
876 char* tip_text =
nullptr)
878 auto const entry = Gtk::make_managed<EntryAttr>(attr, tip_text);
879 add_widget(entry,
label);
880 add_attr_widget(entry);
884 Glib::RefPtr<Gtk::SizeGroup> _size_group;
887 void add_attr_widget(AttrWidget* a)
889 _attrwidgets[_current_type].push_back(a);
890 a->signal_attr_changed().connect(sigc::bind(_set_attr_slot, a));
896 void add_widget(Gtk::Widget*
w,
const Glib::ustring&
label)
898 g_assert(
w->is_managed_());
900 auto const hb = Gtk::make_managed<Gtk::Box>(Gtk::Orientation::HORIZONTAL);
904 auto const lbl = Gtk::make_managed<Gtk::Label>(
label);
905 lbl->set_xalign(0.0);
907 _size_group->add_widget(*lbl);
914 std::vector<Gtk::Box*> _groups;
916 SetAttrSlot _set_attr_slot;
917 std::vector<std::vector< AttrWidget*> > _attrwidgets;
918 int _current_type, _max_types;
922class FilterEffectsDialog::ComponentTransferValues :
public Gtk::Frame,
public AttrWidget
934 add_css_class(
"flat");
939 _type.signal_changed().connect(sigc::mem_fun(*
this, &ComponentTransferValues::on_type_changed));
942 _settings.add_spinscale(1,
SPAttr::SLOPE, _(
"Slope"), -10, 10, 0.1, 0.01, 2);
943 _settings.add_spinscale(0,
SPAttr::INTERCEPT, _(
"Intercept"), -10, 10, 0.1, 0.01, 2);
946 _settings.add_spinscale(1,
SPAttr::AMPLITUDE, _(
"Amplitude"), 0, 10, 0.1, 0.01, 2);
947 _settings.add_spinscale(1,
SPAttr::EXPONENT, _(
"Exponent"), 0, 10, 0.1, 0.01, 2);
948 _settings.add_spinscale(0,
SPAttr::OFFSET, _(
"Offset"), -10, 10, 0.1, 0.01, 2);
951 _settings.add_entry(
SPAttr::TABLEVALUES, _(
"Values"), _(
"List of stops with interpolated output"));
954 _settings.add_entry(
SPAttr::TABLEVALUES, _(
"Values"), _(
"List of discrete values for a step function"));
965 for(
auto&
node: ct->children) {
966 funcNode = cast<SPFeFuncNode>(&
node);
967 if( funcNode->
channel == _channel ) {
978 void set_func_attr(
const AttrWidget* input)
980 _dialog.set_attr( _funcNode, input->get_attribute(), input->get_as_attribute().c_str());
984 void set_from_attribute(
SPObject* o)
override
987 if(is<SPFeComponentTransfer>(o)) {
988 auto ct = cast<SPFeComponentTransfer>(o);
990 _funcNode = find_node(ct);
992 _type.set_from_attribute( _funcNode );
1019 _funcNode = find_node(ct);
1021 _funcNode->setAttribute(
"type",
"identity" );
1033 void on_type_changed()
1039 SPFilter* filter = _dialog._filter_modifier.get_selected_filter();
1051 if(prim && _funcNode) {
1052 auto id = _type.get_selected_id();
1053 if (
id.has_value()) {
1054 _settings.show_and_update(*
id, _funcNode);
1060 Glib::ustring get_as_attribute()
const override
1068 ComboBoxEnum<FilterComponentTransferType> _type;
1074class FilterEffectsDialog::LightSourceControl
1084 _light_label(_(
"Light Source:")),
1089 _light_label.set_xalign(0.0);
1090 _settings._size_group->add_widget(_light_label);
1094 prepend(_light_box);
1095 _light_source.signal_changed().connect(sigc::mem_fun(*
this, &LightSourceControl::on_source_changed));
1100 _settings.add_spinscale(0,
SPAttr::AZIMUTH, _(
"Azimuth:"), 0, 360, 1, 1, 0, _(
"Direction angle for the light source on the XY plane, in degrees"));
1101 _settings.add_spinscale(0,
SPAttr::ELEVATION, _(
"Elevation:"), 0, 360, 1, 1, 0, _(
"Direction angle for the light source on the YZ plane, in degrees"));
1104 _settings.add_multispinbutton( (
double) 0, (
double) 0, (
double) 0,
SPAttr::X,
SPAttr::Y,
SPAttr::Z, _(
"Location:"), -99999, 99999, 1, 100, 0, _(
"X coordinate"), _(
"Y coordinate"), _(
"Z coordinate"));
1107 _settings.add_multispinbutton( (
double) 0, (
double) 0, (
double) 0,
SPAttr::X,
SPAttr::Y,
SPAttr::Z, _(
"Location:"), -99999, 99999, 1, 100, 0, _(
"X coordinate"), _(
"Y coordinate"), _(
"Z coordinate"));
1108 _settings.add_multispinbutton( (
double) 0, (
double) 0, (
double) 0,
1110 _(
"Points at:"), -99999, 99999, 1, 100, 0, _(
"X coordinate"), _(
"Y coordinate"), _(
"Z coordinate"));
1111 _settings.add_spinscale(1,
SPAttr::SPECULAREXPONENT, _(
"Specular Exponent:"), 0.1, 100, 0.1, 1, 1, _(
"Exponent value controlling the focus for the light source"));
1113 _settings.add_spinscale(100,
SPAttr::LIMITINGCONEANGLE, _(
"Cone Angle:"), 0, 180, 1, 5, 0, _(
"This is the angle between the spot light axis (i.e. the axis between the light source and the point to which it is pointing at) and the spot light cone. No light is projected outside this cone."));
1119 Glib::ustring get_as_attribute()
const override
1124 void set_from_attribute(
SPObject* o)
override
1133 if(is<SPFeDistantLight>(
child))
1134 _light_source.set_active(0);
1135 else if(is<SPFePointLight>(
child))
1136 _light_source.set_active(1);
1137 else if(is<SPFeSpotLight>(
child))
1138 _light_source.set_active(2);
1140 _light_source.set_active(-1);
1147 void on_source_changed()
1157 const int ls = _light_source.get_selected();
1159 if(!(ls == -1 && !
child) &&
1160 !(ls == 0 && is<SPFeDistantLight>(
child)) &&
1161 !(ls == 1 && is<SPFePointLight>(
child)) &&
1162 !(ls == 2 && is<SPFeSpotLight>(
child))) {
1189 auto id = _light_source.get_selected_id();
1190 if (
id.has_value()) {
1191 _settings.show_and_update(*
id, prim->
firstChild());
1195 _settings.show_current_only();
1201 Gtk::Box _light_box;
1202 Gtk::Label _light_label;
1203 ComboBoxEnum<LightSource> _light_source;
1207FilterEffectsDialog::ComponentTransferValues* FilterEffectsDialog::Settings::add_componenttransfervalues(
const Glib::ustring&
label,
SPFeFuncNode::Channel channel)
1209 auto const ct = Gtk::make_managed<ComponentTransferValues>(_dialog, channel);
1210 add_widget(ct,
label);
1211 add_attr_widget(ct);
1212 ct->set_margin_top(4);
1213 ct->set_margin_bottom(4);
1217FilterEffectsDialog::LightSourceControl* FilterEffectsDialog::Settings::add_lightsource()
1219 auto const ls = Gtk::make_managed<LightSourceControl>(_dialog);
1220 add_attr_widget(ls);
1226 sigc::slot<
void ()> dup,
1227 sigc::slot<
void ()> rem)
1229 auto menu = std::make_unique<UI::Widget::PopoverMenu>(Gtk::PositionType::RIGHT);
1231 auto mi = Gtk::make_managed<UI::Widget::PopoverMenuItem>(_(
"_Duplicate"),
true);
1232 mi->signal_activate().connect(std::move(dup));
1235 mi = Gtk::make_managed<UI::Widget::PopoverMenuItem>(_(
"_Remove"),
true);
1236 mi->signal_activate().connect(std::move(rem));
1252 _menu(create_menu()),
1253 _observer(
std::make_unique<
Inkscape::XML::SignalObserver>())
1260 Gtk::TreeViewColumn* col =
_list.get_column(selcol - 1);
1264 dynamic_cast<Gtk::CellRendererText &
>(*
_list.get_column(1)->get_first_cell()).
1268 _list.get_column(2)->set_sizing(Gtk::TreeViewColumn::Sizing::AUTOSIZE);
1269 _list.get_column(2)->set_expand(
false);
1270 _list.get_column(2)->set_reorderable(
true);
1272 _list.get_column(1)->set_resizable(
true);
1273 _list.get_column(1)->set_sizing(Gtk::TreeViewColumn::Sizing::FIXED);
1274 _list.get_column(1)->set_expand(
true);
1276 _list.set_reorderable(
false);
1277 _list.enable_model_drag_dest(Gdk::DragAction::MOVE);
1280 _list.signal_drag_drop().connect( sigc::mem_fun(*
this, &FilterModifier::on_filter_move), false );
1290 auto const click = Gtk::GestureClick::create();
1291 click->set_button(3);
1293 _list.add_controller(click);
1309 std::set<SPFilter*>
used;
1311 for (
auto obj : sel->
items()) {
1313 if (!style || !obj) {
1319 obj->bbox_valid = FALSE;
1326 for (
auto &&
item : _filters_model->children()) {
1327 if (
used.count(
item[_columns.filter])) {
1330 _list.get_selection()->select(
item.get_iter());
1334 item[_columns.sel] = 0;
1338 _signal_filters_updated.emit();
1343 auto menu = std::make_unique<UI::Widget::PopoverMenu>(Gtk::PositionType::BOTTOM);
1344 auto append = [&](Glib::ustring
const &text,
auto const mem_fun)
1346 auto &
item = *Gtk::make_managed<UI::Widget::PopoverMenuItem>(text,
true);
1347 item.signal_activate().connect(sigc::mem_fun(*
this, mem_fun));
1359 _observer->set(get_selected_filter());
1360 signal_filter_changed()();
1365 if (
auto iter = _filters_model->get_iter(path)) {
1366 SPFilter* filter = (*iter)[_columns.filter];
1370 (*iter)[_columns.label] = text;
1376bool FilterEffectsDialog::FilterModifier::on_filter_move(
const Glib::RefPtr<Gdk::DragContext>& ,
int ,
int , guint ) {
1395 Gtk::TreeModel::iterator iter = _filters_model->get_iter(path);
1396 selection_toggled(iter,
false);
1405 SPFilter* filter = (*iter)[_columns.filter];
1408 if ((*iter)[_columns.sel] == 1 && toggle) {
1414 g_assert(style !=
nullptr);
1425 update_selection(sel);
1431 for (
auto&&
item : _filters_model->children()) {
1438 if (!filter)
return Glib::ustring();
1443 else if (
auto id = filter->
getId()) {
1455 auto document = _dialog.getDocument();
1460 _filters_model->clear();
1463 for (
auto filter : filters) {
1464 Gtk::TreeModel::Row row = *_filters_model->append();
1465 auto f = cast<SPFilter>(filter);
1466 row[_columns.filter] = f;
1473 update_selection(_dialog.getSelection());
1475 select_filter(first);
1477 _dialog.update_filter_general_settings_view();
1478 _dialog.update_settings_view();
1482 if (
auto&& sel = _list.get_selection()) {
1483 if (Gtk::TreeModel::iterator it = sel->get_selected()) {
1484 return (*it)[_columns.sel] > 0;
1492 return !_filters_model->children().empty();
1496 if (
auto&& sel = _list.get_selection()) {
1497 selection_toggled(sel->get_selected(),
true);
1503 if(_list.get_selection()) {
1504 Gtk::TreeModel::iterator i = _list.get_selection()->get_selected();
1506 return (*i)[_columns.filter];
1514 if (!filter)
return;
1516 for (
auto &&
item : _filters_model->children()) {
1517 if (
item[_columns.filter] == filter) {
1518 _list.get_selection()->select(
item.get_iter());
1524Gtk::EventSequenceState
1527 double const x,
double const y)
1529 const bool sensitive = get_selected_filter() !=
nullptr;
1530 auto const &
items = _menu->get_items();
1531 items.at(0)->set_sensitive(sensitive);
1532 items.at(1)->set_sensitive(sensitive);
1533 items.at(3)->set_sensitive(sensitive);
1534 _dialog._popoverbin.setPopover(_menu.get());
1535 _menu->popup_at(_list, x, y);
1536 return Gtk::EventSequenceState::CLAIMED;
1544 const int count = _filters_model->children().size();
1545 std::ostringstream os;
1546 os << _(
"filter") << count;
1547 filter->
setLabel(os.str().c_str());
1551 select_filter(filter);
1558 SPFilter *filter = get_selected_filter();
1561 auto desktop = _dialog.getDesktop();
1566 for (
auto item : all) {
1575 if (ifilter && ifilter->
href) {
1577 if (obj && obj == (
SPObject *)filter) {
1591 auto &&filters = _filters_model->children();
1592 if (!filters.empty()) {
1593 _list.get_selection()->select(filters[0].get_iter());
1600 SPFilter* filter = get_selected_filter();
1616 _list.set_cursor(_filters_model->get_path(_list.get_selection()->get_selected()), *_list.get_column(1),
true);
1621 SPFilter *filter = get_selected_filter();
1622 auto desktop = _dialog.getDesktop();
1627 std::vector<SPItem*>
items;
1637 if (obj && obj == (
SPObject *)filter) {
1647 , _primitive(*this,
"primitive", nullptr)
1652 return _primitive.get_proxy();
1657 int& natural_width)
const
1661 minimum_width = natural_width = size_w * primlist.primitive_count() + primlist.get_input_type_width() * count;
1667 int& natural_width)
const
1669 get_preferred_width(widget, minimum_width, natural_width);
1673 int& minimum_height,
1674 int& natural_height)
const
1679 minimum_height = natural_height = size_h *
input_count(prim);
1684 int& minimum_height,
1685 int& natural_height)
const
1687 get_preferred_height(widget, minimum_height, natural_height);
1692 :
Glib::ObjectBase{
"FilterEffectsDialogPrimitiveList"}
1697 , _observer(
std::make_unique<
Inkscape::XML::SignalObserver>())
1701 auto const click = Gtk::GestureClick::create();
1702 click->set_button(0);
1703 click->set_propagation_phase(Gtk::PropagationPhase::TARGET);
1706 add_controller(click);
1708 auto const motion = Gtk::EventControllerMotion::create();
1709 motion->set_propagation_phase(Gtk::PropagationPhase::TARGET);
1711 add_controller(motion);
1715 set_reorderable(
true);
1717 auto const drag = Gtk::DragSource::create();
1719 add_controller(drag);
1723 get_column(0)->set_resizable(
true);
1724 set_headers_visible(
false);
1733 Gtk::TreeViewColumn* col = get_column(cols_count - 1);
1748 Glib::RefPtr<Pango::Context> context = create_pango_context();
1749 const Pango::Matrix matrix = {0, -1, 1, 0, 0, 0};
1750 context->set_matrix(matrix);
1751 _vertical_layout = Pango::Layout::create(context);
1755 _input_type_height = _input_type_width = 0;
1759 _vertical_layout->get_pixel_size(fontw, fonth);
1760 if(fonth > _input_type_width)
1761 _input_type_width = fonth;
1762 if (fontw > _input_type_height)
1763 _input_type_height = fontw;
1769 return _signal_primitive_changed;
1774 _observer->set(get_selected());
1775 signal_primitive_changed()();
1782 SPFilter* f = _dialog._filter_modifier.get_selected_filter();
1787 bool active_found =
false;
1788 _dialog._primitive_box->set_sensitive(
true);
1789 _dialog.update_filter_general_settings_view();
1791 auto prim = cast<SPFilterPrimitive>(&prim_obj);
1795 Gtk::TreeModel::Row row = *_model->append();
1796 row[_columns.primitive] = prim;
1802 if (prim->
getId()) {
1803 row[_columns.id] = Glib::ustring(prim->
getId());
1806 if(prim == active_prim) {
1807 get_selection()->select(row.get_iter());
1808 active_found =
true;
1812 if(!active_found && _model->children().begin())
1813 get_selection()->select(_model->children().begin());
1826 get_visible_rect(vis);
1827 convert_tree_to_widget_coords(vis.get_x(), vis.get_y(), vis_x, vis_y);
1828 set_size_request(
width, _input_type_height + 2 + vis_y);
1831 _dialog._primitive_box->set_sensitive(
false);
1832 set_size_request(-1, -1);
1843 if(_dialog._filter_modifier.get_selected_filter()) {
1844 Gtk::TreeModel::iterator i = get_selection()->get_selected();
1846 return (*i)[_columns.primitive];
1854 for (
auto &&
item : _model->children()) {
1855 if (
item[_columns.primitive] == prim) {
1856 get_selection()->select(
item.get_iter());
1865 _observer->
set(
nullptr);
1866 _model->erase(get_selection()->get_selected());
1871 DocumentUndo::done(_dialog.getDocument(), _(
"Remove filter primitive"), INKSCAPE_ICON(
"dialog-filters"));
1878 std::vector<Geom::Point>
const &points,
1879 Gdk::RGBA
const &fill, Gdk::RGBA
const &stroke);
1883 parent_type::snapshot_vfunc(snapshot);
1885 auto const cr = snapshot->append_cairo(get_allocation());
1887 cr->set_line_width(1.0);
1891 int x_origin, y_origin;
1892 convert_bin_window_to_widget_coords(0,0,x_origin,y_origin);
1893 cr->translate(x_origin, y_origin);
1895 auto const fg_color = get_color();
1896 auto bar_color =
mix_colors(bg_color, fg_color, 0.06);
1898 auto mid_color =
mix_colors(bg_color, fg_color, 0.16);
1901 int row_count = get_model()->children().size();
1904 Gdk::Rectangle rct, vis;
1905 Gtk::TreeModel::iterator row = get_model()->children().begin();
1906 int text_start_x = 0;
1908 get_cell_area(get_model()->get_path(row), *get_column(1), rct);
1909 get_visible_rect(vis);
1910 text_start_x = rct.get_x() + rct.get_width() - get_input_type_width() * _inputs_count + 1;
1912 auto w = get_input_type_width();
1913 auto h = vis.get_height();
1916 Gdk::Cairo::set_source_rgba(cr, bg_color);
1917 cr->rectangle(text_start_x + 1, 0,
w * _inputs_count, h);
1922 for(
unsigned int i = 0; i < _inputs_count; ++i) {
1924 const int x = text_start_x +
w * i;
1927 Gdk::Cairo::set_source_rgba(cr, bar_color);
1928 cr->rectangle(x + 1, 0,
w - 2, h);
1931 Gdk::Cairo::set_source_rgba(cr, text_color);
1932 cr->move_to(x +
w, 5);
1933 cr->rotate_degrees(90);
1934 _vertical_layout->show_in_cairo_context(cr);
1940 cr->rectangle(vis.get_x(), 0, vis.get_width(), vis.get_height());
1945 for(; row != get_model()->children().end(); ++row, ++row_index) {
1946 get_cell_area(get_model()->get_path(row), *get_column(1), rct);
1947 const int x = rct.get_x(), y = rct.get_y(), h = rct.get_height();
1951 Gdk::ModifierType mask;
1952 auto const display = get_display();
1953 auto seat = display->get_default_seat();
1954 auto device = seat->get_pointer();
1955 auto const surface =
dynamic_cast<Gtk::Native &
>(*get_root()).get_surface();
1957 surface->get_device_position(device, mx, my, mask);
1959 cr->set_line_width(1);
1962 const int outline_x = x + fwidth * (row_count - row_index);
1965 Gdk::Cairo::set_source_rgba(cr, mid_color);
1967 cr->move_to(vis.get_x(), y + h);
1968 cr->line_to(outline_x, y + h);
1970 cr->line_to(outline_x, y - 1);
1975 std::vector<Geom::Point> con_poly;
1982 if(is<SPFeMerge>(row_prim)) {
1983 for(
int i = 0; i < inputs; ++i) {
1984 inside = do_connection_node(row, i, con_poly, mx, my);
1988 if(_in_drag == (i + 1)) {
1989 con_drag_y = con_poly[2].y();
1990 con_drag_x = con_poly[2].x();
1993 if(_in_drag != (i + 1) || row_prim != prim) {
1995 con_poly[2].y(), row_count, i, fg_color, mid_color);
2001 inside = do_connection_node(row, 0, con_poly, mx, my);
2002 con_drag_y = con_poly[2].y();
2003 con_drag_x = con_poly[2].x();
2008 if(_in_drag != 1 || row_prim != prim) {
2009 draw_connection(cr, row,
SPAttr::IN_, text_start_x, outline_x,
2010 con_poly[2].y(), row_count, -1, fg_color, mid_color);
2015 inside = do_connection_node(row, 1, con_poly, mx, my);
2017 con_drag_y = con_poly[2].y();
2018 con_drag_x = con_poly[2].x();
2024 if(_in_drag != 2 || row_prim != prim) {
2025 draw_connection(cr, row,
SPAttr::IN2, text_start_x, outline_x,
2026 con_poly[2].y(), row_count, -1, fg_color, mid_color);
2032 if(row_prim == prim && _in_drag) {
2034 Gdk::Cairo::set_source_rgba(cr, fg_color);
2035 cr->move_to(con_drag_x, con_drag_y);
2036 cr->line_to(mx, con_drag_y);
2037 cr->line_to(mx, my);
2045 const Gtk::TreeModel::iterator& input,
const SPAttr attr,
2046 const int text_start_x,
const int x1,
const int y1,
2047 const int row_count,
const int pos,
2048 const Gdk::RGBA fg_color,
const Gdk::RGBA mid_color)
2053 Gtk::TreeModel::iterator res = find_result(input, attr, src_id, pos);
2055 const bool is_first = input == get_model()->children().begin();
2056 const bool is_selected = (get_selection()->get_selected())
2057 ? input == get_selection()->get_selected()
2059 const bool is_merge = is<SPFeMerge>((
SPFilterPrimitive*)(*input)[_columns.primitive]);
2060 const bool use_default = !res && !is_merge;
2064 cr->set_line_width(2.5);
2068 if(res == input || (use_default && is_first)) {
2071 const int tw = get_input_type_width();
2072 gint end_x = text_start_x + tw * src_id + 1;
2074 if(use_default && is_first) {
2075 Gdk::Cairo::set_source_rgba(cr, fg_color);
2076 cr->set_dash(std::vector<double> {1.0, 1.0}, 0);
2078 Gdk::Cairo::set_source_rgba(cr, fg_color);
2082 cr->move_to(x1, y1);
2083 cr->line_to(end_x, y1);
2085 cr->arc(end_x, y1, arc_radius, M_PI / 2, M_PI * 1.5);
2099 get_cell_area(get_model()->get_path(_model->children().begin()), *get_column(1), rct);
2103 get_cell_area(get_model()->get_path(res), *get_column(1), rct);
2104 const int row_index = find_index(res);
2105 const int x2 = rct.get_x() + fwidth * (row_count - row_index) - fwidth / 2;
2106 const int y2 = rct.get_y() + rct.get_height();
2109 Gdk::Cairo::set_source_rgba(cr, fg_color);
2110 cr->move_to(x1, y1);
2111 cr->line_to(x2 - fwidth/4, y1);
2112 cr->line_to(x2, y1 - fheight/4);
2113 cr->line_to(x2, y2);
2123 std::vector<Geom::Point>
const &points,
2124 Gdk::RGBA
const &fill, Gdk::RGBA
const &stroke)
2127 cr->move_to(points[0].x() + 0.5, points[0].y() + 0.5);
2128 cr->line_to(points[1].x() + 0.5, points[1].y() + 0.5);
2129 cr->line_to(points[2].x() + 0.5, points[2].y() + 0.5);
2130 cr->line_to(points[0].x() + 0.5, points[0].y() + 0.5);
2133 Gdk::Cairo::set_source_rgba(cr, fill);
2134 cr->fill_preserve();
2135 cr->set_line_width(1);
2136 Gdk::Cairo::set_source_rgba(cr, stroke);
2144 std::vector<Geom::Point> &points,
2145 const int ix,
const int iy)
2148 const int icnt =
input_count((*row)[_columns.primitive]);
2150 get_cell_area(get_model()->get_path(_model->children().begin()), *get_column(1), rct);
2155 const float h = rct.get_height() / icnt;
2157 const int x = rct.get_x() + fwidth * (_model->children().size() - find_index(row));
2159 const int con_w = (int)(fwidth * 0.70f);
2160 const int con_h = (int)(fheight * 0.35f);
2161 const int con_y = (int)(rct.get_y() + (h / 2) - con_h + (input * h));
2163 points.emplace_back(x, con_y);
2164 points.emplace_back(x, con_y + con_h * 2);
2165 points.emplace_back(x - con_w, con_y + con_h);
2167 return ix >= x - h && iy >= con_y && ix <= x && iy <= points[1].y();
2171 const SPAttr attr,
int& src_id,
2175 Gtk::TreeModel::iterator target = _model->
children().end();
2178 if(is<SPFeMerge>(prim)) {
2182 if(
c == pos && is<SPFeMergeNode>(&o)) {
2183 image = cast<SPFeMergeNode>(&o)->get_in();
2195 if(is<SPFeBlend>(prim))
2196 image = cast<SPFeBlend>(prim)->get_in2();
2197 else if(is<SPFeComposite>(prim))
2198 image = cast<SPFeComposite>(prim)->get_in2();
2199 else if(is<SPFeDisplacementMap>(prim))
2200 image = cast<SPFeDisplacementMap>(prim)->get_in2();
2209 for(Gtk::TreeModel::iterator i = _model->children().begin();
2216 else if(
image < -1) {
2217 src_id = -(
image + 2);
2227 for (
auto iter = _model->children().begin(); iter != target; ++iter, ++i) {}
2234 tree_view.convert_widget_to_bin_window_coords(wx, wy, bx, by);
2238Gtk::EventSequenceState
2241 double const wx,
double const wy)
2244 Gtk::TreeViewColumn* col;
2248 _drag_prim =
nullptr;
2250 if(get_path_at_pos(x, y, path, col, cx, cy)) {
2251 Gtk::TreeModel::iterator iter = _model->get_iter(path);
2252 std::vector<Geom::Point> points;
2254 _drag_prim = (*iter)[_columns.primitive];
2257 for(
int i = 0; i < icnt; ++i) {
2258 if(do_connection_node(_model->get_iter(path), i, points, x, y)) {
2271 get_selection()->select(path);
2272 return Gtk::EventSequenceState::CLAIMED;
2275 return Gtk::EventSequenceState::NONE;
2280 const int speed = 10;
2281 const int limit = 15;
2286 get_visible_rect(vis);
2289 convert_widget_to_tree_coords(vis.get_x(), vis.get_y(), vis_x2, vis_y2);
2290 convert_tree_to_widget_coords(vis.get_x(), vis.get_y(), vis_x, vis_y);
2291 const int top = vis_y + vis.get_height();
2292 const int right_edge = vis_x + vis.get_width();
2297 _autoscroll_y = -(int)(speed + (vis_y - y) / 5);
2298 else if (y < vis_y +
limit)
2299 _autoscroll_y = -speed;
2301 _autoscroll_y = (int)(speed + (y - top) / 5);
2302 else if (y > top -
limit)
2303 _autoscroll_y = speed;
2307 double const e2 = x - vis_x2 / 2;
2310 _autoscroll_x = -(int)(speed + (vis_x - e2) / 5);
2311 else if(e2 < vis_x +
limit)
2312 _autoscroll_x = -speed;
2313 else if(e2 > right_edge)
2314 _autoscroll_x = (int)(speed + (e2 - right_edge) / 5);
2315 else if(e2 > right_edge -
limit)
2316 _autoscroll_x = speed;
2323Gtk::EventSequenceState
2326 double const wx,
double const wy)
2328 _scroll_connection.disconnect();
2330 auto const prim = get_selected();
2331 if(_in_drag && prim) {
2334 Gtk::TreeViewColumn* col;
2336 if (get_path_at_pos(x, y, path, col, cx, cy)) {
2337 auto const selected_iter = get_selection()->get_selected();
2338 g_assert(selected_iter);
2340 auto const target_iter = _model->get_iter(path);
2341 g_assert(target_iter);
2343 auto const target = target_iter->get_value(_columns.primitive);
2346 col = get_column(1);
2349 char const *in_val =
nullptr;
2354 const int twidth = get_input_type_width();
2355 const int sources_x = rct.get_width() - twidth * _inputs_count;
2356 if(cx > sources_x) {
2357 int src = (cx - sources_x) / twidth;
2360 }
else if(src >=
static_cast<int>(_inputs_count)) {
2361 src = _inputs_count - 1;
2367 for (
auto iter = _model->children().begin(); iter != selected_iter; ++iter) {
2368 if(iter == target_iter) {
2371 const gchar *gres = repr->
attribute(
"result");
2373 result = cast<SPFilter>(prim->
parent)->get_new_result_name();
2384 if(is<SPFeMerge>(prim)) {
2386 bool handled =
false;
2388 if(
c == _in_drag && is<SPFeMergeNode>(&o)) {
2394 selected_iter->set_value(_columns.primitive, prim);
2405 if(!handled &&
c == _in_drag && in_val) {
2415 selected_iter->set_value(_columns.primitive, prim);
2421 else if(_in_drag == 2)
2429 _dialog.update_settings_view();
2432 if (click.get_current_button() == 3) {
2433 bool const sensitive = prim !=
nullptr;
2434 _primitive_menu->set_sensitive(sensitive);
2435 _dialog._popoverbin.setPopover(_primitive_menu.get());
2436 _primitive_menu->popup_at(*
this, wx + 4, wy);
2437 return Gtk::EventSequenceState::CLAIMED;
2440 return Gtk::EventSequenceState::NONE;
2446 if (prim && (
result >= 0)) {
2451 if (
auto blend = cast<SPFeBlend>(prim)) {
2452 if (blend->get_in2() ==
result) {
2455 }
else if (
auto comp = cast<SPFeComposite>(prim)) {
2456 if (comp->get_in2() ==
result) {
2459 }
else if (
auto disp = cast<SPFeDisplacementMap>(prim)) {
2460 if (disp->get_in2() ==
result) {
2473 for (
auto iter = _model->children().begin(); iter != _model->children().end(); ++iter) {
2474 if(iter == prim_iter)
2490 SPFilter* filter = _dialog._filter_modifier.get_selected_filter();
2494 for (
auto iter = _model->children().begin(); iter != _model->children().end(); ++iter, ++ndx) {
2496 if (prim && prim == _drag_prim) {
2502 for (
auto iter = _model->children().begin(); iter != _model->children().end(); ++iter) {
2504 if (prim && prim == _drag_prim) {
2505 sanitize_connections(iter);
2506 get_selection()->select(iter);
2517 auto v = a->get_value() +
delta;
2518 v = std::clamp(v, 0.0, a->get_upper() - a->get_page_size());
2525 if (!(_autoscroll_y || _autoscroll_x))
return true;
2527 auto &scrolled_window =
dynamic_cast<Gtk::ScrolledWindow &
>(*get_parent());
2530 autoscroll(scrolled_window.get_vadjustment(), _autoscroll_y);
2534 autoscroll(scrolled_window.get_hadjustment(), _autoscroll_x);
2543 return _model->children().size();
2550 return _input_type_width + 2;
2554 return _inputs_count;
2558 _inputs_count = count;
2566 static const std::map<EffectCategory, Glib::ustring> category_names = {
2572 return category_names.at(category);
2575struct EffectMetadata {
2576 EffectCategory category;
2577 Glib::ustring icon_name;
2578 Glib::ustring tooltip;
2581static const std::map<Inkscape::Filters::FilterPrimitiveType, EffectMetadata>&
get_effects() {
2582 static std::map<Inkscape::Filters::FilterPrimitiveType, EffectMetadata> effects = {
2584 _(
"Uniformly blurs its input. Commonly used together with Offset to create a drop shadow effect.") }},
2586 _(
"Provides erode and dilate effects. For single-color objects erode makes the object thinner and dilate makes it thicker.") }},
2588 _(
"Offsets the input by an user-defined amount. Commonly used for drop shadow effects.") }},
2590 _(
"Performs a convolution on the input image enabling effects like blur, sharpening, embossing and edge detection.") }},
2592 _(
"Displaces pixels from the first input using the second as a map of displacement intensity. Classical examples are whirl and pinch effects.") }},
2594 _(
"Tiles a region with an input graphic. The source tile is defined by the filter primitive subregion of the input.") }},
2596 _(
"Composites two images using one of the Porter-Duff blending modes or the arithmetic mode described in SVG standard.") }},
2598 _(
"Provides image blending modes, such as screen, multiply, darken and lighten.") }},
2600 _(
"Merges multiple inputs using normal alpha compositing. Equivalent to using several Blend primitives in 'normal' mode or several Composite primitives in 'over' mode.") }},
2602 _(
"Modifies pixel colors based on a transformation matrix. Useful for adjusting color hue and saturation.") }},
2604 _(
"Manipulates color components according to particular transfer functions. Useful for brightness and contrast adjustment, color balance, and thresholding.") }},
2606 _(
"Creates \"embossed\" shadings. The input's alpha channel is used to provide depth information: higher opacity areas are raised toward the viewer and lower opacity areas recede away from the viewer.") }},
2608 _(
"Creates \"embossed\" shadings. The input's alpha channel is used to provide depth information: higher opacity areas are raised toward the viewer and lower opacity areas recede away from the viewer.") }},
2610 _(
"Fills the region with a given color and opacity. Often used as input to other filters to apply color to a graphic.") }},
2612 _(
"Fills the region with graphics from an external file or from another portion of the document.") }},
2614 _(
"Renders Perlin noise, which is useful to generate textures such as clouds, fire, smoke, marble or granite.") }},
2625 Glib::ustring
label;
2627 Glib::ustring icon_name;
2628 Glib::ustring tooltip;
2630 std::vector<Effect> effects;
2636 effect.second.category,
2637 effect.second.icon_name,
2638 effect.second.tooltip
2641 std::sort(begin(effects),
end(effects), [=](
auto&& a,
auto&& b) {
2642 if (a.category != b.category) {
2643 return a.category < b.category;
2645 return a.label < b.label;
2652 for (
auto const &effect : effects) {
2654 auto const &type = effect.type;
2655 auto const menuitem =
builder.add_item(effect.label, effect.category, effect.tooltip,
2656 effect.icon_name,
true,
true,
2658 auto const id =
static_cast<int>(type);
2659 menuitem->signal_query_tooltip().connect([=,
this] (
int x,
int y,
bool kbd,
const Glib::RefPtr<Gtk::Tooltip>& tooltipw) {
2669 menu.add_css_class(
"symbolic");
2676 :
DialogBase(
"/dialogs/filtereffects",
"FilterEffects"),
2682 _search_wide_box(
get_widget<
Gtk::Box>(_builder,
"search-wide")),
2683 _filter_wnd(
get_widget<
Gtk::ScrolledWindow>(_builder,
"filter")),
2684 _cur_filter_btn(
get_widget<
Gtk::CheckButton>(_builder,
"label"))
2686 , _add_primitive(_(
"Add Effect:"))
2687 , _empty_settings(
"",
Gtk::Align::CENTER)
2688 , _no_filter_selected(_(
"No filter selected"),
Gtk::Align::START)
2689 , _settings_initialized(false)
2692 , _filter_modifier(*this, _builder)
2693 , _primitive_list(*this)
2723 get_widget<Gtk::Popover>(
_builder,
"info-popover").signal_show().connect([
this]{
2725 if (prim->getRepr()) {
2726 auto id = FPConverter.get_id_from_key(prim->getRepr()->name());
2727 const auto& effect = get_effects().at(id);
2728 get_widget<Gtk::Image>(_builder,
"effect-icon").set_from_icon_name(effect.icon_name);
2729 auto buffer = get_widget<Gtk::TextView>(_builder,
"effect-info").get_buffer();
2730 buffer->set_text(
"");
2731 buffer->insert_markup(buffer->begin(), effect.tooltip);
2732 get_widget<Gtk::TextView>(_builder,
"effect-desc").get_buffer()->set_text(
"");
2737 _primitive_list.signal_primitive_changed().connect([
this]{ update_settings_view(); });
2739 _cur_filter_toggle = _cur_filter_btn.signal_toggled().connect([
this]{
2740 _filter_modifier.toggle_current_filter();
2743 auto update_checkbox = [
this]{
2744 auto active = _filter_modifier.is_selected_filter_active();
2745 _cur_filter_toggle.block();
2746 _cur_filter_btn.set_active(active);
2747 _cur_filter_toggle.unblock();
2750 auto update_widgets = [=,
this]{
2751 auto& opt = get_widget<Gtk::MenuButton>(_builder,
"filter-opt");
2752 _primitive_list.update();
2754 if (
auto filter = _filter_modifier.get_selected_filter()) {
2756 _effects_popup.set_sensitive();
2757 _cur_filter_btn.set_sensitive();
2758 opt.set_sensitive();
2761 _effects_popup.set_sensitive(
false);
2762 _cur_filter_btn.set_sensitive(
false);
2763 opt.set_sensitive(
false);
2765 get_widget<Gtk::Label>(_builder,
"filter-name").set_label(
name);
2767 update_settings_view();
2774 init_settings_widgets();
2776 _filter_modifier.signal_filter_changed().connect([=](){
2780 _filter_modifier.signal_filters_updated().connect([=](){
2786 sigc::mem_fun(_primitive_list, &PrimitiveList::remove_selected));
2788 get_widget<Gtk::Button>(_builder,
"new-filter").signal_clicked().connect([
this]{ _filter_modifier.add_filter(); });
2790 _bin.set_expand(
true);
2791 _bin.set_child(_popoverbin);
2792 _popoverbin.setChild(&_main_grid);
2794 get_widget<Gtk::Button>(_builder,
"dup-btn").signal_clicked().connect([
this]{ duplicate_primitive(); });
2795 get_widget<Gtk::Button>(_builder,
"del-btn").signal_clicked().connect([
this]{ _primitive_list.remove_selected(); });
2798 _show_sources = &get_widget<Gtk::ToggleButton>(_builder,
"btn-connect");
2799 auto set_inputs = [
this](
bool const all){
2801 _primitive_list.set_inputs_count(count);
2803 _primitive_list.update();
2806 _show_sources->set_active(show_all_sources);
2807 set_inputs(show_all_sources);
2808 _show_sources->signal_toggled().connect([=,
this]{
2809 bool const show_all = _show_sources->get_active();
2810 set_inputs(show_all);
2815 _paned.property_position().signal_changed().connect([
this]{
2819 _primitive_list.update();
2822 Gtk::Requisition minimum_size, natural_size;
2823 get_preferred_size(minimum_size, natural_size);
2824 int min_width = minimum_size.get_width();
2825 _effects_popup.get_preferred_size(minimum_size, natural_size);
2826 auto const min_effects = minimum_size.get_width();
2831 int threshold_width = min_width + min_effects * 3;
2836 _bin.connectBeforeResize([=,
this] (
int width,
int height,
int baseline) {
2839 double const ratio =
width /
static_cast<double>(
height);
2841 constexpr double hysteresis = 0.01;
2842 if (ratio < 1 - hysteresis ||
width <= threshold_width) {
2844 if (!_narrow_dialog) {
2845 _main_grid.remove(_filter_wnd);
2846 _search_wide_box.remove(_effects_popup);
2847 _paned.set_start_child(_filter_wnd);
2849 _paned.set_size_request();
2850 get_widget<Gtk::Box>(_builder,
"connect-box-wide").remove(*_show_sources);
2851 get_widget<Gtk::Box>(_builder,
"connect-box").append(*_show_sources);
2852 _narrow_dialog =
true;
2854 }
else if (ratio > 1 + hysteresis &&
width > threshold_width) {
2856 if (_narrow_dialog) {
2857 _paned.property_start_child().set_value(
nullptr);
2858 _search_box.remove(_effects_popup);
2859 _main_grid.attach(_filter_wnd, 2, 1, 1, 2);
2861 _paned.set_size_request(min_width);
2862 get_widget<Gtk::Box>(_builder,
"connect-box").remove(*_show_sources);
2863 get_widget<Gtk::Box>(_builder,
"connect-box-wide").append(*_show_sources);
2864 _narrow_dialog =
false;
2871 update_settings_view();
2895 if (flags & (SP_OBJECT_MODIFIED_FLAG |
2896 SP_OBJECT_PARENT_MODIFIED_FLAG |
2897 SP_OBJECT_STYLE_MODIFIED_FLAG)) {
2921 _region_pos =
_filter_general_settings->add_multispinbutton( (
double) -0.1, (
double) -0.1,
SPAttr::X,
SPAttr::Y, _(
"Coordinates:"), -100, 100, 0.01, 0.1, 2, _(
"X coordinate of the left corners of filter effects region"), _(
"Y coordinate of the upper corners of filter effects region"));
2922 _region_size =
_filter_general_settings->add_multispinbutton( (
double) 1.2, (
double) 1.2,
SPAttr::WIDTH,
SPAttr::HEIGHT, _(
"Dimensions:"), 0, 1000, 0.01, 0.1, 2, _(
"Width of filter effects region"), _(
"Height of filter effects region"));
2945 _k1 =
_settings->add_spinscale(0,
SPAttr::K1, _(
"K1:"), -10, 10, 0.1, 0.01, 2, _(
"If the arithmetic operation is chosen, each result pixel is computed using the formula k1*i1*i2 + k2*i1 + k3*i2 + k4 where i1 and i2 are the pixel values of the first and second inputs respectively."));
2946 _k2 =
_settings->add_spinscale(0,
SPAttr::K2, _(
"K2:"), -10, 10, 0.1, 0.01, 2, _(
"If the arithmetic operation is chosen, each result pixel is computed using the formula k1*i1*i2 + k2*i1 + k3*i2 + k4 where i1 and i2 are the pixel values of the first and second inputs respectively."));
2947 _k3 =
_settings->add_spinscale(0,
SPAttr::K3, _(
"K3:"), -10, 10, 0.1, 0.01, 2, _(
"If the arithmetic operation is chosen, each result pixel is computed using the formula k1*i1*i2 + k2*i1 + k3*i2 + k4 where i1 and i2 are the pixel values of the first and second inputs respectively."));
2948 _k4 =
_settings->add_spinscale(0,
SPAttr::K4, _(
"K4:"), -10, 10, 0.1, 0.01, 2, _(
"If the arithmetic operation is chosen, each result pixel is computed using the formula k1*i1*i2 + k2*i1 + k3*i2 + k4 where i1 and i2 are the pixel values of the first and second inputs respectively."));
2952 _convolve_target =
_settings->add_multispinbutton( (
double) 0, (
double) 0,
SPAttr::TARGETX,
SPAttr::TARGETY, _(
"Target:"), 0,
max_convolution_kernel_size - 1, 1, 1, 0, _(
"X coordinate of the target point in the convolve matrix. The convolution is applied to pixels around this point."), _(
"Y coordinate of the target point in the convolve matrix. The convolution is applied to pixels around this point."));
2954 _convolve_matrix =
_settings->add_matrix(
SPAttr::KERNELMATRIX, _(
"Kernel:"), _(
"This matrix describes the convolve operation that is applied to the input image in order to calculate the pixel colors at the output. Different arrangements of values in this matrix result in various possible visual effects. An identity matrix would lead to a motion blur effect (parallel to the matrix diagonal) while a matrix filled with a constant non-zero value would lead to a common blur effect."));
2956 _settings->add_spinscale(0,
SPAttr::DIVISOR, _(
"Divisor:"), 0, 1000, 1, 0.1, 2, _(
"After applying the kernelMatrix to the input image to yield a number, that number is divided by divisor to yield the final destination color value. A divisor that is the sum of all the matrix values tends to have an evening effect on the overall color intensity of the result."));
2957 _settings->add_spinscale(0,
SPAttr::BIAS, _(
"Bias:"), -10, 10, 0.1, 0.5, 2, _(
"This value is added to each component. This is useful to define a constant value as the zero response of the filter."));
2959 _settings->add_checkbutton(
false,
SPAttr::PRESERVEALPHA, _(
"Preserve Alpha"),
"true",
"false", _(
"If set, the alpha channel won't be altered by this filter primitive."));
2963 _settings->add_spinscale(1,
SPAttr::SURFACESCALE, _(
"Surface Scale:"), -5, 5, 0.01, 0.001, 3, _(
"This value amplifies the heights of the bump map defined by the input alpha channel"));
2970 _settings->add_spinscale(0,
SPAttr::SCALE, _(
"Scale:"), 0, 100, 1, 0.01, 1, _(
"This defines the intensity of the displacement effect."));
3000 _settings->add_checkbutton(
false,
SPAttr::PRESERVEALPHA, _(
"Preserve Alpha"),
"true",
"false", _(
"If set, the alpha channel won't be altered by this filter primitive."));
3001 _settings->add_spinscale(0,
SPAttr::DX, _(
"Delta X:"), -100, 100, 1, 0.01, 2, _(
"This is how far the input image gets shifted to the right"));
3002 _settings->add_spinscale(0,
SPAttr::DY, _(
"Delta Y:"), -100, 100, 1, 0.01, 2, _(
"This is how far the input image gets shifted downwards"));
3006 _settings->add_spinscale(1,
SPAttr::SURFACESCALE, _(
"Surface Scale:"), -5, 5, 0.1, 0.01, 2, _(
"This value amplifies the heights of the bump map defined by the input alpha channel"));
3026 _settings->add_spinscale(0,
SPAttr::SEED, _(
"Seed:"), 0, 1000, 1, 1, 0, _(
"The starting number for the pseudo random number generator."));
3040 if (
id.has_value()) {
3050 if (filter && origprim) {
3073 double n = g_strtod(text.c_str(),
nullptr);
3074 if (n == 0.0 && strcmp(text.c_str(),
"0") != 0 && strcmp(text.c_str(),
"0.0") != 0) {
3127 if(filter &&
name && o) {
3133 Glib::ustring undokey =
"filtereffects:";
3173 i->set_visible(
false);
3177 auto& header = get_widget<Gtk::Box>(
_builder,
"effect-header");
3181 if (prim && prim->
getRepr()) {
3187 header.set_visible(
true);
3201 header.set_visible(
false);
3218 const bool use_k = is<SPFeComposite>(prim) && cast<SPFeComposite>(prim)->get_composite_operator() ==
COMPOSITE_ARITHMETIC;
3219 _k1->set_sensitive(use_k);
3220 _k2->set_sensitive(use_k);
3221 _k3->set_sensitive(use_k);
3222 _k4->set_sensitive(use_k);
gchar const * sp_attribute_name(SPAttr id)
Get attribute name by id.
@ INVALID
Must have value 0.
Cairo::RefPtr< Cairo::ImageSurface > surface
std::string toString(bool opacity=true) const
Format the color as a css string and return it.
static void done(SPDocument *document, Glib::ustring const &event_description, Glib::ustring const &undo_icon, unsigned int object_modified_tag=0)
static void maybeDone(SPDocument *document, const gchar *keyconst, Glib::ustring const &event_description, Glib::ustring const &undo_icon, unsigned int object_modified_tag=0)
SPGroup * currentRoot() const
Returns current root (=bottom) layer.
SPItemRange items()
Returns a range of selected SPItems.
boost::enable_if< boost::is_base_of< SPObject, T >, void >::type setList(const std::vector< T * > &objs)
Selects exactly the specified objects.
XMLNodeRange xmlNodes()
Returns a range of the xml nodes of all selected objects.
bool isEmpty()
Returns true if no items are selected.
Preference storage class.
bool getBool(Glib::ustring const &pref_path, bool def=false)
Retrieve a Boolean value.
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.
void setInt(Glib::ustring const &pref_path, int value)
Set an integer value.
int getIntLimited(Glib::ustring const &pref_path, int def=0, int min=INT_MIN, int max=INT_MAX)
Retrieve a limited integer.
void setBool(Glib::ustring const &pref_path, bool value)
Set a Boolean value.
The set of selected SPObjects for a given document and layer model.
DialogBase is the base class for the dialog system.
virtual void update()
The update() method is essential to Gtk state management.
SPDocument * getDocument() const
void get_preferred_width_vfunc(Gtk::Widget &widget, int &minimum_width, int &natural_width) const override
void get_preferred_height_for_width_vfunc(Gtk::Widget &widget, int width, int &minimum_height, int &natural_height) const override
void get_preferred_width_for_height_vfunc(Gtk::Widget &widget, int height, int &minimum_width, int &natural_width) const override
void get_preferred_height_vfunc(Gtk::Widget &widget, int &minimum_height, int &natural_height) const override
static constexpr int size_w
Glib::PropertyProxy< void * > property_primitive()
static constexpr int size_h
Gtk::TreeModelColumn< int > count
Gtk::TreeModelColumn< Glib::ustring > label
Gtk::TreeModelColumn< int > sel
void on_name_edited(const Glib::ustring &, const Glib::ustring &)
void on_filter_selection_changed()
void select_filter_elements()
FilterModifier(FilterEffectsDialog &d, Glib::RefPtr< Gtk::Builder > builder)
std::unique_ptr< Inkscape::XML::SignalObserver > _observer
void selection_toggled(Gtk::TreeModel::iterator iter, bool toggle)
bool is_selected_filter_active()
void update_selection(Selection *)
void select_filter(const SPFilter *)
Gtk::EventSequenceState filter_list_click_released(Gtk::GestureClick const &click, int n_press, double x, double y)
Gtk::CellRendererToggle _cell_toggle
bool filters_present() const
std::unique_ptr< UI::Widget::PopoverMenu > create_menu()
SPFilter * get_selected_filter()
void on_selection_toggled(const Glib::ustring &)
Glib::RefPtr< Gtk::ListStore > _filters_model
void toggle_current_filter()
sigc::signal< void()> & signal_filter_changed()
Gtk::TreeModelColumn< Glib::ustring > type
Gtk::TreeModelColumn< SPFilterPrimitive * > primitive
int get_inputs_count() const
void css_changed(GtkCssStyleChange *change) override
Called after gtk_widget_css_changed(): when a CSS widget node is validated & style changed.
int get_input_type_width() const
int find_index(const Gtk::TreeModel::iterator &target)
void select(SPFilterPrimitive *prim)
PrimitiveList(FilterEffectsDialog &)
void set_menu(sigc::slot< void()> dup, sigc::slot< void()> rem)
bool do_connection_node(const Gtk::TreeModel::iterator &row, const int input, std::vector< Geom::Point > &points, const int ix, const int iy)
sigc::signal< void()> & signal_primitive_changed()
void on_drag_end(Glib::RefPtr< Gdk::Drag > const &drag, bool delete_data)
int primitive_count() const
void on_motion_motion(double x, double y)
void sanitize_connections(const Gtk::TreeModel::iterator &prim_iter)
PrimitiveColumns _columns
std::unique_ptr< Inkscape::XML::SignalObserver > _observer
Gtk::EventSequenceState on_click_released(Gtk::GestureClick const &click, int n_press, double x, double y)
void set_inputs_count(int count)
Gtk::EventSequenceState on_click_pressed(Gtk::GestureClick const &click, int n_press, double x, double y)
SPFilterPrimitive * get_selected()
const Gtk::TreeModel::iterator find_result(const Gtk::TreeModel::iterator &start, const SPAttr attr, int &src_id, const int pos)
Glib::RefPtr< Gtk::ListStore > _model
void draw_connection(const Cairo::RefPtr< Cairo::Context > &cr, const Gtk::TreeModel::iterator &, const SPAttr attr, const int text_start_x, const int x1, const int y1, const int row_count, const int pos, const Gdk::RGBA fg_color, const Gdk::RGBA mid_color)
CellRendererConnection _connection_cell
void snapshot_vfunc(Glib::RefPtr< Gtk::Snapshot > const &snapshot) override
void on_primitive_selection_changed()
void set_attr(SPObject *, const SPAttr, const gchar *val)
~FilterEffectsDialog() override
Gtk::Box _settings_filter
void update_color_matrix()
std::unique_ptr< Settings > _filter_general_settings
FilterModifier _filter_modifier
void selectionModified(Inkscape::Selection *selection, guint flags) override
Gtk::ScrolledWindow * _primitive_box
Gtk::Label * _cur_effect_name
Glib::RefPtr< Gtk::Builder > _builder
void set_filternode_attr(const UI::Widget::AttrWidget *)
std::unique_ptr< Settings > _settings
void update_settings_view()
Gtk::Label _empty_settings
void update_filter_general_settings_view()
void documentReplaced() override
void set_attrs_locked(const bool)
void set_attr_direct(const UI::Widget::AttrWidget *)
void add_filter_primitive(Filters::FilterPrimitiveType type)
Gtk::Label _no_filter_selected
void set_child_attr_direct(const UI::Widget::AttrWidget *)
UI::Widget::ComboBoxEnum< Inkscape::Filters::FilterPrimitiveType > _add_primitive_type
void selectionChanged(Inkscape::Selection *selection) override
void convolve_order_changed()
friend class FileOrElementChooser
MultiSpinButton * _region_pos
void duplicate_primitive()
PrimitiveList _primitive_list
void add_effects(Inkscape::UI::Widget::CompletionPopup &popup, bool symbolic)
Gtk::Box _settings_effect
DualSpinButton * _convolve_order
MultiSpinButton * _convolve_target
void init_settings_widgets()
void update_automatic_region(Gtk::CheckButton *btn)
MultiSpinButton * _region_size
bool _settings_initialized
void update_settings_sensitivity()
ColorMatrixValues * _color_matrix_values
MatrixAttr * _convolve_matrix
sigc::scoped_connection _resource_changed
Inkscape::UI::Widget::CompletionPopup _effects_popup
Simplified management of enumerations of svg items with UI labels.
E get_id_from_key(const Glib::ustring &key) const
const Glib::ustring & get_label(const E id) const
Interface for refcounted XML nodes.
virtual Node * parent()=0
Get the parent of this node.
virtual void setPosition(int pos)=0
Set the position of this node in parent's child order.
virtual void appendChild(Node *child)=0
Append a node as the last child of this node.
virtual char const * name() const =0
Get the name of the element node.
void setAttributeOrRemoveIfEmpty(Inkscape::Util::const_char_ptr key, Inkscape::Util::const_char_ptr value)
Change an attribute of this node.
void setAttribute(Util::const_char_ptr key, Util::const_char_ptr value)
Change an attribute of this node.
virtual Node * duplicate(Document *doc) const =0
Create a duplicate of this node.
virtual char const * attribute(char const *key) const =0
Get the string representation of a node's attribute.
virtual bool matchAttributeName(char const *partial_name) const =0
Check whether this node has any attribute that matches a string.
virtual Document * document()=0
Get the node's associated document.
To do: update description of desktop.
SPDocument * getDocument() const
Inkscape::Selection * getSelection() const
Inkscape::LayerManager & layerManager()
Typed SVG document implementation.
sigc::connection connectResourcesChanged(char const *key, SPDocument::ResourcesChangedSignal::slot_type slot)
std::vector< SPObject * > const getResourceList(char const *key)
Inkscape::XML::Document * getReprDoc()
Our Inkscape::XML::Document.
SPObject * getObjectByRepr(Inkscape::XML::Node *repr) const
void set(SPAttr key, char const *value) override
SPFilter * getObject() const
unsigned getRefCount()
Returns the number of references to the filter.
bool valid_for(SPObject const *obj) const
Checks each filter primitive to make sure the object won't cause issues.
Filter type internal to SPStyle.
Base class for visual SVG elements.
SPObject is an abstract base class of all of the document nodes at the SVG document level.
char const * label() const
Gets the author-visible label property for the object or a default if no label is defined.
void setAttributeOrRemoveIfEmpty(Inkscape::Util::const_char_ptr key, Inkscape::Util::const_char_ptr value)
void setAttribute(Inkscape::Util::const_char_ptr key, Inkscape::Util::const_char_ptr value)
void requestModified(unsigned int flags)
Requests that a modification notification signal be emitted later (e.g.
void removeAttribute(char const *key)
char const * getId() const
Returns the objects current ID string.
SPStyle * style
Represents the style properties, whether from presentation attributes, the style attribute,...
void setLabel(char const *label)
Sets the author-visible label for this object.
Inkscape::XML::Node * getRepr()
Returns the XML representation of tree.
void requestDisplayUpdate(unsigned int flags)
Queues an deferred update of this object's display.
T< SPAttr::FILTER, SPIFilter > filter
Filter effect.
Color picker button and window.
SVG color matrix filter effect.
SVG <filter> implementation, see sp-filter.cpp.
SVG component transferfilter effect.
Utilities to more easily use Gtk::EventController & subclasses like Gesture.
SVG matrix convolution filter effect.
Editable view implementation.
static char const *const parent
@ DISPLACEMENTMAP_CHANNEL_ALPHA
SVG <filter> implementation, see sp-filter.cpp.
TODO: insert short description here.
void remove_filter(SPObject *item, bool recursive)
SPFilterPrimitive * filter_add_primitive(SPFilter *filter, const Inkscape::Filters::FilterPrimitiveType type)
SPFilter * new_filter(SPDocument *document)
const EnumDataConverter< FeCompositeOperator > CompositeOperatorConverter(CompositeOperatorData, COMPOSITE_ENDOPERATOR)
const EnumDataConverter< LightSource > LightSourceConverter(LightSourceData, LIGHT_ENDSOURCE)
const EnumDataConverter< Inkscape::Filters::FilterComponentTransferType > ComponentTransferTypeConverter(ComponentTransferTypeData, Inkscape::Filters::COMPONENTTRANSFER_TYPE_ERROR)
const EnumDataConverter< FilterDisplacementMapChannelSelector > DisplacementMapChannelConverter(DisplacementMapChannelData, DISPLACEMENTMAP_CHANNEL_ENDTYPE)
const EnumDataConverter< Inkscape::Filters::FilterConvolveMatrixEdgeMode > ConvolveMatrixEdgeModeConverter(ConvolveMatrixEdgeModeData, Inkscape::Filters::CONVOLVEMATRIX_EDGEMODE_ENDTYPE)
const EnumDataConverter< FilterPrimitiveInput > FPInputConverter(FPInputData, FPINPUT_END)
const EnumDataConverter< Inkscape::Filters::FilterColorMatrixType > ColorMatrixTypeConverter(ColorMatrixTypeData, Inkscape::Filters::COLORMATRIX_ENDTYPE)
const EnumDataConverter< Inkscape::Filters::FilterTurbulenceType > TurbulenceTypeConverter(TurbulenceTypeData, Inkscape::Filters::TURBULENCE_ENDTYPE)
const EnumDataConverter< Inkscape::Filters::FilterPrimitiveType > FPConverter(FPData, Inkscape::Filters::NR_FILTER_ENDPRIMITIVETYPE)
const EnumDataConverter< Inkscape::Filters::FilterMorphologyOperator > MorphologyOperatorConverter(MorphologyOperatorData, Inkscape::Filters::MORPHOLOGY_OPERATOR_END)
Util::TreeifyResult const & _tree
Macro for icon names used in Inkscape.
std::unique_ptr< Magick::Image > image
Inkscape::XML::Node * node
Inkscape - An SVG editor.
feMergeNode implementation.
Align
Values for the <align> parameter of preserveAspectRatio.
@ MORPHOLOGY_OPERATOR_ERODE
@ NR_FILTER_COMPONENTTRANSFER
@ NR_FILTER_DISPLACEMENTMAP
@ NR_FILTER_SPECULARLIGHTING
@ NR_FILTER_DIFFUSELIGHTING
@ NR_FILTER_CONVOLVEMATRIX
@ NR_FILTER_ENDPRIMITIVETYPE
@ COMPONENTTRANSFER_TYPE_GAMMA
@ COMPONENTTRANSFER_TYPE_TABLE
@ COMPONENTTRANSFER_TYPE_LINEAR
@ COMPONENTTRANSFER_TYPE_ERROR
@ COMPONENTTRANSFER_TYPE_DISCRETE
@ COLORMATRIX_LUMINANCETOALPHA
@ CONVOLVEMATRIX_EDGEMODE_NONE
static R & release(R &r)
Decrements the reference count of a anchored object.
auto use_state(Slot &&slot)
const Glib::ustring & get_category_name(EffectCategory category)
static auto get_cell_area(Gtk::TreeView const &tree_view, Gtk::TreeModel::Path const &path, Gtk::TreeViewColumn &column)
void get_start_directory(std::string &start_path, Glib::ustring const &prefs_path, bool try_document_dir)
Find the start directory for a file dialog.
Glib::RefPtr< Gio::ListStore< Gtk::FileFilter > > create_open_filters()
Create a Gtk::FileFilter for all image file types.
constexpr int max_convolution_kernel_size
static Glib::ustring get_filter_name(SPFilter *filter)
static std::pair< int, int > widget_to_bin_window(Gtk::TreeView const &tree_view, int const wx, int const wy)
void draw_connection_node(const Cairo::RefPtr< Cairo::Context > &cr, std::vector< Geom::Point > const &points, Gdk::RGBA const &fill, Gdk::RGBA const &stroke)
static std::unique_ptr< UI::Widget::PopoverMenu > create_popup_menu(Gtk::Widget &parent, sigc::slot< void()> dup, sigc::slot< void()> rem)
static int input_count(const SPFilterPrimitive *prim)
static void check_single_connection(SPFilterPrimitive *prim, const int result)
static const std::map< Inkscape::Filters::FilterPrimitiveType, EffectMetadata > & get_effects()
static Glib::ustring const prefs_path
static void autoscroll(Glib::RefPtr< Gtk::Adjustment > const &a, double const delta)
bool number_or_empy(const Glib::ustring &text)
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.
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)
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)
GType type()
Returns the type used for storing an object of type T inside a value.
Helper class to stream background task notifications as a series of messages.
static void append(std::vector< T > &target, std::vector< T > &&source)
const Util::EnumDataConverter< SPBlendMode > SPBlendModeConverter
Glib::RefPtr< Gio::File > choose_file_open(Glib::ustring const &title, Gtk::Window *parent, Glib::RefPtr< Gio::ListStore< Gtk::FileFilter > > const &filters_model, std::string ¤t_folder, Glib::ustring const &accept)
Synchronously run a Gtk::FileDialog to open a single file for reading data.
TODO: insert short description here.
Helpers for using Gtk::Boxes, encapsulating large changes between GTK3 & GTK4.
SVG <filter> implementation, see sp-filter.cpp.
Singleton class to access the preferences file in a convenient way.
void sp_repr_unparent(Inkscape::XML::Node *repr)
Remove repr from children of its parent node.
std::vector< SPItem * > get_all_items(SPObject *from, SPDesktop *desktop, bool onlyvisible, bool onlysensitive, bool ingroups, std::vector< SPItem * > const &exclude)
Derived from and replaces SpinSlider.
SVG <filter> implementation, see sp-filter.cpp.
Interface for XML documents.
virtual Node * createElement(char const *name)=0
void sp_style_set_property_url(SPObject *item, gchar const *property, SPObject *linked, bool recursive)
SPStyle - a style object for SPItem objects.
Glib::RefPtr< Gtk::Builder > builder
Gdk::RGBA get_color_with_class(Gtk::Widget &widget, Glib::ustring const &css_class)
Gdk::RGBA change_alpha(const Gdk::RGBA &color, double new_alpha)
Gdk::RGBA mix_colors(const Gdk::RGBA &a, const Gdk::RGBA &b, float ratio)