Reactive UI library wip: add floating, shape_reader and storage

This commit is contained in:
Nikita Lisitsa 2024-08-10 11:58:21 +03:00
parent ddddfb67ce
commit 4fde43313c
10 changed files with 284 additions and 0 deletions

View file

@ -0,0 +1,20 @@
#pragma once
#include <psemek/ui/aligned.hpp>
#include <psemek/react/value.hpp>
#include <psemek/geom/point.hpp>
#include <any>
namespace psemek::ui
{
struct floating
{
react::value<std::any> child = {};
react::value<geom::point<float, 2>> anchor = {0.f, 0.f};
react::value<halignment> halign = halignment::center;
react::value<valignment> valign = valignment::center;
};
}

View file

@ -0,0 +1,28 @@
#pragma once
#include <psemek/ui/floating.hpp>
#include <psemek/ui/impl/single_container.hpp>
#include <psemek/react/source.hpp>
namespace psemek::ui::impl
{
struct floating_base
: single_container
{
floating_base();
void reshape(geom::box<float, 2> const & new_shape) override;
react::value<struct size_constraints> size_constraints() const override;
void update(floating const & value);
private:
react::value<geom::point<float, 2>> anchor_ = geom::point{0.f, 0.f};
react::value<halignment> halign_ = halignment::center;
react::value<valignment> valign_ = valignment::center;
react::value<struct size_constraints> size_constraints_;
};
}

View file

@ -0,0 +1,23 @@
#pragma once
#include <psemek/ui/shape_reader.hpp>
#include <psemek/ui/impl/single_container.hpp>
namespace psemek::ui::impl
{
struct shape_reader_base
: single_container
{
shape_reader_base();
void reshape(geom::box<float, 2> const & new_shape) override;
react::value<struct size_constraints> size_constraints() const override;
void update(shape_reader const & value);
private:
react::source<geom::box<float, 2>> shape_ = {};
};
}

View file

@ -0,0 +1,29 @@
#pragma once
#include <psemek/ui/storage.hpp>
#include <psemek/ui/impl/single_container.hpp>
#include <psemek/react/source.hpp>
namespace psemek::ui::impl
{
struct storage_base
: single_container
{
storage_base();
void reshape(geom::box<float, 2> const & new_shape) override;
react::value<struct size_constraints> size_constraints() const override;
void set_child(std::unique_ptr<component> child) override;
std::unique_ptr<component> release_child() override;
void update(storage const & value);
private:
util::hash_map<std::string, react::source<std::any>> values_;
react::source<react::value<struct size_constraints>> child_size_constraints_;
react::value<struct size_constraints> size_constraints_;
};
}

View file

@ -0,0 +1,17 @@
#pragma once
#include <psemek/react/source.hpp>
#include <psemek/geom/box.hpp>
#include <any>
namespace psemek::ui
{
struct shape_reader
{
react::value<std::any> child = {};
react::source<geom::box<float, 2>> shape = {};
};
}

View file

@ -0,0 +1,19 @@
#pragma once
#include <psemek/react/source.hpp>
#include <psemek/geom/box.hpp>
#include <psemek/util/hash_table.hpp>
#include <any>
namespace psemek::ui
{
struct storage
{
react::value<std::any> child = {};
util::hash_map<std::string, react::source<std::any>> values = {};
};
}

View file

@ -13,6 +13,9 @@
#include <psemek/ui/impl/move_base.hpp>
#include <psemek/ui/impl/button_base.hpp>
#include <psemek/ui/impl/label_base.hpp>
#include <psemek/ui/impl/floating_base.hpp>
#include <psemek/ui/impl/shape_reader_base.hpp>
#include <psemek/ui/impl/storage_base.hpp>
namespace psemek::ui::impl
{
@ -31,6 +34,8 @@ namespace psemek::ui::impl
register_type<move, impl::move_base>();
register_type<button, impl::button_base>();
register_type<label, impl::label_base>();
register_type<floating, impl::floating_base>();
register_type<storage, impl::storage_base>();
}
}

View file

@ -0,0 +1,49 @@
#include <psemek/ui/impl/floating_base.hpp>
#include <psemek/ui/alignment.hpp>
#include <psemek/react/join.hpp>
#include <psemek/react/map.hpp>
namespace psemek::ui::impl
{
namespace
{
geom::box<float, 2> compute_child_shape(geom::box<float, 2> const & size_constraints, geom::point<float, 2> const & anchor, halignment halign, valignment valign)
{
geom::vector size{size_constraints[0].min, size_constraints[1].min};
geom::box<float, 2> result;
result[0] = geom::interval{- size[0], 0.f} + (1.f - lerp_factor(halign)) * size[0] + anchor[0];
result[1] = geom::interval{- size[1], 0.f} + (1.f - lerp_factor(valign)) * size[1] + anchor[1];
return result;
}
}
floating_base::floating_base()
: size_constraints_(impl::size_constraints::max())
{}
void floating_base::reshape(geom::box<float, 2> const & new_shape)
{
single_container::reshape(new_shape);
if (auto child = this->child())
child->reshape(compute_child_shape((*(child->size_constraints())).box, *anchor_, *halign_, *valign_));
}
react::value<struct size_constraints> floating_base::size_constraints() const
{
return size_constraints_;
}
void floating_base::update(floating const & value)
{
anchor_ = value.anchor;
halign_ = value.halign;
valign_ = value.valign;
}
}

View file

@ -0,0 +1,35 @@
#include <psemek/ui/impl/shape_reader_base.hpp>
namespace psemek::ui::impl
{
shape_reader_base::shape_reader_base()
: shape_(geom::box<float, 2>{{{0.f, 0.f}, {0.f, 0.f}}})
{}
void shape_reader_base::reshape(geom::box<float, 2> const & new_shape)
{
single_container::reshape(new_shape);
if (auto child = this->child())
child->reshape(new_shape);
shape_.set(new_shape);
}
react::value<struct size_constraints> shape_reader_base::size_constraints() const
{
if (auto child = this->child())
return child->size_constraints();
return size_constraints::max();
}
void shape_reader_base::update(shape_reader const & value)
{
shape_ = value.shape;
shape_.set(shape());
}
}

View file

@ -0,0 +1,59 @@
#include <psemek/ui/impl/storage_base.hpp>
#include <psemek/react/join.hpp>
namespace psemek::ui::impl
{
storage_base::storage_base()
: child_size_constraints_(size_constraints::max())
, size_constraints_(react::join(child_size_constraints_))
{}
void storage_base::reshape(geom::box<float, 2> const & new_shape)
{
single_container::reshape(new_shape);
if (auto child = this->child())
child->reshape(new_shape);
}
react::value<struct size_constraints> storage_base::size_constraints() const
{
if (auto child = this->child())
return child->size_constraints();
return impl::size_constraints::max();
}
void storage_base::set_child(std::unique_ptr<component> child)
{
if (child)
child_size_constraints_.set(child->size_constraints());
else
child_size_constraints_.set(size_constraints::max());
single_container::set_child(std::move(child));
}
std::unique_ptr<component> storage_base::release_child()
{
child_size_constraints_.set(size_constraints::max());
return single_container::release_child();
}
void storage_base::update(storage const & value)
{
util::hash_map<std::string, react::source<std::any>> new_values;
for (auto const & p : value.values)
{
auto & v = (new_values[p.first] = p.second);
if (auto it = values_.find(p.first); it != values_.end())
v.set(*(it->second));
}
values_ = std::move(new_values);
}
}