diff --git a/AsuroTool/ApplicationData.h b/AsuroTool/ApplicationData.h index 7c77f4c..83db3ef 100644 --- a/AsuroTool/ApplicationData.h +++ b/AsuroTool/ApplicationData.h @@ -49,4 +49,7 @@ class ApplicationData { public: ApplicationSettings settings = {}; std::shared_ptr audioData = std::make_shared(); + + ApplicationData(const ApplicationData&) = delete; + ApplicationData& operator=(const ApplicationData&) = delete; }; diff --git a/AsuroTool/AsuroTool.cpp b/AsuroTool/AsuroTool.cpp index 359d048..e6d8cb4 100644 --- a/AsuroTool/AsuroTool.cpp +++ b/AsuroTool/AsuroTool.cpp @@ -10,6 +10,7 @@ #include +#include #include #include #include @@ -28,12 +29,19 @@ UINT const WMAPP_HIDEFLYOUT = WM_APP + 2; DrawData* hackyDrawData; ApplicationData* hackyAppData; +bool justDocked = false; +bool isHidden = false; int main() { ApplicationData applicationData{}; + ImGuiCallbacks callbacks{}; - startImgui(applicationData, init, draw, cleanup, "Asuro's Tool", 600, 400); + callbacks.initFunc = std::bind(init, std::placeholders::_1, std::ref(applicationData)); + callbacks.drawFunc = std::bind(draw, std::placeholders::_1, std::ref(applicationData)); + callbacks.cleanupFunc = std::bind(cleanup, std::placeholders::_1, std::ref(applicationData)); + + startImgui(callbacks, "Asuro's Tool", 600, 400); } LRESULT CALLBACK trayIconEventHandler(int code, WPARAM wParam, LPARAM lParam) @@ -74,20 +82,6 @@ void init(DrawData& drawData, ApplicationData& appData) icons_config.PixelSnapH = true; io.Fonts->AddFontFromFileTTF("remixicon.ttf", 14.0f, &icons_config, icons_ranges); - // Set up audio device api - HRESULT audioResult; - audioResult = CoInitializeEx(NULL, COINIT_MULTITHREADED); - isError(audioResult, "Failed to initialize COM: "); - - audioResult = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&appData.audioData->deviceEnumerator)); - isError(audioResult, "Failed to set up audio device enumerator: "); - - appData.audioData->audioNotificationListener = new AudioNotificationListener(appData.audioData); - audioResult = appData.audioData->deviceEnumerator->RegisterEndpointNotificationCallback(appData.audioData->audioNotificationListener); - isError(audioResult, "Failed to register audio notification listener: "); - - reloadDeviceLists(*appData.audioData); - // Set window icon HINSTANCE instance = GetModuleHandle(NULL); LPWSTR iconId = MAKEINTRESOURCE(IDI_ICON1); @@ -123,15 +117,61 @@ void init(DrawData& drawData, ApplicationData& appData) // Set window minimize behavior glfwSetWindowIconifyCallback(drawData.window, [](GLFWwindow* window, int isIconified) { - if (isIconified == GLFW_TRUE && hackyAppData->settings.minimizeToTray) + if (isIconified && hackyAppData->settings.minimizeToTray) { glfwHideWindow(window); } + isHidden = isIconified; }); + + glfwSetWindowFocusCallback(drawData.window, [](GLFWwindow* window, int isFocused) { + if (!isFocused && hackyAppData->settings.docked && !justDocked) + { + glfwIconifyWindow(window); + } + }); + + // Load settings + ImGuiSettingsHandler ini_handler; + ini_handler.TypeName = "ApplicationSettings"; + ini_handler.TypeHash = ImHashStr("ApplicationSettings"); + ini_handler.ReadOpenFn = settingsReadOpen; + ini_handler.ReadLineFn = settingsReadLine; + ini_handler.WriteAllFn = settingsWriteAll; + GImGui->SettingsHandlers.push_back(ini_handler); + ImGui::LoadIniSettingsFromDisk("imgui.ini"); + updateSettings(drawData, appData); + + // Set up audio device api + HRESULT audioResult; + audioResult = CoInitializeEx(NULL, COINIT_MULTITHREADED); + isError(audioResult, "Failed to initialize COM: "); + + audioResult = CoCreateInstance(__uuidof(MMDeviceEnumerator), NULL, CLSCTX_INPROC_SERVER, IID_PPV_ARGS(&appData.audioData->deviceEnumerator)); + isError(audioResult, "Failed to set up audio device enumerator: "); + + appData.audioData->audioNotificationListener = new AudioNotificationListener(appData.audioData); + audioResult = appData.audioData->deviceEnumerator->RegisterEndpointNotificationCallback(appData.audioData->audioNotificationListener); + isError(audioResult, "Failed to register audio notification listener: "); + + reloadDeviceLists(*appData.audioData); } void draw(DrawData& drawData, ApplicationData& appData) { + justDocked = false; + + // sad :( + hackyDrawData = &drawData; + hackyAppData = &appData; + + // Actual Drawing + if (isHidden) + { + glfwWaitEvents(); + return; + } + float customYCursor = 0; ImVec2 viewportSize = ImGui::GetMainViewport()->Size; @@ -176,6 +216,7 @@ void cleanup(DrawData& drawData, ApplicationData& appData) ImVec2 menuBar(DrawData& drawData, ApplicationData& appData) { ImVec2 size{}; + bool closeMenu = false; if (ImGui::BeginMainMenuBar()) { @@ -185,7 +226,8 @@ ImVec2 menuBar(DrawData& drawData, ApplicationData& appData) ImGui::Checkbox("Docked", &appData.settings.docked); if (appData.settings.docked != prevDocked) { - glfwSetWindowAttrib(drawData.window, GLFW_DECORATED, !appData.settings.docked); + closeMenu = true; + updateDocked(drawData, appData); } ImGui::Checkbox("Show Disabled Devices", &appData.settings.showDisabledDevices); @@ -223,6 +265,11 @@ ImVec2 menuBar(DrawData& drawData, ApplicationData& appData) ImGui::EndMainMenuBar(); } + if (closeMenu) + { + ImGui::SetWindowFocus(); + } + return size; } @@ -359,3 +406,43 @@ void drawCircle(float radius, ImU32 color) ImVec2 windowPos = ImGui::GetWindowPos(); drawList->AddCircleFilled(ImVec2(cursorPos.x + windowPos.x, cursorPos.y + windowPos.y + ImGui::GetTextLineHeight() / 2.), radius, color); } + +void updateSettings(DrawData& drawData, ApplicationData& appData) +{ + updateDocked(drawData, appData); +} + +void updateDocked(DrawData& drawData, ApplicationData& appData) +{ + justDocked = true; + + glfwSetWindowAttrib(drawData.window, GLFW_DECORATED, !appData.settings.docked); + ShowWindow(drawData.window_handle, SW_HIDE); + SetWindowLongPtr(drawData.window_handle, GWL_EXSTYLE, appData.settings.docked ? WS_EX_TOOLWINDOW : 0); + ShowWindow(drawData.window_handle, SW_SHOW); +} + +void* settingsReadOpen(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name) +{ + ApplicationSettings* settings = &hackyAppData->settings; + *settings = ApplicationSettings(); + return (void*)settings; +} + +void settingsReadLine(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line) +{ + ApplicationSettings* settings = (ApplicationSettings*)entry; + + int docked; + if (sscanf_s(line, "docked=%i", &docked)) + { + settings->docked = (bool)docked; + } +} + +void settingsWriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* outBuf) +{ + outBuf->appendf("[%s][%s]\n", "ApplicationSettings", "ApplicationSettings"); + outBuf->appendf("docked=%i\n", (int)hackyAppData->settings.docked); + outBuf->append("\n"); +} diff --git a/AsuroTool/AsuroTool.h b/AsuroTool/AsuroTool.h index 2a589ca..2351bb8 100644 --- a/AsuroTool/AsuroTool.h +++ b/AsuroTool/AsuroTool.h @@ -1,6 +1,7 @@ #pragma once #include +#include #include "ImguiBase.h" #include "ApplicationData.h" @@ -8,6 +9,14 @@ void init(DrawData& drawData, ApplicationData& customData); void draw(DrawData& drawData, ApplicationData& customData); void cleanup(DrawData& drawData, ApplicationData& appData); + ImVec2 menuBar(DrawData& drawData, ApplicationData& appData); ImVec2 audioDeviceWindow(ApplicationData& appData, std::vector& deviceList, const char* title); void drawCircle(float radius, ImU32 color); + +void updateSettings(DrawData& drawData, ApplicationData& appData); +void updateDocked(DrawData& drawData, ApplicationData& appData); + +void* settingsReadOpen(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name); +void settingsReadLine(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); +void settingsWriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* outBuf); diff --git a/AsuroTool/AsuroTool.vcxproj b/AsuroTool/AsuroTool.vcxproj index 77f6d6f..1b5b0da 100644 --- a/AsuroTool/AsuroTool.vcxproj +++ b/AsuroTool/AsuroTool.vcxproj @@ -92,6 +92,7 @@ true WIN32;_DEBUG;_CONSOLE;%(PreprocessorDefinitions) true + 4305; 4244 Console @@ -106,6 +107,7 @@ true WIN32;NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true + 4305; 4244 Console @@ -120,6 +122,7 @@ true _DEBUG;_CONSOLE;%(PreprocessorDefinitions) true + 4305; 4244 Console @@ -134,6 +137,7 @@ true NDEBUG;_CONSOLE;%(PreprocessorDefinitions) true + 4305; 4244 Console @@ -154,6 +158,7 @@ + diff --git a/AsuroTool/AsuroTool.vcxproj.filters b/AsuroTool/AsuroTool.vcxproj.filters index 311795c..be1df70 100644 --- a/AsuroTool/AsuroTool.vcxproj.filters +++ b/AsuroTool/AsuroTool.vcxproj.filters @@ -59,6 +59,9 @@ Header Files\Audio + + Header Files + diff --git a/ImguiBase/ImguiBase.h b/ImguiBase/ImguiBase.h index 774d697..903de6a 100644 --- a/ImguiBase/ImguiBase.h +++ b/ImguiBase/ImguiBase.h @@ -5,6 +5,7 @@ #include "imgui_impl_glfw.h" #include "imgui_impl_vulkan.h" +#include #include #define GLFW_INCLUDE_NONE #define GLFW_INCLUDE_VULKAN @@ -21,6 +22,13 @@ public: ImVec2 window_size = {}; }; +class ImGuiCallbacks { +public: + std::function initFunc = nullptr; + std::function drawFunc = nullptr; + std::function cleanupFunc = nullptr; +}; + ImVec2 getWindowSize(GLFWwindow* window); static VkAllocationCallbacks* g_Allocator = NULL; @@ -344,8 +352,7 @@ static void glfw_error_callback(int error, const char* description) fprintf(stderr, "Glfw Error %d: %s\n", error, description); } -template -int startImgui(D& customState, void (*const initFunc)(DrawData&, D&), void (*const drawFunc)(DrawData&, D&), void (*const cleanupFunc)(DrawData&, D&), const char* title, int windowWidth, int windowHeight) +int startImgui(ImGuiCallbacks& callbacks, const char* title, int windowWidth, int windowHeight) { // Setup GLFW window glfwSetErrorCallback(glfw_error_callback); @@ -379,6 +386,7 @@ int startImgui(D& customState, void (*const initFunc)(DrawData&, D&), void (*con // Setup Dear ImGui context IMGUI_CHECKVERSION(); ImGui::CreateContext(); + ImGuiIO& io = ImGui::GetIO(); (void)io; //io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls //io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls @@ -426,7 +434,10 @@ int startImgui(D& customState, void (*const initFunc)(DrawData&, D&), void (*con drawData.window_handle = glfwGetWin32Window(window); drawData.window_size = getWindowSize(window); - initFunc(drawData, customState); + if (callbacks.initFunc) + { + callbacks.initFunc(drawData); + } // Upload Fonts { @@ -490,7 +501,10 @@ int startImgui(D& customState, void (*const initFunc)(DrawData&, D&), void (*con ImVec2 prevWindowSize = getWindowSize(window); drawData.window_size = prevWindowSize; - drawFunc(drawData, customState); + if (callbacks.drawFunc) + { + callbacks.drawFunc(drawData); + } if (drawData.window_size.x != prevWindowSize.x || drawData.window_size.y != prevWindowSize.y) { @@ -513,7 +527,10 @@ int startImgui(D& customState, void (*const initFunc)(DrawData&, D&), void (*con } // Cleanup - cleanupFunc(drawData, customState); + if (callbacks.cleanupFunc) + { + callbacks.cleanupFunc(drawData); + } err = vkDeviceWaitIdle(g_Device); check_vk_result(err); ImGui_ImplVulkan_Shutdown(); diff --git a/ImguiNodes/ImguiNodes.cpp b/ImguiNodes/ImguiNodes.cpp index d5025f1..ef8cd29 100644 --- a/ImguiNodes/ImguiNodes.cpp +++ b/ImguiNodes/ImguiNodes.cpp @@ -11,8 +11,11 @@ int main() { ApplicationData applicationData{}; + ImGuiCallbacks callbacks{}; - startImgui(applicationData, init, draw, nullptr, "Node Test", 1280, 720); + callbacks.initFunc = std::bind(init, std::placeholders::_1, applicationData); + callbacks.drawFunc = std::bind(draw, std::placeholders::_1, applicationData); + startImgui(callbacks, "Node Test", 1280, 720); } ///