Bring the two Receive-tab modals onto the settings-modal reference language
(presentation-only):
- struct-form BeginOverlayDialog(OverlayDialogSpec{BlurFloat, cardWidth, idSuffix})
replacing the legacy positional overload (idSuffix qrpopup / requestpay)
- StyledButton -> TactileButton (2 + 3 sites)
- drop Request-payment's description divider
No logic touched: the QR texture lifecycle, payment-URI builder, address combo,
and clipboard/notification calls are unchanged. The "DRGX" ticker stays hardcoded
per the existing codebase convention (7 sites, no currency TR key).
Co-Authored-By: Claude Opus 4.8 (1M context) <noreply@anthropic.com>
146 lines
4.6 KiB
C++
146 lines
4.6 KiB
C++
// DragonX Wallet - ImGui Edition
|
|
// Copyright 2024-2026 The Hush Developers
|
|
// Released under the GPLv3
|
|
|
|
#include "qr_popup_dialog.h"
|
|
#include "../../app.h"
|
|
#include "../../util/i18n.h"
|
|
#include "../widgets/qr_code.h"
|
|
#include "../widgets/copy_field.h"
|
|
#include "../schema/ui_schema.h"
|
|
#include "../material/draw_helpers.h"
|
|
#include "../layout.h"
|
|
#include "../theme.h"
|
|
#include "imgui.h"
|
|
|
|
namespace dragonx {
|
|
namespace ui {
|
|
|
|
// Static member initialization
|
|
bool QRPopupDialog::s_open = false;
|
|
std::string QRPopupDialog::s_address;
|
|
std::string QRPopupDialog::s_label;
|
|
uintptr_t QRPopupDialog::s_qr_texture = 0;
|
|
int QRPopupDialog::s_qr_width = 0;
|
|
int QRPopupDialog::s_qr_height = 0;
|
|
|
|
void QRPopupDialog::show(const std::string& address, const std::string& label)
|
|
{
|
|
// Cleanup previous texture
|
|
if (s_qr_texture != 0) {
|
|
FreeQRTexture(s_qr_texture);
|
|
s_qr_texture = 0;
|
|
}
|
|
|
|
s_open = true;
|
|
s_address = address;
|
|
s_label = label;
|
|
|
|
// Generate new QR texture
|
|
s_qr_texture = GenerateQRTexture(address.c_str(), &s_qr_width, &s_qr_height);
|
|
}
|
|
|
|
bool QRPopupDialog::isOpen()
|
|
{
|
|
return s_open;
|
|
}
|
|
|
|
void QRPopupDialog::close()
|
|
{
|
|
s_open = false;
|
|
if (s_qr_texture != 0) {
|
|
FreeQRTexture(s_qr_texture);
|
|
s_qr_texture = 0;
|
|
}
|
|
}
|
|
|
|
void QRPopupDialog::render(App* app)
|
|
{
|
|
(void)app; // Unused for now
|
|
|
|
if (!s_open) return;
|
|
|
|
auto& S = schema::UI();
|
|
auto qr = S.drawElement("dialogs.qr-popup", "qr-code");
|
|
auto actionBtn = S.button("dialogs.qr-popup", "action-button");
|
|
|
|
// Match the key-export modal: 85% of the window width (divide out the dpiScale that
|
|
// BeginOverlayDialog re-applies, so the final card is exactly 85% at any font scale).
|
|
const float cardW = (0.85f * ImGui::GetMainViewport()->Size.x) / Layout::dpiScale();
|
|
material::OverlayDialogSpec ov;
|
|
ov.title = TR("qr_title"); ov.p_open = &s_open;
|
|
ov.style = material::OverlayStyle::BlurFloat;
|
|
ov.cardWidth = cardW; ov.idSuffix = "qrpopup";
|
|
if (material::BeginOverlayDialog(ov)) {
|
|
|
|
// Label if present
|
|
if (!s_label.empty()) {
|
|
ImGui::TextWrapped("%s", s_label.c_str());
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
}
|
|
|
|
// Center the QR code (responsive — larger, to suit the wider modal).
|
|
float window_width = ImGui::GetWindowWidth();
|
|
float qr_size = qr.size > 0 ? (float)qr.size : 280.0f;
|
|
const float responsive = window_width * 0.5f;
|
|
if (responsive > qr_size) qr_size = responsive;
|
|
if (qr_size > 420.0f) qr_size = 420.0f;
|
|
float padding = (window_width - qr_size) / 2.0f;
|
|
if (padding < 0.0f) padding = 0.0f;
|
|
|
|
ImGui::SetCursorPosX(padding);
|
|
|
|
// Render QR code
|
|
if (s_qr_texture != 0) {
|
|
ImGui::Image((ImTextureID)s_qr_texture, ImVec2(qr_size, qr_size));
|
|
} else {
|
|
// Fallback: show error
|
|
ImGui::BeginChild("QRPlaceholder", ImVec2(qr_size, qr_size), true);
|
|
ImGui::TextWrapped("%s", TR("qr_failed"));
|
|
ImGui::EndChild();
|
|
}
|
|
|
|
ImGui::Spacing();
|
|
ImGui::Separator();
|
|
ImGui::Spacing();
|
|
|
|
// Address — click-to-copy field (same formatting as the key-export dialog).
|
|
ImGui::Text("%s", TR("address_label"));
|
|
widgets::AddressCopyField("##QRAddress", s_address);
|
|
|
|
ImGui::Spacing();
|
|
|
|
// Buttons — size each to its label (so "Copy address" never clips), then center the pair.
|
|
ImFont* btnFont = S.resolveFont(actionBtn.font);
|
|
ImGui::PushFont(btnFont);
|
|
const float btnPad = ImGui::GetStyle().FramePadding.x * 2.0f + 24.0f;
|
|
float w_copy = ImGui::CalcTextSize(TR("copy_address")).x + btnPad;
|
|
float w_close = ImGui::CalcTextSize(TR("close")).x + btnPad;
|
|
ImGui::PopFont();
|
|
if (w_copy < actionBtn.width) w_copy = actionBtn.width;
|
|
if (w_close < actionBtn.width) w_close = actionBtn.width;
|
|
const float total_width = w_copy + w_close + ImGui::GetStyle().ItemSpacing.x;
|
|
ImGui::SetCursorPosX((window_width - total_width) / 2.0f);
|
|
|
|
if (material::TactileButton(TR("copy_address"), ImVec2(w_copy, 0), btnFont)) {
|
|
ImGui::SetClipboardText(s_address.c_str());
|
|
}
|
|
ImGui::SameLine();
|
|
if (material::TactileButton(TR("close"), ImVec2(w_close, 0), btnFont)) {
|
|
close();
|
|
}
|
|
material::EndOverlayDialog();
|
|
}
|
|
|
|
// Handle window close button
|
|
if (!s_open && s_qr_texture != 0) {
|
|
FreeQRTexture(s_qr_texture);
|
|
s_qr_texture = 0;
|
|
}
|
|
}
|
|
|
|
} // namespace ui
|
|
} // namespace dragonx
|