feat: Full UI internationalization, pool hashrate stats, and layout caching

- Replace all hardcoded English strings with TR() translation keys across
  every tab, dialog, and component (~20 UI files)
- Expand all 8 language files (de, es, fr, ja, ko, pt, ru, zh) with
  complete translations (~37k lines added)
- Improve i18n loader with exe-relative path fallback and English base
  fallback for missing keys
- Add pool-side hashrate polling via pool stats API in xmrig_manager
- Introduce Layout::beginFrame() per-frame caching and refresh balance
  layout config only on schema generation change
- Offload daemon output parsing to worker thread
- Add CJK subset fallback font for Chinese/Japanese/Korean glyphs
This commit is contained in:
dan_s
2026-03-11 00:40:50 -05:00
parent cc617dd5be
commit 96c27bb949
71 changed files with 43567 additions and 5267 deletions

View File

@@ -45,6 +45,7 @@ bool UISchema::loadFromFile(const std::string& path) {
// Clear previous data
elements_.clear();
styleCache_.clear();
backgroundImagePath_.clear();
logoImagePath_.clear();
@@ -92,6 +93,7 @@ bool UISchema::loadFromFile(const std::string& path) {
overlayPath_.clear(); // No overlay yet
loaded_ = true;
dirty_ = false;
++generation_;
// Record initial modification time
try {
@@ -126,6 +128,7 @@ bool UISchema::loadFromString(const std::string& tomlStr, const std::string& lab
// Clear previous data
elements_.clear();
styleCache_.clear();
backgroundImagePath_.clear();
logoImagePath_.clear();
@@ -222,6 +225,7 @@ bool UISchema::mergeOverlayFromFile(const std::string& path) {
// Track overlay file for hot-reload
currentPath_ = path;
++generation_;
styleCache_.clear(); // Invalidate after overlay merges new elements
try {
lastModTime_ = std::filesystem::last_write_time(path);
} catch (const std::filesystem::filesystem_error&) {}
@@ -495,6 +499,9 @@ void UISchema::applyIfDirty() {
if (!dirty_) return;
dirty_ = false;
// Clear style cache before snapshot so we re-read from TOML
styleCache_.clear();
// Snapshot font sizes before reload for change detection
static const char* fontKeys[] = {
"h1", "h2", "h3", "h4", "h5", "h6",
@@ -513,10 +520,17 @@ void UISchema::applyIfDirty() {
DEBUG_LOGF("[UISchema] Hot-reload: re-parsing %s\n", currentPath_.c_str());
// Save overlay path before reloading — loadFromFile/loadFromString clear it
std::string savedOverlay = overlayPath_;
// If an overlay is active, reload base first then re-merge overlay
if (!overlayPath_.empty() && !basePath_.empty()) {
if (!savedOverlay.empty() && !basePath_.empty()) {
loadFromFile(basePath_);
mergeOverlayFromFile(overlayPath_);
mergeOverlayFromFile(savedOverlay);
} else if (!savedOverlay.empty() && !embeddedTomlStr_.empty()) {
// Embedded base (e.g. Windows single-file): reload from stored string
loadFromString(embeddedTomlStr_, "embedded-reload");
mergeOverlayFromFile(savedOverlay);
} else {
loadFromFile(currentPath_);
}
@@ -836,15 +850,26 @@ SeparatorStyle UISchema::separator(const std::string& section, const std::string
return result;
}
DrawElementStyle UISchema::drawElement(const std::string& section, const std::string& name) const {
DrawElementStyle result;
const DrawElementStyle& UISchema::drawElement(const std::string& section, const std::string& name) const {
static const DrawElementStyle s_empty{};
const void* elem = findElement(section, name);
if (elem) {
detail::parseDrawElementStyle(elem, result);
std::string key = section + "." + name;
// Return from cache if already parsed
auto cit = styleCache_.find(key);
if (cit != styleCache_.end()) {
return cit->second;
}
return result;
// Parse from TOML and cache
const void* elem = findElement(section, name);
if (!elem) {
return s_empty;
}
auto [it, _] = styleCache_.emplace(std::move(key), DrawElementStyle{});
detail::parseDrawElementStyle(elem, it->second);
return it->second;
}
} // namespace schema

View File

@@ -255,8 +255,12 @@ public:
/**
* @brief Look up a DrawList custom element style
*
* Returns a cached const reference. The cache is invalidated on
* hot-reload (applyIfDirty) and full loads. For missing elements
* a static empty sentinel is returned.
*/
DrawElementStyle drawElement(const std::string& section, const std::string& name) const;
const DrawElementStyle& drawElement(const std::string& section, const std::string& name) const;
/**
* @brief Find a raw stored element by section and name.
@@ -365,6 +369,10 @@ private:
std::any data; // holds toml::table at runtime
};
std::unordered_map<std::string, StoredElement> elements_;
// Parsed DrawElementStyle cache — avoids repeated TOML table iteration.
// Populated lazily on first drawElement() lookup, cleared on reload.
mutable std::unordered_map<std::string, DrawElementStyle> styleCache_;
};
// Convenience alias