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
64 lines
1.9 KiB
C++
64 lines
1.9 KiB
C++
#pragma once
|
|
|
|
#include <algorithm>
|
|
#include <string>
|
|
#include <vector>
|
|
|
|
#include "key_event.h"
|
|
|
|
// The help panel (issue #69, docs/milestones/U1.md): Fn+h on any screen lists the keys that work
|
|
// there. Every App says what its keys are in the state it's in; nothing on a screen names keys.
|
|
namespace roro {
|
|
|
|
// One line of the panel: a key (or keys) and what it does. A line with no action is a heading.
|
|
struct KeyHelp {
|
|
const char* keys;
|
|
const char* action;
|
|
};
|
|
|
|
|
|
// The panel itself: what it lists, and how far it's scrolled. The keys it takes while open are the
|
|
// arrows; any other key closes it, and none reaches the App.
|
|
class HelpModel {
|
|
public:
|
|
explicit HelpModel(int visibleRows = 8) : visible_(visibleRows) {}
|
|
|
|
void open(const std::string& title, std::vector<KeyHelp> rows) {
|
|
title_ = title;
|
|
rows_ = std::move(rows);
|
|
top_ = 0;
|
|
open_ = true;
|
|
}
|
|
void close() {
|
|
open_ = false;
|
|
rows_.clear();
|
|
rows_.shrink_to_fit(); // nothing is kept while it's closed
|
|
}
|
|
bool isOpen() const { return open_; }
|
|
|
|
void onKey(const KeyEvent& e) {
|
|
int last = std::max(0, static_cast<int>(rows_.size()) - visible_);
|
|
switch (e.key) {
|
|
case Key::Up: top_ = std::max(0, top_ - 1); break;
|
|
case Key::Down: top_ = std::min(last, top_ + 1); break;
|
|
case Key::Left: top_ = std::max(0, top_ - visible_); break;
|
|
case Key::Right: top_ = std::min(last, top_ + visible_); break;
|
|
default: close(); break;
|
|
}
|
|
}
|
|
|
|
const std::string& title() const { return title_; }
|
|
const std::vector<KeyHelp>& rows() const { return rows_; }
|
|
int top() const { return top_; }
|
|
int visibleRows() const { return visible_; }
|
|
|
|
private:
|
|
std::string title_;
|
|
std::vector<KeyHelp> rows_;
|
|
int top_ = 0;
|
|
int visible_;
|
|
bool open_ = false;
|
|
};
|
|
|
|
} // namespace roro
|