Implement underline & strikethrough in ui::label

This commit is contained in:
Nikita Lisitsa 2022-05-20 17:05:51 +03:00
parent b9b3e7577b
commit a9de6232de
2 changed files with 70 additions and 0 deletions

View file

@ -106,6 +106,9 @@ namespace psemek::ui
void update_cached_state() const;
cached_state cached_state_for(geom::box<float, 2> const & bbox) const;
mutable std::shared_ptr<gfx::texture_2d> single_white_pixel_texture_;
std::shared_ptr<gfx::texture_2d> single_white_pixel_texture() const;
};
}

View file

@ -141,6 +141,9 @@ namespace psemek::ui
auto font = st->text_style->is_set(text_style_flag::bold) ? st->bold_font.get() : st->font.get();
bool const underline = st->text_style->is_set(text_style_flag::underline);
bool const strikethrough = st->text_style->is_set(text_style_flag::strikethrough);
if (!font) return state;
shape_options opts;
@ -242,6 +245,12 @@ namespace psemek::ui
float max_line_size = 0.f;
float const underline_width = *(st->text_scale);
float const strikethrough_width = *(st->text_scale);
std::vector<geom::box<float, 2>> underline_box(lines.size());
std::vector<geom::box<float, 2>> strikethrough_box(lines.size());
for (std::size_t l = 0; l < lines.size(); ++l)
{
geom::interval<float> x_range;
@ -290,6 +299,14 @@ namespace psemek::ui
break;
}
underline_box[l][0] = x_range + offset[0];
underline_box[l][1].min = offset[1] + font->size()[1] * (*st->text_scale);
underline_box[l][1].max = underline_box[l][1].min + underline_width;
strikethrough_box[l][0] = x_range + offset[0];
strikethrough_box[l][1].min = offset[1] + font->size()[1] * (*st->text_scale) / 2.f;
strikethrough_box[l][1].max = strikethrough_box[l][1].min + strikethrough_width;
for (std::size_t i = lines[l].first; i < lines[l].second; ++i)
{
glyphs[i].position += offset;
@ -315,10 +332,60 @@ namespace psemek::ui
}
}
if (underline)
{
auto & batch = state.batches.emplace_back();
batch.texture = single_white_pixel_texture().get();
for (auto const & u : underline_box)
{
auto & image = batch.images.emplace_back();
image.position = u;
image.texcoords = {{{0.f, 1.f}, {0.f, 1.f}}};
}
}
if (strikethrough)
{
auto & batch = state.batches.emplace_back();
batch.texture = single_white_pixel_texture().get();
for (auto const & u : strikethrough_box)
{
auto & image = batch.images.emplace_back();
image.position = u;
image.texcoords = {{{0.f, 1.f}, {0.f, 1.f}}};
}
}
state.size[0] = max_line_size;
state.size[1] = lines.size() * (*st->text_scale) * font->size()[1];
return state;
}
std::shared_ptr<gfx::texture_2d> label::single_white_pixel_texture() const
{
static std::weak_ptr<gfx::texture_2d> texture;
if (!single_white_pixel_texture_)
{
std::shared_ptr<gfx::texture_2d> ptr;
if (!(ptr = texture.lock()))
{
ptr = std::make_shared<gfx::texture_2d>();
gfx::pixmap_rgba pm({1, 1}, {255, 255, 255, 255});
ptr->load(pm);
ptr->nearest_filter();
texture = ptr;
}
single_white_pixel_texture_ = ptr;
}
return single_white_pixel_texture_;
}
}