- Add expanded address icon picker with search, bottom-aligned actions, and improved modal sizing - Embed a pickaxe icon font subset and wire it into typography/address icon rendering - Track view-only shielded addresses and prevent sends from non-spendable z-addresses - Improve address transfer dialog sizing, max amount handling, and text clipping - Tune main header layout values in ui.toml - Update README, codebase overview, and third-party license documentation
299 lines
11 KiB
C++
299 lines
11 KiB
C++
// DragonX Wallet - ImGui Edition
|
|
// Copyright 2024-2026 The Hush Developers
|
|
// Released under the GPLv3
|
|
|
|
#pragma once
|
|
|
|
#include "imgui.h"
|
|
#include <string>
|
|
|
|
namespace dragonx {
|
|
namespace ui {
|
|
namespace material {
|
|
|
|
// ============================================================================
|
|
// Material Design Type Scale
|
|
// ============================================================================
|
|
// Based on https://m2.material.io/design/typography/the-type-system.html
|
|
//
|
|
// The type scale is a combination of 13 styles that are supported by the
|
|
// type system. It contains reusable categories of text, each with an
|
|
// intended application and meaning.
|
|
|
|
/**
|
|
* @brief Material Design typography style identifiers
|
|
*/
|
|
enum class TypeStyle {
|
|
H1, // 96sp Light - Large display headers
|
|
H2, // 60sp Light - Display headers
|
|
H3, // 48sp Regular - Section titles
|
|
H4, // 34sp Regular - Section titles
|
|
H5, // 24sp Regular - Card titles, dialog titles
|
|
H6, // 20sp Medium - Section headers, subtitles
|
|
Subtitle1, // 16sp Regular - Secondary information
|
|
Subtitle2, // 14sp Medium - Secondary information
|
|
Body1, // 16sp Regular - Primary body text
|
|
Body2, // 14sp Regular - Secondary body text
|
|
Button, // 14sp Medium - Button labels (uppercase)
|
|
Caption, // 12sp Regular - Timestamps, labels
|
|
Overline, // 10sp Regular - Overline labels (uppercase)
|
|
ButtonSm, // Small button labels
|
|
ButtonLg // Large button labels
|
|
};
|
|
|
|
/**
|
|
* @brief Typography specification for a type style
|
|
*/
|
|
struct TypeSpec {
|
|
float size; // Font size in sp (scaled pixels)
|
|
float letterSpacing; // Letter spacing in px (applied after scaling)
|
|
float lineHeight; // Line height multiplier
|
|
bool uppercase; // Whether text should be uppercase
|
|
|
|
// Font weight is handled by which font is used (Light/Regular/Medium)
|
|
};
|
|
|
|
/**
|
|
* @brief Typography system managing Material Design fonts
|
|
*
|
|
* Loads Ubuntu fonts in Light, Regular, and Medium weights at multiple
|
|
* sizes to implement the Material Design type scale.
|
|
*
|
|
* Usage:
|
|
* // Initialize during startup (after ImGui context)
|
|
* dragonx::ui::material::Typography::instance().load(io);
|
|
*
|
|
* // Use fonts throughout the application
|
|
* ImGui::PushFont(Typography::instance().getFont(TypeStyle::H5));
|
|
* ImGui::Text("Card Title");
|
|
* ImGui::PopFont();
|
|
*
|
|
* // Or use convenience functions
|
|
* Typography::instance().pushFont(TypeStyle::Body1);
|
|
* ImGui::TextWrapped("Body text here...");
|
|
* Typography::instance().popFont();
|
|
*/
|
|
class Typography {
|
|
public:
|
|
/**
|
|
* @brief Get the singleton instance
|
|
*/
|
|
static Typography& instance();
|
|
|
|
/**
|
|
* @brief Load all fonts for the type scale
|
|
*
|
|
* Must be called after ImGui context is created but before first frame.
|
|
*
|
|
* @param io ImGui IO reference
|
|
* @param dpiScale DPI scale factor (default 1.0)
|
|
* @return true if fonts loaded successfully
|
|
*/
|
|
bool load(ImGuiIO& io, float dpiScale = 1.0f);
|
|
|
|
/**
|
|
* @brief Reload fonts at a new DPI scale
|
|
*
|
|
* Call when the display scale changes (e.g., window moved to a different
|
|
* DPI monitor). Clears the existing font atlas and reloads all fonts.
|
|
*
|
|
* @param io ImGui IO reference
|
|
* @param dpiScale New DPI scale factor
|
|
* @return true if fonts reloaded successfully
|
|
*/
|
|
bool reload(ImGuiIO& io, float dpiScale);
|
|
|
|
/**
|
|
* @brief Check if typography system is loaded
|
|
*/
|
|
bool isLoaded() const { return loaded_; }
|
|
|
|
/**
|
|
* @brief Get the current DPI scale
|
|
*/
|
|
float getDpiScale() const { return dpiScale_; }
|
|
|
|
/**
|
|
* @brief Get font for a type style
|
|
*
|
|
* @param style The Material Design type style
|
|
* @return ImFont pointer (never null, returns default if not loaded)
|
|
*/
|
|
ImFont* getFont(TypeStyle style) const;
|
|
|
|
/**
|
|
* @brief Get the spec for a type style
|
|
*
|
|
* @param style The Material Design type style
|
|
* @return TypeSpec with size, spacing, and line height
|
|
*/
|
|
const TypeSpec& getSpec(TypeStyle style) const;
|
|
|
|
/**
|
|
* @brief Push font for a type style
|
|
*
|
|
* Convenience wrapper around ImGui::PushFont(getFont(style))
|
|
*/
|
|
void pushFont(TypeStyle style) const;
|
|
|
|
/**
|
|
* @brief Pop the current font
|
|
*
|
|
* Convenience wrapper around ImGui::PopFont()
|
|
*/
|
|
void popFont() const;
|
|
|
|
// ========================================================================
|
|
// Font Accessors (for common cases)
|
|
// ========================================================================
|
|
|
|
// Headers
|
|
ImFont* h1() const { return getFont(TypeStyle::H1); }
|
|
ImFont* h2() const { return getFont(TypeStyle::H2); }
|
|
ImFont* h3() const { return getFont(TypeStyle::H3); }
|
|
ImFont* h4() const { return getFont(TypeStyle::H4); }
|
|
ImFont* h5() const { return getFont(TypeStyle::H5); }
|
|
ImFont* h6() const { return getFont(TypeStyle::H6); }
|
|
|
|
// Body text
|
|
ImFont* subtitle1() const { return getFont(TypeStyle::Subtitle1); }
|
|
ImFont* subtitle2() const { return getFont(TypeStyle::Subtitle2); }
|
|
ImFont* body1() const { return getFont(TypeStyle::Body1); }
|
|
ImFont* body2() const { return getFont(TypeStyle::Body2); }
|
|
|
|
// UI elements
|
|
ImFont* button() const { return getFont(TypeStyle::Button); }
|
|
ImFont* buttonSm() const { return getFont(TypeStyle::ButtonSm); }
|
|
ImFont* buttonLg() const { return getFont(TypeStyle::ButtonLg); }
|
|
ImFont* caption() const { return getFont(TypeStyle::Caption); }
|
|
ImFont* overline() const { return getFont(TypeStyle::Overline); }
|
|
|
|
// Icon fonts — Material Design Icons merged at specific pixel sizes
|
|
// Use these when you need to render an icon at a specific size via AddText/ImGui::Text.
|
|
// Common sizes: iconSmall (14px), iconMed (18px), iconLarge (24px).
|
|
ImFont* iconSmall() const { return iconFonts_[0] ? iconFonts_[0] : getFont(TypeStyle::Body2); }
|
|
ImFont* iconMed() const { return iconFonts_[1] ? iconFonts_[1] : getFont(TypeStyle::Body1); }
|
|
ImFont* iconLarge() const { return iconFonts_[2] ? iconFonts_[2] : getFont(TypeStyle::H5); }
|
|
ImFont* iconXL() const { return iconFonts_[3] ? iconFonts_[3] : getFont(TypeStyle::H3); }
|
|
ImFont* pickaxeSmall() const { return pickaxeFonts_[0] ? pickaxeFonts_[0] : iconSmall(); }
|
|
ImFont* pickaxeMed() const { return pickaxeFonts_[1] ? pickaxeFonts_[1] : iconMed(); }
|
|
ImFont* pickaxeLarge() const { return pickaxeFonts_[2] ? pickaxeFonts_[2] : iconLarge(); }
|
|
ImFont* pickaxeXL() const { return pickaxeFonts_[3] ? pickaxeFonts_[3] : iconXL(); }
|
|
|
|
ImFont* pickaxeFontForSize(float size) const;
|
|
|
|
static constexpr ImWchar kPickaxeCodepoint = 0xE001;
|
|
|
|
/**
|
|
* @brief Resolve a font name string to ImFont*
|
|
* @param name Font name like "button", "button-sm", "button-lg", "h4", "body1"
|
|
* @return ImFont* pointer, or nullptr if name is empty/unknown
|
|
*/
|
|
ImFont* resolveByName(const std::string& name) const {
|
|
if (name.empty()) return nullptr;
|
|
if (name == "h1") return h1();
|
|
if (name == "h2") return h2();
|
|
if (name == "h3") return h3();
|
|
if (name == "h4") return h4();
|
|
if (name == "h5") return h5();
|
|
if (name == "h6") return h6();
|
|
if (name == "subtitle1") return subtitle1();
|
|
if (name == "subtitle2") return subtitle2();
|
|
if (name == "body1") return body1();
|
|
if (name == "body2") return body2();
|
|
if (name == "button") return button();
|
|
if (name == "button-sm") return buttonSm();
|
|
if (name == "button-lg") return buttonLg();
|
|
if (name == "caption") return caption();
|
|
if (name == "overline") return overline();
|
|
return nullptr;
|
|
}
|
|
|
|
// ========================================================================
|
|
// Text Rendering Helpers
|
|
// ========================================================================
|
|
|
|
/**
|
|
* @brief Render text with a specific type style
|
|
*
|
|
* Handles font push/pop and optional uppercase transformation.
|
|
*
|
|
* @param style The type style to use
|
|
* @param text The text to render
|
|
*/
|
|
void text(TypeStyle style, const char* text) const;
|
|
|
|
/**
|
|
* @brief Render wrapped text with a specific type style
|
|
*
|
|
* @param style The type style to use
|
|
* @param text The text to render
|
|
*/
|
|
void textWrapped(TypeStyle style, const char* text) const;
|
|
|
|
/**
|
|
* @brief Render colored text with a specific type style
|
|
*
|
|
* @param style The type style to use
|
|
* @param color Text color
|
|
* @param text The text to render
|
|
*/
|
|
void textColored(TypeStyle style, ImU32 color, const char* text) const;
|
|
|
|
private:
|
|
Typography() = default;
|
|
~Typography() = default;
|
|
Typography(const Typography&) = delete;
|
|
Typography& operator=(const Typography&) = delete;
|
|
|
|
// Load fonts at a specific size with a specific weight
|
|
ImFont* loadFont(ImGuiIO& io, int weight, float size, const char* name);
|
|
|
|
// Font weight constants
|
|
static constexpr int kWeightLight = 300;
|
|
static constexpr int kWeightRegular = 400;
|
|
static constexpr int kWeightMedium = 500;
|
|
|
|
bool loaded_ = false;
|
|
float dpiScale_ = 1.0f;
|
|
|
|
// Fonts for each type style
|
|
ImFont* fonts_[15] = {};
|
|
|
|
// Icon fonts at different sizes: [0]=small(14), [1]=med(18), [2]=large(24), [3]=xl(40)
|
|
ImFont* iconFonts_[4] = {};
|
|
ImFont* pickaxeFonts_[4] = {};
|
|
static constexpr int kNumIconSizes = 4;
|
|
|
|
// Load an icon-only font at a specific pixel size
|
|
ImFont* loadIconFont(ImGuiIO& io, float size, const char* name);
|
|
ImFont* loadPickaxeFont(ImGuiIO& io, float size, const char* name);
|
|
|
|
// Type specifications
|
|
static const TypeSpec* getTypeSpecs();
|
|
static constexpr int kNumStyles = 15;
|
|
};
|
|
|
|
// ============================================================================
|
|
// Convenience Macros (Optional)
|
|
// ============================================================================
|
|
|
|
// Scoped font push/pop using RAII
|
|
class ScopedFont {
|
|
public:
|
|
explicit ScopedFont(TypeStyle style) {
|
|
Typography::instance().pushFont(style);
|
|
}
|
|
~ScopedFont() {
|
|
Typography::instance().popFont();
|
|
}
|
|
};
|
|
|
|
// Usage: MATERIAL_FONT(H5) { ImGui::Text("Title"); }
|
|
#define MATERIAL_FONT(style) \
|
|
if (dragonx::ui::material::ScopedFont _font{dragonx::ui::material::TypeStyle::style}; true)
|
|
|
|
} // namespace material
|
|
} // namespace ui
|
|
} // namespace dragonx
|