HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
CheckboxWidget.hpp
1// Copyright 2020 Pokitec
2// All rights reserved.
3
4#pragma once
5
6#include "TTauri/Widgets/Widget.hpp"
7#include "TTauri/Cells/TextCell.hpp"
8#include "TTauri/GUI/DrawContext.hpp"
9#include "TTauri/Text/FontBook.hpp"
10#include "TTauri/Text/format10.hpp"
11#include "TTauri/Foundation/observable.hpp"
12#include <memory>
13#include <string>
14#include <array>
15#include <optional>
16#include <future>
17
18namespace tt {
19
20template<typename ValueType>
21class CheckboxWidget : public Widget {
22protected:
23 char32_t check = 0x2713;
24
26
27 FontGlyphIDs checkGlyph;
28 aarect checkBoundingBox;
29
30 float button_height;
31 float button_width;
32 float button_x;
33 float button_y;
34 float button_middle;
35 aarect button_rectangle;
36
37 aarect label_rectangle;
38
39 mat::T label_translate;
40 aarect check_rectangle;
41
42 ValueType trueValue;
43 ValueType falseValue;
44
45public:
48
49 template<typename V>
50 CheckboxWidget(Window &window, Widget *parent, V &&value, ValueType trueValue, ValueType falseValue) noexcept :
52 trueValue(trueValue),
53 falseValue(falseValue),
54 value(std::forward<V>(value)),
55 label()
56 {
57 [[maybe_unused]] ttlet value_cbid = value.add_callback([this](auto...){
58 forceRedraw = true;
59 });
60
61 [[maybe_unused]] ttlet label_cbid = label.add_callback([this](auto...){
62 forceLayout = true;
63 });
64 }
65
67
68 CheckboxWidget(const CheckboxWidget &) = delete;
69 CheckboxWidget &operator=(const CheckboxWidget &) = delete;
71 CheckboxWidget &operator=(CheckboxWidget &&) = delete;
72
73 void layout(hires_utc_clock::time_point displayTimePoint) noexcept override {
74 Widget::layout(displayTimePoint);
75
76 // The label is located to the right of the toggle.
77 ttlet label_x = Theme::smallWidth + Theme::margin;
78 label_rectangle = aarect{
79 label_x, 0.0f,
80 rectangle().width() - label_x, rectangle().height()
81 };
82
83 ttlet labelText = *label;
84 labelCell = std::make_unique<TextCell>(labelText, theme->labelStyle);
85 setFixedHeight(std::max(labelCell->heightForWidth(label_rectangle.width()), Theme::smallHeight));
86
87 button_height = Theme::smallHeight;
88 button_width = Theme::smallHeight;
89 button_x = Theme::smallWidth - button_width;
90 button_y = rectangle().height() - button_height;
91 button_rectangle = aarect{button_x, button_y, button_width, button_height};
92 button_middle = button_y + button_height * 0.5f;
93
94
95 ttlet checkFontId = fontBook->find_font("Arial", FontWeight::Regular, false);
96 checkGlyph = fontBook->find_glyph(checkFontId, Grapheme{check});
97 checkBoundingBox = scale(checkGlyph.getBoundingBox(), button_height * 1.2f);
98
99 check_rectangle = align(button_rectangle, checkBoundingBox, Alignment::MiddleCenter);
100 }
101
102 void draw(DrawContext const &drawContext, hires_utc_clock::time_point displayTimePoint) noexcept override {
103 // button.
104 auto context = drawContext;
105 context.drawBoxIncludeBorder(button_rectangle);
106
107 if (*enabled && window.active) {
108 context.color = theme->accentColor;
109 }
110
111 // Checkmark or tristate.
112 if (value == trueValue) {
113 context.transform = drawContext.transform * mat::T{0.0, 0.0, 0.001f};
114 context.drawGlyph(checkGlyph, check_rectangle);
115 } else if (value == falseValue) {
116 ;
117 } else {
118 std::swap(context.color, context.fillColor);
119 context.transform = drawContext.transform * mat::T{0.0, 0.0, 0.001f};
120 context.drawFilledQuad(shrink(button_rectangle, 3.0f));
121 }
122
123 labelCell->draw(context, label_rectangle, Alignment::TopLeft, button_middle);
124 Widget::draw(drawContext, displayTimePoint);
125 }
126
127 void handleMouseEvent(MouseEvent const &event) noexcept override {
129
130 if (*enabled) {
131 if (
132 event.type == MouseEvent::Type::ButtonUp &&
133 event.cause.leftButton &&
134 rectangle().contains(event.position)
135 ) {
136 handleCommand("gui.activate"_ltag);
137 }
138 }
139 }
140
141 void handleCommand(string_ltag command) noexcept override {
142 if (!*enabled) {
143 return;
144 }
145
146 if (command == "gui.activate"_ltag) {
147 if (assign_and_compare(value, value == falseValue ? trueValue : falseValue)) {
148 forceRedraw = true;
149 }
150 }
151 Widget::handleCommand(command);
152 }
153
154 [[nodiscard]] HitBox hitBoxTest(vec position) const noexcept override {
155 if (rectangle().contains(position)) {
156 return HitBox{this, elevation, *enabled ? HitBox::Type::Button : HitBox::Type::Default};
157 } else {
158 return HitBox{};
159 }
160 }
161
162 [[nodiscard]] bool acceptsFocus() const noexcept override {
163 return *enabled;
164 }
165};
166
167
168}
Class which represents an axis-aligned rectangle.
Definition aarect.hpp:13
Optimized translate matrix.
Definition mat.hpp:119
Definition observable.hpp:20
A 4D vector.
Definition vec.hpp:37
Draw context for drawing using the TTauri shaders.
Definition DrawContext.hpp:30
Definition HitBox.hpp:12
Definition MouseEvent.hpp:12
static constexpr float smallHeight
The height of smaller widget like labels, toggles, checkboxes and radio buttons.
Definition Theme.hpp:47
static constexpr float smallWidth
The width of smaller widget like labels, toggles, checkboxes and radio buttons.
Definition Theme.hpp:53
static constexpr float margin
Distance between widgets and between widgets and the border of the container.
Definition Theme.hpp:33
std::atomic< bool > active
Definition Window_base.hpp:86
Definition Window_vulkan_win32.hpp:15
FontGlyphIDs find_glyph(FontID font_id, Grapheme grapheme) const noexcept
Find a glyph using the given code-point.
FontID find_font(FontFamilyID family_id, FontVariant variant) const noexcept
Find a font closest to the variant.
Definition FontGlyphIDs.hpp:77
Definition Grapheme.hpp:20
Definition CheckboxWidget.hpp:21
HitBox hitBoxTest(vec position) const noexcept override
Find the widget that is under the mouse cursor.
Definition CheckboxWidget.hpp:154
void layout(hires_utc_clock::time_point displayTimePoint) noexcept override
Layout the widget.
Definition CheckboxWidget.hpp:73
void handleCommand(string_ltag command) noexcept override
Handle command.
Definition CheckboxWidget.hpp:141
void draw(DrawContext const &drawContext, hires_utc_clock::time_point displayTimePoint) noexcept override
Draw widget.
Definition CheckboxWidget.hpp:102
bool acceptsFocus() const noexcept override
Check if the widget will accept keyboard focus.
Definition CheckboxWidget.hpp:162
void handleMouseEvent(MouseEvent const &event) noexcept override
Definition CheckboxWidget.hpp:127
Definition Widget.hpp:64
virtual void handleCommand(string_ltag command) noexcept
Handle command.
Widget(Window &window, Widget *parent, vec defaultExtent) noexcept
observable< bool > enabled
The widget is enabled.
Definition Widget.hpp:150
virtual void handleMouseEvent(MouseEvent const &event) noexcept
Definition Widget.hpp:374
virtual void layout(hires_utc_clock::time_point displayTimePoint) noexcept
Layout the widget.
virtual void draw(DrawContext const &drawContext, hires_utc_clock::time_point displayTimePoint) noexcept
Draw widget.
aarect rectangle() const noexcept
Get the rectangle in local coordinates.
Definition Widget.hpp:273
T max(T... args)
T swap(T... args)