1
0
mirror of synced 2024-12-15 09:11:15 +01:00
ImHex/lib/libimhex/source/ui/imgui_imhex_extensions.cpp

1240 lines
49 KiB
C++
Raw Normal View History

#include <hex/ui/imgui_imhex_extensions.h>
#include <imgui.h>
#include <imgui_internal.h>
2023-12-02 23:46:20 +01:00
#include <implot.h>
#include <implot_internal.h>
#include <cimgui.h>
#include <opengl_support.h>
2023-11-20 23:51:50 +01:00
#undef IMGUI_DEFINE_MATH_OPERATORS
#define STB_IMAGE_IMPLEMENTATION
#include <stb_image.h>
#include <lunasvg.h>
2023-12-13 11:24:25 +01:00
#include <set>
2021-01-27 12:04:42 +01:00
#include <string>
#include <hex/api/imhex_api.hpp>
2023-12-13 11:24:25 +01:00
#include <hex/api/task_manager.hpp>
#include <hex/api/theme_manager.hpp>
#include <hex/helpers/logger.hpp>
namespace ImGuiExt {
using namespace ImGui;
namespace {
bool isOpenGLExtensionSupported(const char *name) {
GLint extensionCount = 0;
glGetIntegerv(GL_NUM_EXTENSIONS, &extensionCount);
for (GLint i = 0; i < extensionCount; i++) {
std::string_view extension = reinterpret_cast<const char*>(glGetStringi(GL_EXTENSIONS, i));
if (extension == name) {
return true;
}
}
return false;
}
constexpr auto getGLFilter(Texture::Filter filter) {
switch (filter) {
using enum Texture::Filter;
case Nearest:
return GL_NEAREST;
case Linear:
return GL_LINEAR;
}
return GL_NEAREST;
}
GLuint createTextureFromRGBA8Array(const ImU8 *buffer, int width, int height, Texture::Filter filter) {
GLuint texture;
// Generate texture
glGenTextures(1, &texture);
glBindTexture(GL_TEXTURE_2D, texture);
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, getGLFilter(filter));
glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, getGLFilter(filter));
#if defined(GL_UNPACK_ROW_LENGTH)
glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
#endif
// Allocate storage for the texture
glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA8, width, height, 0, GL_RGBA, GL_UNSIGNED_BYTE, buffer);
return texture;
}
GLuint createMultisampleTextureFromRGBA8Array(const ImU8 *buffer, int width, int height, Texture::Filter filter) {
// Create a regular texture from the RGBA8 array
GLuint texture = createTextureFromRGBA8Array(buffer, width, height, filter);
if (filter == Texture::Filter::Nearest)
return texture;
if (!isOpenGLExtensionSupported("GL_ARB_texture_multisample")) {
hex::log::error("Platform does not support texture multisample! Bailing out!");
return texture;
}
#if defined(GL_TEXTURE_2D_MULTISAMPLE)
constexpr static auto SampleCount = 8;
// Generate renderbuffer
GLuint renderbuffer;
glGenRenderbuffers(1, &renderbuffer);
glBindRenderbuffer(GL_RENDERBUFFER, renderbuffer);
glRenderbufferStorageMultisample(GL_RENDERBUFFER, SampleCount, GL_DEPTH24_STENCIL8, width, height);
// Generate framebuffer
GLuint framebuffer;
glGenFramebuffers(1, &framebuffer);
glBindFramebuffer(GL_FRAMEBUFFER, framebuffer);
// Attach texture to color attachment 0
glFramebufferTexture2D(GL_FRAMEBUFFER, GL_COLOR_ATTACHMENT0, GL_TEXTURE_2D_MULTISAMPLE, texture, 0);
// Attach renderbuffer to depth-stencil attachment
glFramebufferRenderbuffer(GL_FRAMEBUFFER, GL_DEPTH_STENCIL_ATTACHMENT, GL_RENDERBUFFER, renderbuffer);
// Check framebuffer status
if (glCheckFramebufferStatus(GL_FRAMEBUFFER) != GL_FRAMEBUFFER_COMPLETE) {
hex::log::error("Platform claim to support texture multisample but the API is failing! Bailing out!");
return texture;
}
// Unbind framebuffer
glBindFramebuffer(GL_FRAMEBUFFER, 0);
#endif
return texture;
}
}
Texture Texture::fromImage(const ImU8 *buffer, int size, Filter filter) {
2023-12-11 11:42:33 +01:00
if (size == 0)
return {};
2023-12-11 11:42:33 +01:00
unsigned char *imageData = nullptr;
Texture result;
imageData = stbi_load_from_memory(buffer, size, &result.m_width, &result.m_height, nullptr, 4);
if (imageData == nullptr)
return {};
GLuint texture = createMultisampleTextureFromRGBA8Array(imageData, result.m_width, result.m_height, filter);
STBI_FREE(imageData);
result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
return result;
}
Texture Texture::fromImage(std::span<const std::byte> buffer, Filter filter) {
return Texture::fromImage(reinterpret_cast<const ImU8*>(buffer.data()), buffer.size(), filter);
}
2022-10-13 15:13:53 +02:00
Texture Texture::fromImage(const std::fs::path &path, Filter filter) {
return Texture::fromImage(wolv::util::toUTF8String(path).c_str(), filter);
}
Texture Texture::fromImage(const char *path, Filter filter) {
Texture result;
unsigned char *imageData = stbi_load(path, &result.m_width, &result.m_height, nullptr, 4);
if (imageData == nullptr)
return {};
GLuint texture = createMultisampleTextureFromRGBA8Array(imageData, result.m_width, result.m_height, filter);
STBI_FREE(imageData);
result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
return result;
}
Texture Texture::fromGLTexture(unsigned int glTexture, int width, int height) {
Texture texture;
texture.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(glTexture));
texture.m_width = width;
texture.m_height = height;
2023-08-26 12:54:52 +02:00
return texture;
}
Texture Texture::fromBitmap(std::span<const std::byte> buffer, int width, int height, Filter filter) {
return Texture::fromBitmap(reinterpret_cast<const ImU8*>(buffer.data()), buffer.size(), width, height, filter);
}
Texture Texture::fromBitmap(const ImU8 *buffer, int size, int width, int height, Filter filter) {
if (width * height * 4 > size)
return {};
GLuint texture = createMultisampleTextureFromRGBA8Array(buffer, width, height, filter);
Texture result;
result.m_width = width;
result.m_height = height;
result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
return result;
}
Texture Texture::fromSVG(const char *path, int width, int height, Filter filter) {
auto document = lunasvg::Document::loadFromFile(path);
auto bitmap = document->renderToBitmap(width, height);
auto texture = createMultisampleTextureFromRGBA8Array(bitmap.data(), bitmap.width(), bitmap.height(), filter);
Texture result;
result.m_width = bitmap.width();
result.m_height = bitmap.height();
result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
return result;
}
Texture Texture::fromSVG(const std::fs::path &path, int width, int height, Filter filter) {
return Texture::fromSVG(wolv::util::toUTF8String(path).c_str(), width, height, filter);
}
Texture Texture::fromSVG(std::span<const std::byte> buffer, int width, int height, Filter filter) {
auto document = lunasvg::Document::loadFromData(reinterpret_cast<const char*>(buffer.data()), buffer.size());
auto bitmap = document->renderToBitmap(width, height);
bitmap.convertToRGBA();
auto texture = createMultisampleTextureFromRGBA8Array(bitmap.data(), bitmap.width(), bitmap.height(), filter);
Texture result;
result.m_width = bitmap.width();
result.m_height = bitmap.height();
result.m_textureId = reinterpret_cast<ImTextureID>(static_cast<intptr_t>(texture));
return result;
}
Texture::Texture(Texture&& other) noexcept {
if (m_textureId != nullptr)
glDeleteTextures(1, reinterpret_cast<GLuint*>(&m_textureId));
2023-12-19 13:10:25 +01:00
m_textureId = other.m_textureId;
m_width = other.m_width;
m_height = other.m_height;
other.m_textureId = nullptr;
}
Texture& Texture::operator=(Texture&& other) noexcept {
if (m_textureId != nullptr)
glDeleteTextures(1, reinterpret_cast<GLuint*>(&m_textureId));
2023-12-19 13:10:25 +01:00
m_textureId = other.m_textureId;
m_width = other.m_width;
m_height = other.m_height;
other.m_textureId = nullptr;
return *this;
}
Texture::~Texture() {
2023-12-19 13:10:25 +01:00
if (m_textureId == nullptr)
return;
2023-12-19 13:10:25 +01:00
auto glTextureId = static_cast<GLuint>(reinterpret_cast<intptr_t>(m_textureId));
glDeleteTextures(1, &glTextureId);
}
2021-12-07 22:47:41 +01:00
int UpdateStringSizeCallback(ImGuiInputTextCallbackData *data) {
if (data->EventFlag == ImGuiInputTextFlags_CallbackResize) {
auto &string = *static_cast<std::string *>(data->UserData);
string.resize(data->BufTextLen);
data->Buf = string.data();
}
2021-12-07 22:47:41 +01:00
return 0;
}
bool IconHyperlink(const char *icon, const char *label, const ImVec2 &size_arg, ImGuiButtonFlags flags) {
ImGuiWindow *window = GetCurrentWindow();
2021-08-04 14:01:24 +02:00
if (window->SkipItems)
return false;
2022-02-01 22:09:44 +01:00
ImGuiContext &g = *GImGui;
const ImGuiID id = window->GetID(label);
ImVec2 label_size = CalcTextSize(icon, nullptr, false);
label_size.x += CalcTextSize(" ", nullptr, false).x + CalcTextSize(label, nullptr, false).x;
2021-08-04 14:01:24 +02:00
2022-02-01 22:09:44 +01:00
ImVec2 pos = window->DC.CursorPos;
2021-08-04 14:01:24 +02:00
ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y);
const ImRect bb(pos, pos + size);
if (!ItemAdd(bb, id))
return false;
2021-08-21 00:51:50 +02:00
if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat)
2021-08-04 14:01:24 +02:00
flags |= ImGuiButtonFlags_Repeat;
bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
// Render
const ImU32 col = hovered ? GetColorU32(ImGuiCol_ButtonHovered) : GetColorU32(ImGuiCol_ButtonActive);
PushStyleColor(ImGuiCol_Text, ImU32(col));
Text("%s %s", icon, label);
if (hovered)
GetWindowDrawList()->AddLine(ImVec2(pos.x, pos.y + size.y), pos + size, ImU32(col));
2021-08-04 14:01:24 +02:00
PopStyleColor();
2023-12-13 11:24:25 +01:00
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
2021-08-04 14:01:24 +02:00
return pressed;
}
bool Hyperlink(const char *label, const ImVec2 &size_arg, ImGuiButtonFlags flags) {
ImGuiWindow *window = GetCurrentWindow();
2022-02-01 22:09:44 +01:00
ImGuiContext &g = *GImGui;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
2022-02-01 22:09:44 +01:00
ImVec2 pos = window->DC.CursorPos;
ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y);
const ImRect bb(pos, pos + size);
ItemAdd(bb, id);
2021-08-21 00:51:50 +02:00
if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat)
flags |= ImGuiButtonFlags_Repeat;
bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
// Render
2021-01-27 12:04:42 +01:00
const ImU32 col = hovered ? GetColorU32(ImGuiCol_ButtonHovered) : GetColorU32(ImGuiCol_ButtonActive);
PushStyleColor(ImGuiCol_Text, ImU32(col));
TextEx(label, nullptr, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
if (hovered)
GetWindowDrawList()->AddLine(ImVec2(pos.x, pos.y + size.y), pos + size, ImU32(col));
PopStyleColor();
2023-12-13 11:24:25 +01:00
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
return pressed;
}
bool BulletHyperlink(const char *label, const ImVec2 &size_arg, ImGuiButtonFlags flags) {
ImGuiWindow *window = GetCurrentWindow();
2021-01-27 12:04:42 +01:00
if (window->SkipItems)
return false;
2022-02-01 22:09:44 +01:00
ImGuiContext &g = *GImGui;
const ImGuiStyle &style = g.Style;
2022-02-01 22:09:44 +01:00
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
2021-01-27 12:04:42 +01:00
2022-02-01 22:09:44 +01:00
ImVec2 pos = window->DC.CursorPos;
2024-02-24 23:34:29 +01:00
ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y) + ImVec2(g.FontSize + style.FramePadding.x * 2, 0.0F);
2021-01-27 12:04:42 +01:00
const ImRect bb(pos, pos + size);
2022-03-04 19:06:29 +01:00
ItemSize(size, 0);
2021-01-27 12:04:42 +01:00
if (!ItemAdd(bb, id))
return false;
2021-08-21 00:51:50 +02:00
if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat)
2021-01-27 12:04:42 +01:00
flags |= ImGuiButtonFlags_Repeat;
bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
// Render
const ImU32 col = hovered ? GetColorU32(ImGuiCol_ButtonHovered) : GetColorU32(ImGuiCol_ButtonActive);
PushStyleColor(ImGuiCol_Text, ImU32(col));
2024-02-24 23:34:29 +01:00
RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x, g.FontSize * 0.5F), col);
RenderText(bb.Min + ImVec2(g.FontSize * 0.5 + style.FramePadding.x, 0.0F), label, nullptr, false);
2022-03-04 19:06:29 +01:00
GetWindowDrawList()->AddLine(bb.Min + ImVec2(g.FontSize * 0.5 + style.FramePadding.x, size.y), pos + size - ImVec2(g.FontSize * 0.5 + style.FramePadding.x, 0), ImU32(col));
2021-01-27 12:04:42 +01:00
PopStyleColor();
2023-12-13 11:24:25 +01:00
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
2021-01-27 12:04:42 +01:00
return pressed;
}
bool DescriptionButton(const char *label, const char *description, const ImVec2 &size_arg, ImGuiButtonFlags flags) {
ImGuiWindow *window = GetCurrentWindow();
2021-01-27 12:04:42 +01:00
if (window->SkipItems)
return false;
2022-02-01 22:09:44 +01:00
ImGuiContext &g = *GImGui;
const ImGuiStyle &style = g.Style;
2022-02-01 22:09:44 +01:00
const ImGuiID id = window->GetID(label);
const ImVec2 text_size = CalcTextSize((std::string(label) + "\n " + std::string(description)).c_str(), nullptr, true);
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
2021-01-27 12:04:42 +01:00
ImVec2 pos = window->DC.CursorPos;
if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag)
2021-01-27 12:04:42 +01:00
pos.y += window->DC.CurrLineTextBaseOffset - style.FramePadding.y;
2024-02-24 23:34:29 +01:00
ImVec2 size = CalcItemSize(size_arg, text_size.x + style.FramePadding.x * 4.0F, text_size.y + style.FramePadding.y * 4.0F);
2021-01-27 12:04:42 +01:00
const ImRect bb(pos, pos + size);
ItemSize(size, style.FramePadding.y);
if (!ItemAdd(bb, id))
return false;
2021-08-21 00:51:50 +02:00
if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat)
2021-01-27 12:04:42 +01:00
flags |= ImGuiButtonFlags_Repeat;
bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
2023-11-16 09:32:24 +01:00
PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0, 0.5));
PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1);
2021-01-27 12:04:42 +01:00
// Render
const ImU32 col = GetCustomColorU32((held && hovered) ? ImGuiCustomCol_DescButtonActive : hovered ? ImGuiCustomCol_DescButtonHovered
: ImGuiCustomCol_DescButton);
2021-01-27 12:04:42 +01:00
RenderNavHighlight(bb, id);
RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
PushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_ButtonActive));
RenderTextClipped(bb.Min + style.FramePadding * 2, bb.Max - style.FramePadding, label, nullptr, nullptr);
2021-01-27 12:04:42 +01:00
PopStyleColor();
PushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_Text));
auto clipBb = bb;
clipBb.Max.x -= style.FramePadding.x;
RenderTextClipped(bb.Min + style.FramePadding * 2 + ImVec2(style.FramePadding.x * 2, label_size.y), bb.Max - style.FramePadding, description, nullptr, &text_size, style.ButtonTextAlign, &clipBb);
2021-01-27 12:04:42 +01:00
PopStyleColor();
2023-11-16 09:32:24 +01:00
PopStyleVar(2);
2021-01-27 12:04:42 +01:00
// Automatically close popups
// if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
2021-01-27 12:04:42 +01:00
// CloseCurrentPopup();
2023-12-13 11:24:25 +01:00
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
2021-01-27 12:04:42 +01:00
return pressed;
}
bool DescriptionButtonProgress(const char *label, const char *description, float fraction, const ImVec2 &size_arg, ImGuiButtonFlags flags) {
ImGuiWindow *window = GetCurrentWindow();
if (window->SkipItems)
return false;
ImGuiContext &g = *GImGui;
const ImGuiStyle &style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 text_size = CalcTextSize((std::string(label) + "\n " + std::string(description)).c_str(), nullptr, true);
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
ImVec2 pos = window->DC.CursorPos;
if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag)
pos.y += window->DC.CurrLineTextBaseOffset - style.FramePadding.y;
2024-02-24 23:34:29 +01:00
ImVec2 size = CalcItemSize(size_arg, text_size.x + style.FramePadding.x * 4.0F, text_size.y + style.FramePadding.y * 6.0F);
const ImRect bb(pos, pos + size);
ItemSize(size, style.FramePadding.y);
if (!ItemAdd(bb, id))
return false;
if (g.LastItemData.InFlags & ImGuiItemFlags_ButtonRepeat)
flags |= ImGuiButtonFlags_Repeat;
bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
PushStyleVar(ImGuiStyleVar_ButtonTextAlign, ImVec2(0.0, 0.5));
PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1);
// Render
const ImU32 col = GetCustomColorU32((held && hovered) ? ImGuiCustomCol_DescButtonActive : hovered ? ImGuiCustomCol_DescButtonHovered
: ImGuiCustomCol_DescButton);
RenderNavHighlight(bb, id);
RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding);
PushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_ButtonActive));
RenderTextClipped(bb.Min + style.FramePadding * 2, bb.Max - style.FramePadding, label, nullptr, nullptr);
PopStyleColor();
PushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_Text));
auto clipBb = bb;
clipBb.Max.x -= style.FramePadding.x;
RenderTextClipped(bb.Min + style.FramePadding * 2 + ImVec2(style.FramePadding.x * 2, label_size.y), bb.Max - style.FramePadding, description, nullptr, &text_size, style.ButtonTextAlign, &clipBb);
PopStyleColor();
RenderFrame(ImVec2(bb.Min.x, bb.Max.y - 5 * hex::ImHexApi::System::getGlobalScale()), bb.Max, GetColorU32(ImGuiCol_ScrollbarBg), false, style.FrameRounding);
RenderFrame(ImVec2(bb.Min.x, bb.Max.y - 5 * hex::ImHexApi::System::getGlobalScale()), ImVec2(bb.Min.x + fraction * bb.GetSize().x, bb.Max.y), GetColorU32(ImGuiCol_Button), false, style.FrameRounding);
RenderFrame(bb.Min, bb.Max, 0x00, true, style.FrameRounding);
PopStyleVar(2);
// Automatically close popups
// if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
// CloseCurrentPopup();
2023-12-13 11:24:25 +01:00
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
return pressed;
}
void HelpHover(const char *text) {
const auto iconColor = GetStyleColorVec4(ImGuiCol_ButtonActive);
PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
PushStyleColor(ImGuiCol_ButtonHovered, ImVec4(0, 0, 0, 0));
PushStyleColor(ImGuiCol_ButtonActive, ImVec4(0, 0, 0, 0));
PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(0, GetStyle().FramePadding.y));
PushStyleColor(ImGuiCol_Text, iconColor);
Button("(?)");
PopStyleColor();
if (IsItemHovered(ImGuiHoveredFlags_AllowWhenDisabled)) {
SetNextWindowSizeConstraints(ImVec2(GetTextLineHeight() * 25, 0), ImVec2(GetTextLineHeight() * 25, FLT_MAX));
BeginTooltip();
TextFormattedWrapped("{}", text);
EndTooltip();
}
PopStyleVar();
PopStyleColor(3);
}
void UnderlinedText(const char *label, ImColor color, const ImVec2 &size_arg) {
ImGuiWindow *window = GetCurrentWindow();
2021-01-27 12:04:42 +01:00
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
2021-01-27 12:04:42 +01:00
2022-02-01 22:09:44 +01:00
ImVec2 pos = window->DC.CursorPos;
2021-01-27 12:04:42 +01:00
ImVec2 size = CalcItemSize(size_arg, label_size.x, label_size.y);
PushStyleColor(ImGuiCol_Text, ImU32(color));
TextEx(label, nullptr, ImGuiTextFlags_NoWidthForLargeClippedText); // Skip formatting
GetWindowDrawList()->AddLine(ImVec2(pos.x, pos.y + size.y), pos + size, ImU32(color));
2021-01-27 12:04:42 +01:00
PopStyleColor();
}
void TextSpinner(const char *label) {
Text("[%c] %s", "|/-\\"[ImU32(GetTime() * 20) % 4], label);
2021-02-22 13:06:53 +01:00
}
void Header(const char *label, bool firstEntry) {
if (!firstEntry)
NewLine();
SeparatorText(label);
}
void HeaderColored(const char *label, ImColor color, bool firstEntry) {
if (!firstEntry)
NewLine();
TextFormattedColored(color, "{}", label);
Separator();
}
bool InfoTooltip(const char *text, bool isSeparator) {
2021-08-21 00:51:50 +02:00
static double lastMoveTime;
static ImGuiID lastHoveredID;
double currTime = GetTime();
ImGuiID hoveredID = GetHoveredID();
2021-08-21 00:51:50 +02:00
bool result = false;
2021-08-21 00:51:50 +02:00
if (IsItemHovered() && (currTime - lastMoveTime) >= 0.5 && hoveredID == lastHoveredID) {
if (!std::string_view(text).empty()) {
BeginTooltip();
if (isSeparator)
SeparatorText(text);
else
TextUnformatted(text);
EndTooltip();
}
result = true;
}
2021-08-21 00:51:50 +02:00
if (hoveredID != lastHoveredID) {
lastMoveTime = currTime;
}
lastHoveredID = hoveredID;
return result;
}
ImU32 GetCustomColorU32(ImGuiCustomCol idx, float alpha_mul) {
auto &customData = *static_cast<ImHexCustomData *>(GImGui->IO.UserData);
2022-02-01 22:09:44 +01:00
ImVec4 c = customData.Colors[idx];
c.w *= GImGui->Style.Alpha * alpha_mul;
return ColorConvertFloat4ToU32(c);
}
2021-08-21 00:51:50 +02:00
ImVec4 GetCustomColorVec4(ImGuiCustomCol idx, float alpha_mul) {
auto &customData = *static_cast<ImHexCustomData *>(GImGui->IO.UserData);
2022-02-01 22:09:44 +01:00
ImVec4 c = customData.Colors[idx];
2021-08-21 00:51:50 +02:00
c.w *= GImGui->Style.Alpha * alpha_mul;
return c;
}
float GetCustomStyleFloat(ImGuiCustomStyle idx) {
auto &customData = *static_cast<ImHexCustomData *>(GImGui->IO.UserData);
switch (idx) {
case ImGuiCustomStyle_WindowBlur:
return customData.styles.WindowBlur;
default:
2024-02-24 23:34:29 +01:00
return 0.0F;
}
}
ImVec2 GetCustomStyleVec2(ImGuiCustomStyle idx) {
switch (idx) {
default:
return { };
}
}
void StyleCustomColorsDark() {
auto &colors = static_cast<ImHexCustomData *>(GImGui->IO.UserData)->Colors;
2022-02-01 22:09:44 +01:00
colors[ImGuiCustomCol_DescButton] = ImColor(20, 20, 20);
colors[ImGuiCustomCol_DescButtonHovered] = ImColor(40, 40, 40);
2022-02-01 22:09:44 +01:00
colors[ImGuiCustomCol_DescButtonActive] = ImColor(60, 60, 60);
2021-08-21 00:51:50 +02:00
2022-02-01 22:09:44 +01:00
colors[ImGuiCustomCol_ToolbarGray] = ImColor(230, 230, 230);
colors[ImGuiCustomCol_ToolbarRed] = ImColor(231, 76, 60);
colors[ImGuiCustomCol_ToolbarYellow] = ImColor(241, 196, 15);
2022-02-01 22:09:44 +01:00
colors[ImGuiCustomCol_ToolbarGreen] = ImColor(56, 139, 66);
colors[ImGuiCustomCol_ToolbarBlue] = ImColor(6, 83, 155);
colors[ImGuiCustomCol_ToolbarPurple] = ImColor(103, 42, 120);
2022-02-01 22:09:44 +01:00
colors[ImGuiCustomCol_ToolbarBrown] = ImColor(219, 179, 119);
colors[ImGuiCustomCol_Highlight] = ImColor(77, 198, 155);
feat: Greatly improved the IEEE754 tool (#1047) I just realized one feature request existed about this tool and have added a comment to it referring this pr. Errors and additions are described in the fork commit already. I'm not sure if I should repeat them here again. I have tested the changes thoroughly, but it is always possible some fringe case was not tested and is incorrect. The tests were done using the many similar online calculators for IEEE 754 floating point formats. IEEE 745 floating point tool redesign modeled after 'float toy' web app (http://evanw.github.io/float-toy/) Streamlined output using colors and compact layout which can be further simplified. Chosen display mode (detailed or simplified) is automatically saved and set on new sessions. Edit the binary bits, the integer hexadecimal or the floating point decimal values and the entire app will update with the change. Supports the main IEEE745 standard formats (half, single and double precision) together with custom formats of size <= 64 bits. Each format choice uses and displays the number of significant decimal digits defined by the mantissa size. Added labels to identify the location of each bit box inside the binary representation. Satisfies round trip / idempotent (reproducing) conversion property Added theme colors, radio buttons for display mode and a clear button that resets the tool. Removed previously and incorrectly added locale translation to various labels and languages Attempted to adhere to code style formatting using existing code as example. An effort was made to use preferred variable types and functions from std namespace when appropriate. Attempted to document code using comments. Not implemented / left to complete at an later time Arbitrary width and precision formats. Extended precision formats. Shortest string property. hexadecimal floating point display and conversions.
2023-05-19 21:18:38 +02:00
colors[ImGuiCustomCol_IEEEToolSign] = ImColor(93, 93, 127);
colors[ImGuiCustomCol_IEEEToolExp] = ImColor(93, 127, 93);
colors[ImGuiCustomCol_IEEEToolMantissa] = ImColor(127, 93, 93);
}
void StyleCustomColorsLight() {
auto &colors = static_cast<ImHexCustomData *>(GImGui->IO.UserData)->Colors;
2022-02-01 22:09:44 +01:00
colors[ImGuiCustomCol_DescButton] = ImColor(230, 230, 230);
colors[ImGuiCustomCol_DescButtonHovered] = ImColor(210, 210, 210);
2022-02-01 22:09:44 +01:00
colors[ImGuiCustomCol_DescButtonActive] = ImColor(190, 190, 190);
2021-08-21 00:51:50 +02:00
2022-02-01 22:09:44 +01:00
colors[ImGuiCustomCol_ToolbarGray] = ImColor(25, 25, 25);
colors[ImGuiCustomCol_ToolbarRed] = ImColor(231, 76, 60);
colors[ImGuiCustomCol_ToolbarYellow] = ImColor(241, 196, 15);
2022-02-01 22:09:44 +01:00
colors[ImGuiCustomCol_ToolbarGreen] = ImColor(56, 139, 66);
colors[ImGuiCustomCol_ToolbarBlue] = ImColor(6, 83, 155);
colors[ImGuiCustomCol_ToolbarPurple] = ImColor(103, 42, 120);
2022-02-01 22:09:44 +01:00
colors[ImGuiCustomCol_ToolbarBrown] = ImColor(219, 179, 119);
colors[ImGuiCustomCol_Highlight] = ImColor(41, 151, 112);
feat: Greatly improved the IEEE754 tool (#1047) I just realized one feature request existed about this tool and have added a comment to it referring this pr. Errors and additions are described in the fork commit already. I'm not sure if I should repeat them here again. I have tested the changes thoroughly, but it is always possible some fringe case was not tested and is incorrect. The tests were done using the many similar online calculators for IEEE 754 floating point formats. IEEE 745 floating point tool redesign modeled after 'float toy' web app (http://evanw.github.io/float-toy/) Streamlined output using colors and compact layout which can be further simplified. Chosen display mode (detailed or simplified) is automatically saved and set on new sessions. Edit the binary bits, the integer hexadecimal or the floating point decimal values and the entire app will update with the change. Supports the main IEEE745 standard formats (half, single and double precision) together with custom formats of size <= 64 bits. Each format choice uses and displays the number of significant decimal digits defined by the mantissa size. Added labels to identify the location of each bit box inside the binary representation. Satisfies round trip / idempotent (reproducing) conversion property Added theme colors, radio buttons for display mode and a clear button that resets the tool. Removed previously and incorrectly added locale translation to various labels and languages Attempted to adhere to code style formatting using existing code as example. An effort was made to use preferred variable types and functions from std namespace when appropriate. Attempted to document code using comments. Not implemented / left to complete at an later time Arbitrary width and precision formats. Extended precision formats. Shortest string property. hexadecimal floating point display and conversions.
2023-05-19 21:18:38 +02:00
colors[ImGuiCustomCol_IEEEToolSign] = ImColor(187, 187, 255);
colors[ImGuiCustomCol_IEEEToolExp] = ImColor(187, 255, 187);
colors[ImGuiCustomCol_IEEEToolMantissa] = ImColor(255, 187,187);
}
void StyleCustomColorsClassic() {
auto &colors = static_cast<ImHexCustomData *>(GImGui->IO.UserData)->Colors;
2022-02-01 22:09:44 +01:00
colors[ImGuiCustomCol_DescButton] = ImColor(40, 40, 80);
colors[ImGuiCustomCol_DescButtonHovered] = ImColor(60, 60, 100);
2022-02-01 22:09:44 +01:00
colors[ImGuiCustomCol_DescButtonActive] = ImColor(80, 80, 120);
2021-08-21 00:51:50 +02:00
2022-02-01 22:09:44 +01:00
colors[ImGuiCustomCol_ToolbarGray] = ImColor(230, 230, 230);
colors[ImGuiCustomCol_ToolbarRed] = ImColor(231, 76, 60);
colors[ImGuiCustomCol_ToolbarYellow] = ImColor(241, 196, 15);
2022-02-01 22:09:44 +01:00
colors[ImGuiCustomCol_ToolbarGreen] = ImColor(56, 139, 66);
colors[ImGuiCustomCol_ToolbarBlue] = ImColor(6, 83, 155);
colors[ImGuiCustomCol_ToolbarPurple] = ImColor(103, 42, 120);
2022-02-01 22:09:44 +01:00
colors[ImGuiCustomCol_ToolbarBrown] = ImColor(219, 179, 119);
colors[ImGuiCustomCol_Highlight] = ImColor(77, 198, 155);
feat: Greatly improved the IEEE754 tool (#1047) I just realized one feature request existed about this tool and have added a comment to it referring this pr. Errors and additions are described in the fork commit already. I'm not sure if I should repeat them here again. I have tested the changes thoroughly, but it is always possible some fringe case was not tested and is incorrect. The tests were done using the many similar online calculators for IEEE 754 floating point formats. IEEE 745 floating point tool redesign modeled after 'float toy' web app (http://evanw.github.io/float-toy/) Streamlined output using colors and compact layout which can be further simplified. Chosen display mode (detailed or simplified) is automatically saved and set on new sessions. Edit the binary bits, the integer hexadecimal or the floating point decimal values and the entire app will update with the change. Supports the main IEEE745 standard formats (half, single and double precision) together with custom formats of size <= 64 bits. Each format choice uses and displays the number of significant decimal digits defined by the mantissa size. Added labels to identify the location of each bit box inside the binary representation. Satisfies round trip / idempotent (reproducing) conversion property Added theme colors, radio buttons for display mode and a clear button that resets the tool. Removed previously and incorrectly added locale translation to various labels and languages Attempted to adhere to code style formatting using existing code as example. An effort was made to use preferred variable types and functions from std namespace when appropriate. Attempted to document code using comments. Not implemented / left to complete at an later time Arbitrary width and precision formats. Extended precision formats. Shortest string property. hexadecimal floating point display and conversions.
2023-05-19 21:18:38 +02:00
colors[ImGuiCustomCol_IEEEToolSign] = ImColor(93, 93, 127);
colors[ImGuiCustomCol_IEEEToolExp] = ImColor(93, 127, 93);
colors[ImGuiCustomCol_IEEEToolMantissa] = ImColor(127, 93, 93);
}
void OpenPopupInWindow(const char *window_name, const char *popup_name) {
if (Begin(window_name)) {
OpenPopup(popup_name);
}
End();
}
2021-08-21 00:51:50 +02:00
bool TitleBarButton(const char *label, ImVec2 size_arg) {
ImGuiWindow *window = GetCurrentWindow();
2021-08-21 00:51:50 +02:00
if (window->SkipItems)
return false;
2022-02-01 22:09:44 +01:00
ImGuiContext &g = *GImGui;
const ImGuiStyle &style = g.Style;
2022-02-01 22:09:44 +01:00
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
2021-08-21 00:51:50 +02:00
ImVec2 pos = window->DC.CursorPos;
2024-02-24 23:34:29 +01:00
ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0F, label_size.y + style.FramePadding.y * 2.0F);
2021-08-21 00:51:50 +02:00
const ImRect bb(pos, pos + size);
ItemSize(size, style.FramePadding.y);
if (!ItemAdd(bb, id))
return false;
bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held);
// Render
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered
: ImGuiCol_Button);
2021-08-21 00:51:50 +02:00
RenderNavHighlight(bb, id);
RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, label, nullptr, &label_size, style.ButtonTextAlign, &bb);
2021-08-21 00:51:50 +02:00
// Automatically close popups
// if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
2021-08-21 00:51:50 +02:00
// CloseCurrentPopup();
2023-12-13 11:24:25 +01:00
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags);
2021-08-21 00:51:50 +02:00
return pressed;
}
bool ToolBarButton(const char *symbol, ImVec4 color) {
ImGuiWindow *window = GetCurrentWindow();
2021-08-21 00:51:50 +02:00
if (window->SkipItems)
return false;
color.w = 1.0F;
2022-02-01 22:09:44 +01:00
ImGuiContext &g = *GImGui;
const ImGuiStyle &style = g.Style;
2022-02-01 22:09:44 +01:00
const ImGuiID id = window->GetID(symbol);
const ImVec2 label_size = CalcTextSize(symbol, nullptr, true);
2021-08-21 00:51:50 +02:00
ImVec2 pos = window->DC.CursorPos;
2024-02-24 23:34:29 +01:00
ImVec2 size = CalcItemSize(ImVec2(1, 1) * GetCurrentWindow()->MenuBarHeight(), label_size.x + style.FramePadding.x * 2.0F, label_size.y + style.FramePadding.y * 2.0F);
2021-08-21 00:51:50 +02:00
const ImRect bb(pos, pos + size);
ItemSize(size, style.FramePadding.y);
if (!ItemAdd(bb, id))
return false;
bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held);
PushStyleColor(ImGuiCol_Text, color);
// Render
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered
: ImGuiCol_MenuBarBg);
2021-08-21 00:51:50 +02:00
RenderNavHighlight(bb, id);
RenderFrame(bb.Min, bb.Max, col, false, style.FrameRounding);
RenderTextClipped(bb.Min + style.FramePadding, bb.Max - style.FramePadding, symbol, nullptr, &label_size, style.ButtonTextAlign, &bb);
2021-08-21 00:51:50 +02:00
PopStyleColor();
// Automatically close popups
// if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
2021-08-21 00:51:50 +02:00
// CloseCurrentPopup();
2023-12-13 11:24:25 +01:00
IMGUI_TEST_ENGINE_ITEM_INFO(id, symbol, g.LastItemData.StatusFlags);
2021-08-21 00:51:50 +02:00
return pressed;
}
bool IconButton(const char *symbol, ImVec4 color, ImVec2 size_arg) {
ImGuiWindow *window = GetCurrentWindow();
if (window->SkipItems)
return false;
color.w = 1.0F;
2022-02-01 22:09:44 +01:00
ImGuiContext &g = *GImGui;
const ImGuiStyle &style = g.Style;
2022-02-01 22:09:44 +01:00
const ImGuiID id = window->GetID(symbol);
const ImVec2 label_size = CalcTextSize(symbol, nullptr, true);
ImVec2 pos = window->DC.CursorPos;
2024-02-24 23:34:29 +01:00
ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0F, label_size.y + style.FramePadding.y * 2.0F);
const ImRect bb(pos, pos + size);
ItemSize(size, style.FramePadding.y);
if (!ItemAdd(bb, id))
return false;
bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held);
PushStyleColor(ImGuiCol_Text, color);
// Render
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered
: ImGuiCol_Button);
RenderNavHighlight(bb, id);
RenderFrame(bb.Min, bb.Max, col, true, style.FrameRounding);
RenderTextClipped(bb.Min + style.FramePadding * ImVec2(1.3, 1), bb.Max - style.FramePadding, symbol, nullptr, &label_size, style.ButtonTextAlign, &bb);
PopStyleColor();
// Automatically close popups
// if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
// CloseCurrentPopup();
2023-12-13 11:24:25 +01:00
IMGUI_TEST_ENGINE_ITEM_INFO(id, symbol, g.LastItemData.StatusFlags);
return pressed;
}
bool InputIntegerPrefix(const char *label, const char *prefix, void *value, ImGuiDataType type, const char *format, ImGuiInputTextFlags flags) {
auto window = GetCurrentWindow();
2022-02-08 21:10:48 +01:00
const ImGuiID id = window->GetID(label);
const ImGuiStyle &style = GImGui->Style;
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
2024-02-24 23:34:29 +01:00
const ImVec2 frame_size = CalcItemSize(ImVec2(0, 0), CalcTextSize(prefix).x, label_size.y + style.FramePadding.y * 2.0F);
2022-02-08 21:10:48 +01:00
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
SetCursorPosX(GetCursorPosX() + frame_size.x);
char buf[64];
DataTypeFormatString(buf, IM_ARRAYSIZE(buf), type, value, format);
bool value_changed = false;
2024-02-24 23:34:29 +01:00
if (InputTextEx(label, nullptr, buf, IM_ARRAYSIZE(buf), ImVec2(CalcItemWidth() - frame_size.x, label_size.y + style.FramePadding.y * 2.0F), flags))
value_changed = DataTypeApplyFromText(buf, type, value, format);
if (value_changed)
MarkItemEdited(GImGui->LastItemData.ID);
2022-02-08 21:10:48 +01:00
RenderNavHighlight(frame_bb, id);
RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
PushStyleVar(ImGuiStyleVar_Alpha, 0.6F);
2022-02-08 21:10:48 +01:00
RenderText(ImVec2(frame_bb.Min.x + style.FramePadding.x, frame_bb.Min.y + style.FramePadding.y), prefix);
PopStyleVar();
2022-02-08 21:10:48 +01:00
return value_changed;
2022-02-08 21:10:48 +01:00
}
bool InputHexadecimal(const char *label, u32 *value, ImGuiInputTextFlags flags) {
return InputIntegerPrefix(label, "0x", value, ImGuiDataType_U32, "%lX", flags | ImGuiInputTextFlags_CharsHexadecimal);
}
bool InputHexadecimal(const char *label, u64 *value, ImGuiInputTextFlags flags) {
return InputIntegerPrefix(label, "0x", value, ImGuiDataType_U64, "%llX", flags | ImGuiInputTextFlags_CharsHexadecimal);
2022-02-08 21:10:48 +01:00
}
void SmallProgressBar(float fraction, float yOffset) {
ImGuiWindow *window = GetCurrentWindow();
if (window->SkipItems)
return;
2022-02-01 22:09:44 +01:00
ImGuiContext &g = *GImGui;
const ImGuiStyle &style = g.Style;
2022-02-01 22:09:44 +01:00
ImVec2 pos = window->DC.CursorPos + ImVec2(0, yOffset);
2024-02-24 23:34:29 +01:00
ImVec2 size = CalcItemSize(ImVec2(100, 5) * hex::ImHexApi::System::getGlobalScale(), 100, g.FontSize + style.FramePadding.y * 2.0F);
ImRect bb(pos, pos + size);
ItemSize(size, 0);
if (!ItemAdd(bb, 0))
return;
// Render
bool no_progress = fraction < 0;
fraction = ImSaturate(fraction);
RenderFrame(bb.Min, bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
bb.Expand(ImVec2(-style.FrameBorderSize, -style.FrameBorderSize));
if (no_progress) {
auto time = (fmod(ImGui::GetTime() * 2, 1.8) - 0.4);
RenderRectFilledRangeH(window->DrawList, bb, GetColorU32(ImGuiCol_PlotHistogram), ImSaturate(time), ImSaturate(time + 0.2), style.FrameRounding);
} else {
2024-02-24 23:34:29 +01:00
RenderRectFilledRangeH(window->DrawList, bb, GetColorU32(ImGuiCol_PlotHistogram), 0.0F, fraction, style.FrameRounding);
}
}
2023-12-02 23:46:20 +01:00
void TextUnformattedCentered(const char *text) {
auto availableSpace = ImGui::GetContentRegionAvail();
std::string drawString;
auto textEnd = text + strlen(text);
for (auto wrapPos = text; wrapPos != textEnd;) {
wrapPos = ImGui::GetFont()->CalcWordWrapPositionA(1, wrapPos, textEnd, availableSpace.x * 0.8F);
drawString += std::string(text, wrapPos) + "\n";
text = wrapPos;
}
drawString.pop_back();
auto textSize = ImGui::CalcTextSize(drawString.c_str());
ImPlot::AddTextCentered(ImGui::GetWindowDrawList(), ImGui::GetCursorScreenPos() + availableSpace / 2 - ImVec2(0, textSize.y / 2), ImGui::GetColorU32(ImGuiCol_Text), drawString.c_str());
}
bool InputTextIcon(const char *label, const char *icon, std::string &buffer, ImGuiInputTextFlags flags) {
auto window = GetCurrentWindow();
const ImGuiID id = window->GetID(label);
const ImGuiStyle &style = GImGui->Style;
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
2024-02-24 23:34:29 +01:00
const ImVec2 icon_frame_size = CalcTextSize(icon) + style.FramePadding * 2.0F;
const ImVec2 frame_size = CalcItemSize(ImVec2(0, 0), icon_frame_size.x, label_size.y + style.FramePadding.y * 2.0F);
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
SetCursorPosX(GetCursorPosX() + frame_size.x);
2024-02-24 23:34:29 +01:00
bool value_changed = InputTextEx(label, nullptr, buffer.data(), buffer.size() + 1, ImVec2(CalcItemWidth(), label_size.y + style.FramePadding.y * 2.0F), ImGuiInputTextFlags_CallbackResize | flags, UpdateStringSizeCallback, &buffer);
if (value_changed)
MarkItemEdited(GImGui->LastItemData.ID);
RenderNavHighlight(frame_bb, id);
RenderFrame(frame_bb.Min, frame_bb.Max, GetColorU32(ImGuiCol_FrameBg), true, style.FrameRounding);
RenderFrame(frame_bb.Min, frame_bb.Min + icon_frame_size, GetColorU32(ImGuiCol_TableBorderStrong), true, style.FrameRounding);
RenderText(ImVec2(frame_bb.Min.x + style.FramePadding.x, frame_bb.Min.y + style.FramePadding.y), icon);
return value_changed;
}
ui/ux: Rewrite of the entire hex editor view to make it more flexible (#512) * ui/ux: Initial recreation of the hex editor view * ui/ux: Added back support for editing cells * ux: Make scrolling and selecting bytes feel nice again * ui/ux: Improved byte selecting, added footer * sys: Make math evaluator more generic to support integer only calculations * patterns: Moved value formatting into pattern language * ui/ux: Added Goto and Search popups, improved selection * ui: Added better tooltips for bookmarks and patterns * sys: Use worse hex search algorithm on macOS Sadly it still doesn't support `std::boyer_moore_horsepool_searcher` * ui: Added back missing events, menu items and shortcuts * fix: Bookmark highlighting being rendered off by one * fix: Various macOS build errors * fix: size_t is not u64 on macos * fix: std::fmod and std::pow not working with integer types on macos * fix: Missing semicolons * sys: Added proper integer pow function * ui: Added back support for custom encodings * fix: Editor not jumping to selection when selection gets changed * ui: Turn Hexii setting into a data visualizer * sys: Added back remaining shortcuts * sys: Remove old hex editor files * sys: Moved more legacy things away from the hex editor view, updated localization * fix: Hex editor scrolling behaving weirdly and inconsistently * sys: Cleaned up Hex editor code * sys: Added selection color setting, localized all new settings * fix: Search feature not working correctly * ui: Replace custom ImGui::Disabled function with native ImGui ones * ui: Fix bookmark tooltip rendering issues * fix: Another size_t not being 64 bit issue on MacOS
2022-05-27 20:42:07 +02:00
bool InputScalarCallback(const char* label, ImGuiDataType data_type, void* p_data, const char* format, ImGuiInputTextFlags flags, ImGuiInputTextCallback callback, void* user_data) {
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return false;
ImGuiContext& g = *GImGui;
if (format == nullptr)
ui/ux: Rewrite of the entire hex editor view to make it more flexible (#512) * ui/ux: Initial recreation of the hex editor view * ui/ux: Added back support for editing cells * ux: Make scrolling and selecting bytes feel nice again * ui/ux: Improved byte selecting, added footer * sys: Make math evaluator more generic to support integer only calculations * patterns: Moved value formatting into pattern language * ui/ux: Added Goto and Search popups, improved selection * ui: Added better tooltips for bookmarks and patterns * sys: Use worse hex search algorithm on macOS Sadly it still doesn't support `std::boyer_moore_horsepool_searcher` * ui: Added back missing events, menu items and shortcuts * fix: Bookmark highlighting being rendered off by one * fix: Various macOS build errors * fix: size_t is not u64 on macos * fix: std::fmod and std::pow not working with integer types on macos * fix: Missing semicolons * sys: Added proper integer pow function * ui: Added back support for custom encodings * fix: Editor not jumping to selection when selection gets changed * ui: Turn Hexii setting into a data visualizer * sys: Added back remaining shortcuts * sys: Remove old hex editor files * sys: Moved more legacy things away from the hex editor view, updated localization * fix: Hex editor scrolling behaving weirdly and inconsistently * sys: Cleaned up Hex editor code * sys: Added selection color setting, localized all new settings * fix: Search feature not working correctly * ui: Replace custom ImGui::Disabled function with native ImGui ones * ui: Fix bookmark tooltip rendering issues * fix: Another size_t not being 64 bit issue on MacOS
2022-05-27 20:42:07 +02:00
format = DataTypeGetInfo(data_type)->PrintFmt;
char buf[64];
DataTypeFormatString(buf, IM_ARRAYSIZE(buf), data_type, p_data, format);
bool value_changed = false;
if ((flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0)
flags |= ImGuiInputTextFlags_CharsDecimal;
flags |= ImGuiInputTextFlags_AutoSelectAll;
flags |= ImGuiInputTextFlags_NoMarkEdited; // We call MarkItemEdited() ourselves by comparing the actual data rather than the string.
if (ImGui::InputText(label, buf, IM_ARRAYSIZE(buf), flags, callback, user_data))
value_changed = DataTypeApplyFromText(buf, data_type, p_data, format);
ui/ux: Rewrite of the entire hex editor view to make it more flexible (#512) * ui/ux: Initial recreation of the hex editor view * ui/ux: Added back support for editing cells * ux: Make scrolling and selecting bytes feel nice again * ui/ux: Improved byte selecting, added footer * sys: Make math evaluator more generic to support integer only calculations * patterns: Moved value formatting into pattern language * ui/ux: Added Goto and Search popups, improved selection * ui: Added better tooltips for bookmarks and patterns * sys: Use worse hex search algorithm on macOS Sadly it still doesn't support `std::boyer_moore_horsepool_searcher` * ui: Added back missing events, menu items and shortcuts * fix: Bookmark highlighting being rendered off by one * fix: Various macOS build errors * fix: size_t is not u64 on macos * fix: std::fmod and std::pow not working with integer types on macos * fix: Missing semicolons * sys: Added proper integer pow function * ui: Added back support for custom encodings * fix: Editor not jumping to selection when selection gets changed * ui: Turn Hexii setting into a data visualizer * sys: Added back remaining shortcuts * sys: Remove old hex editor files * sys: Moved more legacy things away from the hex editor view, updated localization * fix: Hex editor scrolling behaving weirdly and inconsistently * sys: Cleaned up Hex editor code * sys: Added selection color setting, localized all new settings * fix: Search feature not working correctly * ui: Replace custom ImGui::Disabled function with native ImGui ones * ui: Fix bookmark tooltip rendering issues * fix: Another size_t not being 64 bit issue on MacOS
2022-05-27 20:42:07 +02:00
if (value_changed)
MarkItemEdited(g.LastItemData.ID);
return value_changed;
}
void HideTooltip() {
char window_name[16];
ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", GImGui->TooltipOverrideCount);
if (ImGuiWindow* window = FindWindowByName(window_name); window != nullptr) {
if (window->Active)
window->Hidden = true;
}
}
bool BitCheckbox(const char* label, bool* v) {
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return false;
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
const ImVec2 size = ImVec2(CalcTextSize("0").x + style.FramePadding.x * 2, GetFrameHeight());
const ImVec2 pos = window->DC.CursorPos;
const ImRect total_bb(pos, pos + size);
ItemSize(total_bb, style.FramePadding.y);
if (!ItemAdd(total_bb, id))
{
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
return false;
}
bool hovered, held;
bool pressed = ButtonBehavior(total_bb, id, &hovered, &held);
if (pressed)
{
*v = !(*v);
MarkItemEdited(id);
}
const ImRect check_bb(pos, pos + size);
RenderNavHighlight(total_bb, id);
RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding);
RenderText(check_bb.Min + style.FramePadding, *v ? "1" : "0");
ImVec2 label_pos = ImVec2(check_bb.Max.x + style.ItemInnerSpacing.x, check_bb.Min.y + style.FramePadding.y);
2024-02-24 23:34:29 +01:00
if (label_size.x > 0.0F)
RenderText(label_pos, label);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
return pressed;
}
2023-11-18 17:23:15 +01:00
bool DimmedButton(const char* label, ImVec2 size){
PushStyleColor(ImGuiCol_ButtonHovered, GetCustomColorU32(ImGuiCustomCol_DescButtonHovered));
PushStyleColor(ImGuiCol_Button, GetCustomColorU32(ImGuiCustomCol_DescButton));
PushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_ButtonActive));
PushStyleColor(ImGuiCol_ButtonActive, GetCustomColorU32(ImGuiCustomCol_DescButtonActive));
PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1);
2023-11-18 17:23:15 +01:00
bool res = Button(label, size);
PopStyleColor(4);
PopStyleVar(1);
return res;
}
2023-11-18 17:23:15 +01:00
bool DimmedIconButton(const char *symbol, ImVec4 color, ImVec2 size){
PushStyleColor(ImGuiCol_ButtonHovered, GetCustomColorU32(ImGuiCustomCol_DescButtonHovered));
PushStyleColor(ImGuiCol_Button, GetCustomColorU32(ImGuiCustomCol_DescButton));
PushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_ButtonActive));
PushStyleColor(ImGuiCol_ButtonActive, GetCustomColorU32(ImGuiCustomCol_DescButtonActive));
PushStyleVar(ImGuiStyleVar_FrameBorderSize, 1);
2023-11-18 17:23:15 +01:00
bool res = IconButton(symbol, color, size);
PopStyleColor(4);
PopStyleVar(1);
return res;
}
bool DimmedButtonToggle(const char *icon, bool *v, ImVec2 size) {
bool pushed = false;
bool toggled = false;
if (*v) {
PushStyleColor(ImGuiCol_Border, GetStyleColorVec4(ImGuiCol_ButtonActive));
pushed = true;
}
if (DimmedIconButton(icon, GetStyleColorVec4(ImGuiCol_Text), size)) {
*v = !*v;
toggled = true;
}
if (pushed)
PopStyleColor();
return toggled;
}
2023-07-23 09:14:00 +02:00
bool DimmedIconToggle(const char *icon, bool *v) {
bool pushed = false;
bool toggled = false;
if (*v) {
PushStyleColor(ImGuiCol_Border, GetStyleColorVec4(ImGuiCol_ButtonActive));
2023-07-23 09:14:00 +02:00
pushed = true;
}
if (DimmedIconButton(icon, GetStyleColorVec4(ImGuiCol_Text))) {
2023-07-23 09:14:00 +02:00
*v = !*v;
toggled = true;
}
if (pushed)
PopStyleColor();
2023-07-23 09:14:00 +02:00
return toggled;
}
bool DimmedIconToggle(const char *iconOn, const char *iconOff, bool *v) {
bool pushed = false;
bool toggled = false;
if (*v) {
PushStyleColor(ImGuiCol_Border, GetStyleColorVec4(ImGuiCol_ButtonActive));
pushed = true;
}
if (DimmedIconButton(*v ? iconOn : iconOff, GetStyleColorVec4(ImGuiCol_Text))) {
*v = !*v;
toggled = true;
}
if (pushed)
PopStyleColor();
return toggled;
}
void TextOverlay(const char *text, ImVec2 pos) {
const auto textSize = CalcTextSize(text);
const auto textPos = pos - textSize / 2;
const auto margin = GetStyle().FramePadding * 2;
const auto textRect = ImRect(textPos - margin, textPos + textSize + margin);
auto drawList = GetForegroundDrawList();
drawList->AddRectFilled(textRect.Min, textRect.Max, GetColorU32(ImGuiCol_WindowBg) | 0xFF000000);
drawList->AddRect(textRect.Min, textRect.Max, GetColorU32(ImGuiCol_Border));
drawList->AddText(textPos, GetColorU32(ImGuiCol_Text), text);
}
bool BeginBox() {
PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(5, 5));
auto result = BeginTable("##box", 1, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_SizingStretchSame);
TableNextRow();
TableNextColumn();
return result;
}
void EndBox() {
EndTable();
PopStyleVar();
}
2023-11-16 09:32:24 +01:00
void BeginSubWindow(const char *label, ImVec2 size, ImGuiChildFlags flags) {
2023-11-15 22:22:57 +01:00
const bool hasMenuBar = !std::string_view(label).empty();
2024-02-24 23:34:29 +01:00
ImGui::PushStyleVar(ImGuiStyleVar_ChildRounding, 5.0F);
if (ImGui::BeginChild(hex::format("{}##SubWindow", label).c_str(), size, ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY | flags, hasMenuBar ? ImGuiWindowFlags_MenuBar : ImGuiWindowFlags_None)) {
2023-11-15 22:22:57 +01:00
if (hasMenuBar && ImGui::BeginMenuBar()) {
ImGui::TextUnformatted(label);
ImGui::EndMenuBar();
}
}
2023-11-16 09:32:24 +01:00
ImGui::PopStyleVar();
2023-11-15 22:22:57 +01:00
}
void EndSubWindow() {
ImGui::EndChild();
}
bool VSliderAngle(const char* label, const ImVec2& size, float* v_rad, float v_degrees_min, float v_degrees_max, const char* format, ImGuiSliderFlags flags) {
if (format == nullptr)
format = "%.0f deg";
2024-02-24 23:34:29 +01:00
float v_deg = (*v_rad) * 360.0F / (2 * IM_PI);
bool value_changed = ImGui::VSliderFloat(label, size, &v_deg, v_degrees_min, v_degrees_max, format, flags);
2024-02-24 23:34:29 +01:00
*v_rad = v_deg * (2 * IM_PI) / 360.0F;
return value_changed;
}
bool InputFilePicker(const char *label, std::fs::path &path, const std::vector<hex::fs::ItemFilter> &validExtensions) {
bool picked = false;
ImGui::PushID(label);
const auto buttonSize = ImGui::CalcTextSize("...") + ImGui::GetStyle().FramePadding * 2;
ImGui::PushItemWidth(ImGui::CalcItemWidth() - buttonSize.x - ImGui::GetStyle().FramePadding.x);
std::string string = wolv::util::toUTF8String(path);
if (ImGui::InputText("##pathInput", string, ImGuiInputTextFlags_AutoSelectAll)) {
path = std::u8string(string.begin(), string.end());
picked = true;
}
ImGui::PopItemWidth();
ImGui::SameLine();
if (ImGui::Button("...", buttonSize)) {
hex::fs::openFileBrowser(hex::fs::DialogMode::Open, validExtensions, [&](const std::fs::path &pickedPath) {
path = pickedPath;
picked = true;
});
}
ImGui::SameLine();
ImGui::TextUnformatted(label);
ImGui::PopID();
return picked;
}
2023-12-07 11:18:49 +01:00
bool ToggleSwitch(const char *label, bool *v) {
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return false;
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, nullptr, true);
2023-12-07 11:18:49 +01:00
const ImVec2 size = ImVec2(GetFrameHeight() * 2.0F, GetFrameHeight());
const ImVec2 pos = window->DC.CursorPos;
2024-02-24 23:34:29 +01:00
const ImRect total_bb(pos, pos + ImVec2(size.x + (label_size.x > 0.0F ? style.ItemInnerSpacing.x + label_size.x : 0.0F), label_size.y + style.FramePadding.y * 2.0F));
2023-12-07 11:18:49 +01:00
ItemSize(total_bb, style.FramePadding.y);
if (!ItemAdd(total_bb, id))
{
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
return false;
}
bool hovered, held;
bool pressed = ButtonBehavior(total_bb, id, &hovered, &held);
if (pressed)
{
*v = !(*v);
MarkItemEdited(id);
}
const ImRect knob_bb(pos, pos + size);
window->DrawList->AddRectFilled(knob_bb.Min, knob_bb.Max, GetColorU32(held ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : *v ? ImGuiCol_ButtonActive : ImGuiCol_Button), size.y / 2);
if (*v)
window->DrawList->AddCircleFilled(knob_bb.Max - ImVec2(size.y / 2, size.y / 2), (size.y - style.ItemInnerSpacing.y) / 2, GetColorU32(ImGuiCol_Text), 16);
else
window->DrawList->AddCircleFilled(knob_bb.Min + ImVec2(size.y / 2, size.y / 2), (size.y - style.ItemInnerSpacing.y) / 2, GetColorU32(ImGuiCol_Text), 16);
ImVec2 label_pos = ImVec2(knob_bb.Max.x + style.ItemInnerSpacing.x, knob_bb.Min.y + style.FramePadding.y);
if (g.LogEnabled)
LogRenderedText(&label_pos, *v ? "((*) )" : "( (*))");
2024-02-24 23:34:29 +01:00
if (label_size.x > 0.0F)
2023-12-07 11:18:49 +01:00
RenderText(label_pos, label);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, g.LastItemData.StatusFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
return pressed;
}
bool ToggleSwitch(const char *label, bool v) {
return ToggleSwitch(label, &v);
}
}
namespace ImGui {
bool InputText(const char *label, std::u8string &buffer, ImGuiInputTextFlags flags) {
return ImGui::InputText(label, reinterpret_cast<char *>(buffer.data()), buffer.size() + 1, ImGuiInputTextFlags_CallbackResize | flags, ImGuiExt::UpdateStringSizeCallback, &buffer);
}
bool InputText(const char *label, std::string &buffer, ImGuiInputTextFlags flags) {
return ImGui::InputText(label, buffer.data(), buffer.size() + 1, ImGuiInputTextFlags_CallbackResize | flags, ImGuiExt::UpdateStringSizeCallback, &buffer);
}
bool InputTextMultiline(const char *label, std::string &buffer, const ImVec2 &size, ImGuiInputTextFlags flags) {
return ImGui::InputTextMultiline(label, buffer.data(), buffer.size() + 1, size, ImGuiInputTextFlags_CallbackResize | flags, ImGuiExt::UpdateStringSizeCallback, &buffer);
}
bool InputTextWithHint(const char *label, const char *hint, std::string &buffer, ImGuiInputTextFlags flags) {
return ImGui::InputTextWithHint(label, hint, buffer.data(), buffer.size() + 1, ImGuiInputTextFlags_CallbackResize | flags, ImGuiExt::UpdateStringSizeCallback, &buffer);
}
}