- 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
251 lines
11 KiB
C++
251 lines
11 KiB
C++
// DragonX Wallet - ImGui Edition
|
|
// Copyright 2024-2026 The Hush Developers
|
|
// Released under the GPLv3
|
|
|
|
#pragma once
|
|
|
|
#include <imgui.h>
|
|
#include <vector>
|
|
#include <string>
|
|
|
|
namespace dragonx {
|
|
namespace ui {
|
|
namespace effects {
|
|
|
|
/**
|
|
* @brief Per-theme visual effects system.
|
|
*
|
|
* Draws animated accents (hue-cycling, rainbow borders, shimmer sweeps,
|
|
* glow pulses, positional tinting) driven entirely by TOML theme config.
|
|
* All effects use ImDrawList primitives — no shaders or texture uploads.
|
|
*/
|
|
class ThemeEffects {
|
|
public:
|
|
static ThemeEffects& instance();
|
|
|
|
/// Called once per frame (timing updates)
|
|
void beginFrame();
|
|
|
|
/// Master toggle (from settings)
|
|
void setEnabled(bool enabled) { enabled_ = enabled; }
|
|
bool isEnabled() const { return enabled_; }
|
|
|
|
/// Background opacity (from window opacity slider). Multiplies
|
|
/// all effect alphas so they fade with the backdrop while UI stays opaque.
|
|
void setBackgroundOpacity(float o) { bgOpacity_ = std::max(0.0f, std::min(1.0f, o)); }
|
|
float backgroundOpacity() const { return bgOpacity_; }
|
|
|
|
/// Reduced transparency suppresses shimmer + rainbow border
|
|
void setReducedTransparency(bool rt) { reduced_transparency_ = rt; }
|
|
bool isReducedTransparency() const { return reduced_transparency_; }
|
|
|
|
/// Reload [effects] config from the active UISchema overlay
|
|
void loadFromTheme();
|
|
|
|
// === Drawing APIs ===
|
|
|
|
/// Get the current hue-cycled accent color (optionally phase-shifted)
|
|
ImU32 getAccentColor(float phaseOffset = 0.0f) const;
|
|
|
|
/// Draw rainbow gradient border around a rect (for glass panels)
|
|
void drawRainbowBorder(ImDrawList* dl, ImVec2 pMin, ImVec2 pMax,
|
|
float rounding, float thickness) const;
|
|
|
|
/// Draw shimmer sweep over a rect
|
|
void drawShimmer(ImDrawList* dl, ImVec2 pMin, ImVec2 pMax,
|
|
float rounding) const;
|
|
|
|
/// Get positional hue tint for a given screen Y
|
|
ImU32 getPositionalTint(float screenY) const;
|
|
|
|
/// Tint an existing color by positional hue
|
|
ImU32 tintByPosition(ImU32 baseColor, float screenY) const;
|
|
|
|
/// Draw glow pulse behind a rect (for active elements)
|
|
void drawGlowPulse(ImDrawList* dl, ImVec2 pMin, ImVec2 pMax,
|
|
float rounding) const;
|
|
|
|
/// Draw a light that traces along the border perimeter
|
|
void drawEdgeTrace(ImDrawList* dl, ImVec2 pMin, ImVec2 pMax,
|
|
float rounding) const;
|
|
|
|
/// Draw a border that shifts between two colors over time (gem-like)
|
|
void drawGradientBorderShift(ImDrawList* dl, ImVec2 pMin, ImVec2 pMax,
|
|
float rounding) const;
|
|
|
|
/// Draw ember particles that rise from an element (fire theme)
|
|
void drawEmberRise(ImDrawList* dl, ImVec2 pMin, ImVec2 pMax) const;
|
|
|
|
/// Draw specular glare highlights on a panel (polished surface look)
|
|
void drawSpecularGlare(ImDrawList* dl, ImVec2 pMin, ImVec2 pMax,
|
|
float rounding) const;
|
|
|
|
/// Draw viewport-wide ambient ember particles (fire theme atmosphere)
|
|
void drawViewportEmbers(ImDrawList* dl) const;
|
|
|
|
/// Draw viewport-wide sandstorm particles (wind-driven diagonal sand/dust)
|
|
void drawSandstorm(ImDrawList* dl) const;
|
|
|
|
/// Draw shader-like viewport overlay (color wash + vignette post-processing)
|
|
void drawViewportOverlay(ImDrawList* dl) const;
|
|
|
|
/// Draw all applicable panel effects (edge trace + ember rise on glass panels)
|
|
/// phaseKey provides per-panel phase diversity based on panel position
|
|
void drawPanelEffects(ImDrawList* dl, ImVec2 pMin, ImVec2 pMax,
|
|
float rounding) const;
|
|
|
|
// === Query which effects are available ===
|
|
bool hasRainbowBorder() const { return enabled_ && !reduced_transparency_ && rainbow_border_.enabled; }
|
|
bool hasShimmer() const { return enabled_ && !reduced_transparency_ && shimmer_.enabled; }
|
|
bool hasGlowPulse() const { return enabled_ && glow_pulse_.enabled; }
|
|
bool hasHueCycle() const { return enabled_ && hue_cycle_.enabled; }
|
|
bool hasPositionalHue() const { return enabled_ && positional_hue_.enabled; }
|
|
bool hasEdgeTrace() const { return enabled_ && edge_trace_.enabled; } bool hasGradientBorder() const { return enabled_ && gradient_border_.enabled; } bool hasEmberRise() const { return enabled_ && ember_rise_.enabled; }
|
|
bool hasSpecularGlare() const { return enabled_ && !reduced_transparency_ && specular_glare_.enabled; }
|
|
bool hasSandstorm() const { return enabled_ && sandstorm_.enabled; }
|
|
bool hasViewportOverlay() const { return enabled_ && (viewport_overlay_.colorWashEnabled || viewport_overlay_.vignetteEnabled); }
|
|
|
|
/// True when any per-panel visual effect is active (rainbow, shimmer, specular, edge, ember, gradient)
|
|
bool hasAnyPanelEffect() const {
|
|
return hasRainbowBorder() || hasShimmer() || hasSpecularGlare()
|
|
|| hasEdgeTrace() || hasEmberRise() || hasGradientBorder();
|
|
}
|
|
|
|
/// True when any time-dependent effect is active and needs continuous redraws
|
|
bool hasActiveAnimation() const {
|
|
if (!enabled_) return false;
|
|
return hue_cycle_.enabled || rainbow_border_.enabled || shimmer_.enabled
|
|
|| glow_pulse_.enabled || edge_trace_.enabled || ember_rise_.enabled
|
|
|| gradient_border_.enabled || specular_glare_.enabled || sandstorm_.enabled
|
|
|| (viewport_overlay_.colorWashEnabled
|
|
&& (viewport_overlay_.washRotateSpeed > 0.0f || viewport_overlay_.washPulseSpeed > 0.0f));
|
|
}
|
|
|
|
private:
|
|
ThemeEffects() = default;
|
|
|
|
bool enabled_ = true;
|
|
bool reduced_transparency_ = false;
|
|
float time_ = 0.0f;
|
|
float bgOpacity_ = 1.0f; ///< window-opacity multiplier for effect alphas
|
|
|
|
// Viewport bounds (set each frame)
|
|
float vpMinY_ = 0.0f;
|
|
float vpMaxY_ = 1.0f;
|
|
|
|
// ---- Cached config from [effects] ----
|
|
|
|
struct HueCycleConfig {
|
|
bool enabled = false;
|
|
float speed = 0.1f, sat = 0.6f, val = 0.85f;
|
|
float range = 1.0f, offset = 0.0f;
|
|
} hue_cycle_;
|
|
|
|
struct RainbowBorderConfig {
|
|
bool enabled = false;
|
|
float speed = 0.05f, alpha = 0.25f;
|
|
std::vector<ImU32> stops;
|
|
} rainbow_border_;
|
|
|
|
struct ShimmerConfig {
|
|
bool enabled = false;
|
|
float speed = 0.12f, width = 80.0f, alpha = 0.06f, angle = 30.0f;
|
|
ImU32 color = IM_COL32(255,255,255,255);
|
|
} shimmer_;
|
|
|
|
struct PositionalHueConfig {
|
|
bool enabled = false;
|
|
ImVec4 topColor{1,0.42f,0.62f,1};
|
|
ImVec4 bottomColor{0.4f,0.91f,0.98f,1};
|
|
float strength = 0.3f;
|
|
} positional_hue_;
|
|
|
|
struct GlowPulseConfig {
|
|
bool enabled = false;
|
|
float speed = 2.0f, minAlpha = 0.0f, maxAlpha = 0.15f, radius = 4.0f;
|
|
ImU32 color = IM_COL32(255,255,255,255);
|
|
} glow_pulse_;
|
|
|
|
struct EdgeTraceConfig {
|
|
bool enabled = false;
|
|
float speed = 0.3f; ///< full circuits per second
|
|
float length = 0.20f; ///< fraction of perimeter lit (tail length)
|
|
float thickness = 1.5f; ///< line thickness in pixels
|
|
float alpha = 0.6f; ///< peak alpha at head of trace
|
|
ImU32 color = IM_COL32(255,255,255,255);
|
|
} edge_trace_;
|
|
|
|
struct EmberRiseConfig {
|
|
bool enabled = false;
|
|
int count = 8; ///< number of ember particles
|
|
float speed = 0.4f; ///< rise cycles per second
|
|
float particleSize = 1.5f;///< ember radius in pixels
|
|
float alpha = 0.5f; ///< peak alpha
|
|
ImU32 color = IM_COL32(255, 120, 20, 255);
|
|
} ember_rise_;
|
|
|
|
struct GradientBorderConfig {
|
|
bool enabled = false;
|
|
float speed = 0.15f; ///< full color shift cycles per second
|
|
float thickness = 1.5f; ///< border line thickness in pixels
|
|
float alpha = 0.6f; ///< peak alpha
|
|
ImU32 colorA = IM_COL32(206, 147, 216, 255); ///< first color (amethyst)
|
|
ImU32 colorB = IM_COL32(26, 35, 126, 255); ///< second color (indigo)
|
|
} gradient_border_;
|
|
|
|
struct SpecularGlareConfig {
|
|
bool enabled = false;
|
|
float speed = 0.02f; ///< drift speed (Lissajous orbit cycles/sec)
|
|
float intensity = 0.06f; ///< peak alpha at glare center
|
|
float radius = 0.5f; ///< glare radius as fraction of panel min-dim
|
|
int count = 2; ///< number of specular spots per panel
|
|
ImU32 color = IM_COL32(255, 255, 255, 255);
|
|
} specular_glare_;
|
|
|
|
struct SandstormConfig {
|
|
bool enabled = false;
|
|
int count = 80; ///< number of sand particles
|
|
float speed = 0.35f; ///< base horizontal velocity (viewport widths/sec)
|
|
float windAngle = 15.0f; ///< degrees from horizontal (+ve = downward)
|
|
float particleSize = 1.5f; ///< base particle radius in pixels
|
|
float alpha = 0.35f; ///< peak particle alpha
|
|
float gustSpeed = 0.07f; ///< gust oscillation frequency (Hz)
|
|
float gustStrength = 0.4f; ///< speed variation from gusts (fraction)
|
|
float streakLength = 3.0f; ///< motion blur multiplier for fast particles
|
|
ImU32 color = IM_COL32(200, 160, 96, 255);
|
|
} sandstorm_;
|
|
|
|
struct ViewportOverlayConfig {
|
|
// --- Color wash: full-screen 4-corner gradient overlay ---
|
|
bool colorWashEnabled = false;
|
|
ImU32 cornerTL = IM_COL32(255,100,0,255); ///< top-left corner color (RGB; alpha applied separately)
|
|
ImU32 cornerTR = IM_COL32(68,34,0,255); ///< top-right
|
|
ImU32 cornerBL = IM_COL32(68,17,0,255); ///< bottom-left
|
|
ImU32 cornerBR = IM_COL32(255,153,0,255); ///< bottom-right
|
|
float washAlpha = 0.05f; ///< overall wash intensity
|
|
float washRotateSpeed = 0.0f; ///< corner color rotation (turns/sec)
|
|
float washPulseSpeed = 0.0f; ///< alpha breathing speed (Hz)
|
|
float washPulseDepth = 0.0f; ///< pulse depth (0=none, 1=full fade)
|
|
|
|
// --- Vignette: edge darkening/tinting ---
|
|
bool vignetteEnabled = false;
|
|
ImU32 vignetteColor = IM_COL32(0,0,0,255); ///< tint color at edges
|
|
float vignetteRadius = 0.35f; ///< fade zone as fraction of viewport
|
|
float vignetteAlpha = 0.30f; ///< max alpha at outer edge
|
|
} viewport_overlay_;
|
|
|
|
/// Map a 0..1 fraction to a point on the rounded rect perimeter
|
|
ImVec2 perimeterPoint(ImVec2 pMin, ImVec2 pMax, float t, float rounding = 0.0f) const;
|
|
|
|
// Helper: parse hex color string "#RRGGBB" or "#RRGGBBAA" to ImU32
|
|
static ImU32 parseHexColor(const std::string& hex, ImU32 fallback = IM_COL32(255,255,255,255));
|
|
static ImVec4 parseHexColorVec4(const std::string& hex, ImVec4 fallback = ImVec4(1,1,1,1));
|
|
|
|
// Helper: sample a rotating multi-stop gradient
|
|
ImU32 sampleGradient(float t) const;
|
|
};
|
|
|
|
} // namespace effects
|
|
} // namespace ui
|
|
} // namespace dragonx
|