Enhance save as template and new from template dialogs
[inkscape.git] / src / ui / util.h
blob4bb260be5a2bfa253d52445a9154eb30f97cbf09
1 // SPDX-License-Identifier: GPL-2.0-or-later
2 /*
3 * Utility functions for UI
5 * Authors:
6 * Tavmjong Bah
7 * John Smith
9 * Copyright (C) 2013, 2018 Authors
10 * Released under GNU GPL v2+, read the file 'COPYING' for more information.
13 #ifndef UI_UTIL_SEEN
14 #define UI_UTIL_SEEN
16 #include <cstddef> // size_t
17 #include <exception>
18 #include <type_traits>
19 #include <vector>
21 #include <pangomm/layout.h> // Pango::EllipsizeMode
22 #include <gdkmm/rgba.h>
23 #include <gtkmm/cellrenderer.h>
24 #include <gtkmm/enums.h>
25 #include <gtkmm/notebook.h>
26 #include <gtkmm/widget.h>
28 #include <2geom/affine.h>
29 #include <2geom/point.h>
30 #include <2geom/rect.h>
33 * Use these errors when building from glade files for graceful
34 * fallbacks and prevent crashes from corrupt ui files.
36 class UIBuilderError : public std::exception {};
37 class UIFileUnavailable : public UIBuilderError {};
38 class WidgetUnavailable : public UIBuilderError {};
40 namespace Cairo {
41 class Matrix;
42 class ImageSurface;
43 } // namespace Cairo
45 namespace Glib {
46 class ustring;
47 } // namespace Glib
49 namespace Gtk {
50 class Editable;
51 class Label;
52 class TextBuffer;
53 class Widget;
54 } // namespace Gtk
56 namespace Inkscape::Colors {
57 class Color;
58 } // namespace Inkscape::Colors
60 Glib::ustring ink_ellipsize_text(Glib::ustring const &src, std::size_t maxlen);
62 void reveal_widget(Gtk::Widget *widget, bool show);
64 // check if widget in a container is actually visible
65 bool is_widget_effectively_visible(Gtk::Widget const *widget);
67 namespace Inkscape::UI {
69 void set_icon_sizes(Gtk::Widget *parent, int pixel_size);
70 void set_icon_sizes(GtkWidget *parent, int pixel_size);
72 void gui_warning(const std::string &msg, Gtk::Window * parent_window = nullptr);
74 /// Whether for_each_*() will continue or stop after calling Func per child.
75 enum class ForEachResult {
76 _continue, // go on to the next widget
77 _break, // stop here, return current widget
78 _skip // do not recurse into current widget, go to the next one
81 /// Get a vector of the widgetʼs children, from get_first_child() through each get_next_sibling().
82 std::vector<Gtk::Widget *> get_children(Gtk::Widget &widget);
83 /// Get the widgetʼs child at the given position. Throws std::out_of_range if the index is invalid.
84 Gtk::Widget &get_nth_child(Gtk::Widget &widget, std::size_t index);
85 /// For each child in get_children(widget), call widget.remove(*child). May not cause delete child!
86 template <typename Widget> void remove_all_children(Widget &widget)
88 for (auto const child: get_children(widget)) {
89 widget.remove(*child);
93 /// Call Func with a reference to each child of parent, until it returns _break.
94 /// Accessing children changes between GTK3 & GTK4, so best consolidate it here.
95 /// @param widget The initial widget at the top of the hierarchy, to start at
96 /// @param func The widget-testing predicate, returning whether to continue
97 /// @param plus_self Whether to call the predicate @a func on the initial widget
98 /// @param recurse Whether to recurse also calling @a func for nested children
99 /// @return The first widget for which @a func returns _break or nullptr if none
100 template <typename Func>
101 Gtk::Widget *for_each_child(Gtk::Widget &widget, Func &&func,
102 bool const plus_self = false, bool const recurse = false,
103 int const level = 0)
105 static_assert(std::is_invocable_r_v<ForEachResult, Func, Gtk::Widget &>);
107 if (plus_self) {
108 auto ret = func(widget);
109 if (ret == ForEachResult::_break) return &widget;
111 // skip this widget?
112 if (ret == ForEachResult::_skip) return nullptr;
115 if (!recurse && level > 0) return nullptr;
117 for (auto const child: get_children(widget)) {
118 auto const descendant = for_each_child(*child, func, true, recurse, level + 1);
119 if (descendant) return descendant;
122 return nullptr;
125 /// Like for_each_child() but also tests the initial widget & recurses through childrenʼs children.
126 /// @param widget The initial widget at the top of the hierarchy, to start at
127 /// @param func The widget-testing predicate, returning whether to continue
128 /// @return The first widget for which @a func returns _break or nullptr if none
129 template <typename Func>
130 Gtk::Widget *for_each_descendant(Gtk::Widget &widget, Func &&func)
132 return for_each_child(widget, std::forward<Func>(func), true, true);
135 /// Call Func with a reference to successive parents, until Func returns _break.
136 template <typename Func>
137 Gtk::Widget *for_each_parent(Gtk::Widget &widget, Func &&func)
139 static_assert(std::is_invocable_r_v<ForEachResult, Func, Gtk::Widget &>);
140 for (auto parent = widget.get_parent(); parent; parent = parent->get_parent()) {
141 if (func(*parent) == ForEachResult::_break) {
142 return parent;
145 return nullptr;
148 /// Similar to for_each_child, but only iterates over pages in a notebook
149 template <typename Func>
150 Gtk::Widget* for_each_page(Gtk::Notebook& notebook, Func&& func) {
151 static_assert(std::is_invocable_r_v<ForEachResult, Func, Gtk::Widget&>);
153 const int page_number = notebook.get_n_pages();
154 for (int page_index = 0; page_index < page_number; ++page_index) {
155 auto page = notebook.get_nth_page(page_index);
156 if (!page) continue;
158 if (func(*page) == ForEachResult::_break) return page;
161 return nullptr;
164 [[nodiscard]] Gtk::Widget *find_widget_by_name(Gtk::Widget &parent, Glib::ustring const &name, bool visible_only);
165 [[nodiscard]] Gtk::Widget *find_focusable_widget(Gtk::Widget &parent);
166 [[nodiscard]] bool is_descendant_of(Gtk::Widget const &descendant, Gtk::Widget const &ancestor);
167 [[nodiscard]] bool contains_focus(Gtk::Widget &widget);
169 [[nodiscard]] int get_font_size(Gtk::Widget &widget);
171 // If max_width_chars is > 0, then the created Label has :max-width-chars set to
172 // that limit, the :ellipsize mode is set to the passed-in @a mode, & a ::query-
173 // tooltip handler is connected to show the label as the tooltip when ellipsized
174 void ellipsize(Gtk::Label &label, int max_width_chars, Pango::EllipsizeMode mode);
176 } // namespace Inkscape::UI
178 // Mix two RGBA colors using simple linear interpolation:
179 // 0 -> only a, 1 -> only b, x in 0..1 -> (1 - x)*a + x*b
180 Gdk::RGBA mix_colors(const Gdk::RGBA& a, const Gdk::RGBA& b, float ratio);
182 // Create the same color, but with a different opacity (alpha)
183 Gdk::RGBA change_alpha(const Gdk::RGBA& color, double new_alpha);
185 /// Calculate luminance of an RGBA color from its RGB in range 0 to 1 inclusive.
186 /// This uses the perceived brightness formula given at: https://www.w3.org/TR/AERT/#color-contrast
187 double get_luminance(const Gdk::RGBA &color);
189 // Get CSS color for a Widget, based on its current state & a given CSS class.
190 // N.B.!! Big GTK devs donʼt think changing classes should work ‘within a frame’
191 // …but it does… & GTK3 GtkCalendar does that – so keep doing it, till we canʼt!
192 Gdk::RGBA get_color_with_class(Gtk::Widget &widget,
193 Glib::ustring const &css_class);
195 // Convert a Gdk color to a hex code for css injection.
196 Glib::ustring gdk_to_css_color(const Gdk::RGBA& color);
197 Gdk::RGBA css_color_to_gdk(const char *value);
199 guint32 to_guint32(Gdk::RGBA const &rgba);
200 Gdk::RGBA color_to_rgba(Inkscape::Colors::Color const &color);
201 Gdk::RGBA to_rgba(guint32 const u32);
203 // convert Gdk::RGBA into 32-bit rrggbbaa color, optionally replacing alpha, if specified
204 uint32_t conv_gdk_color_to_rgba(const Gdk::RGBA& color, double replace_alpha = -1);
206 Geom::IntRect cairo_to_geom(const Cairo::RectangleInt &rect);
207 Cairo::RectangleInt geom_to_cairo(const Geom::IntRect &rect);
208 Cairo::Matrix geom_to_cairo(const Geom::Affine &affine);
209 Geom::IntPoint dimensions(const Cairo::RefPtr<Cairo::ImageSurface> &surface);
210 Geom::IntPoint dimensions(const Gdk::Rectangle &allocation);
212 // create a gradient with multiple steps to approximate profile described by given cubic spline
213 Cairo::RefPtr<Cairo::LinearGradient> create_cubic_gradient(
214 Geom::Rect rect,
215 const Gdk::RGBA& from,
216 const Gdk::RGBA& to,
217 Geom::Point ctrl1,
218 Geom::Point ctrl2,
219 Geom::Point p0 = Geom::Point(0, 0),
220 Geom::Point p1 = Geom::Point(1, 1),
221 int steps = 8
224 // If on Windows, get the native window & set it to DWMA_USE_IMMERSIVE_DARK_MODE
225 void set_dark_titlebar(Glib::RefPtr<Gdk::Surface> const &surface, bool is_dark);
226 unsigned int get_color_value(const Glib::ustring color);
228 // Parse string that can contain floating point numbers and round them to given precision;
229 // Used on path data ("d" attribute).
230 Glib::ustring round_numbers(const Glib::ustring& text, int precision);
232 // As above, but operating in-place on a TextBuffer
233 void truncate_digits(const Glib::RefPtr<Gtk::TextBuffer>& buffer, int precision);
236 * Convert an image surface in ARGB32 format to a texture.
237 * The texture shares data with the surface, so the surface shouldn't modified afterwards.
239 Glib::RefPtr<Gdk::Texture> to_texture(Cairo::RefPtr<Cairo::Surface> const &surface);
241 // Restrict widget's min size (min-width & min-height) to specified minimum to keep it square (when it's centered).
242 // Widget has to have a name given with set_name.
243 void restrict_minsize_to_square(Gtk::Widget& widget, int min_size_px);
245 /// Get the text from a GtkEditable without the temporary copy imposed by gtkmm.
246 char const *get_text(Gtk::Editable const &editable);
248 #endif // UI_UTIL_SEEN
251 Local Variables:
252 mode:c++
253 c-file-style:"stroustrup"
254 c-file-offsets:((innamespace . 0)(inline-open . 0)(case-label . +))
255 indent-tabs-mode:nil
256 fill-column:99
257 End:
259 // vim: filetype=cpp:expandtab:shiftwidth=4:tabstop=8:softtabstop=4:fileencoding=utf-8:textwidth=99 :