Fix ui::label underline & strikethrough handling

This commit is contained in:
Nikita Lisitsa 2022-05-21 22:07:55 +03:00
parent 2b228fbd32
commit 3f282356d7

View file

@ -449,6 +449,17 @@ namespace psemek::ui
{
float const line_width = 1.f * (*st->text_scale);
auto get_batch = [&](gfx::color_rgba const & color) -> cached_state::batch & {
auto texture = single_white_pixel_texture().get();
if (state.batches.empty() || state.batches.back().texture != texture || state.batches.back().color != color)
{
auto & b = state.batches.emplace_back();
b.texture = texture;
b.color = color;
}
return state.batches.back();
};
std::size_t ch_begin = 0;
std::size_t ch = 0;
for (std::size_t l = 0; l < lines.size(); ++l)
@ -456,33 +467,8 @@ namespace psemek::ui
float underline_y = std::round(line_offset[l][1] + font_height - line_width);
float strikethrough_y = std::round(line_offset[l][1] + font_height / 2.f - line_width / 2.f);
std::optional<std::pair<geom::interval<float>, gfx::color_rgba>> current_underline;
std::optional<std::pair<geom::interval<float>, gfx::color_rgba>> current_strikethrough;
auto batch = [&](gfx::color_rgba const & color) -> cached_state::batch & {
auto texture = single_white_pixel_texture().get();
if (state.batches.empty() || state.batches.back().texture != texture || state.batches.back().color != color)
{
auto & b = state.batches.emplace_back();
b.texture = texture;
b.color = color;
}
return state.batches.back();
};
auto flush_underline = [&]{
auto & image = batch(current_underline->second).images.emplace_back();
image.position[0] = current_underline->first;
image.position[1] = {underline_y, underline_y + line_width};
current_underline = std::nullopt;
};
auto flush_strikethrough = [&]{
auto & image = batch(current_strikethrough->second).images.emplace_back();
image.position[0] = current_strikethrough->first;
image.position[1] = {strikethrough_y, strikethrough_y + line_width};
current_strikethrough = std::nullopt;
};
std::optional<float> last_underline_end;
std::optional<float> last_strikethrough_end;
for (; ch < glyph_chunks.size(); ++ch)
{
@ -500,43 +486,29 @@ namespace psemek::ui
for (std::size_t i = ibegin; i < iend; ++i)
x_range |= glyphs[i].position[0];
if (underline && current_underline)
if (underline)
{
if (current_underline->second != chunk.color)
{
flush_underline();
current_underline = {x_range, chunk.color};
}
else
current_underline->first |= x_range;
}
else if (underline && !current_underline)
{
current_underline = {x_range, chunk.color};
}
else if (!underline && current_underline)
{
flush_underline();
auto & image = get_batch(chunk.color).images.emplace_back();
image.position[0] = x_range;
if (last_underline_end)
image.position[0] |= *last_underline_end;
image.position[1] = {underline_y, underline_y + line_width};
last_underline_end = image.position[0].max;
}
else
last_underline_end = std::nullopt;
if (strikethrough && current_strikethrough)
if (strikethrough)
{
if (current_strikethrough->second != chunk.color)
{
flush_strikethrough();
current_strikethrough = {x_range, chunk.color};
}
else
current_strikethrough->first |= x_range;
}
else if (strikethrough && !current_strikethrough)
{
current_strikethrough = {x_range, chunk.color};
}
else if (!strikethrough && current_strikethrough)
{
flush_strikethrough();
auto & image = get_batch(chunk.color).images.emplace_back();
image.position[0] = x_range;
if (last_strikethrough_end)
image.position[0] |= *last_strikethrough_end;
image.position[1] = {strikethrough_y, strikethrough_y + line_width};
last_strikethrough_end = image.position[0].max;
}
else
last_strikethrough_end = std::nullopt;
}
if (chunk.end > lines[l].end)
@ -544,12 +516,6 @@ namespace psemek::ui
ch_begin = chunk.end;
}
if (current_underline)
flush_underline();
if (current_strikethrough)
flush_strikethrough();
}
}