psemek/libs/ui/source/selector.cpp

126 lines
2.2 KiB
C++

#include <psemek/ui/selector.hpp>
#include <psemek/geom/contains.hpp>
#include <stdexcept>
namespace psemek::ui
{
selector::selector()
: container_(this)
{}
void selector::reshape(geom::box<float, 2> const & box)
{
shape_.box = box;
child_boxes_.clear();
auto st = merged_own_style();
geom::interval<float> x_range = geom::shrink<float>(box[0], (*st->inner_margin)[0]);
float y = box[1].min;
for (auto c : children())
{
float y_start = y;
y += (*st->inner_margin)[1];
if (c)
{
auto sc = c->size_constraints();
c->reshape({{x_range, {y, y + sc[1].min}}});
y += sc[1].min;
}
y += (*st->inner_margin)[1];
child_boxes_.push_back({{box[0], {y_start, y}}});
y += y_extra() * *st->scale;
}
}
geom::box<float, 2> selector::size_constraints() const
{
auto x_range = geom::interval<float>::full();
float y_sum = 0.f;
for (auto c : children())
{
if (!c) continue;
auto sc = c->size_constraints();
x_range &= sc[0];
y_sum += sc[1].min;
}
auto st = merged_own_style();
x_range += (*st->inner_margin)[0] * 2.f;
y_sum += (*st->inner_margin)[1] * 2.f * container_.size();
if (!container_.empty())
y_sum += *st->scale * y_extra() * static_cast<int>(container_.size() - 1);
return {{x_range, {y_sum, y_sum}}};
}
bool selector::on_event(mouse_move const & e)
{
auto const p = geom::cast<float>(e.position);
selected_ = std::nullopt;
for (std::size_t i = 0; i < child_boxes_.size(); ++i)
{
if (geom::contains(child_boxes_[i], p))
{
selected_ = i;
break;
}
}
return true;
}
bool selector::on_event(mouse_click const & e)
{
if (e.down && e.button == mouse_button::left && selected_ && callback_)
{
post([cb = callback_, i = *selected_]{ cb(i); });
return true;
}
return false;
}
std::size_t selector::size() const
{
return container_.size();
}
void selector::resize(std::size_t size)
{
container_.resize(size);
}
void selector::add(std::shared_ptr<element> child)
{
container_.add(child);
}
std::shared_ptr<element> selector::get(std::size_t index)
{
return container_.get(index);
}
void selector::on_selected(std::function<void(std::size_t)> callback)
{
callback_ = std::move(callback);
}
}