UI: the website's colours, on every screen

The theme takes the website's palette, each a colour the RGB332 frame
buffer holds exactly: cyan for the accent, a selected row and a chosen
button in cyan with dark blue text, a slate Status Bar (the grey it
asked for was shown as a dull olive), the website's orange for
warnings and its pink for messages. "Good" (a Fix, the quietest
channel) keeps a green of its own, which the website doesn't have.

Co-Authored-By: Claude Opus 5.5 <noreply@anthropic.com>
Claude-Session: https://claude.ai/code/session_0162FokPdvY2KsS4NBfwyWPk
This commit is contained in:
2026-10-09 23:14:37 +02:00
co-authored by Claude Opus 5.5
parent b1c80c912f
commit aadfd8cb37
10 changed files with 75 additions and 36 deletions
+1 -1
View File
@@ -534,7 +534,7 @@ void GeminiApp::drawLine(Canvas& c, size_t i, int firstRow, int y, int rowsLeft)
for (int r = firstRow; r < static_cast<int>(rows.size()) && r - firstRow < rowsLeft; r++) {
int ry = y + (r - firstRow) * theme::kLineHeight;
if (isSelected) c.fillRect(0, ry, theme::kWidth - 3, theme::kLineHeight, theme::kSelection);
c.setTextColor(isSelected ? theme::kText : st.color);
c.setTextColor(isSelected ? theme::kOnAccent : st.color);
std::string text = rows[r];
if (g.type == LineType::Preformatted) text = hscroll_ < static_cast<int>(text.size()) ? text.substr(hscroll_) : "";
c.drawString(text.c_str(), kMargin, ry + 1);
+7 -7
View File
@@ -22,7 +22,7 @@ uint16_t colorOf(Constellation c) {
switch (c) {
case Constellation::Gps: return theme::kAccent;
case Constellation::Glonass: return 0xF8C8; // red
case Constellation::Galileo: return theme::kMessage;
case Constellation::Galileo: return theme::kGood;
case Constellation::BeiDou: return 0xFEA0; // yellow
case Constellation::Qzss: return 0xC99F; // violet
default: return theme::kText;
@@ -96,7 +96,7 @@ void GnssApp::drawPosition(Canvas& c) {
char line[64];
c.setFont(&fonts::bold);
c.setTextColor(s.fix == FixType::None ? theme::kWarning : theme::kMessage);
c.setTextColor(s.fix == FixType::None ? theme::kWarning : theme::kGood);
if (!gnss_.receiving(now)) std::snprintf(line, sizeof line, "No data from the receiver");
else if (s.fix == FixType::None)
std::snprintf(line, sizeof line, "Searching: %u in view, %s", (unsigned)s.satellites.size(),
@@ -155,10 +155,10 @@ void GnssApp::drawSky(Canvas& c) {
// The sky from above: horizon, 30° and 60° elevation rings, north up.
c.drawCircle(cx, cy, radius, theme::kMuted);
c.drawCircle(cx, cy, radius * 2 / 3, 0x4208);
c.drawCircle(cx, cy, radius / 3, 0x4208);
c.drawFastHLine(cx - radius, cy, 2 * radius, 0x4208);
c.drawFastVLine(cx, cy - radius, 2 * radius, 0x4208);
c.drawCircle(cx, cy, radius * 2 / 3, theme::kFaint);
c.drawCircle(cx, cy, radius / 3, theme::kFaint);
c.drawFastHLine(cx - radius, cy, 2 * radius, theme::kFaint);
c.drawFastVLine(cx, cy - radius, 2 * radius, theme::kFaint);
c.setFont(&fonts::small);
c.setTextColor(theme::kMuted);
c.setTextDatum(middle_center);
@@ -201,7 +201,7 @@ void GnssApp::drawSky(Canvas& c) {
c.drawString("No satellites", x, y);
y += theme::kLineHeight;
}
c.setTextColor(s.fix == FixType::None ? theme::kWarning : theme::kMessage);
c.setTextColor(s.fix == FixType::None ? theme::kWarning : theme::kGood);
c.drawString(fixLabel(s.fix), x, y + 4);
c.setFont(&fonts::small);
c.setTextColor(theme::kMuted);
+1 -1
View File
@@ -327,7 +327,7 @@ void LoraScannerApp::drawSweep(Canvas& c) {
uint32_t hz = radio_.config().frequencyHz;
if (hz >= f.fromHz && hz <= f.fromHz + (f.steps - 1) * f.stepHz) {
int x = x0 + static_cast<int>((hz - f.fromHz) / f.stepHz) * cell + cell / 2;
for (int y = barTop; y < barBottom; y += 3) c.drawPixel(x, y, theme::kMessage);
for (int y = barTop; y < barBottom; y += 3) c.drawPixel(x, y, theme::kGood);
}
// The waterfall.
+1 -1
View File
@@ -424,7 +424,7 @@ void SshApp::drawTerminal(Canvas& c) {
c.setFont(&fonts::small);
c.setTextDatum(top_right);
c.fillRect(area.x + area.w - 5 * static_cast<int>(where.size()) - 3, area.y, 5 * static_cast<int>(where.size()) + 3, 9, theme::kAccent);
c.setTextColor(0x0000);
c.setTextColor(theme::kOnAccent);
c.drawString(where.c_str(), area.x + area.w - 1, area.y + 1);
c.setTextDatum(top_left);
}
+4 -4
View File
@@ -232,7 +232,7 @@ void SystemApp::drawOverview(Canvas& c) {
const auto& h = loadHistory_[core];
for (size_t i = 1; i < h.size(); i++) {
int x0 = gx + 1 + static_cast<int>((i - 1) * gw / kHistory), x1 = gx + 1 + static_cast<int>(i * gw / kHistory);
c.drawLine(x0, gy + gh - h.at(i - 1) * gh / 100, x1, gy + gh - h.at(i) * gh / 100, core ? theme::kMessage : theme::kAccent);
c.drawLine(x0, gy + gh - h.at(i - 1) * gh / 100, x1, gy + gh - h.at(i) * gh / 100, core ? theme::kGood : theme::kAccent);
}
}
}
@@ -290,7 +290,7 @@ void SystemApp::drawMemory(Canvas& c) {
struct {
size_t bytes;
uint16_t color;
} floors[] = {{GeminiService::kStartFloor, theme::kMuted}, {GeminiService::kSteadyFloor, theme::kWarning}, {GeminiService::kTransientFloor, theme::kMessage}};
} floors[] = {{GeminiService::kStartFloor, theme::kMuted}, {GeminiService::kSteadyFloor, theme::kWarning}, {GeminiService::kTransientFloor, theme::kGood}};
for (auto& f : floors) {
int kb = static_cast<int>(f.bytes / 1024), y = yOf(kb);
for (int x = gx + 1; x < gx + gw - 1; x += 4) c.drawPixel(x, y, f.color);
@@ -335,13 +335,13 @@ void SystemApp::drawNetwork(Canvas& c) {
for (size_t i = 0; i < kUsers; i++) {
bool active = rateIn_[i] || rateOut_[i];
c.setTextDatum(top_left);
c.setTextColor(active ? theme::kMessage : theme::kText);
c.setTextColor(active ? theme::kGood : theme::kText);
c.drawString(net::userName(static_cast<net::User>(i)), 4, y);
c.setTextDatum(top_right);
c.setTextColor(theme::kText);
c.drawString(net::formatTraffic(traffic_[i].in).c_str(), 124, y);
c.drawString(net::formatTraffic(traffic_[i].out).c_str(), 168, y);
c.setTextColor(active ? theme::kMessage : theme::kMuted);
c.setTextColor(active ? theme::kGood : theme::kMuted);
c.drawString(active ? net::formatTraffic(rateIn_[i] + rateOut_[i]).c_str() : "-", area.w - 4, y);
y += theme::kLineHeight;
}
+3 -3
View File
@@ -232,9 +232,9 @@ void WifiToolsApp::drawChannels(Canvas& c) {
for (int ch = 1; ch <= 13; ch++) {
int x = x0 + (ch - 1) * slot;
int h = static_cast<int>(load[ch] / maxLoad * barMaxH);
uint16_t color = ch == best ? theme::kMessage : (ch == 1 || ch == 6 || ch == 11) ? theme::kAccent : theme::kMuted;
uint16_t color = ch == best ? theme::kGood : (ch == 1 || ch == 6 || ch == 11) ? theme::kAccent : theme::kMuted;
if (h > 0) c.fillRect(x, baseY - h, slot - 4, h, color);
c.setTextColor(ch == best ? theme::kMessage : theme::kText);
c.setTextColor(ch == best ? theme::kGood : theme::kText);
c.setTextDatum(top_center);
c.drawString(std::to_string(ch).c_str(), x + (slot - 4) / 2, baseY + 3);
c.setTextDatum(top_left);
@@ -265,7 +265,7 @@ void WifiToolsApp::drawTracker(Canvas& c) {
int strength = lost ? 0 : std::min(100, std::max(0, (tracker_.latest() + 95) * 100 / 60));
int barW = area.w - 8;
c.drawRect(4, area.y + 60, barW, 8, theme::kMuted);
c.fillRect(5, area.y + 61, (barW - 2) * strength / 100, 6, theme::kMessage);
c.fillRect(5, area.y + 61, (barW - 2) * strength / 100, 6, theme::kGood);
const int gy = area.y + 74, gh = area.h - 76;
const auto& h = tracker_.history();