Nui
attribute_factory.hpp
Go to the documentation of this file.
1 #pragma once
2 
10 
11 #include <nui/frontend/val.hpp>
12 
13 namespace Nui::Attributes
14 {
15  namespace Detail
16  {
17  template <typename ElementT, typename T>
19  std::weak_ptr<ElementT> element,
20  T const& obs,
21  std::function<bool(std::shared_ptr<ElementT> const&)> onLock)
22  {
23  const auto eventId = globalEventContext.registerEvent(Event{
24  [element, obs, onLock = std::move(onLock)](auto eventId) {
25  if (auto shared = element.lock(); shared)
26  {
27  return onLock(shared);
28  }
29  obs.detachEvent(eventId);
30  return false;
31  },
32  [element]() {
33  return !element.expired();
34  }});
35  obs.attachEvent(eventId);
36  return eventId;
37  }
38 
39  template <typename ElementT, typename T>
40  EventContext::EventIdType defaultAttributeEvent(std::weak_ptr<ElementT> element, T const& obs, char const* name)
41  {
42  return changeEventHandler(
43  element,
44  obs,
45  std::function<bool(std::shared_ptr<ElementT> const&)>{
46  [name, obs](std::shared_ptr<ElementT> const& shared) {
47  shared->setAttribute(name, obs.value());
48  return true;
49  }});
50  }
51 
52  template <typename ElementT, typename T>
53  EventContext::EventIdType defaultPropertyEvent(std::weak_ptr<ElementT> element, T const& obs, char const* name)
54  {
55  return changeEventHandler(
56  element,
57  obs,
58  std::function<bool(std::shared_ptr<ElementT> const&)>{
59  [name, obs](std::shared_ptr<ElementT> const& shared) {
60  shared->setProperty(name, obs.value());
61  return true;
62  }});
63  }
64  }
65 
67  {
68  public:
69  explicit constexpr PropertyFactory(char const* name)
70  : name_{name}
71  {}
72 
73  explicit constexpr PropertyFactory(PropertyFactory const& other)
74  : name_{other.name_}
75  {}
76  explicit constexpr PropertyFactory(PropertyFactory&& other)
77  : name_{other.name_}
78  {}
81 
82  constexpr char const* name() const
83  {
84  return name_;
85  };
86 
87  template <typename U>
89  !IsObservedLike<std::decay_t<U>> && !std::invocable<U, Nui::val> && !std::invocable<U> &&
90  !Nui::Detail::IsProperty<std::decay_t<U>>)
91  Attribute operator=(U val) const
92  {
93  return Attribute{
94  [name = name(), val = std::move(val)](Dom::ChildlessElement& element) {
95  element.setProperty(name, val);
96  },
97  };
98  }
99 
100  template <typename U>
101  requires(IsSharedObserved<std::decay_t<U>>)
102  Attribute operator=(U const& shared) const
103  {
104  return Attribute{
105  [name = name(), weak = std::weak_ptr{shared}](Dom::ChildlessElement& element) {
106  if (auto shared = weak.lock(); shared)
107  element.setProperty(name, shared->value());
108  },
109  [name = name(), weak = std::weak_ptr{shared}](std::weak_ptr<Dom::ChildlessElement>&& element) {
110  auto shared = weak.lock();
111  if (!shared)
113 
114  const auto eventId = globalEventContext.registerEvent(Event{
115  [name, element, obsWeak = std::weak_ptr{shared}](auto eventId) {
116  auto obsShared = obsWeak.lock();
117  if (!obsShared)
118  {
119  return false;
120  }
121  if (auto shared = element.lock(); shared)
122  {
123  shared->setProperty(name, obsShared->value());
124  return true;
125  }
126  obsShared->detachEvent(eventId);
127  return false;
128  },
129  [element, obsWeak = std::weak_ptr{shared}]() {
130  return !element.expired() && !obsWeak.expired();
131  },
132  });
133  shared->attachEvent(eventId);
134  return eventId;
135  },
136  [weak = std::weak_ptr{shared}](EventContext::EventIdType id) {
137  if (auto shared = weak.lock(); shared)
138  shared->detachEvent(id);
139  },
140  };
141  }
142 
143  template <typename U>
144  requires(IsWeakObserved<std::decay_t<U>>)
145  Attribute operator=(U&& val) const
146  {
147  auto shared = val.lock();
148  if (!shared)
149  return Attribute{};
150 
151  return operator=(shared);
152  }
153 
154  template <typename U>
155  requires(IsObserved<std::decay_t<U>>)
156  Attribute operator=(U& val) const
157  {
158  return Attribute{
159  [name = name(), &val](Dom::ChildlessElement& element) {
160  element.setProperty(name, val.value());
161  },
162  [name = name(), &val](std::weak_ptr<Dom::ChildlessElement>&& element) {
164  std::move(element), Nui::Detail::CopyableObservedWrap{val}, name);
165  },
167  val.detachEvent(id);
168  },
169  };
170  }
171 
172  template <typename RendererType, typename... ObservedValues>
173  Attribute
174  operator=(ObservedValueCombinatorWithPropertyGenerator<RendererType, ObservedValues...> const& combinator) const
175  {
176  return Attribute{
177  [name = name(), combinator](Dom::ChildlessElement& element) {
178  element.setProperty(name, combinator.value());
179  },
180  [name = name(), combinator](std::weak_ptr<Dom::ChildlessElement>&& element) {
181  return Detail::defaultPropertyEvent(std::move(element), combinator, name);
182  },
183  [combinator](EventContext::EventIdType id) {
184  combinator.detachEvent(id);
185  },
186  };
187  }
188 
189  template <typename RendererType, typename... ObservedValues>
190  Attribute
191  operator=(ObservedValueCombinatorWithGenerator<RendererType, ObservedValues...> const& combinator) const
192  {
193  return Attribute{
194  [name = name(), combinator](Dom::ChildlessElement& element) {
195  element.setProperty(name, combinator.value());
196  },
197  [name = name(), combinator](std::weak_ptr<Dom::ChildlessElement>&& element) {
198  return Detail::defaultPropertyEvent(std::move(element), combinator, name);
199  },
200  [combinator](EventContext::EventIdType id) {
201  combinator.detachEvent(id);
202  },
203  };
204  }
205 
206  Attribute operator=(std::function<void(Nui::val)> func) const
207  {
208  return Attribute{
209  [name = name(), func = std::move(func)](Dom::ChildlessElement& element) {
210  element.setProperty(name, [func](Nui::val val) {
211  func(val);
213  });
214  },
215  };
216  }
217 
218  Attribute operator=(std::function<void()> func) const
219  {
220  return Attribute{
221  [name = name(), func = std::move(func)](Dom::ChildlessElement& element) {
222  element.setProperty(name, [func](Nui::val) {
223  func();
225  });
226  },
227  };
228  }
229 
230  private:
231  char const* name_;
232  };
233 
235  {
236  public:
237  explicit constexpr AttributeFactory(char const* name)
238  : name_{name}
239  {}
240 
241  explicit constexpr AttributeFactory(AttributeFactory const& other)
242  : name_{other.name_}
243  {}
244  explicit constexpr AttributeFactory(AttributeFactory&& other)
245  : name_{other.name_}
246  {}
249 
250  constexpr char const* name() const
251  {
252  return name_;
253  };
254 
255  template <typename U>
257  !IsObservedLike<std::decay_t<U>> && !std::invocable<U, Nui::val> && !std::invocable<U> &&
258  !Nui::Detail::IsProperty<std::decay_t<U>>)
259  Attribute operator=(U val) const
260  {
261  return Attribute{
262  [name = name(), val = std::move(val)](Dom::ChildlessElement& element) {
263  element.setAttribute(name, val);
264  },
265  };
266  }
267 
268  template <typename U>
269  requires(IsSharedObserved<std::decay_t<U>>)
270  Attribute operator=(U const& shared) const
271  {
272  return Attribute{
273  [name = name(), weak = std::weak_ptr{shared}](Dom::ChildlessElement& element) {
274  if (auto shared = weak.lock(); shared)
275  element.setAttribute(name, shared->value());
276  },
277  [name = name(), weak = std::weak_ptr{shared}](std::weak_ptr<Dom::ChildlessElement>&& element) {
278  auto shared = weak.lock();
279  if (!shared)
281 
282  const auto eventId = globalEventContext.registerEvent(Event{
283  [name, element, obsWeak = std::weak_ptr{shared}](auto eventId) {
284  auto obsShared = obsWeak.lock();
285  if (!obsShared)
286  {
287  return false;
288  }
289  if (auto shared = element.lock(); shared)
290  {
291  shared->setAttribute(name, obsShared->value());
292  return true;
293  }
294  obsShared->detachEvent(eventId);
295  return false;
296  },
297  [element, obsWeak = std::weak_ptr{shared}]() {
298  return !element.expired() && !obsWeak.expired();
299  },
300  });
301  shared->attachEvent(eventId);
302  return eventId;
303  },
304  [weak = std::weak_ptr{shared}](EventContext::EventIdType id) {
305  if (auto shared = weak.lock(); shared)
306  shared->detachEvent(id);
307  },
308  };
309  }
310 
311  template <typename U>
312  requires(IsWeakObserved<std::decay_t<U>>)
313  Attribute operator=(U&& val) const
314  {
315  auto shared = val.lock();
316  if (!shared)
317  return Attribute{};
318 
319  return operator=(shared);
320  }
321 
322  template <typename U>
323  requires(IsObserved<std::decay_t<U>>)
324  Attribute operator=(U& val) const
325  {
326  return Attribute{
327  [name = name(), &val](Dom::ChildlessElement& element) {
328  element.setAttribute(name, val.value());
329  },
330  [name = name(), &val](std::weak_ptr<Dom::ChildlessElement>&& element) {
332  std::move(element), Nui::Detail::CopyableObservedWrap{val}, name);
333  },
335  val.detachEvent(id);
336  },
337  };
338  }
339 
340  template <typename U>
341  requires(IsObserved<std::decay_t<U>>)
342  Attribute operator=(Nui::Detail::Property<U> const& prop) const
343  {
344  return Attribute{
345  [name = name(), p = prop.prop](Dom::ChildlessElement& element) {
346  element.setProperty(name, p->value());
347  },
348  [name = name(), p = prop.prop](std::weak_ptr<Dom::ChildlessElement>&& element) {
350  std::move(element), Nui::Detail::CopyableObservedWrap{*p}, name);
351  },
352  [p = prop.prop](EventContext::EventIdType id) {
353  p->detachEvent(id);
354  },
355  };
356  }
357 
358  template <typename U>
359  requires(IsWeakObserved<std::decay_t<U>>)
360  Attribute operator=(Nui::Detail::Property<U> const& prop) const
361  {
362  auto shared = prop.prop.lock();
363  if (!shared)
364  return Attribute{};
365 
366  return Attribute{
367  [name = name(), weak = std::weak_ptr{shared}](Dom::ChildlessElement& element) {
368  if (auto shared = weak.lock(); shared)
369  element.setProperty(name, shared->value());
370  },
371  [name = name(), weak = std::weak_ptr{shared}](std::weak_ptr<Dom::ChildlessElement>&& element) {
372  auto shared = weak.lock();
373  if (!shared)
375 
376  const auto eventId = globalEventContext.registerEvent(Event{
377  [name, element, obsWeak = std::weak_ptr{shared}](auto eventId) {
378  auto obsShared = obsWeak.lock();
379  if (!obsShared)
380  {
381  return false;
382  }
383  if (auto shared = element.lock(); shared)
384  {
385  shared->setProperty(name, obsShared->value());
386  return true;
387  }
388  obsShared->detachEvent(eventId);
389  return false;
390  },
391  [element, obsWeak = std::weak_ptr{shared}]() {
392  return !element.expired() && !obsWeak.expired();
393  },
394  });
395  shared->attachEvent(eventId);
396  return eventId;
397  },
398  [weak = std::weak_ptr{shared}](EventContext::EventIdType id) {
399  if (auto shared = weak.lock(); shared)
400  shared->detachEvent(id);
401  },
402  };
403  }
404 
405  template <typename U>
406  requires(!IsObservedLike<std::decay_t<U>> && !std::invocable<U, Nui::val> && !std::invocable<U>)
407  Attribute operator=(Nui::Detail::Property<U> const& prop) const
408  {
409  return Attribute{[name = name(), p = std::move(prop.prop)](Dom::ChildlessElement& element) {
410  element.setProperty(name, p);
411  }};
412  }
413 
414  template <typename RendererType, typename... ObservedValues>
415  Attribute
416  operator=(ObservedValueCombinatorWithPropertyGenerator<RendererType, ObservedValues...> const& combinator) const
417  {
418  return Attribute{
419  [name = name(), combinator](Dom::ChildlessElement& element) {
420  element.setProperty(name, combinator.value());
421  },
422  [name = name(), combinator](std::weak_ptr<Dom::ChildlessElement>&& element) {
423  return Detail::defaultPropertyEvent(std::move(element), combinator, name);
424  },
425  [combinator](EventContext::EventIdType id) {
426  combinator.detachEvent(id);
427  },
428  };
429  }
430 
431  template <typename RendererType, typename... ObservedValues>
432  Attribute
433  operator=(ObservedValueCombinatorWithGenerator<RendererType, ObservedValues...> const& combinator) const
434  {
435  return Attribute{
436  [name = name(), combinator](Dom::ChildlessElement& element) {
437  element.setAttribute(name, combinator.value());
438  },
439  [name = name(), combinator](std::weak_ptr<Dom::ChildlessElement>&& element) {
440  return Detail::defaultAttributeEvent(std::move(element), combinator, name);
441  },
442  [combinator](EventContext::EventIdType id) {
443  combinator.detachEvent(id);
444  },
445  };
446  }
447 
448  Attribute operator=(std::function<void(Nui::val)> func) const
449  {
450  return Attribute{
451  [name = name(), func = std::move(func)](Dom::ChildlessElement& element) {
452  element.setAttribute(name, [func](Nui::val val) {
453  func(val);
455  });
456  },
457  };
458  }
459 
460  Attribute operator=(std::function<void()> func) const
461  {
462  return Attribute{
463  [name = name(), func = std::move(func)](Dom::ChildlessElement& element) {
464  element.setAttribute(name, [func](Nui::val) {
465  func();
467  });
468  },
469  };
470  }
471 
472  Attribute operator=(Nui::Detail::Property<std::function<void(Nui::val)>> func) const
473  {
474  return Attribute{
475  [name = name(), func = std::move(func.prop)](Dom::ChildlessElement& element) {
476  element.setProperty(name, [func](Nui::val val) {
477  func(val);
479  });
480  },
481  };
482  }
483 
484  Attribute operator=(Nui::Detail::Property<std::function<void()>> func) const
485  {
486  return Attribute{
487  [name = name(), func = std::move(func.prop)](Dom::ChildlessElement& element) {
488  element.setProperty(name, [func](Nui::val) {
489  func();
491  });
492  },
493  };
494  }
495 
496  private:
497  char const* name_;
498  };
499 
501  {
502  public:
503  explicit constexpr EventFactory(char const* name)
504  : name_{name}
505  {}
506 
507  explicit constexpr EventFactory(EventFactory const& other)
508  : name_{other.name_}
509  {}
510  explicit constexpr EventFactory(EventFactory&& other)
511  : name_{other.name_}
512  {}
515 
516  constexpr char const* name() const
517  {
518  return name_;
519  };
520 
521  Attribute operator=(std::function<void()> func) const
522  {
523  return Attribute{
524  [name = name(), func = std::move(func)](Dom::ChildlessElement& element) {
525  element.addEventListener(name, [func](Nui::val) {
526  func();
528  });
529  },
530  };
531  }
532 
533  Attribute operator=(std::function<void(Nui::val)> func) const
534  {
535  return Attribute{
536  [name = name(), func = std::move(func)](Dom::ChildlessElement& element) {
537  element.addEventListener(name, [func](Nui::val val) {
538  func(std::move(val));
540  });
541  },
542  };
543  }
544 
545  private:
546  char const* name_;
547  };
548 
549  inline namespace Literals
550  {
551  constexpr AttributeFactory operator""_attr(char const* name, std::size_t)
552  {
553  return AttributeFactory{name};
554  }
555  constexpr PropertyFactory operator""_prop(char const* name, std::size_t)
556  {
557  return PropertyFactory{name};
558  }
559  constexpr EventFactory operator""_event(char const* name, std::size_t)
560  {
561  return EventFactory{name};
562  }
563  }
564 
565  namespace Detail
566  {
567  template <typename T>
568  struct DeferWrap
569  {
571 
572  template <typename... Args>
573  Attribute operator=(Args&&... args) const
574  {
575  auto attr = factory.operator=(std::forward<Args>(args)...);
576  attr.defer(true);
577  return attr;
578  };
579  };
580  }
581 
582  template <typename T>
584  std::is_same_v<T, AttributeFactory> || std::is_same_v<T, PropertyFactory> || std::is_same_v<T, EventFactory>)
585  Detail::DeferWrap<T> operator!(T const& factory)
586  {
587  return Detail::DeferWrap<T>{.factory = T{std::move(factory)}};
588  }
589 }
590 
591 #define MAKE_HTML_VALUE_ATTRIBUTE_RENAME(NAME, HTML_NAME) \
592  namespace Nui::Attributes \
593  { \
594  static constexpr auto NAME = AttributeFactory{HTML_NAME}; \
595  }
596 
597 #define MAKE_HTML_VALUE_ATTRIBUTE(NAME) MAKE_HTML_VALUE_ATTRIBUTE_RENAME(NAME, #NAME)
598 
599 #define MAKE_HTML_EVENT_ATTRIBUTE_RENAME(NAME, HTML_ACTUAL) \
600  namespace Nui::Attributes \
601  { \
602  namespace Names \
603  { \
604  static constexpr auto Attr##NAME = fixToLower(HTML_ACTUAL); \
605  } \
606  static constexpr auto NAME = AttributeFactory{Names::Attr##NAME}; \
607  }
608 
609 #define MAKE_HTML_EVENT_ATTRIBUTE(NAME) MAKE_HTML_EVENT_ATTRIBUTE_RENAME(NAME, #NAME)
Definition: attribute.hpp:15
Definition: attribute_factory.hpp:235
constexpr AttributeFactory(AttributeFactory const &other)
Definition: attribute_factory.hpp:241
constexpr char const * name() const
Definition: attribute_factory.hpp:250
constexpr AttributeFactory(char const *name)
Definition: attribute_factory.hpp:237
AttributeFactory & operator=(AttributeFactory &&)=delete
AttributeFactory & operator=(AttributeFactory const &)=delete
requires(!IsObservedLike< std::decay_t< U >> &&!std::invocable< U, Nui::val > &&!std::invocable< U > &&!Nui::Detail::IsProperty< std::decay_t< U >>) Attribute operator
constexpr AttributeFactory(AttributeFactory &&other)
Definition: attribute_factory.hpp:244
Definition: attribute_factory.hpp:501
Attribute operator=(std::function< void(Nui::val)> func) const
Definition: attribute_factory.hpp:533
EventFactory & operator=(EventFactory &&)=delete
constexpr char const * name() const
Definition: attribute_factory.hpp:516
constexpr EventFactory(EventFactory const &other)
Definition: attribute_factory.hpp:507
Attribute operator=(std::function< void()> func) const
Definition: attribute_factory.hpp:521
constexpr EventFactory(char const *name)
Definition: attribute_factory.hpp:503
constexpr EventFactory(EventFactory &&other)
Definition: attribute_factory.hpp:510
EventFactory & operator=(EventFactory const &)=delete
Definition: attribute_factory.hpp:67
PropertyFactory & operator=(PropertyFactory const &)=delete
constexpr PropertyFactory(PropertyFactory const &other)
Definition: attribute_factory.hpp:73
constexpr PropertyFactory(PropertyFactory &&other)
Definition: attribute_factory.hpp:76
constexpr PropertyFactory(char const *name)
Definition: attribute_factory.hpp:69
constexpr char const * name() const
Definition: attribute_factory.hpp:82
requires(!IsObservedLike< std::decay_t< U >> &&!std::invocable< U, Nui::val > &&!std::invocable< U > &&!Nui::Detail::IsProperty< std::decay_t< U >>) Attribute operator
PropertyFactory & operator=(PropertyFactory &&)=delete
The basic element cannot have children and does not hold explicit ownership of them.
Definition: childless_element.hpp:19
EventRegistry::EventIdType EventIdType
Definition: event_context.hpp:40
void executeActiveEventsImmediately()
Definition: event_context.hpp:64
constexpr static auto invalidEventId
Definition: event_context.hpp:41
EventIdType registerEvent(Event event)
Definition: event_context.hpp:52
Definition: event.hpp:40
EventContext::EventIdType changeEventHandler(std::weak_ptr< ElementT > element, T const &obs, std::function< bool(std::shared_ptr< ElementT > const &)> onLock)
Definition: attribute_factory.hpp:18
EventContext::EventIdType defaultPropertyEvent(std::weak_ptr< ElementT > element, T const &obs, char const *name)
Definition: attribute_factory.hpp:53
EventContext::EventIdType defaultAttributeEvent(std::weak_ptr< ElementT > element, T const &obs, char const *name)
Definition: attribute_factory.hpp:40
Definition: attribute_factory.hpp:14
requires(std::is_same_v< T, AttributeFactory >||std::is_same_v< T, PropertyFactory >||std::is_same_v< T, EventFactory >) Detail
Definition: attribute_factory.hpp:583
concept IsProperty
Definition: property.hpp:42
Definition: file_dialog.hpp:6
concept IsSharedObserved
Definition: observed_value.hpp:1453
concept IsObserved
Definition: observed_value.hpp:1451
thread_local EventContext globalEventContext
Definition: event_context.cpp:5
Attribute && operator!(Attribute &&attribute)
Definition: attribute.hpp:84
RendererType
Definition: materialize.hpp:43
emscripten::val val
Definition: val.hpp:5
concept IsWeakObserved
Definition: observed_value.hpp:1455
concept IsObservedLike
Definition: observed_value.hpp:1457
Definition: attribute_factory.hpp:569
T factory
Definition: attribute_factory.hpp:570
Attribute operator=(Args &&... args) const
Definition: attribute_factory.hpp:573
Definition: observed_value.hpp:1463
Definition: property.hpp:13
T prop
Definition: property.hpp:14