mirror of
https://github.com/ocornut/imgui.git
synced 2026-02-27 22:05:08 +00:00
Merge branch 'master' into docking
# Conflicts: # backends/imgui_impl_sdlgpu3.cpp # imgui.cpp
This commit is contained in:
@@ -24,6 +24,7 @@
|
||||
|
||||
// CHANGELOG
|
||||
// 2026-XX-XX: Platform: Added support for multiple windows via the ImGuiPlatformIO interface.
|
||||
// 2026-02-25: Removed unnecessary call to SDL_WaitForGPUIdle when releasing vertex/index buffers. (#9262)
|
||||
// 2025-11-26: macOS version can use MSL shaders in order to support macOS 10.14+ (vs Metallib shaders requiring macOS 14+). Requires calling SDL_CreateGPUDevice() with SDL_GPU_SHADERFORMAT_MSL.
|
||||
// 2025-09-18: Call platform_io.ClearRendererHandlers() on shutdown.
|
||||
// 2025-08-20: Added ImGui_ImplSDLGPU3_InitInfo::SwapchainComposition and ImGui_ImplSDLGPU3_InitInfo::PresentMode to configure how secondary viewports are created.
|
||||
@@ -133,8 +134,7 @@ static void CreateOrResizeBuffers(SDL_GPUBuffer** buffer, SDL_GPUTransferBuffer*
|
||||
ImGui_ImplSDLGPU3_Data* bd = ImGui_ImplSDLGPU3_GetBackendData();
|
||||
ImGui_ImplSDLGPU3_InitInfo* v = &bd->InitInfo;
|
||||
|
||||
// FIXME-OPT: Not optimal, but this is fairly rarely called.
|
||||
SDL_WaitForGPUIdle(v->Device);
|
||||
// There is no need for calling SDL_WaitForGPUIdle here, as SDL3 will handle deferred buffer deletion automatically.
|
||||
SDL_ReleaseGPUBuffer(v->Device, *buffer);
|
||||
SDL_ReleaseGPUTransferBuffer(v->Device, *transferbuffer);
|
||||
|
||||
|
||||
@@ -37,7 +37,7 @@
|
||||
#include <emscripten/version.h>
|
||||
|
||||
#ifdef __EMSCRIPTEN_MAJOR__
|
||||
#if (__EMSCRIPTEN_MAJOR__ >= 4) && (__EMSCRIPTEN_MINOR__ >= 0) && (__EMSCRIPTEN_TINY__ >= 10)
|
||||
#if (__EMSCRIPTEN_MAJOR__ >= 5) || ((__EMSCRIPTEN_MAJOR__ >= 4) && (__EMSCRIPTEN_MINOR__ >= 0) && (__EMSCRIPTEN_TINY__ >= 10))
|
||||
#define IMGUI_IMPL_WEBGPU_BACKEND_DAWN
|
||||
#else
|
||||
#define IMGUI_IMPL_WEBGPU_BACKEND_WGPU
|
||||
|
||||
@@ -41,11 +41,39 @@ HOW TO UPDATE?
|
||||
|
||||
Breaking Changes:
|
||||
|
||||
- Combo(), ListBox(): commented out legacy signatures which were obsoleted in 1.90
|
||||
(Nov 2023), when the getter callback type was changed from:
|
||||
getter type: bool (*getter)(void* user_data, int idx, const char** out_text)
|
||||
To:
|
||||
getter type: const char* (*getter)(void* user_data, int idx)
|
||||
|
||||
Other Changes:
|
||||
|
||||
- TreeNode:
|
||||
- Moved TreeNodeGetOpen() helper to public API. I was hesitant to make this public
|
||||
because I intend to provide a more generic and feature-full version, but in the meanwhile
|
||||
this will do. (#3823, #9251, #7553, #6754, #5423, #2958, #2079, #1947, #1131, #722)
|
||||
- In 'Demo->Property Editor' demonstrate a way to perform tree clipping by fast-forwarding
|
||||
through non-visible chunks. (#3823, #9251, #6990, #6042)
|
||||
Using SetNextItemStorageID() + TreeNodeGetOpen() makes this notably easier than
|
||||
it was prior to 1.91.
|
||||
- InputText:
|
||||
- Shift+Enter in multi-line editor always adds a new line, regardless of
|
||||
ImGuiInputTextFlags_CtrlEnterForNewLine being set or not. (#9239)
|
||||
- Style: border sizes are now scaled (and rounded) by ScaleAllSizes().
|
||||
- Clipper: clear DisplayStart/DisplayEnd fields when Step() returns false.
|
||||
- Demo: fixed IMGUI_DEMO_MARKER locations for examples applets. (#9261, #3689) [@pthom]
|
||||
- Clipper:
|
||||
- Clear `DisplayStart`/`DisplayEnd` fields when `Step()` returns false.
|
||||
- Added `UserIndex` helper storage. This is solely a convenience for cases where
|
||||
you may want to carry an index around.
|
||||
- Backends:
|
||||
- SDLGPU3: removed unnecessary call to SDL_WaitForGPUIdle when releasing
|
||||
vertex/index buffers. (#9262) [@jaenis]
|
||||
- WebGPU: fixed version check for Emscripten 5.0.0+.
|
||||
- Examples:
|
||||
- Emscripten: added `tabindex=-1` to canvas in our shell_minimal.htm. Without it,
|
||||
the canvas was not focusable in the DOM, which in turn make some backends
|
||||
(e.g. pongasoft/emscripten-glfw) not receive focus loss events. (#9259) [@pthom]
|
||||
- WGPU: fixed undefined behaviors in example code for requesting adapter
|
||||
and device. (#9246, #9256) [@r-lyeh]
|
||||
|
||||
|
||||
@@ -29,7 +29,7 @@
|
||||
</style>
|
||||
</head>
|
||||
<body>
|
||||
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()"></canvas>
|
||||
<canvas class="emscripten" id="canvas" oncontextmenu="event.preventDefault()" tabindex=-1></canvas>
|
||||
<script type='text/javascript'>
|
||||
var Module = {
|
||||
preRun: [],
|
||||
|
||||
11
imgui.cpp
11
imgui.cpp
@@ -402,6 +402,9 @@ IMPLEMENTING SUPPORT for ImGuiBackendFlags_RendererHasTextures:
|
||||
- likewise io.MousePos and GetMousePos() will use OS coordinates.
|
||||
If you query mouse positions to interact with non-imgui coordinates you will need to offset them, e.g. subtract GetWindowViewport()->Pos.
|
||||
|
||||
- 2026/02/27 (1.92.7) - Commented out legacy signature for Combo(), ListBox(), signatures which were obsoleted in 1.90 (Nov 2023), when the getter callback type was changed.
|
||||
- Old getter type: bool (*getter)(void* user_data, int idx, const char** out_text) // Set label + return bool. False replaced label with placeholder.
|
||||
- New getter type: const char* (*getter)(void* user_data, int idx) // Return label or NULL/empty label if missing
|
||||
- 2026/01/08 (1.92.6) - Commented out legacy names obsoleted in 1.90 (Sept 2023): 'BeginChildFrame()' --> 'BeginChild()' with 'ImGuiChildFlags_FrameStyle'. 'EndChildFrame()' --> 'EndChild()'. 'ShowStackToolWindow()' --> 'ShowIDStackToolWindow()'. 'IM_OFFSETOF()' --> 'offsetof()'.
|
||||
- 2026/01/07 (1.92.6) - Popups: changed compile-time 'ImGuiPopupFlags popup_flags = 1' default value to be '= 0' for BeginPopupContextItem(), BeginPopupContextWindow(), BeginPopupContextVoid(), OpenPopupOnItemClick(). Default value has same meaning before and after.
|
||||
- Refer to GitHub topic #9157 if you have any question.
|
||||
@@ -4377,6 +4380,7 @@ ImGuiContext::ImGuiContext(ImFontAtlas* shared_font_atlas)
|
||||
SettingsLoaded = false;
|
||||
SettingsDirtyTimer = 0.0f;
|
||||
HookIdNext = 0;
|
||||
DemoMarkerCallback = NULL;
|
||||
|
||||
memset(LocalizationTable, 0, sizeof(LocalizationTable));
|
||||
|
||||
@@ -5180,6 +5184,13 @@ void ImGui::MemFree(void* ptr)
|
||||
return (*GImAllocatorFreeFunc)(ptr, GImAllocatorUserData);
|
||||
}
|
||||
|
||||
void ImGui::DemoMarker(const char* file, int line, const char* section)
|
||||
{
|
||||
ImGuiContext& g = *GImGui;
|
||||
if (g.DemoMarkerCallback != NULL)
|
||||
g.DemoMarkerCallback(file, line, section);
|
||||
}
|
||||
|
||||
// We record the number of allocation in recent frames, as a way to audit/sanitize our guiding principles of "no allocations on idle/repeating frames"
|
||||
void ImGui::DebugAllocHook(ImGuiDebugAllocInfo* info, int frame_count, void* ptr, size_t size)
|
||||
{
|
||||
|
||||
11
imgui.h
11
imgui.h
@@ -30,7 +30,7 @@
|
||||
// Library Version
|
||||
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345')
|
||||
#define IMGUI_VERSION "1.92.7 WIP"
|
||||
#define IMGUI_VERSION_NUM 19262
|
||||
#define IMGUI_VERSION_NUM 19263
|
||||
#define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000
|
||||
#define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198
|
||||
#define IMGUI_HAS_VIEWPORT // In 'docking' WIP branch.
|
||||
@@ -764,6 +764,7 @@ namespace ImGui
|
||||
IMGUI_API bool CollapsingHeader(const char* label, bool* p_visible, ImGuiTreeNodeFlags flags = 0); // when 'p_visible != NULL': if '*p_visible==true' display an additional small close button on upper right of the header which will set the bool to false when clicked, if '*p_visible==false' don't display the header.
|
||||
IMGUI_API void SetNextItemOpen(bool is_open, ImGuiCond cond = 0); // set next TreeNode/CollapsingHeader open state.
|
||||
IMGUI_API void SetNextItemStorageID(ImGuiID storage_id); // set id to use for open/close storage (default to same as item id).
|
||||
IMGUI_API bool TreeNodeGetOpen(ImGuiID storage_id); // retrieve tree node open/close state.
|
||||
|
||||
// Widgets: Selectables
|
||||
// - A selectable highlights when hovered, and can display another color when selected.
|
||||
@@ -1305,7 +1306,7 @@ enum ImGuiInputTextFlags_
|
||||
ImGuiInputTextFlags_AllowTabInput = 1 << 5, // Pressing TAB input a '\t' character into the text field
|
||||
ImGuiInputTextFlags_EnterReturnsTrue = 1 << 6, // Return 'true' when Enter is pressed (as opposed to every time the value was modified). Consider using IsItemDeactivatedAfterEdit() instead!
|
||||
ImGuiInputTextFlags_EscapeClearsAll = 1 << 7, // Escape key clears content if not empty, and deactivate otherwise (contrast to default behavior of Escape to revert)
|
||||
ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 8, // In multi-line mode, validate with Enter, add new line with Ctrl+Enter (default is opposite: validate with Ctrl+Enter, add line with Enter).
|
||||
ImGuiInputTextFlags_CtrlEnterForNewLine = 1 << 8, // In multi-line mode: validate with Enter, add new line with Ctrl+Enter (default is opposite: validate with Ctrl+Enter, add line with Enter). Note that Shift+Enter always enter a new line either way.
|
||||
|
||||
// Other options
|
||||
ImGuiInputTextFlags_ReadOnly = 1 << 9, // Read-only mode
|
||||
@@ -2985,6 +2986,7 @@ struct ImGuiListClipper
|
||||
ImGuiContext* Ctx; // Parent UI context
|
||||
int DisplayStart; // First item to display, updated by each call to Step()
|
||||
int DisplayEnd; // End of items to display (exclusive)
|
||||
int UserIndex; // Helper storage for user convenience/code. Optional, and otherwise unused if you don't use it.
|
||||
int ItemsCount; // [Internal] Number of items
|
||||
float ItemsHeight; // [Internal] Height of item after a first step and item submission can calculate it
|
||||
double StartPosY; // [Internal] Cursor position at the time of Begin() or after table frozen rows are all processed
|
||||
@@ -4318,12 +4320,11 @@ namespace ImGui
|
||||
IMGUI_API ImVec2 GetContentRegionMax(); // Content boundaries max (e.g. window boundaries including scrolling, or current column boundaries). You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()!
|
||||
IMGUI_API ImVec2 GetWindowContentRegionMin(); // Content boundaries min for the window (roughly (0,0)-Scroll), in window-local coordinates. You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()!
|
||||
IMGUI_API ImVec2 GetWindowContentRegionMax(); // Content boundaries max for the window (roughly (0,0)+Size-Scroll), in window-local coordinates. You should never need this. Always use GetCursorScreenPos() and GetContentRegionAvail()!
|
||||
// OBSOLETED in 1.90.0 (from September 2023)
|
||||
IMGUI_API bool Combo(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int popup_max_height_in_items = -1);
|
||||
IMGUI_API bool ListBox(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int height_in_items = -1);
|
||||
|
||||
// Some of the older obsolete names along with their replacement (commented out so they are not reported in IDE)
|
||||
// OBSOLETED in 1.90.0 (from September 2023)
|
||||
//IMGUI_API bool Combo(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int popup_max_height_in_items = -1); // Getter signature changed. See 2023/09/15 and 2026/02/27 commits.
|
||||
//IMGUI_API bool ListBox(const char* label, int* current_item, bool (*old_callback)(void* user_data, int idx, const char** out_text), void* user_data, int items_count, int height_in_items = -1); // Getter signature changed. See 2023/09/15 and 2026/02/27 commits.
|
||||
//inline bool BeginChild(const char* str_id, const ImVec2& size_arg, bool borders, ImGuiWindowFlags window_flags) { return BeginChild(str_id, size_arg, borders ? ImGuiChildFlags_Borders : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Borders
|
||||
//inline bool BeginChild(ImGuiID id, const ImVec2& size_arg, bool borders, ImGuiWindowFlags window_flags) { return BeginChild(id, size_arg, borders ? ImGuiChildFlags_Borders : ImGuiChildFlags_None, window_flags); } // Unnecessary as true == ImGuiChildFlags_Borders
|
||||
//inline bool BeginChildFrame(ImGuiID id, const ImVec2& size, ImGuiWindowFlags flags = 0) { return BeginChild(id, size, ImGuiChildFlags_FrameStyle, flags); }
|
||||
|
||||
193
imgui_demo.cpp
193
imgui_demo.cpp
@@ -295,18 +295,15 @@ static void ShowDockingDisabledMessage()
|
||||
}
|
||||
|
||||
// Helper to wire demo markers located in code to an interactive browser (e.g. imgui_manual)
|
||||
typedef void (*ImGuiDemoMarkerCallback)(const char* file, int line, const char* section, void* user_data);
|
||||
extern ImGuiDemoMarkerCallback GImGuiDemoMarkerCallback;
|
||||
extern void* GImGuiDemoMarkerCallbackUserData;
|
||||
ImGuiDemoMarkerCallback GImGuiDemoMarkerCallback = NULL;
|
||||
void* GImGuiDemoMarkerCallbackUserData = NULL;
|
||||
#define IMGUI_DEMO_MARKER(section) do { if (GImGuiDemoMarkerCallback != NULL) GImGuiDemoMarkerCallback("imgui_demo.cpp", __LINE__, section, GImGuiDemoMarkerCallbackUserData); } while (0)
|
||||
#if IMGUI_VERSION_NUM >= 19263
|
||||
namespace ImGui { extern IMGUI_API void DemoMarker(const char* file, int line, const char* section); };
|
||||
#define IMGUI_DEMO_MARKER(section) do { ImGui::DemoMarker("imgui_demo.cpp", __LINE__, section); } while (0)
|
||||
#endif
|
||||
|
||||
// Sneakily forward declare functions which aren't worth putting in public API yet
|
||||
namespace ImGui
|
||||
{
|
||||
IMGUI_API void ShowFontAtlas(ImFontAtlas* atlas);
|
||||
IMGUI_API bool TreeNodeGetOpen(ImGuiID storage_id);
|
||||
IMGUI_API void TreeNodeSetOpen(ImGuiID storage_id, bool is_open);
|
||||
}
|
||||
|
||||
@@ -729,7 +726,6 @@ void ImGui::ShowDemoWindow(bool* p_open)
|
||||
|
||||
static void DemoWindowMenuBar(ImGuiDemoWindowData* demo_data)
|
||||
{
|
||||
IMGUI_DEMO_MARKER("Menu");
|
||||
if (ImGui::BeginMenuBar())
|
||||
{
|
||||
if (ImGui::BeginMenu("Menu"))
|
||||
@@ -812,7 +808,7 @@ struct ExampleTreeNode
|
||||
int UID = 0;
|
||||
ExampleTreeNode* Parent = NULL;
|
||||
ImVector<ExampleTreeNode*> Childs;
|
||||
unsigned short IndexInParent = 0; // Maintaining this allows us to implement linear traversal more easily
|
||||
int IndexInParent = 0; // Maintaining this allows us to implement linear traversal more easily
|
||||
|
||||
// Leaf Data
|
||||
bool HasData = false; // All leaves have data
|
||||
@@ -846,7 +842,7 @@ static ExampleTreeNode* ExampleTree_CreateNode(const char* name, int uid, Exampl
|
||||
snprintf(node->Name, IM_COUNTOF(node->Name), "%s", name);
|
||||
node->UID = uid;
|
||||
node->Parent = parent;
|
||||
node->IndexInParent = parent ? (unsigned short)parent->Childs.Size : 0;
|
||||
node->IndexInParent = parent ? parent->Childs.Size : 0;
|
||||
if (parent)
|
||||
parent->Childs.push_back(node);
|
||||
return node;
|
||||
@@ -860,18 +856,25 @@ static void ExampleTree_DestroyNode(ExampleTreeNode* node)
|
||||
}
|
||||
|
||||
// Create example tree data
|
||||
// (this allocates _many_ more times than most other code in all of Dear ImGui or others demo)
|
||||
// (warning: this can allocates MANY MANY more times than other code in all of Dear ImGui + demo combined)
|
||||
// (a real application managing one million nodes would likely store its tree data differently)
|
||||
static ExampleTreeNode* ExampleTree_CreateDemoTree()
|
||||
{
|
||||
static const char* root_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" };
|
||||
// 20 root nodes -> 211 total nodes, ~261 allocs.
|
||||
// 1000 root nodes -> ~11K total nodes, ~14K allocs.
|
||||
// 10000 root nodes -> ~123K total nodes, ~154K allocs.
|
||||
// 100000 root nodes -> ~1338K total nodes, ~1666K allocs.
|
||||
const int ROOT_ITEMS_COUNT = 20;
|
||||
|
||||
static const char* category_names[] = { "Apple", "Banana", "Cherry", "Kiwi", "Mango", "Orange", "Pear", "Pineapple", "Strawberry", "Watermelon" };
|
||||
const int category_count = IM_COUNTOF(category_names);
|
||||
const size_t NAME_MAX_LEN = sizeof(ExampleTreeNode::Name);
|
||||
char name_buf[NAME_MAX_LEN];
|
||||
int uid = 0;
|
||||
ExampleTreeNode* node_L0 = ExampleTree_CreateNode("<ROOT>", ++uid, NULL);
|
||||
const int root_items_multiplier = 2;
|
||||
for (int idx_L0 = 0; idx_L0 < IM_COUNTOF(root_names) * root_items_multiplier; idx_L0++)
|
||||
for (int idx_L0 = 0; idx_L0 < ROOT_ITEMS_COUNT; idx_L0++)
|
||||
{
|
||||
snprintf(name_buf, IM_COUNTOF(name_buf), "%s %d", root_names[idx_L0 / root_items_multiplier], idx_L0 % root_items_multiplier);
|
||||
snprintf(name_buf, IM_COUNTOF(name_buf), "%s %d", category_names[idx_L0 / (ROOT_ITEMS_COUNT / category_count)], idx_L0 % (ROOT_ITEMS_COUNT / category_count));
|
||||
ExampleTreeNode* node_L1 = ExampleTree_CreateNode(name_buf, ++uid, node_L0);
|
||||
const int number_of_childs = (int)strlen(node_L1->Name);
|
||||
for (int idx_L1 = 0; idx_L1 < number_of_childs; idx_L1++)
|
||||
@@ -4191,6 +4194,16 @@ static void DemoWindowWidgetsTreeNodes()
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("Clipping Large Trees"))
|
||||
{
|
||||
IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Clipping Large Trees");
|
||||
ImGui::TextWrapped(
|
||||
"- Using ImGuiListClipper with trees is a less easy than on arrays or grids.\n"
|
||||
"- Refer to 'Demo->Examples->Property Editor' for an example of how to do that.\n"
|
||||
"- Discuss in #3823");
|
||||
ImGui::TreePop();
|
||||
}
|
||||
|
||||
if (ImGui::TreeNode("Advanced, with Selectable nodes"))
|
||||
{
|
||||
IMGUI_DEMO_MARKER("Widgets/Tree Nodes/Advanced, with Selectable nodes");
|
||||
@@ -8853,11 +8866,13 @@ static void ShowExampleAppMainMenuBar()
|
||||
{
|
||||
if (ImGui::BeginMenu("File"))
|
||||
{
|
||||
IMGUI_DEMO_MARKER("Menu/File");
|
||||
ShowExampleMenuFile();
|
||||
ImGui::EndMenu();
|
||||
}
|
||||
if (ImGui::BeginMenu("Edit"))
|
||||
{
|
||||
IMGUI_DEMO_MARKER("Menu/Edit");
|
||||
if (ImGui::MenuItem("Undo", "Ctrl+Z")) {}
|
||||
if (ImGui::MenuItem("Redo", "Ctrl+Y", false, false)) {} // Disabled item
|
||||
ImGui::Separator();
|
||||
@@ -8972,7 +8987,6 @@ struct ExampleAppConsole
|
||||
|
||||
ExampleAppConsole()
|
||||
{
|
||||
IMGUI_DEMO_MARKER("Examples/Console");
|
||||
ClearLog();
|
||||
memset(InputBuf, 0, sizeof(InputBuf));
|
||||
HistoryPos = -1;
|
||||
@@ -9026,6 +9040,7 @@ struct ExampleAppConsole
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
IMGUI_DEMO_MARKER("Examples/Console");
|
||||
|
||||
// As a specific feature guaranteed by the library, after calling Begin() the last Item represent the title bar.
|
||||
// So e.g. IsItemHovered() will return true when hovering the title bar.
|
||||
@@ -9557,25 +9572,33 @@ struct ExampleAppPropertyEditor
|
||||
{
|
||||
ImGuiTextFilter Filter;
|
||||
ExampleTreeNode* SelectedNode = NULL;
|
||||
bool UseClipper = false;
|
||||
|
||||
void Draw(ExampleTreeNode* root_node)
|
||||
{
|
||||
IMGUI_DEMO_MARKER("Examples/Property editor");
|
||||
|
||||
// Left side: draw tree
|
||||
// - Currently using a table to benefit from RowBg feature
|
||||
// - Our tree node are all of equal height, facilitating the use of a clipper.
|
||||
if (ImGui::BeginChild("##tree", ImVec2(300, 0), ImGuiChildFlags_ResizeX | ImGuiChildFlags_Borders | ImGuiChildFlags_NavFlattened))
|
||||
{
|
||||
ImGui::PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true);
|
||||
ImGui::Checkbox("Use Clipper", &UseClipper);
|
||||
ImGui::SameLine();
|
||||
ImGui::Text("(%d root nodes)", root_node->Childs.Size);
|
||||
ImGui::SetNextItemWidth(-FLT_MIN);
|
||||
ImGui::SetNextItemShortcut(ImGuiMod_Ctrl | ImGuiKey_F, ImGuiInputFlags_Tooltip);
|
||||
ImGui::PushItemFlag(ImGuiItemFlags_NoNavDefaultFocus, true);
|
||||
if (ImGui::InputTextWithHint("##Filter", "incl,-excl", Filter.InputBuf, IM_COUNTOF(Filter.InputBuf), ImGuiInputTextFlags_EscapeClearsAll))
|
||||
Filter.Build();
|
||||
ImGui::PopItemFlag();
|
||||
|
||||
if (ImGui::BeginTable("##list", 1, ImGuiTableFlags_RowBg))
|
||||
{
|
||||
for (ExampleTreeNode* node : root_node->Childs)
|
||||
if (Filter.PassFilter(node->Name)) // Filter root node
|
||||
DrawTreeNode(node);
|
||||
if (UseClipper)
|
||||
DrawClippedTree(root_node);
|
||||
else
|
||||
DrawTree(root_node);
|
||||
ImGui::EndTable();
|
||||
}
|
||||
}
|
||||
@@ -9648,34 +9671,121 @@ struct ExampleAppPropertyEditor
|
||||
ImGui::EndGroup();
|
||||
}
|
||||
|
||||
void DrawTreeNode(ExampleTreeNode* node)
|
||||
// Custom search filter
|
||||
// - Here we apply on root node only.
|
||||
// - This does a case insensitive stristr which is pretty heavy. In a real large-scale app you would likely store a filtered list which in turns would be trivial to linearize.
|
||||
inline bool IsNodePassingFilter(ExampleTreeNode* node)
|
||||
{
|
||||
return node->Parent->Parent != NULL || Filter.PassFilter(node->Name);
|
||||
}
|
||||
|
||||
// Basic version, recursive. This is how you would generally draw a tree.
|
||||
// - Simple but going to be noticeably costly if you have a large amount of nodes as DrawTreeNode() is called for all of them.
|
||||
// - On my desktop PC (2020), for 10K nodes in an optimized build this takes ~1.2 ms
|
||||
// - Unlike arrays or grids which are very easy to clip, trees are currently more difficult to clip.
|
||||
void DrawTree(ExampleTreeNode* node)
|
||||
{
|
||||
for (ExampleTreeNode* child : node->Childs)
|
||||
if (IsNodePassingFilter(child) && DrawTreeNode(child))
|
||||
{
|
||||
DrawTree(child);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
}
|
||||
|
||||
// More advanced version. Use a alternative clipping technique: fast-forwarding through non-visible chunks.
|
||||
// - On my desktop PC (2020), for 10K nodes in an optimized build this takes ~0.1 ms
|
||||
// (in ExampleTree_CreateDemoTree(), change 'int ROOT_ITEMS_COUNT = 10000' to try with this amount of root nodes).
|
||||
// - 1. Use clipper with indeterminate count (items_count = INT_MAX): we need to call SeekCursorForItem() at the end once we know the count.
|
||||
// - 2. Use SetNextItemStorageID() to specify ID used for open/close storage, making it easy to call TreeNodeGetOpen() on any arbitrary node.
|
||||
// - 3. Linearize tree during traversal: our tree data structure makes it easy to access sibling and parents.
|
||||
// - Unlike clipping for a regular array or grid which may be done using random access limited to visible areas,
|
||||
// this technique requires traversing most accessible nodes. This could be made more optimal with extra work,
|
||||
// but this is a decent simplicity<>speed trade-off.
|
||||
// See https://github.com/ocornut/imgui/issues/3823 for discussions about this.
|
||||
void DrawClippedTree(ExampleTreeNode* root_node)
|
||||
{
|
||||
ExampleTreeNode* node = root_node->Childs[0]; // First node
|
||||
ImGuiListClipper clipper;
|
||||
clipper.Begin(INT_MAX);
|
||||
while (clipper.Step())
|
||||
while (clipper.UserIndex < clipper.DisplayEnd && node != NULL)
|
||||
node = DrawClippedTreeNodeAndAdvanceToNext(&clipper, node);
|
||||
|
||||
// Keep going to count nodes and submit final count so we have a reliable scrollbar.
|
||||
// - One could consider caching this value and only refreshing it occasionally e.g. window is focused and an action occurs.
|
||||
// - Incorrect but cheap approximation would be to use 'clipper_current_idx = IM_MAX(clipper_current_idx, root_node->Childs.Size)' instead.
|
||||
// - If either of those is implemented, the general cost will approach zero when scrolling is at the top of the tree.
|
||||
while (node != NULL)
|
||||
node = DrawClippedTreeNodeAndAdvanceToNext(&clipper, node);
|
||||
//clipper.UserIndex = IM_MAX(clipper.UserIndex, root_node->Childs.Size); // <-- Cheap approximation instead of while() loop above.
|
||||
clipper.SeekCursorForItem(clipper.UserIndex);
|
||||
}
|
||||
|
||||
ExampleTreeNode* DrawClippedTreeNodeAndAdvanceToNext(ImGuiListClipper* clipper, ExampleTreeNode* node)
|
||||
{
|
||||
if (IsNodePassingFilter(node))
|
||||
{
|
||||
// Draw node if within visible range
|
||||
bool is_open = false;
|
||||
if (clipper->UserIndex >= clipper->DisplayStart && clipper->UserIndex < clipper->DisplayEnd)
|
||||
{
|
||||
is_open = DrawTreeNode(node);
|
||||
}
|
||||
else
|
||||
{
|
||||
is_open = (node->Childs.Size > 0 && ImGui::TreeNodeGetOpen((ImGuiID)node->UID));
|
||||
if (is_open)
|
||||
ImGui::TreePush(node->Name);
|
||||
}
|
||||
clipper->UserIndex++;
|
||||
|
||||
// Next node: recurse into childs
|
||||
if (is_open)
|
||||
return node->Childs[0];
|
||||
}
|
||||
|
||||
// Next node: next sibling, otherwise move back to parent
|
||||
while (node != NULL)
|
||||
{
|
||||
if (node->IndexInParent + 1 < node->Parent->Childs.Size)
|
||||
return node->Parent->Childs[node->IndexInParent + 1];
|
||||
node = node->Parent;
|
||||
if (node->Parent == NULL)
|
||||
break;
|
||||
ImGui::TreePop();
|
||||
}
|
||||
return NULL;
|
||||
}
|
||||
|
||||
// To support node with same name we incorporate node->UID into the item ID.
|
||||
// (this would more naturally be done using PushID(node->UID) + TreeNodeEx(node->Name, tree_flags),
|
||||
// but it would require in DrawClippedTreeNodeAndAdvanceToNext() to add PushID() before TreePush(), and PopID() after TreePop(),
|
||||
// so instead we use TreeNodeEx(node->UID, tree_flags, "%s", node->Name) here)
|
||||
bool DrawTreeNode(ExampleTreeNode* node)
|
||||
{
|
||||
ImGui::TableNextRow();
|
||||
ImGui::TableNextColumn();
|
||||
ImGui::PushID(node->UID);
|
||||
ImGuiTreeNodeFlags tree_flags = ImGuiTreeNodeFlags_None;
|
||||
tree_flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;// Standard opening mode as we are likely to want to add selection afterwards
|
||||
tree_flags |= ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick; // Standard opening mode as we are likely to want to add selection afterwards
|
||||
tree_flags |= ImGuiTreeNodeFlags_NavLeftJumpsToParent; // Left arrow support
|
||||
tree_flags |= ImGuiTreeNodeFlags_SpanFullWidth; // Span full width for easier mouse reach
|
||||
tree_flags |= ImGuiTreeNodeFlags_DrawLinesToNodes; // Always draw hierarchy outlines
|
||||
if (node == SelectedNode)
|
||||
tree_flags |= ImGuiTreeNodeFlags_Selected;
|
||||
tree_flags |= ImGuiTreeNodeFlags_Selected; // Draw selection highlight
|
||||
if (node->Childs.Size == 0)
|
||||
tree_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet;
|
||||
tree_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_Bullet | ImGuiTreeNodeFlags_NoTreePushOnOpen; // Use _NoTreePushOnOpen + set is_open=false to avoid unnecessarily push/pop on leaves.
|
||||
if (node->DataMyBool == false)
|
||||
ImGui::PushStyleColor(ImGuiCol_Text, ImGui::GetStyle().Colors[ImGuiCol_TextDisabled]);
|
||||
bool node_open = ImGui::TreeNodeEx("", tree_flags, "%s", node->Name);
|
||||
ImGui::SetNextItemStorageID((ImGuiID)node->UID); // Use node->UID as storage id
|
||||
bool is_open = ImGui::TreeNodeEx((void*)(intptr_t)node->UID, tree_flags, "%s", node->Name);
|
||||
if (node->Childs.Size == 0)
|
||||
is_open = false;
|
||||
if (node->DataMyBool == false)
|
||||
ImGui::PopStyleColor();
|
||||
if (ImGui::IsItemFocused())
|
||||
SelectedNode = node;
|
||||
if (node_open)
|
||||
{
|
||||
for (ExampleTreeNode* child : node->Childs)
|
||||
DrawTreeNode(child);
|
||||
ImGui::TreePop();
|
||||
}
|
||||
ImGui::PopID();
|
||||
return is_open;
|
||||
}
|
||||
};
|
||||
|
||||
@@ -9854,9 +9964,9 @@ static void ShowExampleAppConstrainedResize(bool* p_open)
|
||||
const bool window_open = ImGui::Begin("Example: Constrained Resize", p_open, window_flags);
|
||||
if (!window_padding)
|
||||
ImGui::PopStyleVar();
|
||||
IMGUI_DEMO_MARKER("Examples/Constrained Resizing window");
|
||||
if (window_open)
|
||||
{
|
||||
IMGUI_DEMO_MARKER("Examples/Constrained Resizing window");
|
||||
if (ImGui::GetIO().KeyShift)
|
||||
{
|
||||
// Display a dummy viewport (in your real app you would likely use ImageButton() to display a texture)
|
||||
@@ -9922,7 +10032,7 @@ static void ShowExampleAppSimpleOverlay(bool* p_open)
|
||||
ImGui::SetNextWindowBgAlpha(0.35f); // Transparent background
|
||||
if (ImGui::Begin("Example: Simple overlay", p_open, window_flags))
|
||||
{
|
||||
IMGUI_DEMO_MARKER("Examples/Simple Overlay");
|
||||
IMGUI_DEMO_MARKER("Examples/Simple overlay"); // Scroll up to the beginning of this function to see overlay flags
|
||||
ImGui::Text("Simple overlay\n" "(right-click to change position)");
|
||||
ImGui::Separator();
|
||||
if (ImGui::IsMousePosValid())
|
||||
@@ -9962,6 +10072,7 @@ static void ShowExampleAppFullscreen(bool* p_open)
|
||||
|
||||
if (ImGui::Begin("Example: Fullscreen window", p_open, flags))
|
||||
{
|
||||
IMGUI_DEMO_MARKER("Examples/Fullscreen window");
|
||||
ImGui::Checkbox("Use work area instead of main area", &use_work_area);
|
||||
ImGui::SameLine();
|
||||
HelpMarker("Main Area = entire viewport,\nWork Area = entire viewport minus sections used by the main menu bars, task bars etc.\n\nEnable the main-menu bar in Examples menu to see the difference.");
|
||||
@@ -9998,12 +10109,13 @@ static void ShowExampleAppWindowTitles(bool*)
|
||||
// Using "##" to display same title but have unique identifier.
|
||||
ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 100), ImGuiCond_FirstUseEver);
|
||||
ImGui::Begin("Same title as another window##1");
|
||||
IMGUI_DEMO_MARKER("Examples/Manipulating window titles");
|
||||
IMGUI_DEMO_MARKER("Examples/Manipulating window titles##1");
|
||||
ImGui::Text("This is window 1.\nMy title is the same as window 2, but my identifier is unique.");
|
||||
ImGui::End();
|
||||
|
||||
ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 200), ImGuiCond_FirstUseEver);
|
||||
ImGui::Begin("Same title as another window##2");
|
||||
IMGUI_DEMO_MARKER("Examples/Manipulating window titles##2");;
|
||||
ImGui::Text("This is window 2.\nMy title is the same as window 1, but my identifier is unique.");
|
||||
ImGui::End();
|
||||
|
||||
@@ -10012,6 +10124,7 @@ static void ShowExampleAppWindowTitles(bool*)
|
||||
sprintf(buf, "Animated title %c %d###AnimatedTitle", "|/-\\"[(int)(ImGui::GetTime() / 0.25f) & 3], ImGui::GetFrameCount());
|
||||
ImGui::SetNextWindowPos(ImVec2(base_pos.x + 100, base_pos.y + 300), ImGuiCond_FirstUseEver);
|
||||
ImGui::Begin(buf);
|
||||
IMGUI_DEMO_MARKER("Examples/Manipulating window titles##3");
|
||||
ImGui::Text("This window has a changing title.");
|
||||
ImGui::End();
|
||||
}
|
||||
@@ -10036,7 +10149,7 @@ static void ShowExampleAppCustomRendering(bool* p_open)
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
IMGUI_DEMO_MARKER("Examples/Custom Rendering");
|
||||
IMGUI_DEMO_MARKER("Examples/Custom rendering");
|
||||
|
||||
// Tip: If you do a lot of custom rendering, you probably want to use your own geometrical types and benefit of
|
||||
// overloaded operators, etc. Define IM_VEC2_CLASS_EXTRA in imconfig.h to create implicit conversions between your
|
||||
@@ -10047,6 +10160,7 @@ static void ShowExampleAppCustomRendering(bool* p_open)
|
||||
{
|
||||
if (ImGui::BeginTabItem("Primitives"))
|
||||
{
|
||||
IMGUI_DEMO_MARKER("Examples/Custom rendering/Primitives");
|
||||
ImGui::PushItemWidth(-ImGui::GetFontSize() * 15);
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
|
||||
@@ -10174,6 +10288,7 @@ static void ShowExampleAppCustomRendering(bool* p_open)
|
||||
|
||||
if (ImGui::BeginTabItem("Canvas"))
|
||||
{
|
||||
IMGUI_DEMO_MARKER("Examples/Custom rendering/Canvas");
|
||||
static ImVector<ImVec2> points;
|
||||
static ImVec2 scrolling(0.0f, 0.0f);
|
||||
static bool opt_enable_grid = true;
|
||||
@@ -10271,6 +10386,7 @@ static void ShowExampleAppCustomRendering(bool* p_open)
|
||||
|
||||
if (ImGui::BeginTabItem("BG/FG draw lists"))
|
||||
{
|
||||
IMGUI_DEMO_MARKER("Examples/Custom rendering/BG & FG draw lists");
|
||||
static bool draw_bg = true;
|
||||
static bool draw_fg = true;
|
||||
ImGui::Checkbox("Draw in Background draw list", &draw_bg);
|
||||
@@ -10292,6 +10408,7 @@ static void ShowExampleAppCustomRendering(bool* p_open)
|
||||
// but you can also instantiate your own ImDrawListSplitter if you need to nest them.
|
||||
if (ImGui::BeginTabItem("Draw Channels"))
|
||||
{
|
||||
IMGUI_DEMO_MARKER("Examples/Custom rendering/Draw Channels");
|
||||
ImDrawList* draw_list = ImGui::GetWindowDrawList();
|
||||
{
|
||||
ImGui::Text("Blue shape is drawn first: appears in back");
|
||||
@@ -10636,6 +10753,7 @@ void ShowExampleAppDocuments(bool* p_open)
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
IMGUI_DEMO_MARKER("Examples/Documents");
|
||||
|
||||
// Menu
|
||||
if (ImGui::BeginMenuBar())
|
||||
@@ -10999,6 +11117,7 @@ struct ExampleAssetsBrowser
|
||||
ImGui::End();
|
||||
return;
|
||||
}
|
||||
IMGUI_DEMO_MARKER("Examples/Assets Browser");
|
||||
|
||||
// Menu bar
|
||||
if (ImGui::BeginMenuBar())
|
||||
|
||||
@@ -2376,6 +2376,8 @@ struct ImGuiContextHook
|
||||
ImGuiContextHook() { memset((void*)this, 0, sizeof(*this)); }
|
||||
};
|
||||
|
||||
typedef void (*ImGuiDemoMarkerCallback)(const char* file, int line, const char* section);
|
||||
|
||||
//-----------------------------------------------------------------------------
|
||||
// [SECTION] ImGuiContext (main Dear ImGui context)
|
||||
//-----------------------------------------------------------------------------
|
||||
@@ -2712,8 +2714,11 @@ struct ImGuiContext
|
||||
ImVector<ImGuiSettingsHandler> SettingsHandlers; // List of .ini settings handlers
|
||||
ImChunkStream<ImGuiWindowSettings> SettingsWindows; // ImGuiWindow .ini settings entries
|
||||
ImChunkStream<ImGuiTableSettings> SettingsTables; // ImGuiTable .ini settings entries
|
||||
|
||||
// Hooks
|
||||
ImVector<ImGuiContextHook> Hooks; // Hooks for extensions (e.g. test engine)
|
||||
ImGuiID HookIdNext; // Next available HookId
|
||||
ImGuiDemoMarkerCallback DemoMarkerCallback;
|
||||
|
||||
// Localization
|
||||
const char* LocalizationTable[ImGuiLocKey_COUNT];
|
||||
@@ -3945,7 +3950,6 @@ namespace ImGui
|
||||
IMGUI_API void TreeNodeDrawLineToChildNode(const ImVec2& target_pos);
|
||||
IMGUI_API void TreeNodeDrawLineToTreePop(const ImGuiTreeNodeStackData* data);
|
||||
IMGUI_API void TreePushOverrideID(ImGuiID id);
|
||||
IMGUI_API bool TreeNodeGetOpen(ImGuiID storage_id);
|
||||
IMGUI_API void TreeNodeSetOpen(ImGuiID storage_id, bool open);
|
||||
IMGUI_API bool TreeNodeUpdateNextOpen(ImGuiID storage_id, ImGuiTreeNodeFlags flags); // Return open state. Consume previous SetNextItemOpen() data, if any. May return true when logging.
|
||||
|
||||
@@ -4007,6 +4011,9 @@ namespace ImGui
|
||||
IMGUI_API bool BeginErrorTooltip();
|
||||
IMGUI_API void EndErrorTooltip();
|
||||
|
||||
// Demo Doc Marker for e.g. imgui_manual
|
||||
IMGUI_API void DemoMarker(const char* file, int line, const char* section);
|
||||
|
||||
// Debug Tools
|
||||
IMGUI_API void DebugAllocHook(ImGuiDebugAllocInfo* info, int frame_count, void* ptr, size_t size); // size >= 0 : alloc, size = -1 : free
|
||||
IMGUI_API void DebugDrawCursorPos(ImU32 col = IM_COL32(255, 0, 0, 255));
|
||||
|
||||
@@ -2209,30 +2209,6 @@ bool ImGui::Combo(const char* label, int* current_item, const char* items_separa
|
||||
return value_changed;
|
||||
}
|
||||
|
||||
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
|
||||
|
||||
struct ImGuiGetNameFromIndexOldToNewCallbackData { void* UserData; bool (*OldCallback)(void*, int, const char**); };
|
||||
static const char* ImGuiGetNameFromIndexOldToNewCallback(void* user_data, int idx)
|
||||
{
|
||||
ImGuiGetNameFromIndexOldToNewCallbackData* data = (ImGuiGetNameFromIndexOldToNewCallbackData*)user_data;
|
||||
const char* s = NULL;
|
||||
data->OldCallback(data->UserData, idx, &s);
|
||||
return s;
|
||||
}
|
||||
|
||||
bool ImGui::ListBox(const char* label, int* current_item, bool (*old_getter)(void*, int, const char**), void* user_data, int items_count, int height_in_items)
|
||||
{
|
||||
ImGuiGetNameFromIndexOldToNewCallbackData old_to_new_data = { user_data, old_getter };
|
||||
return ListBox(label, current_item, ImGuiGetNameFromIndexOldToNewCallback, &old_to_new_data, items_count, height_in_items);
|
||||
}
|
||||
bool ImGui::Combo(const char* label, int* current_item, bool (*old_getter)(void*, int, const char**), void* user_data, int items_count, int popup_max_height_in_items)
|
||||
{
|
||||
ImGuiGetNameFromIndexOldToNewCallbackData old_to_new_data = { user_data, old_getter };
|
||||
return Combo(label, current_item, ImGuiGetNameFromIndexOldToNewCallback, &old_to_new_data, items_count, popup_max_height_in_items);
|
||||
}
|
||||
|
||||
#endif
|
||||
|
||||
//-------------------------------------------------------------------------
|
||||
// [SECTION] Data Type and Data Formatting Helpers [Internal]
|
||||
//-------------------------------------------------------------------------
|
||||
@@ -5077,6 +5053,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
const bool nav_gamepad_active = (io.ConfigFlags & ImGuiConfigFlags_NavEnableGamepad) != 0 && (io.BackendFlags & ImGuiBackendFlags_HasGamepad) != 0;
|
||||
const bool is_enter = Shortcut(ImGuiKey_Enter, f_repeat, id) || Shortcut(ImGuiKey_KeypadEnter, f_repeat, id);
|
||||
const bool is_ctrl_enter = Shortcut(ImGuiMod_Ctrl | ImGuiKey_Enter, f_repeat, id) || Shortcut(ImGuiMod_Ctrl | ImGuiKey_KeypadEnter, f_repeat, id);
|
||||
const bool is_shift_enter = Shortcut(ImGuiMod_Shift | ImGuiKey_Enter, f_repeat, id) || Shortcut(ImGuiMod_Shift | ImGuiKey_KeypadEnter, f_repeat, id);
|
||||
const bool is_gamepad_validate = nav_gamepad_active && (IsKeyPressed(ImGuiKey_NavGamepadActivate, false) || IsKeyPressed(ImGuiKey_NavGamepadInput, false));
|
||||
const bool is_cancel = Shortcut(ImGuiKey_Escape, f_repeat, id) || (nav_gamepad_active && Shortcut(ImGuiKey_NavGamepadCancel, f_repeat, id));
|
||||
|
||||
@@ -5111,11 +5088,12 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
|
||||
}
|
||||
state->OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask);
|
||||
}
|
||||
else if (is_enter || is_ctrl_enter || is_gamepad_validate)
|
||||
else if (is_enter || is_ctrl_enter || is_shift_enter || is_gamepad_validate)
|
||||
{
|
||||
// Determine if we turn Enter into a \n character
|
||||
bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0;
|
||||
if (!is_multiline || is_gamepad_validate || (ctrl_enter_for_new_line != is_ctrl_enter))
|
||||
bool is_new_line = is_multiline && !is_gamepad_validate && (is_shift_enter || (is_enter && !ctrl_enter_for_new_line) || (is_ctrl_enter && ctrl_enter_for_new_line));
|
||||
if (!is_new_line)
|
||||
{
|
||||
validated = true;
|
||||
if (io.ConfigInputTextEnterKeepActive && !is_multiline)
|
||||
|
||||
Reference in New Issue
Block a user