CYD-UI
A C++ library for building native graphic user interfaces
Loading...
Searching...
No Matches
component_contexts.cppm
Go to the documentation of this file.
1// Copyright (c) 2024, Víctor Castillo Agüero.
2// SPDX-License-Identifier: GPL-3.0-or-later
3
5
6import std;
7
8import fabric.logging;
9import fabric.async;
10
11export import :holder;
12export import :state;
13
14export template<typename ContextType>
16 constexpr static const char* type = refl::type_name<ContextUpdate<ContextType>>.data();
17 ContextType* ptr = nullptr;
18};
19
20export class with_context {
21public:
22 explicit with_context(std::initializer_list<cydui::components::component_holder_t> &&components) {
23 for (auto c: components) {
24 components_.append(c);
25 }
26 }
27
29 return components_;
30 }
31
32private:
34};
35
36export namespace cydui::components {
38 public:
39 context_store_t() = default;
40
41 template<typename T>
42 void add_context(const std::shared_ptr<T> &ptr) {
43 static constexpr refl::type_id_t type_id = refl::type_id<T>;
44 std::shared_ptr<void> ptr_ = std::static_pointer_cast<void>(ptr);
45
46 context_map_[type_id] = ptr_;
47 }
48
49 template<typename T>
50 std::optional<T*> find_context() {
51 static constexpr refl::type_id_t type_id = refl::type_id<T>;
52 if (context_map_.contains(type_id)) {
53 return static_cast<T*>(context_map_[type_id].get());
54 }
55 return std::nullopt;
56 }
57
58 bool empty() const {
59 return context_map_.empty();
60 }
61 private:
62 [[refl::ignore]]
63 std::unordered_map<refl::type_id_t, std::shared_ptr<void>> context_map_ { };
64 };
65}
66
67namespace cydui {
68 export struct use_context_delegate;
69
70 export template <typename ContextType>
71 struct use_context {
72 using ret_context_type = ContextType;
73 using context_type = std::remove_const_t<ContextType>;
74 static constexpr bool is_readonly = std::is_const_v<ContextType>;
75
76 friend struct use_context_delegate;
77
78 use_context() = default;
79
80 use_context(const use_context& other) = delete;
81
82 use_context& operator=(const use_context& other) = delete;
83
84 use_context(use_context&& other) noexcept
85 : ctx(other.ctx),
86 state(other.state) {
87 other.stop_listening();
88 if (other.owns_context) {
89 this->owns_context = true;
90
91 other.owns_context = false;
92 other.ctx = nullptr;
93 }
94 }
95
97 other.stop_listening();
98 stop_listening();
99 this->ctx = other.ctx;
100 this->state = other.state;
101 if (other.owns_context) {
102 this->owns_context = true;
103 other.owns_context = false;
104 }
105 return *this;
106 }
107
109 stop_listening();
110 if (owns_context) {
111 delete ctx;
112 }
113 }
114
116 return ctx;
117 }
118
120 return *ctx;
121 }
122
123 void notify() {
124 state->emit<ContextUpdate<context_type>>({ctx});
125 }
126
127 private:
128 void start_listening() {
129 stop_listening();
130
131 listener = state->window->on_event([&](ContextUpdate<context_type> ev) -> fabric::task<> {
132 if (ev.ptr == ctx) {
133 state->force_redraw();
134 }
135 co_return;
136 });
137 }
138 void stop_listening() {
139 if (listener.has_value()) {
140 listener.value().remove();
141 listener = std::nullopt;
142 }
143 }
144
145 private:
146 // This object will own the context if it couldn't be found and thus a default one was created
147 bool owns_context = false;
148 context_type* ctx = nullptr;
150
151 std::optional<fabric::async::listener<ContextUpdate<context_type>>> listener{std::nullopt};
152 };
153
154
155 // export template <typename T, typename F>
156 // struct bind {
157 // bind(F T::* field) {}
158 //
159 // bind& transform(std::function<F(const F&)>) {
160 // return *this;
161 // }
162 // };
163
164 export struct provide_context_delegate;
165
166 export template <typename ContextType>
168 using context_type = ContextType;
170
172 : context_(std::make_shared<context_type>()) {}
173
174 // provide_context(std::function<void()>) {}
175
176 // template <typename T, typename F>
177 // provide_context(bind<T, F> b) {}
178
179 provide_context(const provide_context& other) = default;
180
181 provide_context& operator=(const provide_context& other) = default;
182
183 provide_context(provide_context&& other) noexcept = default;
184
186
188 return context_.get();
189 }
190
192 return *context_;
193 }
194
195 void notify() {
196 state->emit<ContextUpdate<context_type>>({context_.get()});
197 }
198
200
201 operator std::shared_ptr<context_type>() {
202 return context_;
203 }
204
205 private:
206 // This object will own the context if it couldn't be found and thus a default one was created
207 components::component_state_ref state = nullptr;
208 std::shared_ptr<context_type> context_;
209 };
210
211
213 template <typename ContextType>
214 static void
216 it->state = state;
217 }
218 template <typename ContextType>
219 static void set_context(use_context<ContextType>* it, ContextType* ctx) {
220 it->ctx = ctx;
221 }
222 template <typename ContextType>
223 static void set_context(use_context<const ContextType>* it, ContextType* ctx) {
224 it->ctx = ctx;
225 }
226 template <typename ContextType>
227 static void set_owns_context(use_context<ContextType>* it, bool value) {
228 it->owns_context = value;
229 }
230 template <typename ContextType>
232 it->start_listening();
233 }
234 };
235
237 template <typename ContextType>
238 static void
240 it->state = state;
241 }
242 template <typename ContextType>
243 static void
244 set_context(provide_context<ContextType>* it, const std::shared_ptr<ContextType>& ctx) {
245 it->context_ = ctx;
246 }
247 };
248}
void add_context(const std::shared_ptr< T > &ptr)
cydui::components::component_holder_t build() const
with_context(std::initializer_list< cydui::components::component_holder_t > &&components)
std::shared_ptr< component_state_t > component_state_ref
static constexpr const char * type
static void set_context(provide_context< ContextType > *it, const std::shared_ptr< ContextType > &ctx)
static void set_state(provide_context< ContextType > *it, const components::component_state_ref &state)
provide_context(const provide_context &other)=default
components::component_holder_t operator>(with_context &&components)
provide_context(provide_context &&other) noexcept=default
provide_context & operator=(provide_context &&other)=default
provide_context & operator=(const provide_context &other)=default
static void set_context(use_context< const ContextType > *it, ContextType *ctx)
static void set_context(use_context< ContextType > *it, ContextType *ctx)
static void set_state(use_context< ContextType > *it, const cydui::components::component_state_ref &state)
static void set_owns_context(use_context< ContextType > *it, bool value)
static void start_listening(use_context< ContextType > *it)
use_context & operator=(use_context &&other)
use_context(const use_context &other)=delete
use_context(use_context &&other) noexcept
ret_context_type * operator->()
static constexpr bool is_readonly
use_context()=default
friend struct use_context_delegate
use_context & operator=(const use_context &other)=delete
ret_context_type & operator*()
std::remove_const_t< ContextType > context_type