HikoGUI
A low latency retained GUI
Loading...
Searching...
No Matches
RadioButtonWidget.hpp
1// Copyright 2020 Pokitec
2// All rights reserved.
3
4#pragma once
5
6#include "TTauri/Widgets/Widget.hpp"
7#include "TTauri/GUI/DrawContext.hpp"
8#include "TTauri/Text/format10.hpp"
9#include "TTauri/Foundation/observable.hpp"
10#include <memory>
11#include <string>
12#include <array>
13#include <optional>
14#include <future>
15
16namespace tt {
17
18template<typename ValueType>
19class RadioButtonWidget : public Widget {
20protected:
21 float button_height;
22 float button_width;
23 float button_x;
24 float button_y;
25 float button_middle;
26 aarect button_rectangle;
27 aarect pip_rectangle;
28 aarect label_rectangle;
29 mat::T label_translate;
31
32 ValueType activeValue;
33
34public:
37
38 template<typename V>
39 RadioButtonWidget(Window &window, Widget *parent, V &&value, ValueType activeValue) noexcept :
41 activeValue(std::move(activeValue)),
42 value(std::forward<V>(value)),
43 label()
44 {
45 [[maybe_unused]] ttlet value_cbid = value.add_callback([this](auto...){
46 forceRedraw = true;
47 });
48 [[maybe_unused]] ttlet label_cbid = label.add_callback([this](auto...){
49 forceLayout = true;
50 });
51 }
52
54 }
55
56 RadioButtonWidget(const RadioButtonWidget &) = delete;
57 RadioButtonWidget &operator=(const RadioButtonWidget &) = delete;
59 RadioButtonWidget &operator=(RadioButtonWidget &&) = delete;
60
61 void layout(hires_utc_clock::time_point displayTimePoint) noexcept override {
62 Widget::layout(displayTimePoint);
63
64 // The label is located to the right of the toggle.
65 ttlet label_x = Theme::smallWidth + Theme::margin;
66 label_rectangle = aarect{
67 label_x, 0.0f,
68 rectangle().width() - label_x, rectangle().height()
69 };
70
71 labelCell = std::make_unique<TextCell>(*label, theme->labelStyle);
72 setFixedHeight(std::max(labelCell->heightForWidth(label_rectangle.width()), Theme::smallHeight));
73
74 // Prepare coordinates.
75 // The button is expanded by half a pixel on each side because it is round.
76 button_height = Theme::smallHeight + 1.0f;
77 button_width = Theme::smallHeight + 1.0f;
78 button_x = (Theme::smallWidth - Theme::smallHeight) - 0.5f;
79 button_y = (rectangle().height() - Theme::smallHeight) - 0.5f;
80 button_rectangle = aarect{button_x, button_y, button_width, button_height};
81 button_middle = button_y + button_height * 0.5f;
82
83 ttlet pip_x = (Theme::smallWidth - Theme::smallHeight) + 1.5f;
84 ttlet pip_y = (rectangle().height() - Theme::smallHeight) + 1.5f;
85 ttlet pip_width = Theme::smallHeight - 3.0f;
86 ttlet pip_height = Theme::smallHeight - 3.0f;
87 pip_rectangle = aarect{pip_x, pip_y, pip_width, pip_height};
88 }
89
90 void draw(DrawContext const &drawContext, hires_utc_clock::time_point displayTimePoint) noexcept override{
91 // button.
92 auto context = drawContext;
93 context.cornerShapes = vec{button_rectangle.height() * 0.5f};
94 context.drawBoxIncludeBorder(button_rectangle);
95
96 // draw pip
97 if (value == activeValue) {
98 if (*enabled && window.active) {
99 context.color = theme->accentColor;
100 }
101 std::swap(context.color, context.fillColor);
102 context.cornerShapes = vec{pip_rectangle.height() * 0.5f};
103 context.drawBoxIncludeBorder(pip_rectangle);
104 }
105
106 labelCell->draw(context, label_rectangle, Alignment::TopLeft, button_middle);
107 Widget::draw(drawContext, displayTimePoint);
108 }
109
110 void handleMouseEvent(MouseEvent const &event) noexcept override {
112
113 if (*enabled) {
114 if (
115 event.type == MouseEvent::Type::ButtonUp &&
116 event.cause.leftButton &&
117 rectangle().contains(event.position)
118 ) {
119 handleCommand("gui.activate"_ltag);
120 }
121 }
122 }
123
124 void handleCommand(string_ltag command) noexcept override {
125 if (!*enabled) {
126 return;
127 }
128
129 if (command == "gui.activate"_ltag) {
130 if (assign_and_compare(value, activeValue)) {
131 forceRedraw = true;
132 }
133 }
134 Widget::handleCommand(command);
135 }
136
137 [[nodiscard]] HitBox hitBoxTest(vec position) const noexcept override {
138 if (rectangle().contains(position)) {
139 return HitBox{this, elevation, *enabled ? HitBox::Type::Button : HitBox::Type::Default};
140 } else {
141 return HitBox{};
142 }
143 }
144
145 [[nodiscard]] bool acceptsFocus() const noexcept override {
146 return *enabled;
147 }
148};
149
150
151}
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
Definition RadioButtonWidget.hpp:19
void layout(hires_utc_clock::time_point displayTimePoint) noexcept override
Layout the widget.
Definition RadioButtonWidget.hpp:61
void handleCommand(string_ltag command) noexcept override
Handle command.
Definition RadioButtonWidget.hpp:124
void draw(DrawContext const &drawContext, hires_utc_clock::time_point displayTimePoint) noexcept override
Draw widget.
Definition RadioButtonWidget.hpp:90
bool acceptsFocus() const noexcept override
Check if the widget will accept keyboard focus.
Definition RadioButtonWidget.hpp:145
void handleMouseEvent(MouseEvent const &event) noexcept override
Definition RadioButtonWidget.hpp:110
HitBox hitBoxTest(vec position) const noexcept override
Find the widget that is under the mouse cursor.
Definition RadioButtonWidget.hpp:137
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 move(T... args)
T swap(T... args)