2021-08-29 14:18:45 +02:00
# include <hex/api/content_registry.hpp>
2022-10-21 12:01:28 +02:00
# include <hex/api/imhex_api.hpp>
2023-11-21 14:38:01 +01:00
# include <hex/api/localization_manager.hpp>
2023-12-26 00:22:47 +01:00
# include <hex/api/task_manager.hpp>
2021-06-07 18:13:54 +02:00
2022-05-27 20:42:07 +02:00
# include <hex/ui/view.hpp>
2021-08-29 22:15:18 +02:00
# include <hex/helpers/utils.hpp>
# include <hex/helpers/fmt.hpp>
2022-07-02 17:53:13 +02:00
# include <hex/helpers/logger.hpp>
2021-08-29 22:15:18 +02:00
2022-07-26 14:59:08 +02:00
# include <fonts/codicons_font.h>
2021-08-21 00:52:11 +02:00
# include <imgui.h>
# include <imgui_internal.h>
2023-12-20 13:42:42 +01:00
# include <implot.h>
2021-12-31 01:10:06 +01:00
# include <hex/ui/imgui_imhex_extensions.h>
2021-08-21 00:52:11 +02:00
2023-12-26 00:22:47 +01:00
# include <toasts/toast_notification.hpp>
2021-06-07 18:13:54 +02:00
2023-04-08 00:58:53 +02:00
namespace hex : : plugin : : builtin {
2022-07-02 17:53:13 +02:00
2023-05-25 09:26:40 +02:00
void addTitleBarButtons ( ) {
2023-11-10 20:47:08 +01:00
# if defined(DEBUG)
ContentRegistry : : Interface : : addTitleBarButton ( ICON_VS_DEBUG , " hex.builtin.title_bar_button.debug_build " , [ ] {
if ( ImGui : : GetIO ( ) . KeyCtrl ) {
// Explicitly trigger a segfault by writing to an invalid memory location
// Used for debugging crashes
* reinterpret_cast < u8 * > ( 0x10 ) = 0x10 ;
std : : unreachable ( ) ;
} else if ( ImGui : : GetIO ( ) . KeyShift ) {
// Explicitly trigger an abort by throwing an uncaught exception
// Used for debugging exception errors
throw std : : runtime_error ( " Debug Error " ) ;
std : : unreachable ( ) ;
} else {
hex : : openWebpage ( " https://imhex.werwolv.net/debug " ) ;
}
} ) ;
# endif
2023-05-25 09:26:40 +02:00
2023-06-26 08:54:30 +02:00
ContentRegistry : : Interface : : addTitleBarButton ( ICON_VS_SMILEY , " hex.builtin.title_bar_button.feedback " , [ ] {
2023-05-25 09:26:40 +02:00
hex : : openWebpage ( " https://github.com/WerWolv/ImHex/discussions/categories/feedback " ) ;
} ) ;
}
2022-05-27 20:42:07 +02:00
static void drawGlobalPopups ( ) {
2023-12-26 00:22:47 +01:00
// Task exception toast
2022-09-03 23:56:57 +02:00
for ( const auto & task : TaskManager : : getRunningTasks ( ) ) {
if ( task - > hadException ( ) ) {
2023-12-26 00:22:47 +01:00
ui : : ToastError : : open ( hex : : format ( " hex.builtin.popup.error.task_exception " _lang , Lang ( task - > getUnlocalizedName ( ) ) , task - > getExceptionMessage ( ) ) ) ;
2022-09-03 23:56:57 +02:00
task - > clearException ( ) ;
break ;
}
}
2022-05-27 20:42:07 +02:00
}
2024-01-10 23:46:50 +01:00
static bool s_drawDragDropOverlay = false ;
static void drawDragNDropOverlay ( ) {
if ( ! s_drawDragDropOverlay )
return ;
auto drawList = ImGui : : GetForegroundDrawList ( ) ;
drawList - > PushClipRectFullScreen ( ) ;
{
const auto windowPos = ImHexApi : : System : : getMainWindowPosition ( ) ;
const auto windowSize = ImHexApi : : System : : getMainWindowSize ( ) ;
const auto center = windowPos + ( windowSize / 2.0F ) - scaled ( { 0 , 50 } ) ;
// Draw background
{
const ImVec2 margin = scaled ( { 15 , 15 } ) ;
drawList - > AddRectFilled ( windowPos , windowPos + windowSize , ImGui : : GetColorU32 ( ImGuiCol_WindowBg , 200.0 / 255.0 ) ) ;
drawList - > AddRect ( windowPos + margin , ( windowPos + windowSize ) - margin , ImGuiExt : : GetCustomColorU32 ( ImGuiCustomCol_Highlight ) , 10 _scaled , ImDrawFlags_None , 7.5 _scaled ) ;
}
// Draw drag n drop icon
{
const ImVec2 iconSize = scaled ( { 64 , 64 } ) ;
const auto offset = scaled ( { 15 , 15 } ) ;
const auto margin = scaled ( { 20 , 20 } ) ;
2024-01-11 10:20:39 +01:00
const auto text = " hex.builtin.drag_drop.text " _lang ;
2024-01-10 23:46:50 +01:00
const auto textSize = ImGui : : CalcTextSize ( text ) ;
drawList - > AddShadowRect ( center - ImVec2 ( textSize . x , iconSize . y + 40 _scaled ) / 2.0F - offset - margin , center + ImVec2 ( textSize . x , iconSize . y + 75 _scaled ) / 2.0F + offset + ImVec2 ( 0 , textSize . y ) + margin , ImGui : : GetColorU32 ( ImGuiCol_WindowShadow ) , 20 _scaled , ImVec2 ( ) , ImDrawFlags_None , 10 _scaled ) ;
drawList - > AddRectFilled ( center - ImVec2 ( textSize . x , iconSize . y + 40 _scaled ) / 2.0F - offset - margin , center + ImVec2 ( textSize . x , iconSize . y + 75 _scaled ) / 2.0F + offset + ImVec2 ( 0 , textSize . y ) + margin , ImGui : : GetColorU32 ( ImGuiCol_MenuBarBg , 10 ) , 1 _scaled , ImDrawFlags_None ) ;
drawList - > AddRect ( center - iconSize / 2.0F - offset , center + iconSize / 2.0F - offset , ImGui : : GetColorU32 ( ImGuiCol_Text ) , 5 _scaled , ImDrawFlags_None , 7.5 _scaled ) ;
drawList - > AddRect ( center - iconSize / 2.0F + offset , center + iconSize / 2.0F + offset , ImGui : : GetColorU32 ( ImGuiCol_Text ) , 5 _scaled , ImDrawFlags_None , 7.5 _scaled ) ;
drawList - > AddText ( center + ImVec2 ( - textSize . x / 2 , 85 _scaled ) , ImGui : : GetColorU32 ( ImGuiCol_Text ) , text ) ;
}
}
drawList - > PopClipRect ( ) ;
}
2022-05-27 20:42:07 +02:00
void addGlobalUIItems ( ) {
2023-12-08 10:29:44 +01:00
EventFrameEnd : : subscribe ( drawGlobalPopups ) ;
2024-01-10 23:46:50 +01:00
EventFrameEnd : : subscribe ( drawDragNDropOverlay ) ;
EventFileDragged : : subscribe ( [ ] ( bool entered ) {
s_drawDragDropOverlay = entered ;
} ) ;
2022-05-27 20:42:07 +02:00
}
2021-06-07 18:13:54 +02:00
void addFooterItems ( ) {
2021-12-13 22:58:23 +01:00
if ( hex : : isProcessElevated ( ) ) {
ContentRegistry : : Interface : : addFooterItem ( [ ] {
2023-11-25 19:11:14 +01:00
ImGui : : PushStyleColor ( ImGuiCol_Text , ImGuiExt : : GetCustomColorU32 ( ImGuiCustomCol_Highlight ) ) ;
2021-12-13 22:58:23 +01:00
ImGui : : TextUnformatted ( ICON_VS_SHIELD ) ;
2023-11-25 19:11:14 +01:00
ImGui : : PopStyleColor ( ) ;
2021-12-13 22:58:23 +01:00
} ) ;
}
2022-09-05 22:37:28 +02:00
# if defined(DEBUG)
ContentRegistry : : Interface : : addFooterItem ( [ ] {
static float framerate = 0 ;
2023-11-16 22:24:06 +01:00
if ( ImGuiExt : : HasSecondPassed ( ) ) {
2022-09-05 22:37:28 +02:00
framerate = 1.0F / ImGui : : GetIO ( ) . DeltaTime ;
}
2021-06-07 18:13:54 +02:00
2023-11-25 16:07:33 +01:00
ImGuiExt : : TextFormatted ( " FPS {0:3}.{1:02} " , u32 ( framerate ) , u32 ( framerate * 100 ) % 100 ) ;
2023-12-20 13:42:42 +01:00
if ( ImGui : : IsItemHovered ( ) ) {
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowPadding , ImVec2 ( ) ) ;
if ( ImGui : : BeginTooltip ( ) ) {
2023-12-25 23:23:19 +01:00
static u32 frameCount = 0 ;
static double largestFrameTime = 0 ;
2023-12-20 13:42:42 +01:00
if ( ImPlot : : BeginPlot ( " ##frame_time_graph " , scaled ( { 200 , 100 } ) , ImPlotFlags_CanvasOnly | ImPlotFlags_NoFrame | ImPlotFlags_NoInputs ) ) {
ImPlot : : SetupAxes ( " " , " " , ImPlotAxisFlags_NoLabel | ImPlotAxisFlags_NoTickLabels , ImPlotAxisFlags_NoLabel | ImPlotAxisFlags_LockMin | ImPlotAxisFlags_AutoFit ) ;
2023-12-25 23:23:19 +01:00
ImPlot : : SetupAxisLimits ( ImAxis_Y1 , 0 , largestFrameTime * 1.25F , ImPlotCond_Always ) ;
2023-12-20 13:42:42 +01:00
ImPlot : : SetupAxisFormat ( ImAxis_Y1 , [ ] ( double value , char * buff , int size , void * ) - > int {
return snprintf ( buff , size , " %dms " , int ( value * 1000.0 ) ) ;
} , nullptr ) ;
2023-12-25 23:23:19 +01:00
ImPlot : : SetupAxisTicks ( ImAxis_Y1 , 0 , largestFrameTime * 1.25F , 3 ) ;
2023-12-20 13:42:42 +01:00
static std : : vector < double > values ( 100 ) ;
values . push_back ( ImHexApi : : System : : getLastFrameTime ( ) ) ;
if ( values . size ( ) > 100 )
values . erase ( values . begin ( ) ) ;
2023-12-25 23:23:19 +01:00
if ( frameCount % 100 = = 0 )
largestFrameTime = * std : : ranges : : max_element ( values ) ;
frameCount + = 1 ;
2023-12-20 13:42:42 +01:00
ImPlot : : PlotLine ( " FPS " , values . data ( ) , values . size ( ) ) ;
ImPlot : : EndPlot ( ) ;
}
ImGui : : EndTooltip ( ) ;
}
ImGui : : PopStyleVar ( ) ;
}
2022-09-05 22:37:28 +02:00
} ) ;
# endif
2021-12-16 23:48:52 +01:00
ContentRegistry : : Interface : : addFooterItem ( [ ] {
2023-05-02 20:35:30 +02:00
static bool shouldResetProgress = false ;
2022-08-17 16:15:36 +02:00
auto taskCount = TaskManager : : getRunningTaskCount ( ) ;
if ( taskCount > 0 ) {
2023-01-24 14:59:19 +01:00
const auto & tasks = TaskManager : : getRunningTasks ( ) ;
2023-11-23 13:19:50 +01:00
const auto & frontTask = tasks . front ( ) ;
2021-12-16 23:48:52 +01:00
2023-12-06 11:04:35 +01:00
if ( frontTask = = nullptr )
return ;
2023-01-14 14:21:16 +01:00
2023-12-28 22:14:45 +01:00
const auto progress = frontTask - > getMaxValue ( ) = = 0 ? - 1 : float ( frontTask - > getValue ( ) ) / float ( frontTask - > getMaxValue ( ) ) ;
2023-12-06 11:04:35 +01:00
ImHexApi : : System : : setTaskBarProgress ( ImHexApi : : System : : TaskProgressState : : Progress , ImHexApi : : System : : TaskProgressType : : Normal , u32 ( progress * 100 ) ) ;
2023-01-14 14:21:16 +01:00
2023-11-23 13:19:50 +01:00
const auto widgetStart = ImGui : : GetCursorPos ( ) ;
{
ImGuiExt : : TextSpinner ( hex : : format ( " ({}) " , taskCount ) . c_str ( ) ) ;
ImGui : : SameLine ( ) ;
2023-12-18 10:14:07 +01:00
ImGuiExt : : SmallProgressBar ( progress , ( ImGui : : GetCurrentWindowRead ( ) - > MenuBarHeight ( ) - 10 _scaled ) / 2.0 ) ;
2023-11-23 13:19:50 +01:00
ImGui : : SameLine ( ) ;
}
const auto widgetEnd = ImGui : : GetCursorPos ( ) ;
2022-08-17 16:15:36 +02:00
ImGui : : SetCursorPos ( widgetStart ) ;
2023-12-28 22:14:45 +01:00
ImGui : : InvisibleButton ( " RestTasks " , ImVec2 ( widgetEnd . x - widgetStart . x , ImGui : : GetCurrentWindowRead ( ) - > MenuBarHeight ( ) ) ) ;
2022-08-17 16:15:36 +02:00
ImGui : : SetCursorPos ( widgetEnd ) ;
2023-11-23 13:19:50 +01:00
ImGuiExt : : InfoTooltip ( hex : : format ( " [{:.1f}%] {} " , progress * 100.0F , Lang ( frontTask - > getUnlocalizedName ( ) ) ) . c_str ( ) ) ;
2022-08-17 16:15:36 +02:00
2023-12-28 22:14:45 +01:00
if ( ImGui : : BeginPopupContextItem ( " RestTasks " , ImGuiPopupFlags_MouseButtonLeft ) ) {
2022-08-17 16:15:36 +02:00
for ( const auto & task : tasks ) {
2022-10-04 23:37:48 +02:00
if ( task - > isBackgroundTask ( ) )
continue ;
2022-08-17 16:15:36 +02:00
ImGui : : PushID ( & task ) ;
2023-11-21 14:38:01 +01:00
ImGuiExt : : TextFormatted ( " {} " , Lang ( task - > getUnlocalizedName ( ) ) ) ;
2022-08-17 16:15:36 +02:00
ImGui : : SameLine ( ) ;
ImGui : : SeparatorEx ( ImGuiSeparatorFlags_Vertical ) ;
ImGui : : SameLine ( ) ;
2023-12-28 22:14:45 +01:00
ImGuiExt : : SmallProgressBar ( task - > getMaxValue ( ) = = 0 ? - 1 : ( float ( task - > getValue ( ) ) / float ( task - > getMaxValue ( ) ) ) , ( ImGui : : GetTextLineHeightWithSpacing ( ) - 5 _scaled ) / 2 ) ;
2022-08-17 16:15:36 +02:00
ImGui : : SameLine ( ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowPadding , ImVec2 ( 0 , 0 ) ) ;
2023-11-16 22:24:06 +01:00
if ( ImGuiExt : : ToolBarButton ( ICON_VS_DEBUG_STOP , ImGui : : GetStyleColorVec4 ( ImGuiCol_Text ) ) )
2022-08-17 16:15:36 +02:00
task - > interrupt ( ) ;
ImGui : : PopStyleVar ( ) ;
ImGui : : PopID ( ) ;
}
ImGui : : EndPopup ( ) ;
}
2021-12-16 23:48:52 +01:00
ImGui : : SameLine ( ) ;
2022-08-17 16:15:36 +02:00
ImGui : : PushStyleVar ( ImGuiStyleVar_FramePadding , scaled ( ImVec2 ( 1 , 2 ) ) ) ;
2023-11-16 22:24:06 +01:00
if ( ImGuiExt : : ToolBarButton ( ICON_VS_DEBUG_STOP , ImGui : : GetStyleColorVec4 ( ImGuiCol_Text ) ) )
2022-08-17 16:15:36 +02:00
frontTask - > interrupt ( ) ;
ImGui : : PopStyleVar ( ) ;
2023-05-02 20:35:30 +02:00
shouldResetProgress = true ;
2023-01-14 14:21:16 +01:00
} else {
2023-05-02 20:35:30 +02:00
if ( shouldResetProgress ) {
ImHexApi : : System : : setTaskBarProgress ( ImHexApi : : System : : TaskProgressState : : Reset , ImHexApi : : System : : TaskProgressType : : Normal , 0 ) ;
shouldResetProgress = false ;
}
2021-12-16 23:48:52 +01:00
}
2021-06-07 18:13:54 +02:00
} ) ;
}
2023-12-18 11:46:23 +01:00
static void drawProviderContextMenu ( prv : : Provider * provider ) {
for ( const auto & menuEntry : provider - > getMenuEntries ( ) ) {
if ( ImGui : : MenuItem ( menuEntry . name . c_str ( ) ) ) {
menuEntry . callback ( ) ;
}
}
}
2021-08-21 00:52:11 +02:00
void addToolbarItems ( ) {
2023-11-17 14:46:21 +01:00
ShortcutManager : : addGlobalShortcut ( AllowWhileTyping + ALT + CTRLCMD + Keys : : Left , " hex.builtin.shortcut.prev_provider " , [ ] {
2023-09-24 18:04:14 +02:00
auto currIndex = ImHexApi : : Provider : : getCurrentProviderIndex ( ) ;
if ( currIndex > 0 )
ImHexApi : : Provider : : setCurrentProvider ( currIndex - 1 ) ;
} ) ;
2023-11-17 14:46:21 +01:00
ShortcutManager : : addGlobalShortcut ( AllowWhileTyping + ALT + CTRLCMD + Keys : : Right , " hex.builtin.shortcut.next_provider " , [ ] {
2023-09-24 18:04:14 +02:00
auto currIndex = ImHexApi : : Provider : : getCurrentProviderIndex ( ) ;
const auto & providers = ImHexApi : : Provider : : getProviders ( ) ;
if ( currIndex < i64 ( providers . size ( ) - 1 ) )
ImHexApi : : Provider : : setCurrentProvider ( currIndex + 1 ) ;
} ) ;
2023-10-24 19:29:22 +02:00
static bool providerJustChanged = true ;
2023-12-08 10:29:44 +01:00
EventProviderChanged : : subscribe ( [ ] ( auto , auto ) { providerJustChanged = true ; } ) ;
2023-10-24 19:29:22 +02:00
2023-12-18 11:46:23 +01:00
static prv : : Provider * rightClickedProvider = nullptr ;
EventSearchBoxClicked : : subscribe ( [ ] ( ImGuiMouseButton button ) {
if ( button = = ImGuiMouseButton_Right ) {
rightClickedProvider = ImHexApi : : Provider : : get ( ) ;
RequestOpenPopup : : post ( " ProviderMenu " ) ;
}
} ) ;
EventFrameBegin : : subscribe ( [ ] {
2023-12-18 22:51:08 +01:00
if ( rightClickedProvider ! = nullptr & & ! rightClickedProvider - > getMenuEntries ( ) . empty ( ) ) {
if ( ImGui : : BeginPopup ( " ProviderMenu " ) ) {
2023-12-18 22:45:15 +01:00
drawProviderContextMenu ( rightClickedProvider ) ;
2023-12-18 22:51:08 +01:00
ImGui : : EndPopup ( ) ;
}
2023-12-18 22:45:15 +01:00
}
2023-12-18 11:46:23 +01:00
} ) ;
2023-12-18 22:51:08 +01:00
EventProviderChanged : : subscribe ( [ ] ( auto , auto ) {
rightClickedProvider = nullptr ;
} ) ;
2021-08-21 00:52:11 +02:00
ContentRegistry : : Interface : : addToolbarItem ( [ ] {
2022-03-13 17:46:59 +01:00
auto provider = ImHexApi : : Provider : : get ( ) ;
bool providerValid = provider ! = nullptr ;
2022-08-17 16:15:36 +02:00
bool tasksRunning = TaskManager : : getRunningTaskCount ( ) > 0 ;
2021-08-21 13:53:50 +02:00
// Undo
2022-05-27 20:42:07 +02:00
ImGui : : BeginDisabled ( ! providerValid | | ! provider - > canUndo ( ) ) ;
{
2023-11-16 22:24:06 +01:00
if ( ImGuiExt : : ToolBarButton ( ICON_VS_DISCARD , ImGuiExt : : GetCustomColorVec4 ( ImGuiCustomCol_ToolbarBlue ) ) )
2021-08-21 13:53:50 +02:00
provider - > undo ( ) ;
2022-05-27 20:42:07 +02:00
}
ImGui : : EndDisabled ( ) ;
2021-08-21 13:53:50 +02:00
// Redo
2022-05-27 20:42:07 +02:00
ImGui : : BeginDisabled ( ! providerValid | | ! provider - > canRedo ( ) ) ;
{
2023-11-16 22:24:06 +01:00
if ( ImGuiExt : : ToolBarButton ( ICON_VS_REDO , ImGuiExt : : GetCustomColorVec4 ( ImGuiCustomCol_ToolbarBlue ) ) )
2021-08-21 13:53:50 +02:00
provider - > redo ( ) ;
2022-05-27 20:42:07 +02:00
}
ImGui : : EndDisabled ( ) ;
2021-08-21 00:52:11 +02:00
ImGui : : SeparatorEx ( ImGuiSeparatorFlags_Vertical ) ;
2022-07-29 11:35:29 +02:00
ImGui : : BeginDisabled ( tasksRunning ) ;
{
// Create new file
2023-11-16 22:24:06 +01:00
if ( ImGuiExt : : ToolBarButton ( ICON_VS_FILE , ImGuiExt : : GetCustomColorVec4 ( ImGuiCustomCol_ToolbarGray ) ) ) {
2022-10-21 12:01:28 +02:00
auto newProvider = hex : : ImHexApi : : Provider : : createProvider ( " hex.builtin.provider.mem_file " , true ) ;
if ( newProvider ! = nullptr & & ! newProvider - > open ( ) )
hex : : ImHexApi : : Provider : : remove ( newProvider ) ;
else
2023-12-08 10:29:44 +01:00
EventProviderOpened : : post ( newProvider ) ;
2022-10-21 12:01:28 +02:00
}
2021-08-21 13:53:50 +02:00
2022-07-29 11:35:29 +02:00
// Open file
2023-11-16 22:24:06 +01:00
if ( ImGuiExt : : ToolBarButton ( ICON_VS_FOLDER_OPENED , ImGuiExt : : GetCustomColorVec4 ( ImGuiCustomCol_ToolbarBrown ) ) )
2023-12-08 10:29:44 +01:00
RequestOpenWindow : : post ( " Open File " ) ;
2022-07-29 11:35:29 +02:00
}
ImGui : : EndDisabled ( ) ;
2021-08-21 00:52:11 +02:00
ImGui : : SeparatorEx ( ImGuiSeparatorFlags_Vertical ) ;
2021-08-21 13:53:50 +02:00
// Save file
2022-05-27 20:42:07 +02:00
ImGui : : BeginDisabled ( ! providerValid | | ! provider - > isWritable ( ) | | ! provider - > isSavable ( ) ) ;
{
2023-11-16 22:24:06 +01:00
if ( ImGuiExt : : ToolBarButton ( ICON_VS_SAVE , ImGuiExt : : GetCustomColorVec4 ( ImGuiCustomCol_ToolbarBlue ) ) )
2021-08-21 13:53:50 +02:00
provider - > save ( ) ;
2022-05-27 20:42:07 +02:00
}
ImGui : : EndDisabled ( ) ;
2021-08-21 13:53:50 +02:00
// Save file as
2022-05-27 20:42:07 +02:00
ImGui : : BeginDisabled ( ! providerValid | | ! provider - > isSavable ( ) ) ;
{
2023-11-16 22:24:06 +01:00
if ( ImGuiExt : : ToolBarButton ( ICON_VS_SAVE_AS , ImGuiExt : : GetCustomColorVec4 ( ImGuiCustomCol_ToolbarBlue ) ) )
2022-03-27 00:01:28 +01:00
fs : : openFileBrowser ( fs : : DialogMode : : Save , { } , [ & provider ] ( auto path ) {
2021-08-21 13:53:50 +02:00
provider - > saveAs ( path ) ;
} ) ;
2022-05-27 20:42:07 +02:00
}
ImGui : : EndDisabled ( ) ;
2021-08-21 13:53:50 +02:00
2021-08-21 00:52:11 +02:00
ImGui : : SeparatorEx ( ImGuiSeparatorFlags_Vertical ) ;
2021-08-21 13:53:50 +02:00
// Create bookmark
2022-05-27 20:42:07 +02:00
ImGui : : BeginDisabled ( ! providerValid | | ! provider - > isReadable ( ) | | ! ImHexApi : : HexEditor : : isSelectionValid ( ) ) ;
{
2023-11-16 22:24:06 +01:00
if ( ImGuiExt : : ToolBarButton ( ICON_VS_BOOKMARK , ImGuiExt : : GetCustomColorVec4 ( ImGuiCustomCol_ToolbarGreen ) ) ) {
2022-05-27 20:42:07 +02:00
auto region = ImHexApi : : HexEditor : : getSelection ( ) ;
2021-08-21 13:53:50 +02:00
2022-05-27 20:42:07 +02:00
if ( region . has_value ( ) )
2022-07-23 21:17:17 +02:00
ImHexApi : : Bookmarks : : add ( region - > getStartAddress ( ) , region - > getSize ( ) , { } , { } ) ;
2021-08-21 13:53:50 +02:00
}
2022-05-27 20:42:07 +02:00
}
ImGui : : EndDisabled ( ) ;
2021-09-21 02:29:54 +02:00
ImGui : : SeparatorEx ( ImGuiSeparatorFlags_Vertical ) ;
ImGui : : Spacing ( ) ;
2022-07-30 21:25:18 +02:00
ImGui : : Spacing ( ) ;
ImGui : : Spacing ( ) ;
2021-09-21 02:29:54 +02:00
// Provider switcher
2022-07-29 11:35:29 +02:00
ImGui : : BeginDisabled ( ! providerValid | | tasksRunning ) ;
2022-05-27 20:42:07 +02:00
{
2021-09-21 02:29:54 +02:00
auto & providers = ImHexApi : : Provider : : getProviders ( ) ;
2022-07-30 21:25:18 +02:00
ImGui : : PushStyleColor ( ImGuiCol_TabActive , ImGui : : GetColorU32 ( ImGuiCol_MenuBarBg ) ) ;
ImGui : : PushStyleColor ( ImGuiCol_TabUnfocusedActive , ImGui : : GetColorU32 ( ImGuiCol_MenuBarBg ) ) ;
2022-07-31 11:09:20 +02:00
auto providerSelectorVisible = ImGui : : BeginTabBar ( " provider_switcher " , ImGuiTabBarFlags_FittingPolicyScroll | ImGuiTabBarFlags_Reorderable | ImGuiTabBarFlags_AutoSelectNewTabs ) ;
2022-07-30 21:25:18 +02:00
ImGui : : PopStyleColor ( 2 ) ;
2021-09-21 02:29:54 +02:00
2022-07-30 21:25:18 +02:00
if ( providerSelectorVisible ) {
2022-03-27 00:01:28 +01:00
for ( size_t i = 0 ; i < providers . size ( ) ; i + + ) {
2023-12-07 11:21:13 +01:00
if ( providers . size ( ) = = 1 )
break ;
2022-07-31 10:55:10 +02:00
auto & tabProvider = providers [ i ] ;
2023-09-24 18:04:14 +02:00
const auto selectedProviderIndex = ImHexApi : : Provider : : getCurrentProviderIndex ( ) ;
2022-07-31 10:55:10 +02:00
2022-07-30 21:25:18 +02:00
bool open = true ;
2022-07-31 10:55:10 +02:00
ImGui : : PushID ( tabProvider ) ;
2023-09-24 18:04:14 +02:00
ImGuiTabItemFlags flags = ImGuiTabItemFlags_NoTooltip ;
if ( tabProvider - > isDirty ( ) )
flags | = ImGuiTabItemFlags_UnsavedDocument ;
2023-10-24 19:29:22 +02:00
if ( i64 ( i ) = = selectedProviderIndex & & providerJustChanged ) {
2023-09-24 18:04:14 +02:00
flags | = ImGuiTabItemFlags_SetSelected ;
2023-10-24 19:29:22 +02:00
providerJustChanged = false ;
}
static size_t lastSelectedProvider = 0 ;
2023-09-24 18:04:14 +02:00
2023-10-24 19:29:22 +02:00
bool isSelected = false ;
2023-09-24 18:04:14 +02:00
if ( ImGui : : BeginTabItem ( tabProvider - > getName ( ) . c_str ( ) , & open , flags ) ) {
2023-10-24 19:29:22 +02:00
isSelected = true ;
2022-07-30 21:25:18 +02:00
ImGui : : EndTabItem ( ) ;
2021-09-21 02:29:54 +02:00
}
2023-10-24 19:29:22 +02:00
if ( isSelected & & lastSelectedProvider ! = i ) {
2023-09-24 18:04:14 +02:00
ImHexApi : : Provider : : setCurrentProvider ( i ) ;
2023-10-24 19:29:22 +02:00
lastSelectedProvider = i ;
}
2023-06-02 14:44:19 +02:00
2023-11-16 22:24:06 +01:00
if ( ImGuiExt : : InfoTooltip ( ) ) {
2023-06-02 14:44:19 +02:00
ImGui : : BeginTooltip ( ) ;
2023-11-16 22:24:06 +01:00
ImGuiExt : : TextFormatted ( " {} " , tabProvider - > getName ( ) . c_str ( ) ) ;
2023-06-02 14:44:19 +02:00
2023-10-12 20:28:02 +02:00
const auto & description = tabProvider - > getDataDescription ( ) ;
2023-06-30 22:28:37 +02:00
if ( ! description . empty ( ) ) {
2023-06-02 14:44:19 +02:00
ImGui : : Separator ( ) ;
2023-06-30 22:28:37 +02:00
if ( ImGui : : GetIO ( ) . KeyShift & & ! description . empty ( ) ) {
2023-06-02 14:44:19 +02:00
2023-06-30 22:28:37 +02:00
if ( ImGui : : BeginTable ( " information " , 2 , ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_NoKeepColumnsVisible , ImVec2 ( 400 _scaled , 0 ) ) ) {
ImGui : : TableSetupColumn ( " type " ) ;
ImGui : : TableSetupColumn ( " value " , ImGuiTableColumnFlags_WidthStretch ) ;
2023-06-02 14:44:19 +02:00
2023-06-30 22:28:37 +02:00
ImGui : : TableNextRow ( ) ;
2023-06-02 14:44:19 +02:00
2023-06-30 22:28:37 +02:00
for ( auto & [ name , value ] : description ) {
ImGui : : TableNextColumn ( ) ;
2023-11-16 22:24:06 +01:00
ImGuiExt : : TextFormatted ( " {} " , name ) ;
2023-06-30 22:28:37 +02:00
ImGui : : TableNextColumn ( ) ;
2023-11-16 22:24:06 +01:00
ImGuiExt : : TextFormattedWrapped ( " {} " , value ) ;
2023-06-30 22:28:37 +02:00
}
2023-06-02 14:44:19 +02:00
2023-06-30 22:28:37 +02:00
ImGui : : EndTable ( ) ;
}
} else {
2023-11-16 22:24:06 +01:00
ImGuiExt : : TextFormattedDisabled ( " hex.builtin.provider.tooltip.show_more " _lang ) ;
2023-06-02 14:44:19 +02:00
}
}
ImGui : : EndTooltip ( ) ;
}
2022-07-31 10:55:10 +02:00
ImGui : : PopID ( ) ;
2021-09-21 02:29:54 +02:00
2022-07-30 21:25:18 +02:00
if ( ! open ) {
ImHexApi : : Provider : : remove ( providers [ i ] ) ;
break ;
}
2023-05-21 13:21:53 +02:00
2023-12-18 11:58:31 +01:00
if ( ImGui : : IsMouseReleased ( ImGuiMouseButton_Right ) & & ImGui : : IsItemHovered ( ) ) {
rightClickedProvider = tabProvider ;
RequestOpenPopup : : post ( " ProviderMenu " ) ;
2023-05-21 13:21:53 +02:00
}
2022-07-30 21:25:18 +02:00
}
ImGui : : EndTabBar ( ) ;
2021-09-21 02:29:54 +02:00
}
2022-05-27 20:42:07 +02:00
}
ImGui : : EndDisabled ( ) ;
2021-08-21 00:52:11 +02:00
} ) ;
}
2022-07-02 17:53:13 +02:00
void handleBorderlessWindowMode ( ) {
// Intel's OpenGL driver has weird bugs that cause the drawn window to be offset to the bottom right.
// This can be fixed by either using Mesa3D's OpenGL Software renderer or by simply disabling it.
// If you want to try if it works anyways on your GPU, set the hex.builtin.setting.interface.force_borderless_window_mode setting to 1
if ( ImHexApi : : System : : isBorderlessWindowModeEnabled ( ) ) {
bool isIntelGPU = hex : : containsIgnoreCase ( ImHexApi : : System : : getGPUVendor ( ) , " Intel " ) ;
ImHexApi : : System : : impl : : setBorderlessWindowMode ( ! isIntelGPU ) ;
if ( isIntelGPU )
log : : warn ( " Intel GPU detected! Intel's OpenGL driver has bugs that can cause issues when using ImHex. If you experience any rendering bugs, please try the Mesa3D Software Renderer " ) ;
}
}
2021-06-07 18:13:54 +02:00
}