1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120 | #include <planet/telemetry/rate.hpp>
#include <planet/ui/baseplate.hpp>
#include <planet/ui/widget.hpp>
#include <planet/log.hpp>
namespace {
planet::telemetry::exponential_decay c_widget_list_length{
"planet_ui_baseplate_widget_count", 20};
planet::telemetry::exponential_decay c_hover_list_length{
"planet_ui_baseplate_hover_count", 5};
}
planet::ui::baseplate::~baseplate() {
if (not widgets.empty()) {
planet::log::warning(
"Baseplate still has", widgets.size(),
"widgets attached to it");
for (auto w : widgets) { w->baseplate = nullptr; }
}
}
void planet::ui::baseplate::start_frame_reset() {
c_widget_list_length.add_measurement(widgets.size());
// Hover handling
auto const now = std::chrono::steady_clock::now();
auto const elapsed = now - last_reset;
last_reset = now;
for (auto widget : widgets) {
if (widget->contains_global_coordinate(last_mouse.location)) {
widget->hover(widget->hover_time += elapsed);
current_hovers.push_back(widget);
std::erase(previous_hovers, widget);
}
}
c_hover_list_length.add_measurement(current_hovers.size());
for (auto widget : previous_hovers) {
widget->hover(widget->hover_time = {});
}
previous_hovers.clear();
std::swap(previous_hovers, current_hovers);
// Widgets and focus
if (soft_focus
and std::find(widgets.begin(), widgets.end(), soft_focus)
== widgets.end()) {
soft_focus = nullptr;
}
if (hard_focus
and std::find(widgets.begin(), widgets.end(), hard_focus)
== widgets.end()) {
hard_focus = nullptr;
}
widgets.clear();
}
void planet::ui::baseplate::add(widget_ptr const w) {
w->baseplate = this;
widgets.push_back(w);
update_if_better_soft_focus(w);
}
void planet::ui::baseplate::update_if_better_soft_focus(widget_ptr w) {
if (w->wants_focus()
and (not soft_focus or soft_focus->z_layer < w->z_layer)
and w->contains_global_coordinate(last_mouse.location)) {
soft_focus = w;
}
}
auto planet::ui::baseplate::forward_mouse() -> task_type {
try {
auto mouse = events.mouse.values();
while (true) {
last_mouse = co_await mouse.next();
// Look for the widget that should now have soft focus
soft_focus = nullptr;
for (widget_ptr w : widgets) { update_if_better_soft_focus(w); }
// Now send the event to the correct widget
if (auto *send_to = find_focused_widget(); send_to) {
send_to->events.mouse.push(last_mouse);
}
}
} catch (std::exception const &e) {
log::critical("Baseplate mouse forwarding exception", e.what());
}
}
auto planet::ui::baseplate::forward_keys() -> task_type {
try {
auto key = events.key.values();
while (true) {
auto const k = co_await key.next();
if (auto *send_to = find_focused_widget(); send_to) {
send_to->events.key.push(k);
}
}
} catch (std::exception const &e) {
log::critical("Baseplate key forwarding exception", e.what());
}
}
auto planet::ui::baseplate::forward_scroll() -> task_type {
try {
auto scroll = events.scroll.values();
while (true) {
auto const s = co_await scroll.next();
if (auto *send_to = find_focused_widget(); send_to) {
send_to->events.scroll.push(s);
}
}
} catch (std::exception const &e) {
log::critical("Baseplate scroll forwarding exception", e.what());
}
}
|