ObsidianDragon - DragonX ImGui Wallet
Full-node GUI wallet for DragonX cryptocurrency. Built with Dear ImGui, SDL3, and OpenGL3/DX11. Features: - Send/receive shielded and transparent transactions - Autoshield with merged transaction display - Built-in CPU mining (xmrig) - Peer management and network monitoring - Wallet encryption with PIN lock - QR code generation for receive addresses - Transaction history with pagination - Console for direct RPC commands - Cross-platform (Linux, Windows)
This commit is contained in:
192
src/ui/schema/skin_manager.h
Normal file
192
src/ui/schema/skin_manager.h
Normal file
@@ -0,0 +1,192 @@
|
||||
// DragonX Wallet - ImGui Edition
|
||||
// Copyright 2024-2026 The Hush Developers
|
||||
// Released under the GPLv3
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <string>
|
||||
#include <vector>
|
||||
#include <functional>
|
||||
#include <filesystem>
|
||||
|
||||
namespace dragonx {
|
||||
namespace ui {
|
||||
namespace schema {
|
||||
|
||||
/**
|
||||
* @brief Manages bundled and user-installed skins (unified TOML files)
|
||||
*
|
||||
* Responsibilities:
|
||||
* - Enumerate bundled skins from res/themes/ directory (any .toml except ui.toml)
|
||||
* - Enumerate user themes from ~/.config/ObsidianDragon/themes/<folder>/theme.toml
|
||||
* - Import / remove user skins
|
||||
* - Validate skin TOML structure before import
|
||||
* - Track active skin ID in settings
|
||||
*/
|
||||
class SkinManager {
|
||||
public:
|
||||
/**
|
||||
* @brief Metadata about an available skin
|
||||
*/
|
||||
struct SkinInfo {
|
||||
std::string id; ///< Unique identifier (folder name or filename stem)
|
||||
std::string name; ///< Display name from theme.name
|
||||
std::string author; ///< Author from theme.author
|
||||
std::string path; ///< Full filesystem path to the TOML file
|
||||
std::string directory; ///< Folder containing theme.toml (empty for bundled flat files)
|
||||
std::string backgroundImagePath; ///< Resolved path to background image override (empty = use default)
|
||||
std::string logoPath; ///< Resolved path to logo image override (empty = use default)
|
||||
bool dark = true; ///< Dark mode flag from theme.dark
|
||||
bool bundled = true; ///< true = shipped with app, false = user-installed
|
||||
bool valid = true; ///< true if theme.toml passed validation
|
||||
std::string validationError; ///< Error message if !valid
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Result of a skin validation
|
||||
*/
|
||||
struct ValidationResult {
|
||||
bool valid = false;
|
||||
std::string error; ///< Error message if !valid
|
||||
};
|
||||
|
||||
/**
|
||||
* @brief Get the singleton instance
|
||||
*/
|
||||
static SkinManager& instance();
|
||||
|
||||
/**
|
||||
* @brief Scan for available skins (bundled + user)
|
||||
*
|
||||
* Re-scans both the bundled res/ directory and the user skins directory.
|
||||
* Call this on startup and after import/remove operations.
|
||||
*/
|
||||
void refresh();
|
||||
|
||||
/**
|
||||
* @brief Get the list of available skins
|
||||
* @return Sorted list: bundled skins first (with "dragonx" at top), then user skins
|
||||
*/
|
||||
const std::vector<SkinInfo>& available() const { return skins_; }
|
||||
|
||||
/**
|
||||
* @brief Find a skin by ID
|
||||
* @return Pointer to SkinInfo, or nullptr if not found
|
||||
*/
|
||||
const SkinInfo* findById(const std::string& id) const;
|
||||
|
||||
/**
|
||||
* @brief Validate a skin TOML file
|
||||
* @param path Path to the TOML file
|
||||
* @return Validation result with error message if invalid
|
||||
*
|
||||
* Validation rules:
|
||||
* 1. File must be valid TOML
|
||||
* 2. Must contain [theme] table
|
||||
* 3. theme.name must be a non-empty string
|
||||
* 4. theme.palette must be a table with at least --primary and --background
|
||||
* 5. If [globals] exists, it must be a table
|
||||
*/
|
||||
static ValidationResult validateSkinFile(const std::string& path);
|
||||
|
||||
/**
|
||||
* @brief Import a skin file into the user skins directory
|
||||
* @param sourcePath Path to the source TOML file
|
||||
* @return true if imported successfully
|
||||
*
|
||||
* Validates the file first. Copies to user skins directory.
|
||||
* Calls refresh() on success.
|
||||
*/
|
||||
bool importSkin(const std::string& sourcePath);
|
||||
|
||||
/**
|
||||
* @brief Remove a user-installed skin
|
||||
* @param id Skin ID to remove
|
||||
* @return true if removed successfully
|
||||
*
|
||||
* Cannot remove bundled skins. Calls refresh() on success.
|
||||
*/
|
||||
bool removeSkin(const std::string& id);
|
||||
|
||||
/**
|
||||
* @brief Apply a skin by ID
|
||||
* @param id Skin ID to activate
|
||||
* @return true if skin was found and loaded
|
||||
*
|
||||
* Loads the skin file into UISchema and applies ImGui colors.
|
||||
*/
|
||||
bool setActiveSkin(const std::string& id);
|
||||
|
||||
/**
|
||||
* @brief Get the currently active skin ID
|
||||
*/
|
||||
const std::string& activeSkinId() const { return activeSkinId_; }
|
||||
|
||||
/**
|
||||
* @brief Get the bundled skins directory path
|
||||
*/
|
||||
static std::string getBundledSkinsDirectory();
|
||||
|
||||
/**
|
||||
* @brief Get the user skins directory path
|
||||
*/
|
||||
static std::string getUserSkinsDirectory();
|
||||
|
||||
/**
|
||||
* @brief Set callback invoked after skin changes (for image reloading)
|
||||
* @param cb Callback receiving backgroundImagePath and logoPath (empty = use default)
|
||||
*/
|
||||
void setImageReloadCallback(std::function<void(const std::string& bgPath, const std::string& logoPath)> cb) {
|
||||
imageReloadCb_ = std::move(cb);
|
||||
}
|
||||
|
||||
/**
|
||||
* @brief Re-resolve image paths from UISchema and trigger reload callback
|
||||
*
|
||||
* Called by UISchema hot-reload when [theme.images] values change.
|
||||
* Updates the active SkinInfo's image paths and fires imageReloadCb_.
|
||||
*
|
||||
* @param skinId Active skin ID to update
|
||||
* @param tomlPath Path to the TOML file whose images section changed
|
||||
*/
|
||||
void resolveAndReloadImages(const std::string& skinId, const std::string& tomlPath);
|
||||
|
||||
/**
|
||||
* @brief Enable/disable gradient background mode
|
||||
*
|
||||
* When enabled, theme backgrounds are replaced with their gradient
|
||||
* variants (e.g. "gradient_drgx_bg.png" instead of "drgx_bg.png").
|
||||
* Falls back to dark_gradient.png or light_gradient.png when no
|
||||
* theme-specific gradient exists.
|
||||
*/
|
||||
void setGradientMode(bool enabled);
|
||||
bool isGradientMode() const { return gradientMode_; }
|
||||
|
||||
private:
|
||||
SkinManager() = default;
|
||||
~SkinManager() = default;
|
||||
SkinManager(const SkinManager&) = delete;
|
||||
SkinManager& operator=(const SkinManager&) = delete;
|
||||
|
||||
void scanDirectory(const std::string& dir, bool bundled);
|
||||
|
||||
/// Resolve the image directory for a given skin
|
||||
std::filesystem::path resolveImgDir(const SkinInfo* skin) const;
|
||||
|
||||
/// Given an original bg relative path and img dir, resolve the gradient variant
|
||||
std::string resolveGradientBg(const std::string& bgFilename,
|
||||
const std::filesystem::path& imgDir,
|
||||
bool isDark) const;
|
||||
|
||||
/// Common helper: resolve bg (optionally gradient) and logo, fire callback
|
||||
void resolveAndFireCallback(SkinInfo* skin, const std::filesystem::path& imgDir);
|
||||
|
||||
std::vector<SkinInfo> skins_;
|
||||
std::string activeSkinId_ = "dragonx";
|
||||
bool gradientMode_ = false;
|
||||
std::function<void(const std::string&, const std::string&)> imageReloadCb_;
|
||||
};
|
||||
|
||||
} // namespace schema
|
||||
} // namespace ui
|
||||
} // namespace dragonx
|
||||
Reference in New Issue
Block a user