Public Access
Every screen's keys are constant tables in lib/core/src/app_keys.h (52 of them, each under an `// id: Title` comment). An App's help() picks the table of the state it is in. site/tools/gen_dev_docs.py reads the same file and writes site/data/keys.toml; the `keys` shortcode shows a screen's tables on its guide page, and /guide/keys/ shows all of them. The Site job fails when the data file is out of date or a page asks for a table that doesn't exist, and now also runs when app_keys.h changes. A key added to an App shows up on the website without anyone editing a page. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01EhqxQ49eCju4CzKYNjZzwT
118 lines
4.4 KiB
C++
118 lines
4.4 KiB
C++
#include "app_keys.h"
|
|
#include "demo_app.h"
|
|
|
|
#include "ui/widgets.h"
|
|
|
|
namespace roro {
|
|
|
|
namespace {
|
|
const char* const kMenu[] = {"Text view", "Line editor", "Dialog", "Toast: info", "Toast: warning",
|
|
"Toast: burst of 5"};
|
|
const char* const kText =
|
|
"Bienvenue sur roro9stack ! Ce texte teste le retour \xC3\xA0 la ligne automatique et les "
|
|
"accents : \xC3\xA9t\xC3\xA9, \xC3\xA0 bient\xC3\xB4t, gar\xC3\xA7on, No\xC3\xABl, "
|
|
"ma\xC3\xAEtre, o\xC3\xB9.\n\n"
|
|
"Use ; and . to scroll, ` to go back. Fn+` always returns to the Launcher.\n\n"
|
|
"Unbreakablewordthatislongerthanawholelineofthescreen to test hard breaks.";
|
|
} // namespace
|
|
|
|
void DemoApp::onEnter() {
|
|
page_ = Page::Menu;
|
|
dialog_.reset();
|
|
menu_.setCount(sizeof(kMenu) / sizeof(kMenu[0]));
|
|
}
|
|
|
|
void DemoApp::notify(const char* text, NotificationLevel level) {
|
|
bus_.publish(Event::withText(EventType::Notification, text, static_cast<int32_t>(level)));
|
|
}
|
|
|
|
void DemoApp::help(std::vector<KeyHelp>& out) const {
|
|
if (dialog_) return keys::add(out, keys::kDialog);
|
|
if (page_ == Page::Editor) return keys::add(out, keys::kText);
|
|
if (page_ == Page::Menu) keys::add(out, keys::kDemo);
|
|
}
|
|
|
|
bool DemoApp::onKey(const KeyEvent& e) {
|
|
requestRedraw();
|
|
if (dialog_) {
|
|
dialog_->onKey(e);
|
|
int r = dialog_->result();
|
|
if (r != DialogModel::kPending) {
|
|
notify(r == DialogModel::kCancelled ? "Dialog cancelled" : ("Chose " + dialog_->buttons()[r]).c_str(),
|
|
NotificationLevel::Info);
|
|
dialog_.reset();
|
|
}
|
|
return true;
|
|
}
|
|
switch (page_) {
|
|
case Page::Menu: return onMenuKey(e);
|
|
case Page::Text:
|
|
if (e.key == Key::Up && textScroll_ > 0) textScroll_--;
|
|
else if (e.key == Key::Down && textScroll_ < textLineCount_ - 1) textScroll_++;
|
|
else if (e.key == Key::Back) page_ = Page::Menu;
|
|
return true;
|
|
case Page::Editor:
|
|
switch (e.key) {
|
|
case Key::Char: editor_.insert(e.ch); break;
|
|
case Key::Delete: editor_.backspace(); break;
|
|
case Key::Left: editor_.left(); break;
|
|
case Key::Right: editor_.right(); break;
|
|
case Key::Up: editor_.home(); break;
|
|
case Key::Down: editor_.end(); break;
|
|
case Key::Select:
|
|
if (!editor_.text().empty()) notify(editor_.text().c_str(), NotificationLevel::Message);
|
|
break;
|
|
case Key::Back: page_ = Page::Menu; break;
|
|
default: break;
|
|
}
|
|
return true;
|
|
}
|
|
return false;
|
|
}
|
|
|
|
bool DemoApp::onMenuKey(const KeyEvent& e) {
|
|
switch (e.key) {
|
|
case Key::Up: menu_.up(); return true;
|
|
case Key::Down: menu_.down(); return true;
|
|
case Key::Select: break;
|
|
default: return false; // Back leaves the App
|
|
}
|
|
switch (menu_.selected()) {
|
|
case 0: page_ = Page::Text; textScroll_ = 0; break;
|
|
case 1: page_ = Page::Editor; break;
|
|
case 2: dialog_.reset(new DialogModel({"Cancel", "Maybe", "OK"})); break;
|
|
case 3: notify("Hello from the demo", NotificationLevel::Info); break;
|
|
case 4: notify("Something needs attention", NotificationLevel::Warning); break;
|
|
case 5:
|
|
for (int i = 1; i <= 5; i++) notify(("Burst " + std::to_string(i)).c_str(), NotificationLevel::Info);
|
|
break;
|
|
}
|
|
return true;
|
|
}
|
|
|
|
void DemoApp::draw(Canvas& c) {
|
|
const auto& area = theme::kContent;
|
|
switch (page_) {
|
|
case Page::Menu:
|
|
widgets::list(c, menu_, area, [](int i) { return std::string(kMenu[i]); });
|
|
break;
|
|
case Page::Text: {
|
|
auto lines = wrapText(kText, area.w - 10, widgets::bodyMeasure(c));
|
|
textLineCount_ = static_cast<int>(lines.size());
|
|
widgets::textLines(c, lines, textScroll_, area);
|
|
break;
|
|
}
|
|
case Page::Editor:
|
|
c.setTextColor(theme::kMuted);
|
|
c.drawString("A line editor", 4, area.y + 4);
|
|
widgets::lineEditor(c, editor_, {4, area.y + 22, area.w - 8, 0});
|
|
c.setTextColor(theme::kMuted);
|
|
c.drawString((std::to_string(editor_.text().size()) + "/39 bytes").c_str(), 4, area.y + 44);
|
|
break;
|
|
}
|
|
if (dialog_)
|
|
widgets::dialog(c, "Dialog", "Left/Right or Tab to choose, Enter to confirm, ` to cancel.", *dialog_);
|
|
}
|
|
|
|
} // namespace roro
|