mirror of
https://github.com/NohamR/Reclass.git
synced 2026-05-10 19:59:21 +00:00
Theme system overhaul, UI polish, and VS2022 Dark theme
- Replaced hardcoded theme factories with JSON files + CMake build step - Shared ThemeFieldMeta table for DRY serialization and editor UI - Fixed live preview (auto-triggers on color change, no toggle button) - Fixed duplicate theme entries when editing built-in themes - Moved title bar from icon to bold "Reclass" text with View > Show Icon toggle - MDI tabs: 24px height, unicode close button styled like TypeSelectorPopup - Added VS2022 Dark theme with purple accent colors - Status bar padding, removed monospace font overrides on tabs/statusbar - Default startup opens Ball demo + Unnamed hex64 tabs
This commit is contained in:
@@ -1,122 +1,56 @@
|
||||
#include "theme.h"
|
||||
#include <type_traits>
|
||||
|
||||
namespace rcx {
|
||||
|
||||
// ── Field table for DRY serialization ──
|
||||
// ── Shared field metadata (serialization + editor UI) ──
|
||||
|
||||
struct ColorField { const char* key; QColor Theme::*ptr; };
|
||||
|
||||
static const ColorField kFields[] = {
|
||||
{"background", &Theme::background},
|
||||
{"backgroundAlt", &Theme::backgroundAlt},
|
||||
{"surface", &Theme::surface},
|
||||
{"border", &Theme::border},
|
||||
{"borderFocused", &Theme::borderFocused},
|
||||
{"button", &Theme::button},
|
||||
{"text", &Theme::text},
|
||||
{"textDim", &Theme::textDim},
|
||||
{"textMuted", &Theme::textMuted},
|
||||
{"textFaint", &Theme::textFaint},
|
||||
{"hover", &Theme::hover},
|
||||
{"selected", &Theme::selected},
|
||||
{"selection", &Theme::selection},
|
||||
{"syntaxKeyword", &Theme::syntaxKeyword},
|
||||
{"syntaxNumber", &Theme::syntaxNumber},
|
||||
{"syntaxString", &Theme::syntaxString},
|
||||
{"syntaxComment", &Theme::syntaxComment},
|
||||
{"syntaxPreproc", &Theme::syntaxPreproc},
|
||||
{"syntaxType", &Theme::syntaxType},
|
||||
{"indHoverSpan", &Theme::indHoverSpan},
|
||||
{"indCmdPill", &Theme::indCmdPill},
|
||||
{"indDataChanged",&Theme::indDataChanged},
|
||||
{"indHintGreen", &Theme::indHintGreen},
|
||||
{"markerPtr", &Theme::markerPtr},
|
||||
{"markerCycle", &Theme::markerCycle},
|
||||
{"markerError", &Theme::markerError},
|
||||
const ThemeFieldMeta kThemeFields[] = {
|
||||
{"background", "Background", "Chrome", &Theme::background},
|
||||
{"backgroundAlt", "Background Alt", "Chrome", &Theme::backgroundAlt},
|
||||
{"surface", "Surface", "Chrome", &Theme::surface},
|
||||
{"border", "Border", "Chrome", &Theme::border},
|
||||
{"borderFocused", "Border Focused", "Chrome", &Theme::borderFocused},
|
||||
{"button", "Button", "Chrome", &Theme::button},
|
||||
{"text", "Text", "Text", &Theme::text},
|
||||
{"textDim", "Text Dim", "Text", &Theme::textDim},
|
||||
{"textMuted", "Text Muted", "Text", &Theme::textMuted},
|
||||
{"textFaint", "Text Faint", "Text", &Theme::textFaint},
|
||||
{"hover", "Hover", "Interactive", &Theme::hover},
|
||||
{"selected", "Selected", "Interactive", &Theme::selected},
|
||||
{"selection", "Selection", "Interactive", &Theme::selection},
|
||||
{"syntaxKeyword", "Keyword", "Syntax", &Theme::syntaxKeyword},
|
||||
{"syntaxNumber", "Number", "Syntax", &Theme::syntaxNumber},
|
||||
{"syntaxString", "String", "Syntax", &Theme::syntaxString},
|
||||
{"syntaxComment", "Comment", "Syntax", &Theme::syntaxComment},
|
||||
{"syntaxPreproc", "Preprocessor", "Syntax", &Theme::syntaxPreproc},
|
||||
{"syntaxType", "Type", "Syntax", &Theme::syntaxType},
|
||||
{"indHoverSpan", "Hover Span", "Indicators", &Theme::indHoverSpan},
|
||||
{"indCmdPill", "Cmd Pill", "Indicators", &Theme::indCmdPill},
|
||||
{"indDataChanged","Data Changed", "Indicators", &Theme::indDataChanged},
|
||||
{"indHintGreen", "Hint Green", "Indicators", &Theme::indHintGreen},
|
||||
{"markerPtr", "Pointer", "Markers", &Theme::markerPtr},
|
||||
{"markerCycle", "Cycle", "Markers", &Theme::markerCycle},
|
||||
{"markerError", "Error", "Markers", &Theme::markerError},
|
||||
};
|
||||
const int kThemeFieldCount = static_cast<int>(std::extent_v<decltype(kThemeFields)>);
|
||||
|
||||
QJsonObject Theme::toJson() const {
|
||||
QJsonObject o;
|
||||
o["name"] = name;
|
||||
for (const auto& f : kFields)
|
||||
o[f.key] = (this->*f.ptr).name();
|
||||
for (int i = 0; i < kThemeFieldCount; i++)
|
||||
o[kThemeFields[i].key] = (this->*kThemeFields[i].ptr).name();
|
||||
return o;
|
||||
}
|
||||
|
||||
Theme Theme::fromJson(const QJsonObject& o) {
|
||||
Theme t = reclassDark();
|
||||
t.name = o["name"].toString(t.name);
|
||||
for (const auto& f : kFields) {
|
||||
if (o.contains(f.key))
|
||||
t.*f.ptr = QColor(o[f.key].toString());
|
||||
Theme t;
|
||||
t.name = o["name"].toString("Untitled");
|
||||
for (int i = 0; i < kThemeFieldCount; i++) {
|
||||
if (o.contains(kThemeFields[i].key))
|
||||
t.*kThemeFields[i].ptr = QColor(o[kThemeFields[i].key].toString());
|
||||
}
|
||||
return t;
|
||||
}
|
||||
|
||||
// ── Built-in themes ──
|
||||
|
||||
Theme Theme::reclassDark() {
|
||||
Theme t;
|
||||
t.name = "Reclass Dark";
|
||||
t.background = QColor("#1e1e1e");
|
||||
t.backgroundAlt = QColor("#252526");
|
||||
t.surface = QColor("#2a2d2e");
|
||||
t.border = QColor("#3c3c3c");
|
||||
t.borderFocused = QColor("#64e6b450"); // indHoverSpan at ~40% alpha
|
||||
t.button = QColor("#333333");
|
||||
t.text = QColor("#d4d4d4");
|
||||
t.textDim = QColor("#858585");
|
||||
t.textMuted = QColor("#585858");
|
||||
t.textFaint = QColor("#505050");
|
||||
t.hover = QColor("#2b2b2b");
|
||||
t.selected = QColor("#232323");
|
||||
t.selection = QColor("#2b2b2b");
|
||||
t.syntaxKeyword = QColor("#569cd6");
|
||||
t.syntaxNumber = QColor("#b5cea8");
|
||||
t.syntaxString = QColor("#ce9178");
|
||||
t.syntaxComment = QColor("#6a9955");
|
||||
t.syntaxPreproc = QColor("#c586c0");
|
||||
t.syntaxType = QColor("#4EC9B0");
|
||||
t.indHoverSpan = QColor("#E6B450");
|
||||
t.indCmdPill = QColor("#2a2a2a");
|
||||
t.indDataChanged= QColor("#8fbc7a");
|
||||
t.indHintGreen = QColor("#5a8248");
|
||||
t.markerPtr = QColor("#f44747");
|
||||
t.markerCycle = QColor("#e5a00d");
|
||||
t.markerError = QColor("#7a2e2e");
|
||||
return t;
|
||||
}
|
||||
|
||||
Theme Theme::warm() {
|
||||
Theme t;
|
||||
t.name = "Warm";
|
||||
t.background = QColor("#212121");
|
||||
t.backgroundAlt = QColor("#2a2a2a");
|
||||
t.surface = QColor("#2a2a2a");
|
||||
t.border = QColor("#373737");
|
||||
t.borderFocused = QColor("#64aa9565"); // indHoverSpan at ~40% alpha
|
||||
t.button = QColor("#373737");
|
||||
t.text = QColor("#AAA99F");
|
||||
t.textDim = QColor("#7a7a6e");
|
||||
t.textMuted = QColor("#555550");
|
||||
t.textFaint = QColor("#464646");
|
||||
t.hover = QColor("#373737");
|
||||
t.selected = QColor("#2d2d2d");
|
||||
t.selection = QColor("#21213A");
|
||||
t.syntaxKeyword = QColor("#AA9565");
|
||||
t.syntaxNumber = QColor("#AAA98C");
|
||||
t.syntaxString = QColor("#6B3B21");
|
||||
t.syntaxComment = QColor("#464646");
|
||||
t.syntaxPreproc = QColor("#AA9565");
|
||||
t.syntaxType = QColor("#6B959F");
|
||||
t.indHoverSpan = QColor("#AA9565");
|
||||
t.indCmdPill = QColor("#2a2a2a");
|
||||
t.indDataChanged= QColor("#6B959F");
|
||||
t.indHintGreen = QColor("#464646");
|
||||
t.markerPtr = QColor("#6B3B21");
|
||||
t.markerCycle = QColor("#AA9565");
|
||||
t.markerError = QColor("#3C2121");
|
||||
return t;
|
||||
}
|
||||
|
||||
} // namespace rcx
|
||||
|
||||
Reference in New Issue
Block a user