From a419ca81dfa15e708b58862be5cd3a0c5880974c Mon Sep 17 00:00:00 2001 From: Nicholas Sharp Date: Wed, 1 Dec 2021 10:22:31 -0500 Subject: [PATCH] refactor to support deeper ImGui customization (#145) * refactor for custom GUIs * move gui helpers to public namespace * missing includes Co-authored-by: xarthur --- include/polyscope/imgui_config.h | 15 +++++ include/polyscope/options.h | 41 ++++++++---- include/polyscope/polyscope.h | 9 +++ src/CMakeLists.txt | 2 + src/imgui_config.cpp | 103 +++++++++++++++++++++++++++++++ src/options.cpp | 11 +++- src/polyscope.cpp | 51 ++++++++------- src/render/engine.cpp | 88 ++------------------------ 8 files changed, 199 insertions(+), 121 deletions(-) create mode 100644 include/polyscope/imgui_config.h create mode 100644 src/imgui_config.cpp diff --git a/include/polyscope/imgui_config.h b/include/polyscope/imgui_config.h new file mode 100644 index 00000000..9ce34a26 --- /dev/null +++ b/include/polyscope/imgui_config.h @@ -0,0 +1,15 @@ +// Copyright 2017-2019, Nicholas Sharp and the Polyscope contributors. http://polyscope.run. +#pragma once + +#include + +#include "imgui.h" + + +namespace polyscope { + +// Default implementations of callbacks to set ImGui style / fonts +void configureImGuiStyle(); +std::tuple prepareImGuiFonts(); + +} // namespace polyscope diff --git a/include/polyscope/options.h b/include/polyscope/options.h index ea17ab93..f34f4d80 100644 --- a/include/polyscope/options.h +++ b/include/polyscope/options.h @@ -1,15 +1,18 @@ // Copyright 2017-2019, Nicholas Sharp and the Polyscope contributors. http://polyscope.run. #pragma once +#include +#include +#include + +#include "imgui.h" + #include "polyscope/scaled_value.h" #include "polyscope/types.h" -#include namespace polyscope { -namespace options { - -// A general name to use when referring to the program in window headings. +namespace options { // A general name to use when referring to the program in window headings. extern std::string programName; // How much should polyscope print to std::out? @@ -43,14 +46,6 @@ extern bool autoscaleStructures; // bounding box and length scale manually. (default: true) extern bool automaticallyComputeSceneExtents; -// If false, Polyscope will not create any ImGui UIs at all, but will still set up ImGui and invoke its render steps -// each frame. The allows advanced users to create their own UIs totally from scratch and circumvent the standard -// Polyscope UIs. (default: true) -extern bool buildGui; - -// Should the user call back start out with an imgui window context open (default: true) -extern bool openImGuiWindowForUserCallback; - // If true, the user callback will be invoked for nested calls to polyscope::show(), otherwise not (default: false) extern bool invokeUserCallbackForNestedShow; @@ -80,6 +75,28 @@ extern int ssaaFactor; extern TransparencyMode transparencyMode; extern int transparencyRenderPasses; +// === Advanced ImGui configuration + +// If false, Polyscope will not create any ImGui UIs at all, but will still set up ImGui and invoke its render steps +// each frame. The allows advanced users to create their own UIs totally from scratch and circumvent the standard +// Polyscope UIs. (default: true) +extern bool buildGui; + +// Should the user call back start out with an imgui window context open (default: true) +extern bool openImGuiWindowForUserCallback; + +// A callback function which will be invoked when an ImGui context is created (which may happen several times as +// Polyscope runs). By default, this is set to invoke `configureImGuiStyle()` from Polyscope's imgui_config.cpp, but you +// may assign your own function to create custom styles. If this callback is null, the default ImGui style will be used. +extern std::function configureImGuiStyleCallback; + +// A callback function which will be invoked exactly once during initialization to construct a font atlas for ImGui to +// use. The callback should return a tuple of three pointers: a newly created global shared font atlas, a regular font, +// and a mono font. By default, this is set to invoke prepareImGuiFonts() from Polyscope's imgui_config.cpp, but you may +// assign your own function to create custom styles. If this callback is null, default fonts will be used. +extern std::function()> prepareImGuiFontsCallback; + + // === Debug options // Enables optional error checks in the rendering system diff --git a/include/polyscope/polyscope.h b/include/polyscope/polyscope.h index a75b3e31..5be0a2fa 100644 --- a/include/polyscope/polyscope.h +++ b/include/polyscope/polyscope.h @@ -113,6 +113,15 @@ bool redrawRequested(); void pushContext(std::function callbackFunction, bool drawDefaultUI = true); void popContext(); +// These helpers are called internally by Polyscope to render and build the UI. +// Normally, applications should not need to call them, but in advanced settings when making custom UIs, they may be +// useful to manually build pieces of the interface. +void buildPolyscopeGui(); +void buildStructureGui(); +void buildPickGui(); +void buildUserGuiAndInvokeCallback(); + + // === Utility // Execute one iteration of the main loop diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt index d1575089..ed098b89 100644 --- a/src/CMakeLists.txt +++ b/src/CMakeLists.txt @@ -178,6 +178,7 @@ SET(SRCS volume_mesh_vector_quantity.cpp # Rendering utilities + imgui_config.cpp vector_artist.cpp trace_vector_field.cpp ribbon_artist.cpp @@ -216,6 +217,7 @@ SET(HEADERS ${INCLUDE_ROOT}/file_helpers.h ${INCLUDE_ROOT}/histogram.h ${INCLUDE_ROOT}/image_scalar_artist.h + ${INCLUDE_ROOT}/imgui_config.h ${INCLUDE_ROOT}/messages.h ${INCLUDE_ROOT}/options.h ${INCLUDE_ROOT}/persistent_value.h diff --git a/src/imgui_config.cpp b/src/imgui_config.cpp new file mode 100644 index 00000000..4526b890 --- /dev/null +++ b/src/imgui_config.cpp @@ -0,0 +1,103 @@ +// Copyright 2017-2019, Nicholas Sharp and the Polyscope contributors. http://polyscope.run. +#include "polyscope/imgui_config.h" + +namespace polyscope { + + +// Forward declare compressed binary font functions +namespace render { +unsigned int getCousineRegularCompressedSize(); +const unsigned int* getCousineRegularCompressedData(); +unsigned int getLatoRegularCompressedSize(); +const unsigned int* getLatoRegularCompressedData(); +} // namespace render + +void configureImGuiStyle() { + + // Style + ImGuiStyle* style = &ImGui::GetStyle(); + style->WindowRounding = 1; + style->FrameRounding = 1; + style->FramePadding.y = 4; + style->ScrollbarRounding = 1; + style->ScrollbarSize = 20; + + + // Colors + ImVec4* colors = style->Colors; + colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); + colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); + colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.70f); + colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_PopupBg] = ImVec4(0.11f, 0.11f, 0.14f, 0.92f); + colors[ImGuiCol_Border] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f); + colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); + colors[ImGuiCol_FrameBg] = ImVec4(0.63f, 0.63f, 0.63f, 0.39f); + colors[ImGuiCol_FrameBgHovered] = ImVec4(0.47f, 0.69f, 0.59f, 0.40f); + colors[ImGuiCol_FrameBgActive] = ImVec4(0.41f, 0.64f, 0.53f, 0.69f); + colors[ImGuiCol_TitleBg] = ImVec4(0.27f, 0.54f, 0.42f, 0.83f); + colors[ImGuiCol_TitleBgActive] = ImVec4(0.32f, 0.63f, 0.49f, 0.87f); + colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.27f, 0.54f, 0.42f, 0.83f); + colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.55f, 0.48f, 0.80f); + colors[ImGuiCol_ScrollbarBg] = ImVec4(0.63f, 0.63f, 0.63f, 0.39f); + colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.00f, 0.00f, 0.00f, 0.30f); + colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.80f, 0.62f, 0.40f); + colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.39f, 0.80f, 0.61f, 0.60f); + colors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f); + colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f); + colors[ImGuiCol_SliderGrabActive] = ImVec4(0.39f, 0.80f, 0.61f, 0.60f); + colors[ImGuiCol_Button] = ImVec4(0.35f, 0.61f, 0.49f, 0.62f); + colors[ImGuiCol_ButtonHovered] = ImVec4(0.40f, 0.71f, 0.57f, 0.79f); + colors[ImGuiCol_ButtonActive] = ImVec4(0.46f, 0.80f, 0.64f, 1.00f); + colors[ImGuiCol_Header] = ImVec4(0.40f, 0.90f, 0.67f, 0.45f); + colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.90f, 0.69f, 0.80f); + colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.87f, 0.71f, 0.80f); + colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); + colors[ImGuiCol_SeparatorHovered] = ImVec4(0.60f, 0.70f, 0.66f, 1.00f); + colors[ImGuiCol_SeparatorActive] = ImVec4(0.70f, 0.90f, 0.81f, 1.00f); + colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.16f); + colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 1.00f, 0.90f, 0.60f); + colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 1.00f, 0.90f, 0.90f); + colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); + colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); + colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); + colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f); + colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); + colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); + colors[ImGuiCol_Tab] = ImVec4(0.27f, 0.54f, 0.42f, 0.83f); + colors[ImGuiCol_TabHovered] = ImVec4(0.34f, 0.68f, 0.53f, 0.83f); + colors[ImGuiCol_TabActive] = ImVec4(0.38f, 0.76f, 0.58f, 0.83f); +} + + +std::tuple prepareImGuiFonts() { + + ImGuiIO& io = ImGui::GetIO(); + + // outputs + ImFontAtlas* globalFontAtlas; + ImFont* regularFont; + ImFont* monoFont; + + { // add regular font + ImFontConfig config; + regularFont = io.Fonts->AddFontFromMemoryCompressedTTF(render::getLatoRegularCompressedData(), + render::getLatoRegularCompressedSize(), 18.0f, &config); + } + + { // add mono font + ImFontConfig config; + monoFont = io.Fonts->AddFontFromMemoryCompressedTTF(render::getCousineRegularCompressedData(), + render::getCousineRegularCompressedSize(), 16.0f, &config); + } + + // io.Fonts->AddFontFromFileTTF("test-font-name.ttf", 16); + + io.Fonts->Build(); + globalFontAtlas = io.Fonts; + + return std::tuple{globalFontAtlas, regularFont, monoFont}; +} + +} // namespace polyscope diff --git a/src/options.cpp b/src/options.cpp index 211cb584..a1225e76 100644 --- a/src/options.cpp +++ b/src/options.cpp @@ -1,5 +1,6 @@ // Copyright 2017-2019, Nicholas Sharp and the Polyscope contributors. http://polyscope.run. #include "polyscope/options.h" +#include "polyscope/imgui_config.h" namespace polyscope { namespace options { @@ -16,8 +17,6 @@ bool alwaysRedraw = false; bool autocenterStructures = false; bool autoscaleStructures = false; bool automaticallyComputeSceneExtents = true; -bool buildGui = true; -bool openImGuiWindowForUserCallback = true; bool invokeUserCallbackForNestedShow = false; bool giveFocusOnShow = false; @@ -41,6 +40,14 @@ int ssaaFactor = 1; TransparencyMode transparencyMode = TransparencyMode::None; int transparencyRenderPasses = 8; +// === Advanced ImGui configuration + +bool buildGui = true; +bool openImGuiWindowForUserCallback = true; +std::function configureImGuiStyleCallback = configureImGuiStyle; +std::function()> prepareImGuiFontsCallback = prepareImGuiFonts; + + // enabled by default in debug mode #ifndef NDEBUG bool enableRenderErrorChecks = false; diff --git a/src/polyscope.cpp b/src/polyscope.cpp index c214e0ab..cdeee586 100644 --- a/src/polyscope.cpp +++ b/src/polyscope.cpp @@ -139,7 +139,10 @@ void pushContext(std::function callbackFunction, bool drawDefaultUI) { ImGuiIO& oldIO = ImGui::GetIO(); // used to copy below, see note ImGui::SetCurrentContext(newContext); - render::engine->setImGuiStyle(); + if (options::configureImGuiStyleCallback) { + options::configureImGuiStyleCallback(); + } + ImGui::GetIO() = oldIO; // Copy all of the old IO values to new. With ImGUI 1.76 (and some previous versions), this // was necessary to fix a bug where keys like delete, etc would break in subcontexts. The // problem was that the key mappings (e.g. GLFW_KEY_BACKSPACE --> ImGuiKey_Backspace) need to @@ -415,6 +418,10 @@ void renderSceneToScreen() { } } +auto lastMainLoopIterTime = std::chrono::steady_clock::now(); + +} // namespace + void buildPolyscopeGui() { // Create window @@ -555,6 +562,25 @@ void buildStructureGui() { ImGui::End(); } +void buildPickGui() { + if (pick::haveSelection()) { + + ImGui::SetNextWindowPos(ImVec2(view::windowWidth - (rightWindowsWidth + imguiStackMargin), + 2 * imguiStackMargin + lastWindowHeightUser)); + ImGui::SetNextWindowSize(ImVec2(rightWindowsWidth, 0.)); + + ImGui::Begin("Selection", nullptr); + std::pair selection = pick::getSelection(); + + ImGui::TextUnformatted((selection.first->typeName() + ": " + selection.first->name).c_str()); + ImGui::Separator(); + selection.first->buildPickUI(selection.second); + + rightWindowsWidth = ImGui::GetWindowWidth(); + ImGui::End(); + } +} + void buildUserGuiAndInvokeCallback() { if (!options::invokeUserCallbackForNestedShow && contextStack.size() > 2) { @@ -587,29 +613,6 @@ void buildUserGuiAndInvokeCallback() { } } -void buildPickGui() { - if (pick::haveSelection()) { - - ImGui::SetNextWindowPos(ImVec2(view::windowWidth - (rightWindowsWidth + imguiStackMargin), - 2 * imguiStackMargin + lastWindowHeightUser)); - ImGui::SetNextWindowSize(ImVec2(rightWindowsWidth, 0.)); - - ImGui::Begin("Selection", nullptr); - std::pair selection = pick::getSelection(); - - ImGui::TextUnformatted((selection.first->typeName() + ": " + selection.first->name).c_str()); - ImGui::Separator(); - selection.first->buildPickUI(selection.second); - - rightWindowsWidth = ImGui::GetWindowWidth(); - ImGui::End(); - } -} - -auto lastMainLoopIterTime = std::chrono::steady_clock::now(); - -} // namespace - void draw(bool withUI, bool withContextCallback) { processLazyProperties(); diff --git a/src/render/engine.cpp b/src/render/engine.cpp index 7b4edad8..a0a5125d 100644 --- a/src/render/engine.cpp +++ b/src/render/engine.cpp @@ -913,36 +913,16 @@ const ValueColorMap& Engine::getColorMap(const std::string& name) { } -// Forward declare compressed binary font functions -unsigned int getCousineRegularCompressedSize(); -const unsigned int* getCousineRegularCompressedData(); -unsigned int getLatoRegularCompressedSize(); -const unsigned int* getLatoRegularCompressedData(); - - void Engine::configureImGui() { - ImGuiIO& io = ImGui::GetIO(); - - { // add regular font - ImFontConfig config; - regularFont = io.Fonts->AddFontFromMemoryCompressedTTF(getLatoRegularCompressedData(), - getLatoRegularCompressedSize(), 18.0f, &config); - } - - { // add mono font - ImFontConfig config; - monoFont = io.Fonts->AddFontFromMemoryCompressedTTF(getCousineRegularCompressedData(), - getCousineRegularCompressedSize(), 16.0f, &config); + if (options::prepareImGuiFontsCallback) { + std::tie(globalFontAtlas, regularFont, monoFont) = options::prepareImGuiFontsCallback(); } - // io.Fonts->AddFontFromFileTTF("test-font-name.ttf", 16); - io.Fonts->Build(); - globalFontAtlas = io.Fonts; - - - setImGuiStyle(); + if (options::configureImGuiStyleCallback) { + options::configureImGuiStyleCallback(); + } } void Engine::loadDefaultColorMap(std::string name) { @@ -1006,64 +986,6 @@ void Engine::showTextureInImGuiWindow(std::string windowName, TextureBuffer* buf ImGui::End(); } -void Engine::setImGuiStyle() { - - // Style - ImGuiStyle* style = &ImGui::GetStyle(); - style->WindowRounding = 1; - style->FrameRounding = 1; - style->FramePadding.y = 4; - style->ScrollbarRounding = 1; - style->ScrollbarSize = 20; - - - // Colors - ImVec4* colors = style->Colors; - colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f); - colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f); - colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.70f); - colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - colors[ImGuiCol_PopupBg] = ImVec4(0.11f, 0.11f, 0.14f, 0.92f); - colors[ImGuiCol_Border] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f); - colors[ImGuiCol_BorderShadow] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f); - colors[ImGuiCol_FrameBg] = ImVec4(0.63f, 0.63f, 0.63f, 0.39f); - colors[ImGuiCol_FrameBgHovered] = ImVec4(0.47f, 0.69f, 0.59f, 0.40f); - colors[ImGuiCol_FrameBgActive] = ImVec4(0.41f, 0.64f, 0.53f, 0.69f); - colors[ImGuiCol_TitleBg] = ImVec4(0.27f, 0.54f, 0.42f, 0.83f); - colors[ImGuiCol_TitleBgActive] = ImVec4(0.32f, 0.63f, 0.49f, 0.87f); - colors[ImGuiCol_TitleBgCollapsed] = ImVec4(0.27f, 0.54f, 0.42f, 0.83f); - colors[ImGuiCol_MenuBarBg] = ImVec4(0.40f, 0.55f, 0.48f, 0.80f); - colors[ImGuiCol_ScrollbarBg] = ImVec4(0.63f, 0.63f, 0.63f, 0.39f); - colors[ImGuiCol_ScrollbarGrab] = ImVec4(0.00f, 0.00f, 0.00f, 0.30f); - colors[ImGuiCol_ScrollbarGrabHovered] = ImVec4(0.40f, 0.80f, 0.62f, 0.40f); - colors[ImGuiCol_ScrollbarGrabActive] = ImVec4(0.39f, 0.80f, 0.61f, 0.60f); - colors[ImGuiCol_CheckMark] = ImVec4(0.90f, 0.90f, 0.90f, 0.50f); - colors[ImGuiCol_SliderGrab] = ImVec4(1.00f, 1.00f, 1.00f, 0.30f); - colors[ImGuiCol_SliderGrabActive] = ImVec4(0.39f, 0.80f, 0.61f, 0.60f); - colors[ImGuiCol_Button] = ImVec4(0.35f, 0.61f, 0.49f, 0.62f); - colors[ImGuiCol_ButtonHovered] = ImVec4(0.40f, 0.71f, 0.57f, 0.79f); - colors[ImGuiCol_ButtonActive] = ImVec4(0.46f, 0.80f, 0.64f, 1.00f); - colors[ImGuiCol_Header] = ImVec4(0.40f, 0.90f, 0.67f, 0.45f); - colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.90f, 0.69f, 0.80f); - colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.87f, 0.71f, 0.80f); - colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f); - colors[ImGuiCol_SeparatorHovered] = ImVec4(0.60f, 0.70f, 0.66f, 1.00f); - colors[ImGuiCol_SeparatorActive] = ImVec4(0.70f, 0.90f, 0.81f, 1.00f); - colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.16f); - colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 1.00f, 0.90f, 0.60f); - colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 1.00f, 0.90f, 0.90f); - colors[ImGuiCol_PlotLines] = ImVec4(1.00f, 1.00f, 1.00f, 1.00f); - colors[ImGuiCol_PlotLinesHovered] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); - colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f); - colors[ImGuiCol_PlotHistogramHovered] = ImVec4(1.00f, 0.60f, 0.00f, 1.00f); - colors[ImGuiCol_TextSelectedBg] = ImVec4(0.00f, 0.00f, 1.00f, 0.35f); - colors[ImGuiCol_ModalWindowDarkening] = ImVec4(0.20f, 0.20f, 0.20f, 0.35f); - colors[ImGuiCol_DragDropTarget] = ImVec4(1.00f, 1.00f, 0.00f, 0.90f); - colors[ImGuiCol_Tab] = ImVec4(0.27f, 0.54f, 0.42f, 0.83f); - colors[ImGuiCol_TabHovered] = ImVec4(0.34f, 0.68f, 0.53f, 0.83f); - colors[ImGuiCol_TabActive] = ImVec4(0.38f, 0.76f, 0.58f, 0.83f); -} - ImFontAtlas* Engine::getImGuiGlobalFontAtlas() { return globalFontAtlas; } } // namespace render