Inkscape
Vector Graphics Editor
style-swatch.cpp
Go to the documentation of this file.
1// SPDX-License-Identifier: GPL-2.0-or-later
6/* Authors:
7 * buliabyak@gmail.com
8 * Krzysztof Kosiński <tweenk.pl@gmail.com>
9 *
10 * Copyright (C) 2005-2008 Authors
11 *
12 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
13 */
14
15#include "style-swatch.h"
16
17#include <functional>
18#include <utility>
19#include <glibmm/i18n.h>
20#include <gtkmm/grid.h>
21#include <sigc++/adaptors/bind.h>
22#include <sigc++/functors/mem_fun.h>
23
24#include "style.h"
25
26#include "actions/actions-tools.h" // Open tool preferences.
29#include "object/sp-pattern.h"
31#include "ui/controller.h"
32#include "ui/pack.h"
33#include "ui/util.h"
35#include "util/units.h"
36#include "xml/sp-css-attr.h"
37
38static constexpr int STYLE_SWATCH_WIDTH = 135;
39
40enum {
43};
44
45namespace Inkscape::UI::Widget {
46
50void style_obs_callback(StyleSwatch &_style_swatch, Preferences::Entry const &val)
51{
53 _style_swatch.setStyle(css);
55}
56
60void tool_obs_callback(StyleSwatch &_style_swatch, Preferences::Entry const &val)
61{
62 auto const prefs = Preferences::get();
63 Glib::ustring path;
64 SPCSSAttr *css = nullptr;
65
66 bool usecurrent = val.getBool();
67 if (usecurrent) {
68 path = "/desktop/style";
69 css = prefs->getStyle(path);
70 const auto &al = css->attributeList();
71 if (al.empty()) {
72 // Fallback to own style if desktop style empty (does this ever happen?).
74 css = nullptr;
75 }
76 }
77
78 if (!css) {
79 path = _style_swatch._tool_path + "/style";
80 css = prefs->getInheritedStyle(path);
81 }
82
83 // Set style at least once.
84 _style_swatch.setStyle(css);
86
87 auto callback = sigc::bind<0>(&style_obs_callback, std::ref(_style_swatch));
88 _style_swatch._style_obs = StyleSwatch::PrefObs::create(std::move(path), std::move(callback));
89}
90
91StyleSwatch::StyleSwatch(SPCSSAttr *css, gchar const *main_tip, Gtk::Orientation orient)
92 : Gtk::Box(Gtk::Orientation::HORIZONTAL),
93 _desktop(nullptr),
94 _css(nullptr),
95 _table(Gtk::make_managed<Gtk::Grid>()),
96 _sw_unit(nullptr),
97 _stroke(Gtk::Orientation::HORIZONTAL)
98{
99 set_name("StyleSwatch");
100 _label[SS_FILL].set_markup(_("Fill:"));
101 _label[SS_STROKE].set_markup(_("Stroke:"));
102
103 for (int i = SS_FILL; i <= SS_STROKE; i++) {
104 _label[i].set_halign(Gtk::Align::START);
105 _label[i].set_valign(Gtk::Align::CENTER);
106 _label[i].set_margin_top(0);
107 _label[i].set_margin_bottom(0);
108 _label[i].set_margin_start(0);
109 _label[i].set_margin_end(0);
110
111 _color_preview[i] = std::make_unique<ColorPreview>(0);
112 }
113
114 _opacity_value.set_halign(Gtk::Align::START);
115 _opacity_value.set_valign(Gtk::Align::CENTER);
116 _opacity_value.set_margin_top(0);
117 _opacity_value.set_margin_bottom(0);
118 _opacity_value.set_margin_start(0);
119 _opacity_value.set_margin_end(0);
120
121 _table->set_column_spacing(2);
122 _table->set_row_spacing(0);
123
124 // We let pack()ed children expand but donʼt propagate expand upwards.
125 set_hexpand(false);
126 _stroke.set_hexpand(false);
127
130
131 if (orient == Gtk::Orientation::VERTICAL) {
132 _table->attach(_label[SS_FILL], 0, 0, 1, 1);
133 _table->attach(_label[SS_STROKE], 0, 1, 1, 1);
134 _table->attach(_place[SS_FILL], 1, 0, 1, 1);
135 _table->attach(_stroke, 1, 1, 1, 1);
136 _table->attach(_empty_space, 2, 0, 1, 2);
137 _table->attach(_opacity_value, 2, 0, 1, 2);
138 UI::pack_start(*this, *_table, true, true);
139
140 set_size_request (STYLE_SWATCH_WIDTH, -1);
141 }
142 else {
143 _table->set_column_spacing(4);
144 _table->attach(_label[SS_FILL], 0, 0, 1, 1);
145 _table->attach(_place[SS_FILL], 1, 0, 1, 1);
146 _label[SS_STROKE].set_margin_start(6);
147 _table->attach(_label[SS_STROKE], 2, 0, 1, 1);
148 _table->attach(_stroke, 3, 0, 1, 1);
149 _opacity_value.set_margin_start(6);
150 _table->attach(_opacity_value, 4, 0, 1, 1);
151 UI::pack_start(*this, *_table, true, true);
152
153 int patch_w = 6 * 6;
154 _place[SS_FILL].set_size_request(patch_w, -1);
155 _place[SS_STROKE].set_size_request(patch_w, -1);
156 }
157
158 setStyle (css);
159
160 Controller::add_click(*_table, sigc::mem_fun(*this, &StyleSwatch::on_click));
161
162 if (main_tip) {
163 _table->set_tooltip_text(main_tip);
164 }
165}
166
167void StyleSwatch::setToolName(const Glib::ustring& tool_name) {
169}
170
172 _desktop = desktop;
173}
174
175Gtk::EventSequenceState StyleSwatch::on_click(Gtk::GestureClick const & /*click*/,
176 int /*n_press*/, double /*x*/, double /*y*/)
177{
178 if (_desktop && !_tool_name.empty()) {
179 auto win = _desktop->getInkscapeWindow();
181 return Gtk::EventSequenceState::CLAIMED;
182 }
184}
185
187{
188 if (_css)
190}
191
192void
193StyleSwatch::setWatchedTool(const char *path, bool synthesize)
194{
195 _tool_obs.reset();
196
197 if (path) {
198 _tool_path = path;
199 _tool_obs = PrefObs::create(_tool_path + "/usecurrent",
200 sigc::bind<0>(&tool_obs_callback, std::ref(*this)));
201 } else {
202 _tool_path = "";
203 }
204
205 if (synthesize && _tool_obs) {
206 _tool_obs->call();
207 }
208}
209
210
212{
213 if (_css)
215
216 if (!css)
217 return;
218
221
222 Glib::ustring css_string;
223 sp_repr_css_write_string (_css, css_string);
224
225 SPStyle style(_desktop ? _desktop->getDocument() : nullptr);
226 if (!css_string.empty()) {
227 style.mergeString(css_string.c_str());
228 }
229 setStyle (&style);
230}
231
233{
236
237 bool has_stroke = true;
238
239 for (int i = SS_FILL; i <= SS_STROKE; i++) {
240 auto const place = &_place[i];
241
242 SPIPaint *paint;
243 if (i == SS_FILL) {
244 paint = &(query->fill);
245 } else {
246 paint = &(query->stroke);
247 }
248
249 if (paint->set && paint->isPaintserver()) {
250 SPPaintServer *server = (i == SS_FILL)? SP_STYLE_FILL_SERVER (query) : SP_STYLE_STROKE_SERVER (query);
251
252 if (is<SPLinearGradient>(server)) {
253 _value[i].set_markup(_("L Gradient"));
254 place->append(_value[i]);
255 place->set_tooltip_text((i == SS_FILL)? (_("Linear gradient (fill)")) : (_("Linear gradient (stroke)")));
256 } else if (is<SPRadialGradient>(server)) {
257 _value[i].set_markup(_("R Gradient"));
258 place->append(_value[i]);
259 place->set_tooltip_text((i == SS_FILL)? (_("Radial gradient (fill)")) : (_("Radial gradient (stroke)")));
260 } else if (is<SPPattern>(server)) {
261 _value[i].set_markup(_("Pattern"));
262 place->append(_value[i]);
263 place->set_tooltip_text((i == SS_FILL)? (_("Pattern (fill)")) : (_("Pattern (stroke)")));
264 }
265 } else if (paint->set && paint->isColor()) {
266 guint32 color = paint->value.color.toRGBA32( SP_SCALE24_TO_FLOAT ((i == SS_FILL)? query->fill_opacity.value : query->stroke_opacity.value) );
267 _color_preview[i]->setRgba32(color);
268 place->append(*_color_preview[i]);
269 gchar *tip;
270 if (i == SS_FILL) {
271 tip = g_strdup_printf (_("Fill: %06x/%.3g"), color >> 8, SP_RGBA32_A_F(color));
272 } else {
273 tip = g_strdup_printf (_("Stroke: %06x/%.3g"), color >> 8, SP_RGBA32_A_F(color));
274 }
275 place->set_tooltip_text(tip);
276 g_free (tip);
277 } else if (paint->set && paint->isNone()) {
278 _value[i].set_markup(C_("Fill and stroke", "<i>None</i>"));
279 place->append(_value[i]);
280 place->set_tooltip_text((i == SS_FILL)? (C_("Fill and stroke", "No fill")) : (C_("Fill and stroke", "No stroke")));
281 if (i == SS_STROKE) has_stroke = false;
282 } else if (!paint->set) {
283 _value[i].set_markup(_("<b>Unset</b>"));
284 place->append(_value[i]);
285 place->set_tooltip_text((i == SS_FILL)? (_("Unset fill")) : (_("Unset stroke")));
286 if (i == SS_STROKE) has_stroke = false;
287 }
288 }
289
290// Now query stroke_width
291 if (has_stroke) {
292 if (query->stroke_extensions.hairline) {
293 Glib::ustring swidth = "<small>";
294 swidth += _("Hairline");
295 swidth += "</small>";
296 _stroke_width.set_markup(swidth.c_str());
297 auto str = Glib::ustring::compose(_("Stroke width: %1"), _("Hairline"));
298 _stroke_width.set_tooltip_text(str);
299 } else {
300 double w;
301 if (_sw_unit) {
302 w = Util::Quantity::convert(query->stroke_width.computed, "px", _sw_unit);
303 } else {
304 w = query->stroke_width.computed;
305 }
306
307 {
308 gchar *str = g_strdup_printf(" %.3g", w);
309 Glib::ustring swidth = "<small>";
310 swidth += str;
311 swidth += "</small>";
312 _stroke_width.set_markup(swidth.c_str());
313 g_free (str);
314 }
315 {
316 gchar *str = g_strdup_printf(_("Stroke width: %.5g%s"),
317 w,
318 _sw_unit? _sw_unit->abbr.c_str() : "px");
319 _stroke_width.set_tooltip_text(str);
320 g_free (str);
321 }
322 }
323 } else {
324 _stroke_width.set_tooltip_text("");
325 _stroke_width.set_markup("");
326 }
327
328 gdouble op = SP_SCALE24_TO_FLOAT(query->opacity.value);
329 if (op != 1) {
330 {
331 gchar *str;
332 str = g_strdup_printf(_("O: %2.0f"), (op*100.0));
333 Glib::ustring opacity = "<small>";
334 opacity += str;
335 opacity += "</small>";
336 _opacity_value.set_markup (opacity.c_str());
337 g_free (str);
338 }
339 {
340 gchar *str = g_strdup_printf(_("Opacity: %2.1f %%"), (op*100.0));
341 _opacity_value.set_tooltip_text(str);
342 g_free (str);
343 }
344 } else {
345 _opacity_value.set_tooltip_text("");
346 _opacity_value.set_markup("");
347 }
348}
349
350} // namespace Inkscape::UI::Widget
351
352/*
353 Local Variables:
354 mode:c++
355 c-file-style:"stroustrup"
356 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
357 indent-tabs-mode:nil
358 fill-column:99
359 End:
360*/
361// vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :
void open_tool_preferences(InkscapeWindow *win, Glib::ustring const &tool)
Data type representing a typeless value of a preference.
Definition: preferences.h:150
bool getBool(bool def=false) const
Interpret the preference as a Boolean value.
Definition: preferences.h:708
SPCSSAttr * getInheritedStyle() const
Interpret the preference as a CSS style with directory-based inheritance.
Definition: preferences.h:810
static std::unique_ptr< PreferencesObserver > create(Glib::ustring path, std::function< void(const Preferences::Entry &new_value)> callback)
static Preferences * get()
Access the singleton Preferences object.
Definition: preferences.h:599
Gtk::EventSequenceState on_click(Gtk::GestureClick const &click, int n_press, double x, double y)
void setWatchedTool(const char *path, bool synthesize)
friend void tool_obs_callback(StyleSwatch &, Preferences::Entry const &)
Watches whether the tool uses the current style.
std::unique_ptr< ColorPreview > _color_preview[2]
Definition: style-swatch.h:75
void setDesktop(SPDesktop *desktop)
void setToolName(const Glib::ustring &tool_name)
std::unique_ptr< PrefObs > _style_obs
Definition: style-swatch.h:67
std::unique_ptr< PrefObs > _tool_obs
Definition: style-swatch.h:66
StyleSwatch(SPCSSAttr *attr, gchar const *main_tip, Gtk::Orientation orient=Gtk::Orientation::VERTICAL)
static double convert(double from_dist, Unit const *from, Unit const *to)
Convert distances.
Definition: units.cpp:525
Glib::ustring abbr
Definition: units.h:76
guint32 toRGBA32(int alpha) const
Convert SPColor with integer alpha value to 32bit RGBA value.
Definition: color.cpp:220
To do: update description of desktop.
Definition: desktop.h:150
SPDocument * getDocument() const
Definition: desktop.h:187
InkscapeWindow const * getInkscapeWindow() const
Definition: desktop.cpp:1096
Paint type internal to SPStyle.
bool isPaintserver() const
bool isColor() const
struct SPIPaint::@48 value
bool isNone() const
SPColor color
An SVG style object.
Definition: style.h:45
T< SPAttr::FILL, SPIPaint > fill
fill
Definition: style.h:240
T< SPAttr::STROKE, SPIPaint > stroke
stroke
Definition: style.h:247
T< SPAttr::STROKE_WIDTH, SPILength > stroke_width
stroke-width
Definition: style.h:249
T< SPAttr::FILL_OPACITY, SPIScale24 > fill_opacity
fill-opacity
Definition: style.h:242
T< SPAttr::STROKE_OPACITY, SPIScale24 > stroke_opacity
stroke-opacity
Definition: style.h:261
void mergeString(char const *p)
Parses a style="..." string and merges it with an existing SPStyle.
Definition: style.cpp:852
T< SPAttr::OPACITY, SPIScale24 > opacity
opacity
Definition: style.h:216
T< SPAttr::STROKE_EXTENSIONS, SPIStrokeExtensions > stroke_extensions
-inkscape-stroke
Definition: style.h:263
unsigned int guint32
Definition: color.h:22
const double w
Definition: conic-4.cpp:19
Utilities to more easily use Gtk::EventController & subclasses like Gesture.
std::shared_ptr< Css const > css
static bool has_stroke(SPObject *source)
D2< T > compose(D2< T > const &a, T const &b)
Definition: d2.h:405
Definition: desktop.h:51
Gtk::GestureClick & add_click(Gtk::Widget &widget, ClickSlot on_pressed, ClickSlot on_released, Button const button, Gtk::PropagationPhase const phase, When const when)
Create a click gesture for the given widget; by default claim sequence.
Definition: controller.cpp:105
Custom widgets.
Definition: desktop.h:127
void tool_obs_callback(StyleSwatch &_style_swatch, Preferences::Entry const &val)
Watches whether the tool uses the current style.
void style_obs_callback(StyleSwatch &_style_swatch, Preferences::Entry const &val)
Watches for changes in the observed style pref.
void remove_all_children(Widget &widget)
For each child in get_children(widget), call widget.remove(*child). May not cause delete child!
Definition: util.h:80
void pack_start(Gtk::Box &box, Gtk::Widget &child, bool const expand, bool const fill, unsigned const padding)
Adds child to box, packed with reference to the start of box.
Definition: pack.cpp:141
@ NONE
Definition: axis-manip.h:35
@ VERTICAL
The y-dimension (1).
Definition: rectangle.h:47
Helpers for using Gtk::Boxes, encapsulating large changes between GTK3 & GTK4.
Ocnode ** ref
Definition: quantize.cpp:32
SPCSSAttr * sp_repr_css_attr_new()
Creates an empty SPCSSAttr (a class for manipulating CSS style properties).
Definition: repr-css.cpp:67
void sp_repr_css_write_string(SPCSSAttr *css, Glib::ustring &str)
Write a style attribute string from a list of properties stored in an SPCSAttr object.
Definition: repr-css.cpp:235
void sp_repr_css_merge(SPCSSAttr *dst, SPCSSAttr *src)
Merges two SPCSSAttr's.
Definition: repr-css.cpp:291
void sp_repr_css_attr_unref(SPCSSAttr *css)
Unreferences an SPCSSAttr (will be garbage collected if no references remain).
Definition: repr-css.cpp:76
SPCSSAttr - interface for CSS Attributes.
TODO: insert short description here.
SVG <pattern> implementation.
TODO: insert short description here.
static constexpr int STYLE_SWATCH_WIDTH
@ SS_STROKE
@ SS_FILL
Static style swatch (fill, stroke, opacity)
SPStyle - a style object for SPItem objects.
Glib::ustring const tool_name
Definition: toolbars.cpp:62