diff --git a/lib/libimhex/include/hex/api/event_manager.hpp b/lib/libimhex/include/hex/api/event_manager.hpp index 9745568ff..5a939096d 100644 --- a/lib/libimhex/include/hex/api/event_manager.hpp +++ b/lib/libimhex/include/hex/api/event_manager.hpp @@ -252,6 +252,7 @@ namespace hex { EVENT_DEF(EventAchievementUnlocked, const Achievement&); EVENT_DEF(EventSearchBoxClicked, u32); EVENT_DEF(EventViewOpened, View*); + EVENT_DEF(EventFirstLaunch); EVENT_DEF(EventFileDragged, bool); EVENT_DEF(EventFileDropped, std::fs::path); diff --git a/lib/libimhex/include/hex/api/imhex_api.hpp b/lib/libimhex/include/hex/api/imhex_api.hpp index c6d1372c3..380bc680f 100644 --- a/lib/libimhex/include/hex/api/imhex_api.hpp +++ b/lib/libimhex/include/hex/api/imhex_api.hpp @@ -381,6 +381,8 @@ namespace hex { void addInitArgument(const std::string &key, const std::string &value = { }); void setLastFrameTime(double time); + + bool isWindowResizable(); } struct ProgramArguments { @@ -579,6 +581,8 @@ namespace hex { void addStartupTask(const std::string &name, bool async, const std::function &function); double getLastFrameTime(); + + void setWindowResizable(bool resizable); } /** diff --git a/lib/libimhex/source/api/imhex_api.cpp b/lib/libimhex/source/api/imhex_api.cpp index 2d5570b37..50d5058ad 100644 --- a/lib/libimhex/source/api/imhex_api.cpp +++ b/lib/libimhex/source/api/imhex_api.cpp @@ -13,6 +13,7 @@ #include #include +#include #if defined(OS_WINDOWS) #define WIN32_LEAN_AND_MEAN @@ -448,6 +449,11 @@ namespace hex { s_lastFrameTime = time; } + static bool s_windowResizable = true; + bool isWindowResizable() { + return s_windowResizable; + } + } @@ -708,6 +714,12 @@ namespace hex { return impl::s_lastFrameTime; } + void setWindowResizable(bool resizable) { + glfwSetWindowAttrib(impl::s_mainWindowHandle, GLFW_RESIZABLE, resizable); + impl::s_windowResizable = resizable; + } + + } diff --git a/main/gui/source/window/win_window.cpp b/main/gui/source/window/win_window.cpp index c7e284fdc..c5ab9e8bf 100644 --- a/main/gui/source/window/win_window.cpp +++ b/main/gui/source/window/win_window.cpp @@ -197,6 +197,12 @@ namespace hex { std::string_view hoveredWindowName = GImGui->HoveredWindow == nullptr ? "" : GImGui->HoveredWindow->Name; + if (!ImHexApi::System::impl::isWindowResizable()) { + if (result != RegionClient) { + return HTCAPTION; + } + } + switch (result) { case RegionLeft: return HTLEFT; @@ -481,6 +487,13 @@ namespace hex { // Remove WS_POPUP style from the window to make various window management tools work auto hwnd = glfwGetWin32Window(m_window); ::SetWindowLong(hwnd, GWL_STYLE, (GetWindowLong(hwnd, GWL_STYLE) | WS_OVERLAPPEDWINDOW) & ~WS_POPUP); + + if (!ImHexApi::System::impl::isWindowResizable()) { + if (glfwGetWindowAttrib(m_window, GLFW_MAXIMIZED)) { + glfwRestoreWindow(m_window); + } + } + } void Window::endNativeWindowFrame() { diff --git a/main/gui/source/window/window.cpp b/main/gui/source/window/window.cpp index e29a76fe6..eced02063 100644 --- a/main/gui/source/window/window.cpp +++ b/main/gui/source/window/window.cpp @@ -159,6 +159,14 @@ namespace hex { glfwPollEvents(); + static ImVec2 lastWindowSize = ImHexApi::System::getMainWindowSize(); + if (ImHexApi::System::impl::isWindowResizable()) { + glfwSetWindowSizeLimits(m_window, 480_scaled, 360_scaled, GLFW_DONT_CARE, GLFW_DONT_CARE); + lastWindowSize = ImHexApi::System::getMainWindowSize(); + } else { + glfwSetWindowSizeLimits(m_window, lastWindowSize.x, lastWindowSize.y, lastWindowSize.x, lastWindowSize.y); + } + // Render frame this->frameBegin(); this->frame(); diff --git a/plugins/builtin/CMakeLists.txt b/plugins/builtin/CMakeLists.txt index 1a33037af..f5f567985 100644 --- a/plugins/builtin/CMakeLists.txt +++ b/plugins/builtin/CMakeLists.txt @@ -44,6 +44,7 @@ add_imhex_plugin( source/content/fonts.cpp source/content/workspaces.cpp source/content/pl_visualizers.cpp + source/content/out_of_box_experience.cpp source/content/data_processor_nodes/basic_nodes.cpp source/content/data_processor_nodes/control_nodes.cpp diff --git a/plugins/builtin/include/content/popups/popup_telemetry_request.hpp b/plugins/builtin/include/content/popups/popup_telemetry_request.hpp deleted file mode 100644 index 2a11d0621..000000000 --- a/plugins/builtin/include/content/popups/popup_telemetry_request.hpp +++ /dev/null @@ -1,117 +0,0 @@ -#pragma once - -#include - -#include - -#include - -#include - -namespace hex::plugin::builtin { - - class PopupTelemetryRequest : public Popup { - public: - PopupTelemetryRequest() - : hex::Popup("hex.ui.common.question", false) { - // Check if there is a telemetry uuid - m_uuid = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.uuid", "").get(); - if(m_uuid.empty()) { - // Generate a new uuid - m_uuid = wolv::hash::generateUUID(); - // Save - ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.uuid", m_uuid); - } - } - - void drawContent() override { - static std::string message = "hex.builtin.welcome.server_contact_text"_lang; - ImGuiExt::TextFormattedWrapped("{}", message.c_str()); - ImGui::NewLine(); - - if(ImGui::CollapsingHeader("hex.builtin.welcome.server_contact.data_collected_title"_lang)) { - if(ImGui::BeginTable("hex.builtin.welcome.server_contact.data_collected_table"_lang, 2, - ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY | ImGuiTableFlags_NoHostExtendY, - ImVec2(ImGui::GetContentRegionAvail().x, 100_scaled))) { - ImGui::TableSetupColumn("hex.builtin.welcome.server_contact.data_collected_table.key"_lang); - ImGui::TableSetupColumn("hex.builtin.welcome.server_contact.data_collected_table.value"_lang, ImGuiTableColumnFlags_WidthStretch); - ImGui::TableSetupScrollFreeze(0, 1); - - ImGui::TableHeadersRow(); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TextUnformatted("hex.builtin.welcome.server_contact.data_collected.uuid"_lang); - ImGui::TableNextColumn(); - ImGui::TextWrapped("%s", m_uuid.c_str()); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TextUnformatted("hex.builtin.welcome.server_contact.data_collected.version"_lang); - ImGui::TableNextColumn(); - ImGuiExt::TextFormattedWrapped("{}\n{}@{}\n{}", - ImHexApi::System::getImHexVersion(), - ImHexApi::System::getCommitHash(true), - ImHexApi::System::getCommitBranch(), - ImHexApi::System::isPortableVersion() ? "Portable" : "Installed" - ); - - ImGui::TableNextRow(); - ImGui::TableNextColumn(); - ImGui::TextUnformatted("hex.builtin.welcome.server_contact.data_collected.os"_lang); - ImGui::TableNextColumn(); - ImGuiExt::TextFormattedWrapped("{}\n{}\n{}\n{}", - ImHexApi::System::getOSName(), - ImHexApi::System::getOSVersion(), - ImHexApi::System::getArchitecture(), - ImHexApi::System::getGPUVendor()); - - ImGui::EndTable(); - } - } - - ImGui::NewLine(); - - const auto width = ImGui::GetWindowWidth(); - const auto buttonSize = ImVec2(width / 3 - ImGui::GetStyle().FramePadding.x * 3, 0); - const auto buttonPos = [&](u8 index) { return ImGui::GetStyle().FramePadding.x + (buttonSize.x + ImGui::GetStyle().FramePadding.x * 3) * index; }; - - ImGui::SetCursorPosX(buttonPos(0)); - if (ImGui::Button("hex.ui.common.allow"_lang, buttonSize)) { - ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.server_contact", 1); - ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.upload_crash_logs", 1); - this->close(); - } - ImGui::SameLine(); - ImGui::SetCursorPosX(buttonPos(1)); - if (ImGui::Button("hex.builtin.welcome.server_contact.crash_logs_only"_lang, buttonSize)) { - ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.server_contact", 0); - ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.upload_crash_logs", 1); - this->close(); - } - ImGui::SameLine(); - ImGui::SetCursorPosX(buttonPos(2)); - if (ImGui::Button("hex.ui.common.deny"_lang, buttonSize)) { - this->close(); - } - - ImGui::SetWindowPos((ImHexApi::System::getMainWindowSize() - ImGui::GetWindowSize()) / 2, ImGuiCond_Appearing); - } - - [[nodiscard]] ImGuiWindowFlags getFlags() const override { - return ImGuiWindowFlags_AlwaysAutoResize; - } - - [[nodiscard]] ImVec2 getMinSize() const override { - return scaled({ 500, 100 }); - } - - [[nodiscard]] ImVec2 getMaxSize() const override { - return scaled({ 500, 450 }); - } - - private: - std::string m_uuid; - }; - -} \ No newline at end of file diff --git a/plugins/builtin/romfs/assets/common/compass.png b/plugins/builtin/romfs/assets/common/compass.png new file mode 100644 index 000000000..4cc7ee2c1 Binary files /dev/null and b/plugins/builtin/romfs/assets/common/compass.png differ diff --git a/plugins/builtin/romfs/assets/screenshot_descriptions.json b/plugins/builtin/romfs/assets/screenshot_descriptions.json new file mode 100644 index 000000000..c1735347d --- /dev/null +++ b/plugins/builtin/romfs/assets/screenshot_descriptions.json @@ -0,0 +1,42 @@ +{ + "3d_visualizer.png": { + "title": "Advanced Data Visualizers", + "description": "After analyzing data using the pattern language, it's often useful to visualize parts of that data. ImHex provides a variety of visualizers that can be used to visualize different types of data right in the editor.\n\nAvailable visualizers include a 3D model viewer, RGBA and Image decoder, a audio player, line and scatter plots and many more!" + }, + "bookmarks.png": { + "title": "Bookmarks", + "description": "Bookmarks can be used to mark interesting locations in the file, give them a name, color and description." + }, + "data_analysis.png": { + "title": "Data Analysis", + "description": "ImHex provides a variety of tools to analyze data and finding interesting information in it. This includes byte type and entropy graphs, byte frequency analysis, digram and layered distribution graphs and file magic based data type detection." + }, + "data_processor.png": { + "title": "Data Pre-processors", + "description": "ImHex's data pre-processors can be used to transform the data before it's displayed in the editor. This can be used to decrypt encrypted data, extract parts of the file for further analysis or calculate custom checksums." + }, + "diffing.png": { + "title": "Binary Diffing", + "description": "ImHex provides a powerful binary diffing tool that can compare two files and find the differences between them. It's able identify insertions, deletions and modifications of data." + }, + "floating_windows.png": { + "title": "Modern Interface", + "description": "ImHex's interface is based on a range of dockable windows that can be moved around and detached from the main window at any time. This allows for a very flexible and customizable interface.\n\nThe interface is also fully themeable and comes with various built-in themes by default." + }, + "patterns.png": { + "title": "Pattern Language", + "description": "ImHex's pattern language is a C-like language that can be used to describe data structures and patterns in the data. Writing format specifications in it allows ImHex to parse and decode the data and display it in a human readable way as well as highlight the different parts of the data in the Hex Editor.\n\nMany common data formats are already supported by the community and new ones can be created and shared easily." + }, + "simplified_mode.png": { + "title": "Simplified Mode", + "description": "ImHex's simplified mode is a more beginner friendly mode that hides some of the more advanced features of the editor. It's a great way to get started with reverse engineering and binary analysis or to use ImHex without being overwhelmed by the amount of features." + }, + "tools.png": { + "title": "Helpful Tools", + "description": "ImHex comes with a variety of tools that can be used to analyze and modify the data. This includes a symbol demangler, calculator, TCP client and server and many more!" + }, + "welcome_screen.png": { + "title": "Welcome Screen", + "description": "ImHex's welcome screen provides a quick overview of the most important features and allows to quickly open files and projects.\n\nThere's many more options that go beyond just opening files, such as connecting to a GDB Server, attaching to a process or opening Intel Hex, Motorola S-Record and Base64 files." + } +} \ No newline at end of file diff --git a/plugins/builtin/romfs/assets/screenshots/3d_visualizer.png b/plugins/builtin/romfs/assets/screenshots/3d_visualizer.png new file mode 100644 index 000000000..c91f07086 Binary files /dev/null and b/plugins/builtin/romfs/assets/screenshots/3d_visualizer.png differ diff --git a/plugins/builtin/romfs/assets/screenshots/bookmarks.png b/plugins/builtin/romfs/assets/screenshots/bookmarks.png new file mode 100644 index 000000000..2d5be084d Binary files /dev/null and b/plugins/builtin/romfs/assets/screenshots/bookmarks.png differ diff --git a/plugins/builtin/romfs/assets/screenshots/data_analysis.png b/plugins/builtin/romfs/assets/screenshots/data_analysis.png new file mode 100644 index 000000000..ccba6ec76 Binary files /dev/null and b/plugins/builtin/romfs/assets/screenshots/data_analysis.png differ diff --git a/plugins/builtin/romfs/assets/screenshots/data_processor.png b/plugins/builtin/romfs/assets/screenshots/data_processor.png new file mode 100644 index 000000000..972e7a1a8 Binary files /dev/null and b/plugins/builtin/romfs/assets/screenshots/data_processor.png differ diff --git a/plugins/builtin/romfs/assets/screenshots/diffing.png b/plugins/builtin/romfs/assets/screenshots/diffing.png new file mode 100644 index 000000000..021a2410c Binary files /dev/null and b/plugins/builtin/romfs/assets/screenshots/diffing.png differ diff --git a/plugins/builtin/romfs/assets/screenshots/floating_windows.png b/plugins/builtin/romfs/assets/screenshots/floating_windows.png new file mode 100644 index 000000000..923f4b72c Binary files /dev/null and b/plugins/builtin/romfs/assets/screenshots/floating_windows.png differ diff --git a/plugins/builtin/romfs/assets/screenshots/patterns.png b/plugins/builtin/romfs/assets/screenshots/patterns.png new file mode 100644 index 000000000..31672243a Binary files /dev/null and b/plugins/builtin/romfs/assets/screenshots/patterns.png differ diff --git a/plugins/builtin/romfs/assets/screenshots/simplified_mode.png b/plugins/builtin/romfs/assets/screenshots/simplified_mode.png new file mode 100644 index 000000000..9566321f8 Binary files /dev/null and b/plugins/builtin/romfs/assets/screenshots/simplified_mode.png differ diff --git a/plugins/builtin/romfs/assets/screenshots/tools.png b/plugins/builtin/romfs/assets/screenshots/tools.png new file mode 100644 index 000000000..d6e78c751 Binary files /dev/null and b/plugins/builtin/romfs/assets/screenshots/tools.png differ diff --git a/plugins/builtin/romfs/assets/screenshots/welcome_screen.png b/plugins/builtin/romfs/assets/screenshots/welcome_screen.png new file mode 100644 index 000000000..92924b7b4 Binary files /dev/null and b/plugins/builtin/romfs/assets/screenshots/welcome_screen.png differ diff --git a/plugins/builtin/romfs/lang/de_DE.json b/plugins/builtin/romfs/lang/de_DE.json index 9c42a07bc..e469c9c7f 100644 --- a/plugins/builtin/romfs/lang/de_DE.json +++ b/plugins/builtin/romfs/lang/de_DE.json @@ -785,14 +785,14 @@ "hex.builtin.visualizer.hexadecimal.8bit": "Hexadezimal (8 bits)", "hex.builtin.visualizer.hexii": "HexII", "hex.builtin.visualizer.rgba8": "RGBA8 Farbe", - "hex.builtin.welcome.server_contact_text": "Möchtest du die Kommunikation mit ImHex Servern zulassen?\n\nDies erlaubt das automatische suchen nach Updates und das hochladen\nvon anonymen crash logs im falle eines absturzes.", - "hex.builtin.welcome.server_contact.data_collected_table.key": "", - "hex.builtin.welcome.server_contact.data_collected_table.value": "", - "hex.builtin.welcome.server_contact.data_collected_title": "", - "hex.builtin.welcome.server_contact.data_collected.uuid": "", - "hex.builtin.welcome.server_contact.data_collected.version": "", - "hex.builtin.welcome.server_contact.data_collected.os": "", - "hex.builtin.welcome.server_contact.crash_logs_only": "", + "hex.builtin.oobe.server_contact_text": "Möchtest du die Kommunikation mit ImHex Servern zulassen?\n\nDies erlaubt das automatische suchen nach Updates und das hochladen\nvon anonymen crash logs im falle eines absturzes.", + "hex.builtin.oobe.server_contact.data_collected_table.key": "", + "hex.builtin.oobe.server_contact.data_collected_table.value": "", + "hex.builtin.oobe.server_contact.data_collected_title": "", + "hex.builtin.oobe.server_contact.data_collected.uuid": "", + "hex.builtin.oobe.server_contact.data_collected.version": "", + "hex.builtin.oobe.server_contact.data_collected.os": "", + "hex.builtin.oobe.server_contact.crash_logs_only": "", "hex.builtin.welcome.customize.settings.desc": "Ändere ImHex's Einstellungen", "hex.builtin.welcome.customize.settings.title": "Einstellungen", "hex.builtin.welcome.header.customize": "Anpassen", diff --git a/plugins/builtin/romfs/lang/en_US.json b/plugins/builtin/romfs/lang/en_US.json index c366d33ff..a6250c159 100644 --- a/plugins/builtin/romfs/lang/en_US.json +++ b/plugins/builtin/romfs/lang/en_US.json @@ -934,14 +934,16 @@ "hex.builtin.visualizer.hexadecimal.8bit": "Hexadecimal (8 bits)", "hex.builtin.visualizer.hexii": "HexII", "hex.builtin.visualizer.rgba8": "RGBA8 Color", - "hex.builtin.welcome.server_contact_text": "Do you want to allow the communication with ImHex's Servers?\n\n\nThis allows performing automatic update checks and uploads of very limited usage statistics, all of which are listed below.\n\nAlternatively you can also choose to only submit crash logs which help immensely with identifying and fixing bugs you might experience.\n\nAll information is processed by our own Servers and is not given out to any third-parties.\n\n\nYou can change these choices at any time in the settings.", - "hex.builtin.welcome.server_contact.data_collected_table.key": "Type", - "hex.builtin.welcome.server_contact.data_collected_table.value": "Value", - "hex.builtin.welcome.server_contact.data_collected_title": "Data that will be shared", - "hex.builtin.welcome.server_contact.data_collected.uuid": "Random ID", - "hex.builtin.welcome.server_contact.data_collected.version": "ImHex Version", - "hex.builtin.welcome.server_contact.data_collected.os": "Operating System", - "hex.builtin.welcome.server_contact.crash_logs_only": "Just crash logs", + "hex.builtin.oobe.server_contact": "Server Contact", + "hex.builtin.oobe.server_contact.text": "Do you want to allow the communication with ImHex's Servers?\n\n\nThis allows performing automatic update checks and uploads of very limited usage statistics, all of which are listed below.\n\nAlternatively you can also choose to only submit crash logs which help immensely with identifying and fixing bugs you might experience.\n\nAll information is processed by our own Servers and is not given out to any third-parties.\n\n\nYou can change these choices at any time in the settings.", + "hex.builtin.oobe.server_contact.data_collected_table.key": "Type", + "hex.builtin.oobe.server_contact.data_collected_table.value": "Value", + "hex.builtin.oobe.server_contact.data_collected_title": "Data that will be shared", + "hex.builtin.oobe.server_contact.data_collected.uuid": "Random ID", + "hex.builtin.oobe.server_contact.data_collected.version": "ImHex Version", + "hex.builtin.oobe.server_contact.data_collected.os": "Operating System", + "hex.builtin.oobe.server_contact.crash_logs_only": "Just crash logs", + "hex.builtin.oobe.tutorial_question": "Since this is the first time you are using ImHex, would you like to play through the introduction tutorial?\n\nYou can always access the tutorial from the Help menu.", "hex.builtin.welcome.customize.settings.desc": "Change preferences of ImHex", "hex.builtin.welcome.customize.settings.title": "Settings", "hex.builtin.welcome.drop_file": "Drop a file here to get started...", @@ -983,7 +985,6 @@ "hex.builtin.popup.safety_backup.report_error": "Send crash log to developers", "hex.builtin.popup.safety_backup.restore": "Yes, Restore", "hex.builtin.popup.safety_backup.title": "Restore lost data", - "hex.builtin.popup.play_tutorial.desc": "As this is your first time launching ImHex, would you like to play through the interactive Tutorial?", "hex.builtin.welcome.start.create_file": "Create New File", "hex.builtin.welcome.start.open_file": "Open File", "hex.builtin.welcome.start.open_other": "Other Providers", diff --git a/plugins/builtin/romfs/lang/es_ES.json b/plugins/builtin/romfs/lang/es_ES.json index 170ce8283..9fdf9ffa5 100644 --- a/plugins/builtin/romfs/lang/es_ES.json +++ b/plugins/builtin/romfs/lang/es_ES.json @@ -783,14 +783,14 @@ "hex.builtin.visualizer.hexadecimal.8bit": "Hexadecimal (8 bits)", "hex.builtin.visualizer.hexii": "HexII", "hex.builtin.visualizer.rgba8": "Color RGBA8", - "hex.builtin.welcome.server_contact_text": "", - "hex.builtin.welcome.server_contact.data_collected_table.key": "", - "hex.builtin.welcome.server_contact.data_collected_table.value": "", - "hex.builtin.welcome.server_contact.data_collected_title": "", - "hex.builtin.welcome.server_contact.data_collected.uuid": "", - "hex.builtin.welcome.server_contact.data_collected.version": "", - "hex.builtin.welcome.server_contact.data_collected.os": "", - "hex.builtin.welcome.server_contact.crash_logs_only": "", + "hex.builtin.oobe.server_contact_text": "", + "hex.builtin.oobe.server_contact.data_collected_table.key": "", + "hex.builtin.oobe.server_contact.data_collected_table.value": "", + "hex.builtin.oobe.server_contact.data_collected_title": "", + "hex.builtin.oobe.server_contact.data_collected.uuid": "", + "hex.builtin.oobe.server_contact.data_collected.version": "", + "hex.builtin.oobe.server_contact.data_collected.os": "", + "hex.builtin.oobe.server_contact.crash_logs_only": "", "hex.builtin.welcome.customize.settings.desc": "Cambie preferencias de ImHex", "hex.builtin.welcome.customize.settings.title": "Ajustes", "hex.builtin.welcome.header.customize": "Personalizar", diff --git a/plugins/builtin/romfs/lang/it_IT.json b/plugins/builtin/romfs/lang/it_IT.json index 80d4fa31d..bf7ea13df 100644 --- a/plugins/builtin/romfs/lang/it_IT.json +++ b/plugins/builtin/romfs/lang/it_IT.json @@ -783,14 +783,14 @@ "hex.builtin.visualizer.hexadecimal.8bit": "", "hex.builtin.visualizer.hexii": "", "hex.builtin.visualizer.rgba8": "", - "hex.builtin.welcome.server_contact_text": "", - "hex.builtin.welcome.server_contact.data_collected_table.key": "", - "hex.builtin.welcome.server_contact.data_collected_table.value": "", - "hex.builtin.welcome.server_contact.data_collected_title": "", - "hex.builtin.welcome.server_contact.data_collected.uuid": "", - "hex.builtin.welcome.server_contact.data_collected.version": "", - "hex.builtin.welcome.server_contact.data_collected.os": "", - "hex.builtin.welcome.server_contact.crash_logs_only": "", + "hex.builtin.oobe.server_contact_text": "", + "hex.builtin.oobe.server_contact.data_collected_table.key": "", + "hex.builtin.oobe.server_contact.data_collected_table.value": "", + "hex.builtin.oobe.server_contact.data_collected_title": "", + "hex.builtin.oobe.server_contact.data_collected.uuid": "", + "hex.builtin.oobe.server_contact.data_collected.version": "", + "hex.builtin.oobe.server_contact.data_collected.os": "", + "hex.builtin.oobe.server_contact.crash_logs_only": "", "hex.builtin.welcome.customize.settings.desc": "Cambia le preferenze di ImHex", "hex.builtin.welcome.customize.settings.title": "Impostazioni", "hex.builtin.welcome.header.customize": "Personalizza", diff --git a/plugins/builtin/romfs/lang/ja_JP.json b/plugins/builtin/romfs/lang/ja_JP.json index e880b6dea..8d4b41876 100644 --- a/plugins/builtin/romfs/lang/ja_JP.json +++ b/plugins/builtin/romfs/lang/ja_JP.json @@ -783,14 +783,14 @@ "hex.builtin.visualizer.hexadecimal.8bit": "16進数 ( 8 bits)", "hex.builtin.visualizer.hexii": "", "hex.builtin.visualizer.rgba8": "RGBA8", - "hex.builtin.welcome.server_contact_text": "", - "hex.builtin.welcome.server_contact.data_collected_table.key": "", - "hex.builtin.welcome.server_contact.data_collected_table.value": "", - "hex.builtin.welcome.server_contact.data_collected_title": "", - "hex.builtin.welcome.server_contact.data_collected.uuid": "", - "hex.builtin.welcome.server_contact.data_collected.version": "", - "hex.builtin.welcome.server_contact.data_collected.os": "", - "hex.builtin.welcome.server_contact.crash_logs_only": "", + "hex.builtin.oobe.server_contact_text": "", + "hex.builtin.oobe.server_contact.data_collected_table.key": "", + "hex.builtin.oobe.server_contact.data_collected_table.value": "", + "hex.builtin.oobe.server_contact.data_collected_title": "", + "hex.builtin.oobe.server_contact.data_collected.uuid": "", + "hex.builtin.oobe.server_contact.data_collected.version": "", + "hex.builtin.oobe.server_contact.data_collected.os": "", + "hex.builtin.oobe.server_contact.crash_logs_only": "", "hex.builtin.welcome.customize.settings.desc": "ImHexの設定を変更します", "hex.builtin.welcome.customize.settings.title": "設定", "hex.builtin.welcome.header.customize": "カスタマイズ", diff --git a/plugins/builtin/romfs/lang/ko_KR.json b/plugins/builtin/romfs/lang/ko_KR.json index dad4f28a9..dbd375506 100644 --- a/plugins/builtin/romfs/lang/ko_KR.json +++ b/plugins/builtin/romfs/lang/ko_KR.json @@ -804,14 +804,14 @@ "hex.builtin.visualizer.hexadecimal.8bit": "16진수 (8비트)", "hex.builtin.visualizer.hexii": "HexII", "hex.builtin.visualizer.rgba8": "RGBA8 색상", - "hex.builtin.welcome.server_contact_text": "ImHex 서버와의 통신을 허용하시겠습니까?\n\n\n이를 통해 자동으로 업데이트를 확인하고 매우 제한된 사용 통계를 업로드할 수 있으며 그 내용은 아래와 같습니다.\n\n또는 크래시 로그만 제출하도록 선택할 수도 있는데, 이는 발생할 수 있는 버그를 식별하고 수정하는 데 큰 도움이 됩니다.\n\n모든 정보는 당사 자체 서버에서 처리되며 제3자에게 제공되지 않습니다.\n\n\n이러한 선택 사항은 설정에서 언제든지 변경할 수 있습니다.", - "hex.builtin.welcome.server_contact.data_collected_table.key": "유형", - "hex.builtin.welcome.server_contact.data_collected_table.value": "값", - "hex.builtin.welcome.server_contact.data_collected_title": "공유할 데이터", - "hex.builtin.welcome.server_contact.data_collected.uuid": "무작위 ID", - "hex.builtin.welcome.server_contact.data_collected.version": "ImHex 버전", - "hex.builtin.welcome.server_contact.data_collected.os": "운영 체제", - "hex.builtin.welcome.server_contact.crash_logs_only": "충돌 로그만 제출", + "hex.builtin.oobe.server_contact_text": "ImHex 서버와의 통신을 허용하시겠습니까?\n\n\n이를 통해 자동으로 업데이트를 확인하고 매우 제한된 사용 통계를 업로드할 수 있으며 그 내용은 아래와 같습니다.\n\n또는 크래시 로그만 제출하도록 선택할 수도 있는데, 이는 발생할 수 있는 버그를 식별하고 수정하는 데 큰 도움이 됩니다.\n\n모든 정보는 당사 자체 서버에서 처리되며 제3자에게 제공되지 않습니다.\n\n\n이러한 선택 사항은 설정에서 언제든지 변경할 수 있습니다.", + "hex.builtin.oobe.server_contact.data_collected_table.key": "유형", + "hex.builtin.oobe.server_contact.data_collected_table.value": "값", + "hex.builtin.oobe.server_contact.data_collected_title": "공유할 데이터", + "hex.builtin.oobe.server_contact.data_collected.uuid": "무작위 ID", + "hex.builtin.oobe.server_contact.data_collected.version": "ImHex 버전", + "hex.builtin.oobe.server_contact.data_collected.os": "운영 체제", + "hex.builtin.oobe.server_contact.crash_logs_only": "충돌 로그만 제출", "hex.builtin.welcome.customize.settings.desc": "ImHex의 설정을 변경합니다", "hex.builtin.welcome.customize.settings.title": "설정", "hex.builtin.welcome.header.customize": "사용자화", diff --git a/plugins/builtin/romfs/lang/pt_BR.json b/plugins/builtin/romfs/lang/pt_BR.json index ad5c9c9dc..ae095b5b2 100644 --- a/plugins/builtin/romfs/lang/pt_BR.json +++ b/plugins/builtin/romfs/lang/pt_BR.json @@ -783,14 +783,14 @@ "hex.builtin.visualizer.hexadecimal.8bit": "Hexadecimal (8 bits)", "hex.builtin.visualizer.hexii": "HexII", "hex.builtin.visualizer.rgba8": "RGBA8 Color", - "hex.builtin.welcome.server_contact_text": "", - "hex.builtin.welcome.server_contact.data_collected_table.key": "", - "hex.builtin.welcome.server_contact.data_collected_table.value": "", - "hex.builtin.welcome.server_contact.data_collected_title": "", - "hex.builtin.welcome.server_contact.data_collected.uuid": "", - "hex.builtin.welcome.server_contact.data_collected.version": "", - "hex.builtin.welcome.server_contact.data_collected.os": "", - "hex.builtin.welcome.server_contact.crash_logs_only": "", + "hex.builtin.oobe.server_contact_text": "", + "hex.builtin.oobe.server_contact.data_collected_table.key": "", + "hex.builtin.oobe.server_contact.data_collected_table.value": "", + "hex.builtin.oobe.server_contact.data_collected_title": "", + "hex.builtin.oobe.server_contact.data_collected.uuid": "", + "hex.builtin.oobe.server_contact.data_collected.version": "", + "hex.builtin.oobe.server_contact.data_collected.os": "", + "hex.builtin.oobe.server_contact.crash_logs_only": "", "hex.builtin.welcome.customize.settings.desc": "Mudar preferencias do ImHex", "hex.builtin.welcome.customize.settings.title": "Configurações", "hex.builtin.welcome.header.customize": "Customizar", diff --git a/plugins/builtin/romfs/lang/zh_CN.json b/plugins/builtin/romfs/lang/zh_CN.json index 75bdaf9d0..7b30d49c9 100644 --- a/plugins/builtin/romfs/lang/zh_CN.json +++ b/plugins/builtin/romfs/lang/zh_CN.json @@ -797,14 +797,14 @@ "hex.builtin.visualizer.hexadecimal.8bit": "十六进制(8 位)", "hex.builtin.visualizer.hexii": "HexII", "hex.builtin.visualizer.rgba8": "RGBA8 颜色", - "hex.builtin.welcome.server_contact_text": "您想允许与 ImHex 的服务器通信吗?\n\n\n这允许执行自动更新检查并上传非常有限的使用统计信息,所有这些都在下面列出。\n\n或者,您也可以选择仅提交崩溃日志,这对确认与修复您可能遇到的错误有很大帮助。\n\n所有信息均由我们自己的服务器处理,不会泄露给任何第三方。\n\n\n您可以随时在设置中更改这些选择。", - "hex.builtin.welcome.server_contact.data_collected_table.key": "类型", - "hex.builtin.welcome.server_contact.data_collected_table.value": "值", - "hex.builtin.welcome.server_contact.data_collected_title": "会被共享的数据", - "hex.builtin.welcome.server_contact.data_collected.uuid": "随机 ID", - "hex.builtin.welcome.server_contact.data_collected.version": "ImHex 版本", - "hex.builtin.welcome.server_contact.data_collected.os": "操作系统", - "hex.builtin.welcome.server_contact.crash_logs_only": "仅崩溃日志", + "hex.builtin.oobe.server_contact_text": "您想允许与 ImHex 的服务器通信吗?\n\n\n这允许执行自动更新检查并上传非常有限的使用统计信息,所有这些都在下面列出。\n\n或者,您也可以选择仅提交崩溃日志,这对确认与修复您可能遇到的错误有很大帮助。\n\n所有信息均由我们自己的服务器处理,不会泄露给任何第三方。\n\n\n您可以随时在设置中更改这些选择。", + "hex.builtin.oobe.server_contact.data_collected_table.key": "类型", + "hex.builtin.oobe.server_contact.data_collected_table.value": "值", + "hex.builtin.oobe.server_contact.data_collected_title": "会被共享的数据", + "hex.builtin.oobe.server_contact.data_collected.uuid": "随机 ID", + "hex.builtin.oobe.server_contact.data_collected.version": "ImHex 版本", + "hex.builtin.oobe.server_contact.data_collected.os": "操作系统", + "hex.builtin.oobe.server_contact.crash_logs_only": "仅崩溃日志", "hex.builtin.welcome.customize.settings.desc": "更改 ImHex 的设置", "hex.builtin.welcome.customize.settings.title": "设置", "hex.builtin.welcome.header.customize": "自定义", diff --git a/plugins/builtin/romfs/lang/zh_TW.json b/plugins/builtin/romfs/lang/zh_TW.json index 89a8570ac..821ea5075 100644 --- a/plugins/builtin/romfs/lang/zh_TW.json +++ b/plugins/builtin/romfs/lang/zh_TW.json @@ -797,14 +797,14 @@ "hex.builtin.visualizer.hexadecimal.8bit": "十六進位 (8 位元)", "hex.builtin.visualizer.hexii": "HexII", "hex.builtin.visualizer.rgba8": "RGBA8 顏色", - "hex.builtin.welcome.server_contact_text": "", - "hex.builtin.welcome.server_contact.data_collected_table.key": "類型", - "hex.builtin.welcome.server_contact.data_collected_table.value": "數值", - "hex.builtin.welcome.server_contact.data_collected_title": "將分享的資料", - "hex.builtin.welcome.server_contact.data_collected.uuid": "隨機 ID", - "hex.builtin.welcome.server_contact.data_collected.version": "ImHex 版本", - "hex.builtin.welcome.server_contact.data_collected.os": "作業系統", - "hex.builtin.welcome.server_contact.crash_logs_only": "僅崩潰記錄檔", + "hex.builtin.oobe.server_contact_text": "", + "hex.builtin.oobe.server_contact.data_collected_table.key": "類型", + "hex.builtin.oobe.server_contact.data_collected_table.value": "數值", + "hex.builtin.oobe.server_contact.data_collected_title": "將分享的資料", + "hex.builtin.oobe.server_contact.data_collected.uuid": "隨機 ID", + "hex.builtin.oobe.server_contact.data_collected.version": "ImHex 版本", + "hex.builtin.oobe.server_contact.data_collected.os": "作業系統", + "hex.builtin.oobe.server_contact.crash_logs_only": "僅崩潰記錄檔", "hex.builtin.welcome.customize.settings.desc": "更改 ImHex 的設定", "hex.builtin.welcome.customize.settings.title": "設定", "hex.builtin.welcome.header.customize": "自訂", diff --git a/plugins/builtin/source/content/events.cpp b/plugins/builtin/source/content/events.cpp index f5f0fb4db..ba12d9fc9 100644 --- a/plugins/builtin/source/content/events.cpp +++ b/plugins/builtin/source/content/events.cpp @@ -194,6 +194,14 @@ namespace hex::plugin::builtin { RequestOpenFile::post(path); }); + EventWindowInitialized::subscribe([] { + if (ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.prev_launch_version", "") == "") { + EventFirstLaunch::post(); + } + + ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.prev_launch_version", ImHexApi::System::getImHexVersion()); + }); + fs::setFileBrowserErrorCallback([](const std::string& errMsg){ #if defined(NFD_PORTAL) ui::PopupError::open(hex::format("hex.builtin.popup.error.file_dialog.portal"_lang, errMsg)); diff --git a/plugins/builtin/source/content/out_of_box_experience.cpp b/plugins/builtin/source/content/out_of_box_experience.cpp new file mode 100644 index 000000000..a704051dd --- /dev/null +++ b/plugins/builtin/source/content/out_of_box_experience.cpp @@ -0,0 +1,367 @@ +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +#include +#include +#include + +namespace hex::plugin::builtin { + + namespace { + + ImGuiExt::Texture s_imhexBanner; + ImGuiExt::Texture s_compassTexture; + std::list> s_screenshots; + nlohmann::json s_screenshotDescriptions; + + + std::string s_uuid; + + class Blend { + public: + Blend(float start, float end) : m_time(0), m_start(start), m_end(end) {} + + [[nodiscard]] operator float() { + m_time += ImGui::GetIO().DeltaTime; + + float t = m_time; + t -= m_start; + t /= (m_end - m_start); + t = std::clamp(t, 0.0F, 1.0F); + + float square = t * t; + return square / (2.0F * (square - t) + 1.0F); + } + + private: + float m_time; + float m_start, m_end; + }; + + EventManager::EventList::iterator s_drawEvent; + void drawOutOfBoxExperience() { + static float windowAlpha = 1.0F; + static bool oobeDone = false; + static bool tutorialEnabled = false; + + ImGui::SetNextWindowPos(ImHexApi::System::getMainWindowPosition()); + ImGui::SetNextWindowSize(ImHexApi::System::getMainWindowSize()); + + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, windowAlpha); + ON_SCOPE_EXIT { ImGui::PopStyleVar(); }; + + if (ImGui::Begin("##oobe", nullptr, ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoScrollWithMouse | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize)) { + ImGui::BringWindowToFocusFront(ImGui::GetCurrentWindowRead()); + + static Blend bannerSlideIn(-0.2F, 1.5F); + static Blend bannerFadeIn(-0.2F, 1.5F); + + // Draw banner + ImGui::SetCursorPos(scaled({ 25 * bannerSlideIn, 25 })); + const auto bannerSize = s_imhexBanner.getSize() / (1.5F * (1.0F / ImHexApi::System::getGlobalScale())); + ImGui::Image( + s_imhexBanner, + bannerSize, + { 0, 0 }, { 1, 1 }, + { 1, 1, 1, (bannerFadeIn - 0.5F) * 2.0F } + ); + + static u32 page = 0; + switch (page) { + // Landing page + case 0: { + static Blend textFadeIn(2.0F, 2.5F); + static Blend buttonFadeIn(2.5F, 3.0F); + + // Draw welcome text + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, textFadeIn); + ImGui::SameLine(); + if (ImGui::BeginChild("Text", ImVec2(ImGui::GetContentRegionAvail().x, bannerSize.y))) { + ImGuiExt::TextFormattedCentered("Welcome to ImHex!\n\nA powerful data analysis and visualization suite for Reverse Engineers, Hackers and Security Researchers."); + } + ImGui::EndChild(); + + if (!s_screenshots.empty()) { + const auto imageSize = s_screenshots.front().second.getSize() * ImHexApi::System::getGlobalScale(); + const auto padding = ImGui::GetStyle().CellPadding.x; + const auto stride = imageSize.x + padding * 2; + static bool imageHovered = false; + static std::string clickedImage; + + // Move last screenshot to the front of the list when the last screenshot is out of view + static float position = 0; + if (position >= stride) { + position = 0; + s_screenshots.splice(s_screenshots.begin(), s_screenshots, std::prev(s_screenshots.end()), s_screenshots.end()); + } + + if (!imageHovered && clickedImage.empty()) + position += (ImGui::GetIO().DeltaTime) * 40; + + imageHovered = false; + + auto drawList = ImGui::GetWindowDrawList(); + const auto drawImage = [&](const std::fs::path &fileName, const ImGuiExt::Texture &screenshot) { + auto pos = ImGui::GetCursorScreenPos(); + + // Draw image + ImGui::Image(screenshot, imageSize); + imageHovered = imageHovered || ImGui::IsItemHovered(); + auto currentHovered = ImGui::IsItemHovered(); + + if (ImGui::IsItemClicked()) { + clickedImage = fileName.string(); + ImGui::OpenPopup("FeatureDescription"); + } + + // Draw shadow + auto &style = ImGui::GetStyle(); + float shadowSize = style.WindowShadowSize * (currentHovered ? 3.0F : 1.0F); + ImU32 shadowCol = ImGui::GetColorU32(ImGuiCol_WindowShadow, currentHovered ? 2.0F : 1.0F); + ImVec2 shadowOffset = ImVec2(ImCos(style.WindowShadowOffsetAngle), ImSin(style.WindowShadowOffsetAngle)) * style.WindowShadowOffsetDist; + drawList->AddShadowRect(pos, pos + imageSize, shadowCol, shadowSize, shadowOffset, ImDrawFlags_ShadowCutOutShapeBackground); + + ImGui::SameLine(); + }; + + ImGui::NewLine(); + + // Draw top screenshot row + ImGui::SetCursorPosX(-position); + for (const auto &[fileName, screenshot] : s_screenshots | std::views::take(s_screenshots.size() / 2) | std::views::reverse) { + drawImage(fileName, screenshot); + } + + ImGui::NewLine(); + + // Draw bottom screenshot row + ImGui::SetCursorPosX(-stride + position); + for (const auto &[fileName, screenshot] : s_screenshots | std::views::drop(s_screenshots.size() / 2)) { + drawImage(fileName, screenshot); + } + + ImGui::SetNextWindowPos(ImGui::GetWindowPos() + (ImGui::GetWindowSize() / 2), ImGuiCond_Always, ImVec2(0.5F, 0.5F)); + ImGui::SetNextWindowSize(ImVec2(400_scaled, 0), ImGuiCond_Always); + if (ImGui::BeginPopup("FeatureDescription")) { + const auto &description = s_screenshotDescriptions[clickedImage]; + ImGuiExt::Header(description["title"].get().c_str(), true); + ImGuiExt::TextFormattedWrapped("{}", description["description"].get().c_str()); + ImGui::EndPopup(); + } else { + clickedImage.clear(); + } + + // Continue button + const auto buttonSize = scaled({ 100, 50 }); + ImGui::SetCursorPos(ImHexApi::System::getMainWindowSize() - buttonSize - scaled({ 10, 10 })); + ImGui::PushStyleVar(ImGuiStyleVar_Alpha, buttonFadeIn); + if (ImGuiExt::DimmedButton(hex::format("{} {}", "hex.ui.common.continue"_lang, ICON_VS_ARROW_RIGHT).c_str(), buttonSize)) + page += 1; + ImGui::PopStyleVar(); + } + + + ImGui::PopStyleVar(); + + + break; + } + + // Server contact page + case 1: { + static ImVec2 subWindowSize = { 0, 0 }; + const auto windowSize = ImHexApi::System::getMainWindowSize(); + + // Draw telemetry subwindow + ImGui::SetCursorPos((windowSize - subWindowSize) / 2); + ImGuiExt::BeginSubWindow("hex.builtin.oobe.server_contact"_lang, subWindowSize, ImGuiChildFlags_AutoResizeY); + { + // Draw telemetry information + auto yBegin = ImGui::GetCursorPosY(); + std::string message = "hex.builtin.oobe.server_contact.text"_lang; + ImGuiExt::TextFormattedWrapped("{}", message.c_str()); + ImGui::NewLine(); + + // Draw table containing everything that's being reported + if (ImGui::CollapsingHeader("hex.builtin.oobe.server_contact.data_collected_title"_lang)) { + if (ImGui::BeginTable("hex.builtin.oobe.server_contact.data_collected_table"_lang, 2, + ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_ScrollY | ImGuiTableFlags_NoHostExtendY, + ImVec2(ImGui::GetContentRegionAvail().x, 150_scaled))) { + ImGui::TableSetupColumn("hex.builtin.oobe.server_contact.data_collected_table.key"_lang); + ImGui::TableSetupColumn("hex.builtin.oobe.server_contact.data_collected_table.value"_lang, ImGuiTableColumnFlags_WidthStretch); + ImGui::TableSetupScrollFreeze(0, 1); + + ImGui::TableHeadersRow(); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("hex.builtin.oobe.server_contact.data_collected.uuid"_lang); + ImGui::TableNextColumn(); + ImGui::TextWrapped("%s", s_uuid.c_str()); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("hex.builtin.oobe.server_contact.data_collected.version"_lang); + ImGui::TableNextColumn(); + ImGuiExt::TextFormattedWrapped("{}\n{}@{}\n{}", + ImHexApi::System::getImHexVersion(), + ImHexApi::System::getCommitHash(true), + ImHexApi::System::getCommitBranch(), + ImHexApi::System::isPortableVersion() ? "Portable" : "Installed" + ); + + ImGui::TableNextRow(); + ImGui::TableNextColumn(); + ImGui::TextUnformatted("hex.builtin.oobe.server_contact.data_collected.os"_lang); + ImGui::TableNextColumn(); + ImGuiExt::TextFormattedWrapped("{}\n{}\n{}\n{}", + ImHexApi::System::getOSName(), + ImHexApi::System::getOSVersion(), + ImHexApi::System::getArchitecture(), + ImHexApi::System::getGPUVendor()); + + ImGui::EndTable(); + } + } + + ImGui::NewLine(); + + const auto width = ImGui::GetWindowWidth(); + const auto buttonSize = ImVec2(width / 3 - ImGui::GetStyle().FramePadding.x * 3, 0); + const auto buttonPos = [&](u8 index) { return ImGui::GetStyle().FramePadding.x + (buttonSize.x + ImGui::GetStyle().FramePadding.x * 3) * index; }; + + // Draw allow button + ImGui::SetCursorPosX(buttonPos(0)); + if (ImGui::Button("hex.ui.common.allow"_lang, buttonSize)) { + ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.server_contact", 1); + ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.upload_crash_logs", 1); + page += 1; + } + + ImGui::SameLine(); + + // Draw crash logs only button + ImGui::SetCursorPosX(buttonPos(1)); + if (ImGui::Button("hex.builtin.oobe.server_contact.crash_logs_only"_lang, buttonSize)) { + ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.server_contact", 0); + ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.upload_crash_logs", 1); + page += 1; + } + + ImGui::SameLine(); + + // Draw deny button + ImGui::SetCursorPosX(buttonPos(2)); + if (ImGui::Button("hex.ui.common.deny"_lang, buttonSize)) { + page += 1; + } + + auto yEnd = ImGui::GetCursorPosY(); + subWindowSize = ImGui::GetWindowSize(); + subWindowSize.y = (yEnd - yBegin) + 35_scaled; + } + ImGuiExt::EndSubWindow(); + + break; + } + + // Tutorial page + case 2: { + ImGui::NewLine(); + + ImGui::NewLine(); + ImGui::NewLine(); + ImGui::NewLine(); + + // Draw compass image + const auto imageSize = s_compassTexture.getSize() / (1.5F * (1.0F / ImHexApi::System::getGlobalScale())); + ImGui::SetCursorPos((ImGui::GetWindowSize() / 2 - imageSize / 2) - ImVec2(0, 50_scaled)); + ImGui::Image(s_compassTexture, imageSize); + + // Draw information text about playing the tutorial + ImGui::SetCursorPosX(0); + ImGuiExt::TextFormattedCentered("hex.builtin.oobe.tutorial_question"_lang); + + // Draw no button + const auto buttonSize = scaled({ 100, 50 }); + ImGui::SetCursorPos(ImHexApi::System::getMainWindowSize() - ImVec2(buttonSize.x * 2 + 20, buttonSize.y + 10)); + if (ImGuiExt::DimmedButton("hex.ui.common.no"_lang, buttonSize)) { + oobeDone = true; + } + + // Draw yes button + ImGui::SetCursorPos(ImHexApi::System::getMainWindowSize() - ImVec2(buttonSize.x + 10, buttonSize.y + 10)); + if (ImGuiExt::DimmedButton("hex.ui.common.yes"_lang, buttonSize)) { + tutorialEnabled = true; + oobeDone = true; + } + break; + } + default: + page = 0; + } + } + ImGui::End(); + + // Handle finishing the out of box experience + if (oobeDone) { + static Blend backgroundFadeOut(0.0F, 1.0F); + windowAlpha = 1.0F - backgroundFadeOut; + + if (backgroundFadeOut >= 1.0F) { + if (tutorialEnabled) { + TutorialManager::startTutorial("hex.builtin.tutorial.introduction"); + } + + TaskManager::doLater([] { + ImHexApi::System::setWindowResizable(true); + EventFrameBegin::unsubscribe(s_drawEvent); + }); + } + } + } + + } + + void setupOutOfBoxExperience() { + // Check if there is a telemetry uuid + s_uuid = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.uuid", "").get(); + + if (s_uuid.empty()) { + // Generate a new UUID + s_uuid = wolv::hash::generateUUID(); + + // Save UUID to settings + ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.uuid", s_uuid); + } + + EventFirstLaunch::subscribe([] { + ImHexApi::System::setWindowResizable(false); + + const auto imageTheme = ThemeManager::getImageTheme(); + s_imhexBanner = ImGuiExt::Texture(romfs::get(hex::format("assets/{}/banner.png", imageTheme)).span()); + s_compassTexture = ImGuiExt::Texture(romfs::get("assets/common/compass.png").span()); + s_screenshotDescriptions = nlohmann::json::parse(romfs::get("assets/screenshot_descriptions.json").string()); + + for (const auto &path : romfs::list("assets/screenshots")) { + s_screenshots.emplace_back(path.filename(), ImGuiExt::Texture(romfs::get(path).span(), ImGuiExt::Texture::Filter::Linear)); + } + + s_drawEvent = EventFrameBegin::subscribe(drawOutOfBoxExperience); + }); + } + +} diff --git a/plugins/builtin/source/content/welcome_screen.cpp b/plugins/builtin/source/content/welcome_screen.cpp index 42e68ef5f..6f5621b25 100644 --- a/plugins/builtin/source/content/welcome_screen.cpp +++ b/plugins/builtin/source/content/welcome_screen.cpp @@ -24,13 +24,11 @@ #include -#include #include #include #include #include -#include #include namespace hex::plugin::builtin { @@ -497,29 +495,6 @@ namespace hex::plugin::builtin { } }); - EventWindowInitialized::subscribe([] { - if (ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.prev_launch_version", "") == "") { - ui::PopupQuestion::open("hex.builtin.popup.play_tutorial.desc"_lang, - []{ - TutorialManager::startTutorial("hex.builtin.tutorial.introduction"); - }, - []{ }); - } - - ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.prev_launch_version", ImHexApi::System::getImHexVersion()); - - // Documentation of the value above the setting definition - auto allowServerContact = ContentRegistry::Settings::read("hex.builtin.setting.general", "hex.builtin.setting.general.server_contact", 2); - if (allowServerContact == 2) { - ContentRegistry::Settings::write("hex.builtin.setting.general", "hex.builtin.setting.general.server_contact", 0); - - // Open the telemetry popup but only on desktop versions - #if !defined(OS_WEB) - PopupTelemetryRequest::open(); - #endif - } - }); - // Clear project context if we go back to the welcome screen EventProviderChanged::subscribe([](const hex::prv::Provider *oldProvider, const hex::prv::Provider *newProvider) { hex::unused(oldProvider); diff --git a/plugins/builtin/source/plugin_builtin.cpp b/plugins/builtin/source/plugin_builtin.cpp index ed75e92a4..9c3a2ea97 100644 --- a/plugins/builtin/source/plugin_builtin.cpp +++ b/plugins/builtin/source/plugin_builtin.cpp @@ -48,6 +48,7 @@ namespace hex::plugin::builtin { void loadFonts(); void handleBorderlessWindowMode(); + void setupOutOfBoxExperience(); void extractBundledFiles(); @@ -117,4 +118,5 @@ IMHEX_PLUGIN_SETUP("Built-in", "WerWolv", "Default ImHex functionality") { addGlobalUIItems(); handleBorderlessWindowMode(); + setupOutOfBoxExperience(); } diff --git a/plugins/ui/romfs/lang/en_US.json b/plugins/ui/romfs/lang/en_US.json index 73d5fab6f..9daefb8f3 100644 --- a/plugins/ui/romfs/lang/en_US.json +++ b/plugins/ui/romfs/lang/en_US.json @@ -16,6 +16,7 @@ "hex.ui.common.choose_file": "Choose file", "hex.ui.common.close": "Close", "hex.ui.common.comment": "Comment", + "hex.ui.common.continue": "Continue", "hex.ui.common.count": "Count", "hex.ui.common.decimal": "Decimal", "hex.ui.common.deny": "Deny",