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)
This commit is contained in:
179
src/ui/widgets/qr_code.cpp
Normal file
179
src/ui/widgets/qr_code.cpp
Normal file
@@ -0,0 +1,179 @@
|
||||
// DragonX Wallet - ImGui Edition
|
||||
// Copyright 2024-2026 The Hush Developers
|
||||
// Released under the GPLv3
|
||||
|
||||
#include "qr_code.h"
|
||||
#include "../schema/ui_schema.h"
|
||||
#include "imgui.h"
|
||||
#include "../../../libs/qrcode/QrCode.hpp"
|
||||
|
||||
#ifdef DRAGONX_USE_DX11
|
||||
#include <d3d11.h>
|
||||
#else
|
||||
#include <SDL3/SDL_opengl.h>
|
||||
#endif
|
||||
#include <cstdint>
|
||||
#include <vector>
|
||||
#include "../../util/logger.h"
|
||||
|
||||
#ifdef DRAGONX_USE_DX11
|
||||
// Forward-declared helper to get D3D11 device from ImGui backend state
|
||||
static ID3D11Device* GetImGuiD3D11Device()
|
||||
{
|
||||
// ImGui_ImplDX11 stores the device in its backend data
|
||||
// Access through the render state stored during init
|
||||
ImGuiIO& io = ImGui::GetIO();
|
||||
if (!io.BackendRendererUserData) return nullptr;
|
||||
// The first field in ImGui_ImplDX11_Data is the device pointer
|
||||
return *reinterpret_cast<ID3D11Device**>(io.BackendRendererUserData);
|
||||
}
|
||||
#endif
|
||||
|
||||
namespace dragonx {
|
||||
namespace ui {
|
||||
|
||||
uintptr_t GenerateQRTexture(const char* data, int* out_width, int* out_height)
|
||||
{
|
||||
if (!data || !data[0]) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
try {
|
||||
// Generate QR code
|
||||
qrcodegen::QrCode qr = qrcodegen::QrCode::encodeText(
|
||||
data, qrcodegen::QrCode::Ecc::MEDIUM);
|
||||
|
||||
const auto& S = schema::UI();
|
||||
int qr_size = qr.getSize();
|
||||
auto qrE = S.drawElement("components.qr-code", "module-scale");
|
||||
int scale = qrE.size >= 0 ? (int)qrE.size : 4;
|
||||
auto qrB = S.drawElement("components.qr-code", "border-modules");
|
||||
int border = qrB.size >= 0 ? (int)qrB.size : 2;
|
||||
|
||||
int img_size = (qr_size + border * 2) * scale;
|
||||
|
||||
// Create pixel data (RGBA)
|
||||
std::vector<unsigned char> pixels(img_size * img_size * 4);
|
||||
|
||||
for (int y = 0; y < img_size; y++) {
|
||||
for (int x = 0; x < img_size; x++) {
|
||||
int qx = x / scale - border;
|
||||
int qy = y / scale - border;
|
||||
|
||||
bool is_black = false;
|
||||
if (qx >= 0 && qx < qr_size && qy >= 0 && qy < qr_size) {
|
||||
is_black = qr.getModule(qx, qy);
|
||||
}
|
||||
|
||||
int idx = (y * img_size + x) * 4;
|
||||
unsigned char color = is_black ? 0 : 255;
|
||||
pixels[idx + 0] = color; // R
|
||||
pixels[idx + 1] = color; // G
|
||||
pixels[idx + 2] = color; // B
|
||||
pixels[idx + 3] = 255; // A
|
||||
}
|
||||
}
|
||||
|
||||
#ifdef DRAGONX_USE_DX11
|
||||
// Create D3D11 texture + shader resource view
|
||||
ID3D11Device* device = GetImGuiD3D11Device();
|
||||
if (!device) return 0;
|
||||
|
||||
D3D11_TEXTURE2D_DESC desc = {};
|
||||
desc.Width = img_size;
|
||||
desc.Height = img_size;
|
||||
desc.MipLevels = 1;
|
||||
desc.ArraySize = 1;
|
||||
desc.Format = DXGI_FORMAT_R8G8B8A8_UNORM;
|
||||
desc.SampleDesc.Count = 1;
|
||||
desc.Usage = D3D11_USAGE_DEFAULT;
|
||||
desc.BindFlags = D3D11_BIND_SHADER_RESOURCE;
|
||||
|
||||
D3D11_SUBRESOURCE_DATA initData = {};
|
||||
initData.pSysMem = pixels.data();
|
||||
initData.SysMemPitch = img_size * 4;
|
||||
|
||||
ID3D11Texture2D* texture = nullptr;
|
||||
HRESULT hr = device->CreateTexture2D(&desc, &initData, &texture);
|
||||
if (FAILED(hr) || !texture) return 0;
|
||||
|
||||
ID3D11ShaderResourceView* srv = nullptr;
|
||||
D3D11_SHADER_RESOURCE_VIEW_DESC srvDesc = {};
|
||||
srvDesc.Format = desc.Format;
|
||||
srvDesc.ViewDimension = D3D11_SRV_DIMENSION_TEXTURE2D;
|
||||
srvDesc.Texture2D.MipLevels = 1;
|
||||
|
||||
hr = device->CreateShaderResourceView(texture, &srvDesc, &srv);
|
||||
texture->Release();
|
||||
if (FAILED(hr) || !srv) return 0;
|
||||
|
||||
if (out_width) *out_width = img_size;
|
||||
if (out_height) *out_height = img_size;
|
||||
|
||||
// Return SRV pointer as uintptr_t (cast to ImTextureID when rendering)
|
||||
return (uintptr_t)srv;
|
||||
#else
|
||||
// Create OpenGL texture
|
||||
GLuint texture;
|
||||
glGenTextures(1, &texture);
|
||||
glBindTexture(GL_TEXTURE_2D, texture);
|
||||
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_NEAREST);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_S, GL_CLAMP_TO_EDGE);
|
||||
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_WRAP_T, GL_CLAMP_TO_EDGE);
|
||||
|
||||
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, img_size, img_size, 0,
|
||||
GL_RGBA, GL_UNSIGNED_BYTE, pixels.data());
|
||||
|
||||
if (out_width) *out_width = img_size;
|
||||
if (out_height) *out_height = img_size;
|
||||
|
||||
return texture;
|
||||
#endif
|
||||
|
||||
} catch (const std::exception& e) {
|
||||
DEBUG_LOGF("QR generation failed: %s\n", e.what());
|
||||
return 0;
|
||||
}
|
||||
}
|
||||
|
||||
void FreeQRTexture(uintptr_t texture_id)
|
||||
{
|
||||
if (texture_id) {
|
||||
#ifdef DRAGONX_USE_DX11
|
||||
ID3D11ShaderResourceView* srv = (ID3D11ShaderResourceView*)texture_id;
|
||||
srv->Release();
|
||||
#else
|
||||
GLuint tex = texture_id;
|
||||
glDeleteTextures(1, &tex);
|
||||
#endif
|
||||
}
|
||||
}
|
||||
|
||||
void RenderQRCode(uintptr_t texture_id, float size)
|
||||
{
|
||||
if (texture_id) {
|
||||
ImGui::Image((ImTextureID)texture_id, ImVec2(size, size));
|
||||
} else {
|
||||
// Draw placeholder
|
||||
ImVec2 cursor = ImGui::GetCursorScreenPos();
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
|
||||
draw_list->AddRectFilled(
|
||||
cursor,
|
||||
ImVec2(cursor.x + size, cursor.y + size),
|
||||
IM_COL32(200, 200, 200, 255)
|
||||
);
|
||||
draw_list->AddRect(
|
||||
cursor,
|
||||
ImVec2(cursor.x + size, cursor.y + size),
|
||||
IM_COL32(100, 100, 100, 255)
|
||||
);
|
||||
|
||||
ImGui::Dummy(ImVec2(size, size));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ui
|
||||
} // namespace dragonx
|
||||
39
src/ui/widgets/qr_code.h
Normal file
39
src/ui/widgets/qr_code.h
Normal file
@@ -0,0 +1,39 @@
|
||||
// DragonX Wallet - ImGui Edition
|
||||
// Copyright 2024-2026 The Hush Developers
|
||||
// Released under the GPLv3
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <cstdint>
|
||||
|
||||
namespace dragonx {
|
||||
namespace ui {
|
||||
|
||||
/**
|
||||
* @brief QR Code rendering utilities
|
||||
*/
|
||||
|
||||
/**
|
||||
* @brief Generate a texture containing a QR code
|
||||
* @param data The data to encode in the QR code
|
||||
* @param out_width Output: width of the texture
|
||||
* @param out_height Output: height of the texture
|
||||
* @return Texture handle (OpenGL texture ID or DX11 SRV pointer), or 0 on failure
|
||||
*/
|
||||
uintptr_t GenerateQRTexture(const char* data, int* out_width, int* out_height);
|
||||
|
||||
/**
|
||||
* @brief Free a QR texture
|
||||
* @param texture_id Texture handle returned by GenerateQRTexture
|
||||
*/
|
||||
void FreeQRTexture(uintptr_t texture_id);
|
||||
|
||||
/**
|
||||
* @brief Render a QR code using ImGui
|
||||
* @param texture_id Texture handle from GenerateQRTexture
|
||||
* @param size Display size (width and height)
|
||||
*/
|
||||
void RenderQRCode(uintptr_t texture_id, float size);
|
||||
|
||||
} // namespace ui
|
||||
} // namespace dragonx
|
||||
Reference in New Issue
Block a user