Public Access
UI: seven themes, each dark and light, chosen in the Settings
Settings > Theme and Settings > Light or dark pick the colours of every screen (issue #10): roro9stack (the website's, the default), Catppuccin, Dracula, Nord, ANSI terminal, Gruvbox and Solarized. - A palette is 14 roles (lib/ui/src/palette.h). theme::kText and the others are now references into the one in use, so the Apps are unchanged; the main loop applies it when a Setting changes. - Every colour is one the RGB332 frame buffer holds exactly: the themes' own were rounded, and those that fell together or lost contrast were picked by hand. test_palette checks exactness and 18 contrast ratios for each palette. - The Sky view's constellation colours come from the theme. - `theme [0-6] [light|dark]` on the consoles. Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_0162FokPdvY2KsS4NBfwyWPk
This commit is contained in:
@@ -17,14 +17,14 @@ using namespace gnss;
|
||||
|
||||
namespace {
|
||||
|
||||
// One colour per constellation, readable in the 8-bit frame buffer.
|
||||
// One colour per constellation, from the theme: readable on its background.
|
||||
uint16_t colorOf(Constellation c) {
|
||||
switch (c) {
|
||||
case Constellation::Gps: return theme::kAccent;
|
||||
case Constellation::Glonass: return 0xF8C8; // red
|
||||
case Constellation::Glonass: return theme::kRed;
|
||||
case Constellation::Galileo: return theme::kGood;
|
||||
case Constellation::BeiDou: return 0xFEA0; // yellow
|
||||
case Constellation::Qzss: return 0xC99F; // violet
|
||||
case Constellation::BeiDou: return theme::kYellow;
|
||||
case Constellation::Qzss: return theme::kViolet;
|
||||
default: return theme::kText;
|
||||
}
|
||||
}
|
||||
|
||||
+19
-1
@@ -193,6 +193,7 @@ void setup() {
|
||||
Serial.begin(115200);
|
||||
|
||||
settings.load();
|
||||
theme::apply(ui::palette(settings.getInt(Setting::Theme), settings.getBool(Setting::ThemeLight)));
|
||||
if (safeMode) return setupSafeMode(crashes);
|
||||
|
||||
battery = new BatteryService(bus);
|
||||
@@ -694,7 +695,7 @@ static const char* const kHelp =
|
||||
"irc start | irc stop | irc dump | irc say <buffer> <text>\n"
|
||||
"install <path.ota> Update from SD\n"
|
||||
"update check | update list | update status | update install <tag> the project's releases on Gitea\n"
|
||||
"sd card | sd list | cat <path> | log <text> | burst | sound on|off | short | normal\n"
|
||||
"sd card | sd list | cat <path> | log <text> | burst | sound on|off | theme [0-6] [light|dark] | short | normal\n"
|
||||
"Irc | Wifi | Gnss | Gemini | Lora | Storage | Notes | Shell | System | Settings open that App: a capital letter is an App, not a command\n"
|
||||
"ping <host> [count] [size] | nslookup <name> [server] | port <host> <port> | traceroute <host> | cancel is it there, does its name resolve, is its port open, which way; one at a time\n"
|
||||
"tls <host> [port] | ntp [server] a TLS handshake: who the certificate is for, by whom, until when, and whether this device trusts it; a time server's clock against this one\n"
|
||||
@@ -1328,6 +1329,14 @@ static void runCommand(String line, bool fromSerial = false) {
|
||||
settings.setBool(Setting::DnsAlways, line.endsWith("on"));
|
||||
wifi->serversChanged();
|
||||
}
|
||||
if (line == "theme" || line.startsWith("theme ")) { // theme [0-6] [light|dark]
|
||||
std::string rest = line.length() > 6 ? line.substring(6).c_str() : "";
|
||||
if (!rest.empty() && isdigit(static_cast<unsigned char>(rest[0]))) settings.setInt(Setting::Theme, rest[0] - '0');
|
||||
if (rest.find("light") != std::string::npos) settings.setBool(Setting::ThemeLight, true);
|
||||
if (rest.find("dark") != std::string::npos) settings.setBool(Setting::ThemeLight, false);
|
||||
for (int t = 0; t < ui::kThemeCount; ++t)
|
||||
console.printf("theme: %d %s%s\n", t, ui::themeName(t), t == settings.getInt(Setting::Theme) ? (settings.getBool(Setting::ThemeLight) ? " (light)" : " (dark)") : "");
|
||||
}
|
||||
if (line == "sound off") settings.setBool(Setting::Sound, false);
|
||||
if (line == "sound on") settings.setBool(Setting::Sound, true);
|
||||
if (line == "short") {
|
||||
@@ -1567,6 +1576,15 @@ static void loopPass() {
|
||||
StatusInfo status = currentStatus();
|
||||
const Toast* toast = notifier->toasts().current(now);
|
||||
bool toastChanged = notifier->toasts().takeChanged();
|
||||
// The theme, when the Settings (or the `theme` command) changed it: every colour is drawn again.
|
||||
static int shownTheme = settings.getInt(Setting::Theme) * 2 + settings.getBool(Setting::ThemeLight);
|
||||
int wantedTheme = settings.getInt(Setting::Theme) * 2 + settings.getBool(Setting::ThemeLight);
|
||||
if (wantedTheme != shownTheme) {
|
||||
shownTheme = wantedTheme;
|
||||
theme::apply(ui::palette(wantedTheme / 2, wantedTheme % 2));
|
||||
screen.invalidate();
|
||||
redrawAfterUpdate = true;
|
||||
}
|
||||
if (apps->takeRedraw() || toastChanged || status != lastStatus || redrawAfterUpdate) {
|
||||
lastStatus = status;
|
||||
redrawAfterUpdate = false;
|
||||
|
||||
@@ -14,6 +14,8 @@ class Screen {
|
||||
// Takes over the screen while a Firmware Update is received or about to restart.
|
||||
void renderUpdate(const std::string& title, const std::string& detail, int percent);
|
||||
Canvas& canvas() { return canvas_; }
|
||||
// The colours changed: an App that keeps what it drew has to draw it all again.
|
||||
void invalidate() { lost_ = true; }
|
||||
|
||||
private:
|
||||
Canvas canvas_;
|
||||
|
||||
+23
-14
@@ -2,22 +2,31 @@
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
#include "palette.h"
|
||||
|
||||
namespace roro::theme {
|
||||
|
||||
// The website's palette (site/static/css/site.css, its dark side), as RGB565. Every one is a colour
|
||||
// the 8-bit frame buffer (RGB332) holds exactly, so what is asked for is what is shown.
|
||||
constexpr uint16_t kBackground = 0x0000;
|
||||
constexpr uint16_t kText = 0xFFFF;
|
||||
constexpr uint16_t kAccent = 0x06DF; // cyan, #00dbff: what is chosen, what is live
|
||||
constexpr uint16_t kOnAccent = 0x000A; // dark blue, #000055: text and pictures on a cyan fill
|
||||
constexpr uint16_t kSelection = kAccent; // behind a selected row, whose text is kOnAccent
|
||||
constexpr uint16_t kMuted = 0x9495; // grey, #9292aa: between the website's two
|
||||
constexpr uint16_t kFaint = 0x4A4A; // slate, #494955: grid lines, what stays behind
|
||||
constexpr uint16_t kBar = kFaint; // Status Bar background
|
||||
constexpr uint16_t kBarMuted = 0xB5B5; // light grey, #b6b6aa: what is idle, on the bar
|
||||
constexpr uint16_t kWarning = 0xFC80; // orange, #ff9200
|
||||
constexpr uint16_t kMessage = 0xFC9F; // pink, #ff92ff: someone wrote
|
||||
constexpr uint16_t kGood = 0x4ECA; // green, #49db55: a Fix, the best of a set (not on the website)
|
||||
// The colours every screen draws with: the theme chosen in the Settings (issue #10, lib/ui's
|
||||
// palette.h), set at boot and whenever it changes. They read as constants, and are references into
|
||||
// the palette in use, so a draw after apply() is in the new colours.
|
||||
inline ui::Palette current = ui::palette(0, false);
|
||||
inline void apply(const ui::Palette& p) { current = p; }
|
||||
|
||||
inline const uint16_t& kBackground = current.background;
|
||||
inline const uint16_t& kText = current.text;
|
||||
inline const uint16_t& kAccent = current.accent; // what is chosen, what is live
|
||||
inline const uint16_t& kOnAccent = current.onAccent; // text and pictures on an accent fill
|
||||
inline const uint16_t& kSelection = current.accent; // behind a selected row, whose text is kOnAccent
|
||||
inline const uint16_t& kMuted = current.muted;
|
||||
inline const uint16_t& kFaint = current.faint; // grid lines, what stays behind
|
||||
inline const uint16_t& kBar = current.bar; // Status Bar background
|
||||
inline const uint16_t& kBarMuted = current.barMuted; // what is idle, on the bar
|
||||
inline const uint16_t& kWarning = current.warning;
|
||||
inline const uint16_t& kMessage = current.message; // someone wrote
|
||||
inline const uint16_t& kGood = current.good; // a Fix, the best of a set
|
||||
inline const uint16_t& kRed = current.red; // these three: to tell things apart
|
||||
inline const uint16_t& kYellow = current.yellow;
|
||||
inline const uint16_t& kViolet = current.violet;
|
||||
|
||||
constexpr int kWidth = 240;
|
||||
constexpr int kHeight = 135;
|
||||
|
||||
Reference in New Issue
Block a user