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:
@@ -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
|
||||
|
||||
@@ -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
|
||||
|
||||
Reference in New Issue
Block a user