Files
ObsidianDragon/src/ui/effects/imgui_acrylic.cpp
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

1179 lines
33 KiB
C++

// DragonX Wallet - ImGui Edition
// Copyright 2024-2026 The Hush Developers
// Released under the GPLv3
#include "imgui_acrylic.h"
#include "../schema/ui_schema.h"
#include "../../util/noise_texture.h"
#ifdef DRAGONX_HAS_GLAD
#include <glad/gl.h>
#endif
#include <cstdio>
#include <cmath>
#include "../../util/logger.h"
// ============================================================================
// Frosted scrim — shared between GLAD and non-GLAD builds.
// Drawn on the popup's draw list as the first command so it appears behind
// the popup content but over the rest of the UI. Replaces ImGui's default
// solid-colour ModalWindowDimBg with a translucent frosted overlay + noise.
// ============================================================================
namespace dragonx { namespace ui { namespace effects { namespace ImGuiAcrylic {
static void DrawFrostedScrim(ImDrawList* dl)
{
const auto& S = ui::schema::UI();
auto sde = [&](const char* key, float fb) -> float {
float v = S.drawElement("components.modal-scrim", key).size;
return v >= 0.0f ? v : fb;
};
ImGuiViewport* vp = ImGui::GetMainViewport();
ImVec2 vpMin = vp->Pos;
ImVec2 vpMax(vp->Pos.x + vp->Size.x, vp->Pos.y + vp->Size.y);
// Semi-transparent white fill (the "frost")
int fillAlpha = (int)sde("fill-alpha", 12.0f);
dl->AddRectFilled(vpMin, vpMax, IM_COL32(255, 255, 255, fillAlpha));
// Noise grain overlay — single draw call via pre-tiled texture
{
int noiseAlpha = (int)sde("noise-alpha", 14.0f);
ImU32 noiseTint = IM_COL32(255, 255, 255, noiseAlpha);
dragonx::util::DrawTiledNoiseRect(dl, vpMin, vpMax, noiseTint);
}
}
} } } } // namespace dragonx::ui::effects::ImGuiAcrylic
// ============================================================================
// Preset table — shared by all backends
// ============================================================================
namespace dragonx { namespace ui { namespace effects { namespace ImGuiAcrylic {
struct PresetDef {
const char* label;
AcrylicQuality quality;
float blur;
};
static const PresetDef kPresets[kPresetCount] = {
{ "Off", AcrylicQuality::Off, 0.0f },
{ "Subtle", AcrylicQuality::Low, 0.6f },
{ "Light", AcrylicQuality::Medium, 1.0f },
{ "Standard", AcrylicQuality::Medium, 1.5f },
{ "Strong", AcrylicQuality::High, 2.5f },
{ "Frosted", AcrylicQuality::High, 4.0f },
};
const char* GetPresetLabel(int preset)
{
if (preset < 0 || preset >= kPresetCount) return "?";
return kPresets[preset].label;
}
AcrylicQuality PresetQuality(int preset)
{
if (preset < 0 || preset >= kPresetCount) return AcrylicQuality::Medium;
return kPresets[preset].quality;
}
float PresetBlur(int preset)
{
if (preset < 0 || preset >= kPresetCount) return 1.0f;
return kPresets[preset].blur;
}
// Find closest preset matching given quality + blur
int MatchPreset(AcrylicQuality q, float blur)
{
// Exact match first
for (int i = 0; i < kPresetCount; ++i) {
if (kPresets[i].quality == q &&
std::abs(kPresets[i].blur - blur) < 0.01f)
return i;
}
// Closest blur within same quality
int best = 3; // Standard fallback
float bestDist = 999.f;
for (int i = 0; i < kPresetCount; ++i) {
if (kPresets[i].quality == q) {
float d = std::abs(kPresets[i].blur - blur);
if (d < bestDist) { bestDist = d; best = i; }
}
}
return best;
}
} } } } // namespace dragonx::ui::effects::ImGuiAcrylic
#ifdef DRAGONX_HAS_GLAD
namespace dragonx {
namespace ui {
namespace effects {
namespace ImGuiAcrylic {
// ============================================================================
// Static State
// ============================================================================
static bool s_initialized = false;
static int s_viewportWidth = 0;
static int s_viewportHeight = 0;
static bool s_backgroundCaptured = false;
// Track window state for acrylic rendering
struct AcrylicWindowState {
ImVec2 windowPos;
ImVec2 windowSize;
AcrylicParams params;
bool active;
};
static AcrylicWindowState s_currentWindow = {};
// ============================================================================
// Initialization
// ============================================================================
bool Init()
{
if (s_initialized) {
return true;
}
AcrylicMaterial& acrylic = getAcrylicMaterial();
if (!acrylic.init()) {
DEBUG_LOGF("ImGuiAcrylic: Failed to initialize acrylic material\n");
return false;
}
s_initialized = true;
DEBUG_LOGF("ImGuiAcrylic: Initialized successfully\n");
return true;
}
void Shutdown()
{
if (!s_initialized) {
return;
}
getAcrylicMaterial().shutdown();
s_initialized = false;
DEBUG_LOGF("ImGuiAcrylic: Shut down\n");
}
bool IsAvailable()
{
return s_initialized && getAcrylicMaterial().isInitialized();
}
// ============================================================================
// Frame Operations
// ============================================================================
void BeginFrame(int width, int height)
{
if (!s_initialized) {
return;
}
// Update viewport dimensions if changed
if (width != s_viewportWidth || height != s_viewportHeight) {
s_viewportWidth = width;
s_viewportHeight = height;
getAcrylicMaterial().resize(width, height);
}
// Capture the first few frames to ensure a clean initial blur,
// then stop. The background (gradient/image/noise) is static;
// re-capturing + re-blurring every frame causes a subtle flicker
// from GPU floating-point non-determinism in the blur shader.
// Resize / theme change already sets dirtyFrames_ via markBackgroundDirty().
static int s_warmupFrames = 3;
if (s_warmupFrames > 0) {
getAcrylicMaterial().markBackgroundDirty();
--s_warmupFrames;
}
s_backgroundCaptured = false;
}
void CaptureBackground()
{
if (!s_initialized || s_backgroundCaptured) {
return;
}
getAcrylicMaterial().captureBackground();
s_backgroundCaptured = true;
}
void InvalidateCapture()
{
if (!s_initialized) return;
getAcrylicMaterial().markBackgroundDirty();
}
// Draw callback: captures framebuffer 0 (which at this point during
// RenderDrawData() contains only the rasterized BackgroundDrawList —
// no UI windows yet) into the acrylic capture buffer.
static void BackgroundCaptureCallback(const ImDrawList*, const ImDrawCmd*)
{
if (!s_initialized) return;
getAcrylicMaterial().captureBackgroundDirect();
s_backgroundCaptured = true;
}
ImDrawCallback GetBackgroundCaptureCallback()
{
return BackgroundCaptureCallback;
}
// ============================================================================
// Drawing Functions
// ============================================================================
void DrawAcrylicRect(ImDrawList* drawList,
const ImVec2& pMin, const ImVec2& pMax,
const AcrylicParams& params,
float rounding)
{
if (!drawList) {
return;
}
// If acrylic not available or disabled, draw fallback
if (!IsAvailable() || !IsEnabled() || !params.enabled) {
drawList->AddRectFilled(pMin, pMax,
ImGui::ColorConvertFloat4ToU32(params.fallbackColor), rounding);
return;
}
// Background capture is now handled by a draw callback inserted
// into the BackgroundDrawList (see GetBackgroundCaptureCallback()).
// On the very first frame the callback hasn't fired yet, so
// drawRect() will fall back to a tinted fill automatically.
// Draw using acrylic material
getAcrylicMaterial().drawRect(drawList, pMin, pMax, params, rounding);
}
void DrawAcrylicRect(ImDrawList* drawList,
const ImVec2& pMin, const ImVec2& pMax,
float rounding)
{
DrawAcrylicRect(drawList, pMin, pMax, AcrylicMaterial::getDarkPreset(), rounding);
}
// ============================================================================
// Window Wrappers
// ============================================================================
bool BeginAcrylicWindow(const char* name, bool* p_open,
ImGuiWindowFlags flags,
const AcrylicParams& params)
{
// Store params for use in EndAcrylicWindow
s_currentWindow.params = params;
s_currentWindow.active = true;
// Ensure dialog windows stay above background windows (MainContent, StatusBar, MenuBar)
if (!(flags & ImGuiWindowFlags_NoBringToFrontOnFocus))
ImGui::SetNextWindowFocus();
// Make window background transparent so acrylic shows through
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0));
bool result = ImGui::Begin(name, p_open, flags);
if (result) {
// Get window bounds for acrylic rendering
s_currentWindow.windowPos = ImGui::GetWindowPos();
s_currentWindow.windowSize = ImGui::GetWindowSize();
// Draw acrylic background
ImDrawList* drawList = ImGui::GetWindowDrawList();
ImVec2 pMin = s_currentWindow.windowPos;
ImVec2 pMax = ImVec2(pMin.x + s_currentWindow.windowSize.x,
pMin.y + s_currentWindow.windowSize.y);
// Get window rounding from style
float rounding = ImGui::GetStyle().WindowRounding;
DrawAcrylicRect(drawList, pMin, pMax, params, rounding);
}
return result;
}
void EndAcrylicWindow()
{
ImGui::End();
ImGui::PopStyleColor(); // WindowBg
s_currentWindow.active = false;
}
// ============================================================================
// Child Region Wrappers
// ============================================================================
bool BeginAcrylicChild(const char* str_id,
const ImVec2& size,
const AcrylicParams& params,
ImGuiChildFlags child_flags,
ImGuiWindowFlags window_flags)
{
// Make child background transparent
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0, 0, 0, 0));
bool result = ImGui::BeginChild(str_id, size, child_flags, window_flags);
if (result) {
// Get child bounds
ImVec2 childPos = ImGui::GetWindowPos();
ImVec2 childSize = ImGui::GetWindowSize();
// Draw acrylic background
ImDrawList* drawList = ImGui::GetWindowDrawList();
ImVec2 pMin = childPos;
ImVec2 pMax = ImVec2(pMin.x + childSize.x, pMin.y + childSize.y);
float rounding = ImGui::GetStyle().ChildRounding;
DrawAcrylicRect(drawList, pMin, pMax, params, rounding);
}
return result;
}
void EndAcrylicChild()
{
ImGui::EndChild();
ImGui::PopStyleColor(); // ChildBg
}
// ============================================================================
// Popup Wrappers
// ============================================================================
bool BeginAcrylicPopup(const char* str_id,
ImGuiWindowFlags flags,
const AcrylicParams& params)
{
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0, 0, 0, 0));
bool result = ImGui::BeginPopup(str_id, flags);
if (result) {
ImVec2 popupPos = ImGui::GetWindowPos();
ImVec2 popupSize = ImGui::GetWindowSize();
ImDrawList* drawList = ImGui::GetWindowDrawList();
ImVec2 pMin = popupPos;
ImVec2 pMax = ImVec2(pMin.x + popupSize.x, pMin.y + popupSize.y);
float rounding = ImGui::GetStyle().PopupRounding;
DrawAcrylicRect(drawList, pMin, pMax, params, rounding);
} else {
ImGui::PopStyleColor(); // Only pop if not opened
}
return result;
}
void EndAcrylicPopup()
{
ImGui::EndPopup();
ImGui::PopStyleColor(); // PopupBg
}
bool BeginAcrylicPopupModal(const char* name, bool* p_open,
ImGuiWindowFlags flags,
const AcrylicParams& params)
{
// Suppress ImGui's built-in dark scrim — we draw our own frosted one
ImGui::PushStyleColor(ImGuiCol_ModalWindowDimBg, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0, 0, 0, 0));
bool result = ImGui::BeginPopupModal(name, p_open, flags);
ImGui::PopStyleColor(); // ModalWindowDimBg (only needed during Begin)
if (result) {
// Draw frosted scrim behind the popup on its own draw list
ImDrawList* drawList = ImGui::GetWindowDrawList();
DrawFrostedScrim(drawList);
ImVec2 popupPos = ImGui::GetWindowPos();
ImVec2 popupSize = ImGui::GetWindowSize();
ImVec2 pMin = popupPos;
ImVec2 pMax = ImVec2(pMin.x + popupSize.x, pMin.y + popupSize.y);
float rounding = ImGui::GetStyle().PopupRounding;
DrawAcrylicRect(drawList, pMin, pMax, params, rounding);
} else {
ImGui::PopStyleColor();
}
return result;
}
// ============================================================================
// Context Menu Helpers
// ============================================================================
bool BeginAcrylicContextItem(const char* str_id,
ImGuiPopupFlags popup_flags,
const AcrylicParams& params)
{
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0, 0, 0, 0));
bool result = ImGui::BeginPopupContextItem(str_id, popup_flags);
if (result) {
ImVec2 popupPos = ImGui::GetWindowPos();
ImVec2 popupSize = ImGui::GetWindowSize();
ImDrawList* drawList = ImGui::GetWindowDrawList();
ImVec2 pMin = popupPos;
ImVec2 pMax = ImVec2(pMin.x + popupSize.x, pMin.y + popupSize.y);
float rounding = ImGui::GetStyle().PopupRounding;
DrawAcrylicRect(drawList, pMin, pMax, params, rounding);
} else {
ImGui::PopStyleColor();
}
return result;
}
bool BeginAcrylicContextWindow(const char* str_id,
ImGuiPopupFlags popup_flags,
const AcrylicParams& params)
{
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0, 0, 0, 0));
bool result = ImGui::BeginPopupContextWindow(str_id, popup_flags);
if (result) {
ImVec2 popupPos = ImGui::GetWindowPos();
ImVec2 popupSize = ImGui::GetWindowSize();
ImDrawList* drawList = ImGui::GetWindowDrawList();
ImVec2 pMin = popupPos;
ImVec2 pMax = ImVec2(pMin.x + popupSize.x, pMin.y + popupSize.y);
float rounding = ImGui::GetStyle().PopupRounding;
DrawAcrylicRect(drawList, pMin, pMax, params, rounding);
} else {
ImGui::PopStyleColor();
}
return result;
}
// ============================================================================
// Sidebar Helper
// ============================================================================
void DrawSidebarBackground(float width, const AcrylicParams& params)
{
ImGuiViewport* viewport = ImGui::GetMainViewport();
// Sidebar starts below menu bar
float menuBarHeight = ImGui::GetFrameHeight();
ImVec2 pMin = ImVec2(viewport->WorkPos.x, viewport->WorkPos.y + menuBarHeight);
ImVec2 pMax = ImVec2(pMin.x + width, viewport->WorkPos.y + viewport->WorkSize.y);
// Draw to background draw list
ImDrawList* drawList = ImGui::GetBackgroundDrawList();
DrawAcrylicRect(drawList, pMin, pMax, params, 0.0f);
}
// ============================================================================
// Settings
// ============================================================================
void SetQuality(AcrylicQuality quality)
{
if (s_initialized) {
getAcrylicMaterial().setQuality(quality);
}
}
AcrylicQuality GetQuality()
{
if (s_initialized) {
return getAcrylicMaterial().getQuality();
}
return AcrylicQuality::Off;
}
void SetEnabled(bool enabled)
{
if (s_initialized) {
getAcrylicMaterial().setEnabled(enabled);
}
}
bool IsEnabled()
{
if (s_initialized) {
return getAcrylicMaterial().isEnabled();
}
return false;
}
void SetBlurMultiplier(float multiplier)
{
if (s_initialized) {
getAcrylicMaterial().setBlurMultiplier(multiplier);
}
}
float GetBlurMultiplier()
{
if (s_initialized) {
return getAcrylicMaterial().getBlurMultiplier();
}
return 1.0f;
}
void SetReducedTransparency(bool reduced)
{
if (s_initialized) {
getAcrylicMaterial().setReducedTransparency(reduced);
}
}
bool GetReducedTransparency()
{
if (s_initialized) {
return getAcrylicMaterial().getReducedTransparency();
}
return false;
}
void SetUIOpacity(float opacity)
{
if (s_initialized) {
getAcrylicMaterial().setUIOpacity(opacity);
}
}
float GetUIOpacity()
{
if (s_initialized) {
return getAcrylicMaterial().getUIOpacity();
}
return 1.0f;
}
void SetNoiseOpacity(float multiplier)
{
if (s_initialized) {
getAcrylicMaterial().setNoiseOpacityMultiplier(multiplier);
}
}
float GetNoiseOpacity()
{
if (s_initialized) {
return getAcrylicMaterial().getNoiseOpacityMultiplier();
}
return 1.0f;
}
const AcrylicSettings& GetSettings()
{
return getAcrylicMaterial().getSettings();
}
void SetSettings(const AcrylicSettings& settings)
{
if (s_initialized) {
getAcrylicMaterial().setSettings(settings);
}
}
void SetPreset(int preset)
{
if (preset < 0 || preset >= kPresetCount) preset = 3;
SetEnabled(preset != 0);
SetQuality(PresetQuality(preset));
SetBlurMultiplier(PresetBlur(preset));
}
int GetPreset()
{
return MatchPreset(GetQuality(), GetBlurMultiplier());
}
void ApplyBlurAmount(float blur)
{
if (blur < 0.001f) {
SetEnabled(false);
SetQuality(AcrylicQuality::Off);
SetBlurMultiplier(0.0f);
} else {
SetEnabled(true);
SetQuality(AcrylicQuality::Low);
SetBlurMultiplier(blur);
}
}
} // namespace ImGuiAcrylic
} // namespace effects
} // namespace ui
} // namespace dragonx
#endif // DRAGONX_HAS_GLAD
// ============================================================================
// Stub Implementations (No GLAD)
// ============================================================================
#ifndef DRAGONX_HAS_GLAD
#ifdef DRAGONX_USE_DX11
// ============================================================================
// DX11 Implementation — mirrors the GLAD version above, delegating to
// AcrylicMaterial which now has a full DX11 backend.
// ============================================================================
namespace dragonx {
namespace ui {
namespace effects {
namespace ImGuiAcrylic {
static bool s_initialized = false;
static int s_viewportWidth = 0;
static int s_viewportHeight = 0;
static bool s_backgroundCaptured = false;
struct AcrylicWindowState {
ImVec2 windowPos;
ImVec2 windowSize;
AcrylicParams params;
bool active;
};
static AcrylicWindowState s_currentWindow = {};
bool Init()
{
if (s_initialized) return true;
AcrylicMaterial& acrylic = getAcrylicMaterial();
if (!acrylic.init()) {
DEBUG_LOGF("ImGuiAcrylic DX11: Failed to initialize acrylic material\n");
return false;
}
s_initialized = true;
DEBUG_LOGF("ImGuiAcrylic DX11: Initialized successfully\n");
return true;
}
void Shutdown()
{
if (!s_initialized) return;
getAcrylicMaterial().shutdown();
s_initialized = false;
}
bool IsAvailable()
{
return s_initialized && getAcrylicMaterial().isInitialized();
}
void BeginFrame(int width, int height)
{
if (!s_initialized) return;
if (width != s_viewportWidth || height != s_viewportHeight) {
s_viewportWidth = width;
s_viewportHeight = height;
getAcrylicMaterial().resize(width, height);
}
// Capture the first few frames to ensure a clean initial blur,
// then stop. Resize / theme change already sets dirtyFrames_ via markBackgroundDirty().
static int s_warmupFrames = 3;
if (s_warmupFrames > 0) {
getAcrylicMaterial().markBackgroundDirty();
--s_warmupFrames;
}
s_backgroundCaptured = false;
}
void CaptureBackground()
{
if (!s_initialized || s_backgroundCaptured) return;
getAcrylicMaterial().captureBackground();
s_backgroundCaptured = true;
}
void InvalidateCapture()
{
if (!s_initialized) return;
getAcrylicMaterial().markBackgroundDirty();
}
static void BackgroundCaptureCallback(const ImDrawList*, const ImDrawCmd*)
{
if (!s_initialized) return;
getAcrylicMaterial().captureBackgroundDirect();
s_backgroundCaptured = true;
}
ImDrawCallback GetBackgroundCaptureCallback()
{
return BackgroundCaptureCallback;
}
void DrawAcrylicRect(ImDrawList* drawList,
const ImVec2& pMin, const ImVec2& pMax,
const AcrylicParams& params,
float rounding)
{
if (!drawList) return;
if (!IsAvailable() || !IsEnabled() || !params.enabled) {
drawList->AddRectFilled(pMin, pMax,
ImGui::ColorConvertFloat4ToU32(params.fallbackColor), rounding);
return;
}
getAcrylicMaterial().drawRect(drawList, pMin, pMax, params, rounding);
}
void DrawAcrylicRect(ImDrawList* drawList,
const ImVec2& pMin, const ImVec2& pMax,
float rounding)
{
DrawAcrylicRect(drawList, pMin, pMax, AcrylicMaterial::getDarkPreset(), rounding);
}
bool BeginAcrylicWindow(const char* name, bool* p_open,
ImGuiWindowFlags flags,
const AcrylicParams& params)
{
s_currentWindow.params = params;
s_currentWindow.active = true;
if (!(flags & ImGuiWindowFlags_NoBringToFrontOnFocus))
ImGui::SetNextWindowFocus();
ImGui::PushStyleColor(ImGuiCol_WindowBg, ImVec4(0, 0, 0, 0));
bool result = ImGui::Begin(name, p_open, flags);
if (result) {
s_currentWindow.windowPos = ImGui::GetWindowPos();
s_currentWindow.windowSize = ImGui::GetWindowSize();
ImDrawList* drawList = ImGui::GetWindowDrawList();
ImVec2 pMin = s_currentWindow.windowPos;
ImVec2 pMax = ImVec2(pMin.x + s_currentWindow.windowSize.x,
pMin.y + s_currentWindow.windowSize.y);
float rounding = ImGui::GetStyle().WindowRounding;
DrawAcrylicRect(drawList, pMin, pMax, params, rounding);
}
return result;
}
void EndAcrylicWindow()
{
ImGui::End();
ImGui::PopStyleColor();
s_currentWindow.active = false;
}
bool BeginAcrylicChild(const char* str_id,
const ImVec2& size,
const AcrylicParams& params,
ImGuiChildFlags child_flags,
ImGuiWindowFlags window_flags)
{
ImGui::PushStyleColor(ImGuiCol_ChildBg, ImVec4(0, 0, 0, 0));
bool result = ImGui::BeginChild(str_id, size, child_flags, window_flags);
if (result) {
ImVec2 childPos = ImGui::GetWindowPos();
ImVec2 childSize = ImGui::GetWindowSize();
ImDrawList* drawList = ImGui::GetWindowDrawList();
ImVec2 pMin = childPos;
ImVec2 pMax = ImVec2(pMin.x + childSize.x, pMin.y + childSize.y);
float rounding = ImGui::GetStyle().ChildRounding;
DrawAcrylicRect(drawList, pMin, pMax, params, rounding);
}
return result;
}
void EndAcrylicChild()
{
ImGui::EndChild();
ImGui::PopStyleColor();
}
bool BeginAcrylicPopup(const char* str_id,
ImGuiWindowFlags flags,
const AcrylicParams& params)
{
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0, 0, 0, 0));
bool result = ImGui::BeginPopup(str_id, flags);
if (result) {
ImVec2 popupPos = ImGui::GetWindowPos();
ImVec2 popupSize = ImGui::GetWindowSize();
ImDrawList* drawList = ImGui::GetWindowDrawList();
ImVec2 pMin = popupPos;
ImVec2 pMax = ImVec2(pMin.x + popupSize.x, pMin.y + popupSize.y);
float rounding = ImGui::GetStyle().PopupRounding;
DrawAcrylicRect(drawList, pMin, pMax, params, rounding);
} else {
ImGui::PopStyleColor();
}
return result;
}
void EndAcrylicPopup()
{
ImGui::EndPopup();
ImGui::PopStyleColor();
}
bool BeginAcrylicPopupModal(const char* name, bool* p_open,
ImGuiWindowFlags flags,
const AcrylicParams& params)
{
ImGui::PushStyleColor(ImGuiCol_ModalWindowDimBg, ImVec4(0, 0, 0, 0));
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0, 0, 0, 0));
bool result = ImGui::BeginPopupModal(name, p_open, flags);
ImGui::PopStyleColor(); // ModalWindowDimBg
if (result) {
ImDrawList* drawList = ImGui::GetWindowDrawList();
DrawFrostedScrim(drawList);
ImVec2 popupPos = ImGui::GetWindowPos();
ImVec2 popupSize = ImGui::GetWindowSize();
ImVec2 pMin = popupPos;
ImVec2 pMax = ImVec2(pMin.x + popupSize.x, pMin.y + popupSize.y);
float rounding = ImGui::GetStyle().PopupRounding;
DrawAcrylicRect(drawList, pMin, pMax, params, rounding);
} else {
ImGui::PopStyleColor();
}
return result;
}
bool BeginAcrylicContextItem(const char* str_id,
ImGuiPopupFlags popup_flags,
const AcrylicParams& params)
{
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0, 0, 0, 0));
bool result = ImGui::BeginPopupContextItem(str_id, popup_flags);
if (result) {
ImVec2 popupPos = ImGui::GetWindowPos();
ImVec2 popupSize = ImGui::GetWindowSize();
ImDrawList* drawList = ImGui::GetWindowDrawList();
ImVec2 pMin = popupPos;
ImVec2 pMax = ImVec2(pMin.x + popupSize.x, pMin.y + popupSize.y);
float rounding = ImGui::GetStyle().PopupRounding;
DrawAcrylicRect(drawList, pMin, pMax, params, rounding);
} else {
ImGui::PopStyleColor();
}
return result;
}
bool BeginAcrylicContextWindow(const char* str_id,
ImGuiPopupFlags popup_flags,
const AcrylicParams& params)
{
ImGui::PushStyleColor(ImGuiCol_PopupBg, ImVec4(0, 0, 0, 0));
bool result = ImGui::BeginPopupContextWindow(str_id, popup_flags);
if (result) {
ImVec2 popupPos = ImGui::GetWindowPos();
ImVec2 popupSize = ImGui::GetWindowSize();
ImDrawList* drawList = ImGui::GetWindowDrawList();
ImVec2 pMin = popupPos;
ImVec2 pMax = ImVec2(pMin.x + popupSize.x, pMin.y + popupSize.y);
float rounding = ImGui::GetStyle().PopupRounding;
DrawAcrylicRect(drawList, pMin, pMax, params, rounding);
} else {
ImGui::PopStyleColor();
}
return result;
}
void DrawSidebarBackground(float width, const AcrylicParams& params)
{
ImGuiViewport* viewport = ImGui::GetMainViewport();
float menuBarHeight = ImGui::GetFrameHeight();
ImVec2 pMin = ImVec2(viewport->WorkPos.x, viewport->WorkPos.y + menuBarHeight);
ImVec2 pMax = ImVec2(pMin.x + width, viewport->WorkPos.y + viewport->WorkSize.y);
ImDrawList* drawList = ImGui::GetBackgroundDrawList();
DrawAcrylicRect(drawList, pMin, pMax, params, 0.0f);
}
void SetQuality(AcrylicQuality quality)
{
if (s_initialized) getAcrylicMaterial().setQuality(quality);
}
AcrylicQuality GetQuality()
{
if (s_initialized) return getAcrylicMaterial().getQuality();
return AcrylicQuality::Off;
}
void SetEnabled(bool enabled)
{
if (s_initialized) getAcrylicMaterial().setEnabled(enabled);
}
bool IsEnabled()
{
if (s_initialized) return getAcrylicMaterial().isEnabled();
return false;
}
void SetBlurMultiplier(float multiplier)
{
if (s_initialized) getAcrylicMaterial().setBlurMultiplier(multiplier);
}
float GetBlurMultiplier()
{
if (s_initialized) return getAcrylicMaterial().getBlurMultiplier();
return 1.0f;
}
void SetReducedTransparency(bool reduced)
{
if (s_initialized) getAcrylicMaterial().setReducedTransparency(reduced);
}
bool GetReducedTransparency()
{
if (s_initialized) return getAcrylicMaterial().getReducedTransparency();
return false;
}
void SetUIOpacity(float opacity)
{
if (s_initialized) getAcrylicMaterial().setUIOpacity(opacity);
}
float GetUIOpacity()
{
if (s_initialized) return getAcrylicMaterial().getUIOpacity();
return 1.0f;
}
void SetNoiseOpacity(float multiplier)
{
if (s_initialized) getAcrylicMaterial().setNoiseOpacityMultiplier(multiplier);
}
float GetNoiseOpacity()
{
if (s_initialized) return getAcrylicMaterial().getNoiseOpacityMultiplier();
return 1.0f;
}
const AcrylicSettings& GetSettings()
{
return getAcrylicMaterial().getSettings();
}
void SetSettings(const AcrylicSettings& settings)
{
if (s_initialized) getAcrylicMaterial().setSettings(settings);
}
void SetPreset(int preset)
{
if (preset < 0 || preset >= kPresetCount) preset = 3;
SetEnabled(preset != 0);
SetQuality(PresetQuality(preset));
SetBlurMultiplier(PresetBlur(preset));
}
int GetPreset()
{
return MatchPreset(GetQuality(), GetBlurMultiplier());
}
void ApplyBlurAmount(float blur)
{
if (blur < 0.001f) {
SetEnabled(false);
SetQuality(AcrylicQuality::Off);
SetBlurMultiplier(0.0f);
} else {
SetEnabled(true);
SetQuality(AcrylicQuality::Low);
SetBlurMultiplier(blur);
}
}
} // namespace ImGuiAcrylic
} // namespace effects
} // namespace ui
} // namespace dragonx
#else // neither GLAD nor DX11
namespace dragonx {
namespace ui {
namespace effects {
namespace ImGuiAcrylic {
bool Init() { return false; }
void Shutdown() {}
bool IsAvailable() { return false; }
void BeginFrame(int, int) {}
void CaptureBackground() {}
void InvalidateCapture() {}
ImDrawCallback GetBackgroundCaptureCallback() { return nullptr; }
void DrawAcrylicRect(ImDrawList* drawList,
const ImVec2& pMin, const ImVec2& pMax,
const AcrylicParams& params,
float rounding)
{
if (drawList) {
drawList->AddRectFilled(pMin, pMax,
ImGui::ColorConvertFloat4ToU32(params.fallbackColor), rounding);
}
}
void DrawAcrylicRect(ImDrawList* drawList,
const ImVec2& pMin, const ImVec2& pMax,
float rounding)
{
if (drawList) {
AcrylicParams params;
drawList->AddRectFilled(pMin, pMax,
ImGui::ColorConvertFloat4ToU32(params.fallbackColor), rounding);
}
}
bool BeginAcrylicWindow(const char* name, bool* p_open,
ImGuiWindowFlags flags,
const AcrylicParams&)
{
if (!(flags & ImGuiWindowFlags_NoBringToFrontOnFocus))
ImGui::SetNextWindowFocus();
return ImGui::Begin(name, p_open, flags);
}
void EndAcrylicWindow()
{
ImGui::End();
}
bool BeginAcrylicChild(const char* str_id,
const ImVec2& size,
const AcrylicParams&,
ImGuiChildFlags child_flags,
ImGuiWindowFlags window_flags)
{
return ImGui::BeginChild(str_id, size, child_flags, window_flags);
}
void EndAcrylicChild()
{
ImGui::EndChild();
}
bool BeginAcrylicPopup(const char* str_id,
ImGuiWindowFlags flags,
const AcrylicParams&)
{
return ImGui::BeginPopup(str_id, flags);
}
void EndAcrylicPopup()
{
ImGui::EndPopup();
}
bool BeginAcrylicPopupModal(const char* name, bool* p_open,
ImGuiWindowFlags flags,
const AcrylicParams&)
{
ImGui::PushStyleColor(ImGuiCol_ModalWindowDimBg, ImVec4(0, 0, 0, 0));
bool result = ImGui::BeginPopupModal(name, p_open, flags);
ImGui::PopStyleColor();
if (result) {
DrawFrostedScrim(ImGui::GetWindowDrawList());
}
return result;
}
bool BeginAcrylicContextItem(const char* str_id,
ImGuiPopupFlags popup_flags,
const AcrylicParams&)
{
return ImGui::BeginPopupContextItem(str_id, popup_flags);
}
bool BeginAcrylicContextWindow(const char* str_id,
ImGuiPopupFlags popup_flags,
const AcrylicParams&)
{
return ImGui::BeginPopupContextWindow(str_id, popup_flags);
}
void DrawSidebarBackground(float, const AcrylicParams&) {}
void SetQuality(AcrylicQuality) {}
AcrylicQuality GetQuality() { return AcrylicQuality::Off; }
void SetEnabled(bool) {}
bool IsEnabled() { return false; }
void SetBlurMultiplier(float) {}
float GetBlurMultiplier() { return 1.0f; }
void SetReducedTransparency(bool) {}
bool GetReducedTransparency() { return false; }
void SetUIOpacity(float) {}
float GetUIOpacity() { return 1.0f; }
void SetNoiseOpacity(float) {}
float GetNoiseOpacity() { return 1.0f; }
static AcrylicSettings s_stubSettings;
const AcrylicSettings& GetSettings() { return s_stubSettings; }
void SetSettings(const AcrylicSettings&) {}
void SetPreset(int) {}
int GetPreset() { return 0; }
void ApplyBlurAmount(float) {}
} // namespace ImGuiAcrylic
} // namespace effects
} // namespace ui
} // namespace dragonx
#endif // DRAGONX_USE_DX11
#endif // !DRAGONX_HAS_GLAD