Skip to content

Commit 3457f88

Browse files
committed
Improved property support and attributes.
1 parent 02bb787 commit 3457f88

File tree

6 files changed

+540
-31
lines changed

6 files changed

+540
-31
lines changed

nui/include/nui/frontend/attributes/impl/attribute_factory.hpp

Lines changed: 170 additions & 30 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
#include <nui/frontend/event_system/event_context.hpp>
77
#include <nui/frontend/event_system/observed_value_combinator.hpp>
88
#include <nui/utility/fixed_string.hpp>
9+
#include <nui/frontend/property.hpp>
910

1011
#include <nui/frontend/val.hpp>
1112

@@ -17,7 +18,6 @@ namespace Nui::Attributes
1718
EventContext::EventIdType changeEventHandler(
1819
std::weak_ptr<ElementT> element,
1920
T const& obs,
20-
char const* name,
2121
std::function<bool(std::shared_ptr<ElementT> const&)> onLock)
2222
{
2323
const auto eventId = globalEventContext.registerEvent(Event{
@@ -42,7 +42,6 @@ namespace Nui::Attributes
4242
return changeEventHandler(
4343
element,
4444
obs,
45-
name,
4645
std::function<bool(std::shared_ptr<ElementT> const&)>{
4746
[name, obs](std::shared_ptr<ElementT> const& shared) {
4847
shared->setAttribute(name, obs.value());
@@ -56,40 +55,124 @@ namespace Nui::Attributes
5655
return changeEventHandler(
5756
element,
5857
obs,
59-
name,
6058
std::function<bool(std::shared_ptr<ElementT> const&)>{
6159
[name, obs](std::shared_ptr<ElementT> const& shared) {
6260
shared->setProperty(name, obs.value());
6361
return true;
6462
}});
6563
}
64+
}
6665

67-
template <typename T>
68-
struct Property
66+
class PropertyFactory
67+
{
68+
public:
69+
explicit constexpr PropertyFactory(char const* name)
70+
: name_{name}
71+
{}
72+
73+
// Dont use this class like a value
74+
PropertyFactory(PropertyFactory const&) = delete;
75+
PropertyFactory(PropertyFactory&&) = delete;
76+
PropertyFactory& operator=(PropertyFactory const&) = delete;
77+
PropertyFactory& operator=(PropertyFactory&&) = delete;
78+
79+
constexpr char const* name() const
6980
{
70-
T prop;
81+
return name_;
7182
};
7283

73-
template <IsObserved T>
74-
struct Property<T>
84+
template <typename U>
85+
requires(
86+
!IsObserved<std::decay_t<U>> && !std::invocable<U, Nui::val> && !std::invocable<U> &&
87+
!Nui::Detail::IsProperty<std::decay_t<U>>)
88+
Attribute operator=(U val) const
7589
{
76-
T const* prop;
77-
};
78-
}
90+
return Attribute{
91+
[name = name(), val = std::move(val)](Dom::ChildlessElement& element) {
92+
element.setProperty(name, val);
93+
},
94+
};
95+
}
7996

80-
template <typename U>
81-
requires(IsObserved<std::decay_t<U>>)
82-
Detail::Property<std::decay_t<U>> property(U& val)
83-
{
84-
return Detail::Property<std::decay_t<U>>{.prop = &val};
85-
}
97+
template <typename U>
98+
requires(IsObserved<std::decay_t<U>>)
99+
Attribute operator=(U& val) const
100+
{
101+
return Attribute{
102+
[name = name(), &val](Dom::ChildlessElement& element) {
103+
element.setProperty(name, val.value());
104+
},
105+
[name = name(), &val](std::weak_ptr<Dom::ChildlessElement>&& element) {
106+
return Detail::defaultPropertyEvent(
107+
std::move(element), Nui::Detail::CopiableObservedWrap{val}, name);
108+
},
109+
[&val](EventContext::EventIdType const& id) {
110+
val.unattachEvent(id);
111+
},
112+
};
113+
}
86114

87-
template <typename U>
88-
requires(!IsObserved<std::decay_t<U>>)
89-
Detail::Property<std::decay_t<U>> property(U val)
90-
{
91-
return Detail::Property<std::decay_t<U>>{.prop = std::move(val)};
92-
}
115+
template <typename RendererType, typename... ObservedValues>
116+
Attribute
117+
operator=(ObservedValueCombinatorWithPropertyGenerator<RendererType, ObservedValues...> const& combinator) const
118+
{
119+
return Attribute{
120+
[name = name(), combinator](Dom::ChildlessElement& element) {
121+
element.setProperty(name, combinator.value());
122+
},
123+
[name = name(), combinator](std::weak_ptr<Dom::ChildlessElement>&& element) {
124+
return Detail::defaultPropertyEvent(std::move(element), combinator, name);
125+
},
126+
[combinator](EventContext::EventIdType const& id) {
127+
combinator.unattachEvent(id);
128+
},
129+
};
130+
}
131+
132+
template <typename RendererType, typename... ObservedValues>
133+
Attribute
134+
operator=(ObservedValueCombinatorWithGenerator<RendererType, ObservedValues...> const& combinator) const
135+
{
136+
return Attribute{
137+
[name = name(), combinator](Dom::ChildlessElement& element) {
138+
element.setProperty(name, combinator.value());
139+
},
140+
[name = name(), combinator](std::weak_ptr<Dom::ChildlessElement>&& element) {
141+
return Detail::defaultPropertyEvent(std::move(element), combinator, name);
142+
},
143+
[combinator](EventContext::EventIdType const& id) {
144+
combinator.unattachEvent(id);
145+
},
146+
};
147+
}
148+
149+
Attribute operator=(std::function<void(Nui::val)> func) const
150+
{
151+
return Attribute{
152+
[name = name(), func = std::move(func)](Dom::ChildlessElement& element) {
153+
element.setProperty(name, [func](Nui::val val) {
154+
func(val);
155+
globalEventContext.executeActiveEventsImmediately();
156+
});
157+
},
158+
};
159+
}
160+
161+
Attribute operator=(std::function<void()> func) const
162+
{
163+
return Attribute{
164+
[name = name(), func = std::move(func)](Dom::ChildlessElement& element) {
165+
element.setProperty(name, [func](Nui::val) {
166+
func();
167+
globalEventContext.executeActiveEventsImmediately();
168+
});
169+
},
170+
};
171+
}
172+
173+
private:
174+
char const* name_;
175+
};
93176

94177
class AttributeFactory
95178
{
@@ -99,18 +182,20 @@ namespace Nui::Attributes
99182
{}
100183

101184
// Dont use this class like a value
102-
AttributeFactory(Attribute const&) = delete;
103-
AttributeFactory(Attribute&&) = delete;
104-
AttributeFactory& operator=(Attribute const&) = delete;
105-
AttributeFactory& operator=(Attribute&&) = delete;
185+
AttributeFactory(AttributeFactory const&) = delete;
186+
AttributeFactory(AttributeFactory&&) = delete;
187+
AttributeFactory& operator=(AttributeFactory const&) = delete;
188+
AttributeFactory& operator=(AttributeFactory&&) = delete;
106189

107190
constexpr char const* name() const
108191
{
109192
return name_;
110193
};
111194

112195
template <typename U>
113-
requires(!IsObserved<std::decay_t<U>> && !std::invocable<U, Nui::val> && !std::invocable<U>)
196+
requires(
197+
!IsObserved<std::decay_t<U>> && !std::invocable<U, Nui::val> && !std::invocable<U> &&
198+
!Nui::Detail::IsProperty<std::decay_t<U>>)
114199
Attribute operator=(U val) const
115200
{
116201
return Attribute{
@@ -119,6 +204,7 @@ namespace Nui::Attributes
119204
},
120205
};
121206
}
207+
122208
template <typename U>
123209
requires(IsObserved<std::decay_t<U>>)
124210
Attribute operator=(U& val) const
@@ -139,7 +225,7 @@ namespace Nui::Attributes
139225

140226
template <typename U>
141227
requires(IsObserved<std::decay_t<U>>)
142-
Attribute operator=(Detail::Property<U>&& prop) const
228+
Attribute operator=(Nui::Detail::Property<U> const& prop) const
143229
{
144230
return Attribute{
145231
[name = name(), p = prop.prop](Dom::ChildlessElement& element) {
@@ -156,13 +242,31 @@ namespace Nui::Attributes
156242
}
157243

158244
template <typename U>
159-
Attribute operator=(Detail::Property<U>&& prop) const
245+
requires(!IsObserved<std::decay_t<U>> && !std::invocable<U, Nui::val> && !std::invocable<U>)
246+
Attribute operator=(Nui::Detail::Property<U> const& prop) const
160247
{
161248
return Attribute{[name = name(), p = std::move(prop.prop)](Dom::ChildlessElement& element) {
162249
element.setProperty(name, p);
163250
}};
164251
}
165252

253+
template <typename RendererType, typename... ObservedValues>
254+
Attribute
255+
operator=(ObservedValueCombinatorWithPropertyGenerator<RendererType, ObservedValues...> const& combinator) const
256+
{
257+
return Attribute{
258+
[name = name(), combinator](Dom::ChildlessElement& element) {
259+
element.setProperty(name, combinator.value());
260+
},
261+
[name = name(), combinator](std::weak_ptr<Dom::ChildlessElement>&& element) {
262+
return Detail::defaultPropertyEvent(std::move(element), combinator, name);
263+
},
264+
[combinator](EventContext::EventIdType const& id) {
265+
combinator.unattachEvent(id);
266+
},
267+
};
268+
}
269+
166270
template <typename RendererType, typename... ObservedValues>
167271
Attribute
168272
operator=(ObservedValueCombinatorWithGenerator<RendererType, ObservedValues...> const& combinator) const
@@ -204,9 +308,45 @@ namespace Nui::Attributes
204308
};
205309
}
206310

311+
Attribute operator=(Nui::Detail::Property<std::function<void(Nui::val)>> func) const
312+
{
313+
return Attribute{
314+
[name = name(), func = std::move(func.prop)](Dom::ChildlessElement& element) {
315+
element.setProperty(name, [func](Nui::val val) {
316+
func(val);
317+
globalEventContext.executeActiveEventsImmediately();
318+
});
319+
},
320+
};
321+
}
322+
323+
Attribute operator=(Nui::Detail::Property<std::function<void()>> func) const
324+
{
325+
return Attribute{
326+
[name = name(), func = std::move(func.prop)](Dom::ChildlessElement& element) {
327+
element.setProperty(name, [func](Nui::val) {
328+
func();
329+
globalEventContext.executeActiveEventsImmediately();
330+
});
331+
},
332+
};
333+
}
334+
207335
private:
208336
char const* name_;
209337
};
338+
339+
inline namespace Literals
340+
{
341+
constexpr AttributeFactory operator""_attr(char const* name, std::size_t)
342+
{
343+
return AttributeFactory{name};
344+
}
345+
constexpr PropertyFactory operator""_prop(char const* name, std::size_t)
346+
{
347+
return PropertyFactory{name};
348+
}
349+
}
210350
}
211351

212352
#define MAKE_HTML_VALUE_ATTRIBUTE_RENAME(NAME, HTML_NAME) \

nui/include/nui/frontend/event_system/observed_value_combinator.hpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -91,10 +91,27 @@ namespace Nui
9191
return std::move(generator_);
9292
}
9393

94-
private:
94+
protected:
9595
const RendererType generator_;
9696
};
9797

98+
template <typename RendererType, typename... ObservedValues>
99+
class ObservedValueCombinatorWithPropertyGenerator
100+
: public ObservedValueCombinatorWithGenerator<RendererType, ObservedValues...>
101+
{
102+
public:
103+
using ObservedValueCombinatorWithGenerator<RendererType, ObservedValues...>::
104+
ObservedValueCombinatorWithGenerator;
105+
ObservedValueCombinatorWithPropertyGenerator(
106+
ObservedValueCombinatorWithGenerator<RendererType, ObservedValues...>&& other)
107+
: ObservedValueCombinatorWithGenerator<RendererType, ObservedValues...>{std::move(other)}
108+
{}
109+
110+
using ObservedValueCombinatorWithGenerator<RendererType, ObservedValues...>::split;
111+
using ObservedValueCombinatorWithGenerator<RendererType, ObservedValues...>::value;
112+
using ObservedValueCombinatorWithGenerator<RendererType, ObservedValues...>::generator;
113+
};
114+
98115
template <typename... ObservedValues>
99116
class ObservedValueCombinator : public ObservedValueCombinatorBase<ObservedValues...>
100117
{
@@ -110,6 +127,15 @@ namespace Nui
110127
return ObservedValueCombinatorWithGenerator<RendererType, ObservedValues...>{
111128
observedValues_, std::forward<RendererType>(generator)};
112129
}
130+
131+
template <typename RendererType>
132+
requires std::invocable<RendererType>
133+
constexpr ObservedValueCombinatorWithPropertyGenerator<RendererType, ObservedValues...>
134+
generateProperty(RendererType&& generator)
135+
{
136+
return ObservedValueCombinatorWithPropertyGenerator<RendererType, ObservedValues...>{
137+
observedValues_, std::forward<RendererType>(generator)};
138+
}
113139
};
114140
template <typename... ObservedValues>
115141
ObservedValueCombinator(ObservedValues const&...) -> ObservedValueCombinator<ObservedValues...>;

0 commit comments

Comments
 (0)