C++, Spec: add support for automatic word wrap

backup spec_v2
Christian Seiler 2 weeks ago
parent 7cbac666b8
commit 7c371b04e3
  1. 2
      Specification.rst
  2. 56
      cpp/src/monoformat_parseonly.cpp
  3. 3
      cpp/src/monoformat_schema.hpp
  4. 59
      cpp/src/monoformat_structured.cpp

@ -491,6 +491,8 @@ Text Flags
+===========+===================================================+ +===========+===================================================+
| ``0`` | Text is dark, background is white | | ``0`` | Text is dark, background is white |
+-----------+---------------------------------------------------+ +-----------+---------------------------------------------------+
| ``1`` | Enable automatic word wrap |
+-----------+---------------------------------------------------+
| ``1`` .. | Reserved for future use | | ``1`` .. | Reserved for future use |
| ``7`` | | | ``7`` | |
+-----------+---------------------------------------------------+ +-----------+---------------------------------------------------+

@ -1109,7 +1109,61 @@ std::expected<void, ParseError> handleClippedText(std::span<std::byte const>& bu
ClippedImage target{screen, *x, *y, *width, *height}; ClippedImage target{screen, *x, *y, *width, *height};
auto renderer = FontRenderer{fontData}.withIgnoreUnknownChars(true); auto renderer = FontRenderer{fontData}.withIgnoreUnknownChars(true);
renderer.render(text, Point{0, static_cast<std::int32_t>(renderer.lineHeight() - 2)}, target, fgColor, bgColor); if (textFlags.autoWordWrap) {
auto dimensions = renderer.getRenderedDimensions(text, Point{0, 0});
if (!dimensions) {
return {};
}
std::int32_t y = 0;
while (dimensions->boundingBox && dimensions->boundingBox->size.width > (*width)) {
std::size_t pos = text.find('\n');
if (pos == std::string_view::npos) {
pos = text.size();
}
std::string_view currentLine = text.substr(0, pos);
if (pos < text.size()) {
text = text.substr(pos + 1);
} else {
text = text.substr(pos);
}
while (currentLine.size() > 0) {
dimensions = renderer.getRenderedDimensions(currentLine, Point{0, 0});
if (!dimensions) {
return {};
}
std::size_t pos = currentLine.size();
while (pos > 0 && dimensions->boundingBox && dimensions->boundingBox->size.width > (*width)) {
std::size_t prevPos = pos;
pos = currentLine.rfind(' ', prevPos - 1);
if (pos == std::string_view::npos) {
pos = prevPos;
break;
}
dimensions = renderer.getRenderedDimensions(currentLine.substr(0, pos), Point{0, 0});
if (!dimensions) {
return {};
}
}
renderer.render(currentLine.substr(0, pos), Point{0, y + static_cast<std::int32_t>(renderer.lineHeight() - 2)}, target, fgColor, bgColor);
y += renderer.lineHeight();
if (pos < currentLine.size()) {
currentLine = currentLine.substr(pos + 1);
} else {
currentLine = currentLine.substr(pos);
}
}
dimensions = renderer.getRenderedDimensions(text, Point{0, 0});
if (!dimensions) {
return {};
}
}
if (text.size() > 0) {
renderer.render(text, Point{0, y + static_cast<std::int32_t>(renderer.lineHeight() - 2)}, target, fgColor, bgColor);
y += renderer.lineHeight();
}
} else {
renderer.render(text, Point{0, static_cast<std::int32_t>(renderer.lineHeight() - 2)}, target, fgColor, bgColor);
}
return {}; return {};
} }

@ -101,17 +101,20 @@ struct FillFlags {
struct TextFlags { struct TextFlags {
bool dark{}; bool dark{};
bool autoWordWrap{};
TextFlags() = default; TextFlags() = default;
explicit TextFlags(std::uint8_t flags) noexcept explicit TextFlags(std::uint8_t flags) noexcept
: dark{isBitSet(flags, 0)} : dark{isBitSet(flags, 0)}
, autoWordWrap{isBitSet(flags, 1)}
{ {
} }
explicit operator std::uint8_t() const noexcept { explicit operator std::uint8_t() const noexcept {
std::uint8_t result{}; std::uint8_t result{};
maybeSetBit(result, 0, dark); maybeSetBit(result, 0, dark);
maybeSetBit(result, 1, autoWordWrap);
return result; return result;
} }
}; };

@ -42,7 +42,7 @@ NLOHMANN_JSON_SERIALIZE_ENUM(FillPattern, {
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(ScrollFlags, endless, invertDirection, padBefore, padAfter) NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(ScrollFlags, endless, invertDirection, padBefore, padAfter)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(LineFlags, dark) NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(LineFlags, dark)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(FillFlags, dark) NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(FillFlags, dark)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(TextFlags, dark) NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(TextFlags, dark, autoWordWrap)
NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(TimeDisplayFlags, use12h, showHours, showMinutes, showSeconds) NLOHMANN_DEFINE_TYPE_NON_INTRUSIVE_WITH_DEFAULT(TimeDisplayFlags, use12h, showHours, showMinutes, showSeconds)
ImageElement::ImageElement(std::uint16_t x, std::uint16_t y, std::uint16_t width, std::uint16_t height) ImageElement::ImageElement(std::uint16_t x, std::uint16_t y, std::uint16_t width, std::uint16_t height)
@ -1466,7 +1466,62 @@ void ClippedTextElement::drawTo(OneBitBufferInterface* imageBuffer, std::size_t
bool fgColor = !m_textFlags.dark; bool fgColor = !m_textFlags.dark;
auto renderer = FontRenderer{fontData}.withIgnoreUnknownChars(true); auto renderer = FontRenderer{fontData}.withIgnoreUnknownChars(true);
renderer.render(m_text, Point{0, static_cast<std::int32_t>(renderer.lineHeight() - 2)}, target, fgColor, bgColor); if (m_textFlags.autoWordWrap) {
std::string_view text = m_text;
auto dimensions = renderer.getRenderedDimensions(text, Point{0, 0});
if (!dimensions) {
return;
}
std::int32_t y = 0;
while (dimensions->boundingBox && dimensions->boundingBox->size.width > m_width) {
std::size_t pos = text.find('\n');
if (pos == std::string_view::npos) {
pos = text.size();
}
std::string_view currentLine = text.substr(0, pos);
if (pos < text.size()) {
text = text.substr(pos + 1);
} else {
text = text.substr(pos);
}
while (currentLine.size() > 0) {
dimensions = renderer.getRenderedDimensions(currentLine, Point{0, 0});
if (!dimensions) {
return;
}
std::size_t pos = currentLine.size();
while (pos > 0 && dimensions->boundingBox && dimensions->boundingBox->size.width > m_width) {
std::size_t prevPos = pos;
pos = currentLine.rfind(' ', prevPos - 1);
if (pos == std::string_view::npos) {
pos = prevPos;
break;
}
dimensions = renderer.getRenderedDimensions(currentLine.substr(0, pos), Point{0, 0});
if (!dimensions) {
return;
}
}
renderer.render(currentLine.substr(0, pos), Point{0, y + static_cast<std::int32_t>(renderer.lineHeight() - 2)}, target, fgColor, bgColor);
y += renderer.lineHeight();
if (pos < currentLine.size()) {
currentLine = currentLine.substr(pos + 1);
} else {
currentLine = currentLine.substr(pos);
}
}
dimensions = renderer.getRenderedDimensions(text, Point{0, 0});
if (!dimensions) {
return;
}
}
if (text.size() > 0) {
renderer.render(text, Point{0, y + static_cast<std::int32_t>(renderer.lineHeight() - 2)}, target, fgColor, bgColor);
y += renderer.lineHeight();
}
} else {
renderer.render(m_text, Point{0, static_cast<std::int32_t>(renderer.lineHeight() - 2)}, target, fgColor, bgColor);
}
} }
std::expected<std::unique_ptr<ClippedTextElement>, ParseError> ClippedTextElement::parse(std::span<std::byte const>& buffer, std::uint32_t formatVersion) { std::expected<std::unique_ptr<ClippedTextElement>, ParseError> ClippedTextElement::parse(std::span<std::byte const>& buffer, std::uint32_t formatVersion) {

Loading…
Cancel
Save