Files
ObsidianDragon/src/ui/material/layout.h
T
DanS 3aee55b49c 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)
2026-02-27 00:26:01 -06:00

352 lines
11 KiB
C++

// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3
#pragma once
#include "imgui.h"
namespace dragonx {
namespace ui {
namespace material {
// ============================================================================
// Material Design 8dp Grid System
// ============================================================================
// All spacing in Material Design is based on an 8dp grid.
// https://m2.material.io/design/layout/spacing-methods.html
constexpr float kGridUnit = 8.0f; // Base unit in dp (device-independent pixels)
// ============================================================================
// Spacing Scale
// ============================================================================
// Use these values for all margins, padding, and gaps
namespace spacing {
constexpr float Xxs = 2.0f; // 0.25x - Very tight spacing
constexpr float Xs = 4.0f; // 0.5x - Extra small
constexpr float Sm = 8.0f; // 1x - Small (default minimum)
constexpr float Md = 16.0f; // 2x - Medium (default standard)
constexpr float Lg = 24.0f; // 3x - Large
constexpr float Xl = 32.0f; // 4x - Extra large
constexpr float Xxl = 40.0f; // 5x - Double extra large
constexpr float Xxxl = 48.0f; // 6x - Triple extra large
// Multiplier helpers
constexpr float Grid(float multiplier) { return kGridUnit * multiplier; }
} // namespace spacing
// ============================================================================
// Component Dimensions
// ============================================================================
// Standard sizes for Material Design components
namespace size {
// Buttons
constexpr float ButtonHeight = 36.0f;
constexpr float ButtonMinWidth = 64.0f;
constexpr float ButtonPaddingH = 16.0f;
constexpr float ButtonPaddingV = 8.0f;
constexpr float ButtonIconGap = 8.0f; // Gap between icon and label
constexpr float ButtonCornerRadius = 4.0f;
// FAB (Floating Action Button)
constexpr float FabSize = 56.0f;
constexpr float FabMiniSize = 40.0f;
constexpr float FabExtendedHeight = 48.0f;
constexpr float FabExtendedPadding = 16.0f;
constexpr float FabCornerRadius = 16.0f; // Half of mini size for circle
// Icons
constexpr float IconSize = 24.0f;
constexpr float IconSizeSm = 18.0f;
constexpr float IconSizeLg = 36.0f;
constexpr float IconButtonSize = 48.0f; // Touch target for icon buttons
// App Bar / Toolbar
constexpr float AppBarHeight = 56.0f; // Mobile
constexpr float AppBarHeightLarge = 64.0f; // Desktop
constexpr float AppBarPadding = 16.0f;
// Navigation
constexpr float NavDrawerWidth = 256.0f;
constexpr float NavRailWidth = 72.0f;
constexpr float NavItemHeight = 48.0f;
constexpr float NavItemPadding = 12.0f;
constexpr float NavSectionPadding = 8.0f;
// Cards
constexpr float CardCornerRadius = 4.0f;
constexpr float CardPadding = 16.0f;
constexpr float CardElevation = 1.0f; // Default elevation in dp
// Dialogs
constexpr float DialogMinWidth = 280.0f;
constexpr float DialogMaxWidth = 560.0f;
constexpr float DialogPadding = 24.0f;
constexpr float DialogTitlePadding = 20.0f;
constexpr float DialogActionGap = 8.0f;
constexpr float DialogCornerRadius = 4.0f;
// Lists
constexpr float ListItemHeight = 48.0f; // Single line
constexpr float ListItemHeightTwoLine = 64.0f;
constexpr float ListItemHeightThreeLine = 88.0f;
constexpr float ListItemPaddingH = 16.0f;
constexpr float ListAvatarSize = 40.0f;
constexpr float ListIconMargin = 32.0f;
// Text Fields
constexpr float TextFieldHeight = 56.0f;
constexpr float TextFieldPadding = 16.0f;
constexpr float TextFieldDenseHeight = 40.0f;
constexpr float TextFieldCornerRadius = 4.0f;
// Chips
constexpr float ChipHeight = 32.0f;
constexpr float ChipPaddingH = 12.0f;
constexpr float ChipCornerRadius = 16.0f;
// Tabs
constexpr float TabHeight = 48.0f;
constexpr float TabMinWidth = 90.0f;
constexpr float TabMaxWidth = 360.0f;
constexpr float TabPaddingH = 16.0f;
constexpr float TabIndicatorHeight = 2.0f;
// Snackbar
constexpr float SnackbarMinWidth = 288.0f;
constexpr float SnackbarMaxWidth = 568.0f;
constexpr float SnackbarHeight = 48.0f;
constexpr float SnackbarPadding = 8.0f;
constexpr float SnackbarMargin = 8.0f;
// Dividers
constexpr float DividerThickness = 1.0f;
constexpr float DividerInset = 16.0f; // For inset dividers
} // namespace size
// ============================================================================
// Responsive Breakpoints
// ============================================================================
// Based on Material Design responsive layout grid
namespace breakpoint {
constexpr float Xs = 0.0f; // Extra small: 0-599dp
constexpr float Sm = 600.0f; // Small: 600-904dp
constexpr float Md = 905.0f; // Medium: 905-1239dp
constexpr float Lg = 1240.0f; // Large: 1240-1439dp
constexpr float Xl = 1440.0f; // Extra large: 1440dp+
// Returns the current breakpoint category
enum class Category { Xs, Sm, Md, Lg, Xl };
inline Category GetCategory(float windowWidth) {
if (windowWidth >= Xl) return Category::Xl;
if (windowWidth >= Lg) return Category::Lg;
if (windowWidth >= Md) return Category::Md;
if (windowWidth >= Sm) return Category::Sm;
return Category::Xs;
}
// Margin values for each breakpoint
inline float GetMargin(Category cat) {
switch (cat) {
case Category::Xs: return 16.0f;
case Category::Sm: return 32.0f;
case Category::Md: return 32.0f; // Or fluid centering
case Category::Lg: return 200.0f;
case Category::Xl: return 200.0f; // Or fluid centering
}
return 16.0f;
}
// Column count for each breakpoint
inline int GetColumns(Category cat) {
switch (cat) {
case Category::Xs: return 4;
case Category::Sm: return 8;
default: return 12;
}
}
// Recommended navigation style
enum class NavStyle { BottomNav, NavRail, NavDrawer };
inline NavStyle GetNavStyle(Category cat) {
switch (cat) {
case Category::Xs: return NavStyle::BottomNav;
case Category::Sm:
case Category::Md: return NavStyle::NavRail;
default: return NavStyle::NavDrawer;
}
}
} // namespace breakpoint
// ============================================================================
// Layout Helpers
// ============================================================================
/**
* @brief Get current window's breakpoint category
*/
inline breakpoint::Category GetCurrentBreakpoint() {
ImVec2 windowSize = ImGui::GetWindowSize();
return breakpoint::GetCategory(windowSize.x);
}
/**
* @brief Get recommended margin for current window
*/
inline float GetCurrentMargin() {
return breakpoint::GetMargin(GetCurrentBreakpoint());
}
/**
* @brief Add horizontal spacing (uses 8dp grid)
* @param units Number of 8dp units (default 1)
*/
inline void HSpace(float units = 1.0f) {
ImGui::SameLine(0, kGridUnit * units);
}
/**
* @brief Add vertical spacing (uses 8dp grid)
* @param units Number of 8dp units (default 1)
*/
inline void VSpace(float units = 1.0f) {
ImGui::Dummy(ImVec2(0, kGridUnit * units));
}
/**
* @brief Begin a padded region
* @param padding Padding in pixels (use spacing:: constants)
*/
inline void BeginPadding(float padding) {
ImGui::BeginGroup();
ImGui::Dummy(ImVec2(0, padding));
ImGui::Indent(padding);
}
/**
* @brief End a padded region
* @param padding Same padding used in BeginPadding
*/
inline void EndPadding(float padding) {
ImGui::Unindent(padding);
ImGui::Dummy(ImVec2(0, padding));
ImGui::EndGroup();
}
/**
* @brief Center the next item horizontally within available width
* @param itemWidth Width of the item to center
*/
inline void CenterHorizontally(float itemWidth) {
float availWidth = ImGui::GetContentRegionAvail().x;
float offset = (availWidth - itemWidth) * 0.5f;
if (offset > 0) {
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + offset);
}
}
/**
* @brief Calculate column width for responsive grid
* @param numColumns Number of columns to span
* @param gutterWidth Gap between columns (default 16dp)
*/
inline float GetColumnWidth(int numColumns = 1, float gutterWidth = spacing::Md) {
float availWidth = ImGui::GetContentRegionAvail().x;
auto cat = GetCurrentBreakpoint();
int totalColumns = breakpoint::GetColumns(cat);
float totalGutter = gutterWidth * (totalColumns - 1);
float columnWidth = (availWidth - totalGutter) / totalColumns;
return columnWidth * numColumns + gutterWidth * (numColumns - 1);
}
// ============================================================================
// Card Layout Helper
// ============================================================================
struct CardLayout {
float width;
float minHeight;
float padding;
float cornerRadius;
int elevation;
CardLayout()
: width(0) // 0 = auto width
, minHeight(0)
, padding(size::CardPadding)
, cornerRadius(size::CardCornerRadius)
, elevation(1)
{}
CardLayout& Width(float w) { width = w; return *this; }
CardLayout& MinHeight(float h) { minHeight = h; return *this; }
CardLayout& Padding(float p) { padding = p; return *this; }
CardLayout& CornerRadius(float r) { cornerRadius = r; return *this; }
CardLayout& Elevation(int e) { elevation = e; return *this; }
};
// ============================================================================
// Navigation Drawer Item
// ============================================================================
struct NavItem {
const char* label;
const char* icon; // Icon font glyph or nullptr
bool selected;
bool enabled;
NavItem(const char* lbl, const char* ico = nullptr)
: label(lbl), icon(ico), selected(false), enabled(true)
{}
NavItem& Selected(bool s) { selected = s; return *this; }
NavItem& Enabled(bool e) { enabled = e; return *this; }
};
// ============================================================================
// Alignment Helpers
// ============================================================================
/**
* @brief Align item to right edge of available space
* @param itemWidth Width of the item
*/
inline void AlignRight(float itemWidth) {
float availWidth = ImGui::GetContentRegionAvail().x;
ImGui::SetCursorPosX(ImGui::GetCursorPosX() + availWidth - itemWidth);
}
/**
* @brief Push items to start from right side (call before group of items)
*/
inline void BeginRightAlign() {
ImGui::BeginGroup();
}
/**
* @brief End right-aligned group and position it
*/
inline void EndRightAlign() {
ImGui::EndGroup();
float groupWidth = ImGui::GetItemRectSize().x;
AlignRight(groupWidth);
}
} // namespace material
} // namespace ui
} // namespace dragonx