NexusForce 1.0.0
A rigorously engineered full-stack C++ backend library.
载入中...
搜索中...
未找到
component.hpp
浏览该文件的文档.
1#ifndef NEFORCE_TUI_COMPONENT_COMPONENT_HPP__
2#define NEFORCE_TUI_COMPONENT_COMPONENT_HPP__
3
12
18NEFORCE_BEGIN_NAMESPACE__
19NEFORCE_BEGIN_TUI__
20
25
31struct empty_props {};
32
37public:
38 virtual ~component_base() = default;
39
49 virtual element render() = 0;
50
56 virtual bool on_key(const key_event& e) {
57 ignore = e;
58 return false;
59 }
60
66 virtual bool on_mouse(const mouse_event& e) {
67 ignore = e;
68 return false;
69 }
70
76 virtual void on_mouse_leave() {}
77
85 void set_pass_through(bool v) noexcept { pass_through_ = v; }
86
91 NEFORCE_NODISCARD bool pass_through() const noexcept { return pass_through_; }
92
97 NEFORCE_NODISCARD bool has_focus() const noexcept { return has_focus_; }
98
103 void set_has_focus(bool v) noexcept { has_focus_ = v; }
104
109 virtual void on_animation(int64_t delta) { ignore = delta; }
110
116 virtual void setup() {}
117
123 virtual void cleanup() noexcept {}
124
132 virtual bool should_update() { return true; }
133
138 NEFORCE_NODISCARD component_base* parent() const noexcept { return parent_; }
139
144 NEFORCE_NODISCARD size_t child_count() const noexcept { return children_.size(); }
145
151 NEFORCE_NODISCARD component_base* child_at(size_t i) const noexcept { return children_[i].get(); }
152
157 NEFORCE_NODISCARD int index() const noexcept {
158 if (parent_ == nullptr) {
159 return -1;
160 }
161 for (size_t i = 0; i < parent_->children_.size(); ++i) {
162 if (parent_->children_[i].get() == this) {
163 return static_cast<int>(i);
164 }
165 }
166 return -1;
167 }
168
176 child->parent_ = this;
177 child->strand_ = strand_;
178 child->ctx_ = ctx_;
179 child->schedule_render_cb_ = schedule_render_cb_;
180 auto* raw = child.get();
181 children_.push_back(move(child));
182 raw->setup();
183 }
184
191 child->cleanup();
192 child->parent_ = nullptr;
193 for (auto it = children_.begin(); it != children_.end(); ++it) {
194 if (it->get() == child) {
195 auto owned = move(*it);
196 children_.erase(it);
197 return owned;
198 }
199 }
200 return nullptr;
201 }
202
207 NEFORCE_NODISCARD unique_ptr<component_base> detach() {
208 if (parent_ != nullptr) {
209 return parent_->remove_child(this);
210 }
211 return nullptr;
212 }
213
218 while (!children_.empty()) {
219 remove_child(children_.back().get());
220 }
221 }
222
227 NEFORCE_NODISCARD virtual bool focusable() const { return false; }
228
233 NEFORCE_NODISCARD component_base* active_child() noexcept { return active_child_; }
234
239 NEFORCE_NODISCARD const component_base* active_child() const noexcept { return active_child_; }
240
245 void set_active_child(component_base* child) noexcept { active_child_ = child; }
246
251 NEFORCE_NODISCARD bool active() const noexcept { return parent_ == nullptr || parent_->active_child() == this; }
252
257 NEFORCE_NODISCARD bool focused() const noexcept {
258 if (parent_ == nullptr) {
259 return true;
260 }
261 if (!active()) {
262 return false;
263 }
264 return parent_->focused();
265 }
266
270 virtual void take_focus() {
271 auto* focus = this;
272 for (auto* p = parent_; p != nullptr; p = p->parent_) {
273 p->set_active_child(focus);
274 focus = p;
275 }
276 }
277
284 if (schedule_render_cb_) {
285 schedule_render_cb_(this);
286 }
287 }
288
294 template <typename Ctx>
295 void provide_context(Ctx value) {
296 contexts_[typeid(Ctx).hash_code()] = _NEFORCE make_shared<Ctx>(_NEFORCE move(value));
297 }
298
304 template <typename Ctx>
305 NEFORCE_NODISCARD const Ctx& context() const {
306 for (const auto* p = this; p != nullptr; p = p->parent_) {
307 auto it = p->contexts_.find(typeid(Ctx).hash_code());
308 if (it != p->contexts_.end()) {
309 return *static_cast<const Ctx*>(it->second.get());
310 }
311 }
312 NEFORCE_THROW_EXCEPTION(value_exception("Context not found in component tree"));
313 }
314
315protected:
316 friend class reconciler;
317 friend class focus_manager;
318 friend class application;
319
322 bool has_focus_ = false;
323 bool pass_through_ = false;
324 strand* strand_ = nullptr;
325 io_context* ctx_ = nullptr;
327
328 virtual void collect_focusable(vector<component_base*>& out) {
329 if (focusable()) {
330 out.push_back(this);
331 }
332 for (const auto& child: children_) {
333 child->collect_focusable(out);
334 }
335 }
336
337private:
338 function<void(component_base*)> schedule_render_cb_;
340};
341
348template <typename P = empty_props>
349class component : public component_base {
350public:
351 using props_type = P;
352
353 component() = default;
354 ~component() override = default;
355 component(const component&) = delete;
356 component& operator=(const component&) = delete;
357 component(component&&) = delete;
358 component& operator=(component&&) = delete;
359
360protected:
365 NEFORCE_NODISCARD const props_type& props() const noexcept { return props_; }
366
377 template <typename T>
378 state<T>& create_state(T initial) {
379 auto s = _NEFORCE make_shared<state<T>>(this, *strand_, _NEFORCE move(initial));
380 states_.push_back(s);
381 return *s;
382 }
383
388 void set_props(props_type p) { props_ = _NEFORCE move(p); }
389
390private:
391 friend class reconciler;
392 friend class focus_manager;
393 friend class application;
394
395 props_type props_;
396 vector<shared_ptr<void>> states_;
397};
398
399
401template <typename T>
402void state<T>::schedule_render() {
403 if (owner_ != nullptr) {
404 owner_->schedule_render();
405 }
406}
408 // TUI
410
411NEFORCE_END_TUI__
412NEFORCE_END_NAMESPACE__
413#endif // NEFORCE_TUI_COMPONENT_COMPONENT_HPP__
函数包装器主模板声明
统一异步操作核心
串行化执行器
void add_child(unique_ptr< component_base > child)
注册子组件
strand * strand_
串行执行器
virtual bool on_key(const key_event &e)
键盘事件处理
component_base * active_child() noexcept
获取当前激活的子组件
void set_active_child(component_base *child) noexcept
设置激活的子组件
virtual element render()=0
声明式渲染
virtual void take_focus()
请求焦点
bool pass_through() const noexcept
是否启用事件穿透
component_base * parent_
父组件指针
bool active() const noexcept
是否处于激活状态
const component_base * active_child() const noexcept
获取当前激活的子组件
void set_pass_through(bool v) noexcept
设置事件穿透
int index() const noexcept
获取自身在父组件中的索引
bool has_focus() const noexcept
是否持有 Reconciler 键盘焦点
void provide_context(Ctx value)
设置上下文值
bool pass_through_
事件穿透标志
virtual void setup()
挂载回调
component_base * active_child_
当前激活的子组件
virtual bool focusable() const
是否可获取焦点
virtual void on_animation(int64_t delta)
动画帧回调
virtual void on_mouse_leave()
鼠标离开回调
bool has_focus_
reconciler 焦点状态
void schedule_render()
调度重渲染
bool focused() const noexcept
是否拥有焦点
io_context * ctx_
事件循环上下文
unique_ptr< component_base > remove_child(component_base *child)
移除子组件
const Ctx & context() const
获取上下文值
size_t child_count() const noexcept
获取子组件数量
component_base * child_at(size_t i) const noexcept
获取指定索引的子组件
component_base * parent() const noexcept
获取父组件
void detach_all_children()
移除所有子组件
unique_ptr< component_base > detach()
从父组件中脱离自身
void set_has_focus(bool v) noexcept
设置 Reconciler 焦点状态(由 Reconciler 调用)
virtual void cleanup() noexcept
卸载回调
vector< unique_ptr< component_base > > children_
子组件列表
virtual bool on_mouse(const mouse_event &e)
鼠标事件处理
virtual bool should_update()
是否需要更新
state< T > & create_state(T initial)
创建响应式状态变量
void set_props(props_type p)
注入属性
const props_type & props() const noexcept
获取父组件传入的属性
响应式状态变量
独占智能指针
constexpr pointer get() const noexcept
获取原始指针
动态大小数组容器
constexpr void push_back(const T &value)
在末尾拷贝插入元素
虚拟UI元素
TUI输入事件类型定义
long int64_t
64位有符号整数类型
enable_if_t<!is_unbounded_array_v< T > &&is_constructible_v< T, Args... >, shared_ptr< T > > make_shared(Args &&... args)
融合分配创建共享指针
constexpr Iterator2 move(Iterator1 first, Iterator1 last, Iterator2 result) noexcept(noexcept(inner::__move_aux(first, last, result)))
移动范围元素
响应式状态变量
独占智能指针
无序映射容器