Public Access
Add widget kit, input layer with Compose Key, Launcher and demo apps
Steps 5 and 6 of M0. - lib/ui (host-tested): ListModel, LineEditor (UTF-8, byte-limited), wrapText, ToastQueue, DialogModel - lib/input (host-tested): KeyMapper turns keyboard state into logical keys (Fn arrows, ` Back, Fn+` Home) and composes accents with opt - src/ui: off-screen 16-bit frame pushed in one transfer (fixes the flicker), Status Bar, list, text, line editor, dialog, Toast widgets, Notifier (Toast + beep + LED), vendored public-domain Latin-1 fonts - Apps: minimal Launcher, Widget demo, Diagnostics (SD erase now behind a confirmation dialog) Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
This commit is contained in:
@@ -0,0 +1,60 @@
|
||||
#include "text_wrap.h"
|
||||
|
||||
#include "utf8.h"
|
||||
|
||||
namespace roro {
|
||||
|
||||
namespace {
|
||||
|
||||
void wrapParagraph(const std::string& para, int maxWidth, const MeasureText& measure,
|
||||
std::vector<std::string>& out) {
|
||||
std::string line;
|
||||
size_t pos = 0;
|
||||
while (pos < para.size()) {
|
||||
size_t space = para.find(' ', pos);
|
||||
std::string word = para.substr(pos, space == std::string::npos ? std::string::npos : space - pos);
|
||||
pos = space == std::string::npos ? para.size() : space + 1;
|
||||
|
||||
std::string candidate = line.empty() ? word : line + " " + word;
|
||||
if (measure(candidate) <= maxWidth) {
|
||||
line = candidate;
|
||||
continue;
|
||||
}
|
||||
if (!line.empty()) {
|
||||
out.push_back(line);
|
||||
line.clear();
|
||||
}
|
||||
// The word alone may still be too wide: cut it character by character.
|
||||
while (measure(word) > maxWidth) {
|
||||
size_t cut = 0;
|
||||
while (true) {
|
||||
size_t nextCut = utf8::next(word, cut);
|
||||
if (measure(word.substr(0, nextCut)) > maxWidth) break;
|
||||
cut = nextCut;
|
||||
}
|
||||
if (cut == 0) cut = utf8::next(word, 0); // a single character wider than the line
|
||||
out.push_back(word.substr(0, cut));
|
||||
word = word.substr(cut);
|
||||
}
|
||||
line = word;
|
||||
}
|
||||
out.push_back(line);
|
||||
}
|
||||
|
||||
} // namespace
|
||||
|
||||
std::vector<std::string> wrapText(const std::string& text, int maxWidth, const MeasureText& measure) {
|
||||
std::vector<std::string> lines;
|
||||
if (text.empty()) return lines;
|
||||
size_t start = 0;
|
||||
while (true) {
|
||||
size_t nl = text.find('\n', start);
|
||||
wrapParagraph(text.substr(start, nl == std::string::npos ? std::string::npos : nl - start), maxWidth,
|
||||
measure, lines);
|
||||
if (nl == std::string::npos) break;
|
||||
start = nl + 1;
|
||||
}
|
||||
return lines;
|
||||
}
|
||||
|
||||
} // namespace roro
|
||||
Reference in New Issue
Block a user