feat(addresses): improve address labeling and view-only handling
- 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
This commit is contained in:
@@ -90,10 +90,40 @@ inline void DrawTextShadow(ImDrawList* dl, const ImVec2& pos, ImU32 col,
|
||||
// and will return true even when a modal popup covers the rect, which
|
||||
// causes background elements to show hover highlights through dialogs.
|
||||
|
||||
inline int& OverlayDialogActiveFrame()
|
||||
{
|
||||
static int s_frame = -1;
|
||||
return s_frame;
|
||||
}
|
||||
|
||||
inline void MarkOverlayDialogActive()
|
||||
{
|
||||
OverlayDialogActiveFrame() = ImGui::GetFrameCount();
|
||||
}
|
||||
|
||||
inline bool IsCurrentWindowOverlayDialog()
|
||||
{
|
||||
ImGuiWindow* window = ImGui::GetCurrentWindow();
|
||||
for (ImGuiWindow* node = window; node; node = node->ParentWindow) {
|
||||
if (node->Name && strcmp(node->Name, "##OverlayScrim") == 0)
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool IsOverlayDialogBlockingInput()
|
||||
{
|
||||
int activeFrame = OverlayDialogActiveFrame();
|
||||
int currentFrame = ImGui::GetFrameCount();
|
||||
return activeFrame == currentFrame || activeFrame == (currentFrame - 1);
|
||||
}
|
||||
|
||||
inline bool IsRectHovered(const ImVec2& r_min, const ImVec2& r_max, bool clip = true)
|
||||
{
|
||||
if (!ImGui::IsMouseHoveringRect(r_min, r_max, clip))
|
||||
return false;
|
||||
if (IsOverlayDialogBlockingInput() && !IsCurrentWindowOverlayDialog())
|
||||
return false;
|
||||
// If a modal popup is open and it is not the current window, treat
|
||||
// the content as non-hoverable (same logic ImGui uses internally
|
||||
// inside IsWindowContentHoverable for modal blocking).
|
||||
@@ -885,8 +915,11 @@ inline bool DrawDialogTitleBar(const char* title, bool* p_open, ImU32 accent_col
|
||||
// Creates a fullscreen semi-transparent overlay with a centered card dialog.
|
||||
// Similar to the shutdown screen pattern but for interactive dialogs.
|
||||
|
||||
inline bool BeginOverlayDialog(const char* title, bool* p_open, float cardWidth = 460.0f, float scrimOpacity = 0.92f)
|
||||
inline bool BeginOverlayDialog(const char* title, bool* p_open, float cardWidth = 460.0f, float scrimOpacity = 0.92f,
|
||||
float cardBottomViewportRatio = 0.85f)
|
||||
{
|
||||
MarkOverlayDialogActive();
|
||||
|
||||
ImGuiViewport* vp = ImGui::GetMainViewport();
|
||||
ImVec2 vp_pos = vp->Pos;
|
||||
ImVec2 vp_size = vp->Size;
|
||||
@@ -914,6 +947,14 @@ inline bool BeginOverlayDialog(const char* title, bool* p_open, float cardWidth
|
||||
}
|
||||
|
||||
ImDrawList* dl = ImGui::GetWindowDrawList();
|
||||
|
||||
// Consume pointer input on the scrim so the overlay owns clicks and wheel
|
||||
// events even when the click lands outside the card content.
|
||||
ImGui::SetCursorScreenPos(vp_pos);
|
||||
ImGui::InvisibleButton("##OverlayInputBlocker", vp_size,
|
||||
ImGuiButtonFlags_MouseButtonLeft |
|
||||
ImGuiButtonFlags_MouseButtonRight |
|
||||
ImGuiButtonFlags_MouseButtonMiddle);
|
||||
|
||||
// Calculate card position (centered)
|
||||
float cardX = vp_pos.x + (vp_size.x - cardWidth) * 0.5f;
|
||||
@@ -921,7 +962,7 @@ inline bool BeginOverlayDialog(const char* title, bool* p_open, float cardWidth
|
||||
|
||||
// Draw glass card background
|
||||
ImVec2 cardMin(cardX, cardY);
|
||||
ImVec2 cardMax(cardX + cardWidth, vp_pos.y + vp_size.y * 0.85f);
|
||||
ImVec2 cardMax(cardX + cardWidth, vp_pos.y + vp_size.y * cardBottomViewportRatio);
|
||||
|
||||
// Card background with glass effect
|
||||
GlassPanelSpec cardGlass;
|
||||
@@ -930,6 +971,11 @@ inline bool BeginOverlayDialog(const char* title, bool* p_open, float cardWidth
|
||||
cardGlass.borderAlpha = 50;
|
||||
cardGlass.borderWidth = 1.0f;
|
||||
DrawGlassPanel(dl, cardMin, cardMax, cardGlass);
|
||||
|
||||
if (p_open && ImGui::IsMouseClicked(ImGuiMouseButton_Left) &&
|
||||
!ImGui::IsMouseHoveringRect(cardMin, cardMax, false)) {
|
||||
*p_open = false;
|
||||
}
|
||||
|
||||
// Set up child region for card content
|
||||
ImGui::SetCursorScreenPos(ImVec2(cardX, cardY));
|
||||
|
||||
@@ -101,6 +101,7 @@ bool Typography::reload(ImGuiIO& io, float dpiScale)
|
||||
loaded_ = false;
|
||||
for (int i = 0; i < kNumStyles; ++i) fonts_[i] = nullptr;
|
||||
for (int i = 0; i < kNumIconSizes; ++i) iconFonts_[i] = nullptr;
|
||||
for (int i = 0; i < kNumIconSizes; ++i) pickaxeFonts_[i] = nullptr;
|
||||
return load(io, dpiScale);
|
||||
}
|
||||
|
||||
@@ -190,6 +191,13 @@ bool Typography::load(ImGuiIO& io, float dpiScale)
|
||||
iconFonts_[2] = loadIconFont(io, 24.0f * scale, "IconLarge");
|
||||
iconFonts_[3] = loadIconFont(io, 40.0f * scale, "IconXL");
|
||||
|
||||
// Load a one-glyph MDI subset for pickaxe. The glyph is remapped onto a
|
||||
// BMP private-use codepoint so it remains renderable with 16-bit ImWchar.
|
||||
pickaxeFonts_[0] = loadPickaxeFont(io, 14.0f * scale, "PickaxeSmall");
|
||||
pickaxeFonts_[1] = loadPickaxeFont(io, 18.0f * scale, "PickaxeMed");
|
||||
pickaxeFonts_[2] = loadPickaxeFont(io, 24.0f * scale, "PickaxeLarge");
|
||||
pickaxeFonts_[3] = loadPickaxeFont(io, 40.0f * scale, "PickaxeXL");
|
||||
|
||||
// Verify all fonts loaded
|
||||
bool allLoaded = true;
|
||||
for (int i = 0; i < kNumStyles; ++i) {
|
||||
@@ -346,6 +354,51 @@ ImFont* Typography::loadIconFont(ImGuiIO& io, float size, const char* name)
|
||||
return font;
|
||||
}
|
||||
|
||||
ImFont* Typography::loadPickaxeFont(ImGuiIO& io, float size, const char* name)
|
||||
{
|
||||
if (g_mdi_pickaxe_subset_size == 0) {
|
||||
DEBUG_LOGF("Typography: Pickaxe subset font is empty\n");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
void* fontDataCopy = IM_ALLOC(g_mdi_pickaxe_subset_size);
|
||||
memcpy(fontDataCopy, g_mdi_pickaxe_subset_data, g_mdi_pickaxe_subset_size);
|
||||
|
||||
ImFontConfig cfg;
|
||||
cfg.FontDataOwnedByAtlas = true;
|
||||
cfg.OversampleH = 2;
|
||||
cfg.OversampleV = 1;
|
||||
cfg.PixelSnapH = true;
|
||||
cfg.MergeMode = false;
|
||||
cfg.GlyphMinAdvanceX = size;
|
||||
|
||||
static const ImWchar pickaxeRange[] = {
|
||||
Typography::kPickaxeCodepoint,
|
||||
Typography::kPickaxeCodepoint,
|
||||
0,
|
||||
};
|
||||
cfg.GlyphRanges = pickaxeRange;
|
||||
|
||||
snprintf(cfg.Name, sizeof(cfg.Name), "MDIPickaxe %.0fpx", size);
|
||||
|
||||
ImFont* font = io.Fonts->AddFontFromMemoryTTF(fontDataCopy, g_mdi_pickaxe_subset_size, size, &cfg);
|
||||
if (font) {
|
||||
DEBUG_LOGF("Typography: Loaded pickaxe font %s (%.0fpx)\n", name, size);
|
||||
} else {
|
||||
DEBUG_LOGF("Typography: Failed to load pickaxe font %s\n", name);
|
||||
IM_FREE(fontDataCopy);
|
||||
}
|
||||
return font;
|
||||
}
|
||||
|
||||
ImFont* Typography::pickaxeFontForSize(float size) const
|
||||
{
|
||||
if (size <= 15.0f) return pickaxeSmall();
|
||||
if (size <= 20.0f) return pickaxeMed();
|
||||
if (size <= 32.0f) return pickaxeLarge();
|
||||
return pickaxeXL();
|
||||
}
|
||||
|
||||
ImFont* Typography::getFont(TypeStyle style) const
|
||||
{
|
||||
int index = static_cast<int>(style);
|
||||
|
||||
@@ -175,6 +175,14 @@ public:
|
||||
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*
|
||||
@@ -254,10 +262,12 @@ private:
|
||||
|
||||
// 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();
|
||||
|
||||
Reference in New Issue
Block a user