Merge branch 'master' into docking

# Conflicts:
#	imgui.cpp
#	imgui_internal.h
This commit is contained in:
omar 2019-11-08 15:45:12 +01:00
commit 69b5c2f541
9 changed files with 200 additions and 119 deletions

View File

@ -135,8 +135,13 @@ Other Changes:
- ColorPicker: Fixed SV triangle gradient to block (broken in 1.73). (#2864, #2711). [@lewa-j] - ColorPicker: Fixed SV triangle gradient to block (broken in 1.73). (#2864, #2711). [@lewa-j]
- TreeNode: Fixed combination of ImGuiTreeNodeFlags_SpanFullWidth and ImGuiTreeNodeFlags_OpenOnArrow - TreeNode: Fixed combination of ImGuiTreeNodeFlags_SpanFullWidth and ImGuiTreeNodeFlags_OpenOnArrow
incorrectly locating the arrow hit position to the left of the frame. (#2451, #2438, #1897) incorrectly locating the arrow hit position to the left of the frame. (#2451, #2438, #1897)
- TreeNode: The collapsing arrow accepts click even if modifier keys are being held, facilitating
interactions with custom multi-selections patterns. (#2886, #1896, #1861)
- TreeNode: Added IsItemToggledOpen() to explicitly query if item was just open/closed, facilitating
interactions with custom multi-selections patterns. (#1896, #1861)
- DragScalar, SliderScalar, InputScalar: Added p_ prefix to parameter that are pointers to the data - DragScalar, SliderScalar, InputScalar: Added p_ prefix to parameter that are pointers to the data
to clarify how they are used, and more comments redirecting to the demo code. (#2844) to clarify how they are used, and more comments redirecting to the demo code. (#2844)
- Misc: Optimized storage of window settings data (reducing allocation count).
- Misc: Windows: Do not use _wfopen() if IMGUI_DISABLE_WIN32_FUNCTIONS is defined. (#2815) - Misc: Windows: Do not use _wfopen() if IMGUI_DISABLE_WIN32_FUNCTIONS is defined. (#2815)
- Docs: Improved and moved FAQ to docs/FAQ.md so it can be readable on the web. [@ButternCream, @ocornut] - Docs: Improved and moved FAQ to docs/FAQ.md so it can be readable on the web. [@ButternCream, @ocornut]
- Docs: Added permanent redirect from https://www.dearimgui.org/faq to FAQ page. - Docs: Added permanent redirect from https://www.dearimgui.org/faq to FAQ page.
@ -144,6 +149,8 @@ Other Changes:
- Metrics: Expose basic details of each window key/value state storage. - Metrics: Expose basic details of each window key/value state storage.
- Examples: DX12: Using IDXGIDebug1::ReportLiveObjects() when DX12_ENABLE_DEBUG_LAYER is enabled. - Examples: DX12: Using IDXGIDebug1::ReportLiveObjects() when DX12_ENABLE_DEBUG_LAYER is enabled.
- Examples: Emscripten: Removed NO_FILESYSTEM from Makefile, seems to fail on some setup. (#2734) [@Funto] - Examples: Emscripten: Removed NO_FILESYSTEM from Makefile, seems to fail on some setup. (#2734) [@Funto]
- Examples: Emscripten: Removed BINARYEN_TRAP_MODE=clamp from Makefile which was removed in Emscripten 1.39.0
but required prior to 1.39.0, making life easier for absolutely no-one. (#2877, #2878) [@podsvirov]
- Backends: OpenGL3: Fix building with pre-3.2 GL loaders which do not expose glDrawElementsBaseVertex(), - Backends: OpenGL3: Fix building with pre-3.2 GL loaders which do not expose glDrawElementsBaseVertex(),
using runtime GL version to decide if we set ImGuiBackendFlags_RendererHasVtxOffset. (#2866, #2852) [@dpilawa] using runtime GL version to decide if we set ImGuiBackendFlags_RendererHasVtxOffset. (#2866, #2852) [@dpilawa]
- Backends: OSX: Fix using Backspace key. (#2578, #2817, #2818) [@DiligentGraphics] - Backends: OSX: Fix using Backspace key. (#2578, #2817, #2818) [@DiligentGraphics]

View File

@ -214,6 +214,10 @@ Ongoing Dear ImGui development is financially supported by users and private spo
And all other past and present supporters; THANK YOU! And all other past and present supporters; THANK YOU!
(Please contact me if you would like to be added or removed from this list) (Please contact me if you would like to be added or removed from this list)
Dear ImGui is using software and services kindly provided free of charge for open source projects:
- [PVS-Studio](https://www.viva64.com/en/b/0570/) for static analysis.
- [GitHub actions](https://github.com/features/actions) for continuous integration systems.
Credits Credits
------- -------

View File

@ -22,9 +22,11 @@ OBJS = $(addsuffix .o, $(basename $(notdir $(SOURCES))))
UNAME_S := $(shell uname -s) UNAME_S := $(shell uname -s)
EMS = -s USE_SDL=2 -s WASM=1 EMS = -s USE_SDL=2 -s WASM=1
EMS += -s ALLOW_MEMORY_GROWTH=1 -s BINARYEN_TRAP_MODE=clamp EMS += -s ALLOW_MEMORY_GROWTH=1
EMS += -s DISABLE_EXCEPTION_CATCHING=1 -s NO_EXIT_RUNTIME=0 EMS += -s DISABLE_EXCEPTION_CATCHING=1 -s NO_EXIT_RUNTIME=0
EMS += -s ASSERTIONS=1 EMS += -s ASSERTIONS=1
# Uncomment next line to fix possible rendering bugs with emscripten version older then 1.39.0 (https://github.com/ocornut/imgui/issues/2877)
#EMS += -s BINARYEN_TRAP_MODE=clamp
#EMS += -s NO_FILESYSTEM=1 ## Getting "error: undefined symbol: $FS" if filesystem is removed #EMS += -s NO_FILESYSTEM=1 ## Getting "error: undefined symbol: $FS" if filesystem is removed
#EMS += -s SAFE_HEAP=1 ## Adds overhead #EMS += -s SAFE_HEAP=1 ## Adds overhead

View File

@ -3,6 +3,10 @@
- You need to install Emscripten from https://emscripten.org/docs/getting_started/downloads.html, and have the environment variables set, as described in https://emscripten.org/docs/getting_started/downloads.html#installation-instructions - You need to install Emscripten from https://emscripten.org/docs/getting_started/downloads.html, and have the environment variables set, as described in https://emscripten.org/docs/getting_started/downloads.html#installation-instructions
``` - Depending on your configuration, in Windows you may need to run `emsdk/emsdk_env.bat` in your console to access the Emscripten command-line tools.
em++ -I.. -I../.. main.cpp ../imgui_impl_sdl.cpp ../imgui_impl_opengl3.cpp ../../imgui*.cpp -s USE_SDL=2 -s USE_WEBGL2=1 -s WASM=1 -s FULL_ES3=1 -s ALLOW_MEMORY_GROWTH=1 -s BINARYEN_TRAP_MODE=clamp --shell-file shell_minimal.html -o example-emscripten.html
``` - Then build using `make` while in the `example_emscripten/` directory.
- Note that Emscripten 1.39.0 (October 2019) obsoleted the `BINARYEN_TRAP_MODE=clamp` compilation flag which was required with version older than 1.39.0 to avoid rendering artefacts. See [#2877](https://github.com/ocornut/imgui/issues/2877) for details. If you use an older version, uncomment this line in the Makefile:
`#EMS += -s BINARYEN_TRAP_MODE=clamp`

115
imgui.cpp
View File

@ -860,9 +860,9 @@ static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, I
static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window); static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, ImGuiWindow* window);
// Settings // Settings
static void* SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name); static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name);
static void SettingsHandlerWindow_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line); static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line);
static void SettingsHandlerWindow_WriteAll(ImGuiContext* imgui_ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf); static void WindowSettingsHandler_WriteAll(ImGuiContext*, ImGuiSettingsHandler*, ImGuiTextBuffer* buf);
// Platform Dependents default implementation for IO functions // Platform Dependents default implementation for IO functions
static const char* GetClipboardTextFn_DefaultImpl(void* user_data); static const char* GetClipboardTextFn_DefaultImpl(void* user_data);
@ -2569,7 +2569,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name)
LastTimeActive = -1.0f; LastTimeActive = -1.0f;
ItemWidthDefault = 0.0f; ItemWidthDefault = 0.0f;
FontWindowScale = FontDpiScale = 1.0f; FontWindowScale = FontDpiScale = 1.0f;
SettingsIdx = -1; SettingsOffset = -1;
DrawList = &DrawListInst; DrawList = &DrawListInst;
DrawList->_OwnerName = Name; DrawList->_OwnerName = Name;
@ -3972,13 +3972,15 @@ void ImGui::Initialize(ImGuiContext* context)
IM_ASSERT(!g.Initialized && !g.SettingsLoaded); IM_ASSERT(!g.Initialized && !g.SettingsLoaded);
// Add .ini handle for ImGuiWindow type // Add .ini handle for ImGuiWindow type
{
ImGuiSettingsHandler ini_handler; ImGuiSettingsHandler ini_handler;
ini_handler.TypeName = "Window"; ini_handler.TypeName = "Window";
ini_handler.TypeHash = ImHashStr("Window"); ini_handler.TypeHash = ImHashStr("Window");
ini_handler.ReadOpenFn = SettingsHandlerWindow_ReadOpen; ini_handler.ReadOpenFn = WindowSettingsHandler_ReadOpen;
ini_handler.ReadLineFn = SettingsHandlerWindow_ReadLine; ini_handler.ReadLineFn = WindowSettingsHandler_ReadLine;
ini_handler.WriteAllFn = SettingsHandlerWindow_WriteAll; ini_handler.WriteAllFn = WindowSettingsHandler_WriteAll;
g.SettingsHandlers.push_back(ini_handler); g.SettingsHandlers.push_back(ini_handler);
}
// Create default viewport // Create default viewport
ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)(); ImGuiViewportP* viewport = IM_NEW(ImGuiViewportP)();
@ -4062,8 +4064,6 @@ void ImGui::Shutdown(ImGuiContext* context)
g.PrivateClipboard.clear(); g.PrivateClipboard.clear();
g.InputTextState.ClearFreeMemory(); g.InputTextState.ClearFreeMemory();
for (int i = 0; i < g.SettingsWindows.Size; i++)
IM_DELETE(g.SettingsWindows[i].Name);
g.SettingsWindows.clear(); g.SettingsWindows.clear();
g.SettingsHandlers.clear(); g.SettingsHandlers.clear();
@ -4821,6 +4821,12 @@ bool ImGui::IsItemClicked(int mouse_button)
return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None); return IsMouseClicked(mouse_button) && IsItemHovered(ImGuiHoveredFlags_None);
} }
bool ImGui::IsItemToggledOpen()
{
ImGuiContext& g = *GImGui;
return (g.CurrentWindow->DC.LastItemStatusFlags & ImGuiItemStatusFlags_ToggledOpen) ? true : false;
}
bool ImGui::IsItemToggledSelection() bool ImGui::IsItemToggledSelection()
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
@ -5062,7 +5068,7 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl
if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID)) if (ImGuiWindowSettings* settings = ImGui::FindWindowSettings(window->ID))
{ {
// Retrieve settings from .ini file // Retrieve settings from .ini file
window->SettingsIdx = g.SettingsWindows.index_from_ptr(settings); window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);
SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false); SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false);
if (settings->ViewportId) if (settings->ViewportId)
{ {
@ -9963,25 +9969,31 @@ void ImGui::MarkIniSettingsDirty(ImGuiWindow* window)
ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name) ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
g.SettingsWindows.push_back(ImGuiWindowSettings());
ImGuiWindowSettings* settings = &g.SettingsWindows.back();
#if !IMGUI_DEBUG_INI_SETTINGS #if !IMGUI_DEBUG_INI_SETTINGS
// Skip to the "###" marker if any. We don't skip past to match the behavior of GetID() // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID()
// Preserve the full string when IMGUI_DEBUG_INI_SETTINGS is set to make .ini inspection easier. // Preserve the full string when IMGUI_DEBUG_INI_SETTINGS is set to make .ini inspection easier.
if (const char* p = strstr(name, "###")) if (const char* p = strstr(name, "###"))
name = p; name = p;
#endif #endif
settings->Name = ImStrdup(name); const size_t name_len = strlen(name);
settings->ID = ImHashStr(name);
// Allocate chunk
const size_t chunk_size = sizeof(ImGuiWindowSettings) + name_len + 1;
ImGuiWindowSettings* settings = g.SettingsWindows.alloc_chunk(chunk_size);
IM_PLACEMENT_NEW(settings) ImGuiWindowSettings();
settings->ID = ImHashStr(name, name_len);
memcpy(settings->GetName(), name, name_len + 1); // Store with zero terminator
return settings; return settings;
} }
ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id) ImGuiWindowSettings* ImGui::FindWindowSettings(ImGuiID id)
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
for (int i = 0; i != g.SettingsWindows.Size; i++) for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
if (g.SettingsWindows[i].ID == id) if (settings->ID == id)
return &g.SettingsWindows[i]; return settings;
return NULL; return NULL;
} }
@ -10108,7 +10120,7 @@ const char* ImGui::SaveIniSettingsToMemory(size_t* out_size)
return g.SettingsIniData.c_str(); return g.SettingsIniData.c_str();
} }
static void* SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name) static void* WindowSettingsHandler_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*, const char* name)
{ {
ImGuiWindowSettings* settings = ImGui::FindWindowSettings(ImHashStr(name)); ImGuiWindowSettings* settings = ImGui::FindWindowSettings(ImHashStr(name));
if (!settings) if (!settings)
@ -10116,7 +10128,7 @@ static void* SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*
return (void*)settings; return (void*)settings;
} }
static void SettingsHandlerWindow_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line) static void WindowSettingsHandler_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line)
{ {
ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry; ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry;
int x, y; int x, y;
@ -10132,7 +10144,7 @@ static void SettingsHandlerWindow_ReadLine(ImGuiContext*, ImGuiSettingsHandler*,
else if (sscanf(line, "ClassId=0x%X", &u1) == 1) { settings->ClassId = u1; } else if (sscanf(line, "ClassId=0x%X", &u1) == 1) { settings->ClassId = u1; }
} }
static void SettingsHandlerWindow_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf) static void WindowSettingsHandler_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandler* handler, ImGuiTextBuffer* buf)
{ {
// Gather data from windows that were active during this session // Gather data from windows that were active during this session
// (if a window wasn't opened in this session we preserve its settings) // (if a window wasn't opened in this session we preserve its settings)
@ -10143,11 +10155,11 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
if (window->Flags & ImGuiWindowFlags_NoSavedSettings) if (window->Flags & ImGuiWindowFlags_NoSavedSettings)
continue; continue;
ImGuiWindowSettings* settings = (window->SettingsIdx != -1) ? &g.SettingsWindows[window->SettingsIdx] : ImGui::FindWindowSettings(window->ID); ImGuiWindowSettings* settings = (window->SettingsOffset != -1) ? g.SettingsWindows.ptr_from_offset(window->SettingsOffset) : ImGui::FindWindowSettings(window->ID);
if (!settings) if (!settings)
{ {
settings = ImGui::CreateNewWindowSettings(window->Name); settings = ImGui::CreateNewWindowSettings(window->Name);
window->SettingsIdx = g.SettingsWindows.index_from_ptr(settings); window->SettingsOffset = g.SettingsWindows.offset_from_ptr(settings);
} }
IM_ASSERT(settings->ID == window->ID); IM_ASSERT(settings->ID == window->ID);
settings->Pos = ImVec2ih(window->Pos - window->ViewportPos); settings->Pos = ImVec2ih(window->Pos - window->ViewportPos);
@ -10162,11 +10174,11 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
} }
// Write to text buffer // Write to text buffer
buf->reserve(buf->size() + g.SettingsWindows.Size * 96); // ballpark reserve buf->reserve(buf->size() + g.SettingsWindows.size() * 6); // ballpark reserve
for (int i = 0; i != g.SettingsWindows.Size; i++) for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
{ {
const ImGuiWindowSettings* settings = &g.SettingsWindows[i]; const char* settings_name = settings->GetName();
buf->appendf("[%s][%s]\n", handler->TypeName, settings->Name); buf->appendf("[%s][%s]\n", handler->TypeName, settings_name);
if (settings->ViewportId != 0 && settings->ViewportId != ImGui::IMGUI_VIEWPORT_DEFAULT_ID) if (settings->ViewportId != 0 && settings->ViewportId != ImGui::IMGUI_VIEWPORT_DEFAULT_ID)
{ {
buf->appendf("ViewportPos=%d,%d\n", settings->ViewportPos.x, settings->ViewportPos.y); buf->appendf("ViewportPos=%d,%d\n", settings->ViewportPos.x, settings->ViewportPos.y);
@ -10187,7 +10199,7 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
if (settings->ClassId != 0) if (settings->ClassId != 0)
buf->appendf("ClassId=0x%08X\n", settings->ClassId); buf->appendf("ClassId=0x%08X\n", settings->ClassId);
} }
buf->appendf("\n"); buf->append("\n");
} }
} }
@ -11416,8 +11428,8 @@ static void ImGui::DockContextPruneUnusedSettingsNodes(ImGuiContext* ctx)
// Count reference to dock ids from window settings // Count reference to dock ids from window settings
// We guard against the possibility of an invalid .ini file (RootID may point to a missing node) // We guard against the possibility of an invalid .ini file (RootID may point to a missing node)
for (int settings_n = 0; settings_n < g.SettingsWindows.Size; settings_n++) for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
if (ImGuiID dock_id = g.SettingsWindows[settings_n].DockId) if (ImGuiID dock_id = settings->DockId)
if (ImGuiDockContextPruneNodeData* data = pool.GetByKey(dock_id)) if (ImGuiDockContextPruneNodeData* data = pool.GetByKey(dock_id))
{ {
data->CountWindows++; data->CountWindows++;
@ -13735,12 +13747,12 @@ void ImGui::DockBuilderRemoveNodeChildNodes(ImGuiID root_id)
} }
// Apply to settings // Apply to settings
for (int settings_n = 0; settings_n < ctx->SettingsWindows.Size; settings_n++) for (ImGuiWindowSettings* settings = ctx->SettingsWindows.begin(); settings != NULL; settings = ctx->SettingsWindows.next_chunk(settings))
if (ImGuiID window_settings_dock_id = ctx->SettingsWindows[settings_n].DockId) if (ImGuiID window_settings_dock_id = settings->DockId)
for (int n = 0; n < nodes_to_remove.Size; n++) for (int n = 0; n < nodes_to_remove.Size; n++)
if (nodes_to_remove[n]->ID == window_settings_dock_id) if (nodes_to_remove[n]->ID == window_settings_dock_id)
{ {
ctx->SettingsWindows[settings_n].DockId = root_id; settings->DockId = root_id;
break; break;
} }
@ -13769,9 +13781,8 @@ void ImGui::DockBuilderRemoveNodeDockedWindows(ImGuiID root_id, bool clear_persi
ImGuiContext& g = *ctx; ImGuiContext& g = *ctx;
if (clear_persistent_docking_references) if (clear_persistent_docking_references)
{ {
for (int n = 0; n < g.SettingsWindows.Size; n++) for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
{ {
ImGuiWindowSettings* settings = &g.SettingsWindows[n];
bool want_removal = (root_id == 0) || (settings->DockId == root_id); bool want_removal = (root_id == 0) || (settings->DockId == root_id);
if (!want_removal && settings->DockId != 0) if (!want_removal && settings->DockId != 0)
if (ImGuiDockNode* node = DockContextFindNodeByID(ctx, settings->DockId)) if (ImGuiDockNode* node = DockContextFindNodeByID(ctx, settings->DockId))
@ -14277,12 +14288,10 @@ static void ImGui::DockSettingsRenameNodeReferences(ImGuiID old_node_id, ImGuiID
if (window->DockId == old_node_id && window->DockNode == NULL) if (window->DockId == old_node_id && window->DockNode == NULL)
window->DockId = new_node_id; window->DockId = new_node_id;
} }
for (int settings_n = 0; settings_n < g.SettingsWindows.Size; settings_n++) // FIXME-OPT: We could remove this loop by storing the index in the map //// FIXME-OPT: We could remove this loop by storing the index in the map
{ for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
ImGuiWindowSettings* window_settings = &g.SettingsWindows[settings_n]; if (settings->DockId == old_node_id)
if (window_settings->DockId == old_node_id) settings->DockId = new_node_id;
window_settings->DockId = new_node_id;
}
} }
// Remove references stored in ImGuiWindowSettings to the given ImGuiDockNodeSettings // Remove references stored in ImGuiWindowSettings to the given ImGuiDockNodeSettings
@ -14290,20 +14299,18 @@ static void ImGui::DockSettingsRemoveNodeReferences(ImGuiID* node_ids, int node_
{ {
ImGuiContext& g = *GImGui; ImGuiContext& g = *GImGui;
int found = 0; int found = 0;
for (int settings_n = 0; settings_n < g.SettingsWindows.Size; settings_n++) // FIXME-OPT: We could remove this loop by storing the index in the map //// FIXME-OPT: We could remove this loop by storing the index in the map
{ for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
ImGuiWindowSettings* window_settings = &g.SettingsWindows[settings_n];
for (int node_n = 0; node_n < node_ids_count; node_n++) for (int node_n = 0; node_n < node_ids_count; node_n++)
if (window_settings->DockId == node_ids[node_n]) if (settings->DockId == node_ids[node_n])
{ {
window_settings->DockId = 0; settings->DockId = 0;
window_settings->DockOrder = -1; settings->DockOrder = -1;
if (++found < node_ids_count) if (++found < node_ids_count)
break; break;
return; return;
} }
} }
}
static ImGuiDockNodeSettings* ImGui::DockSettingsFindNodeSettings(ImGuiContext* ctx, ImGuiID id) static ImGuiDockNodeSettings* ImGui::DockSettingsFindNodeSettings(ImGuiContext* ctx, ImGuiID id)
{ {
@ -14997,9 +15004,9 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImGui::TreePop(); ImGui::TreePop();
} }
if (ImGui::TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.Data.Size)) if (ImGui::TreeNode("TabBars", "Tab Bars (%d)", g.TabBars.GetSize()))
{ {
for (int n = 0; n < g.TabBars.Data.Size; n++) for (int n = 0; n < g.TabBars.GetSize(); n++)
Funcs::NodeTabBar(g.TabBars.GetByIndex(n)); Funcs::NodeTabBar(g.TabBars.GetByIndex(n));
ImGui::TreePop(); ImGui::TreePop();
} }
@ -15030,9 +15037,9 @@ void ImGui::ShowMetricsWindow(bool* p_open)
SaveIniSettingsToDisk(g.IO.IniFilename); SaveIniSettingsToDisk(g.IO.IniFilename);
ImGui::Separator(); ImGui::Separator();
ImGui::Text("Docked Windows:"); ImGui::Text("Docked Windows:");
for (int n = 0; n < g.SettingsWindows.Size; n++) for (ImGuiWindowSettings* settings = g.SettingsWindows.begin(); settings != NULL; settings = g.SettingsWindows.next_chunk(settings))
if (g.SettingsWindows[n].DockId != 0) if (settings->DockId != 0)
ImGui::BulletText("Window '%s' -> DockId %08X", g.SettingsWindows[n].Name, g.SettingsWindows[n].DockId); ImGui::BulletText("Window '%s' -> DockId %08X", settings->GetName(), settings->DockId);
ImGui::Separator(); ImGui::Separator();
ImGui::Text("Dock Nodes:"); ImGui::Text("Dock Nodes:");
for (int n = 0; n < dc->SettingsNodes.Size; n++) for (int n = 0; n < dc->SettingsNodes.Size; n++)
@ -15044,7 +15051,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
if (ImGuiWindow* window = FindWindowByID(settings->SelectedWindowID)) if (ImGuiWindow* window = FindWindowByID(settings->SelectedWindowID))
selected_tab_name = window->Name; selected_tab_name = window->Name;
else if (ImGuiWindowSettings* window_settings = FindWindowSettings(settings->SelectedWindowID)) else if (ImGuiWindowSettings* window_settings = FindWindowSettings(settings->SelectedWindowID))
selected_tab_name = window_settings->Name; selected_tab_name = window_settings->GetName();
} }
ImGui::BulletText("Node %08X, Parent %08X, SelectedTab %08X ('%s')", settings->ID, settings->ParentNodeID, settings->SelectedWindowID, selected_tab_name ? selected_tab_name : settings->SelectedWindowID ? "N/A" : ""); ImGui::BulletText("Node %08X, Parent %08X, SelectedTab %08X ('%s')", settings->ID, settings->ParentNodeID, settings->SelectedWindowID, selected_tab_name ? selected_tab_name : settings->SelectedWindowID ? "N/A" : "");
} }
@ -15055,7 +15062,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
} }
#if 0 #if 0
if (ImGui::TreeNode("Tables", "Tables (%d)", g.Tables.Data.Size)) if (ImGui::TreeNode("Tables", "Tables (%d)", g.Tables.GetSize()))
{ {
ImGui::TreePop(); ImGui::TreePop();
} }

11
imgui.h
View File

@ -662,6 +662,7 @@ namespace ImGui
IMGUI_API bool IsItemActivated(); // was the last item just made active (item was previously inactive). IMGUI_API bool IsItemActivated(); // was the last item just made active (item was previously inactive).
IMGUI_API bool IsItemDeactivated(); // was the last item just made inactive (item was previously active). Useful for Undo/Redo patterns with widgets that requires continuous editing. IMGUI_API bool IsItemDeactivated(); // was the last item just made inactive (item was previously active). Useful for Undo/Redo patterns with widgets that requires continuous editing.
IMGUI_API bool IsItemDeactivatedAfterEdit(); // was the last item just made inactive and made a value change when it was active? (e.g. Slider/Drag moved). Useful for Undo/Redo patterns with widgets that requires continuous editing. Note that you may get false positives (some widgets such as Combo()/ListBox()/Selectable() will return true even when clicking an already selected item). IMGUI_API bool IsItemDeactivatedAfterEdit(); // was the last item just made inactive and made a value change when it was active? (e.g. Slider/Drag moved). Useful for Undo/Redo patterns with widgets that requires continuous editing. Note that you may get false positives (some widgets such as Combo()/ListBox()/Selectable() will return true even when clicking an already selected item).
IMGUI_API bool IsItemToggledOpen(); // was the last item open state toggled? set by TreeNode().
IMGUI_API bool IsAnyItemHovered(); // is any item hovered? IMGUI_API bool IsAnyItemHovered(); // is any item hovered?
IMGUI_API bool IsAnyItemActive(); // is any item active? IMGUI_API bool IsAnyItemActive(); // is any item active?
IMGUI_API bool IsAnyItemFocused(); // is any item focused? IMGUI_API bool IsAnyItemFocused(); // is any item focused?
@ -1295,10 +1296,12 @@ template<typename T> void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Helper: ImVector<> // Helper: ImVector<>
// Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug). // Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug).
// You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our data structures are relying on it. //-----------------------------------------------------------------------------
// Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs. // - You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our public structures are relying on it.
// Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that, // - We use std-like naming convention here, which is a little unusual for this codebase.
// do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset. // - Important: clear() frees memory, resize(0) keep the allocated buffer. We use resize(0) a lot to intentionally recycle allocated buffers across frames and amortize our costs.
// - Important: our implementation does NOT call C++ constructors/destructors, we treat everything as raw data! This is intentional but be extra mindful of that,
// Do NOT use this class as a std::vector replacement in your own code! Many of the structures used by dear imgui can be safely initialized by a zero-memset.
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
template<typename T> template<typename T>

View File

@ -1668,7 +1668,7 @@ static void ShowDemoWindowWidgets()
{ {
// Submit an item (various types available) so we can query their status in the following block. // Submit an item (various types available) so we can query their status in the following block.
static int item_type = 1; static int item_type = 1;
ImGui::Combo("Item Type", &item_type, "Text\0Button\0Button (w/ repeat)\0Checkbox\0SliderFloat\0InputText\0InputFloat\0InputFloat3\0ColorEdit4\0MenuItem\0TreeNode (w/ double-click)\0ListBox\0"); ImGui::Combo("Item Type", &item_type, "Text\0Button\0Button (w/ repeat)\0Checkbox\0SliderFloat\0InputText\0InputFloat\0InputFloat3\0ColorEdit4\0MenuItem\0TreeNode\0TreeNode (w/ double-click)\0ListBox\0", 20);
ImGui::SameLine(); ImGui::SameLine();
HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions."); HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions.");
bool ret = false; bool ret = false;
@ -1685,8 +1685,9 @@ static void ShowDemoWindowWidgets()
if (item_type == 7) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) if (item_type == 7) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
if (item_type == 8) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged) if (item_type == 8) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
if (item_type == 9) { ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy) if (item_type == 9) { ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy)
if (item_type == 10){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy. if (item_type == 10){ ret = ImGui::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node
if (item_type == 11){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); } if (item_type == 11){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy.
if (item_type == 12){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); }
// Display the value of IsItemHovered() and other common item state functions. // Display the value of IsItemHovered() and other common item state functions.
// Note that the ImGuiHoveredFlags_XXX flags can be combined. // Note that the ImGuiHoveredFlags_XXX flags can be combined.
@ -1707,6 +1708,7 @@ static void ShowDemoWindowWidgets()
"IsItemDeactivatedAfterEdit() = %d\n" "IsItemDeactivatedAfterEdit() = %d\n"
"IsItemVisible() = %d\n" "IsItemVisible() = %d\n"
"IsItemClicked() = %d\n" "IsItemClicked() = %d\n"
"IsItemToggledOpen() = %d\n"
"GetItemRectMin() = (%.1f, %.1f)\n" "GetItemRectMin() = (%.1f, %.1f)\n"
"GetItemRectMax() = (%.1f, %.1f)\n" "GetItemRectMax() = (%.1f, %.1f)\n"
"GetItemRectSize() = (%.1f, %.1f)", "GetItemRectSize() = (%.1f, %.1f)",
@ -1724,6 +1726,7 @@ static void ShowDemoWindowWidgets()
ImGui::IsItemDeactivatedAfterEdit(), ImGui::IsItemDeactivatedAfterEdit(),
ImGui::IsItemVisible(), ImGui::IsItemVisible(),
ImGui::IsItemClicked(), ImGui::IsItemClicked(),
ImGui::IsItemToggledOpen(),
ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y, ImGui::GetItemRectMin().x, ImGui::GetItemRectMin().y,
ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y, ImGui::GetItemRectMax().x, ImGui::GetItemRectMax().y,
ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y ImGui::GetItemRectSize().x, ImGui::GetItemRectSize().y

View File

@ -64,6 +64,7 @@ Index of this file:
// Forward declarations // Forward declarations
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
struct ImBoolVector; // Store 1-bit per value
struct ImRect; // An axis-aligned rectangle (2 points) struct ImRect; // An axis-aligned rectangle (2 points)
struct ImDrawDataBuilder; // Helper to build a ImDrawData instance struct ImDrawDataBuilder; // Helper to build a ImDrawData instance
struct ImDrawListSharedData; // Data shared between all ImDrawList instances struct ImDrawListSharedData; // Data shared between all ImDrawList instances
@ -89,7 +90,7 @@ struct ImGuiTabBar; // Storage for a tab bar
struct ImGuiTabItem; // Storage for a tab item (within a tab bar) struct ImGuiTabItem; // Storage for a tab item (within a tab bar)
struct ImGuiWindow; // Storage for one window 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 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) struct ImGuiWindowSettings; // Storage for a window .ini settings (we keep one of those even if the actual window wasn't instanced during this session)
// Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists. // Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists.
typedef int ImGuiDataAuthority; // -> enum ImGuiDataAuthority_ // Enum: for storing the source authority (dock node vs window) of a field typedef int ImGuiDataAuthority; // -> enum ImGuiDataAuthority_ // Enum: for storing the source authority (dock node vs window) of a field
@ -140,7 +141,20 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// Generic helpers // Generic helpers
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
// - Macros
// - Helpers: Misc
// - Helpers: Bit manipulation
// - Helpers: Geometry
// - Helpers: String, Formatting
// - Helpers: UTF-8 <> wchar conversions
// - Helpers: ImVec2/ImVec4 operators
// - Helpers: Maths
// - Helper: ImBoolVector
// - Helper: ImPool<>
// - Helper: ImChunkStream<>
//-----------------------------------------------------------------------------
// Macros
#define IM_PI 3.14159265358979323846f #define IM_PI 3.14159265358979323846f
#ifdef _WIN32 #ifdef _WIN32
#define IM_NEWLINE "\r\n" // Play it nice with Windows users (2018/05 news: Microsoft announced that Notepad will finally display Unix-style carriage returns!) #define IM_NEWLINE "\r\n" // Play it nice with Windows users (2018/05 news: Microsoft announced that Notepad will finally display Unix-style carriage returns!)
@ -170,28 +184,20 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer
#define IMGUI_CDECL #define IMGUI_CDECL
#endif #endif
// Helpers: UTF-8 <> wchar
IMGUI_API int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count
IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // read one character. return input UTF-8 bytes count
IMGUI_API int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count
IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count)
IMGUI_API int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end); // return number of bytes to express one char in UTF-8
IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string in UTF-8
// Helpers: Misc // Helpers: Misc
IMGUI_API ImU32 ImHashData(const void* data, size_t data_size, ImU32 seed = 0);
IMGUI_API ImU32 ImHashStr(const char* data, size_t data_size = 0, ImU32 seed = 0);
IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size = NULL, int padding_bytes = 0); IMGUI_API void* ImFileLoadToMemory(const char* filename, const char* file_open_mode, size_t* out_file_size = NULL, int padding_bytes = 0);
IMGUI_API FILE* ImFileOpen(const char* filename, const char* file_open_mode); IMGUI_API FILE* ImFileOpen(const char* filename, const char* file_open_mode);
static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; }
static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; }
static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; }
static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; }
#define ImQsort qsort #define ImQsort qsort
IMGUI_API ImU32 ImHashData(const void* data, size_t data_size, ImU32 seed = 0);
IMGUI_API ImU32 ImHashStr(const char* data, size_t data_size = 0, ImU32 seed = 0);
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS #ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
static inline ImU32 ImHash(const void* data, int size, ImU32 seed = 0) { return size ? ImHashData(data, (size_t)size, seed) : ImHashStr((const char*)data, 0, seed); } // [moved to ImHashStr/ImHashData in 1.68] static inline ImU32 ImHash(const void* data, int size, ImU32 seed = 0) { return size ? ImHashData(data, (size_t)size, seed) : ImHashStr((const char*)data, 0, seed); } // [moved to ImHashStr/ImHashData in 1.68]
#endif #endif
// Helpers: Bit manipulation
static inline bool ImIsPowerOfTwo(int v) { return v != 0 && (v & (v - 1)) == 0; }
static inline int ImUpperPowerOfTwo(int v) { v--; v |= v >> 1; v |= v >> 2; v |= v >> 4; v |= v >> 8; v |= v >> 16; v++; return v; }
// Helpers: Geometry // Helpers: Geometry
IMGUI_API ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p); IMGUI_API ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p);
IMGUI_API bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p); IMGUI_API bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p);
@ -199,7 +205,7 @@ IMGUI_API ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b,
IMGUI_API void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w); IMGUI_API void ImTriangleBarycentricCoords(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p, float& out_u, float& out_v, float& out_w);
IMGUI_API ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy); IMGUI_API ImGuiDir ImGetDirQuadrantFromDelta(float dx, float dy);
// Helpers: String // Helpers: String, Formatting
IMGUI_API int ImStricmp(const char* str1, const char* str2); IMGUI_API int ImStricmp(const char* str1, const char* str2);
IMGUI_API int ImStrnicmp(const char* str1, const char* str2, size_t count); IMGUI_API int ImStrnicmp(const char* str1, const char* str2, size_t count);
IMGUI_API void ImStrncpy(char* dst, const char* src, size_t count); IMGUI_API void ImStrncpy(char* dst, const char* src, size_t count);
@ -218,6 +224,16 @@ IMGUI_API const char* ImParseFormatFindStart(const char* format);
IMGUI_API const char* ImParseFormatFindEnd(const char* format); IMGUI_API const char* ImParseFormatFindEnd(const char* format);
IMGUI_API const char* ImParseFormatTrimDecorations(const char* format, char* buf, size_t buf_size); IMGUI_API const char* ImParseFormatTrimDecorations(const char* format, char* buf, size_t buf_size);
IMGUI_API int ImParseFormatPrecision(const char* format, int default_value); IMGUI_API int ImParseFormatPrecision(const char* format, int default_value);
static inline bool ImCharIsBlankA(char c) { return c == ' ' || c == '\t'; }
static inline bool ImCharIsBlankW(unsigned int c) { return c == ' ' || c == '\t' || c == 0x3000; }
// Helpers: UTF-8 <> wchar conversions
IMGUI_API int ImTextStrToUtf8(char* buf, int buf_size, const ImWchar* in_text, const ImWchar* in_text_end); // return output UTF-8 bytes count
IMGUI_API int ImTextCharFromUtf8(unsigned int* out_char, const char* in_text, const char* in_text_end); // read one character. return input UTF-8 bytes count
IMGUI_API int ImTextStrFromUtf8(ImWchar* buf, int buf_size, const char* in_text, const char* in_text_end, const char** in_remaining = NULL); // return input UTF-8 bytes count
IMGUI_API int ImTextCountCharsFromUtf8(const char* in_text, const char* in_text_end); // return number of UTF-8 code-points (NOT bytes count)
IMGUI_API int ImTextCountUtf8BytesFromChar(const char* in_text, const char* in_text_end); // return number of bytes to express one char in UTF-8
IMGUI_API int ImTextCountUtf8BytesFromStr(const ImWchar* in_text, const ImWchar* in_text_end); // return number of bytes to express string in UTF-8
// Helpers: ImVec2/ImVec4 operators // Helpers: ImVec2/ImVec4 operators
// We are keeping those disabled by default so they don't leak in user space, to allow user enabling implicit cast operators between ImVec2 and their own types (using IM_VEC2_CLASS_EXTRA etc.) // We are keeping those disabled by default so they don't leak in user space, to allow user enabling implicit cast operators between ImVec2 and their own types (using IM_VEC2_CLASS_EXTRA etc.)
@ -283,9 +299,9 @@ 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 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); } static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
// Helper: ImBoolVector. Store 1-bit per value. // Helper: ImBoolVector
// Note that Resize() currently clears the whole vector. // Store 1-bit per value. Note that Resize() currently clears the whole vector.
struct ImBoolVector struct IMGUI_API ImBoolVector
{ {
ImVector<int> Storage; ImVector<int> Storage;
ImBoolVector() { } ImBoolVector() { }
@ -295,29 +311,52 @@ struct ImBoolVector
void SetBit(int n, bool v) { int off = (n >> 5); int mask = 1 << (n & 31); if (v) Storage[off] |= mask; else Storage[off] &= ~mask; } void SetBit(int n, bool v) { int off = (n >> 5); int mask = 1 << (n & 31); if (v) Storage[off] |= mask; else Storage[off] &= ~mask; }
}; };
// 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, // 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,
// Honor constructor/destructor. Add/remove invalidate all pointers. Indexes have the same lifetime as the associated object. // Honor constructor/destructor. Add/remove invalidate all pointers. Indexes have the same lifetime as the associated object.
typedef int ImPoolIdx; typedef int ImPoolIdx;
template<typename T> template<typename T>
struct IMGUI_API ImPool struct IMGUI_API ImPool
{ {
ImVector<T> Data; // Contiguous data ImVector<T> Buf; // Contiguous data
ImGuiStorage Map; // ID->Index ImGuiStorage Map; // ID->Index
ImPoolIdx FreeIdx; // Next free idx to use ImPoolIdx FreeIdx; // Next free idx to use
ImPool() { FreeIdx = 0; } ImPool() { FreeIdx = 0; }
~ImPool() { Clear(); } ~ImPool() { Clear(); }
T* GetByKey(ImGuiID key) { int idx = Map.GetInt(key, -1); return (idx != -1) ? &Data[idx] : NULL; } T* GetByKey(ImGuiID key) { int idx = Map.GetInt(key, -1); return (idx != -1) ? &Buf[idx] : NULL; }
T* GetByIndex(ImPoolIdx n) { return &Data[n]; } T* GetByIndex(ImPoolIdx n) { return &Buf[n]; }
ImPoolIdx GetIndex(const T* p) const { IM_ASSERT(p >= Data.Data && p < Data.Data + Data.Size); return (ImPoolIdx)(p - Data.Data); } ImPoolIdx GetIndex(const T* p) const { IM_ASSERT(p >= Buf.Data && p < Buf.Data + Buf.Size); return (ImPoolIdx)(p - Buf.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(); } T* GetOrAddByKey(ImGuiID key) { int* p_idx = Map.GetIntRef(key, -1); if (*p_idx != -1) return &Buf[*p_idx]; *p_idx = FreeIdx; return Add(); }
bool Contains(const T* p) const { return (p >= Data.Data && p < Data.Data + Data.Size); } bool Contains(const T* p) const { return (p >= Buf.Data && p < Buf.Data + Buf.Size); }
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; } void Clear() { for (int n = 0; n < Map.Data.Size; n++) { int idx = Map.Data[n].val_i; if (idx != -1) Buf[idx].~T(); } Map.Clear(); Buf.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]; } T* Add() { int idx = FreeIdx; if (idx == Buf.Size) { Buf.resize(Buf.Size + 1); FreeIdx++; } else { FreeIdx = *(int*)&Buf[idx]; } IM_PLACEMENT_NEW(&Buf[idx]) T(); return &Buf[idx]; }
void Remove(ImGuiID key, const T* p) { Remove(key, GetIndex(p)); } void Remove(ImGuiID key, const T* p) { Remove(key, GetIndex(p)); }
void Remove(ImGuiID key, ImPoolIdx idx) { Data[idx].~T(); *(int*)&Data[idx] = FreeIdx; FreeIdx = idx; Map.SetInt(key, -1); } void Remove(ImGuiID key, ImPoolIdx idx) { Buf[idx].~T(); *(int*)&Buf[idx] = FreeIdx; FreeIdx = idx; Map.SetInt(key, -1); }
void Reserve(int capacity) { Data.reserve(capacity); Map.Data.reserve(capacity); } void Reserve(int capacity) { Buf.reserve(capacity); Map.Data.reserve(capacity); }
int GetSize() const { return Data.Size; } int GetSize() const { return Buf.Size; }
};
// Helper: ImChunkStream<>
// Build and iterate a contiguous stream of variable-sized structures.
// This is used by Settings to store persistent data while reducing allocation count.
// We store the chunk size first, and align the final size on 4 bytes boundaries (this what the '(X + 3) & ~3' statement is for)
// The tedious/zealous amount of casting is to avoid -Wcast-align warnings.
template<typename T>
struct IMGUI_API ImChunkStream
{
ImVector<char> Buf;
void clear() { Buf.clear(); }
bool empty() const { return Buf.Size == 0; }
int size() const { return Buf.Size; }
T* alloc_chunk(size_t sz) { size_t HDR_SZ = 4; sz = ((HDR_SZ + sz) + 3u) & ~3u; int off = Buf.Size; Buf.resize(off + (int)sz); ((int*)(void*)(Buf.Data + off))[0] = (int)sz; return (T*)(void*)(Buf.Data + off + (int)HDR_SZ); }
T* begin() { size_t HDR_SZ = 4; if (!Buf.Data) return NULL; return (T*)(void*)(Buf.Data + HDR_SZ); }
T* next_chunk(T* p) { size_t HDR_SZ = 4; IM_ASSERT(p >= begin() && p < end()); p = (T*)(void*)((char*)(void*)p + chunk_size(p)); if (p == (T*)(void*)((char*)end() + HDR_SZ)) return (T*)0; IM_ASSERT(p < end()); return p; }
int chunk_size(const T* p) { return ((const int*)p)[-1]; }
T* end() { return (T*)(void*)(Buf.Data + Buf.Size); }
int offset_from_ptr(const T* p) { IM_ASSERT(p >= begin() && p < end()); const ptrdiff_t off = (const char*)p - Buf.Data; return (int)off; }
T* ptr_from_offset(int off) { IM_ASSERT(off >= 4 && off < Buf.Size); return (T*)(void*)(Buf.Data + off); }
}; };
//----------------------------------------------------------------------------- //-----------------------------------------------------------------------------
@ -337,7 +376,7 @@ enum ImGuiButtonFlags_
ImGuiButtonFlags_DontClosePopups = 1 << 7, // disable automatically closing parent popup on press // [UNUSED] ImGuiButtonFlags_DontClosePopups = 1 << 7, // disable automatically closing parent popup on press // [UNUSED]
ImGuiButtonFlags_Disabled = 1 << 8, // disable interactions ImGuiButtonFlags_Disabled = 1 << 8, // disable interactions
ImGuiButtonFlags_AlignTextBaseLine = 1 << 9, // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine ImGuiButtonFlags_AlignTextBaseLine = 1 << 9, // vertically align button to match text baseline - ButtonEx() only // FIXME: Should be removed and handled by SmallButton(), not possible currently because of DC.CursorPosPrevLine
ImGuiButtonFlags_NoKeyModifiers = 1 << 10, // disable interaction if a key modifier is held ImGuiButtonFlags_NoKeyModifiers = 1 << 10, // disable mouse interaction if a key modifier is held
ImGuiButtonFlags_NoHoldingActiveID = 1 << 11, // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only) ImGuiButtonFlags_NoHoldingActiveID = 1 << 11, // don't set ActiveId while holding the mouse (ImGuiButtonFlags_PressedOnClick only)
ImGuiButtonFlags_PressedOnDragDropHold = 1 << 12, // press when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers) ImGuiButtonFlags_PressedOnDragDropHold = 1 << 12, // press when held into while we are drag and dropping another item (used by e.g. tree nodes, collapsing headers)
ImGuiButtonFlags_NoNavFocus = 1 << 13, // don't override navigation focus when activated ImGuiButtonFlags_NoNavFocus = 1 << 13, // don't override navigation focus when activated
@ -416,8 +455,9 @@ enum ImGuiItemStatusFlags_
ImGuiItemStatusFlags_HasDisplayRect = 1 << 1, ImGuiItemStatusFlags_HasDisplayRect = 1 << 1,
ImGuiItemStatusFlags_Edited = 1 << 2, // Value exposed by item was edited in the current frame (should match the bool return value of most widgets) ImGuiItemStatusFlags_Edited = 1 << 2, // Value exposed by item was edited in the current frame (should match the bool return value of most widgets)
ImGuiItemStatusFlags_ToggledSelection = 1 << 3, // Set when Selectable(), TreeNode() reports toggling a selection. We can't report "Selected" because reporting the change allows us to handle clipping with less issues. ImGuiItemStatusFlags_ToggledSelection = 1 << 3, // Set when Selectable(), TreeNode() reports toggling a selection. We can't report "Selected" because reporting the change allows us to handle clipping with less issues.
ImGuiItemStatusFlags_HasDeactivated = 1 << 4, // Set if the widget/group is able to provide data for the ImGuiItemStatusFlags_Deactivated flag. ImGuiItemStatusFlags_ToggledOpen = 1 << 4, // Set when TreeNode() reports toggling their open state.
ImGuiItemStatusFlags_Deactivated = 1 << 5 // Only valid if ImGuiItemStatusFlags_HasDeactivated is set. ImGuiItemStatusFlags_HasDeactivated = 1 << 5, // Set if the widget/group is able to provide data for the ImGuiItemStatusFlags_Deactivated flag.
ImGuiItemStatusFlags_Deactivated = 1 << 6 // Only valid if ImGuiItemStatusFlags_HasDeactivated is set.
#ifdef IMGUI_ENABLE_TEST_ENGINE #ifdef IMGUI_ENABLE_TEST_ENGINE
, // [imgui_tests only] , // [imgui_tests only]
@ -675,9 +715,10 @@ struct IMGUI_API ImGuiInputTextState
}; };
// Windows data saved in imgui.ini file // Windows data saved in imgui.ini file
// Because we never destroy or rename ImGuiWindowSettings, we can store the names in a separate buffer easily.
// (this is designed to be stored in a ImChunkStream buffer, with the variable-length Name following our structure)
struct ImGuiWindowSettings struct ImGuiWindowSettings
{ {
char* Name;
ImGuiID ID; ImGuiID ID;
ImVec2ih Pos; // NB: Settings position are stored RELATIVE to the viewport! Whereas runtime ones are absolute positions. ImVec2ih Pos; // NB: Settings position are stored RELATIVE to the viewport! Whereas runtime ones are absolute positions.
ImVec2ih Size; ImVec2ih Size;
@ -688,7 +729,8 @@ struct ImGuiWindowSettings
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. 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; bool Collapsed;
ImGuiWindowSettings() { Name = NULL; ID = 0; Pos = Size = ViewportPos = ImVec2ih(0, 0); ViewportId = DockId = ClassId = 0; DockOrder = -1; Collapsed = false; } ImGuiWindowSettings() { ID = 0; Pos = Size = ViewportPos = ImVec2ih(0, 0); ViewportId = DockId = ClassId = 0; DockOrder = -1; Collapsed = false; }
char* GetName() { return (char*)(this + 1); }
}; };
struct ImGuiSettingsHandler struct ImGuiSettingsHandler
@ -1198,7 +1240,7 @@ struct ImGuiContext
float SettingsDirtyTimer; // Save .ini Settings to memory when time reaches zero float SettingsDirtyTimer; // Save .ini Settings to memory when time reaches zero
ImGuiTextBuffer SettingsIniData; // In memory .ini settings ImGuiTextBuffer SettingsIniData; // In memory .ini settings
ImVector<ImGuiSettingsHandler> SettingsHandlers; // List of .ini settings handlers ImVector<ImGuiSettingsHandler> SettingsHandlers; // List of .ini settings handlers
ImVector<ImGuiWindowSettings> SettingsWindows; // ImGuiWindow .ini settings entries (parsed from the last loaded .ini file and maintained on saving) ImChunkStream<ImGuiWindowSettings> SettingsWindows; // ImGuiWindow .ini settings entries
// Logging // Logging
bool LogEnabled; bool LogEnabled;
@ -1529,7 +1571,7 @@ struct IMGUI_API ImGuiWindow
ImVector<ImGuiColumns> ColumnsStorage; ImVector<ImGuiColumns> ColumnsStorage;
float FontWindowScale; // User scale multiplier per-window, via SetWindowFontScale() float FontWindowScale; // User scale multiplier per-window, via SetWindowFontScale()
float FontDpiScale; float FontDpiScale;
int SettingsIdx; // Index into SettingsWindow[] (indices are always valid as we only grow the array from the back) int SettingsOffset; // Offset into SettingsWindows[] (offsets are always valid as we only grow the array from the back)
ImDrawList* DrawList; // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer) ImDrawList* DrawList; // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer)
ImDrawList DrawListInst; ImDrawList DrawListInst;

View File

@ -5279,7 +5279,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
// - OpenOnDoubleClick .............. double-click anywhere to open // - OpenOnDoubleClick .............. double-click anywhere to open
// - OpenOnArrow .................... single-click on arrow to open // - OpenOnArrow .................... single-click on arrow to open
// - OpenOnDoubleClick|OpenOnArrow .. single-click on arrow or double-click anywhere to open // - OpenOnDoubleClick|OpenOnArrow .. single-click on arrow or double-click anywhere to open
ImGuiButtonFlags button_flags = ImGuiButtonFlags_NoKeyModifiers; ImGuiButtonFlags button_flags = 0;
if (flags & ImGuiTreeNodeFlags_AllowItemOverlap) if (flags & ImGuiTreeNodeFlags_AllowItemOverlap)
button_flags |= ImGuiButtonFlags_AllowItemOverlap; button_flags |= ImGuiButtonFlags_AllowItemOverlap;
if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick)
@ -5287,23 +5287,31 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
if (!is_leaf) if (!is_leaf)
button_flags |= ImGuiButtonFlags_PressedOnDragDropHold; button_flags |= ImGuiButtonFlags_PressedOnDragDropHold;
// We allow clicking on the arrow section with keyboard modifiers held, in order to easily
// allow browsing a tree while preserving selection with code implementing multi-selection patterns.
// When clicking on the rest of the tree node we always disallow keyboard modifiers.
const float hit_padding_x = style.TouchExtraPadding.x;
const float arrow_hit_x1 = (text_pos.x - text_offset_x) - hit_padding_x;
const float arrow_hit_x2 = (text_pos.x - text_offset_x) + (g.FontSize + padding.x * 2.0f) + hit_padding_x;
if (window != g.HoveredWindow || !(g.IO.MousePos.x >= arrow_hit_x1 && g.IO.MousePos.x < arrow_hit_x2))
button_flags |= ImGuiButtonFlags_NoKeyModifiers;
bool selected = (flags & ImGuiTreeNodeFlags_Selected) != 0; bool selected = (flags & ImGuiTreeNodeFlags_Selected) != 0;
const bool was_selected = selected; const bool was_selected = selected;
bool hovered, held; bool hovered, held;
bool pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags); bool pressed = ButtonBehavior(interact_bb, id, &hovered, &held, button_flags);
bool toggled = false;
if (!is_leaf) if (!is_leaf)
{ {
bool toggled = false;
if (pressed) if (pressed)
{ {
const float arrow_x1 = text_pos.x - text_offset_x; if ((flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) == 0 || (g.NavActivateId == id))
const float arrow_x2 = arrow_x1 + g.FontSize + padding.x * 2.0f; toggled = true;
toggled = !(flags & (ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick)) || (g.NavActivateId == id);
if (flags & ImGuiTreeNodeFlags_OpenOnArrow) if (flags & ImGuiTreeNodeFlags_OpenOnArrow)
toggled |= IsMouseHoveringRect(ImVec2(arrow_x1, interact_bb.Min.y), ImVec2(arrow_x2, interact_bb.Max.y)) && (!g.NavDisableMouseHover); toggled |= (g.IO.MousePos.x >= arrow_hit_x1 && g.IO.MousePos.x < arrow_hit_x2) && (!g.NavDisableMouseHover); // Lightweight equivalent of IsMouseHoveringRect() since ButtonBehavior() already did the job
if (flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) if ((flags & ImGuiTreeNodeFlags_OpenOnDoubleClick) && g.IO.MouseDoubleClicked[0])
toggled |= g.IO.MouseDoubleClicked[0]; toggled = true;
if (g.DragDropActive && is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again. if (g.DragDropActive && is_open) // When using Drag and Drop "hold to open" we keep the node highlighted after opening, but never close it again.
toggled = false; toggled = false;
} }
@ -5323,6 +5331,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
{ {
is_open = !is_open; is_open = !is_open;
window->DC.StateStorage->SetInt(id, is_open); window->DC.StateStorage->SetInt(id, is_open);
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledOpen;
} }
} }
if (flags & ImGuiTreeNodeFlags_AllowItemOverlap) if (flags & ImGuiTreeNodeFlags_AllowItemOverlap)