From a9de6232de810b21ab6344990761be396faeff08 Mon Sep 17 00:00:00 2001 From: lisyarus Date: Fri, 20 May 2022 17:05:51 +0300 Subject: [PATCH] Implement underline & strikethrough in ui::label --- libs/ui/include/psemek/ui/label.hpp | 3 ++ libs/ui/source/label.cpp | 67 +++++++++++++++++++++++++++++ 2 files changed, 70 insertions(+) diff --git a/libs/ui/include/psemek/ui/label.hpp b/libs/ui/include/psemek/ui/label.hpp index f998de65..f1adff0e 100644 --- a/libs/ui/include/psemek/ui/label.hpp +++ b/libs/ui/include/psemek/ui/label.hpp @@ -106,6 +106,9 @@ namespace psemek::ui void update_cached_state() const; cached_state cached_state_for(geom::box const & bbox) const; + + mutable std::shared_ptr single_white_pixel_texture_; + std::shared_ptr single_white_pixel_texture() const; }; } diff --git a/libs/ui/source/label.cpp b/libs/ui/source/label.cpp index b11c3e4b..c0e001fe 100644 --- a/libs/ui/source/label.cpp +++ b/libs/ui/source/label.cpp @@ -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> underline_box(lines.size()); + std::vector> strikethrough_box(lines.size()); + for (std::size_t l = 0; l < lines.size(); ++l) { geom::interval 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 label::single_white_pixel_texture() const + { + static std::weak_ptr texture; + + if (!single_white_pixel_texture_) + { + std::shared_ptr ptr; + + if (!(ptr = texture.lock())) + { + ptr = std::make_shared(); + + 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_; + } + }