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:
2026-03-11 00:40:50 -05:00
parent f416ff3d09
commit 2c5a658ea5
71 changed files with 43567 additions and 5267 deletions

View File

@@ -351,18 +351,24 @@ inline void DrawGlassPanel(ImDrawList* dl, const ImVec2& pMin,
// Noise grain overlay — drawn OVER the surface overlay so card
// opacity doesn't hide it. Gives cards a tactile paper feel.
// Noise tint is cached per-generation, opacity checked each panel.
{
float noiseMul = dragonx::ui::effects::ImGuiAcrylic::GetNoiseOpacity();
if (noiseMul > 0.0f) {
uint8_t origAlpha = (s_glassNoiseTint >> IM_COL32_A_SHIFT) & 0xFF;
uint8_t scaledAlpha = static_cast<uint8_t>(std::min(255.0f, origAlpha * noiseMul));
// Tint base color changes only on theme reload; opacity slider may change per-frame
static uint32_t s_noiseGen = 0;
static uint8_t s_baseAlpha = 0;
if (curGen != s_noiseGen) {
s_noiseGen = curGen;
s_baseAlpha = (s_glassNoiseTint >> IM_COL32_A_SHIFT) & 0xFF;
}
uint8_t scaledAlpha = static_cast<uint8_t>(std::min(255.0f, s_baseAlpha * noiseMul));
ImU32 noiseTint = (s_glassNoiseTint & ~(0xFFu << IM_COL32_A_SHIFT)) | (scaledAlpha << IM_COL32_A_SHIFT);
float inset = spec.rounding * 0.3f;
ImVec2 clipMin(pMin.x + inset, pMin.y + inset);
ImVec2 clipMax(pMax.x - inset, pMax.y - inset);
dl->PushClipRect(clipMin, clipMax, true);
dragonx::util::DrawTiledNoiseRect(dl, clipMin, clipMax, noiseTint);
dl->PopClipRect();
ImVec2 noiseMin(pMin.x + inset, pMin.y + inset);
ImVec2 noiseMax(pMax.x - inset, pMax.y - inset);
// Image rect matches clip bounds exactly — no PushClipRect needed
dragonx::util::DrawTiledNoiseRect(dl, noiseMin, noiseMax, noiseTint);
}
}
@@ -375,18 +381,20 @@ inline void DrawGlassPanel(ImDrawList* dl, const ImVec2& pMin,
// Theme visual effects drawn on ForegroundDrawList so they
// render above card content (text, values, etc.), not below.
auto& fx = effects::ThemeEffects::instance();
ImDrawList* fxDl = ImGui::GetForegroundDrawList();
if (fx.hasRainbowBorder()) {
fx.drawRainbowBorder(fxDl, pMin, pMax, spec.rounding, spec.borderWidth);
if (fx.hasAnyPanelEffect()) {
ImDrawList* fxDl = ImGui::GetForegroundDrawList();
if (fx.hasRainbowBorder()) {
fx.drawRainbowBorder(fxDl, pMin, pMax, spec.rounding, spec.borderWidth);
}
if (fx.hasShimmer()) {
fx.drawShimmer(fxDl, pMin, pMax, spec.rounding);
}
if (fx.hasSpecularGlare()) {
fx.drawSpecularGlare(fxDl, pMin, pMax, spec.rounding);
}
// Per-panel theme effects: edge trace + ember rise
fx.drawPanelEffects(fxDl, pMin, pMax, spec.rounding);
}
if (fx.hasShimmer()) {
fx.drawShimmer(fxDl, pMin, pMax, spec.rounding);
}
if (fx.hasSpecularGlare()) {
fx.drawSpecularGlare(fxDl, pMin, pMax, spec.rounding);
}
// Per-panel theme effects: edge trace + ember rise
fx.drawPanelEffects(fxDl, pMin, pMax, spec.rounding);
} else {
// Low-spec opaque fallback
dl->AddRectFilled(pMin, pMax,
@@ -749,8 +757,10 @@ inline void ApplySmoothScroll(float speed = 12.0f)
s.current = actualY;
}
// Capture mouse wheel when hovered
if (ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows)) {
// Capture mouse wheel when hovered, but not when a popup (combo dropdown
// etc.) is open — let the popup handle its own scrolling exclusively.
bool popupOpen = ImGui::IsPopupOpen("", ImGuiPopupFlags_AnyPopupId | ImGuiPopupFlags_AnyPopupLevel);
if (!popupOpen && ImGui::IsWindowHovered(ImGuiHoveredFlags_ChildWindows)) {
float wheel = ImGui::GetIO().MouseWheel;
if (wheel != 0.0f) {
float step = ImGui::GetTextLineHeightWithSpacing() * 3.0f;