Esp32-RBGridUI
Library for creating UIs for the RBController app
Loading...
Searching...
No Matches
widget.h
Go to the documentation of this file.
1#pragma once
2
3#include <functional>
4#include <map>
5#include <mutex>
6#include <stdint.h>
7
8#include "rbjson.h"
9
10namespace gridui {
11
12class _GridUi;
13
14namespace builder {
15class Widget;
16
17template <typename Self, typename Finished>
19};
20
21class WidgetState;
22
24 friend class WidgetState;
25public:
26 typedef void (*cb_trampoline_t)(void*, WidgetState*);
27 typedef void (*cb_deleter_t)(void*);
28
30 for(const auto& itr : m_callbacks) {
31 m_cb_deleter(itr.second);
32 }
33 }
34
35 void call(WidgetState* state, const std::string& event) {
36 auto itr = m_callbacks.find(event);
37 if (itr != m_callbacks.end()) {
38 (*m_cb_trampoline)(itr->second, state);
39 }
40 }
41
42 void add(const std::string& event, void *cb) {
43 auto itr = m_callbacks.find(event);
44 if(itr != m_callbacks.end()) {
45 m_cb_deleter(cb);
46 itr->second = cb;
47 } else {
48 m_callbacks[event] = cb;
49 }
50 }
51
52private:
53 CallbacksHolder(cb_trampoline_t trampoline, cb_deleter_t deleter) : m_cb_trampoline(trampoline), m_cb_deleter(deleter) { }
54
55 CallbacksHolder(const WidgetState&) = delete;
56 CallbacksHolder& operator=(const WidgetState&) = delete;
57
58 std::map<std::string, void*> m_callbacks;
59 const cb_trampoline_t m_cb_trampoline;
60 const cb_deleter_t m_cb_deleter;
61};
62
63class WidgetPos {
64 union {
65 uint32_t _encoded;
66 struct {
67 uint8_t _x;
68 uint8_t _y;
69 uint8_t _w;
70 uint8_t _h;
71 };
72 };
73
74public:
75 WidgetPos(uint32_t encoded) {
77 }
78 WidgetPos(float x, float y, float w, float h) {
79 _x = x*10.f;
80 _y = y*10.f;
81 _w = w*10.f;
82 _h = h*10.f;
83 }
84 uint32_t encoded() const { return _encoded; };
85 float x() const { return float(_x)/10.f; }
86 float y() const { return float(_y)/10.f; }
87 float w() const { return float(_w)/10.f; }
88 float h() const { return float(_h)/10.f; }
89 WidgetPos& setX(float x) { _x = x*10.f; return *this; }
90 WidgetPos& setY(float y) { _y = y*10.f; return *this; }
91 WidgetPos& setW(float w) { _w = w*10.f; return *this; }
92 WidgetPos& setH(float h) { _h = h*10.f; return *this; }
93};
94
101 friend class gridui::_GridUi;
102
103 template <typename Self, typename Finished>
105
106public:
107 WidgetState(uint16_t uuid, float x, float y, float w, float h, uint16_t tab);
108
109 uint16_t uuid() const { return m_uuid; }
110
111 std::string getString(const std::string& key, std::string def = "") const;
112 int64_t getInt(const std::string& key, int64_t def = 0) const;
113 double getDouble(const std::string& key, double def = 0.0) const;
114 bool getBool(const std::string& key, bool def = false) const;
115
116 bool set(const std::string& key, rbjson::Value* value);
117 bool setInnerObjectProp(const std::string& objectName, const std::string& propertyName,
118 rbjson::Value* value);
119
120 void markChanged(const std::string& key);
121
123 return bool(m_cb_holder);
124 }
125
126 WidgetPos pos() const {
127 return WidgetPos(getInt("p"));
128 }
129
130 void setPos(const WidgetPos& p) {
131 set("p", new rbjson::Number(p.encoded()));
132 }
133
134 // Use dataLocked only with sharedStateLock or uniqueStateLock locked.
135 // shared is for reads, unique for writes.
136 std::unique_lock<std::mutex> uniqueStateLock() {
137 return std::unique_lock<std::mutex>(m_mutex);
138 }
139 const rbjson::Object& dataLocked() const { return m_data; }
140
141private:
142 // Each mutex is ~100 bytes of heap allocation. Let's keep just one for this.
143 static std::mutex m_mutex;
144
145 WidgetState(const WidgetState&) = delete;
146 WidgetState& operator=(const WidgetState&) = delete;
147
148 rbjson::Object& data() { return m_data; }
149
150 void update(rbjson::Object* other) {
151 m_mutex.lock();
152 for (auto itr : other->members()) {
153 const std::string name_str(itr.name, itr.name_len);
154 m_data.set(name_str, itr.value->copy());
155 markGlobalChangedLocked(name_str);
156 }
157 m_mutex.unlock();
158 }
159
160 void addCallback(CallbacksHolder::cb_trampoline_t trampoline, CallbacksHolder::cb_deleter_t deleter, const std::string& event, void *cb) {
161 if (!m_cb_holder) {
162 m_cb_holder.reset(new CallbacksHolder(trampoline, deleter));
163 }
164 m_cb_holder->add(event, cb);
165 }
166
167 void call(const std::string& event) {
168 if (!m_cb_holder)
169 return;
170 m_cb_holder->call(this, event);
171 }
172
173 void markChangedLocked(const std::string& key);
174 void markGlobalChangedLocked(const std::string& key);
175 inline bool wasChangedInTickLocked(const char *key, size_t key_len) const;
176
177 bool popChanges(rbjson::Object& state);
178 bool remarkAllChanges();
179
180 rbjson::Object m_data;
181 std::unique_ptr<CallbacksHolder> m_cb_holder;
182
183 const uint16_t m_uuid;
184
185 uint16_t m_bloom_global;
186 uint16_t m_bloom_tick;
187};
188
189class Widget {
190public:
192 : m_state(&emptyState) {
193 }
194
195 Widget(const Widget&& o)
196 : m_state(o.m_state) {
197 }
198
199 Widget(const Widget& o)
200 : m_state(o.m_state) {
201 }
202
203 Widget& operator=(const Widget&& o) {
204 m_state = o.m_state;
205 return *this;
206 }
207
210 }
211
212 uint16_t uuid() const {
213 return m_state->uuid();
214 }
215
216 void setWidgetX(float val) {
217 m_state->setPos(m_state->pos().setX(val));
218 }
219
220 float widgetX() const {
221 return m_state->pos().x();
222 }
223
224 void setWidgetY(float val) {
225 m_state->setPos(m_state->pos().setY(val));
226 }
227
228 float widgetY() const {
229 return m_state->pos().y();
230 }
231
232 void setWidgetW(float val) {
233 m_state->setPos(m_state->pos().setW(val));
234 }
235
236 float widgetW() const {
237 return m_state->pos().w();
238 }
239
240 void setWidgetH(float val) {
241 m_state->setPos(m_state->pos().setH(val));
242 }
243
244 float widgetH() const {
245 return m_state->pos().h();
246 }
247
248 void setWidgetTab(uint16_t tab) {
249 m_state->set("tab", new rbjson::Number(tab));
250 }
251
252 uint16_t widgetTab() const {
253 return m_state->getInt("tab");
254 }
255
256 void setCss(const std::string& propertyName, const std::string& value) {
257 m_state->setInnerObjectProp("css", propertyName, new rbjson::String(value));
258 }
259
260 std::string css(const std::string& propertyName) const {
261 auto lock = m_state->uniqueStateLock();
262 auto* css = m_state->dataLocked().getObject("css");
263 if (css == nullptr)
264 return "";
265 return css->getString(propertyName);
266 }
267
268protected:
270 : m_state(state) {
271 }
272
273 Widget& operator=(const Widget&) = delete;
274
276
277private:
278 static WidgetState emptyState;
279};
280
281};
void call(WidgetState *state, const std::string &event)
Definition widget.h:35
void(*) cb_trampoline_t(void *, WidgetState *)
Definition widget.h:26
friend class WidgetState
Definition widget.h:24
void(*) cb_deleter_t(void *)
Definition widget.h:27
void add(const std::string &event, void *cb)
Definition widget.h:42
WidgetPos(uint32_t encoded)
Definition widget.h:75
float x() const
Definition widget.h:85
WidgetPos & setX(float x)
Definition widget.h:89
WidgetPos & setW(float w)
Definition widget.h:91
uint32_t encoded() const
Definition widget.h:84
WidgetPos & setY(float y)
Definition widget.h:90
float w() const
Definition widget.h:87
WidgetPos(float x, float y, float w, float h)
Definition widget.h:78
float h() const
Definition widget.h:88
float y() const
Definition widget.h:86
WidgetPos & setH(float h)
Definition widget.h:92
uint32_t _encoded
Definition widget.h:65
bool set(const std::string &key, rbjson::Value *value)
Definition widget.cpp:47
uint16_t uuid() const
Definition widget.h:109
void setPos(const WidgetPos &p)
Definition widget.h:130
bool setInnerObjectProp(const std::string &objectName, const std::string &propertyName, rbjson::Value *value)
Definition widget.cpp:64
bool hasRegisteredCallbacks() const
Definition widget.h:122
void markChanged(const std::string &key)
Definition widget.cpp:142
std::string getString(const std::string &key, std::string def="") const
Definition widget.cpp:27
WidgetState(uint16_t uuid, float x, float y, float w, float h, uint16_t tab)
Definition widget.cpp:13
std::unique_lock< std::mutex > uniqueStateLock()
Definition widget.h:136
WidgetPos pos() const
Definition widget.h:126
int64_t getInt(const std::string &key, int64_t def=0) const
Definition widget.cpp:32
bool getBool(const std::string &key, bool def=false) const
Definition widget.cpp:42
double getDouble(const std::string &key, double def=0.0) const
Definition widget.cpp:37
const rbjson::Object & dataLocked() const
Definition widget.h:139
std::string css(const std::string &propertyName) const
Definition widget.h:260
float widgetY() const
Definition widget.h:228
float widgetH() const
Definition widget.h:244
void setCss(const std::string &propertyName, const std::string &value)
Definition widget.h:256
bool hasRegisteredCallbacks() const
Definition widget.h:208
WidgetState * m_state
Definition widget.h:275
void setWidgetW(float val)
Definition widget.h:232
float widgetX() const
Definition widget.h:220
Widget & operator=(const Widget &&o)
Definition widget.h:203
Widget(WidgetState *state)
Definition widget.h:269
void setWidgetTab(uint16_t tab)
Definition widget.h:248
void setWidgetX(float val)
Definition widget.h:216
void setWidgetH(float val)
Definition widget.h:240
Widget(const Widget &o)
Definition widget.h:199
uint16_t uuid() const
Definition widget.h:212
float widgetW() const
Definition widget.h:236
Widget(const Widget &&o)
Definition widget.h:195
uint16_t widgetTab() const
Definition widget.h:252
void setWidgetY(float val)
Definition widget.h:224
Widget & operator=(const Widget &)=delete
Definition arm.h:8