Skip to content

Commit

Permalink
Merge pull request #77 from NuiCpp/devel
Browse files Browse the repository at this point in the history
Improve Attributes and Add Property Support
  • Loading branch information
5cript authored Sep 28, 2023
2 parents 28a6e9d + 2c63532 commit 83ea80c
Show file tree
Hide file tree
Showing 7 changed files with 700 additions and 13 deletions.
247 changes: 236 additions & 11 deletions nui/include/nui/frontend/attributes/impl/attribute_factory.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -6,6 +6,7 @@
#include <nui/frontend/event_system/event_context.hpp>
#include <nui/frontend/event_system/observed_value_combinator.hpp>
#include <nui/utility/fixed_string.hpp>
#include <nui/frontend/property.hpp>

#include <nui/frontend/val.hpp>

Expand All @@ -14,14 +15,16 @@ namespace Nui::Attributes
namespace Detail
{
template <typename ElementT, typename T>
EventContext::EventIdType defaultSetEvent(std::weak_ptr<ElementT> element, T const& obs, char const* name)
EventContext::EventIdType changeEventHandler(
std::weak_ptr<ElementT> element,
T const& obs,
std::function<bool(std::shared_ptr<ElementT> const&)> onLock)
{
const auto eventId = globalEventContext.registerEvent(Event{
[element, obs, name](auto eventId) {
[element, obs, onLock = std::move(onLock)](auto eventId) {
if (auto shared = element.lock(); shared)
{
shared->setAttribute(name, obs.value());
return true;
return onLock(shared);
}
obs.unattachEvent(eventId);
return false;
Expand All @@ -32,8 +35,145 @@ namespace Nui::Attributes
obs.attachEvent(eventId);
return eventId;
}

template <typename ElementT, typename T>
EventContext::EventIdType defaultAttributeEvent(std::weak_ptr<ElementT> element, T const& obs, char const* name)
{
return changeEventHandler(
element,
obs,
std::function<bool(std::shared_ptr<ElementT> const&)>{
[name, obs](std::shared_ptr<ElementT> const& shared) {
shared->setAttribute(name, obs.value());
return true;
}});
}

template <typename ElementT, typename T>
EventContext::EventIdType defaultPropertyEvent(std::weak_ptr<ElementT> element, T const& obs, char const* name)
{
return changeEventHandler(
element,
obs,
std::function<bool(std::shared_ptr<ElementT> const&)>{
[name, obs](std::shared_ptr<ElementT> const& shared) {
shared->setProperty(name, obs.value());
return true;
}});
}
}

class PropertyFactory
{
public:
explicit constexpr PropertyFactory(char const* name)
: name_{name}
{}

// Dont use this class like a value
PropertyFactory(PropertyFactory const&) = delete;
PropertyFactory(PropertyFactory&&) = delete;
PropertyFactory& operator=(PropertyFactory const&) = delete;
PropertyFactory& operator=(PropertyFactory&&) = delete;

constexpr char const* name() const
{
return name_;
};

template <typename U>
requires(
!IsObserved<std::decay_t<U>> && !std::invocable<U, Nui::val> && !std::invocable<U> &&
!Nui::Detail::IsProperty<std::decay_t<U>>)
Attribute operator=(U val) const
{
return Attribute{
[name = name(), val = std::move(val)](Dom::ChildlessElement& element) {
element.setProperty(name, val);
},
};
}

template <typename U>
requires(IsObserved<std::decay_t<U>>)
Attribute operator=(U& val) const
{
return Attribute{
[name = name(), &val](Dom::ChildlessElement& element) {
element.setProperty(name, val.value());
},
[name = name(), &val](std::weak_ptr<Dom::ChildlessElement>&& element) {
return Detail::defaultPropertyEvent(
std::move(element), Nui::Detail::CopiableObservedWrap{val}, name);
},
[&val](EventContext::EventIdType const& id) {
val.unattachEvent(id);
},
};
}

template <typename RendererType, typename... ObservedValues>
Attribute
operator=(ObservedValueCombinatorWithPropertyGenerator<RendererType, ObservedValues...> const& combinator) const
{
return Attribute{
[name = name(), combinator](Dom::ChildlessElement& element) {
element.setProperty(name, combinator.value());
},
[name = name(), combinator](std::weak_ptr<Dom::ChildlessElement>&& element) {
return Detail::defaultPropertyEvent(std::move(element), combinator, name);
},
[combinator](EventContext::EventIdType const& id) {
combinator.unattachEvent(id);
},
};
}

template <typename RendererType, typename... ObservedValues>
Attribute
operator=(ObservedValueCombinatorWithGenerator<RendererType, ObservedValues...> const& combinator) const
{
return Attribute{
[name = name(), combinator](Dom::ChildlessElement& element) {
element.setProperty(name, combinator.value());
},
[name = name(), combinator](std::weak_ptr<Dom::ChildlessElement>&& element) {
return Detail::defaultPropertyEvent(std::move(element), combinator, name);
},
[combinator](EventContext::EventIdType const& id) {
combinator.unattachEvent(id);
},
};
}

Attribute operator=(std::function<void(Nui::val)> func) const
{
return Attribute{
[name = name(), func = std::move(func)](Dom::ChildlessElement& element) {
element.setProperty(name, [func](Nui::val val) {
func(val);
globalEventContext.executeActiveEventsImmediately();
});
},
};
}

Attribute operator=(std::function<void()> func) const
{
return Attribute{
[name = name(), func = std::move(func)](Dom::ChildlessElement& element) {
element.setProperty(name, [func](Nui::val) {
func();
globalEventContext.executeActiveEventsImmediately();
});
},
};
}

private:
char const* name_;
};

class AttributeFactory
{
public:
Expand All @@ -42,18 +182,20 @@ namespace Nui::Attributes
{}

// Dont use this class like a value
AttributeFactory(Attribute const&) = delete;
AttributeFactory(Attribute&&) = delete;
AttributeFactory& operator=(Attribute const&) = delete;
AttributeFactory& operator=(Attribute&&) = delete;
AttributeFactory(AttributeFactory const&) = delete;
AttributeFactory(AttributeFactory&&) = delete;
AttributeFactory& operator=(AttributeFactory const&) = delete;
AttributeFactory& operator=(AttributeFactory&&) = delete;

constexpr char const* name() const
{
return name_;
};

template <typename U>
requires(!IsObserved<std::decay_t<U>> && !std::invocable<U, Nui::val> && !std::invocable<U>)
requires(
!IsObserved<std::decay_t<U>> && !std::invocable<U, Nui::val> && !std::invocable<U> &&
!Nui::Detail::IsProperty<std::decay_t<U>>)
Attribute operator=(U val) const
{
return Attribute{
Expand All @@ -62,6 +204,7 @@ namespace Nui::Attributes
},
};
}

template <typename U>
requires(IsObserved<std::decay_t<U>>)
Attribute operator=(U& val) const
Expand All @@ -71,13 +214,59 @@ namespace Nui::Attributes
element.setAttribute(name, val.value());
},
[name = name(), &val](std::weak_ptr<Dom::ChildlessElement>&& element) {
return Detail::defaultSetEvent(std::move(element), Nui::Detail::CopiableObservedWrap{val}, name);
return Detail::defaultAttributeEvent(
std::move(element), Nui::Detail::CopiableObservedWrap{val}, name);
},
[&val](EventContext::EventIdType const& id) {
val.unattachEvent(id);
},
};
}

template <typename U>
requires(IsObserved<std::decay_t<U>>)
Attribute operator=(Nui::Detail::Property<U> const& prop) const
{
return Attribute{
[name = name(), p = prop.prop](Dom::ChildlessElement& element) {
element.setProperty(name, p->value());
},
[name = name(), p = prop.prop](std::weak_ptr<Dom::ChildlessElement>&& element) {
return Detail::defaultPropertyEvent(
std::move(element), Nui::Detail::CopiableObservedWrap{*p}, name);
},
[p = prop.prop](EventContext::EventIdType const& id) {
p->unattachEvent(id);
},
};
}

template <typename U>
requires(!IsObserved<std::decay_t<U>> && !std::invocable<U, Nui::val> && !std::invocable<U>)
Attribute operator=(Nui::Detail::Property<U> const& prop) const
{
return Attribute{[name = name(), p = std::move(prop.prop)](Dom::ChildlessElement& element) {
element.setProperty(name, p);
}};
}

template <typename RendererType, typename... ObservedValues>
Attribute
operator=(ObservedValueCombinatorWithPropertyGenerator<RendererType, ObservedValues...> const& combinator) const
{
return Attribute{
[name = name(), combinator](Dom::ChildlessElement& element) {
element.setProperty(name, combinator.value());
},
[name = name(), combinator](std::weak_ptr<Dom::ChildlessElement>&& element) {
return Detail::defaultPropertyEvent(std::move(element), combinator, name);
},
[combinator](EventContext::EventIdType const& id) {
combinator.unattachEvent(id);
},
};
}

template <typename RendererType, typename... ObservedValues>
Attribute
operator=(ObservedValueCombinatorWithGenerator<RendererType, ObservedValues...> const& combinator) const
Expand All @@ -87,7 +276,7 @@ namespace Nui::Attributes
element.setAttribute(name, combinator.value());
},
[name = name(), combinator](std::weak_ptr<Dom::ChildlessElement>&& element) {
return Detail::defaultSetEvent(std::move(element), combinator, name);
return Detail::defaultAttributeEvent(std::move(element), combinator, name);
},
[combinator](EventContext::EventIdType const& id) {
combinator.unattachEvent(id);
Expand Down Expand Up @@ -119,9 +308,45 @@ namespace Nui::Attributes
};
}

Attribute operator=(Nui::Detail::Property<std::function<void(Nui::val)>> func) const
{
return Attribute{
[name = name(), func = std::move(func.prop)](Dom::ChildlessElement& element) {
element.setProperty(name, [func](Nui::val val) {
func(val);
globalEventContext.executeActiveEventsImmediately();
});
},
};
}

Attribute operator=(Nui::Detail::Property<std::function<void()>> func) const
{
return Attribute{
[name = name(), func = std::move(func.prop)](Dom::ChildlessElement& element) {
element.setProperty(name, [func](Nui::val) {
func();
globalEventContext.executeActiveEventsImmediately();
});
},
};
}

private:
char const* name_;
};

inline namespace Literals
{
constexpr AttributeFactory operator""_attr(char const* name, std::size_t)
{
return AttributeFactory{name};
}
constexpr PropertyFactory operator""_prop(char const* name, std::size_t)
{
return PropertyFactory{name};
}
}
}

#define MAKE_HTML_VALUE_ATTRIBUTE_RENAME(NAME, HTML_NAME) \
Expand Down
Loading

0 comments on commit 83ea80c

Please sign in to comment.