Inkscape
Vector Graphics Editor
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages Concepts
extensions-gallery.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
2
4
5#include <algorithm>
6#include <cmath>
7#include <gdkmm/paintable.h>
8#include <gdkmm/texture.h>
9#include <giomm/liststore.h>
10#include <glibmm/objectbase.h>
11#include <gtkmm/boolfilter.h>
12#include <gtkmm/centerbox.h>
13#include <gtkmm/filter.h>
14#include <gtkmm/filterlistmodel.h>
15#include <gtkmm/fixed.h>
16#include <gtkmm/grid.h>
17#include <gtkmm/gridview.h>
18#include <gtkmm/listitemfactory.h>
19#include <gtkmm/object.h>
20#include <gtkmm/overlay.h>
21#include <gtkmm/picture.h>
22#include <gtkmm/scrollinfo.h>
23#include <gtkmm/signallistitemfactory.h>
24#include <gtkmm/singleselection.h>
25#include <gtkmm/tooltip.h>
26#include <gtkmm/widgetpaintable.h>
27#include <initializer_list>
28#include <iterator>
29#include <list>
30#include <memory>
31#include <set>
32#include <sstream>
33#include <string>
34#include <utility>
35#include <2geom/point.h>
36#include <2geom/rect.h>
37#include <cairo.h>
38#include <glibmm/markup.h>
39#include <gtkmm/adjustment.h>
40#include <gtkmm/box.h>
41#include <gtkmm/button.h>
42#include <gtkmm/enums.h>
43#include <gtkmm/iconview.h>
44#include <gtkmm/label.h>
45#include <gtkmm/liststore.h>
46#include <gtkmm/paned.h>
47#include <gtkmm/scale.h>
48#include <gtkmm/searchentry2.h>
49#include <gtkmm/togglebutton.h>
50#include <gtkmm/treemodelfilter.h>
51#include <gtkmm/treemodelsort.h>
52#include <gtkmm/treeview.h>
53#include <libintl.h>
54
55#include "document.h"
56#include "preferences.h"
57
58#include "display/cairo-utils.h"
59#include "extension/db.h"
60#include "extension/effect.h"
61#include "io/file.h"
62#include "io/resource.h"
63#include "io/sys.h"
64#include "object/sp-item.h"
65#include "ui/builder-utils.h"
67#include "ui/svg-renderer.h"
68#include "ui/util.h"
69
70namespace Inkscape::UI::Dialog {
71
72struct EffectItem : public Glib::Object {
73 std::string id; // extension ID
74 Glib::ustring name; // effect's name (translated)
75 Glib::ustring tooltip; // menu tip if present, access path otherwise (translated)
76 Glib::ustring description; // short description (filters have one; translated)
77 Glib::ustring access; // menu access path (translated)
78 Glib::ustring order; // string to sort items (translated)
79 Glib::ustring category; // category (from menu item; translated)
81 std::string icon; // path to effect's SVG icon file
82
83 static Glib::RefPtr<EffectItem> create(
84 std::string id,
85 Glib::ustring name,
86 Glib::ustring tooltip,
87 Glib::ustring description,
88 Glib::ustring access,
89 Glib::ustring order,
90 Glib::ustring category,
92 std::string icon
93 ) {
94 auto item = Glib::make_refptr_for_instance<EffectItem>(new EffectItem());
95 item->id = id;
96 item->name = name;
97 item->tooltip = tooltip;
98 item->description = description;
99 item->access = access;
100 item->order = order;
101 item->category = category;
102 item->effect = effect;
103 item->icon = icon;
104 return item;
105 }
106};
107
108struct CategoriesColumns : public Gtk::TreeModel::ColumnRecord {
109 Gtk::TreeModelColumn<Glib::ustring> id;
110 Gtk::TreeModelColumn<Glib::ustring> name;
111
112 CategoriesColumns() {
113 add(id);
114 add(name);
115 }
117
118
119Cairo::RefPtr<Cairo::Surface> add_shadow(Geom::Point image_size, Cairo::RefPtr<Cairo::Surface> image, int device_scale) {
120 if (!image) return {};
121
122 auto w = image_size.x();
123 auto h = image_size.y();
124 auto margin = 6;
125 auto width = w + 2 * margin;
126 auto height = h + 2 * margin;
127 auto rect = Geom::Rect::from_xywh(margin, margin, w, h);
128
129 auto surface = Cairo::ImageSurface::create(Cairo::Surface::Format::ARGB32, width * device_scale, height * device_scale);
130 cairo_surface_set_device_scale(surface->cobj(), device_scale, device_scale);
131 auto ctx = Cairo::Context::create(surface);
132
133 // transparent background
134 ctx->rectangle(0, 0, width, height);
135 ctx->set_source_rgba(1, 1, 1, 0);
136 ctx->fill();
137
138 // white image background
139 ctx->rectangle(margin, margin, w, h);
140 ctx->set_source_rgba(1, 1, 1, 1);
141 ctx->fill();
142
143 // image (centered)
144 auto imgw = cairo_image_surface_get_width(image->cobj()) / device_scale;
145 auto imgh = cairo_image_surface_get_height(image->cobj()) / device_scale;
146 auto cx = floor(margin + (w - imgw) / 2.0);
147 auto cy = floor(margin + (h - imgh) / 2.0);
148 ctx->set_source(image, cx, cy);
149 ctx->paint();
150
151 // drop shadow
152 auto black = 0x000000;
153 ink_cairo_draw_drop_shadow(ctx, rect, margin, black, 0.30);
154
155 return surface;
156}
157
158const std::vector<Inkscape::Extension::Effect*> prepare_effects(const std::vector<Inkscape::Extension::Effect*>& effects, bool get_effects) {
159 std::vector<Inkscape::Extension::Effect*> out;
160
161 std::copy_if(effects.begin(), effects.end(), std::back_inserter(out), [=](auto effect) {
162 if (effect->hidden_from_menu()) return false;
163
164 return effect->is_filter_effect() != get_effects;
165 });
166
167 return out;
168}
169
170Glib::ustring get_category(const std::list<Glib::ustring>& menu) {
171 if (menu.empty()) return {};
172
173 // effect's category; for filters it is always right, but effect extensions may be nested, so this is just a first level group
174 return menu.front();
175}
176
177Cairo::RefPtr<Cairo::Surface> render_icon(Extension::Effect* effect, std::string icon, Geom::Point icon_size, int device_scale) {
178 Cairo::RefPtr<Cairo::Surface> image;
179
180 if (icon.empty() || !IO::file_test(icon.c_str(), G_FILE_TEST_EXISTS)) {
181 // placeholder
182 image = Cairo::ImageSurface::create(Cairo::Surface::Format::ARGB32, icon_size.x(), icon_size.y());
183 cairo_surface_set_device_scale(image->cobj(), device_scale, device_scale);
184 }
185 else {
186 // render icon
187 try {
188 auto file = Gio::File::create_for_path(icon);
189 auto doc = ink_file_open(file).first;
190 if (!doc) return image;
191
192 if (auto item = cast<SPItem>(doc->getObjectById("test-object"))) {
193 effect->apply_filter(item);
194 }
195 svg_renderer r(*doc);
196 auto w = r.get_width_px();
197 auto h = r.get_height_px();
198 if (w > 0 && h > 0) {
199 auto scale = std::max(w / icon_size.x(), h / icon_size.y());
200 r.set_scale(1 / scale);
201 }
202 image = r.render_surface(device_scale);
203 }
204 catch (...) {
205 g_warning("Cannot render icon for effect %s", effect->get_id());
206 }
207 }
208
209 image = add_shadow(icon_size, image, device_scale);
210
211 return image;
212}
213
214void add_effects(Gio::ListStore<EffectItem>& item_store, const std::vector<Inkscape::Extension::Effect*>& effects, bool root) {
215 for (auto& effect : effects) {
216 const auto id = effect->get_sanitized_id();
217
218 std::string name = effect->get_name();
219 // remove ellipsis and mnemonics
220 auto pos = name.find("...", 0);
221 if (pos != std::string::npos) {
222 name.erase(pos, 3);
223 }
224 pos = name.find("…", 0);
225 if (pos != std::string::npos) {
226 name.erase(pos, 1);
227 }
228 pos = name.find("_", 0);
229 if (pos != std::string::npos) {
230 name.erase(pos, 1);
231 }
232
233 std::ostringstream order;
234 std::ostringstream access;
235 auto menu = effect->get_menu_list();
236 for (auto& part : menu) {
237 order << part.raw() << '\n'; // effect sorting order
238 access << part.raw() << " \u25b8 "; // right pointing triangle; what about translations and RTL languages?
239 }
240 access << name;
241 order << name;
242 auto translated = [](const char* text) { return *text ? gettext(text) : ""; };
243 auto description = effect->get_menu_tip();
244
246 auto icon = effect->find_icon_file(dir);
247
248 if (icon.empty()) {
249 // fallback image
250 icon = Inkscape::IO::Resource::get_path_string(IO::Resource::SYSTEM, IO::Resource::UIS, "resources", root ? "missing-icon.svg" : "filter-test.svg");
251 }
252
253 auto tooltip = "<small>" + access.str() + "</small>";
254 if (!description.empty()) {
255 tooltip += "\n\n";
256 tooltip += translated(description.c_str());
257 }
258
259 item_store.append(EffectItem::create(
260 id,
261 name,
262 std::move(tooltip),
263 translated(description.c_str()),
264 access.str(),
265 order.str(),
266 get_category(menu),
267 effect,
268 icon
269 ));
270 }
271
272 item_store.sort([](auto& a, auto& b) { return a->order.compare(b->order); });
273}
274
275std::set<std::string> add_categories(Glib::RefPtr<Gtk::ListStore>& store, const std::vector<Inkscape::Extension::Effect*>& effects, bool effect) {
276 std::set<std::string> categories;
277
278 // collect categories
279 for (auto& effect : effects) {
280 auto menu = effect->get_menu_list();
281 auto category = get_category(menu);
282 if (!category.empty()) {
283 categories.insert(category);
284 }
285 }
286
287 auto row = *store->append();
288 row[g_categories_columns.id] = "all";
289 row[g_categories_columns.name] = effect ? _("All Effects") : _("All Filters");
290
291 row = *store->append();
292 row[g_categories_columns.id] = "-";
293
294 for (auto cat : categories) {
295 auto row = *store->append();
296 row[g_categories_columns.id] = cat;
297 row[g_categories_columns.name] = cat;
298 }
299
300 return categories;
301}
302
304 DialogBase(type == Effects ? "/dialogs/extensions-gallery/effects" : "/dialogs/extensions-gallery/filters",
305 type == Effects ? "ExtensionsGallery" : "FilterGallery"),
306 _builder(create_builder("dialog-extensions.glade")),
307 _gridview(get_widget<Gtk::GridView>(_builder, "grid")),
308 _search(get_widget<Gtk::SearchEntry2>(_builder, "search")),
309 _run(get_widget<Gtk::Button>(_builder, "run")),
310 _run_btn_label(get_widget<Gtk::Label>(_builder, "run-label")),
311 _selector(get_widget<Gtk::TreeView>(_builder, "selector")),
312 _image_cache(1000), // arbitrary limit for how many rendered thumbnails to keep around
313 _type(type)
314{
316 _run_btn_label.get_label() :
317 C_("apply-filter", "_Apply");
318
319 auto& header = get_widget<Gtk::Label>(_builder, "header");
320 header.set_label(_type == Effects ?
321 _("Select extension to run:") :
322 _("Select filter to apply:"));
323
324 auto prefs = Preferences::get();
325 // last selected effect
326 auto selected = prefs->getString(_prefs_path + "/selected");
327 // selected category
328 _current_category = prefs->getString(_prefs_path + "/category", "all");
329 auto show_list = prefs->getBool(_prefs_path + "/show-list", true);
330 auto position = prefs->getIntLimited(_prefs_path + "/position", 120, 10, 1000);
331
332 auto paned = &get_widget<Gtk::Paned>(_builder, "paned");
333 auto show_categories_list = [=](bool show){
334 paned->get_start_child()->set_visible(show);
335 };
336 paned->set_position(position);
337 paned->property_position().signal_changed().connect([paned, prefs, this](){
338 if (auto const w = paned->get_start_child()) {
339 if (w->is_visible()) prefs->setInt(_prefs_path + "/position", paned->get_position());
340 }
341 });
342
343 // show/hide categories
344 auto toggle = &get_widget<Gtk::ToggleButton>(_builder, "toggle");
345 toggle->set_tooltip_text(_type == Effects ?
346 _("Toggle list of effect categories") :
347 _("Toggle list of filter categories"));
348 toggle->set_active(show_list);
349 toggle->signal_toggled().connect([=, this](){
350 auto visible = toggle->get_active();
351 show_categories_list(visible);
352 if (!visible) show_category("all"); // don't leave hidden category selection filter active
353 });
354 show_categories_list(show_list);
355
356 _categories = get_object<Gtk::ListStore>(_builder, "categories-store");
357 _selector.set_row_separator_func([=](auto&, auto& it) {
358 Glib::ustring id;
359 it->get_value(g_categories_columns.id.index(), id);
360 return id == "-";
361 });
362
364 _filter = Gtk::BoolFilter::create({});
365 _filtered_model = Gtk::FilterListModel::create(store, _filter);
366
367 auto effects = prepare_effects(Inkscape::Extension::db.get_effect_list(), _type == Effects);
368
369 add_effects(*store, effects, _type == Effects);
370
371 auto categories = add_categories(_categories, effects, _type == Effects);
372 if (!categories.count(_current_category.raw())) {
373 _current_category = "all";
374 }
375 _selector.set_model(_categories);
376
377 _page_selection = _selector.get_selection();
378 _selection_change = _page_selection->signal_changed().connect([this](){
379 if (auto it = _page_selection->get_selected()) {
380 Glib::ustring id;
381 it->get_value(g_categories_columns.id.index(), id);
382 show_category(id);
383 }
384 });
385
386 _selection_model = Gtk::SingleSelection::create(_filtered_model);
387
389 auto effect = std::dynamic_pointer_cast<EffectItem>(ptr);
390 if (!effect) return {};
391
392 auto tex = get_image(effect->id, effect->icon, effect->effect);
393 auto name = Glib::Markup::escape_text(effect->name);
394 return { .label_markup = name, .image = tex, .tooltip = effect->tooltip };
395 });
396 _factory->set_use_tooltip_markup();
397 _gridview.set_min_columns(1);
398 // max columns impacts number of prerendered items requested by gridview (= maxcol * 32 + 1),
399 // so it needs to be artificially kept low to prevent gridview from rendering all items up front
400 _gridview.set_max_columns(5);
401 // gtk_list_base_set_anchor_max_widgets(0); - private method, no way to customize prerender items number
402 _gridview.set_model(_selection_model);
403 _gridview.set_factory(_factory->get_factory());
404 // handle item activation (double-click)
405 _gridview.signal_activate().connect([this](auto pos){
406 _run.activate_action(_run.get_action_name());
407 });
408 _gridview.set_single_click_activate(false);
409
410 _search.signal_search_changed().connect([this](){
411 refilter();
412 });
413
414 _selection_model->signal_selection_changed().connect([this](auto first, auto count) {
415 update_name();
416 });
417
418 // restore last selected category
419 _categories->foreach([this](const auto& path, const auto&it) {
420 Glib::ustring id;
421 it->get_value(g_categories_columns.id.index(), id);
422
423 if (id.raw() == _current_category.raw()) {
424 _page_selection->select(path);
425 return true;
426 }
427 return false;
428 });
429
430 // restore thumbnail size
431 auto adj = get_object<Gtk::Adjustment>(_builder, "adjustment-thumbnails");
432 _thumb_size_index = prefs->getIntLimited(_prefs_path + "/tile-size", 6, adj->get_lower(), adj->get_upper());
433 auto scale = &get_widget<Gtk::Scale>(_builder, "thumb-size");
434 scale->set_value(_thumb_size_index);
435
436 // populate filtered model
437 refilter();
438
439 // initial selection
440 _selection_model->select_item(0, true);
441
442 // restore selection: last used extension
443 if (!selected.empty()) {
444 const auto N = _filtered_model->get_n_items();
445 for (int pos = 0; pos < N; ++pos) {
446 auto item = _filtered_model->get_typed_object<EffectItem>(pos);
447 if (!item) continue;
448
449 if (item->id == selected.raw()) {
450 _selection_model->select_item(pos, true);
451 //TODO: it's too early for scrolling to work (?)
452 auto scroll = Gtk::ScrollInfo::create();
453 scroll->set_enable_vertical();
454 _gridview.scroll_to(pos, Gtk::ListScrollFlags::NONE, scroll);
455 break;
456 }
457 }
458 }
459
460 update_name();
461
462 scale->signal_value_changed().connect([scale, prefs, this](){
463 _thumb_size_index = scale->get_value();
464 rebuild();
465 prefs->setInt(_prefs_path + "/tile-size", _thumb_size_index);
466 });
467
468 append(get_widget<Gtk::Box>(_builder, "main"));
469}
470
472 auto& label = get_widget<Gtk::Label>(_builder, "name");
473 auto& info = get_widget<Gtk::Label>(_builder, "info");
474
475 auto item = _selection_model->get_selected_item();
476 if (auto effect = std::dynamic_pointer_cast<EffectItem>(item)) {
477 // access path - where to find it in the main menu
478 label.set_label(effect->access);
479 label.set_tooltip_text(effect->access);
480
481 // set action name
482 _run.set_action_name("app." + effect->id);
483 _run.set_sensitive();
484 // add ellipsis if extension takes input
485 auto& effect_obj = *effect->effect;
486 _run_btn_label.set_label(_run_label + (effect_obj.takes_input() ? C_("take-input", "...") : ""));
487 // info: extension description, if any
488 Glib::ustring desc = effect->description;
489 info.set_markup("<i>" + Glib::Markup::escape_text(desc) + "</i>");
490 info.set_tooltip_text(desc);
491
492 auto prefs = Inkscape::Preferences::get();
493 prefs->setString(_prefs_path + "/selected", effect->id);
494 }
495 else {
496 label.set_label("");
497 label.set_tooltip_text("");
498 info.set_text("");
499 info.set_tooltip_text("");
500 _run_btn_label.set_label(_run_label);
501 _run.set_sensitive(false);
502 }
503}
504
505void ExtensionsGallery::show_category(const Glib::ustring& id) {
506 if (_current_category.raw() == id.raw()) return;
507
509
510 auto prefs = Preferences::get();
511 prefs->setString(_prefs_path + "/category", id);
512
513 refilter();
514}
515
516bool ExtensionsGallery::is_item_visible(const Glib::RefPtr<Glib::ObjectBase>& item) const {
517 auto effect_ptr = std::dynamic_pointer_cast<EffectItem>(item);
518 if (!effect_ptr) return false;
519
520 const auto& effect = *effect_ptr;
521
522 // filter by category
523 if (_current_category != "all") {
524 if (_current_category.raw() != effect.category.raw()) return false;
525 }
526
527 // filter by name
528 auto str = _search.get_text().lowercase();
529 if (str.empty()) return true;
530
531 Glib::ustring text = effect.access;
532 return text.lowercase().find(str) != Glib::ustring::npos;
533}
534
536 // When a new expression is set in the BoolFilter, it emits signal_changed(),
537 // and the FilterListModel re-evaluates the filter.
538 auto expression = Gtk::ClosureExpression<bool>::create([this](auto& item){ return is_item_visible(item); });
539 // filter results
540 _filter->set_expression(expression);
541}
542
544 // empty cache, so item will get re-rendered at new size
545 _image_cache.clear();
546 // remove all
547 auto none = Gtk::ClosureExpression<bool>::create([this](auto& item){ return false; });
548 _filter->set_expression(none);
549 // restore
550 refilter();
551}
552
554 auto effects = type == ExtensionsGallery::Effects;
555 // effect icons range of sizes starts smaller, while filter icons benefit from larger sizes
556 int min_size = effects ? 35 : 50;
557 const double factor = std::pow(2.0, 1.0 / 6.0);
558 // thumbnail size: starting from min_size and growing exponentially
559 auto size = std::round(std::pow(factor, index) * min_size);
560
561 auto icon_size = Geom::Point(size, size);
562 if (effects) {
563 // effects icons have a 70x60 size ratio
564 auto height = std::round(size * 6.0 / 7.0);
565 icon_size = Geom::Point(size, height);
566 }
567 return icon_size;
568}
569
570Glib::RefPtr<Gdk::Texture> ExtensionsGallery::get_image(const std::string& key, const std::string& icon, Extension::Effect* effect) {
571 if (auto image = _image_cache.get(key)) {
572 // cache hit
573 return *image;
574 }
575 else {
576 // render
577 auto icon_size = get_thumbnail_size(_thumb_size_index, _type);
578 auto surface = render_icon(effect, icon, icon_size, get_scale_factor());
579 auto tex = to_texture(surface);
580 _image_cache.insert(key, tex);
581 return tex;
582 }
583}
584
585} // namespace Inkscape::UI::Dialog
Cartesian point / 2D vector and related operations.
double scale
Definition aa.cpp:228
Gtk builder utilities.
void ink_cairo_draw_drop_shadow(const Cairo::RefPtr< Cairo::Context > &ctx, const Geom::Rect &rect, double size, guint32 color, double color_alpha)
Draw drop shadow around the 'rect' with given 'size' and 'color'; shadow extends to the right and bot...
Cairo integration helpers.
Cairo::RefPtr< Cairo::ImageSurface > surface
Definition canvas.cpp:137
Geom::IntRect visible
Definition canvas.cpp:154
Fragment store
Definition canvas.cpp:155
int margin
Definition canvas.cpp:166
static CRect from_xywh(Coord x, Coord y, Coord w, Coord h)
Create rectangle from origin and dimensions.
Two-dimensional point that doubles as a vector.
Definition point.h:66
constexpr Coord y() const noexcept
Definition point.h:106
constexpr Coord x() const noexcept
Definition point.h:104
Effects are extensions that take a document and do something to it in place.
Definition effect.h:39
std::string find_icon_file(const std::string &default_dir) const
Definition effect.cpp:314
const Glib::ustring & get_menu_tip() const
Definition effect.cpp:359
bool apply_filter(SPItem *item)
Definition effect.cpp:374
std::string get_sanitized_id() const
Sanitizes the id and returns.
Definition effect.cpp:114
std::list< Glib::ustring > get_menu_list() const
Definition effect.cpp:363
void effect(SPDesktop *desktop, SPDocument *document=nullptr)
The function that 'does' the effect itself.
Definition effect.cpp:233
char const * get_name() const
Get the name of this extension - not a copy don't delete!
char const * get_id() const
Get the ID of this extension - not a copy don't delete!
static Preferences * get()
Access the singleton Preferences object.
DialogBase is the base class for the dialog system.
Definition dialog-base.h:41
Glib::ustring const _prefs_path
Definition dialog-base.h:86
Glib::RefPtr< Gtk::BoolFilter > _filter
Glib::RefPtr< Gtk::FilterListModel > _filtered_model
std::unique_ptr< IconViewItemFactory > _factory
boost::compute::detail::lru_cache< std::string, Glib::RefPtr< Gdk::Texture > > _image_cache
Glib::RefPtr< Gtk::SingleSelection > _selection_model
Glib::RefPtr< Gtk::ListStore > _categories
Glib::RefPtr< Gdk::Texture > get_image(const std::string &key, const std::string &icon, Extension::Effect *effect)
Glib::RefPtr< Gtk::Builder > _builder
bool is_item_visible(const Glib::RefPtr< Glib::ObjectBase > &item) const
void show_category(const Glib::ustring &id)
Glib::RefPtr< Gtk::TreeSelection > _page_selection
static std::unique_ptr< IconViewItemFactory > create(std::function< ItemData(Glib::RefPtr< Glib::ObjectBase > &)> get_item)
double get_width_px() const
void set_scale(double scale)
double get_height_px() const
Cairo::RefPtr< Cairo::ImageSurface > render_surface(double scale)
virtual char * description() const
Definition sp-item.cpp:1176
char * id
Definition sp-object.h:192
const double w
Definition conic-4.cpp:19
RootCluster root
A base class for all dialogs.
const unsigned order
auto floor(Geom::Rect const &rect)
Definition geom.h:130
std::unique_ptr< Magick::Image > image
SPItem * item
std::unique_ptr< SPDocument > ink_file_open(std::span< char const > buffer)
Open a document from memory.
Definition file.cpp:73
Glib::ustring label
Definition desktop.h:50
DB db
This is the actual database object.
Definition db.cpp:32
Util::ptr_shared get_path(Domain domain, Type type, char const *filename, char const *extra)
Definition resource.cpp:137
std::string get_path_string(Domain domain, Type type, char const *filename, char const *extra)
Definition resource.cpp:148
bool file_test(char const *utf8name, GFileTest test)
Definition sys.cpp:116
Dialog code.
Definition desktop.h:117
Inkscape::UI::Dialog::CategoriesColumns g_categories_columns
Geom::Point get_thumbnail_size(int index, ExtensionsGallery::Type type)
Cairo::RefPtr< Cairo::Surface > add_shadow(Geom::Point image_size, Cairo::RefPtr< Cairo::Surface > image, int device_scale)
static const std::map< Inkscape::Filters::FilterPrimitiveType, EffectMetadata > & get_effects()
const std::vector< Inkscape::Extension::Effect * > prepare_effects(const std::vector< Inkscape::Extension::Effect * > &effects, bool get_effects)
Cairo::RefPtr< Cairo::Surface > render_icon(Extension::Effect *effect, std::string icon, Geom::Point icon_size, int device_scale)
Glib::ustring get_category(const std::list< Glib::ustring > &menu)
void add_effects(Gio::ListStore< EffectItem > &item_store, const std::vector< Inkscape::Extension::Effect * > &effects, bool root)
std::set< std::string > add_categories(Glib::RefPtr< Gtk::ListStore > &store, const std::vector< Inkscape::Extension::Effect * > &effects, bool effect)
static constexpr int height
W & get_widget(const Glib::RefPtr< Gtk::Builder > &builder, const char *id)
Glib::RefPtr< Gtk::Builder > create_builder(const char *filename)
static void append(std::vector< T > &target, std::vector< T > &&source)
static std::string _run(char const *command)
Wrapper around g_spawn_sync which captures STDOUT and strips trailing whitespace.
static cairo_user_data_key_t key
Singleton class to access the preferences file in a convenient way.
Axis-aligned rectangle.
Inkscape::IO::Resource - simple resource API.
size_t N
Some things pertinent to all visible shapes: SPItem, SPItemView, SPItemCtx.
int index
double width
std::unique_ptr< Toolbar >(* create)()
Definition toolbars.cpp:56
Glib::ustring name
Definition toolbars.cpp:55
Glib::RefPtr< Gdk::Texture > to_texture(Cairo::RefPtr< Cairo::Surface > const &surface)
Convert an image surface in ARGB32 format to a texture.
Definition util.cpp:495