mirror of
https://github.com/ocornut/imgui.git
synced 2024-11-15 19:43:28 +01:00
Merge branch 'docking2' into viewport_docking
# Conflicts: # examples/example_glfw_opengl2/main.cpp # examples/example_glfw_opengl3/main.cpp # examples/example_glfw_vulkan/main.cpp # examples/example_sdl_opengl3/main.cpp # examples/example_sdl_vulkan/main.cpp # examples/example_win32_directx10/main.cpp # examples/example_win32_directx11/main.cpp # examples/example_win32_directx12/main.cpp # imgui.cpp # imgui.h # imgui_demo.cpp # imgui_internal.h
This commit is contained in:
commit
a82be53407
@ -29,6 +29,32 @@ HOW TO UPDATE?
|
||||
- Please report any issue!
|
||||
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
DOCKING BRANCH (In Progress)
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
- Added ImGuiConfigFlags_DockingEnable flag to enable Docking. [BETA]
|
||||
Set with `io.ConfigFlags |= ImGuiConfigFlags_DockingEnable;`.
|
||||
- Added BeginTabBar(), EndTabBar(), BeginTabItem(), EndTabItem(), SetTabItemClosed() API. (#261, #351)
|
||||
- Added DockSpace() API. (#351)
|
||||
- Added SetNextWindowDock() API. (#351)
|
||||
- Added IsWindowDocked() API. (#351)
|
||||
- Added ImGuiWindowFlags_NoDocking window flag to disable the possibility for a window to be docked.
|
||||
Popup, Menu and Child windows always have the ImGuiWindowFlags_NoDocking flag set. (#351)
|
||||
- Added ImGuiWindowFlags_UnsavedDocument window flag to append '*' to title without altering the ID,
|
||||
as a convenience to avoid using the ### operator.
|
||||
- Added io.ConfigDockingWithKeyMod option to configure docking mode.
|
||||
- Style: Added ImGuiCol_DockingPreview, ImGuiCol_DockingBg colors. (#351)
|
||||
- Style: Added ImGuiCol_Tab, ImGuiCol_TabHovered, ImGuiCol_TabActive, ImGuiCol_TabUnfocused, ImGuiCol_TabUnfocusedActive colors. (#261, #351)
|
||||
- Demo: Added Layout->Tabs demo code. (#261, #351)
|
||||
- Demo: Added "Documents" example app showcasing possible use for tabs. (#261, #351)
|
||||
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
VERSION 1.66 (In Progress)
|
||||
-----------------------------------------------------------------------
|
||||
|
||||
|
||||
-----------------------------------------------------------------------
|
||||
VERSION 1.65 (Released 2018-09-06)
|
||||
-----------------------------------------------------------------------
|
||||
|
@ -26,7 +26,9 @@ int main(int, char**)
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
|
||||
|
||||
ImGui_ImplAllegro5_Init(display);
|
||||
|
||||
// Setup style
|
||||
|
@ -241,7 +241,8 @@
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
|
||||
|
||||
ImGui_ImplOSX_Init();
|
||||
ImGui_ImplOpenGL2_Init();
|
||||
|
@ -98,7 +98,8 @@ int main(int argc, char** argv)
|
||||
// Setup ImGui binding
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
|
||||
|
||||
ImGui_ImplFreeGLUT_Init();
|
||||
ImGui_ImplFreeGLUT_InstallFuncs();
|
||||
|
@ -33,10 +33,12 @@ int main(int, char**)
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
|
||||
|
||||
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
||||
ImGui_ImplOpenGL2_Init();
|
||||
|
@ -76,11 +76,12 @@ int main(int, char**)
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
|
||||
|
||||
ImGui_ImplGlfw_InitForOpenGL(window, true);
|
||||
ImGui_ImplOpenGL3_Init(glsl_version);
|
||||
|
@ -347,10 +347,12 @@ int main(int, char**)
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad; // Enable Gamepad Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
|
||||
|
||||
// Setup GLFW binding
|
||||
ImGui_ImplGlfw_InitForVulkan(window, true);
|
||||
|
@ -20,7 +20,9 @@ int main(int, char**)
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
|
||||
|
||||
ImGui_Marmalade_Init(true);
|
||||
|
||||
// Setup style
|
||||
|
@ -38,7 +38,8 @@ int main(int, char**)
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
|
||||
|
||||
ImGui_ImplSDL2_InitForOpenGL(window, gl_context);
|
||||
ImGui_ImplOpenGL2_Init();
|
||||
|
@ -76,9 +76,11 @@ int main(int, char**)
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
|
||||
|
||||
ImGui_ImplSDL2_InitForOpenGL(window, gl_context);
|
||||
ImGui_ImplOpenGL3_Init(glsl_version);
|
||||
|
@ -335,9 +335,11 @@ int main(int, char**)
|
||||
// Setup ImGui binding
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
|
||||
|
||||
// Setup SDL binding
|
||||
ImGui_ImplSDL2_InitForVulkan(window);
|
||||
|
@ -118,9 +118,11 @@ int main(int, char**)
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
|
||||
|
||||
ImGui_ImplWin32_Init(hwnd);
|
||||
ImGui_ImplDX10_Init(g_pd3dDevice);
|
||||
|
@ -134,12 +134,13 @@ int main(int, char**)
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DpiEnableScaleFonts; // FIXME-DPI: THIS CURRENTLY DOESN'T WORK AS EXPECTED. DON'T USE IN USER APP!
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DpiEnableScaleViewports;
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DpiEnableScaleFonts; // FIXME-DPI: THIS CURRENTLY DOESN'T WORK AS EXPECTED. DON'T USE IN USER APP!
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DpiEnableScaleViewports; // FIXME-DPI
|
||||
|
||||
ImGui_ImplWin32_Init(hwnd);
|
||||
ImGui_ImplDX11_Init(g_pd3dDevice, g_pd3dDeviceContext);
|
||||
|
@ -290,8 +290,11 @@ int main(int, char**)
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
|
||||
io.ConfigFlags |= ImGuiConfigFlags_ViewportsEnable; // Enable Multi-Viewport / Platform Windows
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoTaskBarIcons;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_ViewportsNoMerge;
|
||||
|
||||
ImGui_ImplWin32_Init(hwnd);
|
||||
ImGui_ImplDX12_Init(g_pd3dDevice, NUM_FRAMES_IN_FLIGHT,
|
||||
|
@ -79,7 +79,9 @@ int main(int, char**)
|
||||
IMGUI_CHECKVERSION();
|
||||
ImGui::CreateContext();
|
||||
ImGuiIO& io = ImGui::GetIO(); (void)io;
|
||||
//io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard; // Enable Keyboard Controls
|
||||
io.ConfigFlags |= ImGuiConfigFlags_DockingEnable; // Enable Docking
|
||||
|
||||
ImGui_ImplWin32_Init(hwnd);
|
||||
ImGui_ImplDX9_Init(g_pd3dDevice);
|
||||
|
||||
|
61
imgui.h
61
imgui.h
@ -27,6 +27,8 @@
|
||||
#define IMGUI_VERSION_NUM 16501
|
||||
#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert))
|
||||
#define IMGUI_HAS_VIEWPORT 1 // Viewport WIP branch
|
||||
#define IMGUI_HAS_DOCK 1 // Docking WIP branch
|
||||
#define IMGUI_HAS_TABS 1 // Docking WIP branch
|
||||
|
||||
// Define attributes of all API symbols declarations (e.g. for DLL under Windows)
|
||||
// IMGUI_API is used for core imgui functions, IMGUI_IMPL_API is used for the default bindings files (imgui_impl_xxx.h)
|
||||
@ -114,6 +116,8 @@ typedef int ImGuiFocusedFlags; // -> enum ImGuiFocusedFlags_ // Flags: f
|
||||
typedef int ImGuiHoveredFlags; // -> enum ImGuiHoveredFlags_ // Flags: for IsItemHovered(), IsWindowHovered() etc.
|
||||
typedef int ImGuiInputTextFlags; // -> enum ImGuiInputTextFlags_ // Flags: for InputText*()
|
||||
typedef int ImGuiSelectableFlags; // -> enum ImGuiSelectableFlags_ // Flags: for Selectable()
|
||||
typedef int ImGuiTabBarFlags; // -> enum ImGuiTabBarFlags_ // Flags: for BeginTabBar()
|
||||
typedef int ImGuiTabItemFlags; // -> enum ImGuiTabItemFlags_ // Flags: for BeginTabItem()
|
||||
typedef int ImGuiTreeNodeFlags; // -> enum ImGuiTreeNodeFlags_ // Flags: for TreeNode*(),CollapsingHeader()
|
||||
typedef int ImGuiViewportFlags; // -> enum ImGuiViewportFlags_ // Flags: for ImGuiViewport
|
||||
typedef int ImGuiWindowFlags; // -> enum ImGuiWindowFlags_ // Flags: for Begin*()
|
||||
@ -211,6 +215,7 @@ namespace ImGui
|
||||
IMGUI_API bool IsWindowCollapsed();
|
||||
IMGUI_API bool IsWindowFocused(ImGuiFocusedFlags flags=0); // is current window focused? or its root/child, depending on flags. see flags for options.
|
||||
IMGUI_API bool IsWindowHovered(ImGuiHoveredFlags flags=0); // is current window hovered (and typically: not blocked by a popup/modal)? see flags for options. NB: If you are trying to check whether your mouse should be dispatched to imgui or to your app, you should use the 'io.WantCaptureMouse' boolean for that! Please read the FAQ!
|
||||
IMGUI_API bool IsWindowDocked();
|
||||
IMGUI_API ImDrawList* GetWindowDrawList(); // get draw list associated to the current window, to append your own drawing primitives
|
||||
IMGUI_API float GetWindowDpiScale(); // get DPI scale currently associated to the current window's viewport.
|
||||
IMGUI_API ImGuiViewport*GetWindowViewport(); // get viewport currently associated to the current window.
|
||||
@ -233,6 +238,7 @@ namespace ImGui
|
||||
IMGUI_API void SetNextWindowFocus(); // set next window to be focused / front-most. call before Begin()
|
||||
IMGUI_API void SetNextWindowBgAlpha(float alpha); // set next window background color alpha. helper to easily modify ImGuiCol_WindowBg/ChildBg/PopupBg.
|
||||
IMGUI_API void SetNextWindowViewport(ImGuiID viewport_id); // set next window viewport
|
||||
IMGUI_API void SetNextWindowDock(ImGuiID dock_id, ImGuiCond cond = 0); // set next window dock id (FIXME-DOCK)
|
||||
IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiCond cond = 0); // (not recommended) set current window position - call within Begin()/End(). prefer using SetNextWindowPos(), as this may incur tearing and side-effects.
|
||||
IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiCond cond = 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0,0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects.
|
||||
IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed().
|
||||
@ -502,6 +508,19 @@ namespace ImGui
|
||||
IMGUI_API void SetColumnOffset(int column_index, float offset_x); // set position of column line (in pixels, from the left side of the contents region). pass -1 to use current column
|
||||
IMGUI_API int GetColumnsCount();
|
||||
|
||||
// Tabs
|
||||
// Note: Tabs are automatically created by the docking system. Use this to create tab bars/tabs yourself without docking being involved.
|
||||
IMGUI_API bool BeginTabBar(const char* str_id, ImGuiTabBarFlags flags = 0); // create and append into a TabBar
|
||||
IMGUI_API void EndTabBar();
|
||||
IMGUI_API bool BeginTabItem(const char* label, bool* p_open = NULL, ImGuiTabItemFlags = 0);// create a Tab. Returns true if the Tab is selected.
|
||||
IMGUI_API void EndTabItem(); // only call EndTabItem() if BeginTabItem() returns true!
|
||||
IMGUI_API void SetTabItemClosed(const char* tab_or_docked_window_label); // notify TabBar or Docking system of a closed tab/window ahead (useful to reduce visual flicker on reorderable tab bars). For tab-bar: call after BeginTabBar() and before Tab submissions. Otherwise call with a window name.
|
||||
|
||||
// Docking
|
||||
// [BETA API] Enable with io.ConfigFlags |= ImGuiConfigFlags_DockingEnable.
|
||||
// Note: you DO NOT need to call DockSpace() to use most Docking facilities! You can hold SHIFT anywhere while moving windows. Use DockSpace() if you need to create an explicit docking space _within_ an existing window. See Docking demo for details)
|
||||
IMGUI_API void DockSpace(const char* str_id, const ImVec2& size = ImVec2(0, 0));
|
||||
|
||||
// Logging/Capture: all text output from interface is captured to tty/file/clipboard. By default, tree nodes are automatically opened during logging.
|
||||
IMGUI_API void LogToTTY(int max_depth = -1); // start logging to tty
|
||||
IMGUI_API void LogToFile(int max_depth = -1, const char* filename = NULL); // start logging to file
|
||||
@ -641,6 +660,8 @@ enum ImGuiWindowFlags_
|
||||
ImGuiWindowFlags_NoNavInputs = 1 << 18, // No gamepad/keyboard navigation within the window
|
||||
ImGuiWindowFlags_NoNavFocus = 1 << 19, // No focusing toward this window with gamepad/keyboard navigation (e.g. skipped by CTRL+TAB)
|
||||
ImGuiWindowFlags_NoNav = ImGuiWindowFlags_NoNavInputs | ImGuiWindowFlags_NoNavFocus,
|
||||
ImGuiWindowFlags_UnsavedDocument = 1 << 20, // Append '*' to title without affecting the ID, as a convenience to avoid using the ### operator. When used in a tab/docking context, tab is selected on closure and closure is deferred by one frame to allow code to cancel the closure (with a confirmation popup, etc.) without flicker.
|
||||
ImGuiWindowFlags_NoDocking = 1 << 21, // Disable docking of this window
|
||||
|
||||
// [Internal]
|
||||
ImGuiWindowFlags_NavFlattened = 1 << 23, // [BETA] Allow gamepad/keyboard navigation to cross over parent border to this child (only use on child that have no scrolling!)
|
||||
@ -648,7 +669,8 @@ enum ImGuiWindowFlags_
|
||||
ImGuiWindowFlags_Tooltip = 1 << 25, // Don't use! For internal use by BeginTooltip()
|
||||
ImGuiWindowFlags_Popup = 1 << 26, // Don't use! For internal use by BeginPopup()
|
||||
ImGuiWindowFlags_Modal = 1 << 27, // Don't use! For internal use by BeginPopupModal()
|
||||
ImGuiWindowFlags_ChildMenu = 1 << 28 // Don't use! For internal use by BeginMenu()
|
||||
ImGuiWindowFlags_ChildMenu = 1 << 28, // Don't use! For internal use by BeginMenu()
|
||||
ImGuiWindowFlags_DockNodeHost = 1 << 29 // Don't use! For internal use by Begin()/NewFrame()
|
||||
|
||||
// [Obsolete]
|
||||
//ImGuiWindowFlags_ShowBorders = 1 << 7, // --> Set style.FrameBorderSize=1.0f / style.WindowBorderSize=1.0f to enable borders around windows and items
|
||||
@ -732,6 +754,31 @@ enum ImGuiComboFlags_
|
||||
ImGuiComboFlags_HeightMask_ = ImGuiComboFlags_HeightSmall | ImGuiComboFlags_HeightRegular | ImGuiComboFlags_HeightLarge | ImGuiComboFlags_HeightLargest
|
||||
};
|
||||
|
||||
// Flags for ImGui::BeginTabBar()
|
||||
enum ImGuiTabBarFlags_
|
||||
{
|
||||
ImGuiTabBarFlags_None = 0,
|
||||
ImGuiTabBarFlags_Reorderable = 1 << 0, // Allow manually dragging tabs to re-order them + New tabs are appended at the end of list
|
||||
ImGuiTabBarFlags_AutoSelectNewTabs = 1 << 1, // Automatically select new tabs when they appear
|
||||
ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false.
|
||||
ImGuiTabBarFlags_NoTabListPopupButton = 1 << 3,
|
||||
ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4,
|
||||
ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 5, // Resize tabs when they don't fit
|
||||
ImGuiTabBarFlags_FittingPolicyScroll = 1 << 6, // Add scroll buttons when tabs don't fit
|
||||
ImGuiTabBarFlags_FittingPolicyMask_ = ImGuiTabBarFlags_FittingPolicyResizeDown | ImGuiTabBarFlags_FittingPolicyScroll,
|
||||
ImGuiTabBarFlags_FittingPolicyDefault_ = ImGuiTabBarFlags_FittingPolicyResizeDown
|
||||
};
|
||||
|
||||
// Flags for ImGui::BeginTabItem()
|
||||
enum ImGuiTabItemFlags_
|
||||
{
|
||||
ImGuiTabItemFlags_None = 0,
|
||||
ImGuiTabItemFlags_UnsavedDocument = 1 << 0, // Append '*' to title without affecting the ID, as a convenience to avoid using the ### operator. Also: tab is selected on closure and closure is deferred by one frame to allow code to undo it without flicker.
|
||||
ImGuiTabItemFlags_SetSelected = 1 << 1, // Trigger flag to programatically make the tab selected when calling BeginTabItem()
|
||||
ImGuiTabItemFlags_NoCloseWithMiddleMouseButton = 1 << 2, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false.
|
||||
ImGuiTabItemFlags_NoPushId = 1 << 3 // Don't call PushID(tab->ID)/PopID() on BeginTabItem()/EndTabItem()
|
||||
};
|
||||
|
||||
// Flags for ImGui::IsWindowFocused()
|
||||
enum ImGuiFocusedFlags_
|
||||
{
|
||||
@ -877,6 +924,9 @@ enum ImGuiConfigFlags_
|
||||
ImGuiConfigFlags_NoMouse = 1 << 4, // Instruct imgui to clear mouse position/buttons in NewFrame(). This allows ignoring the mouse information set by the back-end.
|
||||
ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, // Instruct back-end to not alter mouse cursor shape and visibility. Use if the back-end cursor changes are interfering with yours and you don't want to use SetMouseCursor() to change mouse cursor. You may want to honor requests from imgui by reading GetMouseCursor() yourself instead.
|
||||
|
||||
// [BETA] Docking
|
||||
ImGuiConfigFlags_DockingEnable = 1 << 6, // Docking enable flags. Use SHIFT to dock window into another (or without SHIFT if io.ConfigDockingWithKeyMod = false).
|
||||
|
||||
// [BETA] Viewports
|
||||
ImGuiConfigFlags_ViewportsEnable = 1 << 10, // Viewport enable flags (require both ImGuiConfigFlags_PlatformHasViewports + ImGuiConfigFlags_RendererHasViewports set by the respective back-ends)
|
||||
ImGuiConfigFlags_ViewportsNoTaskBarIcons= 1 << 11, // Disable task bars icons for all secondary viewports (will set ImGuiViewportFlags_NoTaskBarIcon on them)
|
||||
@ -938,6 +988,13 @@ enum ImGuiCol_
|
||||
ImGuiCol_ResizeGrip,
|
||||
ImGuiCol_ResizeGripHovered,
|
||||
ImGuiCol_ResizeGripActive,
|
||||
ImGuiCol_Tab,
|
||||
ImGuiCol_TabHovered,
|
||||
ImGuiCol_TabActive,
|
||||
ImGuiCol_TabUnfocused,
|
||||
ImGuiCol_TabUnfocusedActive,
|
||||
ImGuiCol_DockingPreview,
|
||||
ImGuiCol_DockingBg, // Empty node
|
||||
ImGuiCol_PlotLines,
|
||||
ImGuiCol_PlotLinesHovered,
|
||||
ImGuiCol_PlotHistogram,
|
||||
@ -1081,6 +1138,7 @@ struct ImGuiStyle
|
||||
ImVec2 FramePadding; // Padding within a framed rectangle (used by most widgets).
|
||||
float FrameRounding; // Radius of frame corners rounding. Set to 0.0f to have rectangular frame (used by most widgets).
|
||||
float FrameBorderSize; // Thickness of border around frames. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).
|
||||
float TabBorderSize; // Thickness of border around tabs.
|
||||
ImVec2 ItemSpacing; // Horizontal and vertical spacing between widgets/lines.
|
||||
ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label).
|
||||
ImVec2 TouchExtraPadding; // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much!
|
||||
@ -1134,6 +1192,7 @@ struct ImGuiIO
|
||||
|
||||
// Miscellaneous configuration options
|
||||
bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by back-end implementations.
|
||||
bool ConfigDockingWithKeyMod; // = true // Enable docking with holding Shift key (reduce visual noise, allows dropping in wider space)
|
||||
bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl (was called io.OptMacOSXBehaviors prior to 1.63)
|
||||
bool ConfigInputTextCursorBlink; // = true // Set to false to disable blinking cursor, for users who consider it distracting. (was called: io.OptCursorBlink prior to 1.63)
|
||||
bool ConfigResizeWindowsFromEdges; // = false // [BETA] Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be the ImGuiWindowFlags_ResizeFromAnySide flag)
|
||||
|
476
imgui_demo.cpp
476
imgui_demo.cpp
@ -36,6 +36,8 @@ Index of this file:
|
||||
// [SECTION] Example App: Simple Overlay / ShowExampleAppSimpleOverlay()
|
||||
// [SECTION] Example App: Manipulating Window Titles / ShowExampleAppWindowTitles()
|
||||
// [SECTION] Example App: Custom Rendering using ImDrawList API / ShowExampleAppCustomRendering()
|
||||
// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
|
||||
// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
|
||||
|
||||
*/
|
||||
|
||||
@ -98,6 +100,8 @@ Index of this file:
|
||||
#if !defined(IMGUI_DISABLE_DEMO_WINDOWS)
|
||||
|
||||
// Forward Declarations
|
||||
static void ShowExampleAppDockSpace(bool* p_open);
|
||||
static void ShowExampleAppDocuments(bool* p_open);
|
||||
static void ShowExampleAppMainMenuBar();
|
||||
static void ShowExampleAppConsole(bool* p_open);
|
||||
static void ShowExampleAppLog(bool* p_open);
|
||||
@ -157,6 +161,8 @@ void ImGui::ShowUserGuide()
|
||||
void ImGui::ShowDemoWindow(bool* p_open)
|
||||
{
|
||||
// Examples Apps (accessible from the "Examples" menu)
|
||||
static bool show_app_dockspace = false;
|
||||
static bool show_app_documents = false;
|
||||
static bool show_app_main_menu_bar = false;
|
||||
static bool show_app_console = false;
|
||||
static bool show_app_log = false;
|
||||
@ -169,6 +175,8 @@ void ImGui::ShowDemoWindow(bool* p_open)
|
||||
static bool show_app_window_titles = false;
|
||||
static bool show_app_custom_rendering = false;
|
||||
|
||||
if (show_app_dockspace) ShowExampleAppDockSpace(&show_app_dockspace); // Process the Docking app first, as explicit DockSpace() needs to be submitted early (read comments near the DockSpace function)
|
||||
if (show_app_documents) ShowExampleAppDocuments(&show_app_documents); // Process the Document app next, as it may also use a DockSpace()
|
||||
if (show_app_main_menu_bar) ShowExampleAppMainMenuBar();
|
||||
if (show_app_console) ShowExampleAppConsole(&show_app_console);
|
||||
if (show_app_log) ShowExampleAppLog(&show_app_log);
|
||||
@ -207,6 +215,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
|
||||
static bool no_collapse = false;
|
||||
static bool no_close = false;
|
||||
static bool no_nav = false;
|
||||
static bool no_docking = false;
|
||||
|
||||
ImGuiWindowFlags window_flags = 0;
|
||||
if (no_titlebar) window_flags |= ImGuiWindowFlags_NoTitleBar;
|
||||
@ -216,6 +225,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
|
||||
if (no_resize) window_flags |= ImGuiWindowFlags_NoResize;
|
||||
if (no_collapse) window_flags |= ImGuiWindowFlags_NoCollapse;
|
||||
if (no_nav) window_flags |= ImGuiWindowFlags_NoNav;
|
||||
if (no_docking) window_flags |= ImGuiWindowFlags_NoDocking;
|
||||
if (no_close) p_open = NULL; // Don't pass our bool* to Begin
|
||||
|
||||
// We specify a default position/size in case there's no data in the .ini file. Typically this isn't required! We only do it to make the Demo applications a little more welcoming.
|
||||
@ -257,6 +267,8 @@ void ImGui::ShowDemoWindow(bool* p_open)
|
||||
ImGui::MenuItem("Simple overlay", NULL, &show_app_simple_overlay);
|
||||
ImGui::MenuItem("Manipulating window titles", NULL, &show_app_window_titles);
|
||||
ImGui::MenuItem("Custom rendering", NULL, &show_app_custom_rendering);
|
||||
ImGui::MenuItem("Docking", NULL, &show_app_dockspace);
|
||||
ImGui::MenuItem("Documents", NULL, &show_app_documents);
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::BeginMenu("Help"))
|
||||
@ -308,12 +320,19 @@ void ImGui::ShowDemoWindow(bool* p_open)
|
||||
}
|
||||
ImGui::CheckboxFlags("io.ConfigFlags: NoMouseCursorChange", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_NoMouseCursorChange);
|
||||
ImGui::SameLine(); ShowHelpMarker("Instruct back-end to not alter mouse cursor shape and visibility.");
|
||||
|
||||
ImGui::CheckboxFlags("io.ConfigFlags: DockingEnable", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_DockingEnable);
|
||||
ImGui::SameLine(); ShowHelpMarker("Use SHIFT to dock window into another (or without SHIFT if io.ConfigDockingWithKeyMod == false)");
|
||||
|
||||
ImGui::CheckboxFlags("io.ConfigFlags: ViewportsEnable", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_ViewportsEnable);
|
||||
ImGui::SameLine(); ShowHelpMarker("Toggling this at runtime is normally unsupported (it will offset your windows).");
|
||||
ImGui::CheckboxFlags("io.ConfigFlags: ViewportsNoTaskBarIcons", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_ViewportsNoTaskBarIcons);
|
||||
ImGui::SameLine(); ShowHelpMarker("Toggling this at runtime is normally unsupported (most platform back-ends won't refresh the task bar icon state right away).");
|
||||
ImGui::CheckboxFlags("io.ConfigFlags: ViewportsNoMerge", (unsigned int *)&io.ConfigFlags, ImGuiConfigFlags_ViewportsNoMerge);
|
||||
ImGui::SameLine(); ShowHelpMarker("All floating windows will always create their own viewport and platform window.");
|
||||
|
||||
ImGui::Checkbox("io.ConfigDockingWithKeyMod", &io.ConfigDockingWithKeyMod);
|
||||
ImGui::SameLine(); ShowHelpMarker("Enable docking when holding Shift only (allows to drop in wider space, reduce visual noise)");
|
||||
ImGui::Checkbox("io.ConfigInputTextCursorBlink", &io.ConfigInputTextCursorBlink);
|
||||
ImGui::SameLine(); ShowHelpMarker("Set to false to disable blinking cursor, for users who consider it distracting");
|
||||
ImGui::Checkbox("io.ConfigResizeWindowsFromEdges [beta]", &io.ConfigResizeWindowsFromEdges);
|
||||
@ -369,7 +388,8 @@ void ImGui::ShowDemoWindow(bool* p_open)
|
||||
ImGui::Checkbox("No resize", &no_resize); ImGui::SameLine(300);
|
||||
ImGui::Checkbox("No collapse", &no_collapse);
|
||||
ImGui::Checkbox("No close", &no_close); ImGui::SameLine(150);
|
||||
ImGui::Checkbox("No nav", &no_nav);
|
||||
ImGui::Checkbox("No nav", &no_nav); ImGui::SameLine(300);
|
||||
ImGui::Checkbox("No docking", &no_docking);
|
||||
}
|
||||
|
||||
if (ImGui::CollapsingHeader("Widgets"))
|
||||
@ -1468,6 +1488,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
|
||||
|
||||
// Calling IsItemHovered() after begin returns the hovered status of the title bar.
|
||||
// This is useful in particular if you want to create a context menu (with BeginPopupContextItem) associated to the title bar of a window.
|
||||
// This will also work when docked into a Tab (the Tab replace the Title Bar and guarantee the same properties).
|
||||
static bool test_window = false;
|
||||
ImGui::Checkbox("Hovered/Active tests after Begin() for title bar testing", &test_window);
|
||||
if (test_window)
|
||||
@ -1478,6 +1499,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
|
||||
if (ImGui::MenuItem("Close")) { test_window = false; }
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
//if (IsItemHovered() || IsItemActive()) { printf("[%05d] Hovered %d Active %d\n", GetFrameCount(), IsItemHovered(), IsItemActive()); } // [DEBUG]
|
||||
ImGui::Text(
|
||||
"IsItemHovered() after begin = %d (== is title bar hovered)\n"
|
||||
"IsItemActive() after begin = %d (== is window being clicked/moved)\n",
|
||||
@ -1673,6 +1695,72 @@ void ImGui::ShowDemoWindow(bool* p_open)
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("Tabs"))
|
||||
{
|
||||
if (ImGui::TreeNode("Basic"))
|
||||
{
|
||||
ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_None;
|
||||
ImGui::BeginTabBar("MyTabBar", tab_bar_flags);
|
||||
if (ImGui::BeginTabItem("Avocado"))
|
||||
{
|
||||
ImGui::Text("This is the Avocado tab!\nblah blah blah blah blah");
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ImGui::BeginTabItem("Broccoli"))
|
||||
{
|
||||
ImGui::Text("This is the Broccoli tab!\nblah blah blah blah blah");
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
if (ImGui::BeginTabItem("Cucumber"))
|
||||
{
|
||||
ImGui::Text("This is the Cucumber tab!\nblah blah blah blah blah");
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
ImGui::EndTabBar();
|
||||
ImGui::Separator();
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("Advanced & Close Button"))
|
||||
{
|
||||
// Expose a couple of the available flags. In most cases you may just call BeginTabBar() with no flags (0).
|
||||
static ImGuiTabBarFlags tab_bar_flags = ImGuiTabBarFlags_Reorderable;
|
||||
ImGui::CheckboxFlags("ImGuiTabBarFlags_Reorderable", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_Reorderable);
|
||||
ImGui::CheckboxFlags("ImGuiTabBarFlags_AutoSelectNewTabs", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_AutoSelectNewTabs);
|
||||
ImGui::CheckboxFlags("ImGuiTabBarFlags_NoCloseWithMiddleMouseButton", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_NoCloseWithMiddleMouseButton);
|
||||
if ((tab_bar_flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
|
||||
tab_bar_flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
|
||||
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyResizeDown", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyResizeDown))
|
||||
tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyResizeDown);
|
||||
if (ImGui::CheckboxFlags("ImGuiTabBarFlags_FittingPolicyScroll", (unsigned int*)&tab_bar_flags, ImGuiTabBarFlags_FittingPolicyScroll))
|
||||
tab_bar_flags &= ~(ImGuiTabBarFlags_FittingPolicyMask_ ^ ImGuiTabBarFlags_FittingPolicyScroll);
|
||||
|
||||
// Tab Bar
|
||||
const char* names[4] = { "Artichoke", "Beetroot", "Celery", "Daikon" };
|
||||
static bool opened[4] = { true, true, true, true }; // Persistent user state
|
||||
for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
|
||||
{
|
||||
if (n > 0) { ImGui::SameLine(); }
|
||||
ImGui::Checkbox(names[n], &opened[n]);
|
||||
}
|
||||
|
||||
// Passing a bool* to BeginTabItem() is similar to passing one to Begin(): the underlying bool will be set to false when the tab is closed.
|
||||
ImGui::BeginTabBar("MyTabBar", tab_bar_flags);
|
||||
for (int n = 0; n < IM_ARRAYSIZE(opened); n++)
|
||||
if (opened[n] && ImGui::BeginTabItem(names[n], &opened[n]))
|
||||
{
|
||||
ImGui::Text("This is the %s tab!", names[n]);
|
||||
if (n & 1)
|
||||
ImGui::Text("I am an odd tab.");
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
ImGui::EndTabBar();
|
||||
ImGui::Separator();
|
||||
ImGui::TreePop();
|
||||
}
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("Groups"))
|
||||
{
|
||||
ImGui::TextWrapped("(Using ImGui::BeginGroup()/EndGroup() to layout items. BeginGroup() basically locks the horizontal position. EndGroup() bundles the whole group so that you can use functions such as IsItemHovered() on it.)");
|
||||
@ -2507,6 +2595,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
|
||||
ImGui::SliderFloat("ChildBorderSize", &style.ChildBorderSize, 0.0f, 1.0f, "%.0f");
|
||||
ImGui::SliderFloat("PopupBorderSize", &style.PopupBorderSize, 0.0f, 1.0f, "%.0f");
|
||||
ImGui::SliderFloat("FrameBorderSize", &style.FrameBorderSize, 0.0f, 1.0f, "%.0f");
|
||||
ImGui::SliderFloat("TabBorderSize", &style.TabBorderSize, 0.0f, 1.0f, "%.0f");
|
||||
ImGui::Text("Rounding");
|
||||
ImGui::SliderFloat("WindowRounding", &style.WindowRounding, 0.0f, 14.0f, "%.0f");
|
||||
ImGui::SliderFloat("ChildRounding", &style.ChildRounding, 0.0f, 16.0f, "%.0f");
|
||||
@ -3397,6 +3486,8 @@ static void ShowExampleAppConstrainedResize(bool* p_open)
|
||||
"Custom: Always Square",
|
||||
"Custom: Fixed Steps (100)",
|
||||
};
|
||||
if (ImGui::IsWindowDocked())
|
||||
ImGui::Text("Warning: Sizing Constraints won't work if the window is docked!");
|
||||
if (ImGui::Button("200x200")) { ImGui::SetWindowSize(ImVec2(200, 200)); } ImGui::SameLine();
|
||||
if (ImGui::Button("500x500")) { ImGui::SetWindowSize(ImVec2(500, 500)); } ImGui::SameLine();
|
||||
if (ImGui::Button("800x200")) { ImGui::SetWindowSize(ImVec2(800, 200)); }
|
||||
@ -3430,7 +3521,7 @@ static void ShowExampleAppSimpleOverlay(bool* p_open)
|
||||
ImGui::SetNextWindowViewport(viewport->ID);
|
||||
}
|
||||
ImGui::SetNextWindowBgAlpha(0.3f); // Transparent background
|
||||
if (ImGui::Begin("Example: Simple Overlay", p_open, (corner != -1 ? ImGuiWindowFlags_NoMove : 0) | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav))
|
||||
if (ImGui::Begin("Example: Simple Overlay", p_open, (corner != -1 ? ImGuiWindowFlags_NoMove : 0) | ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_NoFocusOnAppearing | ImGuiWindowFlags_NoNav))
|
||||
{
|
||||
ImGui::Text("Simple overlay\n" "in the corner of the screen.\n" "(right-click to change position)");
|
||||
ImGui::Separator();
|
||||
@ -3594,6 +3685,387 @@ static void ShowExampleAppCustomRendering(bool* p_open)
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Example App: Docking, DockSpace / ShowExampleAppDockSpace()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Demonstrate using DockSpace() to create an explicit docking spacing within an existing window.
|
||||
// Note that you already dock windows into each others _without_ a DockSpace() by just holding SHIFT when moving a window.
|
||||
// DockSpace() is only useful to construct to a central location for your application.
|
||||
void ShowExampleAppDockSpace(bool* p_open)
|
||||
{
|
||||
static bool opt_fullscreen_persistant = true;
|
||||
bool opt_fullscreen = opt_fullscreen_persistant;
|
||||
|
||||
// We are using the ImGuiWindowFlags_NoDocking flag to make the parent window not dockable into.
|
||||
// Because 1) it would be confusing to have two docking targets within each others.
|
||||
// and 2) we want our main DockSpace to always be visible (never hidden within a tab bar): if the DockSpace disappear its child windows will be orphaned.
|
||||
ImGuiWindowFlags flags = ImGuiWindowFlags_MenuBar;
|
||||
flags |= ImGuiWindowFlags_NoDocking;
|
||||
if (opt_fullscreen)
|
||||
{
|
||||
ImGuiViewport* viewport = ImGui::GetMainViewport();
|
||||
ImGui::SetNextWindowPos(viewport->Pos);
|
||||
ImGui::SetNextWindowSize(viewport->Size);
|
||||
ImGui::SetNextWindowViewport(viewport->ID);
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||
flags |= ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove;
|
||||
flags |= ImGuiWindowFlags_NoBringToFrontOnFocus | ImGuiWindowFlags_NoNavFocus;
|
||||
}
|
||||
ImGui::PushStyleVar(ImGuiStyleVar_WindowPadding, ImVec2(0.0f, 0.0f));
|
||||
ImGui::Begin("Docking Documents Demo", p_open, flags);
|
||||
ImGui::PopStyleVar();
|
||||
|
||||
if (ImGui::BeginMenuBar())
|
||||
{
|
||||
if (ImGui::BeginMenu("Docking"))
|
||||
{
|
||||
if (ImGui::MenuItem("Remove DockSpace", NULL, false, p_open != NULL))
|
||||
*p_open = false;
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
// Disabling fullscreen would allow the window to be moved to the front of other windows,
|
||||
// which we can't undo at the moment without finer window depth/z control.
|
||||
/*if (ImGui::BeginMenu("Options"))
|
||||
{
|
||||
ImGui::MenuItem("Fullscreen", NULL, &opt_fullscreen_persistant);
|
||||
ImGui::EndMenu();
|
||||
}*/
|
||||
ShowHelpMarker(
|
||||
"You can _always_ dock _any_ window into another by holding the SHIFT key while moving a window. Try it now!" "\n"
|
||||
"This demo app has nothing to do with it!" "\n\n"
|
||||
"This demo app only demonstrate the use of ImGui::DockSpace() which allows you to specify a docking spot _within_ another window. This is useful so you can decorate your main application window (e.g. with a menu bar)." "\n\n"
|
||||
"ImGui::DockSpace() comes with one hard constraint: it needs to be submitted _before_ any window which may be docked into it. Therefore, if you use a dock spot as the central point of your application, you'll probably want it to be part of the very first window you are submitting to imgui every frame." "\n\n"
|
||||
"(NB: because of this constraint, the implicit \"Debug\" window can not be docked into an explicit DockSpace(), because that window is submitted as part of the NewFrame() call. An easy workaround is that you can create your own implicit \"Debug##2\" window after calling DockSpace() and leave it in the window stack for anyone to use.)"
|
||||
);
|
||||
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
|
||||
//ImGui::PushStyleColor(ImGuiCol_DockingBg, ImVec4(0.2f, 0.2f, 0.2f, 1.0f));
|
||||
ImGui::DockSpace("##MyCentralDockSpace");
|
||||
//ImGui::PopStyleColor();
|
||||
|
||||
ImGui::End();
|
||||
if (opt_fullscreen)
|
||||
ImGui::PopStyleVar();
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Example App: Documents Handling / ShowExampleAppDocuments()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Simplified structure to mimic a Document model
|
||||
struct MyDocument
|
||||
{
|
||||
const char* Name; // Document title
|
||||
bool Open; // Set when the document is open (in this demo, we keep an array of all available documents to simplify the demo)
|
||||
bool OpenPrev; // Copy of Open from last update.
|
||||
bool Dirty; // Set when the document has been modified
|
||||
bool WantClose; // Set when the document
|
||||
ImVec4 Color; // An arbitrary variable associated to the document
|
||||
|
||||
MyDocument(const char* name, bool open = true, const ImVec4& color = ImVec4(1.0f,1.0f,1.0f,1.0f))
|
||||
{
|
||||
Name = name;
|
||||
Open = OpenPrev = open;
|
||||
Dirty = false;
|
||||
WantClose = false;
|
||||
Color = color;
|
||||
}
|
||||
void DoOpen() { Open = true; }
|
||||
void DoQueueClose() { WantClose = true; }
|
||||
void DoForceClose() { Open = false; Dirty = false; }
|
||||
void DoSave() { Dirty = false; }
|
||||
|
||||
// Display dummy contents for the Document
|
||||
static void DisplayContents(MyDocument* doc)
|
||||
{
|
||||
ImGui::PushID(doc);
|
||||
ImGui::Text("Document \"%s\"", doc->Name);
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, doc->Color);
|
||||
ImGui::TextWrapped("Lorem ipsum dolor sit amet, consectetur adipiscing elit, sed do eiusmod tempor incididunt ut labore et dolore magna aliqua.");
|
||||
ImGui::PopStyleColor();
|
||||
if (ImGui::Button("Modify", ImVec2(100, 0)))
|
||||
doc->Dirty = true;
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Save", ImVec2(100, 0)))
|
||||
doc->DoSave();
|
||||
ImGui::ColorEdit3("color", &doc->Color.x); // Useful to test drag and drop and hold-dragged-to-open-tab behavior.
|
||||
ImGui::PopID();
|
||||
}
|
||||
|
||||
// Display context menu for the Document
|
||||
static void DisplayContextMenu(MyDocument* doc)
|
||||
{
|
||||
if (!ImGui::BeginPopupContextItem())
|
||||
return;
|
||||
|
||||
char buf[256];
|
||||
sprintf(buf, "Save %s", doc->Name);
|
||||
if (ImGui::MenuItem(buf, "CTRL+S", false, doc->Open))
|
||||
doc->DoSave();
|
||||
if (ImGui::MenuItem("Close", "CTRL+W", false, doc->Open))
|
||||
doc->DoQueueClose();
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
};
|
||||
|
||||
struct ExampleAppDocuments
|
||||
{
|
||||
ImVector<MyDocument> Documents;
|
||||
|
||||
ExampleAppDocuments()
|
||||
{
|
||||
Documents.push_back(MyDocument("Radish", true, ImVec4(1.0f, 1.0f, 1.0f, 1.0f)));
|
||||
Documents.push_back(MyDocument("Eggplant", true, ImVec4(0.8f, 0.5f, 1.0f, 1.0f)));
|
||||
Documents.push_back(MyDocument("Carrot", true, ImVec4(1.0f, 0.8f, 0.5f, 1.0f)));
|
||||
Documents.push_back(MyDocument("Tomato", false, ImVec4(1.0f, 0.3f, 0.4f, 1.0f)));
|
||||
Documents.push_back(MyDocument("A Rather Long Title", false));
|
||||
Documents.push_back(MyDocument("Some Document", false));
|
||||
}
|
||||
};
|
||||
|
||||
// [Optional] Notify the system of Tabs/Windows of closure that happened outside the regular tab interface
|
||||
// If a tab has been closed programmatically (aka closed from another source such as the Checkbox() in the demo, as opposed
|
||||
// to clicking on the regular tab closing button) and stops being submitted, it will take a frame for the tab bar to notice its absence.
|
||||
// During this frame there will be a gap in the tab bar, and if the tab that has disappeared was the selected one, the tab bar
|
||||
// will report no selected tab during the frame. This will effectively give the impression of a flicker for one frame.
|
||||
// We call SetTabItemClosed() to manually notify the Tab Bar or Docking system of removed tabs to avoid this glitch.
|
||||
// Note that this completely optional, and only affect tab bars with the ImGuiTabBarFlags_Reorderable flag.
|
||||
static void NotifyOfDocumentsClosedElsewhere(ExampleAppDocuments& app)
|
||||
{
|
||||
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
|
||||
{
|
||||
MyDocument* doc = &app.Documents[doc_n];
|
||||
if (!doc->Open && doc->OpenPrev)
|
||||
ImGui::SetTabItemClosed(doc->Name);
|
||||
doc->OpenPrev = doc->Open;
|
||||
}
|
||||
}
|
||||
|
||||
void ShowExampleAppDocuments(bool* p_open)
|
||||
{
|
||||
static ExampleAppDocuments app;
|
||||
|
||||
ImGui::Begin("Examples: Documents", p_open, ImGuiWindowFlags_MenuBar);
|
||||
|
||||
// Options
|
||||
enum Target
|
||||
{
|
||||
Target_None,
|
||||
Target_Tab, // Create document as a local tab into a local tab bar
|
||||
Target_Window // Create document as a regular window
|
||||
};
|
||||
static Target opt_target = Target_Tab;
|
||||
static bool opt_reorderable = true;
|
||||
static ImGuiTabBarFlags opt_fitting_flags = ImGuiTabBarFlags_FittingPolicyDefault_;
|
||||
|
||||
// Menu
|
||||
if (ImGui::BeginMenuBar())
|
||||
{
|
||||
if (ImGui::BeginMenu("File"))
|
||||
{
|
||||
int open_count = 0;
|
||||
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
|
||||
open_count += app.Documents[doc_n].Open ? 1 : 0;
|
||||
|
||||
if (ImGui::BeginMenu("Open", open_count < app.Documents.Size))
|
||||
{
|
||||
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
|
||||
{
|
||||
MyDocument* doc = &app.Documents[doc_n];
|
||||
if (!doc->Open)
|
||||
if (ImGui::MenuItem(doc->Name))
|
||||
doc->DoOpen();
|
||||
}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::MenuItem("Close All Documents", NULL, false, open_count > 0))
|
||||
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
|
||||
app.Documents[doc_n].DoQueueClose();
|
||||
if (ImGui::MenuItem("Exit", "Alt+F4")) {}
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
ImGui::EndMenuBar();
|
||||
}
|
||||
|
||||
// [Debug] List documents with one checkbox for each
|
||||
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
|
||||
{
|
||||
MyDocument* doc = &app.Documents[doc_n];
|
||||
if (doc_n > 0)
|
||||
ImGui::SameLine();
|
||||
ImGui::PushID(doc);
|
||||
if (ImGui::Checkbox(doc->Name, &doc->Open))
|
||||
if (!doc->Open)
|
||||
doc->DoForceClose();
|
||||
ImGui::PopID();
|
||||
}
|
||||
ImGui::PushItemWidth(ImGui::GetFontSize() * 12);
|
||||
ImGui::Combo("Output", (int*)&opt_target, "None\0TabBar+Tabs\0DockSpace+Window\0");
|
||||
ImGui::PopItemWidth();
|
||||
bool redock_all = false;
|
||||
if (opt_target == Target_Tab) { ImGui::SameLine(); ImGui::Checkbox("Reorderable Tabs", &opt_reorderable); }
|
||||
if (opt_target == Target_Window) { ImGui::SameLine(); redock_all = ImGui::Button("Redock all"); }
|
||||
|
||||
ImGui::Separator();
|
||||
|
||||
// Tabs
|
||||
if (opt_target == Target_Tab)
|
||||
{
|
||||
ImGuiTabBarFlags tab_bar_flags = (opt_fitting_flags) | (opt_reorderable ? ImGuiTabBarFlags_Reorderable : 0);
|
||||
ImGui::BeginTabBar("##tabs", tab_bar_flags);
|
||||
|
||||
if (opt_reorderable)
|
||||
NotifyOfDocumentsClosedElsewhere(app);
|
||||
|
||||
// [DEBUG] Stress tests
|
||||
//if ((ImGui::GetFrameCount() % 30) == 0) docs[1].Open ^= 1; // [DEBUG] Automatically show/hide a tab. Test various interactions e.g. dragging with this on.
|
||||
//if (ImGui::GetIO().KeyCtrl) ImGui::SetTabItemSelected(docs[1].Name); // [DEBUG] Test SetTabItemSelected(), probably not very useful as-is anyway..
|
||||
|
||||
// Submit Tabs
|
||||
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
|
||||
{
|
||||
MyDocument* doc = &app.Documents[doc_n];
|
||||
if (!doc->Open)
|
||||
continue;
|
||||
|
||||
ImGuiTabItemFlags tab_flags = (doc->Dirty ? ImGuiTabItemFlags_UnsavedDocument : 0);
|
||||
bool visible = ImGui::BeginTabItem(doc->Name, &doc->Open, tab_flags);
|
||||
|
||||
// Cancel attempt to close when unsaved add to save queue so we can display a popup.
|
||||
if (!doc->Open && doc->Dirty)
|
||||
{
|
||||
doc->Open = true;
|
||||
doc->DoQueueClose();
|
||||
}
|
||||
|
||||
MyDocument::DisplayContextMenu(doc);
|
||||
if (visible)
|
||||
{
|
||||
MyDocument::DisplayContents(doc);
|
||||
ImGui::EndTabItem();
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::EndTabBar();
|
||||
}
|
||||
else if (opt_target == Target_Window)
|
||||
{
|
||||
NotifyOfDocumentsClosedElsewhere(app);
|
||||
|
||||
// Create a DockSpace where any window can be docked
|
||||
ImGui::DockSpace("##DockSpace");
|
||||
ImGuiID dockspace_id = ImGui::GetID("##DockSpace");
|
||||
|
||||
// Create Windows
|
||||
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
|
||||
{
|
||||
MyDocument* doc = &app.Documents[doc_n];
|
||||
if (!doc->Open)
|
||||
continue;
|
||||
|
||||
// FIXME-DOCK: SetNextWindowDock()
|
||||
//ImGuiID default_dock_id = GetDockspaceRootDocumentDockID();
|
||||
//ImGuiID default_dock_id = GetDockspacePreferedDocumentDockID();
|
||||
ImGui::SetNextWindowDock(dockspace_id, redock_all ? ImGuiCond_Always : ImGuiCond_FirstUseEver);
|
||||
ImGuiWindowFlags window_flags = (doc->Dirty ? ImGuiWindowFlags_UnsavedDocument : 0);
|
||||
bool visible = ImGui::Begin(doc->Name, &doc->Open, window_flags);
|
||||
|
||||
// Cancel attempt to close when unsaved add to save queue so we can display a popup.
|
||||
if (!doc->Open && doc->Dirty)
|
||||
{
|
||||
doc->Open = true;
|
||||
doc->DoQueueClose();
|
||||
}
|
||||
|
||||
MyDocument::DisplayContextMenu(doc);
|
||||
if (visible)
|
||||
MyDocument::DisplayContents(doc);
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
}
|
||||
|
||||
// Update closing queue
|
||||
static ImVector<MyDocument*> close_queue;
|
||||
if (close_queue.empty())
|
||||
{
|
||||
// Close queue is locked once we started a popup
|
||||
for (int doc_n = 0; doc_n < app.Documents.Size; doc_n++)
|
||||
{
|
||||
MyDocument* doc = &app.Documents[doc_n];
|
||||
if (doc->WantClose)
|
||||
{
|
||||
doc->WantClose = false;
|
||||
close_queue.push_back(doc);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Display closing confirmation UI
|
||||
if (!close_queue.empty())
|
||||
{
|
||||
int close_queue_unsaved_documents = 0;
|
||||
for (int n = 0; n < close_queue.Size; n++)
|
||||
if (close_queue[n]->Dirty)
|
||||
close_queue_unsaved_documents++;
|
||||
|
||||
if (close_queue_unsaved_documents == 0)
|
||||
{
|
||||
// Close documents when all are unsaved
|
||||
for (int n = 0; n < close_queue.Size; n++)
|
||||
close_queue[n]->DoForceClose();
|
||||
close_queue.clear();
|
||||
}
|
||||
else
|
||||
{
|
||||
if (!ImGui::IsPopupOpen("Save?"))
|
||||
ImGui::OpenPopup("Save?");
|
||||
if (ImGui::BeginPopupModal("Save?"))
|
||||
{
|
||||
ImGui::Text("Save change to the following items?");
|
||||
ImGui::PushItemWidth(-1.0f);
|
||||
ImGui::ListBoxHeader("##", close_queue_unsaved_documents, 6);
|
||||
for (int n = 0; n < close_queue.Size; n++)
|
||||
if (close_queue[n]->Dirty)
|
||||
ImGui::Text("%s", close_queue[n]->Name);
|
||||
ImGui::ListBoxFooter();
|
||||
|
||||
if (ImGui::Button("Yes", ImVec2(80, 0)))
|
||||
{
|
||||
for (int n = 0; n < close_queue.Size; n++)
|
||||
{
|
||||
if (close_queue[n]->Dirty)
|
||||
close_queue[n]->DoSave();
|
||||
close_queue[n]->DoForceClose();
|
||||
}
|
||||
close_queue.clear();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("No", ImVec2(80, 0)))
|
||||
{
|
||||
for (int n = 0; n < close_queue.Size; n++)
|
||||
close_queue[n]->DoForceClose();
|
||||
close_queue.clear();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::SameLine();
|
||||
if (ImGui::Button("Cancel", ImVec2(80, 0)))
|
||||
{
|
||||
close_queue.clear();
|
||||
ImGui::CloseCurrentPopup();
|
||||
}
|
||||
ImGui::EndPopup();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImGui::End();
|
||||
}
|
||||
|
||||
// End of Demo code
|
||||
#else
|
||||
|
||||
|
@ -205,6 +205,13 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst)
|
||||
colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.25f);
|
||||
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
|
||||
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
|
||||
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
|
||||
colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
|
||||
colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
|
||||
colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
|
||||
colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
|
||||
colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_HeaderActive] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
|
||||
colors[ImGuiCol_DockingBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);;
|
||||
colors[ImGuiCol_PlotLines] = ImVec4(0.61f, 0.61f, 0.61f, 1.00f);
|
||||
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
|
||||
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
||||
@ -255,6 +262,13 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst)
|
||||
colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.16f);
|
||||
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f);
|
||||
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f);
|
||||
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
|
||||
colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
|
||||
colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
|
||||
colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
|
||||
colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
|
||||
colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
|
||||
colors[ImGuiCol_DockingBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);;
|
||||
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);
|
||||
@ -306,6 +320,13 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst)
|
||||
colors[ImGuiCol_ResizeGrip] = ImVec4(0.80f, 0.80f, 0.80f, 0.56f);
|
||||
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
|
||||
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
|
||||
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f);
|
||||
colors[ImGuiCol_TabActive] = ImLerp(colors[ImGuiCol_HeaderActive], colors[ImGuiCol_TitleBgActive], 0.60f);
|
||||
colors[ImGuiCol_TabUnfocused] = ImLerp(colors[ImGuiCol_Tab], colors[ImGuiCol_TitleBg], 0.80f);
|
||||
colors[ImGuiCol_TabUnfocusedActive] = ImLerp(colors[ImGuiCol_TabActive], colors[ImGuiCol_TitleBg], 0.40f);
|
||||
colors[ImGuiCol_TabHovered] = colors[ImGuiCol_HeaderHovered];
|
||||
colors[ImGuiCol_DockingPreview] = colors[ImGuiCol_Header] * ImVec4(1.0f, 1.0f, 1.0f, 0.7f);
|
||||
colors[ImGuiCol_DockingBg] = ImVec4(0.20f, 0.20f, 0.20f, 1.00f);;
|
||||
colors[ImGuiCol_PlotLines] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
|
||||
colors[ImGuiCol_PlotLinesHovered] = ImVec4(1.00f, 0.43f, 0.35f, 1.00f);
|
||||
colors[ImGuiCol_PlotHistogram] = ImVec4(0.90f, 0.70f, 0.00f, 1.00f);
|
||||
@ -2816,8 +2837,11 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
|
||||
// (progressively moved from imgui.cpp to here when they are redesigned to stop accessing ImGui global state)
|
||||
//-----------------------------------------------------------------------------
|
||||
// - RenderMouseCursor()
|
||||
// - RenderArrowDockMenu()
|
||||
// - RenderArrowPointingAt()
|
||||
// - RenderRectFilledRangeH()
|
||||
// - RenderRectFilledWithHole()
|
||||
// - RenderPixelEllipsis()
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
void ImGui::RenderMouseCursor(ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor)
|
||||
@ -2869,6 +2893,14 @@ void ImGui::RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half
|
||||
}
|
||||
}
|
||||
|
||||
// This is less wide than RenderArrow() and we use in dock nodes instead of the regular RenderArrow() to denote a change of functionality,
|
||||
// and because the saved space means that the left-most tab label can stay at exactly the same position as the label of a loose window.
|
||||
void ImGui::RenderArrowDockMenu(ImDrawList* draw_list, ImVec2 p_min, float sz, ImU32 col)
|
||||
{
|
||||
draw_list->AddRectFilled(p_min + ImVec2(sz * 0.10f, sz * 0.15f), p_min + ImVec2(sz * 0.70f, sz * 0.30f), col);
|
||||
RenderArrowPointingAt(draw_list, p_min + ImVec2(sz * 0.40f, sz * 0.85f), ImVec2(sz * 0.30f, sz * 0.40f), ImGuiDir_Down, col);
|
||||
}
|
||||
|
||||
static inline float ImAcos01(float x)
|
||||
{
|
||||
if (x <= 0.0f) return IM_PI * 0.5f;
|
||||
@ -2937,6 +2969,32 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im
|
||||
draw_list->PathFillConvex(col);
|
||||
}
|
||||
|
||||
// For CTRL+TAB within a docking node we need to render the dimming background in 8 steps
|
||||
// (Because the root node renders the background in one shot, in order to avoid flickering when a child dock node is not submitted)
|
||||
void ImGui::RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect inner, ImU32 col, float rounding)
|
||||
{
|
||||
const bool fill_L = (inner.Min.x > outer.Min.x);
|
||||
const bool fill_R = (inner.Max.x < outer.Max.x);
|
||||
const bool fill_U = (inner.Min.y > outer.Min.y);
|
||||
const bool fill_D = (inner.Max.y < outer.Max.y);
|
||||
if (fill_L) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Min.y), ImVec2(inner.Min.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawCornerFlags_TopLeft) | (fill_D ? 0 : ImDrawCornerFlags_BotLeft));
|
||||
if (fill_R) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Min.y), ImVec2(outer.Max.x, inner.Max.y), col, rounding, (fill_U ? 0 : ImDrawCornerFlags_TopRight) | (fill_D ? 0 : ImDrawCornerFlags_BotRight));
|
||||
if (fill_U) draw_list->AddRectFilled(ImVec2(inner.Min.x, outer.Min.y), ImVec2(inner.Max.x, inner.Min.y), col, rounding, (fill_L ? 0 : ImDrawCornerFlags_TopLeft) | (fill_R ? 0 : ImDrawCornerFlags_TopRight));
|
||||
if (fill_D) draw_list->AddRectFilled(ImVec2(inner.Min.x, inner.Max.y), ImVec2(inner.Max.x, outer.Max.y), col, rounding, (fill_L ? 0 : ImDrawCornerFlags_BotLeft) | (fill_R ? 0 : ImDrawCornerFlags_BotRight));
|
||||
if (fill_L && fill_U) draw_list->AddRectFilled(ImVec2(outer.Min.x, outer.Min.y), ImVec2(inner.Min.x, inner.Min.y), col, rounding, ImDrawCornerFlags_TopLeft);
|
||||
if (fill_R && fill_U) draw_list->AddRectFilled(ImVec2(inner.Max.x, outer.Min.y), ImVec2(outer.Max.x, inner.Min.y), col, rounding, ImDrawCornerFlags_TopRight);
|
||||
if (fill_L && fill_D) draw_list->AddRectFilled(ImVec2(outer.Min.x, inner.Max.y), ImVec2(inner.Min.x, outer.Max.y), col, rounding, ImDrawCornerFlags_BotLeft);
|
||||
if (fill_R && fill_D) draw_list->AddRectFilled(ImVec2(inner.Max.x, inner.Max.y), ImVec2(outer.Max.x, outer.Max.y), col, rounding, ImDrawCornerFlags_BotRight);
|
||||
}
|
||||
|
||||
// FIXME: Rendering an ellipsis "..." is a surprisingly tricky problem... can't rely on font glyph having it, and regular dot are typically too wide.
|
||||
// If we render a dot/shape ourselves it comes with the risk that it wouldn't match the boldness or positioning of what the font uses...
|
||||
void ImGui::RenderPixelEllipsis(ImDrawList* draw_list, ImFont* font, ImVec2 pos, int count, ImU32 col)
|
||||
{
|
||||
pos.y += (float)(int)(font->DisplayOffset.y + font->Ascent + 0.5f - 1.0f);
|
||||
for (int dot_n = 0; dot_n < count; dot_n++)
|
||||
draw_list->AddRectFilled(ImVec2(pos.x + dot_n * 2.0f, pos.y), ImVec2(pos.x + dot_n * 2.0f + 1.0f, pos.y + 1.0f), col);
|
||||
}
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] Decompression code
|
||||
|
272
imgui_internal.h
272
imgui_internal.h
@ -40,6 +40,9 @@ struct ImGuiColorMod; // Stacked color modifier, backup of modifie
|
||||
struct ImGuiColumnData; // Storage data for a single column
|
||||
struct ImGuiColumnsSet; // Storage data for a columns set
|
||||
struct ImGuiContext; // Main imgui context
|
||||
struct ImGuiDockContext; // Docking system context
|
||||
struct ImGuiDockNode; // Docking system node (hold a list of Windows OR two child dock nodes)
|
||||
struct ImGuiDockNodeSettings; // Storage for a dock node in .ini file (we preserve those even if the associated dock node isn't active during the session)
|
||||
struct ImGuiGroupData; // Stacked storage data for BeginGroup()/EndGroup()
|
||||
struct ImGuiInputTextState; // Internal state of the currently focused/edited text input box
|
||||
struct ImGuiItemHoveredDataBackup; // Backup and restore IsItemHovered() internal data
|
||||
@ -49,6 +52,8 @@ struct ImGuiNextWindowData; // Storage for SetNexWindow** functions
|
||||
struct ImGuiPopupRef; // Storage for current popup stack
|
||||
struct ImGuiSettingsHandler; // Storage for one type registered in the .ini file
|
||||
struct ImGuiStyleMod; // Stacked style modifier, backup of modified data so we can restore it
|
||||
struct ImGuiTabBar; // Storage for a tab bar
|
||||
struct ImGuiTabItem; // Storage for a tab item (within a tab bar)
|
||||
struct ImGuiWindow; // Storage for one window
|
||||
struct ImGuiWindowTempData; // Temporary storage for one window (that's the data which in theory we could ditch at the end of the frame)
|
||||
struct ImGuiWindowSettings; // Storage for window settings stored in .ini file (we keep one of those even if the actual window wasn't instanced during this session)
|
||||
@ -88,6 +93,9 @@ namespace ImGuiStb
|
||||
extern IMGUI_API ImGuiContext* GImGui; // Current implicit ImGui context pointer
|
||||
#endif
|
||||
|
||||
// Internal Drag and Drop payload types. String starting with '_' are reserved for Dear ImGui.
|
||||
#define IMGUI_PAYLOAD_TYPE_WINDOW "_IMWINDOW" // Payload == ImGuiWindow*
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Helpers
|
||||
//-----------------------------------------------------------------------------
|
||||
@ -98,6 +106,8 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit ImGui context pointe
|
||||
#else
|
||||
#define IM_NEWLINE "\n"
|
||||
#endif
|
||||
|
||||
#define IMGUI_DEBUG_LOG(FMT,...) printf("[%05d] " FMT, GImGui->FrameCount, __VA_ARGS__)
|
||||
#define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1]
|
||||
#define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose
|
||||
#define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255
|
||||
@ -144,6 +154,7 @@ IMGUI_API int ImStrlenW(const ImWchar* str);
|
||||
IMGUI_API const ImWchar*ImStrbolW(const ImWchar* buf_mid_line, const ImWchar* buf_begin); // Find beginning-of-line
|
||||
IMGUI_API const char* ImStristr(const char* haystack, const char* haystack_end, const char* needle, const char* needle_end);
|
||||
IMGUI_API void ImStrTrimBlanks(char* str);
|
||||
IMGUI_API const char* ImStrSkipBlank(const char* str);
|
||||
IMGUI_API int ImFormatString(char* buf, size_t buf_size, const char* fmt, ...) IM_FMTARGS(3);
|
||||
IMGUI_API int ImFormatStringV(char* buf, size_t buf_size, const char* fmt, va_list args) IM_FMTLIST(3);
|
||||
IMGUI_API const char* ImParseFormatFindStart(const char* format);
|
||||
@ -211,18 +222,32 @@ static inline ImVec2 ImRotate(const ImVec2& v, float cos_a, float sin_a)
|
||||
static inline float ImLinearSweep(float current, float target, float speed) { if (current < target) return ImMin(current + speed, target); if (current > target) return ImMax(current - speed, target); return current; }
|
||||
static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
|
||||
|
||||
// Helper: ImPool<>. Basic keyed storage for contiguous instances, slow/amortized insertion, O(1) indexable, O(Log N) queries by ID over a dense/hot buffer
|
||||
// Creation/Erasure invalidate all pointers, but indexes are valid as long as the object lifetime.
|
||||
template<typename T>
|
||||
struct IMGUI_API ImPool
|
||||
{
|
||||
ImVector<T> Data; // Contiguous data
|
||||
ImGuiStorage Map; // ID->Index
|
||||
int FreeIdx; // Next free idx to use
|
||||
|
||||
ImPool() { FreeIdx = 0; }
|
||||
~ImPool() { Clear(); }
|
||||
T* GetByKey(ImGuiID key) { int idx = Map.GetInt(key, -1); return (idx != -1) ? &Data[idx] : NULL; }
|
||||
T* GetByIndex(int n) { return &Data[n]; }
|
||||
int GetIndex(const T* p) const { IM_ASSERT(p >= Data.Data && p < Data.Data + Data.Size); return (int)(p - Data.Data); }
|
||||
T* GetOrAddByKey(ImGuiID key) { int* p_idx = Map.GetIntRef(key, -1); if (*p_idx != -1) return &Data[*p_idx]; *p_idx = FreeIdx; return Add(); }
|
||||
void Clear() { for (int n = 0; n < Map.Data.Size; n++) { int idx = Map.Data[n].val_i; if (idx != -1) Data[idx].~T(); } Map.Clear(); Data.clear(); FreeIdx = 0; }
|
||||
T* Add() { int idx = FreeIdx; if (idx == Data.Size) { Data.resize(Data.Size + 1); FreeIdx++; } else { FreeIdx = *(int*)&Data[idx]; } IM_PLACEMENT_NEW(&Data[idx]) T(); return &Data[idx]; }
|
||||
void Remove(ImGuiID key, const T* p) { Remove(key, GetIndex(p)); }
|
||||
void Remove(ImGuiID key, int idx) { Data[idx].~T(); *(int*)&Data[idx] = FreeIdx; FreeIdx = idx; Map.SetInt(key, -1); }
|
||||
};
|
||||
typedef int ImPoolIdx;
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Types
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// 1D vector (this odd construct is used to facilitate the transition between 1D and 2D and maintenance of some patches)
|
||||
struct ImVec1
|
||||
{
|
||||
float x;
|
||||
ImVec1() { x = 0.0f; }
|
||||
ImVec1(float _x) { x = _x; }
|
||||
};
|
||||
|
||||
enum ImGuiButtonFlags_
|
||||
{
|
||||
ImGuiButtonFlags_None = 0,
|
||||
@ -275,6 +300,19 @@ enum ImGuiSeparatorFlags_
|
||||
ImGuiSeparatorFlags_Vertical = 1 << 1
|
||||
};
|
||||
|
||||
// Transient per-window ItemFlags, reset at the beginning of the frame. For child windows: inherited from parent on first Begin().
|
||||
// This is going to be exposed in imgui.h when stabilized enough.
|
||||
enum ImGuiItemFlags_
|
||||
{
|
||||
ImGuiItemFlags_AllowKeyboardFocus = 1 << 0, // true
|
||||
ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings.
|
||||
ImGuiItemFlags_Disabled = 1 << 2, // false // [BETA] Disable interactions but doesn't affect visuals yet. See github.com/ocornut/imgui/issues/211
|
||||
ImGuiItemFlags_NoNav = 1 << 3, // false
|
||||
ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false
|
||||
ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // MenuItem/Selectable() automatically closes current Popup window
|
||||
ImGuiItemFlags_Default_ = ImGuiItemFlags_AllowKeyboardFocus
|
||||
};
|
||||
|
||||
// Storage for LastItem data
|
||||
enum ImGuiItemStatusFlags_
|
||||
{
|
||||
@ -366,6 +404,22 @@ enum ImGuiPopupPositionPolicy
|
||||
ImGuiPopupPositionPolicy_ComboBox
|
||||
};
|
||||
|
||||
// 1D vector (this odd construct is used to facilitate the transition between 1D and 2D and maintenance of some patches)
|
||||
struct ImVec1
|
||||
{
|
||||
float x;
|
||||
ImVec1() { x = 0.0f; }
|
||||
ImVec1(float _x) { x = _x; }
|
||||
};
|
||||
|
||||
// 2D vector (half-size integer)
|
||||
struct ImVec2ih
|
||||
{
|
||||
short x, y;
|
||||
ImVec2ih() { x = y = 0; }
|
||||
ImVec2ih(short _x, short _y) { x = _x; y = _y; }
|
||||
};
|
||||
|
||||
// 2D axis aligned bounding-box
|
||||
// NB: we can't rely on ImVec2 math operators being available here
|
||||
struct IMGUI_API ImRect
|
||||
@ -482,19 +536,21 @@ struct ImGuiWindowSettings
|
||||
{
|
||||
char* Name;
|
||||
ImGuiID ID;
|
||||
ImVec2 Pos; // NB: Settings position are stored RELATIVE to the viewport! Whereas runtime ones are absolute positions.
|
||||
ImVec2 Pos; // NB: Settings position are stored RELATIVE to the viewport! Whereas runtime ones are absolute positions.
|
||||
ImVec2 Size;
|
||||
ImVec2 ViewportPos;
|
||||
ImGuiID ViewportId;
|
||||
ImGuiID DockId; // ID of last known DockNode (even if the DockNode is invisible because it has only 1 active window), or 0 if none.
|
||||
short DockOrder; // Order of the last time the window was visible within its DockNode. This is used to reorder windows that are reappearing on the same frame. Same value between windows that were active and windows that were none are possible.
|
||||
bool Collapsed;
|
||||
|
||||
ImGuiWindowSettings() { Name = NULL; ID = ViewportId = 0; Pos = Size = ViewportPos = ImVec2(0, 0); Collapsed = false; }
|
||||
ImGuiWindowSettings() { Name = NULL; ID = 0; Pos = Size = ViewportPos = ImVec2(0, 0); ViewportId = DockId = 0; DockOrder = -1; Collapsed = false; }
|
||||
};
|
||||
|
||||
struct ImGuiSettingsHandler
|
||||
{
|
||||
const char* TypeName; // Short description stored in .ini file. Disallowed characters: '[' ']'
|
||||
ImGuiID TypeHash; // == ImHash(TypeName, 0, 0)
|
||||
const char* TypeName; // Short description stored in .ini file. Disallowed characters: '[' ']'
|
||||
ImGuiID TypeHash; // == ImHash(TypeName, 0, 0)
|
||||
void* (*ReadOpenFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, const char* name); // Read: Called when entering into a new ini entry e.g. "[Window][Name]"
|
||||
void (*ReadLineFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, void* entry, const char* line); // Read: Called for every line of text within an ini entry
|
||||
void (*WriteAllFn)(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* out_buf); // Write: Output every entries into 'out_buf'
|
||||
@ -635,39 +691,92 @@ struct ImGuiNextWindowData
|
||||
ImGuiCond FocusCond;
|
||||
ImGuiCond BgAlphaCond;
|
||||
ImGuiCond ViewportCond;
|
||||
ImGuiCond DockCond;
|
||||
ImVec2 PosVal;
|
||||
ImVec2 PosPivotVal;
|
||||
ImVec2 SizeVal;
|
||||
ImVec2 ContentSizeVal;
|
||||
bool PosUndock;
|
||||
bool CollapsedVal;
|
||||
ImRect SizeConstraintRect;
|
||||
ImGuiSizeCallback SizeCallback;
|
||||
void* SizeCallbackUserData;
|
||||
float BgAlphaVal;
|
||||
ImGuiID ViewportId;
|
||||
ImGuiID DockId;
|
||||
ImVec2 MenuBarOffsetMinVal; // This is not exposed publicly, so we don't clear it.
|
||||
|
||||
ImGuiNextWindowData()
|
||||
{
|
||||
PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = ViewportCond = 0;
|
||||
PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = ViewportCond = DockCond = 0;
|
||||
PosVal = PosPivotVal = SizeVal = ImVec2(0.0f, 0.0f);
|
||||
ContentSizeVal = ImVec2(0.0f, 0.0f);
|
||||
CollapsedVal = false;
|
||||
PosUndock = CollapsedVal = false;
|
||||
SizeConstraintRect = ImRect();
|
||||
SizeCallback = NULL;
|
||||
SizeCallbackUserData = NULL;
|
||||
BgAlphaVal = FLT_MAX;
|
||||
ViewportId = 0;
|
||||
ViewportId = DockId = 0;
|
||||
MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f);
|
||||
}
|
||||
|
||||
void Clear()
|
||||
{
|
||||
PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = ViewportCond = 0;
|
||||
PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = ViewportCond = DockCond = 0;
|
||||
}
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Docking, Tabs
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct ImGuiTabBarSortItem
|
||||
{
|
||||
int Index;
|
||||
float Width;
|
||||
};
|
||||
|
||||
// sizeof() 88~124
|
||||
struct ImGuiDockNode
|
||||
{
|
||||
ImGuiID ID;
|
||||
ImGuiDockNode* ParentNode;
|
||||
ImGuiDockNode* ChildNodes[2];
|
||||
ImVector<ImGuiWindow*> Windows; // Note: unordered list! Iterate TabBar->Tabs for user-order.
|
||||
ImGuiTabBar* TabBar;
|
||||
ImVec2 Pos, Size; // Current position, size
|
||||
ImVec2 LastExplicitSize; // Last explicit size (overridden when using a splitter affecting the node)
|
||||
int SplitAxis;
|
||||
float SplitRatio;
|
||||
|
||||
ImGuiWindow* HostWindow;
|
||||
ImGuiWindow* VisibleWindow;
|
||||
ImGuiDockNode* OnlyNodeWithWindows; // Root node only, set when there is a single visible node within the hierarchy
|
||||
ImGuiID SelectedTabID;
|
||||
int LastFrameActive;
|
||||
ImGuiID LastFocusedNodeID;
|
||||
ImGuiID WantCloseOne;
|
||||
bool InitFromFirstWindow :1;
|
||||
bool IsVisible :1; // Set to false when the node is hidden (usually disabled as it has no active window)
|
||||
bool IsExplicitRoot :1; // Mark root node as explicit when created from a DockSpace()
|
||||
bool IsDocumentRoot :1;
|
||||
bool HasCloseButton :1;
|
||||
bool HasCollapseButton :1;
|
||||
bool WantCloseAll :1;
|
||||
bool WantLockSizeOnce :1;
|
||||
|
||||
ImGuiDockNode(ImGuiID id);
|
||||
~ImGuiDockNode();
|
||||
bool IsRootNode() const { return ParentNode == NULL; }
|
||||
bool IsParent() const { return ChildNodes[0] != NULL; }
|
||||
bool IsEmpty() const { return ChildNodes[0] == NULL && Windows.Size == 0; }
|
||||
ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x + Size.x, Pos.y + Size.y); }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Main imgui context
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
struct ImGuiContext
|
||||
{
|
||||
bool Initialized;
|
||||
@ -794,6 +903,11 @@ struct ImGuiContext
|
||||
ImVector<unsigned char> DragDropPayloadBufHeap; // We don't expose the ImVector<> directly
|
||||
unsigned char DragDropPayloadBufLocal[8]; // Local buffer for small payloads
|
||||
|
||||
// Tab bars
|
||||
ImPool<ImGuiTabBar> TabBars;
|
||||
ImVector<ImGuiTabBar*> CurrentTabBar;
|
||||
ImVector<ImGuiTabBarSortItem> TabSortByWidthBuffer;
|
||||
|
||||
// Widget state
|
||||
ImGuiInputTextState InputTextState;
|
||||
ImFont InputTextPasswordFont;
|
||||
@ -811,6 +925,10 @@ struct ImGuiContext
|
||||
ImVec2 PlatformImePos, PlatformImeLastPos; // Cursor position request & last passed to the OS Input Method Editor
|
||||
ImGuiViewport* PlatformImePosViewport;
|
||||
|
||||
// Extensions
|
||||
// FIXME: We could provide an API to register one slot in an array held in ImGuiContext?
|
||||
ImGuiDockContext* DockContext;
|
||||
|
||||
// Settings
|
||||
bool SettingsLoaded;
|
||||
float SettingsDirtyTimer; // Save .ini Settings to memory when time reaches zero
|
||||
@ -927,6 +1045,8 @@ struct ImGuiContext
|
||||
PlatformImePos = PlatformImeLastPos = ImVec2(FLT_MAX, FLT_MAX);
|
||||
PlatformImePosViewport = 0;
|
||||
|
||||
DockContext = NULL;
|
||||
|
||||
SettingsLoaded = false;
|
||||
SettingsDirtyTimer = 0.0f;
|
||||
|
||||
@ -943,18 +1063,9 @@ struct ImGuiContext
|
||||
}
|
||||
};
|
||||
|
||||
// Transient per-window flags, reset at the beginning of the frame. For child window, inherited from parent on first Begin().
|
||||
// This is going to be exposed in imgui.h when stabilized enough.
|
||||
enum ImGuiItemFlags_
|
||||
{
|
||||
ImGuiItemFlags_AllowKeyboardFocus = 1 << 0, // true
|
||||
ImGuiItemFlags_ButtonRepeat = 1 << 1, // false // Button() will return true multiple times based on io.KeyRepeatDelay and io.KeyRepeatRate settings.
|
||||
ImGuiItemFlags_Disabled = 1 << 2, // false // [BETA] Disable interactions but doesn't affect visuals yet. See github.com/ocornut/imgui/issues/211
|
||||
ImGuiItemFlags_NoNav = 1 << 3, // false
|
||||
ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false
|
||||
ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // MenuItem/Selectable() automatically closes current Popup window
|
||||
ImGuiItemFlags_Default_ = ImGuiItemFlags_AllowKeyboardFocus
|
||||
};
|
||||
//-----------------------------------------------------------------------------
|
||||
// ImGuiWindow
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
// Transient per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the DC variable name in ImGuiWindow.
|
||||
// FIXME: That's theory, in practice the delimitation between ImGuiWindow and ImGuiWindowTempData is quite tenuous and could be reconsidered.
|
||||
@ -1086,6 +1197,7 @@ struct IMGUI_API ImGuiWindow
|
||||
ImGuiCond SetWindowPosAllowFlags; // store acceptable condition flags for SetNextWindowPos() use.
|
||||
ImGuiCond SetWindowSizeAllowFlags; // store acceptable condition flags for SetNextWindowSize() use.
|
||||
ImGuiCond SetWindowCollapsedAllowFlags; // store acceptable condition flags for SetNextWindowCollapsed() use.
|
||||
ImGuiCond SetWindowDockAllowFlags; // store acceptable condition flags for SetNextWindowDock() use.
|
||||
ImVec2 SetWindowPosVal; // store window position when using a non-zero Pivot (position set needs to be processed when we know the window size)
|
||||
ImVec2 SetWindowPosPivot; // store window pivot for positioning. ImVec2(0,0) when positioning from top-left corner; ImVec2(0.5f,0.5f) for centering; ImVec2(1,1) for bottom right.
|
||||
|
||||
@ -1108,6 +1220,7 @@ struct IMGUI_API ImGuiWindow
|
||||
ImDrawList DrawListInst;
|
||||
ImGuiWindow* ParentWindow; // If we are a child _or_ popup window, this is pointing to our parent. Otherwise NULL.
|
||||
ImGuiWindow* RootWindow; // Point to ourself or first ancestor that is not a child window.
|
||||
ImGuiWindow* RootWindowDockStop; // Point to ourself or first ancestor that is not a child window. Doesn't cross through dock nodes. We use this so IsWindowFocused() can behave consistently regardless of docking state.
|
||||
ImGuiWindow* RootWindowForTitleBarHighlight; // Point to ourself or first ancestor which will display TitleBgActive color when this window is active.
|
||||
ImGuiWindow* RootWindowForNav; // Point to ourself or first ancestor which doesn't have the NavFlattened flag.
|
||||
|
||||
@ -1124,6 +1237,17 @@ struct IMGUI_API ImGuiWindow
|
||||
int FocusIdxAllRequestNext; // Item being requested for focus, for next update (relies on layout to be stable between the frame pressing TAB and the next frame)
|
||||
int FocusIdxTabRequestNext; // "
|
||||
|
||||
// Docking
|
||||
ImGuiDockNode* DockNode; // Which node are we docked into
|
||||
ImGuiDockNode* DockNodeAsHost; // Which node are we owning (for parent windows)
|
||||
ImGuiID DockId; // Backup of last valid DockNode->Id, so single value remember their dock node id
|
||||
ImGuiItemStatusFlags DockTabItemStatusFlags;
|
||||
ImRect DockTabItemRect;
|
||||
short DockOrder; // Order of the last time the window was visible within its DockNode. This is used to reorder windows that are reappearing on the same frame. Same value between windows that were active and windows that were none are possible.
|
||||
bool DockIsActive; // =~ (DockNode != NULL) && (DockNode->Windows.Size > 1)
|
||||
bool DockTabIsVisible; // Is the window visible this frame? =~ is the corresponding tab selected?
|
||||
bool DockTabWantClose;
|
||||
|
||||
public:
|
||||
ImGuiWindow(ImGuiContext* context, const char* name);
|
||||
~ImGuiWindow();
|
||||
@ -1156,6 +1280,67 @@ struct ImGuiItemHoveredDataBackup
|
||||
void Restore() const { ImGuiWindow* window = GImGui->CurrentWindow; window->DC.LastItemId = LastItemId; window->DC.LastItemStatusFlags = LastItemStatusFlags; window->DC.LastItemRect = LastItemRect; window->DC.LastItemDisplayRect = LastItemDisplayRect; }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Tab Bar, Tab Item
|
||||
//-----------------------------------------------------------------------------
|
||||
|
||||
enum ImGuiTabBarFlagsPrivate_
|
||||
{
|
||||
ImGuiTabBarFlags_DockNode = 1 << 20, // Part of a dock node
|
||||
ImGuiTabBarFlags_DockNodeExplicitRoot = 1 << 21, // Part of an explicit dock node
|
||||
ImGuiTabBarFlags_IsFocused = 1 << 22,
|
||||
ImGuiTabBarFlags_SaveSettings = 1 << 23 // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs
|
||||
};
|
||||
|
||||
enum ImGuiTabItemFlagsPrivate_
|
||||
{
|
||||
ImGuiTabItemFlags_DockedWindow = 1 << 20,
|
||||
ImGuiTabItemFlags_Preview = 1 << 21
|
||||
};
|
||||
|
||||
// Storage for one active tab item (sizeof() 32~40 bytes)
|
||||
struct ImGuiTabItem
|
||||
{
|
||||
ImGuiID ID;
|
||||
ImGuiTabItemFlags Flags;
|
||||
ImGuiWindow* Window; // When TabItem is part of a DockNode's TabBar, we hold on to a window.
|
||||
int LastFrameVisible;
|
||||
int LastFrameSelected; // This allows us to infer an ordered list of the last activated tabs with little maintenance
|
||||
float Offset; // Position relative to beginning of tab
|
||||
float Width; // Width currently displayed
|
||||
float WidthContents; // Width of actual contents, stored during BeginTabItem() call
|
||||
|
||||
ImGuiTabItem() { ID = Flags = 0; Window = NULL; LastFrameVisible = LastFrameSelected = -1; Offset = Width = WidthContents = 0.0f; }
|
||||
};
|
||||
|
||||
// Storage for a tab bar (sizeof() 92~96 bytes)
|
||||
struct ImGuiTabBar
|
||||
{
|
||||
ImVector<ImGuiTabItem> Tabs;
|
||||
ImGuiID ID; // Zero for tab-bars used by docking
|
||||
ImGuiID SelectedTabId; // Selected tab
|
||||
ImGuiID NextSelectedTabId;
|
||||
ImGuiID VisibleTabId; // Can occasionally be != SelectedTabId (e.g. when previewing contents for CTRL+TAB preview)
|
||||
ImGuiID WantFocusTabId; // Request focus for the window associated to this tab. Used and only honored by DockNode (meaningless for standalone tab bars)
|
||||
int CurrFrameVisible;
|
||||
int PrevFrameVisible;
|
||||
ImRect BarRect;
|
||||
float ContentsHeight;
|
||||
float OffsetMax; // Distance from BarRect.Min.x, locked during layout
|
||||
float OffsetNextTab; // Distance from BarRect.Min.x, incremented with each BeginTabItem() call, not used if ImGuiTabBarFlags_Reorderable if set.
|
||||
float ScrollingAnim;
|
||||
float ScrollingTarget;
|
||||
ImGuiTabBarFlags Flags;
|
||||
ImGuiID ReorderRequestTabId;
|
||||
int ReorderRequestDir;
|
||||
bool WantLayout;
|
||||
bool VisibleTabWasSubmitted;
|
||||
short LastTabItemIdx; // For BeginTabItem()/EndTabItem()
|
||||
|
||||
ImGuiTabBar();
|
||||
int GetTabOrder(const ImGuiTabItem* tab) const { return Tabs.index_from_pointer(tab); }
|
||||
};
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// Internal API
|
||||
// No guarantee of forward compatibility here.
|
||||
@ -1169,6 +1354,7 @@ namespace ImGui
|
||||
// - You are calling ImGui functions after ImGui::EndFrame()/ImGui::Render() and before the next ImGui::NewFrame(), which is also illegal.
|
||||
inline ImGuiWindow* GetCurrentWindowRead() { ImGuiContext& g = *GImGui; return g.CurrentWindow; }
|
||||
inline ImGuiWindow* GetCurrentWindow() { ImGuiContext& g = *GImGui; g.CurrentWindow->WriteAccessed = true; return g.CurrentWindow; }
|
||||
IMGUI_API ImGuiWindow* FindWindowByID(ImGuiID id);
|
||||
IMGUI_API ImGuiWindow* FindWindowByName(const char* name);
|
||||
IMGUI_API void FocusWindow(ImGuiWindow* window); // FIXME: Rename to SetWindowFocus()
|
||||
IMGUI_API void FocusFrontMostActiveWindowIgnoringOne(ImGuiWindow* ignore_window);
|
||||
@ -1265,6 +1451,20 @@ namespace ImGui
|
||||
inline bool IsNavInputDown(ImGuiNavInput n) { return GImGui->IO.NavInputs[n] > 0.0f; }
|
||||
inline bool IsNavInputPressed(ImGuiNavInput n, ImGuiInputReadMode mode) { return GetNavInputAmount(n, mode) > 0.0f; }
|
||||
inline bool IsNavInputPressedAnyOfTwo(ImGuiNavInput n1, ImGuiNavInput n2, ImGuiInputReadMode mode) { return (GetNavInputAmount(n1, mode) + GetNavInputAmount(n2, mode)) > 0.0f; }
|
||||
|
||||
// Docking
|
||||
IMGUI_API void DockContextInitialize(ImGuiContext* imgui_context);
|
||||
IMGUI_API void DockContextShutdown(ImGuiContext* imgui_context);
|
||||
IMGUI_API void DockContextOnLoadSettings();
|
||||
IMGUI_API void DockContextRebuild(ImGuiDockContext* ctx);
|
||||
IMGUI_API void DockContextUpdateUndocking(ImGuiDockContext* ctx);
|
||||
IMGUI_API void DockContextUpdateDocking(ImGuiDockContext* ctx);
|
||||
IMGUI_API void DockContextQueueUndock(ImGuiDockContext* ctx, ImGuiWindow* window);
|
||||
IMGUI_API void BeginDocked(ImGuiWindow* window, bool* p_open);
|
||||
IMGUI_API void BeginAsDockableDragDropSource(ImGuiWindow* window);
|
||||
IMGUI_API void BeginAsDockableDragDropTarget(ImGuiWindow* window);
|
||||
IMGUI_API void SetWindowDock(ImGuiWindow* window, ImGuiID dock_id, ImGuiCond cond);
|
||||
IMGUI_API void ShowDockingDebug();
|
||||
|
||||
// Drag and Drop
|
||||
IMGUI_API bool BeginDragDropTargetCustom(const ImRect& bb, ImGuiID id);
|
||||
@ -1276,12 +1476,25 @@ namespace ImGui
|
||||
IMGUI_API void EndColumns(); // close columns
|
||||
IMGUI_API void PushColumnClipRect(int column_index = -1);
|
||||
|
||||
// Tab Bars
|
||||
IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags, ImGuiDockNode* dock_node);
|
||||
IMGUI_API ImGuiTabItem* TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id);
|
||||
IMGUI_API void TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiWindow* window);
|
||||
IMGUI_API void TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id);
|
||||
IMGUI_API void TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);
|
||||
IMGUI_API void TabBarQueueChangeTabOrder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir);
|
||||
IMGUI_API bool TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window);
|
||||
IMGUI_API ImVec2 TabItemCalcSize(const char* label, bool has_close_button);
|
||||
IMGUI_API void TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col);
|
||||
IMGUI_API bool TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, const char* label, ImGuiID tab_id, ImGuiID close_button_id);
|
||||
|
||||
// Render helpers
|
||||
// AVOID USING OUTSIDE OF IMGUI.CPP! NOT FOR PUBLIC CONSUMPTION. THOSE FUNCTIONS ARE A MESS. THEIR SIGNATURE AND BEHAVIOR WILL CHANGE, THEY NEED TO BE REFACTORED INTO SOMETHING DECENT.
|
||||
// NB: All position are in absolute pixels coordinates (we are never using window coordinates internally)
|
||||
IMGUI_API void RenderText(ImVec2 pos, const char* text, const char* text_end = NULL, bool hide_text_after_hash = true);
|
||||
IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width);
|
||||
IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0,0), const ImRect* clip_rect = NULL);
|
||||
IMGUI_API void RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL);
|
||||
IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f);
|
||||
IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f);
|
||||
IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, int rounding_corners_flags = ~0);
|
||||
@ -1295,7 +1508,10 @@ namespace ImGui
|
||||
|
||||
// Render helpers (those functions don't access any ImGui state!)
|
||||
IMGUI_API void RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col);
|
||||
IMGUI_API void RenderArrowDockMenu(ImDrawList* draw_list, ImVec2 p_min, float sz, ImU32 col);
|
||||
IMGUI_API void RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding);
|
||||
IMGUI_API void RenderRectFilledWithHole(ImDrawList* draw_list, ImRect outer, ImRect inner, ImU32 col, float rounding);
|
||||
IMGUI_API void RenderPixelEllipsis(ImDrawList* draw_list, ImFont* font, ImVec2 pos, int count, ImU32 col);
|
||||
|
||||
// Widgets
|
||||
IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), ImGuiButtonFlags flags = 0);
|
||||
|
@ -22,6 +22,8 @@ Index of this file:
|
||||
// [SECTION] Widgets: PlotLines, PlotHistogram
|
||||
// [SECTION] Widgets: Value helpers
|
||||
// [SECTION] Widgets: MenuItem, BeginMenu, EndMenu, etc.
|
||||
// [SECTION] Widgets: BeginTabBar, EndTabBar, etc.
|
||||
// [SECTION] Widgets: BeginTabItem, EndTabItem, etc.
|
||||
|
||||
*/
|
||||
|
||||
@ -677,10 +679,16 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos)
|
||||
bool hovered, held;
|
||||
bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_None);
|
||||
|
||||
bool is_dock_menu = (window->DockNodeAsHost && !window->Collapsed);
|
||||
ImVec2 off = is_dock_menu ? ImVec2((float)(int)(-g.Style.ItemInnerSpacing.x * 0.5f) + 0.5f, 0.0f) : ImVec2(0.0f, 0.0f);
|
||||
ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
|
||||
if (hovered || held)
|
||||
window->DrawList->AddCircleFilled(bb.GetCenter() + ImVec2(0.0f, -0.5f), g.FontSize * 0.5f + 1.0f, col, 9);
|
||||
RenderArrow(bb.Min + g.Style.FramePadding, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f);
|
||||
window->DrawList->AddCircleFilled(bb.GetCenter() + off + ImVec2(0,-0.5f), g.FontSize * 0.5f + 1.0f, col, 9);
|
||||
|
||||
if (is_dock_menu)
|
||||
RenderArrowDockMenu(window->DrawList, bb.Min + g.Style.FramePadding, g.FontSize, GetColorU32(ImGuiCol_Text));
|
||||
else
|
||||
RenderArrow(bb.Min + g.Style.FramePadding, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f);
|
||||
|
||||
// Switch to moving the window after mouse is moved beyond the initial drag threshold
|
||||
if (IsItemActive() && IsMouseDragging())
|
||||
@ -5430,7 +5438,7 @@ bool ImGui::BeginMainMenuBar()
|
||||
SetNextWindowSize(ImVec2(g.Viewports[0]->Size.x, g.NextWindowData.MenuBarOffsetMinVal.y + g.FontBaseSize + g.Style.FramePadding.y));
|
||||
PushStyleVar(ImGuiStyleVar_WindowRounding, 0.0f);
|
||||
PushStyleVar(ImGuiStyleVar_WindowMinSize, ImVec2(0,0));
|
||||
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar;
|
||||
ImGuiWindowFlags window_flags = ImGuiWindowFlags_NoDocking | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoScrollbar | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_MenuBar;
|
||||
bool is_open = Begin("##MainMenuBar", NULL, window_flags) && BeginMenuBar();
|
||||
PopStyleVar(2);
|
||||
g.NextWindowData.MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f);
|
||||
@ -5724,3 +5732,912 @@ bool ImGui::MenuItem(const char* label, const char* shortcut, bool* p_selected,
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// [SECTION] Widgets: BeginTabBar, EndTabBar, etc.
|
||||
//-------------------------------------------------------------------------
|
||||
// - BeginTabBar()
|
||||
// - BeginTabBarEx() [Internal]
|
||||
// - EndTabBar()
|
||||
// - TabBarLayout() [Internal]
|
||||
// - TabBarCalcTabID() [Internal]
|
||||
// - TabBarCalcMaxTabWidth() [Internal]
|
||||
// - TabBarFindTabById() [Internal]
|
||||
// - TabBarAddTab() [Internal]
|
||||
// - TabBarRemoveTab() [Internal]
|
||||
// - TabBarCloseTab() [Internal]
|
||||
// - TabBarScrollClamp()v
|
||||
// - TabBarScrollToTab() [Internal]
|
||||
// - TabBarQueueChangeTabOrder() [Internal]
|
||||
// - TabBarScrollingButtons() [Internal]
|
||||
// - TabBarTabListPopupButton() [Internal]
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
namespace ImGui
|
||||
{
|
||||
static void TabBarLayout(ImGuiTabBar* tab_bar);
|
||||
static ImU32 TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label);
|
||||
static float TabBarCalcMaxTabWidth();
|
||||
static float TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling);
|
||||
static void TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab);
|
||||
static ImGuiTabItem* TabBarScrollingButtons(ImGuiTabBar* tab_bar);
|
||||
static ImGuiTabItem* TabBarTabListPopupButton(ImGuiTabBar* tab_bar);
|
||||
}
|
||||
|
||||
ImGuiTabBar::ImGuiTabBar()
|
||||
{
|
||||
ID = 0;
|
||||
SelectedTabId = NextSelectedTabId = VisibleTabId = WantFocusTabId = 0;
|
||||
CurrFrameVisible = PrevFrameVisible = -1;
|
||||
OffsetMax = OffsetNextTab = 0.0f;
|
||||
ScrollingAnim = ScrollingTarget = 0.0f;
|
||||
Flags = ImGuiTabBarFlags_None;
|
||||
ReorderRequestTabId = 0;
|
||||
ReorderRequestDir = 0;
|
||||
WantLayout = VisibleTabWasSubmitted = false;
|
||||
LastTabItemIdx = -1;
|
||||
}
|
||||
|
||||
static int IMGUI_CDECL TabItemComparerByVisibleOffset(const void* lhs, const void* rhs)
|
||||
{
|
||||
const ImGuiTabItem* a = (const ImGuiTabItem*)lhs;
|
||||
const ImGuiTabItem* b = (const ImGuiTabItem*)rhs;
|
||||
return (int)(a->Offset - b->Offset);
|
||||
}
|
||||
|
||||
static int IMGUI_CDECL TabBarSortItemComparer(const void* lhs, const void* rhs)
|
||||
{
|
||||
const ImGuiTabBarSortItem* a = (const ImGuiTabBarSortItem*)lhs;
|
||||
const ImGuiTabBarSortItem* b = (const ImGuiTabBarSortItem*)rhs;
|
||||
if (int d = (int)(b->Width - a->Width))
|
||||
return d;
|
||||
return (b->Index - a->Index);
|
||||
}
|
||||
|
||||
bool ImGui::BeginTabBar(const char* str_id, ImGuiTabBarFlags flags)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
if (window->SkipItems)
|
||||
return false;
|
||||
|
||||
ImGuiID id = window->GetID(str_id);
|
||||
ImGuiTabBar* tab_bar = g.TabBars.GetOrAddByKey(id);
|
||||
ImRect tab_bar_bb = ImRect(window->DC.CursorPos.x, window->DC.CursorPos.y, window->InnerClipRect.Max.x, window->DC.CursorPos.y + g.FontSize + g.Style.FramePadding.y * 2);
|
||||
tab_bar->ID = id;
|
||||
return BeginTabBarEx(tab_bar, tab_bar_bb, flags | ImGuiTabBarFlags_IsFocused, NULL);
|
||||
}
|
||||
|
||||
bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImGuiTabBarFlags flags, ImGuiDockNode* dock_node)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
if (window->SkipItems)
|
||||
return false;
|
||||
|
||||
if ((flags & ImGuiTabBarFlags_DockNode) == 0)
|
||||
window->IDStack.push_back(tab_bar->ID);
|
||||
|
||||
g.CurrentTabBar.push_back(tab_bar);
|
||||
if (tab_bar->CurrFrameVisible == g.FrameCount)
|
||||
{
|
||||
printf("[%05d] BeginTabBarEx already called this frame\n", g.FrameCount);
|
||||
//IM_ASSERT(0);
|
||||
return true;
|
||||
}
|
||||
|
||||
// When toggling back from ordered to manually-reorderable, shuffle tabs to enforce the last visible order.
|
||||
// Otherwise, the most recently inserted tabs would move at the end of visible list which can be a little too confusing or magic for the user.
|
||||
if ((flags & ImGuiTabBarFlags_Reorderable) && !(tab_bar->Flags & ImGuiTabBarFlags_Reorderable) && tab_bar->Tabs.Size > 1 && tab_bar->PrevFrameVisible != -1)
|
||||
ImQsort(tab_bar->Tabs.Data, tab_bar->Tabs.Size, sizeof(ImGuiTabItem), TabItemComparerByVisibleOffset);
|
||||
|
||||
// Flags
|
||||
if ((flags & ImGuiTabBarFlags_FittingPolicyMask_) == 0)
|
||||
flags |= ImGuiTabBarFlags_FittingPolicyDefault_;
|
||||
|
||||
tab_bar->Flags = flags;
|
||||
tab_bar->BarRect = tab_bar_bb;
|
||||
tab_bar->WantLayout = true; // Layout will be done on the first call to ItemTab()
|
||||
tab_bar->PrevFrameVisible = tab_bar->CurrFrameVisible;
|
||||
tab_bar->CurrFrameVisible = g.FrameCount;
|
||||
|
||||
// Layout
|
||||
ItemSize(ImVec2(tab_bar->OffsetMax, tab_bar->BarRect.GetHeight()));
|
||||
window->DC.CursorPos.x = tab_bar->BarRect.Min.x;
|
||||
|
||||
// Draw separator
|
||||
const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_Tab);
|
||||
const float y = tab_bar->BarRect.Max.y - 1.0f;
|
||||
if (dock_node != NULL)
|
||||
{
|
||||
const float separator_min_x = dock_node->Pos.x;
|
||||
const float separator_max_x = dock_node->Pos.x + dock_node->Size.x;
|
||||
window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f);
|
||||
}
|
||||
else
|
||||
{
|
||||
const float separator_min_x = tab_bar->BarRect.Min.x - ((flags & ImGuiTabBarFlags_DockNodeExplicitRoot) ? 0.0f : window->WindowPadding.x);
|
||||
const float separator_max_x = tab_bar->BarRect.Max.x + ((flags & ImGuiTabBarFlags_DockNodeExplicitRoot) ? 0.0f : window->WindowPadding.x);
|
||||
window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
void ImGui::EndTabBar()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
if (window->SkipItems)
|
||||
return;
|
||||
|
||||
IM_ASSERT(!g.CurrentTabBar.empty()); // Mismatched BeginTabBar/EndTabBar
|
||||
ImGuiTabBar* tab_bar = g.CurrentTabBar.back();
|
||||
if (tab_bar->WantLayout)
|
||||
TabBarLayout(tab_bar);
|
||||
|
||||
// Restore the last visible height if no tab is visible, this reduce vertical flicker/movement when a tabs gets removed without calling SetTabItemClosed().
|
||||
const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount);
|
||||
if (tab_bar->VisibleTabWasSubmitted || tab_bar->VisibleTabId == 0 || tab_bar_appearing)
|
||||
tab_bar->ContentsHeight = ImMax(window->DC.CursorPos.y - tab_bar->BarRect.Max.y, 0.0f);
|
||||
else
|
||||
window->DC.CursorPos.y = tab_bar->BarRect.Max.y + tab_bar->ContentsHeight;
|
||||
|
||||
if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0)
|
||||
PopID();
|
||||
g.CurrentTabBar.pop_back();
|
||||
}
|
||||
|
||||
// This is called only once a frame before by the first call to ItemTab()
|
||||
// The reason we're not calling it in BeginTabBar() is to leave a chance to the user to call the SetTabItemClosed() functions.
|
||||
static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
tab_bar->WantLayout = false;
|
||||
|
||||
// Garbage collect
|
||||
int tab_dst_n = 0;
|
||||
for (int tab_src_n = 0; tab_src_n < tab_bar->Tabs.Size; tab_src_n++)
|
||||
{
|
||||
ImGuiTabItem* tab = &tab_bar->Tabs[tab_src_n];
|
||||
if (tab->LastFrameVisible < tab_bar->PrevFrameVisible)
|
||||
{
|
||||
if (tab->ID == tab_bar->SelectedTabId)
|
||||
tab_bar->SelectedTabId = 0;
|
||||
continue;
|
||||
}
|
||||
if (tab_dst_n != tab_src_n)
|
||||
tab_bar->Tabs[tab_dst_n] = tab_bar->Tabs[tab_src_n];
|
||||
tab_dst_n++;
|
||||
}
|
||||
if (tab_bar->Tabs.Size != tab_dst_n)
|
||||
tab_bar->Tabs.resize(tab_dst_n);
|
||||
|
||||
// Setup next selected tab
|
||||
ImGuiID scroll_track_selected_tab_id = 0;
|
||||
tab_bar->WantFocusTabId = 0;
|
||||
if (tab_bar->NextSelectedTabId)
|
||||
{
|
||||
tab_bar->SelectedTabId = tab_bar->WantFocusTabId = tab_bar->NextSelectedTabId;
|
||||
tab_bar->NextSelectedTabId = 0;
|
||||
scroll_track_selected_tab_id = tab_bar->SelectedTabId;
|
||||
}
|
||||
|
||||
// Process order change request (we could probably process it when requested but it's just saner to do it in a single spot).
|
||||
if (tab_bar->ReorderRequestTabId != 0)
|
||||
{
|
||||
if (ImGuiTabItem* tab1 = TabBarFindTabByID(tab_bar, tab_bar->ReorderRequestTabId))
|
||||
{
|
||||
IM_ASSERT(tab_bar->Flags & ImGuiTabBarFlags_Reorderable);
|
||||
int tab2_order = tab_bar->GetTabOrder(tab1) + tab_bar->ReorderRequestDir;
|
||||
if (tab2_order >= 0 && tab2_order < tab_bar->Tabs.Size)
|
||||
{
|
||||
ImGuiTabItem* tab2 = &tab_bar->Tabs[tab2_order];
|
||||
ImGuiTabItem item_tmp = *tab1;
|
||||
*tab1 = *tab2;
|
||||
*tab2 = item_tmp;
|
||||
if (tab2->ID == tab_bar->SelectedTabId)
|
||||
scroll_track_selected_tab_id = tab2->ID;
|
||||
tab1 = tab2 = NULL;
|
||||
}
|
||||
if (tab_bar->Flags & ImGuiTabBarFlags_SaveSettings)
|
||||
MarkIniSettingsDirty();
|
||||
}
|
||||
tab_bar->ReorderRequestTabId = 0;
|
||||
}
|
||||
|
||||
ImVector<ImGuiTabBarSortItem>& width_sort_buffer = g.TabSortByWidthBuffer;
|
||||
width_sort_buffer.resize(tab_bar->Tabs.Size);
|
||||
|
||||
// Compute ideal widths
|
||||
float width_total_contents = 0.0f;
|
||||
ImGuiTabItem* most_recently_selected_tab = NULL;
|
||||
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
|
||||
{
|
||||
ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
|
||||
IM_ASSERT(tab->LastFrameVisible >= tab_bar->PrevFrameVisible);
|
||||
|
||||
if (most_recently_selected_tab == NULL || most_recently_selected_tab->LastFrameSelected < tab->LastFrameSelected)
|
||||
most_recently_selected_tab = tab;
|
||||
|
||||
// Refresh tab width immediately if we can (for manual tab bar, WidthContent will lag by one frame which is mostly noticeable when changing style.FramePadding.x)
|
||||
// Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet,
|
||||
// and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window.
|
||||
if (tab->Window)
|
||||
tab->WidthContents = TabItemCalcSize(tab->Window->Name, tab->Window->HasCloseButton).x;
|
||||
width_total_contents += (tab_n > 0 ? g.Style.ItemInnerSpacing.x : 0.0f) + tab->WidthContents;
|
||||
|
||||
// Store data so we can build an array sorted by width if we need to shrink tabs down
|
||||
width_sort_buffer[tab_n].Index = tab_n;
|
||||
width_sort_buffer[tab_n].Width = tab->WidthContents;
|
||||
}
|
||||
|
||||
// Compute width
|
||||
const float width_avail = tab_bar->BarRect.GetWidth();
|
||||
float width_excess = (width_avail < width_total_contents) ? (width_total_contents - width_avail) : 0.0f;
|
||||
if (width_excess > 0.0f && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown))
|
||||
{
|
||||
// If we don't have enough room, resize down the largest tabs first
|
||||
if (tab_bar->Tabs.Size > 1)
|
||||
ImQsort(width_sort_buffer.Data, (size_t)width_sort_buffer.Size, sizeof(ImGuiTabBarSortItem), TabBarSortItemComparer);
|
||||
int tab_count_same_width = 1;
|
||||
while (width_excess > 0.0f && tab_count_same_width < tab_bar->Tabs.Size)
|
||||
{
|
||||
while (tab_count_same_width < tab_bar->Tabs.Size && width_sort_buffer[0].Width == width_sort_buffer[tab_count_same_width].Width)
|
||||
tab_count_same_width++;
|
||||
float width_to_remove_per_tab_max = (tab_count_same_width < tab_bar->Tabs.Size) ? (width_sort_buffer[0].Width - width_sort_buffer[tab_count_same_width].Width) : (width_sort_buffer[0].Width - 1.0f);
|
||||
float width_to_remove_per_tab = ImMin(width_excess / tab_count_same_width, width_to_remove_per_tab_max);
|
||||
for (int tab_n = 0; tab_n < tab_count_same_width; tab_n++)
|
||||
width_sort_buffer[tab_n].Width -= width_to_remove_per_tab;
|
||||
width_excess -= width_to_remove_per_tab * tab_count_same_width;
|
||||
}
|
||||
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
|
||||
tab_bar->Tabs[width_sort_buffer[tab_n].Index].Width = (float)(int)width_sort_buffer[tab_n].Width;
|
||||
}
|
||||
else
|
||||
{
|
||||
const float tab_max_width = TabBarCalcMaxTabWidth();
|
||||
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
|
||||
{
|
||||
ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
|
||||
tab->Width = ImMin(tab->WidthContents, tab_max_width);
|
||||
}
|
||||
}
|
||||
|
||||
// Layout all active tabs
|
||||
float offset_x = 0.0f;
|
||||
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
|
||||
{
|
||||
ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
|
||||
tab->Offset = offset_x;
|
||||
if (scroll_track_selected_tab_id == 0 && g.NavJustMovedToId == tab->ID)
|
||||
scroll_track_selected_tab_id = tab->ID;
|
||||
offset_x += tab->Width + g.Style.ItemInnerSpacing.x;
|
||||
}
|
||||
tab_bar->OffsetMax = ImMax(offset_x - g.Style.ItemInnerSpacing.x, 0.0f);
|
||||
tab_bar->OffsetNextTab = 0.0f;
|
||||
|
||||
// Tab List Popup
|
||||
const bool tab_list_popup_button = (tab_bar->Flags & ImGuiTabBarFlags_DockNode) != 0 && (tab_bar->Flags & ImGuiTabBarFlags_NoTabListPopupButton) == 0;
|
||||
if (tab_list_popup_button)
|
||||
if (ImGuiTabItem* tab_to_select = TabBarTabListPopupButton(tab_bar)) // NB: Will alter BarRect.Max.x!
|
||||
scroll_track_selected_tab_id = tab_bar->SelectedTabId = tab_to_select->ID;
|
||||
|
||||
// Horizontal scrolling buttons
|
||||
const bool scrolling_buttons = (tab_bar->OffsetMax > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll);
|
||||
if (scrolling_buttons)
|
||||
if (ImGuiTabItem* tab_to_select = TabBarScrollingButtons(tab_bar)) // NB: Will alter BarRect.Max.x!
|
||||
scroll_track_selected_tab_id = tab_bar->SelectedTabId = tab_to_select->ID;
|
||||
|
||||
// If we have lost the selected tab, select the next most recently active one.
|
||||
if (tab_bar->SelectedTabId == 0 && tab_bar->NextSelectedTabId == 0 && most_recently_selected_tab != NULL)
|
||||
scroll_track_selected_tab_id = tab_bar->SelectedTabId = most_recently_selected_tab->ID;
|
||||
|
||||
// Lock in visible tab
|
||||
tab_bar->VisibleTabId = tab_bar->SelectedTabId;
|
||||
tab_bar->VisibleTabWasSubmitted = false;
|
||||
|
||||
// CTRL+TAB can override visible tab temporarily
|
||||
if (g.NavWindowingTarget != NULL && g.NavWindowingTarget->DockNode && g.NavWindowingTarget->DockNode->TabBar == tab_bar)
|
||||
tab_bar->VisibleTabId = scroll_track_selected_tab_id = g.NavWindowingTarget->ID;
|
||||
|
||||
// Update scrolling
|
||||
if (scroll_track_selected_tab_id)
|
||||
if (ImGuiTabItem* scroll_track_selected_tab = TabBarFindTabByID(tab_bar, scroll_track_selected_tab_id))
|
||||
TabBarScrollToTab(tab_bar, scroll_track_selected_tab);
|
||||
tab_bar->ScrollingAnim = TabBarScrollClamp(tab_bar, tab_bar->ScrollingAnim);
|
||||
tab_bar->ScrollingTarget = TabBarScrollClamp(tab_bar, tab_bar->ScrollingTarget);
|
||||
const float scrolling_speed = (tab_bar->PrevFrameVisible + 1 < g.FrameCount) ? FLT_MAX : (g.IO.DeltaTime * g.FontSize * 70.0f);
|
||||
if (tab_bar->ScrollingAnim != tab_bar->ScrollingTarget)
|
||||
tab_bar->ScrollingAnim = ImLinearSweep(tab_bar->ScrollingAnim, tab_bar->ScrollingTarget, scrolling_speed);
|
||||
}
|
||||
|
||||
// Dockables uses Name/ID in the global namespace. Non-dockable items use the ID stack.
|
||||
static ImU32 ImGui::TabBarCalcTabID(ImGuiTabBar* tab_bar, const char* label)
|
||||
{
|
||||
if (tab_bar->Flags & ImGuiTabBarFlags_DockNode)
|
||||
{
|
||||
ImGuiID id = ImHash(label, 0);
|
||||
KeepAliveID(id);
|
||||
return id;
|
||||
}
|
||||
else
|
||||
{
|
||||
ImGuiWindow* window = GImGui->CurrentWindow;
|
||||
return window->GetID(label);
|
||||
}
|
||||
}
|
||||
|
||||
static float ImGui::TabBarCalcMaxTabWidth()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
return g.FontSize * 20.0f;
|
||||
}
|
||||
|
||||
ImGuiTabItem* ImGui::TabBarFindTabByID(ImGuiTabBar* tab_bar, ImGuiID tab_id)
|
||||
{
|
||||
if (tab_id != 0)
|
||||
for (int n = 0; n < tab_bar->Tabs.Size; n++)
|
||||
if (tab_bar->Tabs[n].ID == tab_id)
|
||||
return &tab_bar->Tabs[n];
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// The purpose of this call is to register tab in advance so we can control their order at the time they appear.
|
||||
// Otherwise calling this is unnecessary as tabs are appending as needed by the BeginTabItem() function.
|
||||
void ImGui::TabBarAddTab(ImGuiTabBar* tab_bar, ImGuiWindow* window)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
IM_ASSERT(TabBarFindTabByID(tab_bar, window->ID) == NULL);
|
||||
IM_ASSERT(g.CurrentTabBar.empty()); // Can't work while the tab bar is active as our tab doesn't have an X offset yet
|
||||
|
||||
ImGuiTabItem new_tab;
|
||||
new_tab.ID = window->ID;
|
||||
new_tab.LastFrameVisible = tab_bar->CurrFrameVisible; // Required so BeginTabBar doesn't ditch the tab
|
||||
if (new_tab.LastFrameVisible == -1)
|
||||
new_tab.LastFrameVisible = g.FrameCount - 1;
|
||||
new_tab.Window = window; // Required so tab bar layout can compute the tab width before tab submission
|
||||
if (tab_bar->Tabs.empty())
|
||||
tab_bar->Tabs.push_back(new_tab);
|
||||
else
|
||||
tab_bar->Tabs.insert(tab_bar->Tabs.Data + tab_bar->Tabs.Size, new_tab);
|
||||
}
|
||||
|
||||
// The *TabId fields be already set by the docking system _before_ the actual TabItem was created, so we clear them regardless.
|
||||
void ImGui::TabBarRemoveTab(ImGuiTabBar* tab_bar, ImGuiID tab_id)
|
||||
{
|
||||
if (ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, tab_id))
|
||||
tab_bar->Tabs.erase(tab);
|
||||
if (tab_bar->VisibleTabId == tab_id) { tab_bar->VisibleTabId = 0; }
|
||||
if (tab_bar->WantFocusTabId == tab_id) { tab_bar->WantFocusTabId = 0; }
|
||||
if (tab_bar->SelectedTabId == tab_id) { tab_bar->SelectedTabId = 0; }
|
||||
if (tab_bar->NextSelectedTabId == tab_id) { tab_bar->NextSelectedTabId = 0; }
|
||||
}
|
||||
|
||||
void ImGui::TabBarCloseTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
|
||||
{
|
||||
if ((tab_bar->VisibleTabId == tab->ID) && !(tab->Flags & ImGuiTabItemFlags_UnsavedDocument))
|
||||
{
|
||||
// This will remove a frame of lag for selecting another tab on closure.
|
||||
// However we don't run it in the case where the 'Unsaved' flag is set, so user gets a chance to fully undo the closure
|
||||
tab->LastFrameVisible = -1;
|
||||
tab_bar->SelectedTabId = tab_bar->NextSelectedTabId = 0;
|
||||
}
|
||||
else if ((tab_bar->VisibleTabId != tab->ID) && (tab->Flags & ImGuiTabItemFlags_UnsavedDocument))
|
||||
{
|
||||
// Actually select before expecting closure
|
||||
tab_bar->NextSelectedTabId = tab->ID;
|
||||
}
|
||||
}
|
||||
|
||||
static float ImGui::TabBarScrollClamp(ImGuiTabBar* tab_bar, float scrolling)
|
||||
{
|
||||
scrolling = ImMin(scrolling, tab_bar->OffsetMax - tab_bar->BarRect.GetWidth());
|
||||
return ImMax(scrolling, 0.0f);
|
||||
}
|
||||
|
||||
static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
float margin = g.FontSize * 1.0f; // When to scroll to make Tab N+1 visible always make a bit of N visible to suggest more scrolling area (since we don't have a scrollbar)
|
||||
int order = tab_bar->GetTabOrder(tab);
|
||||
float tab_x1 = tab->Offset + (order > 0 ? -margin : 0.0f);
|
||||
float tab_x2 = tab->Offset + tab->Width + (order + 1 < tab_bar->Tabs.Size ? margin : 1.0f);
|
||||
if (tab_bar->ScrollingTarget > tab_x1)
|
||||
tab_bar->ScrollingTarget = tab_x1;
|
||||
if (tab_bar->ScrollingTarget + tab_bar->BarRect.GetWidth() < tab_x2)
|
||||
tab_bar->ScrollingTarget = tab_x2 - tab_bar->BarRect.GetWidth();
|
||||
}
|
||||
|
||||
void ImGui::TabBarQueueChangeTabOrder(ImGuiTabBar* tab_bar, const ImGuiTabItem* tab, int dir)
|
||||
{
|
||||
IM_ASSERT(dir == -1 || dir == +1);
|
||||
IM_ASSERT(tab_bar->ReorderRequestTabId == 0);
|
||||
tab_bar->ReorderRequestTabId = tab->ID;
|
||||
tab_bar->ReorderRequestDir = dir;
|
||||
}
|
||||
|
||||
static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
|
||||
const ImVec2 arrow_button_size(g.FontSize - 2.0f, g.FontSize + g.Style.FramePadding.y * 2.0f);
|
||||
const float scrolling_buttons_width = arrow_button_size.x * 2.0f;
|
||||
|
||||
const ImVec2 backup_cursor_pos = window->DC.CursorPos;
|
||||
//window->DrawList->AddRect(ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width, tab_bar->BarRect.Min.y), ImVec2(tab_bar->BarRect.Max.x, tab_bar->BarRect.Max.y), IM_COL32(255,0,0,255));
|
||||
|
||||
const ImRect avail_bar_rect = tab_bar->BarRect;
|
||||
bool want_clip_rect = !avail_bar_rect.Contains(ImRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(scrolling_buttons_width, 0.0f)));
|
||||
if (want_clip_rect)
|
||||
PushClipRect(tab_bar->BarRect.Min, tab_bar->BarRect.Max + ImVec2(g.Style.ItemInnerSpacing.x, 0.0f), true);
|
||||
|
||||
ImGuiTabItem* tab_to_select = NULL;
|
||||
|
||||
int select_dir = 0;
|
||||
ImVec4 arrow_col = g.Style.Colors[ImGuiCol_Text];
|
||||
arrow_col.w *= 0.5f;
|
||||
|
||||
PushStyleColor(ImGuiCol_Text, arrow_col);
|
||||
PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
|
||||
const float backup_repeat_delay = g.IO.KeyRepeatDelay;
|
||||
const float backup_repeat_rate = g.IO.KeyRepeatRate;
|
||||
g.IO.KeyRepeatDelay = 0.250f;
|
||||
g.IO.KeyRepeatRate = 0.200f;
|
||||
window->DC.CursorPos = ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width, tab_bar->BarRect.Min.y);
|
||||
if (ArrowButtonEx("##<", ImGuiDir_Left, arrow_button_size, ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_Repeat))
|
||||
select_dir = -1;
|
||||
window->DC.CursorPos = ImVec2(tab_bar->BarRect.Max.x - scrolling_buttons_width + arrow_button_size.x, tab_bar->BarRect.Min.y);
|
||||
if (ArrowButtonEx("##>", ImGuiDir_Right, arrow_button_size, ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_Repeat))
|
||||
select_dir = +1;
|
||||
PopStyleColor(2);
|
||||
g.IO.KeyRepeatRate = backup_repeat_rate;
|
||||
g.IO.KeyRepeatDelay = backup_repeat_delay;
|
||||
|
||||
if (want_clip_rect)
|
||||
PopClipRect();
|
||||
|
||||
if (select_dir != 0)
|
||||
if (ImGuiTabItem* tab_item = TabBarFindTabByID(tab_bar, tab_bar->SelectedTabId))
|
||||
{
|
||||
int selected_order = tab_bar->GetTabOrder(tab_item);
|
||||
int target_order = selected_order + select_dir;
|
||||
tab_to_select = &tab_bar->Tabs[(target_order >= 0 && target_order < tab_bar->Tabs.Size) ? target_order : selected_order]; // If we are at the end of the list, still scroll to make our tab visible
|
||||
}
|
||||
window->DC.CursorPos = backup_cursor_pos;
|
||||
tab_bar->BarRect.Max.x -= scrolling_buttons_width + 1.0f;
|
||||
|
||||
return tab_to_select;
|
||||
}
|
||||
|
||||
// FIXME-DOCK: Unused by Docking system
|
||||
static ImGuiTabItem* ImGui::TabBarTabListPopupButton(ImGuiTabBar* tab_bar)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
|
||||
const float tab_list_popup_button_width = g.FontSize + g.Style.FramePadding.y * 2.0f;
|
||||
const ImVec2 backup_cursor_pos = window->DC.CursorPos;
|
||||
tab_bar->BarRect.Max.x -= tab_list_popup_button_width;
|
||||
if (window->HasCloseButton)
|
||||
tab_bar->BarRect.Max.x += g.Style.ItemInnerSpacing.x;
|
||||
window->DC.CursorPos = ImVec2(tab_bar->BarRect.Max.x, tab_bar->BarRect.Min.y);
|
||||
|
||||
ImVec4 arrow_col = g.Style.Colors[ImGuiCol_Text];
|
||||
arrow_col.w *= 0.5f;
|
||||
PushStyleColor(ImGuiCol_Text, arrow_col);
|
||||
PushStyleColor(ImGuiCol_Button, ImVec4(0, 0, 0, 0));
|
||||
bool open = BeginCombo("##v", NULL, ImGuiComboFlags_NoPreview | ImGuiComboFlags_PopupAlignLeft);
|
||||
PopStyleColor(2);
|
||||
|
||||
ImGuiTabItem* tab_to_select = NULL;
|
||||
if (open)
|
||||
{
|
||||
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
|
||||
{
|
||||
ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
|
||||
IM_ASSERT(tab->Window != NULL);
|
||||
if (MenuItem(tab->Window->Name))
|
||||
tab_to_select = tab;
|
||||
}
|
||||
EndCombo();
|
||||
}
|
||||
|
||||
window->DC.CursorPos = backup_cursor_pos;
|
||||
return tab_to_select;
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// [SECTION] Widgets: BeginTabItem, EndTabItem, etc.
|
||||
//-------------------------------------------------------------------------
|
||||
// - BeginTabItem()
|
||||
// - EndTabItem()
|
||||
// - TabItemEx() [Internal]
|
||||
// - SetTabItemClosed()
|
||||
// - TabItemCalcSize() [Internal]
|
||||
// - TabItemRenderBackground() [Internal]
|
||||
// - TabItemLabelAndCloseButton() [Internal]
|
||||
//-------------------------------------------------------------------------
|
||||
|
||||
bool ImGui::BeginTabItem(const char* label, bool* p_open, ImGuiTabItemFlags flags)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
if (g.CurrentWindow->SkipItems)
|
||||
return false;
|
||||
|
||||
IM_ASSERT(g.CurrentTabBar.Size > 0 && "Needs to be called between BeginTabBar() and EndTabBar()!");
|
||||
ImGuiTabBar* tab_bar = g.CurrentTabBar.back();
|
||||
bool ret = TabItemEx(tab_bar, label, p_open, flags, NULL);
|
||||
if (ret && !(flags & ImGuiTabItemFlags_NoPushId))
|
||||
PushID(tab_bar->Tabs[tab_bar->LastTabItemIdx].ID);
|
||||
return ret;
|
||||
}
|
||||
|
||||
void ImGui::EndTabItem()
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
if (g.CurrentWindow->SkipItems)
|
||||
return;
|
||||
|
||||
IM_ASSERT(g.CurrentTabBar.Size > 0 && "Needs to be called between BeginTabBar() and EndTabBar()!");
|
||||
ImGuiTabBar* tab_bar = g.CurrentTabBar.back();
|
||||
ImGuiTabItem* tab = &tab_bar->Tabs[tab_bar->LastTabItemIdx];
|
||||
if (!(tab->Flags & ImGuiTabItemFlags_NoPushId))
|
||||
PopID();
|
||||
}
|
||||
|
||||
bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open, ImGuiTabItemFlags flags, ImGuiWindow* docked_window)
|
||||
{
|
||||
// Layout whole tab bar if not already done
|
||||
if (tab_bar->WantLayout)
|
||||
TabBarLayout(tab_bar);
|
||||
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiWindow* window = g.CurrentWindow;
|
||||
if (window->SkipItems)
|
||||
return false;
|
||||
|
||||
const ImGuiStyle& style = g.Style;
|
||||
const ImGuiID id = TabBarCalcTabID(tab_bar, label);
|
||||
|
||||
// If the user called us with *p_open == false, we early out and don't render. We make a dummy call to ItemAdd() so that attempts to use a contextual popup menu with an implicit ID won't use an older ID.
|
||||
if (p_open && !*p_open)
|
||||
{
|
||||
PushItemFlag(ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus, true);
|
||||
ItemAdd(ImRect(), id);
|
||||
PopItemFlag();
|
||||
return false;
|
||||
}
|
||||
|
||||
// Calculate tab contents size
|
||||
ImVec2 size = TabItemCalcSize(label, p_open != NULL);
|
||||
|
||||
// Acquire tab data
|
||||
ImGuiTabItem* tab = TabBarFindTabByID(tab_bar, id);
|
||||
bool tab_is_new = false;
|
||||
if (tab == NULL)
|
||||
{
|
||||
tab_bar->Tabs.push_back(ImGuiTabItem());
|
||||
tab = &tab_bar->Tabs.back();
|
||||
tab->ID = id;
|
||||
tab->Width = size.x;
|
||||
tab_is_new = true;
|
||||
}
|
||||
tab_bar->LastTabItemIdx = (short)tab_bar->Tabs.index_from_pointer(tab);
|
||||
tab->WidthContents = size.x;
|
||||
|
||||
const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount);
|
||||
const bool tab_bar_focused = (tab_bar->Flags & ImGuiTabBarFlags_IsFocused) != 0;
|
||||
const bool tab_appearing = (tab->LastFrameVisible + 1 < g.FrameCount);
|
||||
tab->LastFrameVisible = g.FrameCount;
|
||||
tab->Flags = flags;
|
||||
tab->Window = docked_window;
|
||||
|
||||
// If we are not reorderable, always reset offset based on submission order.
|
||||
// (We already handled layout and sizing using the previous known order, but sizing is not affected by order!)
|
||||
if (!tab_appearing && !(tab_bar->Flags & ImGuiTabBarFlags_Reorderable))
|
||||
{
|
||||
tab->Offset = tab_bar->OffsetNextTab;
|
||||
tab_bar->OffsetNextTab += tab->Width + g.Style.ItemInnerSpacing.x;
|
||||
}
|
||||
|
||||
// Update selected tab
|
||||
if (tab_appearing && (tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs) && tab_bar->NextSelectedTabId == 0)
|
||||
if (!tab_bar_appearing || tab_bar->SelectedTabId == 0)
|
||||
tab_bar->NextSelectedTabId = id; // New tabs gets activated
|
||||
|
||||
// Lock visibility
|
||||
bool tab_contents_visible = (tab_bar->VisibleTabId == id);
|
||||
if (tab_contents_visible)
|
||||
tab_bar->VisibleTabWasSubmitted = true;
|
||||
|
||||
// On the very first frame of a tab bar we let first tab contents be visible to minimize appearing glitches
|
||||
if (!tab_contents_visible && tab_bar->SelectedTabId == 0 && tab_bar_appearing && docked_window == NULL)
|
||||
if (tab_bar->Tabs.Size == 1 && !(tab_bar->Flags & ImGuiTabBarFlags_AutoSelectNewTabs))
|
||||
tab_contents_visible = true;
|
||||
|
||||
if (tab_appearing && !(tab_bar_appearing && !tab_is_new))
|
||||
{
|
||||
PushItemFlag(ImGuiItemFlags_NoNav | ImGuiItemFlags_NoNavDefaultFocus, true);
|
||||
ItemAdd(ImRect(), id);
|
||||
PopItemFlag();
|
||||
return tab_contents_visible;
|
||||
}
|
||||
|
||||
if (tab_bar->SelectedTabId == id)
|
||||
tab->LastFrameSelected = g.FrameCount;
|
||||
|
||||
// Backup current layout position
|
||||
const ImVec2 backup_main_cursor_pos = window->DC.CursorPos;
|
||||
|
||||
// Layout
|
||||
size.x = tab->Width;
|
||||
window->DC.CursorPos = tab_bar->BarRect.Min + ImVec2((float)(int)tab->Offset - tab_bar->ScrollingAnim, 0.0f);
|
||||
ImVec2 pos = window->DC.CursorPos;
|
||||
ImRect bb(pos, pos + size);
|
||||
|
||||
// We don't have CPU clipping primitives to clip the CloseButton (until it becomes a texture), so need to add an extra draw call (temporary in the case of vertical animation)
|
||||
bool want_clip_rect = (bb.Min.x < tab_bar->BarRect.Min.x) || (bb.Max.x >= tab_bar->BarRect.Max.x);
|
||||
if (want_clip_rect)
|
||||
PushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->BarRect.Min.x), bb.Min.y - 1), ImVec2(tab_bar->BarRect.Max.x, bb.Max.y), true);
|
||||
|
||||
ItemSize(bb, style.FramePadding.y);
|
||||
if (!ItemAdd(bb, id))
|
||||
{
|
||||
if (want_clip_rect)
|
||||
PopClipRect();
|
||||
window->DC.CursorPos = backup_main_cursor_pos;
|
||||
return tab_contents_visible;
|
||||
}
|
||||
|
||||
// Click to Select a tab
|
||||
ImGuiButtonFlags button_flags = (ImGuiButtonFlags_PressedOnClick | ImGuiButtonFlags_AllowItemOverlap);
|
||||
if (g.DragDropActive && !g.DragDropPayload.IsDataType(IMGUI_PAYLOAD_TYPE_WINDOW))
|
||||
button_flags |= ImGuiButtonFlags_PressedOnDragDropHold;
|
||||
bool hovered, held;
|
||||
bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags);
|
||||
hovered |= (g.HoveredId == id);
|
||||
if (pressed || ((flags & ImGuiTabItemFlags_SetSelected) && !tab_contents_visible)) // SetSelected can only be passed on explicit tab bar, so we don't need to set WantFocusTabId
|
||||
tab_bar->NextSelectedTabId = id;
|
||||
|
||||
// Allow the close button to overlap unless we are dragging (in which case we don't want any overlapping tabs to be hovered)
|
||||
if (!held)
|
||||
SetItemAllowOverlap();
|
||||
|
||||
// Drag and drop
|
||||
if (held && !tab_appearing && IsMouseDragging())
|
||||
{
|
||||
// Re-order local or dockable tabs
|
||||
float drag_distance_from_edge_x = 0.0f;
|
||||
if (!g.DragDropActive && ((tab_bar->Flags & ImGuiTabBarFlags_Reorderable) || (flags & ImGuiTabItemFlags_DockedWindow)))
|
||||
{
|
||||
// While moving a tab it will jump on the other side of the mouse, so we also test for MouseDelta.x
|
||||
if (g.IO.MouseDelta.x < 0.0f && g.IO.MousePos.x < bb.Min.x)
|
||||
{
|
||||
drag_distance_from_edge_x = bb.Min.x - g.IO.MousePos.x;
|
||||
if (tab_bar->Flags & ImGuiTabBarFlags_Reorderable)
|
||||
TabBarQueueChangeTabOrder(tab_bar, tab, -1);
|
||||
}
|
||||
else if (g.IO.MouseDelta.x > 0.0f && g.IO.MousePos.x > bb.Max.x)
|
||||
{
|
||||
drag_distance_from_edge_x = g.IO.MousePos.x - bb.Max.x;
|
||||
if (tab_bar->Flags & ImGuiTabBarFlags_Reorderable)
|
||||
TabBarQueueChangeTabOrder(tab_bar, tab, +1);
|
||||
}
|
||||
}
|
||||
|
||||
// Extract a Dockable window out of it's tab bar
|
||||
if (flags & ImGuiTabItemFlags_DockedWindow)
|
||||
{
|
||||
// We use a variable threshold to distinguish dragging tabs within a tab bar and extracting them out of the tab bar
|
||||
//ImVec2 drag_delta = GetMouseDragDelta();
|
||||
bool undocking_tab = (g.DragDropActive && g.DragDropPayload.SourceId == id);
|
||||
if (!undocking_tab && held)// && (drag_delta.x != 0.0f || drag_delta.y != 0.0f))
|
||||
{
|
||||
//if (!g.IO.ConfigDockingWithKeyMod || g.IO.KeyShift)
|
||||
{
|
||||
float threshold_base = g.FontSize;
|
||||
//float threshold_base = g.IO.ConfigDockingWithKeyMod ? g.FontSize * 0.5f : g.FontSize;
|
||||
float threshold_x = (threshold_base * 2.2f);
|
||||
float threshold_y = (threshold_base * 1.5f) + ImClamp((ImFabs(g.IO.MouseDragMaxDistanceAbs[0].x) - threshold_base * 2.0f) * 0.20f, 0.0f, threshold_base * 4.0f);
|
||||
//GetOverlayDrawList(window)->AddRect(ImVec2(bb.Min.x - threshold_x, bb.Min.y - threshold_y), ImVec2(bb.Max.x + threshold_x, bb.Max.y + threshold_y), IM_COL32_WHITE); // [DEBUG]
|
||||
|
||||
float distance_from_edge_y = ImMax(bb.Min.y - g.IO.MousePos.y, g.IO.MousePos.y - bb.Max.y);
|
||||
if (distance_from_edge_y >= threshold_y)
|
||||
undocking_tab = true;
|
||||
else if (drag_distance_from_edge_x > threshold_x)
|
||||
if ((tab_bar->ReorderRequestDir < 0 && tab_bar->GetTabOrder(tab) == 0) || (tab_bar->ReorderRequestDir > 0 && tab_bar->GetTabOrder(tab) == tab_bar->Tabs.Size - 1))
|
||||
undocking_tab = true;
|
||||
}
|
||||
}
|
||||
|
||||
// Undock
|
||||
if (undocking_tab && g.ActiveId == id && IsMouseDragging())
|
||||
{
|
||||
ImGuiDockContext* ctx = g.DockContext;
|
||||
DockContextQueueUndock(ctx, docked_window);
|
||||
g.MovingWindow = docked_window;
|
||||
g.ActiveId = g.MovingWindow->MoveId;
|
||||
g.ActiveIdClickOffset -= g.MovingWindow->Pos - bb.Min;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#if 0
|
||||
if (hovered && g.HoveredIdTimer > 0.40f && bb.GetWidth() < tab->WidthContents)
|
||||
{
|
||||
// Enlarge tab display when hovering
|
||||
bb.Max.x = bb.Min.x + (float)(int)ImLerp(bb.GetWidth(), tab->WidthContents, ImSaturate((g.HoveredIdTimer - 0.40f) * 6.0f));
|
||||
display_draw_list = GetOverlayDrawList(window);
|
||||
TabItemRenderBackground(display_draw_list, bb, flags, GetColorU32(ImGuiCol_TitleBgActive));
|
||||
}
|
||||
#endif
|
||||
|
||||
// Render tab shape
|
||||
ImDrawList* display_draw_list = window->DrawList;
|
||||
const ImU32 tab_col = GetColorU32((held || hovered) ? ImGuiCol_TabHovered : tab_contents_visible ? (tab_bar_focused ? ImGuiCol_TabActive : ImGuiCol_TabUnfocusedActive) : (tab_bar_focused ? ImGuiCol_Tab : ImGuiCol_TabUnfocused));
|
||||
TabItemBackground(display_draw_list, bb, flags, tab_col);
|
||||
RenderNavHighlight(bb, id);
|
||||
|
||||
// Select with right mouse button. This is so the common idiom for context menu automatically highlight the current widget.
|
||||
const bool hovered_unblocked = IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup);
|
||||
if (hovered_unblocked && (IsMouseClicked(1) || IsMouseReleased(1)))
|
||||
tab_bar->NextSelectedTabId = tab_bar->WantFocusTabId = id;
|
||||
|
||||
if (tab_bar->Flags & ImGuiTabBarFlags_NoCloseWithMiddleMouseButton)
|
||||
flags |= ImGuiTabItemFlags_NoCloseWithMiddleMouseButton;
|
||||
|
||||
// Render tab label, process close button
|
||||
const ImGuiID close_button_id = p_open ? window->GetID((void*)(intptr_t)(id + 1)) : 0;
|
||||
bool just_closed = TabItemLabelAndCloseButton(display_draw_list, bb, flags, label, id, close_button_id);
|
||||
if (just_closed)
|
||||
{
|
||||
*p_open = false;
|
||||
TabBarCloseTab(tab_bar, tab);
|
||||
}
|
||||
|
||||
// Tooltip (FIXME: Won't work over the close button because ItemOverlap systems messes up with HoveredIdTimer)
|
||||
if (g.HoveredId == id && !held && g.HoveredIdTimer > 0.50f)
|
||||
SetTooltip("%.*s", (int)(FindRenderedTextEnd(label) - label), label);
|
||||
|
||||
// Restore main window position so user can draw there
|
||||
if (want_clip_rect)
|
||||
PopClipRect();
|
||||
window->DC.CursorPos = backup_main_cursor_pos;
|
||||
|
||||
return tab_contents_visible;
|
||||
}
|
||||
|
||||
// [Public] This is call is 100% optional but it allows to remove some one-frame glitches when a tab has been unexpectedly removed.
|
||||
// To use it to need to call the function SetTabItemClosed() after BeginTabBar() and before any call to BeginTabItem()
|
||||
void ImGui::SetTabItemClosed(const char* label)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
bool is_within_manual_tab_bar = (g.CurrentTabBar.Size > 0) && !(g.CurrentTabBar.back()->Flags & ImGuiTabBarFlags_DockNode);
|
||||
if (is_within_manual_tab_bar)
|
||||
{
|
||||
ImGuiTabBar* tab_bar = g.CurrentTabBar.back();
|
||||
IM_ASSERT(tab_bar->WantLayout); // Needs to be called AFTER BeginTabBar() and BEFORE the first call to BeginTabItem()
|
||||
ImGuiID tab_id = TabBarCalcTabID(tab_bar, label);
|
||||
TabBarRemoveTab(tab_bar, tab_id);
|
||||
}
|
||||
else if (ImGuiWindow* window = FindWindowByName(label))
|
||||
{
|
||||
if (window->DockIsActive)
|
||||
if (ImGuiDockNode* node = window->DockNode)
|
||||
{
|
||||
ImGuiID tab_id = TabBarCalcTabID(node->TabBar, label);
|
||||
TabBarRemoveTab(node->TabBar, tab_id);
|
||||
window->DockTabWantClose = true;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ImVec2 ImGui::TabItemCalcSize(const char* label, bool has_close_button)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImVec2 label_size = CalcTextSize(label, NULL, true);
|
||||
ImVec2 size = ImVec2(label_size.x + g.Style.FramePadding.x, label_size.y + g.Style.FramePadding.y * 2.0f);
|
||||
if (has_close_button)
|
||||
size.x += g.Style.FramePadding.x + (g.Style.ItemInnerSpacing.x + g.FontSize); // We use Y intentionally to fit the close button circle.
|
||||
else
|
||||
size.x += g.Style.FramePadding.x + 1.0f;
|
||||
return ImVec2(ImMin(size.x, TabBarCalcMaxTabWidth()), size.y);
|
||||
}
|
||||
|
||||
void ImGui::TabItemBackground(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, ImU32 col)
|
||||
{
|
||||
// While rendering tabs, we trim 1 pixel off the top of our bounding box so they can fit within a regular frame height while looking "detached" from it.
|
||||
ImGuiContext& g = *GImGui;
|
||||
const float width = bb.GetWidth();
|
||||
IM_ASSERT(width > 0.0f);
|
||||
const float rounding = ImMax(0.0f, ImMin(g.FontSize * 0.35f, width * 0.5f - 1.0f)); // FIXME-DOCK: g.Style.TabRounding?
|
||||
float y1 = bb.Min.y + 1.0f;
|
||||
float y2 = bb.Max.y + ((flags & ImGuiTabItemFlags_Preview) ? 0.0f : -1.0f);
|
||||
draw_list->PathLineTo(ImVec2(bb.Min.x, y2));
|
||||
draw_list->PathArcToFast(ImVec2(bb.Min.x + rounding, y1 + rounding), rounding, 6, 9);
|
||||
draw_list->PathArcToFast(ImVec2(bb.Max.x - rounding, y1 + rounding), rounding, 9, 12);
|
||||
draw_list->PathLineTo(ImVec2(bb.Max.x, y2));
|
||||
draw_list->AddConvexPolyFilled(draw_list->_Path.Data, draw_list->_Path.Size, col);
|
||||
if (g.Style.TabBorderSize > 0.0f)
|
||||
draw_list->AddPolyline(draw_list->_Path.Data, draw_list->_Path.Size, GetColorU32(ImGuiCol_Border), false, g.Style.TabBorderSize);
|
||||
draw_list->PathClear();
|
||||
}
|
||||
|
||||
// Render text label (with clipping + alpha gradient) + unsaved marker + Close Button logic
|
||||
bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb, ImGuiTabItemFlags flags, const char* label, ImGuiID tab_id, ImGuiID close_button_id)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
ImGuiStyle& style = g.Style;
|
||||
ImVec2 label_size = CalcTextSize(label, NULL, true);
|
||||
if (bb.GetWidth() <= 1.0f)
|
||||
return false;
|
||||
|
||||
// Render text label (with clipping + alpha gradient) + unsaved marker
|
||||
const char* TAB_UNSAVED_MARKER = "*";
|
||||
ImRect text_pixel_clip_bb(bb.Min.x + style.FramePadding.x, bb.Min.y + style.FramePadding.y, bb.Max.x - style.FramePadding.x, bb.Max.y);
|
||||
if (flags & ImGuiTabItemFlags_UnsavedDocument)
|
||||
{
|
||||
text_pixel_clip_bb.Max.x -= CalcTextSize(TAB_UNSAVED_MARKER, NULL, false).x;
|
||||
ImVec2 unsaved_marker_pos(ImMin(bb.Min.x + style.FramePadding.x + label_size.x + 2, text_pixel_clip_bb.Max.x), bb.Min.y + style.FramePadding.y + (float)(int)(-g.FontSize * 0.25f));
|
||||
RenderTextClippedEx(draw_list, unsaved_marker_pos, bb.Max - style.FramePadding, TAB_UNSAVED_MARKER, NULL, NULL);
|
||||
}
|
||||
ImRect text_ellipsis_clip_bb = text_pixel_clip_bb;
|
||||
|
||||
// Close Button
|
||||
// We are relying on a subtle and confusing distinction between 'hovered' and 'g.HoveredId' which happens because we are using ImGuiButtonFlags_AllowOverlapMode + SetItemAllowOverlap()
|
||||
// 'hovered' will be true when hovering the Tab but NOT when hovering the close button
|
||||
// 'g.HoveredId==id' will be true when hovering the Tab including when hovering the close button
|
||||
// 'g.ActiveId==close_button_id' will be true when we are holding on the close button, in which case both hovered booleans are false
|
||||
bool close_button_pressed = false;
|
||||
bool close_button_visible = false;
|
||||
if (close_button_id != 0)
|
||||
if (g.HoveredId == tab_id || g.HoveredId == close_button_id || g.ActiveId == close_button_id)
|
||||
close_button_visible = true;
|
||||
if (close_button_visible)
|
||||
{
|
||||
ImGuiItemHoveredDataBackup last_item_backup;
|
||||
const float close_button_sz = g.FontSize * 0.5f;
|
||||
if (CloseButton(close_button_id, ImVec2(bb.Max.x - style.FramePadding.x - close_button_sz, bb.Min.y + style.FramePadding.y + close_button_sz), close_button_sz))
|
||||
close_button_pressed = true;
|
||||
last_item_backup.Restore();
|
||||
|
||||
// Close with middle mouse button
|
||||
if (!(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2))
|
||||
close_button_pressed = true;
|
||||
|
||||
text_pixel_clip_bb.Max.x -= close_button_sz * 2.0f;
|
||||
}
|
||||
|
||||
// Label with ellipsis
|
||||
// FIXME: This could be extracted into a helper but or use of text_pixel_clip_bb and !close_button_visible makes it tricky to abstract at the moment
|
||||
const char* label_display_end = FindRenderedTextEnd(label);
|
||||
if (label_size.x > text_ellipsis_clip_bb.GetWidth())
|
||||
{
|
||||
const int ellipsis_dot_count = 3;
|
||||
const float ellipsis_width = (1.0f + 1.0f) * ellipsis_dot_count - 1.0f;
|
||||
const char* label_end = NULL;
|
||||
float label_size_clipped_x = g.Font->CalcTextSizeA(g.FontSize, text_ellipsis_clip_bb.GetWidth() - ellipsis_width + 1.0f, 0.0f, label, label_display_end, &label_end).x;
|
||||
if (label_end == label && label_end < label_display_end) // Always display at least 1 character if there's no room for character + ellipsis
|
||||
{
|
||||
label_end = label + ImTextCountUtf8BytesFromChar(label, label_display_end);
|
||||
label_size_clipped_x = g.Font->CalcTextSizeA(g.FontSize, FLT_MAX, 0.0f, label, label_end).x;
|
||||
}
|
||||
while (label_end > label && ImCharIsBlankA(label_end[-1])) // Trim trailing space
|
||||
{
|
||||
label_end--;
|
||||
label_size_clipped_x -= g.Font->CalcTextSizeA(g.FontSize, FLT_MAX, 0.0f, label_end, label_end + 1).x; // Ascii blanks are always 1 byte
|
||||
}
|
||||
RenderTextClippedEx(draw_list, text_pixel_clip_bb.Min, text_pixel_clip_bb.Max, label, label_end, &label_size, ImVec2(0.0f, 0.0f));
|
||||
|
||||
const float ellipsis_x = text_pixel_clip_bb.Min.x + label_size_clipped_x + 1.0f;
|
||||
if (!close_button_visible && ellipsis_x + ellipsis_width <= bb.Max.x)
|
||||
RenderPixelEllipsis(draw_list, g.Font, ImVec2(ellipsis_x, text_pixel_clip_bb.Min.y), ellipsis_dot_count, GetColorU32(ImGuiCol_Text));
|
||||
}
|
||||
else
|
||||
{
|
||||
RenderTextClippedEx(draw_list, text_pixel_clip_bb.Min, text_pixel_clip_bb.Max, label, label_display_end, &label_size, ImVec2(0.0f, 0.0f));
|
||||
}
|
||||
|
||||
return close_button_pressed;
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user