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>
2022-07-02 16:22:38 +02:00
# include <hex/api/localization.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>
2021-12-31 01:10:06 +01:00
# include <hex/ui/imgui_imhex_extensions.h>
2021-08-21 00:52:11 +02:00
2023-04-08 00:58:53 +02:00
# include <content/popups/popup_tasks_waiting.hpp>
# include <content/popups/popup_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
2022-05-27 20:42:07 +02:00
static void drawGlobalPopups ( ) {
2022-09-03 23:56:57 +02:00
// Task exception popup
for ( const auto & task : TaskManager : : getRunningTasks ( ) ) {
if ( task - > hadException ( ) ) {
2023-04-08 00:58:53 +02:00
PopupError : : open ( hex : : format ( " hex.builtin.popup.error.task_exception " _lang , LangEntry ( task - > getUnlocalizedName ( ) ) , task - > getExceptionMessage ( ) ) ) ;
2022-09-03 23:56:57 +02:00
task - > clearException ( ) ;
break ;
}
}
2022-05-27 20:42:07 +02:00
}
void addGlobalUIItems ( ) {
EventManager : : subscribe < EventFrameEnd > ( drawGlobalPopups ) ;
}
2021-06-07 18:13:54 +02:00
void addFooterItems ( ) {
2021-12-13 22:58:23 +01:00
if ( hex : : isProcessElevated ( ) ) {
ContentRegistry : : Interface : : addFooterItem ( [ ] {
ImGui : : TextUnformatted ( ICON_VS_SHIELD ) ;
} ) ;
}
2022-09-05 22:37:28 +02:00
# if defined(DEBUG)
ContentRegistry : : Interface : : addFooterItem ( [ ] {
static float framerate = 0 ;
if ( ImGui : : HasSecondPassed ( ) ) {
framerate = 1.0F / ImGui : : GetIO ( ) . DeltaTime ;
}
2021-06-07 18:13:54 +02:00
2022-09-05 22:37:28 +02:00
ImGui : : TextFormatted ( " FPS {0:2}.{1:02} " , u32 ( framerate ) , u32 ( framerate * 100 ) % 100 ) ;
} ) ;
# 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 ( ) ;
2022-08-17 16:15:36 +02:00
auto frontTask = tasks . front ( ) ;
2021-12-16 23:48:52 +01:00
2023-01-24 13:42:08 +01:00
auto progress = frontTask - > getMaxValue ( ) = = 0 ? 1 : float ( frontTask - > getValue ( ) ) / frontTask - > getMaxValue ( ) ;
2023-01-14 14:21:16 +01:00
ImHexApi : : System : : setTaskBarProgress ( ImHexApi : : System : : TaskProgressState : : Progress , ImHexApi : : System : : TaskProgressType : : Normal , progress * 100 ) ;
2022-08-17 16:15:36 +02:00
auto widgetStart = ImGui : : GetCursorPos ( ) ;
2021-12-16 23:48:52 +01:00
2022-08-04 11:00:49 +02:00
ImGui : : TextSpinner ( hex : : format ( " ({}) " , taskCount ) . c_str ( ) ) ;
2022-08-17 16:15:36 +02:00
ImGui : : SameLine ( ) ;
2023-01-24 13:42:08 +01:00
ImGui : : SmallProgressBar ( progress , ( ImGui : : GetCurrentWindow ( ) - > MenuBarHeight ( ) - 10 _scaled ) / 2.0 ) ;
2022-08-17 16:15:36 +02:00
ImGui : : SameLine ( ) ;
auto widgetEnd = ImGui : : GetCursorPos ( ) ;
ImGui : : SetCursorPos ( widgetStart ) ;
ImGui : : InvisibleButton ( " FrontTask " , ImVec2 ( widgetEnd . x - widgetStart . x , ImGui : : GetCurrentWindow ( ) - > MenuBarHeight ( ) ) ) ;
ImGui : : SetCursorPos ( widgetEnd ) ;
ImGui : : InfoTooltip ( LangEntry ( frontTask - > getUnlocalizedName ( ) ) . get ( ) . c_str ( ) ) ;
if ( ImGui : : BeginPopupContextItem ( " FrontTask " , ImGuiPopupFlags_MouseButtonLeft ) ) {
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 ) ;
ImGui : : TextFormatted ( " {} " , LangEntry ( task - > getUnlocalizedName ( ) ) ) ;
ImGui : : SameLine ( ) ;
ImGui : : SeparatorEx ( ImGuiSeparatorFlags_Vertical ) ;
ImGui : : SameLine ( ) ;
ImGui : : SmallProgressBar ( frontTask - > getMaxValue ( ) = = 0 ? 1 : ( float ( frontTask - > getValue ( ) ) / frontTask - > getMaxValue ( ) ) , ( ImGui : : GetTextLineHeightWithSpacing ( ) - 5 _scaled ) / 2 ) ;
ImGui : : SameLine ( ) ;
ImGui : : PushStyleVar ( ImGuiStyleVar_WindowPadding , ImVec2 ( 0 , 0 ) ) ;
if ( ImGui : : ToolBarButton ( ICON_VS_DEBUG_STOP , ImGui : : GetStyleColorVec4 ( ImGuiCol_Text ) ) )
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 ) ) ) ;
if ( ImGui : : ToolBarButton ( ICON_VS_DEBUG_STOP , ImGui : : GetStyleColorVec4 ( ImGuiCol_Text ) ) )
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
} ) ;
}
2021-08-21 00:52:11 +02:00
void addToolbarItems ( ) {
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 ( ) ) ;
{
2021-10-07 11:34:46 +02:00
if ( ImGui : : ToolBarButton ( ICON_VS_DISCARD , ImGui : : 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 ( ) ) ;
{
2021-10-07 11:34:46 +02:00
if ( ImGui : : ToolBarButton ( ICON_VS_REDO , ImGui : : 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
2022-10-21 12:01:28 +02:00
if ( ImGui : : ToolBarButton ( ICON_VS_FILE , ImGui : : GetCustomColorVec4 ( ImGuiCustomCol_ToolbarGray ) ) ) {
auto newProvider = hex : : ImHexApi : : Provider : : createProvider ( " hex.builtin.provider.mem_file " , true ) ;
if ( newProvider ! = nullptr & & ! newProvider - > open ( ) )
hex : : ImHexApi : : Provider : : remove ( newProvider ) ;
else
EventManager : : post < EventProviderOpened > ( newProvider ) ;
}
2021-08-21 13:53:50 +02:00
2022-07-29 11:35:29 +02:00
// Open file
if ( ImGui : : ToolBarButton ( ICON_VS_FOLDER_OPENED , ImGui : : GetCustomColorVec4 ( ImGuiCustomCol_ToolbarBrown ) ) )
EventManager : : post < RequestOpenWindow > ( " Open File " ) ;
}
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 ( ) ) ;
{
2021-10-07 11:34:46 +02:00
if ( ImGui : : ToolBarButton ( ICON_VS_SAVE , ImGui : : 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 ( ) ) ;
{
2021-10-07 11:34:46 +02:00
if ( ImGui : : ToolBarButton ( ICON_VS_SAVE_AS , ImGui : : 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 ( ) ) ;
{
2021-10-07 11:34:46 +02:00
if ( ImGui : : ToolBarButton ( ICON_VS_BOOKMARK , ImGui : : 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 + + ) {
2022-07-31 10:55:10 +02:00
auto & tabProvider = providers [ i ] ;
2022-07-30 21:25:18 +02:00
bool open = true ;
2022-07-31 10:55:10 +02:00
ImGui : : PushID ( tabProvider ) ;
2022-08-14 19:11:49 +02:00
if ( ImGui : : BeginTabItem ( tabProvider - > getName ( ) . c_str ( ) , & open , tabProvider - > isDirty ( ) ? ImGuiTabItemFlags_UnsavedDocument : ImGuiTabItemFlags_None ) ) {
2022-02-01 18:09:40 +01:00
ImHexApi : : Provider : : setCurrentProvider ( i ) ;
2022-07-30 21:25:18 +02:00
ImGui : : EndTabItem ( ) ;
2021-09-21 02:29:54 +02:00
}
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
std : : string popupID = std : : string ( " ProviderMenu. " ) + std : : to_string ( tabProvider - > getID ( ) ) ;
if ( ImGui : : IsMouseReleased ( 1 ) & & ImGui : : IsItemHovered ( ) ) {
ImGui : : OpenPopup ( popupID . c_str ( ) ) ;
}
if ( ImGui : : BeginPopup ( popupID . c_str ( ) ) ) {
for ( auto p : tabProvider - > getMenuEntries ( ) ) {
if ( ImGui : : MenuItem ( p . first . c_str ( ) ) ) {
p . second ( ) ;
}
}
ImGui : : EndPopup ( ) ;
}
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
}