psemek/libs/ui/source/impl/label_base.cpp

64 lines
2 KiB
C++

#include <psemek/ui/impl/label_base.hpp>
#include <psemek/react/map.hpp>
#include <psemek/react/join.hpp>
namespace psemek::ui::impl
{
label_base::label_base()
: font_(react::value<fonts::font *>(nullptr))
, glyphs_(react::value<std::vector<fonts::shaped_glyph>>(std::vector<fonts::shaped_glyph>{}))
, size_(react::map([](std::vector<fonts::shaped_glyph> const & glyphs, fonts::font * font){
if (!font)
return geom::vector{0.f, 0.f};
geom::box<float, 2> bbox;
for (auto const & glyph : glyphs)
bbox |= glyph.position;
return geom::vector{bbox[0].length(), font->size()[1]};
}, react::join(glyphs_), react::join(font_)))
, size_constraints_(react::map([](geom::vector<float, 2> const & size){
geom::box<float, 2> result;
result[0].min = size[0];
result[0].max = size_constraints::infinity;
result[1].min = size[1];
result[1].max = size_constraints::infinity;
return impl::size_constraints{result};
}, size_))
{}
react::value<size_constraints> label_base::size_constraints() const
{
return size_constraints_;
}
void label_base::draw(renderer & renderer)
{
if (!glyphs_ || !*glyphs_)
return;
auto const size = *size_;
auto const shape = this->shape();
geom::vector<float, 2> origin;
origin[0] = std::round(geom::lerp(shape[0].min, shape[0].max - size[0], lerp_factor(*halign_)));
origin[1] = std::round(geom::lerp(shape[1].min, shape[1].max - size[1], lerp_factor(*valign_)));
origin[1] += std::round((size[1] + (**font_)->xheight()) / 2.f);
for (auto const & glyph : **glyphs_)
renderer.draw_glyph(*glyph.texture, glyph.position + origin, glyph.texcoords, *color_);
}
void label_base::update(label const & value)
{
font_.set(value.font);
glyphs_.set(react::map([](std::string const & str, fonts::font * font) -> std::vector<fonts::shaped_glyph> {
if (!font)
return {};
return font->shape(str, {});
}, value.text, value.font));
color_ = value.color;
halign_ = value.halign;
valign_ = value.valign;
}
}