Skip to content

Commit

Permalink
Merge pull request #541 from UE4SS-RE/ImGuiSettingsPersistentWindow
Browse files Browse the repository at this point in the history
Update ImGui ini location; make os window position and size persistent across runs
  • Loading branch information
narknon committed Jun 3, 2024
2 parents edaf6fc + 37b7ccd commit 664c83a
Show file tree
Hide file tree
Showing 6 changed files with 161 additions and 15 deletions.
1 change: 1 addition & 0 deletions UE4SS/include/GUI/GLFW3_OpenGL3.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@ namespace RC::GUI
auto handle_window_resize(int64_t param_1, int64_t param_2) -> void override;
auto on_os_backend_set() -> void override;
auto get_window_size() -> WindowSize override;
auto get_window_position() -> WindowPosition override;
auto exit_requested() -> bool override;
};
} // namespace RC::GUI
43 changes: 39 additions & 4 deletions UE4SS/include/GUI/GUI.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,8 @@
#include <Helpers/String.hpp>
#include <imgui.h>

struct ImGuiSettingsHandler;

namespace RC::GUI
{
class GUITab; // dunno why forward declaration is necessary
Expand All @@ -27,8 +29,14 @@ namespace RC::GUI

struct WindowSize
{
long x;
long y;
int32_t x;
int32_t y;
};

struct WindowPosition
{
int32_t x;
int32_t y;
};

class GfxBackendBase
Expand Down Expand Up @@ -60,6 +68,10 @@ namespace RC::GUI
{
return {};
};
virtual auto get_window_position() -> WindowPosition
{
return {};
};
virtual inline auto exit_requested() -> bool
{
return false;
Expand Down Expand Up @@ -89,12 +101,13 @@ namespace RC::GUI
public:
virtual auto init() -> void = 0;
virtual auto imgui_backend_newframe() -> void = 0;
virtual auto create_window() -> void = 0;
virtual auto create_window(int loc_x = 100, int loc_y = 100, int size_x = 1280, int size_y = 800) -> void = 0;
virtual auto exec_message_loop(bool* exit_requested) -> void = 0;
virtual auto shutdown() -> void = 0;
virtual auto cleanup() -> void = 0;
virtual auto get_window_handle() -> void* = 0;
virtual auto get_window_size() -> WindowSize = 0;
virtual auto get_window_position() -> WindowPosition = 0;
virtual auto on_gfx_backend_set() -> void = 0;
};

Expand All @@ -114,7 +127,7 @@ namespace RC::GUI
inline auto imgui_backend_newframe() -> void override
{
}
inline auto create_window() -> void override
inline auto create_window(int loc_x, int loc_y, int size_x, int size_y) -> void override
{
}
inline auto exec_message_loop([[maybe_unused]] bool* exit_requested) -> void override
Expand All @@ -134,6 +147,10 @@ namespace RC::GUI
{
return {};
}
inline auto get_window_position() -> WindowPosition override
{
return {};
}
inline auto on_gfx_backend_set() -> void override
{
}
Expand Down Expand Up @@ -181,6 +198,14 @@ namespace RC::GUI
public:
using EndOfFrameCallback = std::function<void()>;

struct WindowSettings
{
int pos_x = 100;
int pos_y = 100;
int size_x = 1280;
int size_y = 800;
};

private:
std::unique_ptr<GfxBackendBase> m_gfx_backend{};
std::unique_ptr<OSBackendBase> m_os_backend{};
Expand All @@ -191,6 +216,8 @@ namespace RC::GUI
bool m_exit_requested{};
std::vector<std::shared_ptr<GUITab>> m_tabs;
std::mutex m_tabs_mutex;
std::string m_imgui_ini_file{};
WindowSettings m_backend_window_settings;

public:
bool m_event_thread_busy{};
Expand Down Expand Up @@ -225,6 +252,14 @@ namespace RC::GUI
auto on_update() -> void;
auto main_loop_internal() -> void;

private:
// TODO: Move ImGui data saves to their own object
std::chrono::time_point<std::chrono::steady_clock> m_imgui_last_save = std::chrono::steady_clock::now();
static auto imgui_ue4ss_data_should_save() -> bool;
static auto imgui_ue4ss_data_read_open(ImGuiContext*, ImGuiSettingsHandler*, const char* name) -> void*;
static auto imgui_ue4ss_data_read_line(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line) -> void;
static auto imgui_ue4ss_data_write_all(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) -> void;

public:
static auto execute_at_end_of_frame(EndOfFrameCallback callback) -> void;
};
Expand Down
3 changes: 2 additions & 1 deletion UE4SS/include/GUI/Windows.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -12,12 +12,13 @@ namespace RC::GUI
public:
auto init() -> void override;
auto imgui_backend_newframe() -> void override;
auto create_window() -> void override;
auto create_window(int loc_x, int loc_y, int size_x, int size_y) -> void override;
auto exec_message_loop(bool* exit_requested) -> void override;
auto shutdown() -> void override;
auto cleanup() -> void override;
auto get_window_handle() -> void* override;
auto get_window_size() -> WindowSize override;
auto get_window_position() -> WindowPosition override;
auto on_gfx_backend_set() -> void override;
};
} // namespace RC::GUI
8 changes: 8 additions & 0 deletions UE4SS/src/GUI/GLFW3_OpenGL3.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -113,6 +113,14 @@ namespace RC::GUI
return {w + left + right, h + top + bottom};
}

auto Backend_GLFW3_OpenGL3::get_window_position() -> WindowPosition
{
int left, top, right, bottom;
glfwGetWindowFrameSize(m_window, &left, &top, &right, &bottom);

return {left, top};
}

auto Backend_GLFW3_OpenGL3::exit_requested() -> bool
{
return glfwWindowShouldClose(m_window);
Expand Down
108 changes: 101 additions & 7 deletions UE4SS/src/GUI/GUI.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@
#include "FaSolid900.hpp"
#include <imgui.h>
#include <IconsFontAwesome5.h>
#include <imgui_internal.h>

namespace RC::GUI
{
Expand Down Expand Up @@ -52,7 +53,6 @@ namespace RC::GUI
auto DebuggingGUI::on_update() -> void
{
static bool show_window = true;
static bool is_console_open = true;

if (!is_valid())
{
Expand All @@ -61,6 +61,11 @@ namespace RC::GUI

if (show_window)
{
if (imgui_ue4ss_data_should_save())
{
ImGui::SaveIniSettingsToDisk(m_imgui_ini_file.c_str());
}

ImGui::SetNextWindowPos({0, 0});
auto current_window_size = m_os_backend->is_valid() ? m_os_backend->get_window_size() : m_gfx_backend->get_window_size();
ImGui::SetNextWindowSize({static_cast<float>(current_window_size.x), static_cast<float>(current_window_size.y)});
Expand Down Expand Up @@ -306,7 +311,7 @@ namespace RC::GUI
while (!m_exit_requested && !m_gfx_backend->exit_requested())
{
m_os_backend->exec_message_loop(&m_exit_requested);

if (m_exit_requested)
{
break;
Expand Down Expand Up @@ -365,6 +370,81 @@ namespace RC::GUI
s_end_of_frame_callbacks.emplace_back(callback);
}

auto DebuggingGUI::imgui_ue4ss_data_should_save() -> bool
{
auto& debugging_gui = UE4SSProgram::get_program().get_debugging_ui();

auto now = std::chrono::steady_clock::now();
auto duration = std::chrono::duration_cast<std::chrono::seconds>(now - debugging_gui.m_imgui_last_save).count();
if (duration <= 5)
{
return false;
}

auto& settings = debugging_gui.m_backend_window_settings;

auto const current_window_size = debugging_gui.m_os_backend->is_valid() ? debugging_gui.m_os_backend->get_window_size() : debugging_gui.m_gfx_backend->get_window_size();
if (current_window_size.x != settings.size_x || current_window_size.y != settings.size_y)
{
settings.size_x = current_window_size.x;
settings.size_y = current_window_size.y;
debugging_gui.m_imgui_last_save = now;
return true;
}

auto const current_window_position = debugging_gui.m_os_backend->is_valid() ? debugging_gui.m_os_backend->get_window_position() : debugging_gui.m_gfx_backend->get_window_position();
if (current_window_position.x != settings.pos_x || current_window_position.y != settings.pos_y)
{
settings.pos_x = current_window_position.x;
settings.pos_y = current_window_position.y;
debugging_gui.m_imgui_last_save = now;
return true;
}

return false;
}

auto DebuggingGUI::imgui_ue4ss_data_read_open(ImGuiContext*, ImGuiSettingsHandler*, const char* name) -> void*
{
// UE4SS ImGui Settings
return (void*)name;
}

auto DebuggingGUI::imgui_ue4ss_data_read_line(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line) -> void
{
auto& debugging_gui = UE4SSProgram::get_program().get_debugging_ui();

// Read settings for backend window size/position
WindowSettings& settings = debugging_gui.m_backend_window_settings;
if (std::string((const char*)entry) == "Backend_Window")
{
int x, y;
if (sscanf_s(line, "Pos=%i,%i", &x, &y) == 2) { settings.pos_x = x; settings.pos_y = y; }
else if (sscanf_s(line, "Size=%i,%i", &x, &y) == 2) { settings.size_x = x; settings.size_y = y; }
}

}

auto DebuggingGUI::imgui_ue4ss_data_write_all(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) -> void
{
/*ImGuiContext& g = *ctx;*/
auto& debugging_gui = UE4SSProgram::get_program().get_debugging_ui();

// Write settings for backend window size/position
auto current_window_size = debugging_gui.m_os_backend->is_valid() ? debugging_gui.m_os_backend->get_window_size() : debugging_gui.m_gfx_backend->get_window_size();
auto current_window_position = debugging_gui.m_os_backend->is_valid() ? debugging_gui.m_os_backend->get_window_position() : debugging_gui.m_gfx_backend->get_window_position();

// Write to text buffer
buf->reserve(buf->size() + 15 * 6); // ballpark reserve
const char* backend_window_settings_name = "Backend_Window";
buf->appendf("[%s][%s]\n", handler->TypeName, backend_window_settings_name);
buf->appendf("Pos=%d,%d\n", static_cast<int>(current_window_position.x), static_cast<int>(current_window_position.y));
buf->appendf("Size=%d,%d\n", static_cast<int>(current_window_size.x), static_cast<int>(current_window_size.y));
buf->append("\n");

// Add any additional ImGui UE4SS settings here
}

auto DebuggingGUI::setup(std::stop_token&& stop_token) -> void
{
if (!is_valid())
Expand All @@ -374,14 +454,28 @@ namespace RC::GUI
m_thread_stop_token = stop_token;

m_live_view.initialize();

m_os_backend->create_window();


IMGUI_CHECKVERSION();
ImGui::CreateContext();
ImGuiIO& io = ImGui::GetIO();
(void)io;
io.IniFilename = nullptr;
m_imgui_ini_file = to_string(StringType{UE4SSProgram::get_program().get_working_directory()} + STR("\\imgui.ini"));
io.IniFilename = m_imgui_ini_file.c_str();

// Add .ini handle for UserData type
ImGuiSettingsHandler ini_handler;
ini_handler.TypeName = "UE4SSData";
ini_handler.TypeHash = ImHashStr("UE4SSData");
ini_handler.ReadOpenFn = imgui_ue4ss_data_read_open;
ini_handler.ReadLineFn = imgui_ue4ss_data_read_line;
ini_handler.WriteAllFn = imgui_ue4ss_data_write_all;
ImGui::AddSettingsHandler(&ini_handler);

ImGui::LoadIniSettingsFromDisk(m_imgui_ini_file.c_str());

auto& debugging_gui = UE4SSProgram::get_program().get_debugging_ui();
WindowSettings& settings = debugging_gui.m_backend_window_settings;

m_os_backend->create_window(settings.pos_x, settings.pos_y, settings.size_x, settings.size_y);

gui_setup_style();
io.Fonts->Clear();
Expand Down
13 changes: 10 additions & 3 deletions UE4SS/src/GUI/Windows.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ namespace RC::GUI
ImGui_ImplWin32_NewFrame();
}

auto Backend_Windows::create_window() -> void
auto Backend_Windows::create_window(int loc_x, int loc_y, int size_x, int size_y) -> void
{
StringType title_bar_text{STR("UE4SS Debugging Tools")};
if (dynamic_cast<Backend_DX11*>(m_gfx_backend))
Expand All @@ -58,7 +58,7 @@ namespace RC::GUI
s_wc.lpszClassName = title_bar_text.c_str();
s_wc.hIconSm = NULL;
::RegisterClassEx(&s_wc);
s_hwnd = ::CreateWindow(s_wc.lpszClassName, title_bar_text.c_str(), WS_OVERLAPPEDWINDOW, 100, 100, 1280, 800, NULL, NULL, s_wc.hInstance, NULL);
s_hwnd = ::CreateWindow(s_wc.lpszClassName, title_bar_text.c_str(), WS_OVERLAPPEDWINDOW, loc_x, loc_y, size_x, size_y, NULL, NULL, s_wc.hInstance, NULL);

if (!m_gfx_backend->create_device())
{
Expand Down Expand Up @@ -105,7 +105,14 @@ namespace RC::GUI
{
RECT current_window_rect{};
GetWindowRect(s_hwnd, &current_window_rect);
return {current_window_rect.right - current_window_rect.left, current_window_rect.bottom - current_window_rect.top};
return {static_cast<int32_t>(current_window_rect.right - current_window_rect.left), static_cast<int32_t>(current_window_rect.bottom - current_window_rect.top)};
}

auto Backend_Windows::get_window_position() -> WindowPosition
{
RECT current_window_rect{};
GetWindowRect(s_hwnd, &current_window_rect);
return {static_cast<int32_t>(current_window_rect.left), static_cast<int32_t>(current_window_rect.top)};
}

auto Backend_Windows::on_gfx_backend_set() -> void
Expand Down

0 comments on commit 664c83a

Please sign in to comment.