openMSX
ImGuiCpp.hh
Go to the documentation of this file.
1#ifndef IMGUI_CPP_HH
2#define IMGUI_CPP_HH
3
4#include "narrow.hh"
5#include "xrange.hh"
6
7#include <imgui.h>
8
9#include <concepts>
10
11// C++ wrapper around the Dear ImGui C-API
12//
13// Several Dear ImGui functions always need to be called in pairs. Some examples:
14// * ImGui::Begin() always needs to be paired with ImGui::End().
15// * Similar for ImGui::TreeNodeEx() and ImGui::TreePop().
16//
17// These wrapper ensure that you cannot do a wrong pairing.
18//
19// In case of the former 'End()' must always be called (whether 'Begin()'
20// returned 'true' or 'false'). But for the latter 'TreePop()' may only be
21// called when 'TreeNodeEx()' returned 'true'. This difference only exists for
22// historic reason (and thus for backwards compatibility). The Dear ImGui
23// documentation states that in some future version this difference will likely
24// be removed. These wrappers already hide this difference today.
25//
26// Example usage:
27// * This uses the original Dear ImGui C-API:
28// if (ImGui::Begin("my-window")) {
29// ImGui::BeginDisabled(b);
30// if (ImGui::TreeNodeEx("bla", flag)) {
31// ... more stuff
32// ImGui::TreePop();
33// }
34// if (ImGui::TreeNodeEx("foobar")) {
35// ... more stuff
36// ImGui::TreePop();
37// }
38// ImGui::EndDisabled();
39// }
40// ImGui::End();
41//
42// * This is the exact same example, but with our C++ wrapper functions:
43// im::Window("my-window", [&]{
44// im::Disabled(b, [&]{
45// im::TreeNode("bla", flag, [&]{
46// ... more stuff
47// });
48// im::TreeNode("foobar", [&]{
49// ... more stuff
50// });
51// });
52// });
53//
54// This wrapper is inspired by ideas from:
55// https://github.com/ocornut/imgui/issues/2096
56// https://github.com/ocornut/imgui/pull/2197
57// https://github.com/mnesarco/imgui_sugar
58// https://github.com/kfsone/imguiwrap
59
60namespace im {
61
62// im::Window(): wrapper around ImGui::Begin() / ImGui::End()
63inline void Window(const char* name, bool* p_open, ImGuiWindowFlags flags, std::invocable<> auto next)
64{
65 if (ImGui::Begin(name, p_open, flags)) {
66 next();
67 }
68 ImGui::End();
69}
70inline void Window(const char* name, bool* p_open, std::invocable<> auto next)
71{
72 Window(name, p_open, 0, next);
73}
74inline void Window(const char* name, std::invocable<> auto next)
75{
76 Window(name, nullptr, 0, next);
77}
78
80 bool open = false; // [level] true <=> window is open
81 bool do_raise = false; // [edge] set to true when you want to raise this window
82 // gets automatically reset when done
83 void raise() { do_raise = open = true; }
84};
85inline void Window(const char* name, WindowStatus& status, ImGuiWindowFlags flags, std::invocable<> auto next)
86{
87 if (ImGui::Begin(name, &status.open, flags)) {
88 if (status.do_raise) {
89 status.do_raise = false;
90 if (!ImGui::IsWindowAppearing()) { // otherwise crash, viewport not yet initialized???
91 // depending on the backend (e.g. Wayland) this could be nullptr
92 if (auto* swf = ImGui::GetPlatformIO().Platform_SetWindowFocus) {
93 swf(ImGui::GetWindowViewport());
94 }
95 // When window is inside the main viewport, this function is
96 // needed to raise focus even if Platform_SetWindowFocus exists
97 ImGui::SetWindowFocus();
98 }
99 }
100 next();
101 }
102 ImGui::End();
103}
104inline void Window(const char* name, WindowStatus& status, std::invocable<> auto next)
105{
106 Window(name, status, 0, next);
107}
108
109// im::Child(): wrapper around ImGui::BeginChild() / ImGui::EndChild()
110inline void Child(const char* str_id, const ImVec2& size, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags, std::invocable<> auto next)
111{
112 if (ImGui::BeginChild(str_id, size, child_flags, window_flags)) {
113 next();
114 }
115 ImGui::EndChild();
116}
117inline void Child(const char* str_id, const ImVec2& size, ImGuiChildFlags child_flags, std::invocable<> auto next)
118{
119 Child(str_id, size, child_flags, 0, next);
120}
121inline void Child(const char* str_id, const ImVec2& size, std::invocable<> auto next)
122{
123 Child(str_id, size, 0, 0, next);
124}
125inline void Child(const char* str_id, std::invocable<> auto next)
126{
127 Child(str_id, {}, 0, 0, next);
128}
129
130// im::Font(): wrapper around ImGui::PushFont() / ImGui::PopFont()
131inline void Font(ImFont* font, std::invocable<> auto next)
132{
133 ImGui::PushFont(font);
134 next();
135 ImGui::PopFont();
136}
137// Same functionality as im::Font(), but different usage (sometimes one sometimes the other is easier).
139 explicit ScopedFont(ImFont* font) { ImGui::PushFont(font); }
140 ~ScopedFont() { ImGui::PopFont(); }
141
142 ScopedFont(const ScopedFont&) = delete;
144 ScopedFont& operator=(const ScopedFont&) = delete;
146};
147
148// im::StyleColor(): wrapper around ImGui::PushStyleColor() / ImGui::PopStyleColor()
149// Can be called like:
150// im::StyleColor(
151// bool active, // _optional_ boolean parameter
152// ImGuiCol idx1, ImVec4 col1, // followed by an arbitrary number of [idx, col] pairs
153// ImGuiCol idx2, ImU32 col2, // where col can either be 'ImVec4' or 'ImU32'
154// ...
155// std::invocable<> auto next); // and finally a lambda that will be executed with these color changes
156template<int N>
157inline void StyleColor_impl(bool active, std::invocable<> auto next)
158{
159 next();
160 if (active) ImGui::PopStyleColor(N);
161}
162template<int N, typename... Args>
163inline void StyleColor_impl(bool active, ImGuiCol idx, ImVec4 col, Args&& ...args)
164{
165 if (active) ImGui::PushStyleColor(idx, col);
166 StyleColor_impl<N>(active, std::forward<Args>(args)...);
167}
168template<int N, typename... Args>
169inline void StyleColor_impl(bool active, ImGuiCol idx, ImU32 col, Args&& ...args)
170{
171 if (active) ImGui::PushStyleColor(idx, ImGui::ColorConvertU32ToFloat4(col));
172 StyleColor_impl<N>(active, std::forward<Args>(args)...);
173}
174template<typename... Args>
175inline void StyleColor(bool active, Args&& ...args)
176{
177 static constexpr auto N = sizeof...(args);
178 static_assert(N >= 3);
179 static_assert((N & 1) == 1);
180 StyleColor_impl<(N - 1) / 2>(active, std::forward<Args>(args)...);
181}
182template<typename... Args>
183inline void StyleColor(Args&& ...args)
184{
185 StyleColor(true, std::forward<Args>(args)...);
186}
187
188// im::StyleVar(): wrapper around ImGui::PushStyleVar() / ImGui::PopStyleVar()
189// Add more overloads when needed
190inline void StyleVar(ImGuiStyleVar idx, float val, std::invocable<> auto next)
191{
192 ImGui::PushStyleVar(idx, val);
193 next();
194 ImGui::PopStyleVar(1);
195}
196inline void StyleVar(ImGuiStyleVar idx, const ImVec2& val, std::invocable<> auto next)
197{
198 ImGui::PushStyleVar(idx, val);
199 next();
200 ImGui::PopStyleVar(1);
201}
202
203// im::ItemWidth(): wrapper around ImGui::PushItemWidth() / ImGui::PopItemWidth()
204inline void ItemWidth(float item_width, std::invocable<> auto next)
205{
206 ImGui::PushItemWidth(item_width);
207 next();
208 ImGui::PopItemWidth();
209}
210
211// im::TextWrapPos(): wrapper around ImGui::PushTextWrapPos() / ImGui::PopTextWrapPos()
212inline void TextWrapPos(float wrap_local_pos_x, std::invocable<> auto next)
213{
214 ImGui::PushTextWrapPos(wrap_local_pos_x);
215 next();
216 ImGui::PopTextWrapPos();
217}
218inline void TextWrapPos(std::invocable<> auto next)
219{
220 TextWrapPos(0.0f, next);
221}
222
223// im::Indent(): wrapper around ImGui::Indent() / ImGui::Unindent()
224inline void Indent(float indent_w, std::invocable<> auto next)
225{
226 ImGui::Indent(indent_w);
227 next();
228 ImGui::Unindent(indent_w);
229}
230inline void Indent(std::invocable<> auto next)
231{
232 Indent(0.0f, next);
233}
234
235// im::Group(): wrapper around ImGui::BeginGroup() / ImGui::EndGroup()
236inline void Group(std::invocable<> auto next)
237{
238 ImGui::BeginGroup();
239 next();
240 ImGui::EndGroup();
241}
242
243// im::ID(): wrapper around ImGui::PushID() / ImGui::PopID()
244inline void ID(const char* str_id, std::invocable<> auto next)
245{
246 ImGui::PushID(str_id);
247 next();
248 ImGui::PopID();
249}
250inline void ID(const char* str_id_begin, const char* str_id_end, std::invocable<> auto next)
251{
252 ImGui::PushID(str_id_begin, str_id_end);
253 next();
254 ImGui::PopID();
255}
256inline void ID(const void* ptr_id, std::invocable<> auto next)
257{
258 ImGui::PushID(ptr_id);
259 next();
260 ImGui::PopID();
261}
262inline void ID(int int_id, std::invocable<> auto next)
263{
264 ImGui::PushID(int_id);
265 next();
266 ImGui::PopID();
267}
268inline void ID(const std::string& str, std::invocable<> auto next)
269{
270 auto begin = str.data();
271 auto end = begin + str.size();
272 ID(begin, end, next);
273}
274inline void ID(std::string_view str, std::invocable<> auto next)
275{
276 auto begin = str.data();
277 auto end = begin + str.size();
278 ID(begin, end, next);
279}
280
281inline void ID_for_range(std::integral auto count, std::invocable<int> auto next)
282{
283 for (auto i : xrange(narrow<int>(count))) {
284 ID(i, [&]{ next(i); });
285 }
286}
287
288// im::Combo(): wrapper around ImGui::BeginCombo() / ImGui::EndCombo()
289inline void Combo(const char* label, const char* preview_value, ImGuiComboFlags flags, std::invocable<> auto next)
290{
291 if (ImGui::BeginCombo(label, preview_value, flags)) {
292 next();
293 ImGui::EndCombo();
294 }
295}
296inline void Combo(const char* label, const char* preview_value, std::invocable<> auto next)
297{
298 Combo(label, preview_value, 0, next);
299}
300
301// im::TreeNode(): wrapper around ImGui::TreeNodeEx() / ImGui::TreePop()
302inline bool TreeNode(const char* label, ImGuiTreeNodeFlags flags, std::invocable<> auto next)
303{
304 bool open = ImGui::TreeNodeEx(label, flags);
305 if (open) {
306 next();
307 ImGui::TreePop();
308 }
309 return open;
310}
311inline bool TreeNode(const char* label, std::invocable<> auto next)
312{
313 return TreeNode(label, 0, next);
314}
315inline void TreeNode(const char* label, bool* p_open, std::invocable<> auto next)
316{
317 assert(p_open);
318 ImGui::SetNextItemOpen(*p_open);
319 int flags = 0;
320 *p_open = ImGui::TreeNodeEx(label, flags);
321 if (*p_open) {
322 next();
323 ImGui::TreePop();
324 }
325}
326
327// im::ListBox(): wrapper around ImGui::BeginListBox() / ImGui::EndListBox()
328inline void ListBox(const char* label, const ImVec2& size, std::invocable<> auto next)
329{
330 if (ImGui::BeginListBox(label, size)) {
331 next();
332 ImGui::EndListBox();
333 }
334}
335inline void ListBox(const char* label, std::invocable<> auto next)
336{
337 ListBox(label, {}, next);
338}
339
340// im::MainMenuBar(): wrapper around ImGui::BeginMenuBar() / ImGui::EndMenuBar()
341inline void MenuBar(std::invocable<> auto next)
342{
343 if (ImGui::BeginMenuBar()) {
344 next();
345 ImGui::EndMenuBar();
346 }
347}
348
349// im::MainMenuBar(): wrapper around ImGui::BeginMainMenuBar() / ImGui::EndMainMenuBar()
350inline void MainMenuBar(std::invocable<> auto next)
351{
352 if (ImGui::BeginMainMenuBar()) {
353 next();
354 ImGui::EndMainMenuBar();
355 }
356}
357
358// im::Menu(): wrapper around ImGui::BeginMenu() / ImGui::EndMenu()
359inline bool Menu(const char* label, bool enabled, std::invocable<> auto next)
360{
361 bool open = ImGui::BeginMenu(label, enabled);
362 if (open) {
363 next();
364 ImGui::EndMenu();
365 }
366 return open;
367}
368inline bool Menu(const char* label, std::invocable<> auto next)
369{
370 return Menu(label, true, next);
371}
372
373// im::Tooltip(): wrapper around ImGui::BeginTooltip() / ImGui::EndTooltip()
374inline void Tooltip(std::invocable<> auto next)
375{
376 if (ImGui::BeginTooltip()) {
377 next();
378 ImGui::EndTooltip();
379 }
380}
381// im::Tooltip(): wrapper around ImGui::BeginItemTooltip() / ImGui::EndTooltip()
382inline void ItemTooltip(std::invocable<> auto next)
383{
384 if (ImGui::BeginItemTooltip()) {
385 next();
386 ImGui::EndTooltip();
387 }
388}
389
390// im::Popup(): wrapper around ImGui::BeginPopup() / ImGui::EndPopup()
391inline void Popup(const char* str_id, ImGuiWindowFlags flags, std::invocable<> auto next)
392{
393 if (ImGui::BeginPopup(str_id, flags)) {
394 next();
395 ImGui::EndPopup();
396 }
397}
398inline void Popup(const char* str_id, std::invocable<> auto next)
399{
400 Popup(str_id, 0, next);
401}
402
403// im::PopupModal(): wrapper around ImGui::BeginPopupModal() / ImGui::EndPopup()
404inline void PopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags, std::invocable<> auto next)
405{
406 if (ImGui::BeginPopupModal(name, p_open, flags)) {
407 next();
408 ImGui::EndPopup();
409 }
410}
411inline void PopupModal(const char* name, bool* p_open, std::invocable<> auto next)
412{
413 PopupModal(name, p_open, 0, next);
414}
415inline void PopupModal(const char* name, std::invocable<> auto next)
416{
417 PopupModal(name, nullptr, 0, next);
418}
419
420// im::PopupContextItem(): wrapper around ImGui::BeginPopupContextItem() / ImGui::EndPopup()
421inline void PopupContextItem(const char* str_id, ImGuiPopupFlags popup_flags, std::invocable<> auto next)
422{
423 if (ImGui::BeginPopupContextItem(str_id, popup_flags)) {
424 next();
425 ImGui::EndPopup();
426 }
427}
428inline void PopupContextItem(const char* str_id, std::invocable<> auto next)
429{
430 PopupContextItem(str_id, ImGuiPopupFlags_MouseButtonRight, next);
431}
432inline void PopupContextItem(std::invocable<> auto next)
433{
434 PopupContextItem(nullptr, ImGuiPopupFlags_MouseButtonRight, next);
435}
436
437// im::PopupContextWindow(): wrapper around ImGui::BeginPopupContextWindow() / ImGui::EndPopup()
438inline void PopupContextWindow(const char* str_id, ImGuiPopupFlags popup_flags, std::invocable<> auto next)
439{
440 if (ImGui::BeginPopupContextWindow(str_id, popup_flags)) {
441 next();
442 ImGui::EndPopup();
443 }
444}
445inline void PopupContextWindow(const char* str_id, std::invocable<> auto next)
446{
447 PopupContextWindow(str_id, 1, next);
448}
449inline void PopupContextWindow(std::invocable<> auto next)
450{
451 PopupContextWindow(nullptr, 1, next);
452}
453
454// im::Table(): wrapper around ImGui::BeginTable() / ImGui::EndTable()
455inline void Table(const char* str_id, int column, ImGuiTableFlags flags, const ImVec2& outer_size, float inner_width, std::invocable<> auto next)
456{
457 if (ImGui::BeginTable(str_id, column, flags, outer_size, inner_width)) {
458 next();
459 ImGui::EndTable();
460 }
461}
462inline void Table(const char* str_id, int column, ImGuiTableFlags flags, const ImVec2& outer_size, std::invocable<> auto next)
463{
464 Table(str_id, column, flags, outer_size, 0.0f, next);
465}
466inline void Table(const char* str_id, int column, ImGuiTableFlags flags, std::invocable<> auto next)
467{
468 Table(str_id, column, flags, {}, 0.0f, next);
469}
470inline void Table(const char* str_id, int column, std::invocable<> auto next)
471{
472 Table(str_id, column, 0, {}, 0.0f, next);
473}
474
475// im::TabBar(): wrapper around ImGui::BeginTabBar() / ImGui::EndTabBar()
476inline void TabBar(const char* str_id, ImGuiTabBarFlags flags, std::invocable<> auto next)
477{
478 if (ImGui::BeginTabBar(str_id, flags)) {
479 next();
480 ImGui::EndTabBar();
481 }
482}
483inline void TabBar(const char* str_id, std::invocable<> auto next)
484{
485 TabBar(str_id, 0, next);
486}
487
488// im::TabItem(): wrapper around ImGui::BeginTabItem() / ImGui::EndTabItem()
489inline void TabItem(const char* label, bool* p_open, ImGuiTabItemFlags flags, std::invocable<> auto next)
490{
491 if (ImGui::BeginTabItem(label, p_open, flags)) {
492 next();
493 ImGui::EndTabItem();
494 }
495}
496inline void TabItem(const char* label, bool* p_open, std::invocable<> auto next)
497{
498 TabItem(label, p_open, 0, next);
499}
500inline void TabItem(const char* label, std::invocable<> auto next)
501{
502 TabItem(label, nullptr, 0, next);
503}
504
505// im::Disabled(): wrapper around ImGui::BeginDisabled() / ImGui::EndDisabled()
506inline void Disabled(bool b, std::invocable<> auto next)
507{
508 ImGui::BeginDisabled(b);
509 next();
510 ImGui::EndDisabled();
511}
512
513// im::DisabledIndent(): combination of Disabled() and Indent()
514inline void DisabledIndent(bool b, std::invocable<> auto next)
515{
516 ImGui::BeginDisabled(b);
517 ImGui::Indent(); // TODO for now not configurable
518 next();
519 ImGui::Unindent();
520 ImGui::EndDisabled();
521}
522
523// im::VisuallyDisabled(): similar to Disabled(), but only visually disable, still allow to interact normally
524inline void VisuallyDisabled(bool b, std::invocable<> auto next)
525{
526 if (b) {
527 const auto& style = ImGui::GetStyle();
528 ImGui::PushStyleVar(ImGuiStyleVar_Alpha, style.Alpha * style.DisabledAlpha);
529 }
530 next();
531 if (b) {
532 ImGui::PopStyleVar(1);
533 }
534}
535
536// im::ListClipper: wrapper around ImGuiListClipper
537// hides the typical nested loop
538inline void ListClipper(size_t count, int forceIndex, float lineHeight, std::invocable<int> auto next)
539{
540 ImGuiListClipper clipper; // only draw the actually visible lines
541 clipper.Begin(narrow<int>(count), lineHeight);
542 if (forceIndex > 0) clipper.IncludeItemByIndex(narrow<int>(forceIndex));
543 while (clipper.Step()) {
544 for (int i : xrange(clipper.DisplayStart, clipper.DisplayEnd)) {
545 next(i);
546 }
547 }
548}
549inline void ListClipper(size_t count, int forceIndex, std::invocable<int> auto next)
550{
551 ListClipper(count, forceIndex, -1.0f, next);
552}
553inline void ListClipper(size_t count, std::invocable<int> auto next)
554{
555 ListClipper(count, -1, next);
556}
557
558// im::ListClipperID: combination of im::ListClipper() and im::ID()
559inline void ListClipperID(size_t count, std::invocable<int> auto next)
560{
561 ImGuiListClipper clipper; // only draw the actually visible lines
562 clipper.Begin(narrow<int>(count));
563 while (clipper.Step()) {
564 for (int i : xrange(clipper.DisplayStart, clipper.DisplayEnd)) {
565 ImGui::PushID(i);
566 next(i);
567 ImGui::PopID();
568 }
569 }
570}
571
572} // namespace im
573
574#endif
Definition ImGuiCpp.hh:60
void DisabledIndent(bool b, std::invocable<> auto next)
Definition ImGuiCpp.hh:514
void Table(const char *str_id, int column, ImGuiTableFlags flags, const ImVec2 &outer_size, float inner_width, std::invocable<> auto next)
Definition ImGuiCpp.hh:455
void MainMenuBar(std::invocable<> auto next)
Definition ImGuiCpp.hh:350
void MenuBar(std::invocable<> auto next)
Definition ImGuiCpp.hh:341
void Window(const char *name, bool *p_open, ImGuiWindowFlags flags, std::invocable<> auto next)
Definition ImGuiCpp.hh:63
void VisuallyDisabled(bool b, std::invocable<> auto next)
Definition ImGuiCpp.hh:524
void ID(const char *str_id, std::invocable<> auto next)
Definition ImGuiCpp.hh:244
void PopupContextItem(const char *str_id, ImGuiPopupFlags popup_flags, std::invocable<> auto next)
Definition ImGuiCpp.hh:421
void StyleColor_impl(bool active, std::invocable<> auto next)
Definition ImGuiCpp.hh:157
void StyleVar(ImGuiStyleVar idx, float val, std::invocable<> auto next)
Definition ImGuiCpp.hh:190
void TabBar(const char *str_id, ImGuiTabBarFlags flags, std::invocable<> auto next)
Definition ImGuiCpp.hh:476
void PopupContextWindow(const char *str_id, ImGuiPopupFlags popup_flags, std::invocable<> auto next)
Definition ImGuiCpp.hh:438
bool TreeNode(const char *label, ImGuiTreeNodeFlags flags, std::invocable<> auto next)
Definition ImGuiCpp.hh:302
void Combo(const char *label, const char *preview_value, ImGuiComboFlags flags, std::invocable<> auto next)
Definition ImGuiCpp.hh:289
void ItemWidth(float item_width, std::invocable<> auto next)
Definition ImGuiCpp.hh:204
void ListBox(const char *label, const ImVec2 &size, std::invocable<> auto next)
Definition ImGuiCpp.hh:328
void StyleColor(bool active, Args &&...args)
Definition ImGuiCpp.hh:175
void Child(const char *str_id, const ImVec2 &size, ImGuiChildFlags child_flags, ImGuiWindowFlags window_flags, std::invocable<> auto next)
Definition ImGuiCpp.hh:110
void PopupModal(const char *name, bool *p_open, ImGuiWindowFlags flags, std::invocable<> auto next)
Definition ImGuiCpp.hh:404
void TextWrapPos(float wrap_local_pos_x, std::invocable<> auto next)
Definition ImGuiCpp.hh:212
bool Menu(const char *label, bool enabled, std::invocable<> auto next)
Definition ImGuiCpp.hh:359
void Disabled(bool b, std::invocable<> auto next)
Definition ImGuiCpp.hh:506
void Group(std::invocable<> auto next)
Definition ImGuiCpp.hh:236
void Font(ImFont *font, std::invocable<> auto next)
Definition ImGuiCpp.hh:131
void TabItem(const char *label, bool *p_open, ImGuiTabItemFlags flags, std::invocable<> auto next)
Definition ImGuiCpp.hh:489
void Tooltip(std::invocable<> auto next)
Definition ImGuiCpp.hh:374
void Indent(float indent_w, std::invocable<> auto next)
Definition ImGuiCpp.hh:224
void ListClipper(size_t count, int forceIndex, float lineHeight, std::invocable< int > auto next)
Definition ImGuiCpp.hh:538
void ListClipperID(size_t count, std::invocable< int > auto next)
Definition ImGuiCpp.hh:559
void Popup(const char *str_id, ImGuiWindowFlags flags, std::invocable<> auto next)
Definition ImGuiCpp.hh:391
void ID_for_range(std::integral auto count, std::invocable< int > auto next)
Definition ImGuiCpp.hh:281
void ItemTooltip(std::invocable<> auto next)
Definition ImGuiCpp.hh:382
ScopedFont(ImFont *font)
Definition ImGuiCpp.hh:139
ScopedFont(const ScopedFont &)=delete
ScopedFont(ScopedFont &&)=delete
ScopedFont & operator=(ScopedFont &&)=delete
ScopedFont & operator=(const ScopedFont &)=delete
constexpr auto xrange(T e)
Definition xrange.hh:132
constexpr auto begin(const zstring_view &x)
constexpr auto end(const zstring_view &x)