-
-
Notifications
You must be signed in to change notification settings - Fork 134
/
Copy pathfocus.h
102 lines (83 loc) · 2.56 KB
/
focus.h
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
#pragma once
#include <karm-app/inputs.h>
#include <karm-ui/node.h>
#include "funcs.h"
namespace Karm::Ui {
struct FocusEvent {
enum struct Type {
STEAL,
ENTER,
LEAVE,
};
using enum Type;
Type type;
FocusEvent(Type type) : type(type) {
}
};
struct FocusListener {
bool _focused = false;
void event(Ui::Node &n, App::Event &e) {
if (auto fe = e.is<FocusEvent>()) {
if (fe->type == FocusEvent::ENTER) {
_focused = true;
shouldRepaint(n);
} else if (fe->type == FocusEvent::LEAVE) {
_focused = false;
shouldRepaint(n);
}
}
}
bool focused() const {
return _focused;
}
operator bool() const {
return _focused;
}
};
struct Focusable : public ProxyNode<Focusable> {
bool _focused = false;
Focusable(Ui::Child child) : ProxyNode<Focusable>(std::move(child)) {
}
void paint(Gfx::Canvas &g, Math::Recti r) override {
ProxyNode<Focusable>::paint(g, r);
if (_focused) {
g.strokeStyle(Gfx::stroke(ACCENT600).withWidth(2).withAlign(Gfx::INSIDE_ALIGN));
g.stroke(bound().cast<f64>(), 4);
}
}
void event(App::Event &e) override {
bool passthrough = false;
if (auto fe = e.is<FocusEvent>()) {
if (fe->type == FocusEvent::STEAL and _focused) {
_focused = false;
shouldRepaint(*this);
event<FocusEvent>(*_child, FocusEvent::LEAVE);
}
} else if (auto me = e.is<App::MouseEvent>()) {
passthrough = true;
if (me->type == App::MouseEvent::PRESS) {
if (bound().contains(me->pos) and not _focused) {
bubble<FocusEvent>(*this, FocusEvent::STEAL);
_focused = true;
shouldRepaint(*this);
event<FocusEvent>(*_child, FocusEvent::ENTER);
} else if (not bound().contains(me->pos) and _focused) {
_focused = false;
shouldRepaint(*this);
event<FocusEvent>(*_child, FocusEvent::LEAVE);
}
}
}
if (_focused or passthrough)
ProxyNode<Focusable>::event(e);
}
};
static inline Ui::Child focusable(Ui::Child child) {
return makeStrong<Focusable>(std::move(child));
}
static inline auto focusable() {
return [](Ui::Child child) {
return focusable(std::move(child));
};
}
} // namespace Karm::Ui