Inkscape
Vector Graphics Editor
All Classes Namespaces Files Functions Variables Typedefs Enumerations Enumerator Friends Modules Pages Concepts
gradient-editor.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
13#include "gradient-editor.h"
14
15#include <array>
16#include <initializer_list>
17#include <utility>
18#include <2geom/point.h>
19#include <2geom/line.h>
20#include <2geom/transforms.h>
21#include <cairo.h>
22#include <glibmm/i18n.h>
23#include <gtkmm/adjustment.h>
24#include <gtkmm/builder.h>
25#include <gtkmm/button.h>
26#include <gtkmm/expander.h>
27#include <gtkmm/grid.h>
28#include <gtkmm/grid.h>
29#include <gtkmm/image.h>
30#include <gtkmm/liststore.h>
31#include <gtkmm/menubutton.h>
32#include <gtkmm/spinbutton.h>
33#include <gtkmm/togglebutton.h>
34#include <gtkmm/treeview.h>
35#include <sigc++/adaptors/bind.h>
36#include <sigc++/functors/mem_fun.h>
37
38#include "document-undo.h"
39#include "gradient-chemistry.h"
40#include "gradient-selector.h"
41#include "preferences.h"
42#include "display/cairo-utils.h"
43#include "io/resource.h"
47#include "ui/builder-utils.h"
48#include "ui/icon-loader.h"
49#include "ui/icon-names.h"
54
55namespace Inkscape::UI::Widget {
56
57using namespace Inkscape::IO;
59
60class scope {
61public:
62 scope(bool& flag): _flag(flag) {
63 flag = true;
64 }
65
66 ~scope() {
67 _flag = false;
68 }
69
70private:
71 bool& _flag;
72};
73
74void set_icon(Gtk::Button &btn, char const *pixmap)
75{
76 btn.set_image_from_icon_name(pixmap, Gtk::IconSize::NORMAL);
77}
78
79// draw solid color circle with black outline; right side is to show checkerboard if color's alpha is > 0
80Glib::RefPtr<Gdk::Pixbuf> draw_circle(int size, Colors::Color color) {
81 int width = size;
82 int height = size;
83 gint w2 = width / 2;
84
85 cairo_surface_t* s = cairo_image_surface_create(CAIRO_FORMAT_ARGB32, width, height);
86 cairo_t* cr = cairo_create(s);
87
88 int x = 0, y = 0;
89 double radius = size / 2;
90 double degrees = M_PI / 180.0;
91 cairo_new_sub_path(cr);
92 cairo_arc(cr, x + radius, y + radius, radius, 0, 2 * M_PI);
93 cairo_close_path(cr);
94 // semi-transparent black outline
95 cairo_set_source_rgba(cr, 0, 0, 0, 0.2);
96 cairo_fill(cr);
97
98 radius--;
99
100 cairo_new_sub_path(cr);
101 cairo_line_to(cr, x + w2, 0);
102 cairo_line_to(cr, x + w2, height);
103 cairo_arc(cr, x + w2, y + w2, radius, 90 * degrees, 270 * degrees);
104 cairo_close_path(cr);
105
106 // solid part
107 auto opacity = color.stealOpacity();
109 cairo_fill(cr);
110
111 x = w2;
112
113 cairo_new_sub_path(cr);
114 cairo_arc(cr, x, y + w2, radius, -90 * degrees, 90 * degrees);
115 cairo_line_to(cr, x, y);
116 cairo_close_path(cr);
117
118 // (semi)transparent part
119 if (opacity < 1.0) {
121 cairo_set_source(cr, checkers);
122 cairo_fill_preserve(cr);
123 cairo_pattern_destroy(checkers);
124 }
125 color.addOpacity(opacity);
127 cairo_fill(cr);
128
129 cairo_destroy(cr);
130 cairo_surface_flush(s);
131
133 return Glib::wrap(pixbuf);
134}
135
136
137Glib::RefPtr<Gdk::Pixbuf> get_stop_pixmap(SPStop* stop) {
138 const int size = 30;
139 return draw_circle(size, stop->getColor());
140}
141
143 const char* ico = "";
144 switch (mode) {
146 ico = "gradient-spread-pad";
147 break;
149 ico = "gradient-spread-repeat";
150 break;
152 ico = "gradient-spread-reflect";
153 break;
154 default:
155 g_warning("Missing case in %s\n", __func__);
156 break;
157 }
158 return ico;
159}
160
162 _builder(Inkscape::UI::create_builder("gradient-edit.glade")),
163 _selector(Gtk::make_managed<GradientSelector>()),
164 _colors(new Colors::ColorSet()),
165 _repeat_popover{std::make_unique<UI::Widget::PopoverMenu>(Gtk::PositionType::BOTTOM)},
166 _repeat_icon(get_widget<Gtk::Image>(_builder, "repeatIco")),
167 _stop_tree(get_widget<Gtk::TreeView>(_builder, "stopList")),
168 _offset_btn(get_widget<Gtk::SpinButton>(_builder, "offsetSpin")),
169 _show_stops_list(get_widget<Gtk::Expander>(_builder, "stopsBtn")),
170 _add_stop(get_widget<Gtk::Button>(_builder, "stopAdd")),
171 _delete_stop(get_widget<Gtk::Button>(_builder, "stopDelete")),
172 _stops_gallery(get_widget<Gtk::Box>(_builder, "stopsGallery")),
173 _colors_box(get_widget<Gtk::Box>(_builder, "colorsBox")),
174 _linear_btn(get_widget<Gtk::ToggleButton>(_builder, "linearBtn")),
175 _radial_btn(get_widget<Gtk::ToggleButton>(_builder, "radialBtn")),
176 _turn_gradient(get_widget<Gtk::Button>(_builder, "turnBtn")),
177 _angle_adj(get_object<Gtk::Adjustment>(_builder, "adjustmentAngle")),
178 _main_grid(get_widget<Gtk::Grid>(_builder, "mainGrid")),
179 _prefs(prefs)
180{
181 // gradient type buttons; not currently used, hidden, WIP
182 set_icon(_linear_btn, INKSCAPE_ICON("paint-gradient-linear"));
183 set_icon(_radial_btn, INKSCAPE_ICON("paint-gradient-radial"));
184
185 auto& reverse = get_widget<Gtk::Button>(_builder, "reverseBtn");
186 set_icon(reverse, INKSCAPE_ICON("object-flip-horizontal"));
187 reverse.signal_clicked().connect([this](){ reverse_gradient(); });
188
189 set_icon(_turn_gradient, INKSCAPE_ICON("object-rotate-right"));
190 _turn_gradient.signal_clicked().connect([this](){ turn_gradient(90, true); });
191 _angle_adj->signal_value_changed().connect([this](){
192 turn_gradient(_angle_adj->get_value(), false);
193 });
194
195 auto& gradBox = get_widget<Gtk::Box>(_builder, "gradientBox");
196 const int dot_size = 8;
197 _gradient_image.set_visible(true);
198 _gradient_image.set_margin_start(dot_size / 2);
199 _gradient_image.set_margin_end(dot_size / 2);
200 // gradient stop selected in a gradient widget; sync list selection
201 _gradient_image.signal_stop_selected().connect([this](size_t index) {
204 });
205 _gradient_image.signal_stop_offset_changed().connect([this](size_t index, double offset) {
207 });
208 _gradient_image.signal_add_stop_at().connect([this](double offset) {
210 });
211 _gradient_image.signal_delete_stop().connect([this](size_t index) {
213 });
214 gradBox.append(_gradient_image);
215
216 // add color selector
217 auto const color_selector = Gtk::make_managed<ColorNotebook>(_colors);
218 color_selector->set_label(_("Stop color"));
219 color_selector->set_visible(true);
220 _colors_box.append(*color_selector);
221
222 // gradient library in a popup
223 get_widget<Gtk::Popover>(_builder, "libraryPopover").set_child(*_selector);
224 const int h = 5;
225 const int v = 3;
226 _selector->set_margin_start(h);
227 _selector->set_margin_end(h);
228 _selector->set_margin_top(v);
229 _selector->set_margin_bottom(v);
230 _selector->set_visible(true);
234 // gradient changed is currently the only signal that GradientSelector can emit:
235 _selector->signal_changed().connect([this](SPGradient* gradient) {
236 // new gradient selected from the library
237 _signal_changed.emit(gradient);
238 });
239
240 // construct store for a list of stops
245 _stop_list_store = Gtk::ListStore::create(_stop_columns);
246 _stop_tree.set_model(_stop_list_store);
247 // indices in the stop list view; currently hidden
248 // _stop_tree.append_column("n", _stopID); // 1-based stop index
249 _stop_tree.append_column("c", _stop_color); // and its color
250
251 auto selection = _stop_tree.get_selection();
252 selection->signal_changed().connect([this]() {
253 if (!_update.pending()) {
254 stop_selected();
255 fire_stop_selected(get_current_stop());
256 }
257 });
258
259 _show_stops_list.property_expanded().signal_changed().connect(
260 [&](){ show_stops(_show_stops_list.get_expanded()); }
261 );
262
263 set_icon(_add_stop, "list-add");
264 _add_stop.signal_clicked().connect([this](){
265 if (auto row = current_stop()) {
266 auto index = row->get_value(_stopIdx);
267 add_stop(static_cast<int>(index));
268 }
269 });
270
271 set_icon(_delete_stop, "list-remove");
272 _delete_stop.signal_clicked().connect([this]() {
273 if (auto row = current_stop()) {
274 auto index = row->get_value(_stopIdx);
275 delete_stop(static_cast<int>(index));
276 }
277 });
278
279 // connect gradient repeat modes menu
280 static auto const repeats = std::to_array({std::pair
281 {SP_GRADIENT_SPREAD_PAD , _("None" )},
282 {SP_GRADIENT_SPREAD_REPEAT , _("Direct" )},
283 {SP_GRADIENT_SPREAD_REFLECT, _("Reflected")}
284 });
285 for (auto const &[mode, text] : repeats) {
286 auto const icon = get_repeat_icon(mode);
287 auto const item = Gtk::make_managed<UI::Widget::PopoverMenuItem>(text, false, icon);
288 item->signal_activate().connect(sigc::bind(sigc::mem_fun(
290 _repeat_popover->append(*item);
291 }
292 get_widget<Gtk::MenuButton>(_builder, "repeatMode").set_popover(*_repeat_popover);
294
295 _colors->signal_changed.connect([this]() {
296 set_stop_color(_colors->getAverage());
297 });
298
299 _offset_btn.signal_changed().connect([this]() {
300 if (auto row = current_stop()) {
301 auto index = row->get_value(_stopIdx);
302 double offset = _offset_btn.get_value();
304 }
305 });
306
308
309 // restore visibility of the stop list view
313}
314
317
319{
320 if (_update.pending()) return;
321
323 if (!vector) return;
324
325 if (auto row = current_stop()) {
326 auto index = row->get_value(_stopIdx);
327 SPStop* stop = sp_get_nth_stop(vector, index);
328 if (stop && _document) {
329 auto scoped(_update.block());
330
331 // update list view too
332 row->set_value(_stop_color, get_stop_pixmap(stop));
333
335 }
336 }
337}
338
339std::optional<Gtk::TreeRow> GradientEditor::current_stop() {
340 auto sel = _stop_tree.get_selection();
341 auto it = sel->get_selected();
342 if (!it) {
343 return std::nullopt;
344 }
345 else {
346 return *it;
347 }
348}
349
351 if (SPGradient* vector = get_gradient_vector()) {
352 return sp_get_nth_stop(vector, index);
353 }
354 return nullptr;
355}
356
357// stop has been selected in a list view
359 _colors->clear();
360 if (auto row = current_stop()) {
361 SPStop* stop = row->get_value(_stopObj);
362 if (stop) {
363 auto scoped(_update.block());
364
365 _colors->set(stop->getId(), stop->getColor());
366
367 auto stops = sp_get_before_after_stops(stop);
368 if (stops.first && stops.second) {
369 _offset_btn.set_range(stops.first->offset, stops.second->offset);
370 }
371 else {
372 _offset_btn.set_range(stops.first ? stops.first->offset : 0, stops.second ? stops.second->offset : 1);
373 }
374 _offset_btn.set_sensitive();
375 _offset_btn.set_value(stop->offset);
376
377 int index = row->get_value(_stopIdx);
379 }
380 }
381 else {
382 // no selection
383 auto scoped(_update.block());
384 _offset_btn.set_range(0, 0);
385 _offset_btn.set_value(0);
386 _offset_btn.set_sensitive(false);
387 }
388}
389
391 if (SPGradient* vector = get_gradient_vector()) {
392 // only insert new stop if there are some stops present
393 if (vector->hasStops()) {
394 SPStop* stop = sp_gradient_add_stop_at(vector, offset);
395 // just select next stop; newly added stop will be in a list view after selection refresh (on idle)
396 auto pos = sp_number_of_stops_before_stop(vector, stop);
397 auto selected = select_stop(pos);
398 fire_stop_selected(stop);
399 if (!selected) {
400 select_stop(pos);
401 }
402 }
403 }
404}
405
407 if (SPGradient* vector = get_gradient_vector()) {
408 if (SPStop* current = sp_get_nth_stop(vector, index)) {
409 SPStop* stop = sp_gradient_add_stop(vector, current);
410 // just select next stop; newly added stop will be in a list view after selection refresh (on idle)
412 fire_stop_selected(stop);
413 }
414 }
415}
416
418 if (SPGradient* vector = get_gradient_vector()) {
419 if (SPStop* stop = sp_get_nth_stop(vector, index)) {
420 // try deleting a stop, if it can be
421 sp_gradient_delete_stop(vector, stop);
422 }
423 }
424}
425
426// collapse/expand list of stops in the UI
432
435 _stops_gallery.set_visible(true);
436 }
437 else {
438 _stops_gallery.set_visible(false);
439 }
440}
441
442double line_angle(const Geom::Line& line) {
443 auto d = line.finalPoint() - line.initialPoint();
444 return std::atan2(d.y(), d.x());
445}
446
447// turn linear gradient 90 degrees
448void GradientEditor::turn_gradient(double angle, bool relative) {
449 if (_update.pending() || !_document || !_gradient) return;
450
451 if (auto linear = cast<SPLinearGradient>(_gradient)) {
452 auto scoped(_update.block());
453
454 auto line = Geom::Line(
455 Geom::Point(linear->x1.computed, linear->y1.computed),
456 Geom::Point(linear->x2.computed, linear->y2.computed)
457 );
458 auto center = line.pointAt(0.5);
459 auto radians = angle / 180 * M_PI;
460 if (!relative) {
461 radians -= line_angle(line);
462 }
463 auto rotate = Geom::Translate(-center) * Geom::Rotate(radians) * Geom::Translate(center);
464 auto rotated = line.transformed(rotate);
465
466 linear->x1 = rotated.initialPoint().x();
467 linear->y1 = rotated.initialPoint().y();
468 linear->x2 = rotated.finalPoint().x();
469 linear->y2 = rotated.finalPoint().y();
470
472
473 DocumentUndo::done(_document, _("Rotate gradient"), INKSCAPE_ICON("color-gradient"));
474 }
475}
476
478 if (_document && _gradient) {
479 // reverse works on a gradient definition, the one with stops:
481
482 if (vector) {
484 DocumentUndo::done(_document, _("Reverse gradient"), INKSCAPE_ICON("color-gradient"));
485 }
486 }
487}
488
490 if (_update.pending()) return;
491
492 if (_document && _gradient) {
493 auto scoped(_update.block());
494
495 // spread is set on a gradient reference, which is _gradient object
498
499 DocumentUndo::done(_document, _("Set gradient repeat"), INKSCAPE_ICON("color-gradient"));
500
502 }
503}
504
506 auto ico = get_repeat_icon(mode);
507 if (!ico.empty()) {
508 _repeat_icon.set_from_icon_name(ico);
509 }
510}
511
513 auto scoped(_update.block());
514 auto scoped2(_notification.block());
515 _gradient = gradient;
516 _document = gradient ? gradient->document : nullptr;
517 set_gradient(gradient);
518}
519
523
525 auto scoped(_update.block());
526 _selector->setVector(doc, vector);
527}
528
532
536
540
544
548
550 if (_notification.pending()) return;
551
552 auto scoped(_notification.block());
553 // request from the outside to sync stop selection
554 const auto& items = _stop_tree.get_model()->children();
555 auto it = std::find_if(items.begin(), items.end(), [selected, this](const auto& row) {
556 SPStop* stop = row.get_value(_stopObj);
557 return stop == selected;
558 });
559 if (it != items.end()) {
560 select_stop(std::distance(items.begin(), it));
561 }
562}
563
568
570 auto scoped(_update.block());
571
572 // remember which stop is selected, so we can restore it
573 size_t selected_stop_index = 0;
574 if (auto it = _stop_tree.get_selection()->get_selected()) {
575 selected_stop_index = it->get_value(_stopIdx);
576 }
577
578 _stop_list_store->clear();
579
580 SPGradient* vector = gradient ? gradient->getVector() : nullptr;
581
582 if (vector) {
583 vector->ensureVector();
584 }
585
587
588 if (!vector || !vector->hasStops()) return;
589
590 size_t index = 0;
591 for (auto& child : vector->children) {
592 if (is<SPStop>(&child)) {
593 auto stop = cast<SPStop>(&child);
594 auto it = _stop_list_store->append();
595 it->set_value(_stopObj, stop);
596 it->set_value(_stopIdx, index);
597 it->set_value(_stopID, Glib::ustring::compose("%1.", index + 1));
598 it->set_value(_stop_color, get_stop_pixmap(stop));
599
600 ++index;
601 }
602 }
603
604 auto mode = gradient->isSpreadSet() ? gradient->getSpread() : SP_GRADIENT_SPREAD_PAD;
606
607 auto can_rotate = false;
608 // only linear gradient can be rotated currently
609 if (auto linear = cast<SPLinearGradient>(gradient)) {
610 can_rotate = true;
611 auto line = Geom::Line(
612 Geom::Point(linear->x1.computed, linear->y1.computed),
613 Geom::Point(linear->x2.computed, linear->y2.computed)
614 );
615 auto angle = line_angle(line) * 180 / M_PI;
616 _angle_adj->set_value(angle);
617 }
618 _turn_gradient.set_sensitive(can_rotate);
619 get_widget<Gtk::SpinButton>(_builder, "angle").set_sensitive(can_rotate);
620 get_widget<Gtk::Scale>(_builder, "angleSlider").set_sensitive(can_rotate);
621
622 // list not empty?
623 if (index > 0) {
624 select_stop(std::min(selected_stop_index, index - 1));
625 // update related widgets
627 //
628 // emit_stop_selected(get_current_stop());
629 }
630}
631
633 if (_update.pending()) return;
634
635 // adjust stop's offset after user edits it in offset spin button or drags stop handle
636 SPStop* stop = get_nth_stop(index);
637 if (stop) {
638 auto scoped(_update.block());
639
640 stop->offset = offset;
641 if (auto repr = stop->getRepr()) {
642 repr->setAttributeCssDouble("offset", stop->offset);
643 }
644
645 DocumentUndo::maybeDone(stop->document, "gradient:stop:offset", _("Change gradient stop offset"), INKSCAPE_ICON("color-gradient"));
646 }
647}
648
649// select requested stop in a list view
651 if (!_gradient) return false;
652
653 bool selected = false;
654 const auto& items = _stop_tree.get_model()->children();
655 if (index < items.size()) {
656 auto it = items.begin();
657 std::advance(it, index);
658 auto path = _stop_tree.get_model()->get_path(it);
659 _stop_tree.get_selection()->select(it);
660 _stop_tree.scroll_to_cell(path, *_stop_tree.get_column(0));
661 selected = true;
662 }
663
664 return selected;
665}
666
668 if (auto row = current_stop()) {
669 SPStop* stop = row->get_value(_stopObj);
670 return stop;
671 }
672 return nullptr;
673}
674
676 if (!_notification.pending()) {
677 auto scoped(_notification.block());
678 emit_stop_selected(stop);
679 }
680}
681
682} // namespace Inkscape::UI::Widget
683
684/*
685 Local Variables:
686 mode:c++
687 c-file-style:"stroustrup"
688 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
689 indent-tabs-mode:nil
690 fill-column:99
691 End:
692*/
693// vim:filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99:
Cartesian point / 2D vector and related operations.
Gtk builder utilities.
void ink_cairo_set_source_color(Cairo::RefPtr< Cairo::Context > ctx, Inkscape::Colors::Color const &color, double opacity)
The following functions interact between Inkscape color model, and cairo surface rendering.
cairo_pattern_t * ink_cairo_pattern_create_checkerboard(guint32 rgba, bool use_alpha)
GdkPixbuf * ink_pixbuf_create_from_cairo_surface(cairo_surface_t *s)
Converts the Cairo surface to a GdkPixbuf pixel format, without allocating extra memory.
Cairo integration helpers.
struct _GdkPixbuf GdkPixbuf
Definition cairo-utils.h:20
Geom::IntRect visible
Definition canvas.cpp:154
Infinite line on a plane.
Definition line.h:53
Point finalPoint() const
Definition line.h:228
Point initialPoint() const
Definition line.h:225
Two-dimensional point that doubles as a vector.
Definition point.h:66
Rotation around the origin.
Definition transforms.h:187
Translation by a vector.
Definition transforms.h:115
double stealOpacity()
Get the opacity, and remove it from this color.
Definition color.cpp:411
bool addOpacity(double opacity=1.0)
Definition color.h:56
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)
bool getBool(Glib::ustring const &pref_path, bool def=false)
Retrieve a Boolean value.
static Preferences * get()
Access the singleton Preferences object.
void setBool(Glib::ustring const &pref_path, bool value)
Set a Boolean value.
std::optional< Gtk::TreeRow > current_stop()
Glib::RefPtr< Gtk::Builder > _builder
void setMode(SelectorMode mode) final
std::shared_ptr< Colors::ColorSet > _colors
Gtk::TreeModelColumn< SPStop * > _stopObj
Glib::RefPtr< Gtk::Adjustment > _angle_adj
Gtk::TreeModelColumn< Glib::ustring > _stopID
void setVector(SPDocument *doc, SPGradient *vector) final
void setSpread(SPGradientSpread spread) final
Gtk::TreeModelColumnRecord _stop_columns
void setUnits(SPGradientUnits units) final
Gtk::TreeModelColumn< Glib::RefPtr< Gdk::Pixbuf > > _stop_color
void set_repeat_mode(SPGradientSpread mode)
Gtk::TreeModelColumn< size_t > _stopIdx
void selectStop(SPStop *selected) final
void turn_gradient(double angle, bool relative)
Glib::RefPtr< Gtk::ListStore > _stop_list_store
void set_repeat_icon(SPGradientSpread mode)
void setGradient(SPGradient *gradient) final
sigc::signal< void(SPGradient *)> _signal_changed
void set_gradient(SPGradient *gradient)
void set_stop_offset(size_t index, double offset)
void set_stop_color(Colors::Color const &color)
std::unique_ptr< UI::Widget::PopoverMenu > _repeat_popover
void setSpread(SPGradientSpread spread) override
void setVector(SPDocument *doc, SPGradient *vector) override
void setUnits(SPGradientUnits units) override
void set_gradient_size(int width, int height)
void setMode(SelectorMode mode) override
decltype(_signal_changed) signal_changed() const
sigc::signal< void(size_t, double)> & signal_stop_offset_changed()
sigc::signal< void(double)> & signal_add_stop_at()
sigc::signal< void(size_t)> & signal_delete_stop()
sigc::signal< void(size_t)> & signal_stop_selected()
A replacement for GTK3ʼs Gtk::Menu, as removed in GTK4.
SpinButton widget, that allows entry of simple math expressions (also units, when linked with UnitMen...
Definition spinbutton.h:52
scoped_block block()
Typed SVG document implementation.
Definition document.h:102
Gradient.
Definition sp-gradient.h:86
SPGradientSpread getSpread() const
bool hasStops() const
bool isSpreadSet() const
SPGradient * getVector(bool force_private=false)
Returns private vector of given gradient (the gradient at the end of the href chain which has stops),...
void setSpread(SPGradientSpread spread)
Set spread property of gradient and emit modified.
void ensureVector()
Forces vector to be built, if not present (i.e.
SPDocument * document
Definition sp-object.h:188
char const * getId() const
Returns the objects current ID string.
Inkscape::XML::Node * updateRepr(unsigned int flags=SP_OBJECT_WRITE_EXT)
Updates the object's repr based on the object's state.
Inkscape::XML::Node * getRepr()
Returns the XML representation of tree.
ChildrenList children
Definition sp-object.h:907
Gradient stop.
Definition sp-stop.h:31
float offset
Definition sp-stop.h:38
Inkscape::Colors::Color getColor() const
Definition sp-stop.cpp:130
A notebook with RGB, CMYK, CMS, HSL, and Wheel pages.
TODO: insert short description here.
static char const *const current
Definition dir-util.cpp:71
TODO: insert short description here.
_cairo_pattern cairo_pattern_t
struct _cairo_surface cairo_surface_t
std::pair< SPStop *, SPStop * > sp_get_before_after_stops(SPStop *stop)
SPStop * sp_get_nth_stop(SPGradient *gradient, guint index)
void sp_set_gradient_stop_color(SPDocument *document, SPStop *stop, Color const &color)
void sp_gradient_reverse_vector(SPGradient *gradient)
SPStop * sp_gradient_add_stop_at(SPGradient *gradient, double offset)
SPStop * sp_gradient_add_stop(SPGradient *gradient, SPStop *current)
void sp_gradient_delete_stop(SPGradient *gradient, SPStop *stop)
SPGradient * sp_gradient_get_forked_vector_if_necessary(SPGradient *gradient, bool force_vector)
Obtain the vector from the gradient.
guint sp_number_of_stops_before_stop(SPGradient *gradient, SPStop *target)
Gradient vector and position widget.
Icon Loader.
Macro for icon names used in Inkscape.
SPItem * item
Infinite straight line.
double offset
Definition desktop.h:50
Low-level IO code.
Custom widgets.
Definition desktop.h:126
void set_icon(Gtk::Button &btn, char const *pixmap)
double line_angle(const Geom::Line &line)
static constexpr int height
Glib::ustring get_repeat_icon(SPGradientSpread mode)
Glib::RefPtr< Gdk::Pixbuf > get_stop_pixmap(SPStop *stop)
Glib::RefPtr< Gdk::Pixbuf > draw_circle(int size, Colors::Color color)
Glib::RefPtr< Ob > get_object(Glib::RefPtr< Gtk::Builder > const &builder, char const *id)
W & get_widget(const Glib::RefPtr< Gtk::Builder > &builder, const char *id)
Glib::RefPtr< Gtk::Builder > create_builder(const char *filename)
Helper class to stream background task notifications as a series of messages.
static void append(std::vector< T > &target, std::vector< T > &&source)
STL namespace.
int mode
void cairo_line_to(cairo_t *cr, Geom::Point p1)
struct _cairo cairo_t
Definition path-cairo.h:16
A replacement for GTK3ʼs Gtk::MenuItem, as removed in GTK4.
A replacement for GTK3ʼs Gtk::Menu, as removed in GTK4.
Singleton class to access the preferences file in a convenient way.
Ocnode * child[8]
Definition quantize.cpp:33
Inkscape::IO::Resource - simple resource API.
Linear linear(double ax, double b)
GList * items
SPGradientSpread
@ SP_GRADIENT_SPREAD_PAD
@ SP_GRADIENT_SPREAD_REPEAT
@ SP_GRADIENT_SPREAD_REFLECT
SPGradientUnits
TODO: insert short description here.
TODO: insert short description here.
int index
double width
void cairo_set_source_rgba(cairo_t *cr, colour c)
Affine transformation classes.