2021-12-31 01:10:06 +01:00
# include <hex/ui/imgui_imhex_extensions.h>
2021-01-27 00:00:20 +01:00
# include <imgui.h>
# include <imgui_internal.h>
2023-12-02 23:46:20 +01:00
# include <implot.h>
# include <implot_internal.h>
2024-03-12 23:17:49 +01:00
# include <cimgui.h>
2023-11-20 23:58:49 +01:00
# include <opengl_support.h>
2023-11-20 23:51:50 +01:00
2021-01-27 00:00:20 +01:00
# undef IMGUI_DEFINE_MATH_OPERATORS
2021-04-17 15:46:26 +02:00
# define STB_IMAGE_IMPLEMENTATION
# include <stb_image.h>
2024-05-01 20:36:10 +02:00
# include <lunasvg.h>
2023-12-13 11:24:25 +01:00
# include <set>
2021-01-27 12:04:42 +01:00
# include <string>
2024-05-19 14:18:12 +02:00
# include <algorithm>
2021-01-27 12:04:42 +01:00
2022-08-17 16:15:36 +02:00
# 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>
2024-05-03 19:27:12 +02:00
# include <hex/helpers/logger.hpp>
2023-05-11 12:00:45 +02:00
2021-01-27 00:00:20 +01:00
2023-11-16 22:24:06 +01:00
namespace ImGuiExt {
using namespace ImGui ;
2023-12-09 22:00:35 +01:00
namespace {
2024-05-03 19:27:12 +02:00
bool isOpenGLExtensionSupported ( const char * name ) {
2024-05-08 22:09:47 +02:00
static std : : set < std : : string > extensions ;
2024-05-03 19:27:12 +02:00
2024-05-08 22:09:47 +02:00
if ( extensions . empty ( ) ) {
GLint extensionCount = 0 ;
glGetIntegerv ( GL_NUM_EXTENSIONS , & extensionCount ) ;
for ( GLint i = 0 ; i < extensionCount ; i + + ) {
std : : string extension = reinterpret_cast < const char * > ( glGetStringi ( GL_EXTENSIONS , i ) ) ;
extensions . emplace ( std : : move ( extension ) ) ;
2024-05-03 19:27:12 +02:00
}
}
2024-05-08 22:09:47 +02:00
return extensions . contains ( name ) ;
}
bool isOpenGLVersionAtLeast ( u8 major , u8 minor ) {
static GLint actualMajor = 0 , actualMinor = 0 ;
if ( actualMajor = = 0 | | actualMinor = = 0 ) {
glGetIntegerv ( GL_MAJOR_VERSION , & actualMajor ) ;
glGetIntegerv ( GL_MINOR_VERSION , & actualMinor ) ;
}
return actualMajor > major | | ( actualMajor = = major & & actualMinor > = minor ) ;
2024-05-03 19:27:12 +02:00
}
2023-12-09 22:00:35 +01:00
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 ;
}
2024-05-20 10:18:03 +02:00
[[maybe_unused]] GLint getMaxSamples ( GLenum target , GLenum format ) {
2024-05-19 14:18:12 +02:00
GLint maxSamples ;
glGetInternalformativ ( target , format , GL_SAMPLES , 1 , & maxSamples ) ;
return maxSamples ;
}
2024-05-01 20:36:10 +02:00
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 ) ;
2024-05-08 22:09:47 +02:00
if ( filter = = Texture : : Filter : : Nearest ) {
2024-05-01 20:36:10 +02:00
return texture ;
2024-05-08 22:09:47 +02:00
}
if ( ! isOpenGLVersionAtLeast ( 3 , 2 ) ) {
return texture ;
}
2024-05-01 20:36:10 +02:00
2024-05-03 19:27:12 +02:00
if ( ! isOpenGLExtensionSupported ( " GL_ARB_texture_multisample " ) ) {
return texture ;
}
# if defined(GL_TEXTURE_2D_MULTISAMPLE)
2024-05-19 14:18:12 +02:00
static const auto sampleCount = std : : min ( static_cast < GLint > ( 8 ) , getMaxSamples ( GL_RENDERBUFFER , GL_DEPTH24_STENCIL8 ) ) ;
2024-05-02 09:40:39 +02:00
2024-05-03 14:02:43 +02:00
// Generate renderbuffer
GLuint renderbuffer ;
glGenRenderbuffers ( 1 , & renderbuffer ) ;
glBindRenderbuffer ( GL_RENDERBUFFER , renderbuffer ) ;
2024-05-19 14:18:12 +02:00
glRenderbufferStorageMultisample ( GL_RENDERBUFFER , sampleCount , GL_DEPTH24_STENCIL8 , width , height ) ;
2024-05-01 20:36:10 +02:00
2024-05-03 14:02:43 +02:00
// Generate framebuffer
GLuint framebuffer ;
glGenFramebuffers ( 1 , & framebuffer ) ;
glBindFramebuffer ( GL_FRAMEBUFFER , framebuffer ) ;
2024-05-01 20:36:10 +02:00
2024-05-08 23:08:45 +02:00
// Unbind framebuffer on exit
ON_SCOPE_EXIT {
glBindFramebuffer ( GL_FRAMEBUFFER , 0 ) ;
} ;
2024-05-03 14:02:43 +02:00
// Attach texture to color attachment 0
2024-05-03 19:27:12 +02:00
glFramebufferTexture2D ( GL_FRAMEBUFFER , GL_COLOR_ATTACHMENT0 , GL_TEXTURE_2D_MULTISAMPLE , texture , 0 ) ;
2024-05-01 20:36:10 +02:00
2024-05-03 14:02:43 +02:00
// Attach renderbuffer to depth-stencil attachment
glFramebufferRenderbuffer ( GL_FRAMEBUFFER , GL_DEPTH_STENCIL_ATTACHMENT , GL_RENDERBUFFER , renderbuffer ) ;
2024-05-01 20:36:10 +02:00
2024-05-03 14:02:43 +02:00
// Check framebuffer status
if ( glCheckFramebufferStatus ( GL_FRAMEBUFFER ) ! = GL_FRAMEBUFFER_COMPLETE ) {
2024-05-03 21:41:02 +02:00
hex : : log : : error ( " Driver claims to support texture multisampling but it's not working " ) ;
2024-05-03 19:27:12 +02:00
return texture ;
2024-05-03 14:02:43 +02:00
}
2024-05-01 20:36:10 +02:00
2024-05-03 14:02:43 +02:00
# endif
2024-05-01 20:36:10 +02:00
return texture ;
}
2023-12-09 22:00:35 +01:00
}
2023-11-16 22:24:06 +01:00
2024-05-01 20:36:10 +02:00
Texture Texture : : fromImage ( const ImU8 * buffer , int size , Filter filter ) {
2023-12-11 11:42:33 +01:00
if ( size = = 0 )
2024-05-01 20:36:10 +02:00
return { } ;
2023-12-11 11:42:33 +01:00
2024-01-08 09:39:01 +01:00
unsigned char * imageData = nullptr ;
2024-05-01 20:36:10 +02:00
Texture result ;
imageData = stbi_load_from_memory ( buffer , size , & result . m_width , & result . m_height , nullptr , 4 ) ;
if ( imageData = = nullptr )
return { } ;
2024-01-08 09:39:01 +01:00
2024-05-01 20:36:10 +02:00
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
2022-09-18 20:38:45 +02:00
2024-05-01 20:36:10 +02:00
Texture Texture : : fromImage ( const std : : fs : : path & path , Filter filter ) {
return Texture : : fromImage ( wolv : : util : : toUTF8String ( path ) . c_str ( ) , filter ) ;
}
2022-09-18 20:38:45 +02:00
2024-05-01 20:36:10 +02:00
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 { } ;
2022-09-18 20:38:45 +02:00
2024-05-01 20:36:10 +02:00
GLuint texture = createMultisampleTextureFromRGBA8Array ( imageData , result . m_width , result . m_height , filter ) ;
2022-09-18 20:38:45 +02:00
2024-02-24 23:23:53 +01:00
STBI_FREE ( imageData ) ;
2022-09-18 20:38:45 +02:00
2024-05-01 20:36:10 +02:00
result . m_textureId = reinterpret_cast < ImTextureID > ( static_cast < intptr_t > ( texture ) ) ;
return result ;
2022-09-18 20:38:45 +02:00
}
2024-05-01 20:36:10 +02:00
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
2024-05-01 20:36:10 +02:00
return texture ;
}
2023-12-05 10:49:51 +01:00
2024-05-01 20:36:10 +02:00
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 ) ;
}
2022-09-18 20:38:45 +02:00
2024-05-01 20:36:10 +02:00
Texture Texture : : fromBitmap ( const ImU8 * buffer , int size , int width , int height , Filter filter ) {
if ( width * height * 4 > size )
return { } ;
2022-09-18 20:38:45 +02:00
2024-05-01 20:36:10 +02:00
GLuint texture = createMultisampleTextureFromRGBA8Array ( buffer , width , height , filter ) ;
2022-09-18 20:38:45 +02:00
2024-05-01 20:36:10 +02:00
Texture result ;
result . m_width = width ;
result . m_height = height ;
result . m_textureId = reinterpret_cast < ImTextureID > ( static_cast < intptr_t > ( texture ) ) ;
2022-09-18 20:38:45 +02:00
2024-05-01 20:36:10 +02:00
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 ) ;
2022-09-18 20:38:45 +02:00
2024-05-01 20:36:10 +02:00
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 ) ;
2022-09-18 20:38:45 +02:00
}
2024-05-01 20:36:10 +02:00
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 ) ) ;
2023-01-20 21:16:28 +01:00
2024-05-01 20:36:10 +02:00
return result ;
2023-01-20 21:16:28 +01:00
}
2022-09-18 20:38:45 +02:00
Texture : : Texture ( Texture & & other ) noexcept {
2024-02-24 18:07:10 +01:00
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 ;
2022-09-18 20:38:45 +02:00
other . m_textureId = nullptr ;
}
2022-10-02 17:30:26 +02:00
Texture & Texture : : operator = ( Texture & & other ) noexcept {
2024-02-24 18:07:10 +01:00
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 ;
2022-09-18 20:38:45 +02:00
other . m_textureId = nullptr ;
2022-10-02 17:30:26 +02:00
return * this ;
2022-09-18 20:38:45 +02:00
}
Texture : : ~ Texture ( ) {
2023-12-19 13:10:25 +01:00
if ( m_textureId = = nullptr )
2022-09-18 20:38:45 +02:00
return ;
2024-05-18 12:57:29 +02:00
glDeleteTextures ( 1 , reinterpret_cast < GLuint * > ( & m_textureId ) ) ;
2022-09-18 20:38:45 +02:00
}
2021-12-07 22:47:41 +01:00
int UpdateStringSizeCallback ( ImGuiInputTextCallbackData * data ) {
2022-03-01 16:12:00 +01:00
if ( data - > EventFlag = = ImGuiInputTextFlags_CallbackResize ) {
auto & string = * static_cast < std : : string * > ( data - > UserData ) ;
2022-05-30 16:36:46 +02:00
string . resize ( data - > BufTextLen ) ;
2022-03-01 16:12:00 +01:00
data - > Buf = string . data ( ) ;
}
2021-12-07 22:47:41 +01:00
return 0 ;
}
2022-01-24 20:53:17 +01:00
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 ) ;
2022-10-02 17:30:26 +02:00
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 ) ;
2024-04-29 20:06:50 +02:00
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 ;
}
2022-01-24 20:53:17 +01:00
bool Hyperlink ( const char * label , const ImVec2 & size_arg , ImGuiButtonFlags flags ) {
ImGuiWindow * window = GetCurrentWindow ( ) ;
2021-01-27 00:00:20 +01:00
2022-02-01 22:09:44 +01:00
ImGuiContext & g = * GImGui ;
const ImGuiID id = window - > GetID ( label ) ;
2022-10-02 17:30:26 +02:00
const ImVec2 label_size = CalcTextSize ( label , nullptr , true ) ;
2021-01-27 00:00:20 +01:00
2022-02-01 22:09:44 +01:00
ImVec2 pos = window - > DC . CursorPos ;
2021-01-27 00:00:20 +01:00
ImVec2 size = CalcItemSize ( size_arg , label_size . x , label_size . y ) ;
const ImRect bb ( pos , pos + size ) ;
2023-12-27 02:14:38 +01:00
ItemAdd ( bb , id ) ;
2021-01-27 00:00:20 +01:00
2021-08-21 00:51:50 +02:00
if ( g . LastItemData . InFlags & ImGuiItemFlags_ButtonRepeat )
2021-01-27 00:00:20 +01:00
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 ) ;
2021-01-27 00:00:20 +01:00
PushStyleColor ( ImGuiCol_Text , ImU32 ( col ) ) ;
2022-10-02 17:30:26 +02:00
TextEx ( label , nullptr , ImGuiTextFlags_NoWidthForLargeClippedText ) ; // Skip formatting
2024-04-29 20:06:50 +02:00
if ( hovered )
GetWindowDrawList ( ) - > AddLine ( ImVec2 ( pos . x , pos . y + size . y ) , pos + size , ImU32 ( col ) ) ;
2021-01-27 00:00:20 +01:00
PopStyleColor ( ) ;
2023-12-13 11:24:25 +01:00
IMGUI_TEST_ENGINE_ITEM_INFO ( id , label , g . LastItemData . StatusFlags ) ;
2021-01-27 00:00:20 +01:00
return pressed ;
}
2022-01-24 20:53:17 +01:00
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 ;
2022-01-24 20:53:17 +01:00
const ImGuiStyle & style = g . Style ;
2022-02-01 22:09:44 +01:00
const ImGuiID id = window - > GetID ( label ) ;
2022-10-02 17:30:26 +02: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 ;
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 ;
}
2022-01-24 20:53:17 +01:00
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 ;
2022-01-24 20:53:17 +01:00
const ImGuiStyle & style = g . Style ;
2022-02-01 22:09:44 +01:00
const ImGuiID id = window - > GetID ( label ) ;
2022-10-02 17:30:26 +02:00
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 ;
2022-01-24 20:53:17 +01:00
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
2022-01-24 20:53:17 +01:00
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 ) ) ;
2023-12-18 13:08:17 +01:00
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 ) ) ;
2023-12-18 13:08:17 +01:00
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
2022-01-24 20:53:17 +01:00
// 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 ;
}
2023-11-16 13:23:28 +01:00
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 ) ;
2023-11-16 13:23:28 +01:00
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 ) ) ;
2023-12-18 13:08:17 +01:00
RenderTextClipped ( bb . Min + style . FramePadding * 2 , bb . Max - style . FramePadding , label , nullptr , nullptr ) ;
2023-11-16 13:23:28 +01:00
PopStyleColor ( ) ;
PushStyleColor ( ImGuiCol_Text , GetColorU32 ( ImGuiCol_Text ) ) ;
2023-12-18 13:08:17 +01:00
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 ) ;
2023-11-16 13:23:28 +01:00
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 ) ;
2023-11-16 13:23:28 +01:00
return pressed ;
}
2024-05-18 20:32:57 +02:00
void HelpHover ( const char * text , const char * icon , ImU32 iconColor ) {
2023-11-16 22:24:06 +01:00
PushStyleColor ( ImGuiCol_Button , ImVec4 ( 0 , 0 , 0 , 0 ) ) ;
PushStyleColor ( ImGuiCol_ButtonHovered , ImVec4 ( 0 , 0 , 0 , 0 ) ) ;
PushStyleColor ( ImGuiCol_ButtonActive , ImVec4 ( 0 , 0 , 0 , 0 ) ) ;
2024-06-08 13:40:39 +02:00
PushStyleVar ( ImGuiStyleVar_FramePadding , ImVec2 ( 0 , 0 ) ) ;
2024-05-17 20:47:22 +02:00
PushStyleVar ( ImGuiStyleVar_FrameBorderSize , 0.0F ) ;
2023-11-16 22:24:06 +01:00
PushStyleColor ( ImGuiCol_Text , iconColor ) ;
2024-05-18 20:32:57 +02:00
Button ( icon ) ;
2023-11-16 22:24:06 +01:00
PopStyleColor ( ) ;
if ( IsItemHovered ( ImGuiHoveredFlags_AllowWhenDisabled ) ) {
2024-06-08 13:40:39 +02:00
SetNextWindowSizeConstraints ( ImVec2 ( GetTextLineHeight ( ) * 25 , 0 ) , ImVec2 ( GetTextLineHeight ( ) * 35 , FLT_MAX ) ) ;
2023-11-16 22:24:06 +01:00
BeginTooltip ( ) ;
TextFormattedWrapped ( " {} " , text ) ;
EndTooltip ( ) ;
2023-05-11 12:00:45 +02:00
}
2024-05-17 20:47:22 +02:00
PopStyleVar ( 2 ) ;
2023-11-16 22:24:06 +01:00
PopStyleColor ( 3 ) ;
2023-05-11 12:00:45 +02:00
}
2022-01-24 20:53:17 +01:00
void UnderlinedText ( const char * label , ImColor color , const ImVec2 & size_arg ) {
ImGuiWindow * window = GetCurrentWindow ( ) ;
2021-01-27 12:04:42 +01:00
2022-10-02 17:30:26 +02: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 ) ) ;
2022-10-02 17:30:26 +02:00
TextEx ( label , nullptr , ImGuiTextFlags_NoWidthForLargeClippedText ) ; // Skip formatting
2021-01-27 14:26:24 +01:00
GetWindowDrawList ( ) - > AddLine ( ImVec2 ( pos . x , pos . y + size . y ) , pos + size , ImU32 ( color ) ) ;
2021-01-27 12:04:42 +01:00
PopStyleColor ( ) ;
}
2022-01-24 20:53:17 +01:00
void TextSpinner ( const char * label ) {
2023-11-16 22:24:06 +01:00
Text ( " [%c] %s " , " |/- \\ " [ ImU32 ( GetTime ( ) * 20 ) % 4 ] , label ) ;
2021-02-22 13:06:53 +01:00
}
2021-03-02 13:49:45 +01:00
void Header ( const char * label , bool firstEntry ) {
if ( ! firstEntry )
2023-11-16 22:24:06 +01:00
NewLine ( ) ;
SeparatorText ( label ) ;
2021-03-02 13:49:45 +01:00
}
2021-08-28 16:02:53 +02:00
void HeaderColored ( const char * label , ImColor color , bool firstEntry ) {
if ( ! firstEntry )
2023-11-16 22:24:06 +01:00
NewLine ( ) ;
TextFormattedColored ( color , " {} " , label ) ;
Separator ( ) ;
2021-08-28 16:02:53 +02:00
}
2023-12-05 10:49:51 +01:00
bool InfoTooltip ( const char * text , bool isSeparator ) {
2021-08-21 00:51:50 +02:00
static double lastMoveTime ;
static ImGuiID lastHoveredID ;
2023-11-16 22:24:06 +01:00
double currTime = GetTime ( ) ;
ImGuiID hoveredID = GetHoveredID ( ) ;
2021-08-21 00:51:50 +02:00
2023-06-05 09:07:58 +02:00
bool result = false ;
2021-08-21 00:51:50 +02:00
if ( IsItemHovered ( ) & & ( currTime - lastMoveTime ) > = 0.5 & & hoveredID = = lastHoveredID ) {
2023-06-05 09:07:58 +02:00
if ( ! std : : string_view ( text ) . empty ( ) ) {
2024-06-25 21:19:59 +02:00
const auto textWidth = CalcTextSize ( text ) . x ;
auto width = 150 * hex : : ImHexApi : : System : : getGlobalScale ( ) ;
if ( textWidth < width )
width = textWidth ;
ImGui : : SetNextWindowSizeConstraints ( ImVec2 ( width , 0 ) , ImVec2 ( width * 2 , FLT_MAX ) ) ;
2024-05-19 15:10:22 +02:00
if ( BeginTooltip ( ) ) {
if ( isSeparator )
SeparatorText ( text ) ;
else
TextFormattedWrapped ( " {} " , text ) ;
EndTooltip ( ) ;
}
2023-06-05 09:07:58 +02:00
}
result = true ;
2021-08-18 23:12:27 +02:00
}
2021-08-21 00:51:50 +02:00
if ( hoveredID ! = lastHoveredID ) {
lastMoveTime = currTime ;
}
lastHoveredID = hoveredID ;
2023-06-05 09:07:58 +02:00
return result ;
2021-08-18 23:12:27 +02:00
}
2021-02-25 00:17:41 +01:00
ImU32 GetCustomColorU32 ( ImGuiCustomCol idx , float alpha_mul ) {
2022-01-24 20:53:17 +01:00
auto & customData = * static_cast < ImHexCustomData * > ( GImGui - > IO . UserData ) ;
2022-02-01 22:09:44 +01:00
ImVec4 c = customData . Colors [ idx ] ;
2021-02-25 00:17:41 +01:00
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 ) {
2022-01-24 20:53:17 +01:00
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 ;
}
2023-05-22 12:00:35 +02:00
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 ;
2023-05-22 12:00:35 +02:00
}
}
ImVec2 GetCustomStyleVec2 ( ImGuiCustomStyle idx ) {
switch ( idx ) {
default :
return { } ;
}
}
2021-02-25 00:17:41 +01:00
void StyleCustomColorsDark ( ) {
2022-01-24 20:53:17 +01:00
auto & colors = static_cast < ImHexCustomData * > ( GImGui - > IO . UserData ) - > Colors ;
2021-02-25 00:17:41 +01:00
2022-02-01 22:09:44 +01:00
colors [ ImGuiCustomCol_DescButton ] = ImColor ( 20 , 20 , 20 ) ;
2022-01-24 20:53:17 +01:00
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 ) ;
2022-01-24 20:53:17 +01:00
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 ) ;
2022-01-24 20:53:17 +01:00
colors [ ImGuiCustomCol_ToolbarPurple ] = ImColor ( 103 , 42 , 120 ) ;
2022-02-01 22:09:44 +01:00
colors [ ImGuiCustomCol_ToolbarBrown ] = ImColor ( 219 , 179 , 119 ) ;
2021-08-28 16:02:53 +02:00
2022-01-24 20:53:17 +01:00
colors [ ImGuiCustomCol_Highlight ] = ImColor ( 77 , 198 , 155 ) ;
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 ) ;
2021-02-25 00:17:41 +01:00
}
void StyleCustomColorsLight ( ) {
2022-01-24 20:53:17 +01:00
auto & colors = static_cast < ImHexCustomData * > ( GImGui - > IO . UserData ) - > Colors ;
2021-02-25 00:17:41 +01:00
2022-02-01 22:09:44 +01:00
colors [ ImGuiCustomCol_DescButton ] = ImColor ( 230 , 230 , 230 ) ;
2022-01-24 20:53:17 +01:00
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 ) ;
2022-01-24 20:53:17 +01:00
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 ) ;
2022-01-24 20:53:17 +01:00
colors [ ImGuiCustomCol_ToolbarPurple ] = ImColor ( 103 , 42 , 120 ) ;
2022-02-01 22:09:44 +01:00
colors [ ImGuiCustomCol_ToolbarBrown ] = ImColor ( 219 , 179 , 119 ) ;
2021-08-28 16:02:53 +02:00
2022-01-24 20:53:17 +01:00
colors [ ImGuiCustomCol_Highlight ] = ImColor ( 41 , 151 , 112 ) ;
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 ) ;
2021-02-25 00:17:41 +01:00
}
void StyleCustomColorsClassic ( ) {
2022-01-24 20:53:17 +01:00
auto & colors = static_cast < ImHexCustomData * > ( GImGui - > IO . UserData ) - > Colors ;
2021-02-25 00:17:41 +01:00
2022-02-01 22:09:44 +01:00
colors [ ImGuiCustomCol_DescButton ] = ImColor ( 40 , 40 , 80 ) ;
2022-01-24 20:53:17 +01:00
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 ) ;
2022-01-24 20:53:17 +01:00
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 ) ;
2022-01-24 20:53:17 +01:00
colors [ ImGuiCustomCol_ToolbarPurple ] = ImColor ( 103 , 42 , 120 ) ;
2022-02-01 22:09:44 +01:00
colors [ ImGuiCustomCol_ToolbarBrown ] = ImColor ( 219 , 179 , 119 ) ;
2021-08-28 16:02:53 +02:00
2022-01-24 20:53:17 +01:00
colors [ ImGuiCustomCol_Highlight ] = ImColor ( 77 , 198 , 155 ) ;
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 ) ;
2021-02-25 00:17:41 +01:00
}
2021-09-28 12:34:55 +02:00
void OpenPopupInWindow ( const char * window_name , const char * popup_name ) {
2023-11-16 22:24:06 +01:00
if ( Begin ( window_name ) ) {
OpenPopup ( popup_name ) ;
2021-09-28 12:34:55 +02:00
}
2023-11-16 22:24:06 +01:00
End ( ) ;
2021-09-28 12:34:55 +02:00
}
2021-08-21 00:51:50 +02:00
2022-01-24 20:53:17 +01: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 ;
2022-01-24 20:53:17 +01:00
const ImGuiStyle & style = g . Style ;
2022-02-01 22:09:44 +01:00
const ImGuiID id = window - > GetID ( label ) ;
2022-10-02 17:30:26 +02:00
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
2022-01-24 20:53:17 +01:00
const ImU32 col = GetColorU32 ( ( held & & hovered ) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered
: ImGuiCol_Button ) ;
2021-08-21 00:51:50 +02:00
RenderNavHighlight ( bb , id ) ;
2024-05-17 20:38:22 +02:00
RenderFrame ( bb . Min , bb . Max , col , false , style . FrameRounding ) ;
2023-06-09 00:30:12 +02:00
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
2022-01-24 20:53:17 +01:00
// 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 ;
}
2022-01-24 20:53:17 +01:00
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 ;
2022-01-24 20:53:17 +01:00
const ImGuiStyle & style = g . Style ;
2022-02-01 22:09:44 +01:00
const ImGuiID id = window - > GetID ( symbol ) ;
2022-10-02 17:30:26 +02:00
const ImVec2 label_size = CalcTextSize ( symbol , nullptr , true ) ;
2021-08-21 00:51:50 +02:00
ImVec2 pos = window - > DC . CursorPos ;
2024-06-07 22:12:50 +02: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
2024-06-18 22:10:02 +02:00
ImVec2 padding = ( size - label_size ) / 2 ;
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
2022-01-24 20:53:17 +01:00
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 ) ;
2024-06-18 22:10:02 +02:00
RenderTextClipped ( bb . Min + padding , bb . Max - padding , symbol , nullptr , & size , style . ButtonTextAlign , & bb ) ;
2021-08-21 00:51:50 +02:00
PopStyleColor ( ) ;
// Automatically close popups
2022-01-24 20:53:17 +01:00
// 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 ;
}
2022-01-24 20:53:17 +01:00
bool IconButton ( const char * symbol , ImVec4 color , ImVec2 size_arg ) {
ImGuiWindow * window = GetCurrentWindow ( ) ;
2021-10-07 11:34:46 +02:00
if ( window - > SkipItems )
return false ;
color . w = 1.0F ;
2022-02-01 22:09:44 +01:00
ImGuiContext & g = * GImGui ;
2022-01-24 20:53:17 +01:00
const ImGuiStyle & style = g . Style ;
2022-02-01 22:09:44 +01:00
const ImGuiID id = window - > GetID ( symbol ) ;
2022-10-02 17:30:26 +02:00
const ImVec2 label_size = CalcTextSize ( symbol , nullptr , true ) ;
2021-10-07 11:34:46 +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-10-07 11:34:46 +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
2022-01-24 20:53:17 +01:00
const ImU32 col = GetColorU32 ( ( held & & hovered ) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered
: ImGuiCol_Button ) ;
2021-10-07 11:34:46 +02:00
RenderNavHighlight ( bb , id ) ;
2023-05-11 12:00:45 +02:00
RenderFrame ( bb . Min , bb . Max , col , true , style . FrameRounding ) ;
2023-12-14 13:49:46 +01:00
RenderTextClipped ( bb . Min + style . FramePadding * ImVec2 ( 1.3 , 1 ) , bb . Max - style . FramePadding , symbol , nullptr , & label_size , style . ButtonTextAlign , & bb ) ;
2021-10-07 11:34:46 +02:00
PopStyleColor ( ) ;
// Automatically close popups
2022-01-24 20:53:17 +01:00
// if (pressed && !(flags & ImGuiButtonFlags_DontClosePopups) && (window->Flags & ImGuiWindowFlags_Popup))
2021-10-07 11:34:46 +02:00
// CloseCurrentPopup();
2023-12-13 11:24:25 +01:00
IMGUI_TEST_ENGINE_ITEM_INFO ( id , symbol , g . LastItemData . StatusFlags ) ;
2021-10-07 11:34:46 +02:00
return pressed ;
}
2023-01-18 14:30:44 +01:00
bool InputIntegerPrefix ( const char * label , const char * prefix , void * value , ImGuiDataType type , const char * format , ImGuiInputTextFlags flags ) {
2023-11-16 22:24:06 +01:00
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 ) ;
2024-05-17 20:38:22 +02:00
const ImRect frame_bb ( window - > DC . CursorPos , window - > DC . CursorPos + ImVec2 ( CalcItemWidth ( ) , frame_size . y ) ) ;
2022-02-08 21:10:48 +01:00
2023-11-16 22:24:06 +01:00
SetCursorPosX ( GetCursorPosX ( ) + frame_size . x ) ;
2022-02-08 21:51:09 +01:00
char buf [ 64 ] ;
2023-01-18 14:30:44 +01:00
DataTypeFormatString ( buf , IM_ARRAYSIZE ( buf ) , type , value , format ) ;
2022-02-08 21:51:09 +01:00
2024-05-19 10:21:54 +02:00
RenderNavHighlight ( frame_bb , id ) ;
RenderFrame ( frame_bb . Min , frame_bb . Max , GetColorU32 ( ImGuiCol_FrameBg ) , true , style . FrameRounding ) ;
PushStyleVar ( ImGuiStyleVar_Alpha , 0.6F ) ;
RenderText ( ImVec2 ( frame_bb . Min . x + style . FramePadding . x , frame_bb . Min . y + style . FramePadding . y ) , prefix ) ;
PopStyleVar ( ) ;
2022-02-08 21:51:09 +01:00
bool value_changed = false ;
2024-05-17 20:38:22 +02:00
PushStyleVar ( ImGuiStyleVar_FrameBorderSize , 0 ) ;
2024-05-19 10:21:54 +02:00
PushStyleColor ( ImGuiCol_FrameBg , 0x00000000 ) ;
PushStyleColor ( ImGuiCol_FrameBgHovered , 0x00000000 ) ;
PushStyleColor ( ImGuiCol_FrameBgActive , 0x00000000 ) ;
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 ) )
2023-01-18 14:30:44 +01:00
value_changed = DataTypeApplyFromText ( buf , type , value , format ) ;
2024-05-19 10:21:54 +02:00
PopStyleColor ( 3 ) ;
2024-05-17 20:38:22 +02:00
PopStyleVar ( ) ;
2022-02-08 21:51:09 +01:00
if ( value_changed )
MarkItemEdited ( GImGui - > LastItemData . ID ) ;
return value_changed ;
2022-02-08 21:10:48 +01:00
}
2022-05-30 16:36:46 +02:00
bool InputHexadecimal ( const char * label , u32 * value , ImGuiInputTextFlags flags ) {
2023-01-18 14:30:44 +01:00
return InputIntegerPrefix ( label , " 0x " , value , ImGuiDataType_U32 , " %lX " , flags | ImGuiInputTextFlags_CharsHexadecimal ) ;
2022-05-30 16:36:46 +02:00
}
2022-02-08 22:25:25 +01:00
bool InputHexadecimal ( const char * label , u64 * value , ImGuiInputTextFlags flags ) {
2023-01-18 14:30:44 +01:00
return InputIntegerPrefix ( label , " 0x " , value , ImGuiDataType_U64 , " %llX " , flags | ImGuiInputTextFlags_CharsHexadecimal ) ;
2022-02-08 21:10:48 +01:00
}
2024-05-19 10:21:54 +02:00
bool SliderBytes ( const char * label , u64 * value , u64 min , u64 max , ImGuiSliderFlags flags ) {
std : : string format ;
if ( * value < 1024 ) {
format = hex : : format ( " {} Bytes " , * value ) ;
} else if ( * value < 1024 * 1024 ) {
format = hex : : format ( " {:.2f} KB " , * value / 1024.0 ) ;
} else if ( * value < 1024 * 1024 * 1024 ) {
format = hex : : format ( " {:.2f} MB " , * value / ( 1024.0 * 1024.0 ) ) ;
} else {
format = hex : : format ( " {:.2f} GB " , * value / ( 1024.0 * 1024.0 * 1024.0 ) ) ;
}
return ImGui : : SliderScalar ( label , ImGuiDataType_U64 , value , & min , & max , format . c_str ( ) , flags | ImGuiSliderFlags_Logarithmic ) ;
}
2021-12-16 23:48:52 +01:00
void SmallProgressBar ( float fraction , float yOffset ) {
2022-01-24 20:53:17 +01:00
ImGuiWindow * window = GetCurrentWindow ( ) ;
2021-12-16 23:48:52 +01:00
if ( window - > SkipItems )
return ;
2022-02-01 22:09:44 +01:00
ImGuiContext & g = * GImGui ;
2022-01-24 20:53:17 +01:00
const ImGuiStyle & style = g . Style ;
2021-12-16 23:48:52 +01:00
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 ) ;
2021-12-16 23:48:52 +01:00
ImRect bb ( pos , pos + size ) ;
ItemSize ( size , 0 ) ;
if ( ! ItemAdd ( bb , 0 ) )
return ;
// Render
2023-12-28 22:14:45 +01:00
bool no_progress = fraction < 0 ;
2021-12-16 23:48:52 +01:00
fraction = ImSaturate ( fraction ) ;
RenderFrame ( bb . Min , bb . Max , GetColorU32 ( ImGuiCol_FrameBg ) , true , style . FrameRounding ) ;
bb . Expand ( ImVec2 ( - style . FrameBorderSize , - style . FrameBorderSize ) ) ;
2023-12-28 22:14:45 +01:00
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-28 22:14:45 +01:00
}
2021-12-16 23:48:52 +01:00
}
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 ( ) ) ;
}
2023-11-16 22:24:06 +01:00
2022-09-19 11:29:51 +02:00
bool InputTextIcon ( const char * label , const char * icon , std : : string & buffer , ImGuiInputTextFlags flags ) {
2023-11-16 22:24:06 +01:00
auto window = GetCurrentWindow ( ) ;
2022-09-19 11:29:51 +02: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 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 ) ;
2022-09-19 11:29:51 +02:00
const ImRect frame_bb ( window - > DC . CursorPos , window - > DC . CursorPos + frame_size ) ;
2023-11-16 22:24:06 +01:00
SetCursorPosX ( GetCursorPosX ( ) + frame_size . x ) ;
2022-09-19 11:29:51 +02:00
2024-06-09 14:56:56 +02: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 ) ;
2022-09-19 11:29:51 +02:00
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 ) ;
2023-06-09 00:30:12 +02:00
RenderText ( ImVec2 ( frame_bb . Min . x + style . FramePadding . x , frame_bb . Min . y + style . FramePadding . y ) , icon ) ;
2022-09-19 11:29:51 +02:00
return value_changed ;
}
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 ;
2022-10-02 17:30:26 +02:00
if ( format = = nullptr )
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.
2023-11-16 22:24:06 +01:00
if ( ImGui : : InputText ( label , buf , IM_ARRAYSIZE ( buf ) , flags , callback , user_data ) )
2022-08-03 23:32:34 +02:00
value_changed = DataTypeApplyFromText ( buf , data_type , p_data , format ) ;
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 ;
}
}
2022-05-29 14:57:59 +02:00
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 ) ;
2022-10-02 17:30:26 +02:00
const ImVec2 label_size = CalcTextSize ( label , nullptr , true ) ;
2022-05-29 14:57:59 +02:00
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 )
2022-05-29 14:57:59 +02:00
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 ) {
2023-11-16 22:24:06 +01:00
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-05-05 22:00:17 +02:00
2023-11-18 17:23:15 +01:00
bool res = Button ( label , size ) ;
2023-05-05 22:00:17 +02:00
2023-11-16 22:24:06 +01:00
PopStyleColor ( 4 ) ;
PopStyleVar ( 1 ) ;
2023-05-11 12:00:45 +02:00
return res ;
}
2023-11-18 17:23:15 +01:00
bool DimmedIconButton ( const char * symbol , ImVec4 color , ImVec2 size ) {
2023-11-16 22:24:06 +01:00
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-05-11 12:00:45 +02:00
2023-11-18 17:23:15 +01:00
bool res = IconButton ( symbol , color , size ) ;
2023-05-11 12:00:45 +02:00
2023-11-16 22:24:06 +01:00
PopStyleColor ( 4 ) ;
PopStyleVar ( 1 ) ;
2023-05-11 12:00:45 +02:00
2023-05-05 22:00:17 +02:00
return res ;
}
2023-11-19 16:08:21 +01:00
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 ) {
2023-11-16 22:24:06 +01:00
PushStyleColor ( ImGuiCol_Border , GetStyleColorVec4 ( ImGuiCol_ButtonActive ) ) ;
2023-07-23 09:14:00 +02:00
pushed = true ;
}
2023-11-16 22:24:06 +01:00
if ( DimmedIconButton ( icon , GetStyleColorVec4 ( ImGuiCol_Text ) ) ) {
2023-07-23 09:14:00 +02:00
* v = ! * v ;
toggled = true ;
}
if ( pushed )
2023-11-16 22:24:06 +01:00
PopStyleColor ( ) ;
2023-07-23 09:14:00 +02:00
return toggled ;
}
2023-12-05 10:49:51 +01:00
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 ;
}
2023-08-30 10:04:06 +02:00
void TextOverlay ( const char * text , ImVec2 pos ) {
2023-11-16 22:24:06 +01:00
const auto textSize = CalcTextSize ( text ) ;
2023-08-30 10:04:06 +02:00
const auto textPos = pos - textSize / 2 ;
2023-11-16 22:24:06 +01:00
const auto margin = GetStyle ( ) . FramePadding * 2 ;
2023-08-30 10:04:06 +02:00
const auto textRect = ImRect ( textPos - margin , textPos + textSize + margin ) ;
2023-11-16 22:24:06 +01:00
auto drawList = GetForegroundDrawList ( ) ;
2023-08-30 10:04:06 +02:00
2023-11-16 22:24:06 +01:00
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 ) ;
2023-08-30 10:04:06 +02:00
}
2023-11-07 00:46:44 +01:00
bool BeginBox ( ) {
2023-11-16 22:24:06 +01:00
PushStyleVar ( ImGuiStyleVar_CellPadding , ImVec2 ( 5 , 5 ) ) ;
auto result = BeginTable ( " ##box " , 1 , ImGuiTableFlags_BordersOuter | ImGuiTableFlags_SizingStretchSame ) ;
TableNextRow ( ) ;
TableNextColumn ( ) ;
2023-11-07 00:46:44 +01:00
return result ;
}
void EndBox ( ) {
2023-11-16 22:24:06 +01:00
EndTable ( ) ;
PopStyleVar ( ) ;
2023-11-07 00:46:44 +01:00
}
2024-06-25 13:54:29 +02:00
bool BeginSubWindow ( const char * label , bool * collapsed , ImVec2 size , ImGuiChildFlags flags ) {
2023-11-15 22:22:57 +01:00
const bool hasMenuBar = ! std : : string_view ( label ) . empty ( ) ;
2024-06-25 13:54:29 +02:00
bool result = false ;
2024-02-24 23:34:29 +01:00
ImGui : : PushStyleVar ( ImGuiStyleVar_ChildRounding , 5.0F ) ;
2023-11-17 16:05:45 +01:00
if ( ImGui : : BeginChild ( hex : : format ( " {}##SubWindow " , label ) . c_str ( ) , size , ImGuiChildFlags_Border | ImGuiChildFlags_AutoResizeY | flags , hasMenuBar ? ImGuiWindowFlags_MenuBar : ImGuiWindowFlags_None ) ) {
2024-06-25 13:54:29 +02:00
result = true ;
2023-11-15 22:22:57 +01:00
if ( hasMenuBar & & ImGui : : BeginMenuBar ( ) ) {
2024-06-25 13:54:29 +02:00
if ( collapsed = = nullptr )
ImGui : : TextUnformatted ( label ) ;
else {
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , ImVec2 ( 0 , ImGui : : GetStyle ( ) . FramePadding . y ) ) ;
ImGui : : PushStyleColor ( ImGuiCol_Button , 0x00 ) ;
if ( ImGui : : Button ( label ) )
* collapsed = ! * collapsed ;
ImGui : : PopStyleColor ( ) ;
ImGui : : PopStyleVar ( ) ;
}
2023-11-15 22:22:57 +01:00
ImGui : : EndMenuBar ( ) ;
}
2024-06-25 13:54:29 +02:00
if ( collapsed ! = nullptr & & * collapsed ) {
ImGui : : SetCursorPosY ( ImGui : : GetCursorPosY ( ) - ( ImGui : : GetStyle ( ) . FramePadding . y * 2 ) ) ;
ImGui : : TextDisabled ( " ... " ) ;
result = false ;
}
2023-11-15 22:22:57 +01:00
}
2023-11-16 09:32:24 +01:00
ImGui : : PopStyleVar ( ) ;
2024-06-25 13:54:29 +02:00
return result ;
2023-11-15 22:22:57 +01:00
}
void EndSubWindow ( ) {
ImGui : : EndChild ( ) ;
}
2023-12-09 22:00:35 +01:00
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 )
2023-12-05 10:49:51 +01:00
format = " %.0f deg " ;
2024-02-24 23:34:29 +01:00
float v_deg = ( * v_rad ) * 360.0F / ( 2 * IM_PI ) ;
2023-12-05 10:49:51 +01:00
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 ;
2023-12-05 10:49:51 +01:00
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 ) ;
2024-01-28 22:14:59 +01:00
const auto buttonSize = ImGui : : CalcTextSize ( " ... " ) + ImGui : : GetStyle ( ) . FramePadding * 2 ;
2023-12-05 10:49:51 +01:00
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 ( ) ;
2024-01-28 22:14:59 +01:00
if ( ImGui : : Button ( " ... " , buttonSize ) ) {
2023-12-05 10:49:51 +01:00
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 ) ;
2023-12-09 22:00:35 +01:00
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 )
2024-05-17 22:20:56 +02:00
window - > DrawList - > AddCircleFilled ( knob_bb . Max - ImVec2 ( size . y / 2 , size . y / 2 ) , ( size . y - style . ItemInnerSpacing . y ) / 2 , GetColorU32 ( ImGuiCol_ScrollbarGrabActive ) , 16 ) ;
2023-12-07 11:18:49 +01:00
else
2024-05-17 22:20:56 +02:00
window - > DrawList - > AddCircleFilled ( knob_bb . Min + ImVec2 ( size . y / 2 , size . y / 2 ) , ( size . y - style . ItemInnerSpacing . y ) / 2 , GetColorU32 ( ImGuiCol_ScrollbarGrabActive ) , 16 ) ;
2023-12-07 11:18:49 +01:00
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 ) ;
}
impr: Convert all hex editor popups to floating, movable windows (#1658)
### Problem description
In previous versions of ImHex, all tool windows were implemented as
static popups fixed in the upper left position of the hex view. This PR
refactors all tool popups to use floating windows that can be dragged
around by the user, or closed with a dedicated close button on the title
bar. These popup also support a stylable transparency when the user is
not hovering their mouse over the window.
### Implementation description
I rewrote the logic in `ViewHexEditor::drawPopup()` to use a custom
`ImGuiExt::BeginHoveringPopup` function for rendering the popup windows.
This new function is an almost exact replica of the built-in
`ImGui::BeginPopupModal`, except it does also displays the default
window title bar with a close button.
A second custom function, `ImGuiExt::PopupTitleBarButton` was also added
for rendering small icon-based buttons into the title bar of the parent
popup window. This new function was used to implement an optional
"Pinning" feature that individual popup implementations can specify. If
a window is pinned, it won't close automatically when its main action is
executed. For example, the "Select" button on the Select dialog will
close the popup by default, unless the window is pinned.
### Screenshots
Popup dialogs before:
![image](https://github.com/WerWolv/ImHex/assets/45818400/7c253181-8284-4076-a066-089403554f0f)
Popup dialogs after:
https://github.com/WerWolv/ImHex/assets/45818400/99d1a628-8ac1-40ac-9146-9062091bb0db
### Additional things
- When the user stops hovering their mouse over a popup window, it
becomes semi-transparent, making it easier to see the content behind it
- This PR also introduces the `styles.imhex.popup-alpha` style, making
the transparency effect configurable, including the ability to disable
the effect completely by setting `popup-alpha` to `1.0`.
- Fixed a bug that caused some popup windows to ignore the Enter and the
KeypadEnter keys. With this PR, all tool windows will execute their main
action when the user presses either one of the two Enter keys, and will
also close automatically unless the window is pinned.
### Possible changes and improvements
- Should the transparency effect be disabled if a window is pinned?
- Should the transparency factor be modifiable on the Settings/Interface
page?
- A keyboard shortcut could be added for quickly pinning / unpinning the
current window.
- Can the pin icon stay on the left, or should it be moved next to the
close button, with a similar circular background?
---------
Co-authored-by: WerWolv <werwolv98@gmail.com>
2024-05-10 21:21:19 +02:00
bool PopupTitleBarButton ( const char * label , bool p_enabled )
{
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
const ImGuiID id = window - > GetID ( label ) ;
const ImRect title_rect = window - > TitleBarRect ( ) ;
const ImVec2 size ( g . FontSize , g . FontSize ) ; // Button size matches font size for aesthetic consistency.
const ImVec2 pos = window - > DC . CursorPos ;
const ImVec2 max_pos = pos + size ;
const ImRect bb ( pos . x , title_rect . Min . y , max_pos . x , title_rect . Max . y ) ;
ImGui : : PushClipRect ( title_rect . Min , title_rect . Max , false ) ;
// Check for item addition (similar to how clipping is handled in the original button functions).
bool is_clipped = ! ItemAdd ( bb , id ) ;
bool hovered , held ;
bool pressed = ButtonBehavior ( bb , id , & hovered , & held , ImGuiButtonFlags_None ) ;
if ( is_clipped )
{
ImGui : : PopClipRect ( ) ;
return pressed ;
}
// const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
// window->DrawList->AddCircleFilled(bb.GetCenter(), ImMax(2.0f, g.FontSize * 0.5f + 1.0f), bg_col);
// Draw the label in the center
ImU32 text_col = GetColorU32 ( p_enabled | | hovered ? ImGuiCol_Text : ImGuiCol_TextDisabled ) ;
window - > DrawList - > AddText ( bb . GetCenter ( ) - ImVec2 ( g . FontSize * 0.45F , g . FontSize * 0.5F ) , text_col , label ) ;
// Return the button press state
ImGui : : PopClipRect ( ) ;
return pressed ;
}
void PopupTitleBarText ( const char * text ) {
ImGuiContext & g = * GImGui ;
ImGuiWindow * window = g . CurrentWindow ;
const ImRect title_rect = window - > TitleBarRect ( ) ;
const ImVec2 size ( g . FontSize , g . FontSize ) ; // Button size matches font size for aesthetic consistency.
const ImVec2 pos = window - > DC . CursorPos ;
const ImVec2 max_pos = pos + size ;
const ImRect bb ( pos . x , title_rect . Min . y , max_pos . x , title_rect . Max . y ) ;
ImGui : : PushClipRect ( title_rect . Min , title_rect . Max , false ) ;
// Draw the label in the center
ImU32 text_col = GetColorU32 ( ImGuiCol_Text ) ;
window - > DrawList - > AddText ( bb . GetCenter ( ) - ImVec2 ( g . FontSize * 0.45F , g . FontSize * 0.5F ) , text_col , text ) ;
// Return the button press state
ImGui : : PopClipRect ( ) ;
}
2023-11-16 22:24:06 +01:00
}
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 ) ;
}
2024-05-19 14:18:12 +02:00
}