Welcome to mirror list, hosted at ThFree Co, Russian Federation.

github.com/wolfpld/tracy.git - Unnamed repository; edit this file 'description' to name the repository.
summaryrefslogtreecommitdiff
path: root/imgui
diff options
context:
space:
mode:
authorBartosz Taudul <wolf.pld@gmail.com>2019-06-12 23:53:23 +0300
committerBartosz Taudul <wolf.pld@gmail.com>2019-06-12 23:53:23 +0300
commit796ca57067d08add10cee93f8110947084e370bc (patch)
treeb8419f9f9978524231fef5f4eb9bfc69bdf9e6c7 /imgui
parentd3e0163dd4a3b087f113fb5de58179d54f4712a2 (diff)
Update imgui to 1.71.
Diffstat (limited to 'imgui')
-rw-r--r--imgui/imconfig.h25
-rw-r--r--imgui/imgui.cpp1193
-rw-r--r--imgui/imgui.h173
-rw-r--r--imgui/imgui_demo.cpp242
-rw-r--r--imgui/imgui_draw.cpp265
-rw-r--r--imgui/imgui_internal.h326
-rw-r--r--imgui/imgui_widgets.cpp618
7 files changed, 1762 insertions, 1080 deletions
diff --git a/imgui/imconfig.h b/imgui/imconfig.h
index c44d4ef3..f4b64cb8 100644
--- a/imgui/imconfig.h
+++ b/imgui/imconfig.h
@@ -3,10 +3,10 @@
// Runtime options (clipboard callbacks, enabling various features, etc.) can generally be set via the ImGuiIO structure.
// You can use ImGui::SetAllocatorFunctions() before calling ImGui::CreateContext() to rewire memory allocation functions.
//-----------------------------------------------------------------------------
-// A) You may edit imconfig.h (and not overwrite it when updating imgui, or maintain a patch/branch with your modifications to imconfig.h)
+// A) You may edit imconfig.h (and not overwrite it when updating Dear ImGui, or maintain a patch/branch with your modifications to imconfig.h)
// B) or add configuration directives in your own file and compile with #define IMGUI_USER_CONFIG "myfilename.h"
-// If you do so you need to make sure that configuration settings are defined consistently _everywhere_ dear imgui is used, which include
-// the imgui*.cpp files but also _any_ of your code that uses imgui. This is because some compile-time options have an affect on data structures.
+// If you do so you need to make sure that configuration settings are defined consistently _everywhere_ Dear ImGui is used, which include
+// the imgui*.cpp files but also _any_ of your code that uses Dear ImGui. This is because some compile-time options have an affect on data structures.
// Defining those options in imconfig.h will ensure every compilation unit gets to see the same data structure layouts.
// Call IMGUI_CHECKVERSION() from your .cpp files to verify that the data structures your files are using are matching the ones imgui.cpp is using.
//-----------------------------------------------------------------------------
@@ -17,7 +17,8 @@
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
-//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows.
+//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
+// Using dear imgui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
//#define IMGUI_API __declspec( dllexport )
//#define IMGUI_API __declspec( dllimport )
@@ -25,13 +26,14 @@
//#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS
//---- Don't implement demo windows functionality (ShowDemoWindow()/ShowStyleEditor()/ShowUserGuide() methods will be empty)
-//---- It is very strongly recommended to NOT disable the demo windows during development. Please read the comments in imgui_demo.cpp.
+// It is very strongly recommended to NOT disable the demo windows during development. Please read the comments in imgui_demo.cpp.
//#define IMGUI_DISABLE_DEMO_WINDOWS
//---- Don't implement some functions to reduce linkage requirements.
//#define IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS // [Win32] Don't implement default clipboard handler. Won't use and link with OpenClipboard/GetClipboardData/CloseClipboard etc.
//#define IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS // [Win32] Don't implement default IME handler. Won't use and link with ImmGetContext/ImmSetCompositionWindow.
-//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function.
+//#define IMGUI_DISABLE_WIN32_FUNCTIONS // [Win32] Won't use and link with any Win32 function (clipboard, ime).
+//#define IMGUI_DISABLE_OSX_FUNCTIONS // [OSX] Won't use and link with any OSX function (clipboard).
//#define IMGUI_DISABLE_FORMAT_STRING_FUNCTIONS // Don't implement ImFormatString/ImFormatStringV so you can implement them yourself if you don't want to link with vsnprintf.
//#define IMGUI_DISABLE_MATH_FUNCTIONS // Don't implement ImFabs/ImSqrt/ImPow/ImFmod/ImCos/ImSin/ImAcos/ImAtan2 wrapper so you can implement them yourself. Declare your prototypes in imconfig.h.
//#define IMGUI_DISABLE_DEFAULT_ALLOCATORS // Don't implement default allocators calling malloc()/free() to avoid linking with them. You will need to call ImGui::SetAllocatorFunctions().
@@ -61,9 +63,18 @@
operator MyVec4() const { return MyVec4(x,y,z,w); }
*/
-//---- Use 32-bit vertex indices (default is 16-bit) to allow meshes with more than 64K vertices. Render function needs to support it.
+//---- Using 32-bits vertex indices (default is 16-bits) is one way to allow large meshes with more than 64K vertices.
+// Your renderer back-end will need to support it (most example renderer back-ends support both 16/32-bits indices).
+// Another way to allow large meshes while keeping 16-bits indices is to handle ImDrawCmd::VtxOffset in your renderer.
+// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
#define ImDrawIdx unsigned int
+//---- Override ImDrawCallback signature (will need to modify renderer back-ends accordingly)
+//struct ImDrawList;
+//struct ImDrawCmd;
+//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
+//#define ImDrawCallback MyImDrawCallback
+
//---- Tip: You can add extra functions within the ImGui:: namespace, here or in your own headers files.
/*
namespace ImGui
diff --git a/imgui/imgui.cpp b/imgui/imgui.cpp
index 0bcaee50..72ea25e7 100644
--- a/imgui/imgui.cpp
+++ b/imgui/imgui.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.70
+// dear imgui, v1.71
// (main code and documentation)
// Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code.
@@ -51,7 +51,7 @@ DOCUMENTATION
- How can I load multiple fonts?
- How can I display and input non-latin characters such as Chinese, Japanese, Korean, Cyrillic?
- How can I interact with standard C++ types (such as std::string and std::vector)?
- - How can I use the drawing facilities without an ImGui window? (using ImDrawList API)
+ - How can I use the drawing facilities without a Dear ImGui window? (using ImDrawList API)
- How can I use Dear ImGui on a platform that doesn't have a mouse or a keyboard? (input share, remoting, gamepad)
- I integrated Dear ImGui in my engine and the text or lines are blurry..
- I integrated Dear ImGui in my engine and some elements are clipping or disappearing when I move windows around..
@@ -172,7 +172,7 @@ CODE
- Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library.
- Add the Dear ImGui source files to your projects or using your preferred build system.
It is recommended you build and statically link the .cpp files as part of your project and not as shared library (DLL).
- - You can later customize the imconfig.h file to tweak some compile-time behavior, such as integrating imgui types with your own maths types.
+ - You can later customize the imconfig.h file to tweak some compile-time behavior, such as integrating Dear ImGui types with your own maths types.
- When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them.
- Dear ImGui never touches or knows about your GPU state. The only function that knows about GPU is the draw function that you provide.
Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render"
@@ -251,16 +251,16 @@ CODE
io.MouseDown[1] = my_mouse_buttons[1];
// Call NewFrame(), after this point you can use ImGui::* functions anytime
- // (So you want to try calling NewFrame() as early as you can in your mainloop to be able to use imgui everywhere)
+ // (So you want to try calling NewFrame() as early as you can in your mainloop to be able to use Dear ImGui everywhere)
ImGui::NewFrame();
// Most of your application code here
ImGui::Text("Hello, world!");
- MyGameUpdate(); // may use any ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End();
- MyGameRender(); // may use any ImGui functions as well!
+ MyGameUpdate(); // may use any Dear ImGui functions, e.g. ImGui::Begin("My window"); ImGui::Text("Hello, world!"); ImGui::End();
+ MyGameRender(); // may use any Dear ImGui functions as well!
- // Render imgui, swap buffers
- // (You want to try calling EndFrame/Render as late as you can, to be able to use imgui in your own game rendering code)
+ // Render dear imgui, swap buffers
+ // (You want to try calling EndFrame/Render as late as you can, to be able to use Dear ImGui in your own game rendering code)
ImGui::EndFrame();
ImGui::Render();
ImDrawData* draw_data = ImGui::GetDrawData();
@@ -282,8 +282,8 @@ CODE
for (int n = 0; n < draw_data->CmdListsCount; n++)
{
const ImDrawList* cmd_list = draw_data->CmdLists[n];
- const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by ImGui
- const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by ImGui
+ const ImDrawVert* vtx_buffer = cmd_list->VtxBuffer.Data; // vertex buffer generated by Dear ImGui
+ const ImDrawIdx* idx_buffer = cmd_list->IdxBuffer.Data; // index buffer generated by Dear ImGui
for (int cmd_i = 0; cmd_i < cmd_list->CmdBuffer.Size; cmd_i++)
{
const ImDrawCmd* pcmd = &cmd_list->CmdBuffer[cmd_i];
@@ -294,7 +294,7 @@ CODE
else
{
// The texture for the draw call is specified by pcmd->TextureId.
- // The vast majority of draw calls will use the imgui texture atlas, which value you have set yourself during initialization.
+ // The vast majority of draw calls will use the Dear ImGui texture atlas, which value you have set yourself during initialization.
MyEngineBindTexture((MyTexture*)pcmd->TextureId);
// We are using scissoring to clip some objects. All low-level graphics API should supports it.
@@ -319,8 +319,8 @@ CODE
- The examples/ folders contains many actual implementation of the pseudo-codes above.
- When calling NewFrame(), the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags are updated.
- They tell you if Dear ImGui intends to use your inputs. When a flag is set you want to hide the corresponding inputs
- from the rest of your application. In every cases you need to pass on the inputs to imgui. Refer to the FAQ for more information.
+ They tell you if Dear ImGui intends to use your inputs. When a flag is set you want to hide the corresponding inputs from the
+ rest of your application. In every cases you need to pass on the inputs to Dear ImGui. Refer to the FAQ for more information.
- Please read the FAQ below!. Amusingly, it is called a FAQ because people frequently run into the same issues!
USING GAMEPAD/KEYBOARD NAVIGATION CONTROLS
@@ -369,6 +369,12 @@ CODE
When you are not sure about a old symbol or function name, try using the Search/Find function of your IDE to look for comments or references in all imgui files.
You can read releases logs https://github.com/ocornut/imgui/releases for more details.
+ - 2019/06/07 (1.71) - rendering of child window outer decorations (bg color, border, scrollbars) is now performed as part of the parent window. If you have
+ overlapping child windows in a same parent, and relied on their relative z-order to be mapped to their submission order, this will affect your rendering.
+ This optimization is disabled if the parent window has no visual output, because it appears to be the most common situation leading to the creation of overlapping child windows.
+ Please reach out if you are affected.
+ - 2019/05/13 (1.71) - renamed SetNextTreeNodeOpen() to SetNextItemOpen(). Kept inline redirection function (will obsolete).
+ - 2019/05/11 (1.71) - changed io.AddInputCharacter(unsigned short c) signature to io.AddInputCharacter(unsigned int c).
- 2019/04/29 (1.70) - improved ImDrawList thick strokes (>1.0f) preserving correct thickness up to 90 degrees angles (e.g. rectangles). If you have custom rendering using thick lines, they will appear thicker now.
- 2019/04/29 (1.70) - removed GetContentRegionAvailWidth(), use GetContentRegionAvail().x instead. Kept inline redirection function (will obsolete).
- 2019/03/04 (1.69) - renamed GetOverlayDrawList() to GetForegroundDrawList(). Kept redirection function (will obsolete).
@@ -593,7 +599,7 @@ CODE
longer name "Dear ImGui" that people can use to refer to this specific library.
Please try to refer to this library as "Dear ImGui".
- Q: How can I tell whether to dispatch mouse/keyboard to imgui or to my application?
+ Q: How can I tell whether to dispatch mouse/keyboard to Dear ImGui or to my application?
A: You can read the 'io.WantCaptureMouse', 'io.WantCaptureKeyboard' and 'io.WantTextInput' flags from the ImGuiIO structure (e.g. if (ImGui::GetIO().WantCaptureMouse) { ... } )
- When 'io.WantCaptureMouse' is set, imgui wants to use your mouse state, and you may want to discard/hide the inputs from the rest of your application.
- When 'io.WantCaptureKeyboard' is set, imgui wants to use your keyboard state, and you may want to discard/hide the inputs from the rest of your application.
@@ -993,7 +999,7 @@ CODE
#endif
// Clang/GCC warnings with -Weverything
-#ifdef __clang__
+#if defined(__clang__)
#pragma clang diagnostic ignored "-Wunknown-pragmas" // warning : unknown warning group '-Wformat-pedantic *' // not all warnings are known by all clang versions.. so ignoring warnings triggers new warnings on some configuration. great!
#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse.
#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.
@@ -1075,8 +1081,10 @@ static int FindWindowFocusIndex(ImGuiWindow* window);
// Misc
static void UpdateMouseInputs();
static void UpdateMouseWheel();
-static void UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]);
-static void RenderOuterBorders(ImGuiWindow* window);
+static bool UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]);
+static void RenderWindowOuterBorders(ImGuiWindow* window);
+static void RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size);
+static void RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open);
}
@@ -1129,6 +1137,7 @@ ImGuiStyle::ImGuiStyle()
WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested.
WindowMinSize = ImVec2(32,32); // Minimum window size
WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text
+ WindowMenuButtonPosition= ImGuiDir_Left; // Position of the collapsing/docking button in the title bar (left/right). Defaults to ImGuiDir_Left.
ChildRounding = 0.0f; // Radius of child window corners rounding. Set to 0.0f to have rectangular child windows
ChildBorderSize = 1.0f; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. Other values not well tested.
PopupRounding = 0.0f; // Radius of popup window corners rounding. Set to 0.0f to have rectangular child windows
@@ -1140,8 +1149,8 @@ ImGuiStyle::ImGuiStyle()
ItemInnerSpacing = ImVec2(4,4); // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label)
TouchExtraPadding = ImVec2(0,0); // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much!
IndentSpacing = 21.0f; // Horizontal spacing when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
- ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns
- ScrollbarSize = 16.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar
+ ColumnsMinSpacing = 6.0f; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1).
+ ScrollbarSize = 14.0f; // Width of the vertical scrollbar, Height of the horizontal scrollbar
ScrollbarRounding = 9.0f; // Radius of grab corners rounding for scrollbar
GrabMinSize = 10.0f; // Minimum width/height of a grab box for slider/scrollbar
GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
@@ -1249,9 +1258,10 @@ ImGuiIO::ImGuiIO()
// Pass in translated ASCII characters for text input.
// - with glfw you can get those from the callback set in glfwSetCharCallback()
// - on Windows you can get those using ToAscii+keyboard state, or via the WM_CHAR message
-void ImGuiIO::AddInputCharacter(ImWchar c)
+void ImGuiIO::AddInputCharacter(unsigned int c)
{
- InputQueueCharacters.push_back(c);
+ if (c > 0 && c < 0x10000)
+ InputQueueCharacters.push_back((ImWchar)c);
}
void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
@@ -1260,7 +1270,7 @@ void ImGuiIO::AddInputCharactersUTF8(const char* utf8_chars)
{
unsigned int c = 0;
utf8_chars += ImTextCharFromUtf8(&c, utf8_chars, NULL);
- if (c > 0 && c <= 0xFFFF)
+ if (c > 0 && c < 0x10000)
InputQueueCharacters.push_back((ImWchar)c);
}
}
@@ -2412,6 +2422,60 @@ void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, cons
LogRenderedText(&pos_min, text, text_display_end);
}
+
+// Another overly complex function until we reorganize everything into a nice all-in-one helper.
+// This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) which define _where_ the ellipsis is, from actual clipping of text and limit of the ellipsis display.
+// This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move.
+void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known)
+{
+ ImGuiContext& g = *GImGui;
+ if (text_end_full == NULL)
+ text_end_full = FindRenderedTextEnd(text);
+ const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f);
+
+ if (text_size.x > pos_max.x - pos_min.x)
+ {
+ // Hello wo...
+ // | | |
+ // min max ellipsis_max
+ // <-> this is generally some padding value
+
+ // FIXME-STYLE: RenderPixelEllipsis() style should use actual font data.
+ const ImFont* font = draw_list->_Data->Font;
+ const float font_size = draw_list->_Data->FontSize;
+ const int ellipsis_dot_count = 3;
+ const float ellipsis_width = (1.0f + 1.0f) * ellipsis_dot_count - 1.0f;
+ const char* text_end_ellipsis = NULL;
+
+ float text_width = ImMax((pos_max.x - ellipsis_width) - pos_min.x, 1.0f);
+ float text_size_clipped_x = font->CalcTextSizeA(font_size, text_width, 0.0f, text, text_end_full, &text_end_ellipsis).x;
+ if (text == text_end_ellipsis && text_end_ellipsis < text_end_full)
+ {
+ // Always display at least 1 character if there's no room for character + ellipsis
+ text_end_ellipsis = text + ImTextCountUtf8BytesFromChar(text, text_end_full);
+ text_size_clipped_x = font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text, text_end_ellipsis).x;
+ }
+ while (text_end_ellipsis > text && ImCharIsBlankA(text_end_ellipsis[-1]))
+ {
+ // Trim trailing space before ellipsis
+ text_end_ellipsis--;
+ text_size_clipped_x -= font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text_end_ellipsis, text_end_ellipsis + 1).x; // Ascii blanks are always 1 byte
+ }
+ RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f));
+
+ const float ellipsis_x = pos_min.x + text_size_clipped_x + 1.0f;
+ if (ellipsis_x + ellipsis_width - 1.0f <= ellipsis_max_x)
+ RenderPixelEllipsis(draw_list, ImVec2(ellipsis_x, pos_min.y), GetColorU32(ImGuiCol_Text), ellipsis_dot_count);
+ }
+ else
+ {
+ RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_full, &text_size, ImVec2(0.0f, 0.0f));
+ }
+
+ if (g.LogEnabled)
+ LogRenderedText(&pos_min, text, text_end_full);
+}
+
// Render a rectangle shaped with optional rounding and borders
void ImGui::RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border, float rounding)
{
@@ -2439,13 +2503,11 @@ void ImGui::RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding)
}
// Render an arrow aimed to be aligned with text (p_min is a position in the same space text would be positioned). To e.g. denote expanded/collapsed state
-void ImGui::RenderArrow(ImVec2 p_min, ImGuiDir dir, float scale)
+void ImGui::RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale)
{
- ImGuiContext& g = *GImGui;
-
- const float h = g.FontSize * 1.00f;
+ const float h = draw_list->_Data->FontSize * 1.00f;
float r = h * 0.40f * scale;
- ImVec2 center = p_min + ImVec2(h * 0.50f, h * 0.50f * scale);
+ ImVec2 center = pos + ImVec2(h * 0.50f, h * 0.50f * scale);
ImVec2 a, b, c;
switch (dir)
@@ -2469,15 +2531,12 @@ void ImGui::RenderArrow(ImVec2 p_min, ImGuiDir dir, float scale)
IM_ASSERT(0);
break;
}
-
- g.CurrentWindow->DrawList->AddTriangleFilled(center + a, center + b, center + c, GetColorU32(ImGuiCol_Text));
+ draw_list->AddTriangleFilled(center + a, center + b, center + c, col);
}
-void ImGui::RenderBullet(ImVec2 pos)
+void ImGui::RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col)
{
- ImGuiContext& g = *GImGui;
- ImGuiWindow* window = g.CurrentWindow;
- window->DrawList->AddCircleFilled(pos, g.FontSize*0.20f, GetColorU32(ImGuiCol_Text), 8);
+ draw_list->AddCircleFilled(pos, draw_list->_Data->FontSize * 0.20f, col, 8);
}
void ImGui::RenderCheckMark(ImVec2 pos, ImU32 col, float sz)
@@ -2544,7 +2603,7 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name)
Flags = ImGuiWindowFlags_None;
Pos = ImVec2(0.0f, 0.0f);
Size = SizeFull = ImVec2(0.0f, 0.0f);
- SizeContents = SizeContentsExplicit = ImVec2(0.0f, 0.0f);
+ ContentSize = ContentSizeExplicit = ImVec2(0.0f, 0.0f);
WindowPadding = ImVec2(0.0f, 0.0f);
WindowRounding = 0.0f;
WindowBorderSize = 0.0f;
@@ -2618,6 +2677,14 @@ ImGuiID ImGuiWindow::GetID(const void* ptr)
return id;
}
+ImGuiID ImGuiWindow::GetID(int n)
+{
+ ImGuiID seed = IDStack.back();
+ ImGuiID id = ImHashData(&n, sizeof(n), seed);
+ ImGui::KeepAliveID(id);
+ return id;
+}
+
ImGuiID ImGuiWindow::GetIDNoKeepAlive(const char* str, const char* str_end)
{
ImGuiID seed = IDStack.back();
@@ -2630,6 +2697,12 @@ ImGuiID ImGuiWindow::GetIDNoKeepAlive(const void* ptr)
return ImHashData(&ptr, sizeof(void*), seed);
}
+ImGuiID ImGuiWindow::GetIDNoKeepAlive(int n)
+{
+ ImGuiID seed = IDStack.back();
+ return ImHashData(&n, sizeof(n), seed);
+}
+
// This is only used in rare/specific situations to manufacture an ID out of nowhere.
ImGuiID ImGuiWindow::GetIDFromRectangle(const ImRect& r_abs)
{
@@ -2674,8 +2747,8 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
if (g.ActiveIdIsJustActivated)
{
g.ActiveIdTimer = 0.0f;
- g.ActiveIdHasBeenPressed = false;
- g.ActiveIdHasBeenEdited = false;
+ g.ActiveIdHasBeenPressedBefore = false;
+ g.ActiveIdHasBeenEditedBefore = false;
if (id != 0)
{
g.LastActiveId = id;
@@ -2687,6 +2760,7 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
g.ActiveIdBlockNavInputFlags = 0;
g.ActiveIdAllowOverlap = false;
g.ActiveIdWindow = window;
+ g.ActiveIdHasBeenEditedThisFrame = false;
if (id)
{
g.ActiveIdIsAlive = id;
@@ -2754,7 +2828,8 @@ void ImGui::MarkItemEdited(ImGuiID id)
IM_ASSERT(g.ActiveId == id || g.ActiveId == 0 || g.DragDropActive);
IM_UNUSED(id); // Avoid unused variable warnings when asserts are compiled out.
//IM_ASSERT(g.CurrentWindow->DC.LastItemId == id);
- g.ActiveIdHasBeenEdited = true;
+ g.ActiveIdHasBeenEditedThisFrame = true;
+ g.ActiveIdHasBeenEditedBefore = true;
g.CurrentWindow->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
}
@@ -2787,10 +2862,11 @@ void ImGui::ItemSize(const ImVec2& size, float text_offset_y)
return;
// Always align ourselves on pixel boundaries
- const float line_height = ImMax(window->DC.CurrentLineSize.y, size.y);
- const float text_base_offset = ImMax(window->DC.CurrentLineTextBaseOffset, text_offset_y);
+ const float line_height = ImMax(window->DC.CurrLineSize.y, size.y);
+ const float text_base_offset = ImMax(window->DC.CurrLineTextBaseOffset, text_offset_y);
//if (g.IO.KeyAlt) window->DrawList->AddRect(window->DC.CursorPos, window->DC.CursorPos + ImVec2(size.x, line_height), IM_COL32(255,0,0,200)); // [DEBUG]
- window->DC.CursorPosPrevLine = ImVec2(window->DC.CursorPos.x + size.x, window->DC.CursorPos.y);
+ window->DC.CursorPosPrevLine.x = window->DC.CursorPos.x + size.x;
+ window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y;
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
window->DC.CursorPos.y = (float)(int)(window->DC.CursorPos.y + line_height + g.Style.ItemSpacing.y);
window->DC.CursorMaxPos.x = ImMax(window->DC.CursorMaxPos.x, window->DC.CursorPosPrevLine.x);
@@ -2799,7 +2875,7 @@ void ImGui::ItemSize(const ImVec2& size, float text_offset_y)
window->DC.PrevLineSize.y = line_height;
window->DC.PrevLineTextBaseOffset = text_base_offset;
- window->DC.CurrentLineSize.y = window->DC.CurrentLineTextBaseOffset = 0.0f;
+ window->DC.CurrLineSize.y = window->DC.CurrLineTextBaseOffset = 0.0f;
// Horizontal layout mode
if (window->DC.LayoutType == ImGuiLayoutType_Horizontal)
@@ -2823,9 +2899,13 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
{
// Navigation processing runs prior to clipping early-out
// (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget
- // (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests unfortunately, but it is still limited to one window.
- // it may not scale very well for windows with ten of thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.
- // We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick)
+ // (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests
+ // unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of
+ // thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.
+ // We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able
+ // to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick).
+ // We intentionally don't check if g.NavWindow != NULL because g.NavAnyRequest should only be set when it is non null.
+ // If we crash on a NULL g.NavWindow we need to fix the bug elsewhere.
window->DC.NavLayerActiveMaskNext |= window->DC.NavLayerCurrentMask;
if (g.NavId == id || g.NavAnyRequest)
if (g.NavWindow->RootWindowForNav == window->RootWindowForNav)
@@ -2836,6 +2916,7 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
window->DC.LastItemId = id;
window->DC.LastItemRect = bb;
window->DC.LastItemStatusFlags = ImGuiItemStatusFlags_None;
+ g.NextItemData.Flags = ImGuiNextItemDataFlags_None;
#ifdef IMGUI_ENABLE_TEST_ENGINE
if (id != 0)
@@ -2983,7 +3064,7 @@ float ImGui::CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x)
ImGuiWindow* window = GImGui->CurrentWindow;
if (wrap_pos_x == 0.0f)
- wrap_pos_x = GetWorkRectMax().x;
+ wrap_pos_x = window->WorkRect.Max.x;
else if (wrap_pos_x > 0.0f)
wrap_pos_x += window->Pos.x - window->Scroll.x; // wrap_pos_x is provided is window local space
@@ -3023,7 +3104,7 @@ const char* ImGui::GetVersion()
return IMGUI_VERSION;
}
-// Internal state access - if you want to share ImGui state between modules (e.g. DLL) or allocate it yourself
+// Internal state access - if you want to share Dear ImGui state between modules (e.g. DLL) or allocate it yourself
// Note that we still point to some static data and members (such as GFontAtlas), so the state instance you end up using will point to the static data within its module
ImGuiContext* ImGui::GetCurrentContext()
{
@@ -3042,7 +3123,7 @@ void ImGui::SetCurrentContext(ImGuiContext* ctx)
// Helper function to verify ABI compatibility between caller code and compiled version of Dear ImGui.
// Verify that the type sizes are matching between the calling file's compilation unit and imgui.cpp's compilation unit
// If the user has inconsistent compilation settings, imgui configuration #define, packing pragma, etc. your user code
-// may see different structures thanwhat imgui.cpp sees, which is problematic.
+// may see different structures than what imgui.cpp sees, which is problematic.
// We usually require settings to be in imconfig.h to make sure that they are accessible to all compilation units involved with Dear ImGui.
bool ImGui::DebugCheckVersionAndDataLayout(const char* version, size_t sz_io, size_t sz_style, size_t sz_vec2, size_t sz_vec4, size_t sz_vert, size_t sz_idx)
{
@@ -3316,7 +3397,7 @@ void ImGui::UpdateMouseWheel()
// Zoom / Scale window
// FIXME-OBSOLETE: This is an old feature, it still works but pretty much nobody is using it and may be best redesigned.
- if (g.IO.MouseWheel != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling)
+ if (g.IO.MouseWheel != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling && !window->Collapsed)
{
const float new_font_scale = ImClamp(window->FontWindowScale + g.IO.MouseWheel * 0.10f, 0.50f, 2.50f);
const float scale = new_font_scale / window->FontWindowScale;
@@ -3324,7 +3405,7 @@ void ImGui::UpdateMouseWheel()
if (!(window->Flags & ImGuiWindowFlags_ChildWindow))
{
const ImVec2 offset = window->Size * (1.0f - scale) * (g.IO.MousePos - window->Pos) / window->Size;
- window->Pos = ImFloor(window->Pos + offset);
+ SetWindowPos(window, window->Pos + offset, 0);
window->Size = ImFloor(window->Size * scale);
window->SizeFull = ImFloor(window->SizeFull * scale);
}
@@ -3402,13 +3483,13 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags()
if (!mouse_avail_to_imgui && !mouse_dragging_extern_payload)
g.HoveredWindow = g.HoveredRootWindow = NULL;
- // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to imgui, false = dispatch mouse info to imgui + app)
+ // Update io.WantCaptureMouse for the user application (true = dispatch mouse info to imgui, false = dispatch mouse info to Dear ImGui + app)
if (g.WantCaptureMouseNextFrame != -1)
g.IO.WantCaptureMouse = (g.WantCaptureMouseNextFrame != 0);
else
g.IO.WantCaptureMouse = (mouse_avail_to_imgui && (g.HoveredWindow != NULL || mouse_any_down)) || (!g.OpenPopupStack.empty());
- // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to imgui, false = dispatch keyboard info to imgui + app)
+ // Update io.WantCaptureKeyboard for the user application (true = dispatch keyboard info to imgui, false = dispatch keyboard info to Dear ImGui + app)
if (g.WantCaptureKeyboardNextFrame != -1)
g.IO.WantCaptureKeyboard = (g.WantCaptureKeyboardNextFrame != 0);
else
@@ -3440,6 +3521,8 @@ void ImGui::NewFrame()
IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!");
IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting. Alpha cannot be negative (allows us to avoid a few clamps in color computations)!");
IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting.");
+ IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right);
+
for (int n = 0; n < ImGuiKey_COUNT; n++)
IM_ASSERT(g.IO.KeyMap[n] >= -1 && g.IO.KeyMap[n] < IM_ARRAYSIZE(g.IO.KeysDown) && "io.KeyMap[] contains an out of bound value (need to be 0..512, or -1 for unmapped key)");
@@ -3486,16 +3569,21 @@ void ImGui::NewFrame()
IM_ASSERT(g.Font->IsLoaded());
g.DrawListSharedData.ClipRectFullscreen = ImVec4(0.0f, 0.0f, g.IO.DisplaySize.x, g.IO.DisplaySize.y);
g.DrawListSharedData.CurveTessellationTol = g.Style.CurveTessellationTol;
+ g.DrawListSharedData.InitialFlags = ImDrawListFlags_None;
+ if (g.Style.AntiAliasedLines)
+ g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedLines;
+ if (g.Style.AntiAliasedFill)
+ g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AntiAliasedFill;
+ if (g.IO.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset)
+ g.DrawListSharedData.InitialFlags |= ImDrawListFlags_AllowVtxOffset;
g.BackgroundDrawList.Clear();
g.BackgroundDrawList.PushTextureID(g.IO.Fonts->TexID);
g.BackgroundDrawList.PushClipRectFullScreen();
- g.BackgroundDrawList.Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0);
g.ForegroundDrawList.Clear();
g.ForegroundDrawList.PushTextureID(g.IO.Fonts->TexID);
g.ForegroundDrawList.PushClipRectFullScreen();
- g.ForegroundDrawList.Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0);
// Mark rendering data as invalid to prevent user who may have a handle on it to use it.
g.DrawData.Clear();
@@ -3523,8 +3611,9 @@ void ImGui::NewFrame()
g.LastActiveIdTimer += g.IO.DeltaTime;
g.ActiveIdPreviousFrame = g.ActiveId;
g.ActiveIdPreviousFrameWindow = g.ActiveIdWindow;
- g.ActiveIdPreviousFrameHasBeenEdited = g.ActiveIdHasBeenEdited;
+ g.ActiveIdPreviousFrameHasBeenEditedBefore = g.ActiveIdHasBeenEditedBefore;
g.ActiveIdIsAlive = 0;
+ g.ActiveIdHasBeenEditedThisFrame = false;
g.ActiveIdPreviousFrameIsAlive = false;
g.ActiveIdIsJustActivated = false;
if (g.TempInputTextId != 0 && g.ActiveId != g.TempInputTextId)
@@ -3553,9 +3642,12 @@ void ImGui::NewFrame()
g.FramerateSecPerFrameIdx = (g.FramerateSecPerFrameIdx + 1) % IM_ARRAYSIZE(g.FramerateSecPerFrame);
g.IO.Framerate = (g.FramerateSecPerFrameAccum > 0.0f) ? (1.0f / (g.FramerateSecPerFrameAccum / (float)IM_ARRAYSIZE(g.FramerateSecPerFrame))) : FLT_MAX;
+ // Find hovered window
+ // (needs to be before UpdateMouseMovingWindowNewFrame so we fill g.HoveredWindowUnderMovingWindow on the mouse release frame)
+ UpdateHoveredWindowAndCaptureFlags();
+
// Handle user moving window with mouse (at the beginning of the frame to avoid input lag or sheering)
UpdateMouseMovingWindowNewFrame();
- UpdateHoveredWindowAndCaptureFlags();
// Background darkening/whitening
if (GetFrontMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f))
@@ -3663,7 +3755,7 @@ void ImGui::Shutdown(ImGuiContext* context)
}
g.IO.Fonts = NULL;
- // Cleanup of other data are conditional on actually having initialized ImGui.
+ // Cleanup of other data are conditional on actually having initialized Dear ImGui.
if (!g.Initialized)
return;
@@ -3734,7 +3826,7 @@ static void AddWindowToSortBuffer(ImVector<ImGuiWindow*>* out_sorted_windows, Im
{
int count = window->DC.ChildWindows.Size;
if (count > 1)
- ImQsort(window->DC.ChildWindows.begin(), (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);
+ ImQsort(window->DC.ChildWindows.Data, (size_t)count, sizeof(ImGuiWindow*), ChildWindowComparer);
for (int i = 0; i < count; i++)
{
ImGuiWindow* child = window->DC.ChildWindows[i];
@@ -3758,19 +3850,28 @@ static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* d
return;
}
- // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc. May trigger for you if you are using PrimXXX functions incorrectly.
+ // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc.
+ // May trigger for you if you are using PrimXXX functions incorrectly.
IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size);
IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size);
- IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);
+ if (!(draw_list->Flags & ImDrawListFlags_AllowVtxOffset))
+ IM_ASSERT((int)draw_list->_VtxCurrentIdx == draw_list->VtxBuffer.Size);
// Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window)
// If this assert triggers because you are drawing lots of stuff manually:
- // A) Make sure you are coarse clipping, because ImDrawList let all your vertices pass. You can use the Metrics window to inspect draw list contents.
- // B) If you need/want meshes with more than 64K vertices, uncomment the '#define ImDrawIdx unsigned int' line in imconfig.h to set the index size to 4 bytes.
- // You'll need to handle the 4-bytes indices to your renderer. For example, the OpenGL example code detect index size at compile-time by doing:
- // glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
- // Your own engine or render API may use different parameters or function calls to specify index sizes. 2 and 4 bytes indices are generally supported by most API.
- // C) If for some reason you cannot use 4 bytes indices or don't want to, a workaround is to call BeginChild()/EndChild() before reaching the 64K limit to split your draw commands in multiple draw lists.
+ // - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds.
+ // Be mindful that the ImDrawList API doesn't filter vertices. Use the Metrics window to inspect draw list contents.
+ // - If you want large meshes with more than 64K vertices, you can either:
+ // (A) Handle the ImDrawCmd::VtxOffset value in your renderer back-end, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'.
+ // Most example back-ends already support this from 1.71. Pre-1.71 back-ends won't.
+ // Some graphics API such as GL ES 1/2 don't have a way to offset the starting vertex so it is not supported for them.
+ // (B) Or handle 32-bits indices in your renderer back-end, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h.
+ // Most example back-ends already support this. For example, the OpenGL example code detect index size at compile-time:
+ // glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
+ // Your own engine or render API may use different parameters or function calls to specify index sizes.
+ // 2 and 4 bytes indices are generally supported by most graphics API.
+ // - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() before reaching
+ // the 64K limit to split your draw commands in multiple draw lists.
if (sizeof(ImDrawIdx) == 2)
IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above");
@@ -4329,13 +4430,15 @@ bool ImGui::IsItemDeactivated()
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
+ if (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_HasDeactivated)
+ return (window->DC.LastItemStatusFlags & ImGuiItemStatusFlags_Deactivated) != 0;
return (g.ActiveIdPreviousFrame == window->DC.LastItemId && g.ActiveIdPreviousFrame != 0 && g.ActiveId != window->DC.LastItemId);
}
bool ImGui::IsItemDeactivatedAfterEdit()
{
ImGuiContext& g = *GImGui;
- return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEdited || (g.ActiveId == 0 && g.ActiveIdHasBeenEdited));
+ return IsItemDeactivated() && (g.ActiveIdPreviousFrameHasBeenEditedBefore || (g.ActiveId == 0 && g.ActiveIdHasBeenEditedBefore));
}
bool ImGui::IsItemFocused()
@@ -4604,8 +4707,8 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl
if (ImLengthSqr(settings->Size) > 0.00001f)
size = ImFloor(settings->Size);
}
- window->Size = window->SizeFull = window->SizeFullAtLastBegin = ImFloor(size);
- window->DC.CursorMaxPos = window->Pos; // So first call to CalcSizeContents() doesn't return crazy values
+ window->Size = window->SizeFull = ImFloor(size);
+ window->DC.CursorStartPos = window->DC.CursorMaxPos = window->Pos; // So first call to CalcContentSize() doesn't return crazy values
if ((flags & ImGuiWindowFlags_AlwaysAutoResize) != 0)
{
@@ -4632,7 +4735,7 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl
static ImVec2 CalcSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size)
{
ImGuiContext& g = *GImGui;
- if (g.NextWindowData.SizeConstraintCond != 0)
+ if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint)
{
// Using -1,-1 on either X/Y axis to preserve the current size.
ImRect cr = g.NextWindowData.SizeConstraintRect;
@@ -4661,45 +4764,50 @@ static ImVec2 CalcSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size)
return new_size;
}
-static ImVec2 CalcSizeContents(ImGuiWindow* window)
+static ImVec2 CalcContentSize(ImGuiWindow* window)
{
if (window->Collapsed)
if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
- return window->SizeContents;
+ return window->ContentSize;
if (window->Hidden && window->HiddenFramesCannotSkipItems == 0 && window->HiddenFramesCanSkipItems > 0)
- return window->SizeContents;
+ return window->ContentSize;
ImVec2 sz;
- sz.x = (float)(int)((window->SizeContentsExplicit.x != 0.0f) ? window->SizeContentsExplicit.x : (window->DC.CursorMaxPos.x - window->Pos.x + window->Scroll.x));
- sz.y = (float)(int)((window->SizeContentsExplicit.y != 0.0f) ? window->SizeContentsExplicit.y : (window->DC.CursorMaxPos.y - window->Pos.y + window->Scroll.y));
- return sz + window->WindowPadding;
+ sz.x = (float)(int)((window->ContentSizeExplicit.x != 0.0f) ? window->ContentSizeExplicit.x : window->DC.CursorMaxPos.x - window->DC.CursorStartPos.x);
+ sz.y = (float)(int)((window->ContentSizeExplicit.y != 0.0f) ? window->ContentSizeExplicit.y : window->DC.CursorMaxPos.y - window->DC.CursorStartPos.y);
+ return sz;
}
static ImVec2 CalcSizeAutoFit(ImGuiWindow* window, const ImVec2& size_contents)
{
ImGuiContext& g = *GImGui;
ImGuiStyle& style = g.Style;
+ ImVec2 size_decorations = ImVec2(0.0f, window->TitleBarHeight() + window->MenuBarHeight());
+ ImVec2 size_pad = window->WindowPadding * 2.0f;
+ ImVec2 size_desired = size_contents + size_pad + size_decorations;
if (window->Flags & ImGuiWindowFlags_Tooltip)
{
// Tooltip always resize
- return size_contents;
+ return size_desired;
}
else
{
- // Maximum window size is determined by the display size
+ // Maximum window size is determined by the viewport size or monitor size
const bool is_popup = (window->Flags & ImGuiWindowFlags_Popup) != 0;
const bool is_menu = (window->Flags & ImGuiWindowFlags_ChildMenu) != 0;
ImVec2 size_min = style.WindowMinSize;
if (is_popup || is_menu) // Popups and menus bypass style.WindowMinSize by default, but we give then a non-zero minimum size to facilitate understanding problematic cases (e.g. empty popups)
size_min = ImMin(size_min, ImVec2(4.0f, 4.0f));
- ImVec2 size_auto_fit = ImClamp(size_contents, size_min, ImMax(size_min, g.IO.DisplaySize - style.DisplaySafeAreaPadding * 2.0f));
+ ImVec2 size_auto_fit = ImClamp(size_desired, size_min, ImMax(size_min, g.IO.DisplaySize - style.DisplaySafeAreaPadding * 2.0f));
// When the window cannot fit all contents (either because of constraints, either because screen is too small),
// we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding.
ImVec2 size_auto_fit_after_constraint = CalcSizeAfterConstraint(window, size_auto_fit);
- if (size_auto_fit_after_constraint.x < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar))
+ bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - size_decorations.x < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar);
+ bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - size_decorations.y < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar);
+ if (will_have_scrollbar_x)
size_auto_fit.y += style.ScrollbarSize;
- if (size_auto_fit_after_constraint.y < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar))
+ if (will_have_scrollbar_y)
size_auto_fit.x += style.ScrollbarSize;
return size_auto_fit;
}
@@ -4707,20 +4815,10 @@ static ImVec2 CalcSizeAutoFit(ImGuiWindow* window, const ImVec2& size_contents)
ImVec2 ImGui::CalcWindowExpectedSize(ImGuiWindow* window)
{
- ImVec2 size_contents = CalcSizeContents(window);
+ ImVec2 size_contents = CalcContentSize(window);
return CalcSizeAfterConstraint(window, CalcSizeAutoFit(window, size_contents));
}
-float ImGui::GetWindowScrollMaxX(ImGuiWindow* window)
-{
- return ImMax(0.0f, window->SizeContents.x - (window->SizeFull.x - window->ScrollbarSizes.x));
-}
-
-float ImGui::GetWindowScrollMaxY(ImGuiWindow* window)
-{
- return ImMax(0.0f, window->SizeContents.y - (window->SizeFull.y - window->ScrollbarSizes.y));
-}
-
static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool snap_on_edges)
{
ImGuiContext& g = *GImGui;
@@ -4728,7 +4826,7 @@ static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool s
if (window->ScrollTarget.x < FLT_MAX)
{
float cr_x = window->ScrollTargetCenterRatio.x;
- scroll.x = window->ScrollTarget.x - cr_x * (window->SizeFull.x - window->ScrollbarSizes.x);
+ scroll.x = window->ScrollTarget.x - cr_x * window->InnerRect.GetWidth();
}
if (window->ScrollTarget.y < FLT_MAX)
{
@@ -4737,15 +4835,15 @@ static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool s
float target_y = window->ScrollTarget.y;
if (snap_on_edges && cr_y <= 0.0f && target_y <= window->WindowPadding.y)
target_y = 0.0f;
- if (snap_on_edges && cr_y >= 1.0f && target_y >= window->SizeContents.y - window->WindowPadding.y + g.Style.ItemSpacing.y)
- target_y = window->SizeContents.y;
- scroll.y = target_y - (1.0f - cr_y) * (window->TitleBarHeight() + window->MenuBarHeight()) - cr_y * (window->SizeFull.y - window->ScrollbarSizes.y);
+ if (snap_on_edges && cr_y >= 1.0f && target_y >= window->ContentSize.y + window->WindowPadding.y + g.Style.ItemSpacing.y)
+ target_y = window->ContentSize.y + window->WindowPadding.y * 2.0f;
+ scroll.y = target_y - cr_y * window->InnerRect.GetHeight();
}
scroll = ImMax(scroll, ImVec2(0.0f, 0.0f));
if (!window->Collapsed && !window->SkipItems)
{
- scroll.x = ImMin(scroll.x, ImGui::GetWindowScrollMaxX(window));
- scroll.y = ImMin(scroll.y, ImGui::GetWindowScrollMaxY(window));
+ scroll.x = ImMin(scroll.x, window->ScrollMax.x);
+ scroll.y = ImMin(scroll.y, window->ScrollMax.y);
}
return scroll;
}
@@ -4801,15 +4899,18 @@ static ImRect GetResizeBorderRect(ImGuiWindow* window, int border_n, float perp_
}
// Handle resize for: Resize Grips, Borders, Gamepad
-static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4])
+// Return true when using auto-fit (double click on resize grip)
+static bool ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4])
{
ImGuiContext& g = *GImGui;
ImGuiWindowFlags flags = window->Flags;
+
if ((flags & ImGuiWindowFlags_NoResize) || (flags & ImGuiWindowFlags_AlwaysAutoResize) || window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
- return;
+ return false;
if (window->WasActive == false) // Early out to avoid running this code for e.g. an hidden implicit/fallback Debug window.
- return;
+ return false;
+ bool ret_auto_fit = false;
const int resize_border_count = g.IO.ConfigWindowsResizeFromEdges ? 4 : 0;
const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f);
const float grip_hover_inner_size = (float)(int)(grip_draw_size * 0.75f);
@@ -4843,6 +4944,7 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
{
// Manual auto-fit when double-clicking
size_target = CalcSizeAfterConstraint(window, size_auto_fit);
+ ret_auto_fit = true;
ClearActiveID();
}
else if (held)
@@ -4917,6 +5019,7 @@ static void ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main);
window->Size = window->SizeFull;
+ return ret_auto_fit;
}
static inline void ClampWindowRect(ImGuiWindow* window, const ImRect& rect, const ImVec2& padding)
@@ -4926,7 +5029,7 @@ static inline void ClampWindowRect(ImGuiWindow* window, const ImRect& rect, cons
window->Pos = ImMin(rect.Max - padding, ImMax(window->Pos + size_for_clamping, rect.Min + padding) - size_for_clamping);
}
-static void ImGui::RenderOuterBorders(ImGuiWindow* window)
+static void ImGui::RenderWindowOuterBorders(ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
float rounding = window->WindowRounding;
@@ -4963,6 +5066,166 @@ static void ImGui::RenderOuterBorders(ImGuiWindow* window)
}
}
+void ImGui::RenderWindowDecorations(ImGuiWindow* window, const ImRect& title_bar_rect, bool title_bar_is_highlight, int resize_grip_count, const ImU32 resize_grip_col[4], float resize_grip_draw_size)
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiStyle& style = g.Style;
+ ImGuiWindowFlags flags = window->Flags;
+
+ // Draw window + handle manual resize
+ // As we highlight the title bar when want_focus is set, multiple reappearing windows will have have their title bar highlighted on their reappearing frame.
+ const float window_rounding = window->WindowRounding;
+ const float window_border_size = window->WindowBorderSize;
+ if (window->Collapsed)
+ {
+ // Title bar only
+ float backup_border_size = style.FrameBorderSize;
+ g.Style.FrameBorderSize = window->WindowBorderSize;
+ ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed);
+ RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding);
+ g.Style.FrameBorderSize = backup_border_size;
+ }
+ else
+ {
+ // Window background
+ if (!(flags & ImGuiWindowFlags_NoBackground))
+ {
+ ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags));
+ float alpha = 1.0f;
+ if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasBgAlpha)
+ alpha = g.NextWindowData.BgAlphaVal;
+ if (alpha != 1.0f)
+ bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT);
+ window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot);
+ }
+
+ // Title bar
+ if (!(flags & ImGuiWindowFlags_NoTitleBar))
+ {
+ ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg);
+ window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top);
+ }
+
+ // Menu bar
+ if (flags & ImGuiWindowFlags_MenuBar)
+ {
+ ImRect menu_bar_rect = window->MenuBarRect();
+ menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them.
+ window->DrawList->AddRectFilled(menu_bar_rect.Min + ImVec2(window_border_size, 0), menu_bar_rect.Max - ImVec2(window_border_size, 0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top);
+ if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y)
+ window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
+ }
+
+ // Scrollbars
+ if (window->ScrollbarX)
+ Scrollbar(ImGuiAxis_X);
+ if (window->ScrollbarY)
+ Scrollbar(ImGuiAxis_Y);
+
+ // Render resize grips (after their input handling so we don't have a frame of latency)
+ if (!(flags & ImGuiWindowFlags_NoResize))
+ {
+ for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
+ {
+ const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
+ const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
+ window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, resize_grip_draw_size) : ImVec2(resize_grip_draw_size, window_border_size)));
+ window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(resize_grip_draw_size, window_border_size) : ImVec2(window_border_size, resize_grip_draw_size)));
+ window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12);
+ window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]);
+ }
+ }
+
+ // Borders
+ RenderWindowOuterBorders(window);
+ }
+}
+
+// Render title text, collapse button, close button
+void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& title_bar_rect, const char* name, bool* p_open)
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiStyle& style = g.Style;
+ ImGuiWindowFlags flags = window->Flags;
+
+ const bool has_close_button = (p_open != NULL);
+ const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse);
+
+ // Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer)
+ const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags;
+ window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus;
+ window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
+ window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu);
+
+ // Layout buttons
+ // FIXME: Would be nice to generalize the subtleties expressed here into reusable code.
+ float pad_l = style.FramePadding.x;
+ float pad_r = style.FramePadding.x;
+ float button_sz = g.FontSize;
+ ImVec2 close_button_pos;
+ ImVec2 collapse_button_pos;
+ if (has_close_button)
+ {
+ pad_r += button_sz;
+ close_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y);
+ }
+ if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Right)
+ {
+ pad_r += button_sz;
+ collapse_button_pos = ImVec2(title_bar_rect.Max.x - pad_r - style.FramePadding.x, title_bar_rect.Min.y);
+ }
+ if (has_collapse_button && style.WindowMenuButtonPosition == ImGuiDir_Left)
+ {
+ collapse_button_pos = ImVec2(title_bar_rect.Min.x + pad_l - style.FramePadding.x, title_bar_rect.Min.y);
+ pad_l += button_sz;
+ }
+
+ // Collapse button (submitting first so it gets priority when choosing a navigation init fallback)
+ if (has_collapse_button)
+ if (CollapseButton(window->GetID("#COLLAPSE"), collapse_button_pos))
+ window->WantCollapseToggle = true; // Defer actual collapsing to next frame as we are too far in the Begin() function
+
+ // Close button
+ if (has_close_button)
+ if (CloseButton(window->GetID("#CLOSE"), close_button_pos))
+ *p_open = false;
+
+ window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
+ window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main);
+ window->DC.ItemFlags = item_flags_backup;
+
+ // Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker)
+ // FIXME: Refactor text alignment facilities along with RenderText helpers, this is WAY too much messy code..
+ const char* UNSAVED_DOCUMENT_MARKER = "*";
+ const float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? CalcTextSize(UNSAVED_DOCUMENT_MARKER, NULL, false).x : 0.0f;
+ const ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f);
+
+ // As a nice touch we try to ensure that centered title text doesn't get affected by visibility of Close/Collapse button,
+ // while uncentered title text will still reach edges correct.
+ if (pad_l > style.FramePadding.x)
+ pad_l += g.Style.ItemInnerSpacing.x;
+ if (pad_r > style.FramePadding.x)
+ pad_r += g.Style.ItemInnerSpacing.x;
+ if (style.WindowTitleAlign.x > 0.0f && style.WindowTitleAlign.x < 1.0f)
+ {
+ float centerness = ImSaturate(1.0f - ImFabs(style.WindowTitleAlign.x - 0.5f) * 2.0f); // 0.0f on either edges, 1.0f on center
+ float pad_extend = ImMin(ImMax(pad_l, pad_r), title_bar_rect.GetWidth() - pad_l - pad_r - text_size.x);
+ pad_l = ImMax(pad_l, pad_extend * centerness);
+ pad_r = ImMax(pad_r, pad_extend * centerness);
+ }
+
+ ImRect layout_r(title_bar_rect.Min.x + pad_l, title_bar_rect.Min.y, title_bar_rect.Max.x - pad_r, title_bar_rect.Max.y);
+ ImRect clip_r(layout_r.Min.x, layout_r.Min.y, layout_r.Max.x + g.Style.ItemInnerSpacing.x, layout_r.Max.y);
+ //if (g.IO.KeyCtrl) window->DrawList->AddRect(layout_r.Min, layout_r.Max, IM_COL32(255, 128, 0, 255)); // [DEBUG]
+ RenderTextClipped(layout_r.Min, layout_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_r);
+ if (flags & ImGuiWindowFlags_UnsavedDocument)
+ {
+ ImVec2 marker_pos = ImVec2(ImMax(layout_r.Min.x, layout_r.Min.x + (layout_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x) + text_size.x, layout_r.Min.y) + ImVec2(2 - marker_size_x, 0.0f);
+ ImVec2 off = ImVec2(0.0f, (float)(int)(-g.FontSize * 0.25f));
+ RenderTextClipped(marker_pos + off, layout_r.Max + off, UNSAVED_DOCUMENT_MARKER, NULL, NULL, ImVec2(0, style.WindowTitleAlign.y), &clip_r);
+ }
+}
+
void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags flags, ImGuiWindow* parent_window)
{
window->ParentWindow = parent_window;
@@ -4978,7 +5241,7 @@ void ImGui::UpdateWindowParentAndRootLinks(ImGuiWindow* window, ImGuiWindowFlags
}
}
-// Push a new ImGui window to add widgets to.
+// Push a new Dear ImGui window to add widgets to.
// - A default window called "Debug" is automatically stacked at the beginning of every frame so you can use widgets without explicitly calling a Begin/End pair.
// - Begin/End can be called multiple times during the frame with the same window name to append content.
// - The window name is used as a unique identifier to preserve window information across frames (and save rudimentary information to the .ini file).
@@ -4998,7 +5261,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
const bool window_just_created = (window == NULL);
if (window_just_created)
{
- ImVec2 size_on_first_use = (g.NextWindowData.SizeCond != 0) ? g.NextWindowData.SizeVal : ImVec2(0.0f, 0.0f); // Any condition flag will do since we are creating a new window here.
+ ImVec2 size_on_first_use = (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize) ? g.NextWindowData.SizeVal : ImVec2(0.0f, 0.0f); // Any condition flag will do since we are creating a new window here.
window = CreateNewWindow(name, size_on_first_use, flags);
}
@@ -5062,7 +5325,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Process SetNextWindow***() calls
bool window_pos_set_by_api = false;
bool window_size_x_set_by_api = false, window_size_y_set_by_api = false;
- if (g.NextWindowData.PosCond)
+ if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos)
{
window_pos_set_by_api = (window->SetWindowPosAllowFlags & g.NextWindowData.PosCond) != 0;
if (window_pos_set_by_api && ImLengthSqr(g.NextWindowData.PosPivotVal) > 0.00001f)
@@ -5078,26 +5341,19 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
SetWindowPos(window, g.NextWindowData.PosVal, g.NextWindowData.PosCond);
}
}
- if (g.NextWindowData.SizeCond)
+ if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSize)
{
window_size_x_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.x > 0.0f);
window_size_y_set_by_api = (window->SetWindowSizeAllowFlags & g.NextWindowData.SizeCond) != 0 && (g.NextWindowData.SizeVal.y > 0.0f);
SetWindowSize(window, g.NextWindowData.SizeVal, g.NextWindowData.SizeCond);
}
- if (g.NextWindowData.ContentSizeCond)
- {
- // Adjust passed "client size" to become a "window size"
- window->SizeContentsExplicit = g.NextWindowData.ContentSizeVal;
- if (window->SizeContentsExplicit.y != 0.0f)
- window->SizeContentsExplicit.y += window->TitleBarHeight() + window->MenuBarHeight();
- }
+ if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasContentSize)
+ window->ContentSizeExplicit = g.NextWindowData.ContentSizeVal;
else if (first_begin_of_the_frame)
- {
- window->SizeContentsExplicit = ImVec2(0.0f, 0.0f);
- }
- if (g.NextWindowData.CollapsedCond)
+ window->ContentSizeExplicit = ImVec2(0.0f, 0.0f);
+ if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasCollapsed)
SetWindowCollapsed(window, g.NextWindowData.CollapsedVal, g.NextWindowData.CollapsedCond);
- if (g.NextWindowData.FocusCond)
+ if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasFocus)
FocusWindow(window);
if (window->Appearing)
SetWindowConditionAllowFlags(window, ImGuiCond_Appearing, false);
@@ -5129,7 +5385,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS
// Update contents size from last frame for auto-fitting (or use explicit size)
- window->SizeContents = CalcSizeContents(window);
+ window->ContentSize = CalcContentSize(window);
if (window->HiddenFramesCanSkipItems > 0)
window->HiddenFramesCanSkipItems--;
if (window->HiddenFramesCannotSkipItems > 0)
@@ -5140,7 +5396,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->HiddenFramesCannotSkipItems = 1;
// Hide popup/tooltip window when re-opening while we measure size (because we recycle the windows)
- // We reset Size/SizeContents for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size.
+ // We reset Size/ContentSize for reappearing popups/tooltips early in this function, so further code won't be tempted to use the old size.
if (window_just_activated_by_user && (flags & (ImGuiWindowFlags_Popup | ImGuiWindowFlags_Tooltip)) != 0)
{
window->HiddenFramesCannotSkipItems = 1;
@@ -5150,13 +5406,15 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->Size.x = window->SizeFull.x = 0.f;
if (!window_size_y_set_by_api)
window->Size.y = window->SizeFull.y = 0.f;
- window->SizeContents = ImVec2(0.f, 0.f);
+ window->ContentSize = ImVec2(0.f, 0.f);
}
}
+ // FIXME-VIEWPORT: In the docking/viewport branch, this is the point where we select the current viewport (which may affect the style)
SetCurrentWindow(window);
- // Lock border size and padding for the frame (so that altering them doesn't cause inconsistencies)
+ // LOCK BORDER SIZE AND PADDING FOR THE FRAME (so that altering them doesn't cause inconsistencies)
+
if (flags & ImGuiWindowFlags_ChildWindow)
window->WindowBorderSize = style.ChildBorderSize;
else
@@ -5191,24 +5449,37 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// SIZE
// Calculate auto-fit size, handle automatic resize
- const ImVec2 size_auto_fit = CalcSizeAutoFit(window, window->SizeContents);
- ImVec2 size_full_modified(FLT_MAX, FLT_MAX);
+ const ImVec2 size_auto_fit = CalcSizeAutoFit(window, window->ContentSize);
+ bool use_current_size_for_scrollbar_x = window_just_created;
+ bool use_current_size_for_scrollbar_y = window_just_created;
if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed)
{
// Using SetNextWindowSize() overrides ImGuiWindowFlags_AlwaysAutoResize, so it can be used on tooltips/popups, etc.
if (!window_size_x_set_by_api)
- window->SizeFull.x = size_full_modified.x = size_auto_fit.x;
+ {
+ window->SizeFull.x = size_auto_fit.x;
+ use_current_size_for_scrollbar_x = true;
+ }
if (!window_size_y_set_by_api)
- window->SizeFull.y = size_full_modified.y = size_auto_fit.y;
+ {
+ window->SizeFull.y = size_auto_fit.y;
+ use_current_size_for_scrollbar_y = true;
+ }
}
else if (window->AutoFitFramesX > 0 || window->AutoFitFramesY > 0)
{
// Auto-fit may only grow window during the first few frames
// We still process initial auto-fit on collapsed windows to get a window width, but otherwise don't honor ImGuiWindowFlags_AlwaysAutoResize when collapsed.
if (!window_size_x_set_by_api && window->AutoFitFramesX > 0)
- window->SizeFull.x = size_full_modified.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x;
+ {
+ window->SizeFull.x = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.x, size_auto_fit.x) : size_auto_fit.x;
+ use_current_size_for_scrollbar_x = true;
+ }
if (!window_size_y_set_by_api && window->AutoFitFramesY > 0)
- window->SizeFull.y = size_full_modified.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y;
+ {
+ window->SizeFull.y = window->AutoFitOnlyGrows ? ImMax(window->SizeFull.y, size_auto_fit.y) : size_auto_fit.y;
+ use_current_size_for_scrollbar_y = true;
+ }
if (!window->Collapsed)
MarkIniSettingsDirty(window);
}
@@ -5217,20 +5488,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->SizeFull = CalcSizeAfterConstraint(window, window->SizeFull);
window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull;
- // SCROLLBAR STATUS
-
- // Update scrollbar status (based on the Size that was effective during last frame or the auto-resized Size).
- if (!window->Collapsed)
- {
- // When reading the current size we need to read it after size constraints have been applied
- float size_x_for_scrollbars = size_full_modified.x != FLT_MAX ? window->SizeFull.x : window->SizeFullAtLastBegin.x;
- float size_y_for_scrollbars = size_full_modified.y != FLT_MAX ? window->SizeFull.y : window->SizeFullAtLastBegin.y;
- window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((window->SizeContents.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar));
- window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((window->SizeContents.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar));
- if (window->ScrollbarX && !window->ScrollbarY)
- window->ScrollbarY = (window->SizeContents.y > size_y_for_scrollbars - style.ScrollbarSize) && !(flags & ImGuiWindowFlags_NoScrollbar);
- window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);
- }
+ // Decoration size
+ const float decoration_up_height = window->TitleBarHeight() + window->MenuBarHeight();
// POSITION
@@ -5262,7 +5521,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
else if ((flags & ImGuiWindowFlags_Tooltip) != 0 && !window_pos_set_by_api && !window_is_child_tooltip)
window->Pos = FindBestWindowPosForPopup(window);
- // Clamp position so it stays visible
+ // Clamp position/size so window stays visible within its viewport or monitor
+
// Ignore zero-sized display explicitly to avoid losing positions if a window manager reports zero-sized window when initializing or minimizing.
ImRect viewport_rect(GetViewportRect());
if (!window_pos_set_by_api && !(flags & ImGuiWindowFlags_ChildWindow) && window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
@@ -5278,10 +5538,6 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Lock window rounding for the frame (so that altering them doesn't cause inconsistencies)
window->WindowRounding = (flags & ImGuiWindowFlags_ChildWindow) ? style.ChildRounding : ((flags & ImGuiWindowFlags_Popup) && !(flags & ImGuiWindowFlags_Modal)) ? style.PopupRounding : style.WindowRounding;
- // Apply scrolling
- window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window, true);
- window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
-
// Apply window focus (new and reactivated windows are moved to front)
bool want_focus = false;
if (window_just_activated_by_user && !(flags & ImGuiWindowFlags_NoFocusOnAppearing))
@@ -5296,27 +5552,96 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
int border_held = -1;
ImU32 resize_grip_col[4] = { 0 };
const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // 4
- const float grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f);
+ const float resize_grip_draw_size = (float)(int)ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f);
if (!window->Collapsed)
- UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0]);
+ if (UpdateManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0]))
+ use_current_size_for_scrollbar_x = use_current_size_for_scrollbar_y = true;
window->ResizeBorderHeld = (signed char)border_held;
+ // SCROLLBAR VISIBILITY
+
+ // Update scrollbar visibility (based on the Size that was effective during last frame or the auto-resized Size).
+ if (!window->Collapsed)
+ {
+ // When reading the current size we need to read it after size constraints have been applied.
+ // When we use InnerRect here we are intentionally reading last frame size, same for ScrollbarSizes values before we set them again.
+ ImVec2 avail_size_from_current_frame = ImVec2(window->SizeFull.x, window->SizeFull.y - decoration_up_height);
+ ImVec2 avail_size_from_last_frame = window->InnerRect.GetSize() + window->ScrollbarSizes;
+ ImVec2 needed_size_from_last_frame = window_just_created ? ImVec2(0, 0) : window->ContentSize + window->WindowPadding * 2.0f;
+ float size_x_for_scrollbars = use_current_size_for_scrollbar_x ? avail_size_from_current_frame.x : avail_size_from_last_frame.x;
+ float size_y_for_scrollbars = use_current_size_for_scrollbar_y ? avail_size_from_current_frame.y : avail_size_from_last_frame.y;
+ //bool scrollbar_y_from_last_frame = window->ScrollbarY; // FIXME: May want to use that in the ScrollbarX expression? How many pros vs cons?
+ window->ScrollbarY = (flags & ImGuiWindowFlags_AlwaysVerticalScrollbar) || ((needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar));
+ window->ScrollbarX = (flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar) || ((needed_size_from_last_frame.x > size_x_for_scrollbars - (window->ScrollbarY ? style.ScrollbarSize : 0.0f)) && !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar));
+ if (window->ScrollbarX && !window->ScrollbarY)
+ window->ScrollbarY = (needed_size_from_last_frame.y > size_y_for_scrollbars) && !(flags & ImGuiWindowFlags_NoScrollbar);
+ window->ScrollbarSizes = ImVec2(window->ScrollbarY ? style.ScrollbarSize : 0.0f, window->ScrollbarX ? style.ScrollbarSize : 0.0f);
+ }
+
+ // UPDATE RECTANGLES (1- THOSE NOT AFFECTED BY SCROLLING)
+ // Update various regions. Variables they depends on should be set above in this function.
+ // We set this up after processing the resize grip so that our rectangles doesn't lag by a frame.
+
+ // Outer rectangle
+ // Not affected by window border size. Used by:
+ // - FindHoveredWindow() (w/ extra padding when border resize is enabled)
+ // - Begin() initial clipping rect for drawing window background and borders.
+ // - Begin() clipping whole child
+ const ImRect host_rect = ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip) ? parent_window->ClipRect : viewport_rect;
+ const ImRect outer_rect = window->Rect();
+ const ImRect title_bar_rect = window->TitleBarRect();
+ window->OuterRectClipped = outer_rect;
+ window->OuterRectClipped.ClipWith(host_rect);
+
+ // Inner rectangle
+ // Not affected by window border size. Used by:
+ // - InnerClipRect
+ // - NavScrollToBringItemIntoView()
+ // - NavUpdatePageUpPageDown()
+ // - Scrollbar()
+ window->InnerRect.Min.x = window->Pos.x;
+ window->InnerRect.Min.y = window->Pos.y + decoration_up_height;
+ window->InnerRect.Max.x = window->Pos.x + window->Size.x - window->ScrollbarSizes.x;
+ window->InnerRect.Max.y = window->Pos.y + window->Size.y - window->ScrollbarSizes.y;
+
+ // Inner clipping rectangle.
+ // Will extend a little bit outside the normal work region.
+ // This is to allow e.g. Selectable or CollapsingHeader or some separators to cover that space.
+ // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result.
+ // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior.
+ // Affected by window/frame border size. Used by:
+ // - Begin() initial clip rect
+ float top_border_size = (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize);
+ window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerRect.Min.x + ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize));
+ window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerRect.Min.y + top_border_size);
+ window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(ImFloor(window->WindowPadding.y * 0.5f), window->WindowBorderSize));
+ window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y - window->WindowBorderSize);
+ window->InnerClipRect.ClipWithFull(host_rect);
+
// Default item width. Make it proportional to window size if window manually resizes
if (window->Size.x > 0.0f && !(flags & ImGuiWindowFlags_Tooltip) && !(flags & ImGuiWindowFlags_AlwaysAutoResize))
window->ItemWidthDefault = (float)(int)(window->Size.x * 0.65f);
else
window->ItemWidthDefault = (float)(int)(g.FontSize * 16.0f);
+ // SCROLLING
+
+ // Lock down maximum scrolling
+ // The value of ScrollMax are ahead from ScrollbarX/ScrollbarY which is intentionally using InnerRect from previous rect in order to accommodate
+ // for right/bottom aligned items without creating a scrollbar.
+ window->ScrollMax.x = ImMax(0.0f, window->ContentSize.x + window->WindowPadding.x * 2.0f - window->InnerRect.GetWidth());
+ window->ScrollMax.y = ImMax(0.0f, window->ContentSize.y + window->WindowPadding.y * 2.0f - window->InnerRect.GetHeight());
+
+ // Apply scrolling
+ window->Scroll = CalcNextScrollFromScrollTargetAndClamp(window, true);
+ window->ScrollTarget = ImVec2(FLT_MAX, FLT_MAX);
+
// DRAWING
// Setup draw list and outer clipping rectangle
window->DrawList->Clear();
- window->DrawList->Flags = (g.Style.AntiAliasedLines ? ImDrawListFlags_AntiAliasedLines : 0) | (g.Style.AntiAliasedFill ? ImDrawListFlags_AntiAliasedFill : 0);
window->DrawList->PushTextureID(g.Font->ContainerAtlas->TexID);
- if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip)
- PushClipRect(parent_window->ClipRect.Min, parent_window->ClipRect.Max, true);
- else
- PushClipRect(viewport_rect.Min, viewport_rect.Max, true);
+ PushClipRect(host_rect.Min, host_rect.Max, false);
// Draw modal window background (darkens what is behind them, all viewports)
const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetFrontMostPopupModal() && window->HiddenFramesCannotSkipItems <= 0;
@@ -5336,77 +5661,24 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha * 0.25f), g.Style.WindowRounding);
}
- // Draw window + handle manual resize
- // As we highlight the title bar when want_focus is set, multiple reappearing windows will have have their title bar highlighted on their reappearing frame.
- const float window_rounding = window->WindowRounding;
- const float window_border_size = window->WindowBorderSize;
+ // Since 1.71, child window can render their decoration (bg color, border, scrollbars, etc.) within their parent to save a draw call.
+ // When using overlapping child windows, this will break the assumption that child z-order is mapped to submission order.
+ // We disable this when the parent window has zero vertices, which is a common pattern leading to laying out multiple overlapping child.
+ // We also disabled this when we have dimming overlay behind this specific one child.
+ // FIXME: More code may rely on explicit sorting of overlapping child window and would need to disable this somehow. Please get in contact if you are affected.
+ bool render_decorations_in_parent = false;
+ if ((flags & ImGuiWindowFlags_ChildWindow) && !(flags & ImGuiWindowFlags_Popup) && !window_is_child_tooltip)
+ if (window->DrawList->CmdBuffer.back().ElemCount == 0 && parent_window->DrawList->VtxBuffer.Size > 0)
+ render_decorations_in_parent = true;
+ if (render_decorations_in_parent)
+ window->DrawList = parent_window->DrawList;
+
const ImGuiWindow* window_to_highlight = g.NavWindowingTarget ? g.NavWindowingTarget : g.NavWindow;
const bool title_bar_is_highlight = want_focus || (window_to_highlight && window->RootWindowForTitleBarHighlight == window_to_highlight->RootWindowForTitleBarHighlight);
- const ImRect title_bar_rect = window->TitleBarRect();
- if (window->Collapsed)
- {
- // Title bar only
- float backup_border_size = style.FrameBorderSize;
- g.Style.FrameBorderSize = window->WindowBorderSize;
- ImU32 title_bar_col = GetColorU32((title_bar_is_highlight && !g.NavDisableHighlight) ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBgCollapsed);
- RenderFrame(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, true, window_rounding);
- g.Style.FrameBorderSize = backup_border_size;
- }
- else
- {
- // Window background
- if (!(flags & ImGuiWindowFlags_NoBackground))
- {
- ImU32 bg_col = GetColorU32(GetWindowBgColorIdxFromFlags(flags));
- float alpha = 1.0f;
- if (g.NextWindowData.BgAlphaCond != 0)
- alpha = g.NextWindowData.BgAlphaVal;
- if (alpha != 1.0f)
- bg_col = (bg_col & ~IM_COL32_A_MASK) | (IM_F32_TO_INT8_SAT(alpha) << IM_COL32_A_SHIFT);
- window->DrawList->AddRectFilled(window->Pos + ImVec2(0, window->TitleBarHeight()), window->Pos + window->Size, bg_col, window_rounding, (flags & ImGuiWindowFlags_NoTitleBar) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Bot);
- }
- g.NextWindowData.BgAlphaCond = 0;
-
- // Title bar
- if (!(flags & ImGuiWindowFlags_NoTitleBar))
- {
- ImU32 title_bar_col = GetColorU32(title_bar_is_highlight ? ImGuiCol_TitleBgActive : ImGuiCol_TitleBg);
- window->DrawList->AddRectFilled(title_bar_rect.Min, title_bar_rect.Max, title_bar_col, window_rounding, ImDrawCornerFlags_Top);
- }
+ RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, resize_grip_count, resize_grip_col, resize_grip_draw_size);
- // Menu bar
- if (flags & ImGuiWindowFlags_MenuBar)
- {
- ImRect menu_bar_rect = window->MenuBarRect();
- menu_bar_rect.ClipWith(window->Rect()); // Soft clipping, in particular child window don't have minimum size covering the menu bar so this is useful for them.
- window->DrawList->AddRectFilled(menu_bar_rect.Min+ImVec2(window_border_size,0), menu_bar_rect.Max-ImVec2(window_border_size,0), GetColorU32(ImGuiCol_MenuBarBg), (flags & ImGuiWindowFlags_NoTitleBar) ? window_rounding : 0.0f, ImDrawCornerFlags_Top);
- if (style.FrameBorderSize > 0.0f && menu_bar_rect.Max.y < window->Pos.y + window->Size.y)
- window->DrawList->AddLine(menu_bar_rect.GetBL(), menu_bar_rect.GetBR(), GetColorU32(ImGuiCol_Border), style.FrameBorderSize);
- }
-
- // Scrollbars
- if (window->ScrollbarX)
- Scrollbar(ImGuiAxis_X);
- if (window->ScrollbarY)
- Scrollbar(ImGuiAxis_Y);
-
- // Render resize grips (after their input handling so we don't have a frame of latency)
- if (!(flags & ImGuiWindowFlags_NoResize))
- {
- for (int resize_grip_n = 0; resize_grip_n < resize_grip_count; resize_grip_n++)
- {
- const ImGuiResizeGripDef& grip = resize_grip_def[resize_grip_n];
- const ImVec2 corner = ImLerp(window->Pos, window->Pos + window->Size, grip.CornerPosN);
- window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(window_border_size, grip_draw_size) : ImVec2(grip_draw_size, window_border_size)));
- window->DrawList->PathLineTo(corner + grip.InnerDir * ((resize_grip_n & 1) ? ImVec2(grip_draw_size, window_border_size) : ImVec2(window_border_size, grip_draw_size)));
- window->DrawList->PathArcToFast(ImVec2(corner.x + grip.InnerDir.x * (window_rounding + window_border_size), corner.y + grip.InnerDir.y * (window_rounding + window_border_size)), window_rounding, grip.AngleMin12, grip.AngleMax12);
- window->DrawList->PathFillConvex(resize_grip_col[resize_grip_n]);
- }
- }
-
- // Borders
- RenderOuterBorders(window);
- }
+ if (render_decorations_in_parent)
+ window->DrawList = &window->DrawListInst;
// Draw navigation selection/windowing rectangle border
if (g.NavWindowingTargetAnim == window)
@@ -5422,48 +5694,44 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->DrawList->AddRect(bb.Min, bb.Max, GetColorU32(ImGuiCol_NavWindowingHighlight, g.NavWindowingHighlightAlpha), rounding, ~0, 3.0f);
}
- // Store a backup of SizeFull which we will use next frame to decide if we need scrollbars.
- window->SizeFullAtLastBegin = window->SizeFull;
-
- // Update various regions. Variables they depends on are set above in this function.
- // FIXME: window->ContentsRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it.
- // NB: WindowBorderSize is included in WindowPadding _and_ ScrollbarSizes so we need to cancel one out.
+ // UPDATE RECTANGLES (2- THOSE AFFECTED BY SCROLLING)
+
+ // Work rectangle.
+ // Affected by window padding and border size. Used by:
+ // - Columns() for right-most edge
+ // - TreeNode(), CollapsingHeader() for right-most edge
+ // - BeginTabBar() for right-most edge
+ const bool allow_scrollbar_x = !(flags & ImGuiWindowFlags_NoScrollbar) && (flags & ImGuiWindowFlags_HorizontalScrollbar);
+ const bool allow_scrollbar_y = !(flags & ImGuiWindowFlags_NoScrollbar);
+ const float work_rect_size_x = (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : ImMax(allow_scrollbar_x ? window->ContentSize.x : 0.0f, window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x));
+ const float work_rect_size_y = (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : ImMax(allow_scrollbar_y ? window->ContentSize.y : 0.0f, window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y));
+ window->WorkRect.Min.x = ImFloor(window->InnerRect.Min.x - window->Scroll.x + ImMax(window->WindowPadding.x, window->WindowBorderSize));
+ window->WorkRect.Min.y = ImFloor(window->InnerRect.Min.y - window->Scroll.y + ImMax(window->WindowPadding.y, window->WindowBorderSize));
+ window->WorkRect.Max.x = window->WorkRect.Min.x + work_rect_size_x;
+ window->WorkRect.Max.y = window->WorkRect.Min.y + work_rect_size_y;
+
+ // [LEGACY] Contents Region
+ // FIXME-OBSOLETE: window->ContentsRegionRect.Max is currently very misleading / partly faulty, but some BeginChild() patterns relies on it.
+ // Used by:
+ // - Mouse wheel scrolling + many other things
window->ContentsRegionRect.Min.x = window->Pos.x - window->Scroll.x + window->WindowPadding.x;
- window->ContentsRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + window->TitleBarHeight() + window->MenuBarHeight();
- window->ContentsRegionRect.Max.x = window->Pos.x - window->Scroll.x - window->WindowPadding.x + (window->SizeContentsExplicit.x != 0.0f ? window->SizeContentsExplicit.x : (window->Size.x - window->ScrollbarSizes.x + ImMin(window->ScrollbarSizes.x, window->WindowBorderSize)));
- window->ContentsRegionRect.Max.y = window->Pos.y - window->Scroll.y - window->WindowPadding.y + (window->SizeContentsExplicit.y != 0.0f ? window->SizeContentsExplicit.y : (window->Size.y - window->ScrollbarSizes.y + ImMin(window->ScrollbarSizes.y, window->WindowBorderSize)));
-
- // Save clipped aabb so we can access it in constant-time in FindHoveredWindow()
- window->OuterRectClipped = window->Rect();
- window->OuterRectClipped.ClipWith(window->ClipRect);
-
- // Inner rectangle
- // We set this up after processing the resize grip so that our clip rectangle doesn't lag by a frame
- // Note that if our window is collapsed we will end up with an inverted (~null) clipping rectangle which is the correct behavior.
- window->InnerMainRect.Min.x = title_bar_rect.Min.x + window->WindowBorderSize;
- window->InnerMainRect.Min.y = title_bar_rect.Max.y + window->MenuBarHeight() + (((flags & ImGuiWindowFlags_MenuBar) || !(flags & ImGuiWindowFlags_NoTitleBar)) ? style.FrameBorderSize : window->WindowBorderSize);
- window->InnerMainRect.Max.x = window->Pos.x + window->Size.x - ImMax(window->ScrollbarSizes.x, window->WindowBorderSize);
- window->InnerMainRect.Max.y = window->Pos.y + window->Size.y - ImMax(window->ScrollbarSizes.y, window->WindowBorderSize);
+ window->ContentsRegionRect.Min.y = window->Pos.y - window->Scroll.y + window->WindowPadding.y + decoration_up_height;
+ window->ContentsRegionRect.Max.x = window->ContentsRegionRect.Min.x + (window->ContentSizeExplicit.x != 0.0f ? window->ContentSizeExplicit.x : (window->Size.x - window->WindowPadding.x * 2.0f - window->ScrollbarSizes.x));
+ window->ContentsRegionRect.Max.y = window->ContentsRegionRect.Min.y + (window->ContentSizeExplicit.y != 0.0f ? window->ContentSizeExplicit.y : (window->Size.y - window->WindowPadding.y * 2.0f - decoration_up_height - window->ScrollbarSizes.y));
- // Inner clipping rectangle
- // Force round operator last to ensure that e.g. (int)(max.x-min.x) in user's render code produce correct result.
- window->InnerClipRect.Min.x = ImFloor(0.5f + window->InnerMainRect.Min.x + ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize)));
- window->InnerClipRect.Min.y = ImFloor(0.5f + window->InnerMainRect.Min.y);
- window->InnerClipRect.Max.x = ImFloor(0.5f + window->InnerMainRect.Max.x - ImMax(0.0f, ImFloor(window->WindowPadding.x * 0.5f - window->WindowBorderSize)));
- window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerMainRect.Max.y);
// Setup drawing context
// (NB: That term "drawing context / DC" lost its meaning a long time ago. Initially was meant to hold transient data only. Nowadays difference between window-> and window->DC-> is dubious.)
window->DC.Indent.x = 0.0f + window->WindowPadding.x - window->Scroll.x;
window->DC.GroupOffset.x = 0.0f;
window->DC.ColumnsOffset.x = 0.0f;
- window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.Indent.x + window->DC.ColumnsOffset.x, window->TitleBarHeight() + window->MenuBarHeight() + window->WindowPadding.y - window->Scroll.y);
+ window->DC.CursorStartPos = window->Pos + ImVec2(window->DC.Indent.x + window->DC.ColumnsOffset.x, decoration_up_height + window->WindowPadding.y - window->Scroll.y);
window->DC.CursorPos = window->DC.CursorStartPos;
window->DC.CursorPosPrevLine = window->DC.CursorPos;
window->DC.CursorMaxPos = window->DC.CursorStartPos;
- window->DC.CurrentLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f);
- window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
+ window->DC.CurrLineSize = window->DC.PrevLineSize = ImVec2(0.0f, 0.0f);
+ window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset = 0.0f;
window->DC.NavHideHighlightOneFrame = false;
- window->DC.NavHasScroll = (GetWindowScrollMaxY(window) > 0.0f);
+ window->DC.NavHasScroll = (window->ScrollMax.y > 0.0f);
window->DC.NavLayerActiveMask = window->DC.NavLayerActiveMaskNext;
window->DC.NavLayerActiveMaskNext = 0x00;
window->DC.MenuBarAppending = false;
@@ -5504,52 +5772,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// Title bar
if (!(flags & ImGuiWindowFlags_NoTitleBar))
- {
- // Close & collapse button are on layer 1 (same as menus) and don't default focus
- const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags;
- window->DC.ItemFlags |= ImGuiItemFlags_NoNavDefaultFocus;
- window->DC.NavLayerCurrent = ImGuiNavLayer_Menu;
- window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Menu);
-
- // Collapse button
- if (!(flags & ImGuiWindowFlags_NoCollapse))
- if (CollapseButton(window->GetID("#COLLAPSE"), window->Pos))
- window->WantCollapseToggle = true; // Defer collapsing to next frame as we are too far in the Begin() function
-
- // Close button
- if (p_open != NULL)
- {
- const float rad = g.FontSize * 0.5f;
- if (CloseButton(window->GetID("#CLOSE"), ImVec2(window->Pos.x + window->Size.x - style.FramePadding.x - rad, window->Pos.y + style.FramePadding.y + rad), rad + 1))
- *p_open = false;
- }
-
- window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
- window->DC.NavLayerCurrentMask = (1 << ImGuiNavLayer_Main);
- window->DC.ItemFlags = item_flags_backup;
-
- // Title bar text (with: horizontal alignment, avoiding collapse/close button, optional "unsaved document" marker)
- // FIXME: Refactor text alignment facilities along with RenderText helpers, this is too much code..
- const char* UNSAVED_DOCUMENT_MARKER = "*";
- float marker_size_x = (flags & ImGuiWindowFlags_UnsavedDocument) ? CalcTextSize(UNSAVED_DOCUMENT_MARKER, NULL, false).x : 0.0f;
- ImVec2 text_size = CalcTextSize(name, NULL, true) + ImVec2(marker_size_x, 0.0f);
- ImRect text_r = title_bar_rect;
- float pad_left = (flags & ImGuiWindowFlags_NoCollapse) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x);
- float pad_right = (p_open == NULL) ? style.FramePadding.x : (style.FramePadding.x + g.FontSize + style.ItemInnerSpacing.x);
- if (style.WindowTitleAlign.x > 0.0f)
- pad_right = ImLerp(pad_right, pad_left, style.WindowTitleAlign.x);
- text_r.Min.x += pad_left;
- text_r.Max.x -= pad_right;
- ImRect clip_rect = text_r;
- clip_rect.Max.x = window->Pos.x + window->Size.x - (p_open ? title_bar_rect.GetHeight() - 3 : style.FramePadding.x); // Match the size of CloseButton()
- RenderTextClipped(text_r.Min, text_r.Max, name, NULL, &text_size, style.WindowTitleAlign, &clip_rect);
- if (flags & ImGuiWindowFlags_UnsavedDocument)
- {
- ImVec2 marker_pos = ImVec2(ImMax(text_r.Min.x, text_r.Min.x + (text_r.GetWidth() - text_size.x) * style.WindowTitleAlign.x) + text_size.x, text_r.Min.y) + ImVec2(2 - marker_size_x, 0.0f);
- ImVec2 off = ImVec2(0.0f, (float)(int)(-g.FontSize * 0.25f));
- RenderTextClipped(marker_pos + off, text_r.Max + off, UNSAVED_DOCUMENT_MARKER, NULL, NULL, ImVec2(0, style.WindowTitleAlign.y), &clip_rect);
- }
- }
+ RenderWindowTitleBarContents(window, title_bar_rect, name, p_open);
// Pressing CTRL+C while holding on a window copy its content to the clipboard
// This works but 1. doesn't handle multiple Begin/End pairs, 2. recursing into another Begin/End pair - so we need to work that out and add better logging scope.
@@ -5583,7 +5806,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->WriteAccessed = false;
window->BeginCount++;
- g.NextWindowData.Clear();
+ g.NextWindowData.ClearFlags();
if (flags & ImGuiWindowFlags_ChildWindow)
{
@@ -5771,20 +5994,24 @@ void ImGui::FocusTopMostWindowUnderOne(ImGuiWindow* under_this_window, ImGuiWind
void ImGui::SetNextItemWidth(float item_width)
{
- ImGuiWindow* window = GetCurrentWindow();
- window->DC.NextItemWidth = item_width;
+ ImGuiContext& g = *GImGui;
+ g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasWidth;
+ g.NextItemData.Width = item_width;
}
void ImGui::PushItemWidth(float item_width)
{
- ImGuiWindow* window = GetCurrentWindow();
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
window->DC.ItemWidth = (item_width == 0.0f ? window->ItemWidthDefault : item_width);
window->DC.ItemWidthStack.push_back(window->DC.ItemWidth);
+ g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;
}
void ImGui::PushMultiItemsWidths(int components, float w_full)
{
- ImGuiWindow* window = GetCurrentWindow();
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
const ImGuiStyle& style = GImGui->Style;
const float w_item_one = ImMax(1.0f, (float)(int)((w_full - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
const float w_item_last = ImMax(1.0f, (float)(int)(w_full - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
@@ -5792,6 +6019,7 @@ void ImGui::PushMultiItemsWidths(int components, float w_full)
for (int i = 0; i < components-1; i++)
window->DC.ItemWidthStack.push_back(w_item_one);
window->DC.ItemWidth = window->DC.ItemWidthStack.back();
+ g.NextItemData.Flags &= ~ImGuiNextItemDataFlags_HasWidth;
}
void ImGui::PopItemWidth()
@@ -5801,52 +6029,37 @@ void ImGui::PopItemWidth()
window->DC.ItemWidth = window->DC.ItemWidthStack.empty() ? window->ItemWidthDefault : window->DC.ItemWidthStack.back();
}
-// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth(),
-// Then consume the
-float ImGui::GetNextItemWidth()
+// Calculate default item width given value passed to PushItemWidth() or SetNextItemWidth().
+// The SetNextItemWidth() data is generally cleared/consumed by ItemAdd() or NextItemData.ClearFlags()
+float ImGui::CalcItemWidth()
{
- ImGuiWindow* window = GImGui->CurrentWindow;
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
float w;
- if (window->DC.NextItemWidth != FLT_MAX)
- {
- w = window->DC.NextItemWidth;
- window->DC.NextItemWidth = FLT_MAX;
- }
+ if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasWidth)
+ w = g.NextItemData.Width;
else
- {
w = window->DC.ItemWidth;
- }
if (w < 0.0f)
{
- float region_max_x = GetWorkRectMax().x;
+ float region_max_x = GetContentRegionMaxAbs().x;
w = ImMax(1.0f, region_max_x - window->DC.CursorPos.x + w);
}
w = (float)(int)w;
return w;
}
-// Calculate item width *without* popping/consuming NextItemWidth if it was set.
-// (rarely used, which is why we avoid calling this from GetNextItemWidth() and instead do a backup/restore here)
-float ImGui::CalcItemWidth()
-{
- ImGuiWindow* window = GImGui->CurrentWindow;
- float backup_next_item_width = window->DC.NextItemWidth;
- float w = GetNextItemWidth();
- window->DC.NextItemWidth = backup_next_item_width;
- return w;
-}
-
-// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == GetNextItemWidth().
+// [Internal] Calculate full item size given user provided 'size' parameter and default width/height. Default width is often == CalcItemWidth().
// Those two functions CalcItemWidth vs CalcItemSize are awkwardly named because they are not fully symmetrical.
// Note that only CalcItemWidth() is publicly exposed.
-// The 4.0f here may be changed to match GetNextItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable)
+// The 4.0f here may be changed to match CalcItemWidth() and/or BeginChild() (right now we have a mismatch which is harmless but undesirable)
ImVec2 ImGui::CalcItemSize(ImVec2 size, float default_w, float default_h)
{
ImGuiWindow* window = GImGui->CurrentWindow;
ImVec2 region_max;
if (size.x < 0.0f || size.y < 0.0f)
- region_max = GetWorkRectMax();
+ region_max = GetContentRegionMaxAbs();
if (size.x == 0.0f)
size.x = default_w;
@@ -6227,16 +6440,12 @@ ImVec2 ImGui::GetWindowPos()
void ImGui::SetWindowScrollX(ImGuiWindow* window, float new_scroll_x)
{
- window->DC.CursorMaxPos.x += window->Scroll.x; // SizeContents is generally computed based on CursorMaxPos which is affected by scroll position, so we need to apply our change to it.
window->Scroll.x = new_scroll_x;
- window->DC.CursorMaxPos.x -= window->Scroll.x;
}
void ImGui::SetWindowScrollY(ImGuiWindow* window, float new_scroll_y)
{
- window->DC.CursorMaxPos.y += window->Scroll.y; // SizeContents is generally computed based on CursorMaxPos which is affected by scroll position, so we need to apply our change to it.
window->Scroll.y = new_scroll_y;
- window->DC.CursorMaxPos.y -= window->Scroll.y;
}
void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond)
@@ -6252,8 +6461,10 @@ void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond)
// Set
const ImVec2 old_pos = window->Pos;
window->Pos = ImFloor(pos);
- window->DC.CursorPos += (window->Pos - old_pos); // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor
- window->DC.CursorMaxPos += (window->Pos - old_pos); // And more importantly we need to adjust this so size calculation doesn't get affected.
+ ImVec2 offset = window->Pos - old_pos;
+ window->DC.CursorPos += offset; // As we happen to move the window while it is being appended to (which is a bad idea - will smear) let's at least offset the cursor
+ window->DC.CursorMaxPos += offset; // And more importantly we need to offset CursorMaxPos/CursorStartPos this so ContentSize calculation doesn't get affected.
+ window->DC.CursorStartPos += offset;
}
void ImGui::SetWindowPos(const ImVec2& pos, ImGuiCond cond)
@@ -6373,6 +6584,7 @@ void ImGui::SetNextWindowPos(const ImVec2& pos, ImGuiCond cond, const ImVec2& pi
{
ImGuiContext& g = *GImGui;
IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
+ g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasPos;
g.NextWindowData.PosVal = pos;
g.NextWindowData.PosPivotVal = pivot;
g.NextWindowData.PosCond = cond ? cond : ImGuiCond_Always;
@@ -6382,6 +6594,7 @@ void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
+ g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSize;
g.NextWindowData.SizeVal = size;
g.NextWindowData.SizeCond = cond ? cond : ImGuiCond_Always;
}
@@ -6389,23 +6602,26 @@ void ImGui::SetNextWindowSize(const ImVec2& size, ImGuiCond cond)
void ImGui::SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback, void* custom_callback_user_data)
{
ImGuiContext& g = *GImGui;
- g.NextWindowData.SizeConstraintCond = ImGuiCond_Always;
+ g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSizeConstraint;
g.NextWindowData.SizeConstraintRect = ImRect(size_min, size_max);
g.NextWindowData.SizeCallback = custom_callback;
g.NextWindowData.SizeCallbackUserData = custom_callback_user_data;
}
+// Content size = inner scrollable rectangle, padded with WindowPadding.
+// SetNextWindowContentSize(ImVec2(100,100) + ImGuiWindowFlags_AlwaysAutoResize will always allow submitting a 100x100 item.
void ImGui::SetNextWindowContentSize(const ImVec2& size)
{
ImGuiContext& g = *GImGui;
- g.NextWindowData.ContentSizeVal = size; // In Begin() we will add the size of window decorations (title bar, menu etc.) to that to form a SizeContents value.
- g.NextWindowData.ContentSizeCond = ImGuiCond_Always;
+ g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasContentSize;
+ g.NextWindowData.ContentSizeVal = size;
}
void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(cond == 0 || ImIsPowerOfTwo(cond)); // Make sure the user doesn't attempt to combine multiple condition flags.
+ g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasCollapsed;
g.NextWindowData.CollapsedVal = collapsed;
g.NextWindowData.CollapsedCond = cond ? cond : ImGuiCond_Always;
}
@@ -6413,14 +6629,14 @@ void ImGui::SetNextWindowCollapsed(bool collapsed, ImGuiCond cond)
void ImGui::SetNextWindowFocus()
{
ImGuiContext& g = *GImGui;
- g.NextWindowData.FocusCond = ImGuiCond_Always; // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op)
+ g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasFocus;
}
void ImGui::SetNextWindowBgAlpha(float alpha)
{
ImGuiContext& g = *GImGui;
+ g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasBgAlpha;
g.NextWindowData.BgAlphaVal = alpha;
- g.NextWindowData.BgAlphaCond = ImGuiCond_Always; // Using a Cond member for consistency (may transition all of them to single flag set for fast Clear() op)
}
// FIXME: This is in window space (not screen space!). We should try to obsolete all those functions.
@@ -6434,7 +6650,7 @@ ImVec2 ImGui::GetContentRegionMax()
}
// [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features.
-ImVec2 ImGui::GetWorkRectMax()
+ImVec2 ImGui::GetContentRegionMaxAbs()
{
ImGuiWindow* window = GImGui->CurrentWindow;
ImVec2 mx = window->ContentsRegionRect.Max;
@@ -6446,7 +6662,7 @@ ImVec2 ImGui::GetWorkRectMax()
ImVec2 ImGui::GetContentRegionAvail()
{
ImGuiWindow* window = GImGui->CurrentWindow;
- return GetWorkRectMax() - window->DC.CursorPos;
+ return GetContentRegionMaxAbs() - window->DC.CursorPos;
}
// In window space (not screen space!)
@@ -6583,22 +6799,26 @@ void ImGui::SetCursorScreenPos(const ImVec2& pos)
float ImGui::GetScrollX()
{
- return GImGui->CurrentWindow->Scroll.x;
+ ImGuiWindow* window = GImGui->CurrentWindow;
+ return window->Scroll.x;
}
float ImGui::GetScrollY()
{
- return GImGui->CurrentWindow->Scroll.y;
+ ImGuiWindow* window = GImGui->CurrentWindow;
+ return window->Scroll.y;
}
float ImGui::GetScrollMaxX()
{
- return GetWindowScrollMaxX(GImGui->CurrentWindow);
+ ImGuiWindow* window = GImGui->CurrentWindow;
+ return window->ScrollMax.x;
}
float ImGui::GetScrollMaxY()
{
- return GetWindowScrollMaxY(GImGui->CurrentWindow);
+ ImGuiWindow* window = GImGui->CurrentWindow;
+ return window->ScrollMax.y;
}
void ImGui::SetScrollX(float scroll_x)
@@ -6611,7 +6831,7 @@ void ImGui::SetScrollX(float scroll_x)
void ImGui::SetScrollY(float scroll_y)
{
ImGuiWindow* window = GetCurrentWindow();
- window->ScrollTarget.y = scroll_y + window->TitleBarHeight() + window->MenuBarHeight(); // title bar height canceled out when using ScrollTargetRelY
+ window->ScrollTarget.y = scroll_y;
window->ScrollTargetCenterRatio.y = 0.0f;
}
@@ -6698,9 +6918,8 @@ void ImGui::PushID(const void* ptr_id)
void ImGui::PushID(int int_id)
{
- const void* ptr_id = (void*)(intptr_t)int_id;
ImGuiWindow* window = GImGui->CurrentWindow;
- window->IDStack.push_back(window->GetIDNoKeepAlive(ptr_id));
+ window->IDStack.push_back(window->GetIDNoKeepAlive(int_id));
}
// Push a given id value ignoring the ID stack as a seed.
@@ -6758,16 +6977,16 @@ void ImGui::BeginGroup()
group_data.BackupCursorMaxPos = window->DC.CursorMaxPos;
group_data.BackupIndent = window->DC.Indent;
group_data.BackupGroupOffset = window->DC.GroupOffset;
- group_data.BackupCurrentLineSize = window->DC.CurrentLineSize;
- group_data.BackupCurrentLineTextBaseOffset = window->DC.CurrentLineTextBaseOffset;
+ group_data.BackupCurrLineSize = window->DC.CurrLineSize;
+ group_data.BackupCurrLineTextBaseOffset = window->DC.CurrLineTextBaseOffset;
group_data.BackupActiveIdIsAlive = g.ActiveIdIsAlive;
group_data.BackupActiveIdPreviousFrameIsAlive = g.ActiveIdPreviousFrameIsAlive;
- group_data.AdvanceCursor = true;
+ group_data.EmitItem = true;
window->DC.GroupOffset.x = window->DC.CursorPos.x - window->Pos.x - window->DC.ColumnsOffset.x;
window->DC.Indent = window->DC.GroupOffset;
window->DC.CursorMaxPos = window->DC.CursorPos;
- window->DC.CurrentLineSize = ImVec2(0.0f, 0.0f);
+ window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
if (g.LogEnabled)
g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return
}
@@ -6780,36 +6999,49 @@ void ImGui::EndGroup()
ImGuiGroupData& group_data = window->DC.GroupStack.back();
- ImRect group_bb(group_data.BackupCursorPos, window->DC.CursorMaxPos);
- group_bb.Max = ImMax(group_bb.Min, group_bb.Max);
+ ImRect group_bb(group_data.BackupCursorPos, ImMax(window->DC.CursorMaxPos, group_data.BackupCursorPos));
window->DC.CursorPos = group_data.BackupCursorPos;
window->DC.CursorMaxPos = ImMax(group_data.BackupCursorMaxPos, window->DC.CursorMaxPos);
window->DC.Indent = group_data.BackupIndent;
window->DC.GroupOffset = group_data.BackupGroupOffset;
- window->DC.CurrentLineSize = group_data.BackupCurrentLineSize;
- window->DC.CurrentLineTextBaseOffset = group_data.BackupCurrentLineTextBaseOffset;
+ window->DC.CurrLineSize = group_data.BackupCurrLineSize;
+ window->DC.CurrLineTextBaseOffset = group_data.BackupCurrLineTextBaseOffset;
if (g.LogEnabled)
g.LogLinePosY = -FLT_MAX; // To enforce Log carriage return
- if (group_data.AdvanceCursor)
+ if (!group_data.EmitItem)
{
- window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrentLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.
- ItemSize(group_bb.GetSize(), 0.0f);
- ItemAdd(group_bb, 0);
+ window->DC.GroupStack.pop_back();
+ return;
}
+ window->DC.CurrLineTextBaseOffset = ImMax(window->DC.PrevLineTextBaseOffset, group_data.BackupCurrLineTextBaseOffset); // FIXME: Incorrect, we should grab the base offset from the *first line* of the group but it is hard to obtain now.
+ ItemSize(group_bb.GetSize(), 0.0f);
+ ItemAdd(group_bb, 0);
+
// If the current ActiveId was declared within the boundary of our group, we copy it to LastItemId so IsItemActive(), IsItemDeactivated() etc. will be functional on the entire group.
// It would be be neater if we replaced window.DC.LastItemId by e.g. 'bool LastItemIsActive', but would put a little more burden on individual widgets.
- // (and if you grep for LastItemId you'll notice it is only used in that context.
- if ((group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId) // && g.ActiveIdWindow->RootWindow == window->RootWindow)
+ // Also if you grep for LastItemId you'll notice it is only used in that context.
+ // (The tests not symmetrical because ActiveIdIsAlive is an ID itself, in order to be able to handle ActiveId being overwritten during the frame.)
+ const bool group_contains_curr_active_id = (group_data.BackupActiveIdIsAlive != g.ActiveId) && (g.ActiveIdIsAlive == g.ActiveId) && g.ActiveId;
+ const bool group_contains_prev_active_id = !group_data.BackupActiveIdPreviousFrameIsAlive && g.ActiveIdPreviousFrameIsAlive;
+ if (group_contains_curr_active_id)
window->DC.LastItemId = g.ActiveId;
- else if (!group_data.BackupActiveIdPreviousFrameIsAlive && g.ActiveIdPreviousFrameIsAlive) // && g.ActiveIdPreviousFrameWindow->RootWindow == window->RootWindow)
+ else if (group_contains_prev_active_id)
window->DC.LastItemId = g.ActiveIdPreviousFrame;
window->DC.LastItemRect = group_bb;
- window->DC.GroupStack.pop_back();
+ // Forward Edited flag
+ if (group_contains_curr_active_id && g.ActiveIdHasBeenEditedThisFrame)
+ window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Edited;
+
+ // Forward Deactivated flag
+ window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDeactivated;
+ if (group_contains_prev_active_id && g.ActiveId != g.ActiveIdPreviousFrame)
+ window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_Deactivated;
+ window->DC.GroupStack.pop_back();
//window->DrawList->AddRect(group_bb.Min, group_bb.Max, IM_COL32(255,0,255,255)); // [Debug]
}
@@ -6837,8 +7069,8 @@ void ImGui::SameLine(float offset_from_start_x, float spacing_w)
window->DC.CursorPos.x = window->DC.CursorPosPrevLine.x + spacing_w;
window->DC.CursorPos.y = window->DC.CursorPosPrevLine.y;
}
- window->DC.CurrentLineSize = window->DC.PrevLineSize;
- window->DC.CurrentLineTextBaseOffset = window->DC.PrevLineTextBaseOffset;
+ window->DC.CurrLineSize = window->DC.PrevLineSize;
+ window->DC.CurrLineTextBaseOffset = window->DC.PrevLineTextBaseOffset;
}
void ImGui::Indent(float indent_w)
@@ -7115,7 +7347,7 @@ bool ImGui::BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags)
ImGuiContext& g = *GImGui;
if (!IsPopupOpen(id))
{
- g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values
+ g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
return false;
}
@@ -7137,7 +7369,7 @@ bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
ImGuiContext& g = *GImGui;
if (g.OpenPopupStack.Size <= g.BeginPopupStack.Size) // Early out for performance
{
- g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values
+ g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
return false;
}
flags |= ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoSavedSettings;
@@ -7145,7 +7377,7 @@ bool ImGui::BeginPopup(const char* str_id, ImGuiWindowFlags flags)
}
// If 'p_open' is specified for a modal popup window, the popup will have a regular close button which will close the popup.
-// Note that popup visibility status is owned by imgui (and manipulated with e.g. OpenPopup) so the actual value of *p_open is meaningless here.
+// Note that popup visibility status is owned by Dear ImGui (and manipulated with e.g. OpenPopup) so the actual value of *p_open is meaningless here.
bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags flags)
{
ImGuiContext& g = *GImGui;
@@ -7153,13 +7385,13 @@ bool ImGui::BeginPopupModal(const char* name, bool* p_open, ImGuiWindowFlags fla
const ImGuiID id = window->GetID(name);
if (!IsPopupOpen(id))
{
- g.NextWindowData.Clear(); // We behave like Begin() and need to consume those values
+ g.NextWindowData.ClearFlags(); // We behave like Begin() and need to consume those values
return false;
}
// Center modal windows by default
// FIXME: Should test for (PosCond & window->SetWindowPosAllowFlags) with the upcoming window.
- if (g.NextWindowData.PosCond == 0)
+ if ((g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasPos) == 0)
SetNextWindowPos(g.IO.DisplaySize * 0.5f, ImGuiCond_Appearing, ImVec2(0.5f, 0.5f));
flags |= ImGuiWindowFlags_Popup | ImGuiWindowFlags_Modal | ImGuiWindowFlags_NoCollapse | ImGuiWindowFlags_NoSavedSettings;
@@ -7192,6 +7424,8 @@ void ImGui::EndPopup()
bool ImGui::BeginPopupContextItem(const char* str_id, int mouse_button)
{
ImGuiWindow* window = GImGui->CurrentWindow;
+ if (window->SkipItems)
+ return false;
ImGuiID id = str_id ? window->GetID(str_id) : window->DC.LastItemId; // If user hasn't passed an ID, we can use the LastItemID. Using LastItemID as a Popup ID won't conflict!
IM_ASSERT(id != 0); // You cannot pass a NULL str_id if the last item has no identifier (e.g. a Text() item)
if (IsMouseReleased(mouse_button) && IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup))
@@ -7601,7 +7835,7 @@ void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags mov
ImGuiDir clip_dir = g.NavMoveDir;
if (g.NavMoveDir == ImGuiDir_Left && (move_flags & (ImGuiNavMoveFlags_WrapX | ImGuiNavMoveFlags_LoopX)))
{
- bb_rel.Min.x = bb_rel.Max.x = ImMax(window->SizeFull.x, window->SizeContents.x) - window->Scroll.x;
+ bb_rel.Min.x = bb_rel.Max.x = ImMax(window->SizeFull.x, window->ContentSize.x + window->WindowPadding.x * 2.0f) - window->Scroll.x;
if (move_flags & ImGuiNavMoveFlags_WrapX) { bb_rel.TranslateY(-bb_rel.GetHeight()); clip_dir = ImGuiDir_Up; }
NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
}
@@ -7613,7 +7847,7 @@ void ImGui::NavMoveRequestTryWrapping(ImGuiWindow* window, ImGuiNavMoveFlags mov
}
if (g.NavMoveDir == ImGuiDir_Up && (move_flags & (ImGuiNavMoveFlags_WrapY | ImGuiNavMoveFlags_LoopY)))
{
- bb_rel.Min.y = bb_rel.Max.y = ImMax(window->SizeFull.y, window->SizeContents.y) - window->Scroll.y;
+ bb_rel.Min.y = bb_rel.Max.y = ImMax(window->SizeFull.y, window->ContentSize.y + window->WindowPadding.y * 2.0f) - window->Scroll.y;
if (move_flags & ImGuiNavMoveFlags_WrapY) { bb_rel.TranslateX(-bb_rel.GetWidth()); clip_dir = ImGuiDir_Left; }
NavMoveRequestForward(g.NavMoveDir, clip_dir, bb_rel, move_flags);
}
@@ -7749,7 +7983,7 @@ ImVec2 ImGui::GetNavInputAmount2d(ImGuiNavDirSourceFlags dir_sources, ImGuiInput
// NB: We modify rect_rel by the amount we scrolled for, so it is immediately updated.
static void NavScrollToBringItemIntoView(ImGuiWindow* window, const ImRect& item_rect)
{
- ImRect window_rect(window->InnerMainRect.Min - ImVec2(1, 1), window->InnerMainRect.Max + ImVec2(1, 1));
+ ImRect window_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1));
//GetForegroundDrawList(window)->AddRect(window_rect.Min, window_rect.Max, IM_COL32_WHITE); // [DEBUG]
if (window_rect.Contains(item_rect))
return;
@@ -7817,10 +8051,10 @@ static void ImGui::NavUpdate()
g.IO.NavInputsDownDuration[i] = (g.IO.NavInputs[i] > 0.0f) ? (g.IO.NavInputsDownDuration[i] < 0.0f ? 0.0f : g.IO.NavInputsDownDuration[i] + g.IO.DeltaTime) : -1.0f;
// Process navigation init request (select first/default focus)
- if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove))
+ // In very rare cases g.NavWindow may be null (e.g. clearing focus after requesting an init request, which does happen when releasing Alt while clicking on void)
+ if (g.NavInitResultId != 0 && (!g.NavDisableHighlight || g.NavInitRequestFromMove) && g.NavWindow)
{
// Apply result from previous navigation init request (will typically select the first item, unless SetItemDefaultFocus() has been called)
- IM_ASSERT(g.NavWindow);
if (g.NavInitRequestFromMove)
SetNavIDWithRectRel(g.NavInitResultId, g.NavLayer, g.NavInitResultRectRel);
else
@@ -8023,7 +8257,7 @@ static void ImGui::NavUpdate()
if (g.NavMoveRequest && g.NavMoveFromClampedRefRect && g.NavLayer == 0)
{
ImGuiWindow* window = g.NavWindow;
- ImRect window_rect_rel(window->InnerMainRect.Min - window->Pos - ImVec2(1,1), window->InnerMainRect.Max - window->Pos + ImVec2(1,1));
+ ImRect window_rect_rel(window->InnerRect.Min - window->Pos - ImVec2(1,1), window->InnerRect.Max - window->Pos + ImVec2(1,1));
if (!window_rect_rel.Contains(window->NavRectRel[g.NavLayer]))
{
float pad = window->CalcFontSize() * 0.5f;
@@ -8124,14 +8358,14 @@ static float ImGui::NavUpdatePageUpPageDown(int allowed_dir_flags)
{
// Fallback manual-scroll when window has no navigable item
if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageUp], true))
- SetWindowScrollY(window, window->Scroll.y - window->InnerMainRect.GetHeight());
+ SetWindowScrollY(window, window->Scroll.y - window->InnerRect.GetHeight());
else if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageDown], true))
- SetWindowScrollY(window, window->Scroll.y + window->InnerMainRect.GetHeight());
+ SetWindowScrollY(window, window->Scroll.y + window->InnerRect.GetHeight());
}
else
{
const ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer];
- const float page_offset_y = ImMax(0.0f, window->InnerMainRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight());
+ const float page_offset_y = ImMax(0.0f, window->InnerRect.GetHeight() - window->CalcFontSize() * 1.0f + nav_rect_rel.GetHeight());
float nav_scoring_rect_offset_y = 0.0f;
if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageUp], true))
{
@@ -8282,7 +8516,7 @@ static void ImGui::NavUpdateWindowing()
{
const float NAV_MOVE_SPEED = 800.0f;
const float move_speed = ImFloor(NAV_MOVE_SPEED * g.IO.DeltaTime * ImMin(g.IO.DisplayFramebufferScale.x, g.IO.DisplayFramebufferScale.y)); // FIXME: Doesn't code variable framerate very well
- g.NavWindowingTarget->RootWindow->Pos += move_delta * move_speed;
+ SetWindowPos(g.NavWindowingTarget->RootWindow, g.NavWindowingTarget->RootWindow->Pos + move_delta * move_speed, ImGuiCond_Always);
g.NavDisableMouseHover = true;
MarkIniSettingsDirty(g.NavWindowingTarget);
}
@@ -8398,24 +8632,25 @@ void ImGui::NextColumn()
columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y);
if (++columns->Current < columns->Count)
{
- // New column (columns 1+ cancels out IndentX)
+ // Columns 1+ cancel out IndentX
+ // FIXME-COLUMNS: Unnecessary, could be locked?
window->DC.ColumnsOffset.x = GetColumnOffset(columns->Current) - window->DC.Indent.x + g.Style.ItemSpacing.x;
- window->DrawList->ChannelsSetCurrent(columns->Current);
+ window->DrawList->ChannelsSetCurrent(columns->Current + 1);
}
else
{
// New row/line
window->DC.ColumnsOffset.x = 0.0f;
- window->DrawList->ChannelsSetCurrent(0);
+ window->DrawList->ChannelsSetCurrent(1);
columns->Current = 0;
columns->LineMinY = columns->LineMaxY;
}
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
window->DC.CursorPos.y = columns->LineMinY;
- window->DC.CurrentLineSize = ImVec2(0.0f, 0.0f);
- window->DC.CurrentLineTextBaseOffset = 0.0f;
+ window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
+ window->DC.CurrLineTextBaseOffset = 0.0f;
- PushColumnClipRect();
+ PushColumnClipRect(columns->Current); // FIXME-COLUMNS: Could it be an overwrite?
PushItemWidth(GetColumnWidth() * 0.65f); // FIXME-COLUMNS: Move on columns setup
}
@@ -8433,12 +8668,12 @@ int ImGui::GetColumnsCount()
static float OffsetNormToPixels(const ImGuiColumns* columns, float offset_norm)
{
- return offset_norm * (columns->MaxX - columns->MinX);
+ return offset_norm * (columns->OffMaxX - columns->OffMinX);
}
static float PixelsToOffsetNorm(const ImGuiColumns* columns, float offset)
{
- return offset / (columns->MaxX - columns->MinX);
+ return offset / (columns->OffMaxX - columns->OffMinX);
}
static const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f;
@@ -8471,7 +8706,7 @@ float ImGui::GetColumnOffset(int column_index)
IM_ASSERT(column_index < columns->Columns.Size);
const float t = columns->Columns[column_index].OffsetNorm;
- const float x_offset = ImLerp(columns->MinX, columns->MaxX, t);
+ const float x_offset = ImLerp(columns->OffMinX, columns->OffMaxX, t);
return x_offset;
}
@@ -8514,8 +8749,8 @@ void ImGui::SetColumnOffset(int column_index, float offset)
const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f;
if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow))
- offset = ImMin(offset, columns->MaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index));
- columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->MinX);
+ offset = ImMin(offset, columns->OffMaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index));
+ columns->Columns[column_index].OffsetNorm = PixelsToOffsetNorm(columns, offset - columns->OffMinX);
if (preserve_width)
SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width));
@@ -8543,6 +8778,26 @@ void ImGui::PushColumnClipRect(int column_index)
PushClipRect(column->ClipRect.Min, column->ClipRect.Max, false);
}
+// Get into the columns background draw command (which is generally the same draw command as before we called BeginColumns)
+void ImGui::PushColumnsBackground()
+{
+ ImGuiWindow* window = GetCurrentWindowRead();
+ ImGuiColumns* columns = window->DC.CurrentColumns;
+ window->DrawList->ChannelsSetCurrent(0);
+ int cmd_size = window->DrawList->CmdBuffer.Size;
+ PushClipRect(columns->HostClipRect.Min, columns->HostClipRect.Max, false);
+ IM_UNUSED(cmd_size);
+ IM_ASSERT(cmd_size == window->DrawList->CmdBuffer.Size); // Being in channel 0 this should not have created an ImDrawCmd
+}
+
+void ImGui::PopColumnsBackground()
+{
+ ImGuiWindow* window = GetCurrentWindowRead();
+ ImGuiColumns* columns = window->DC.CurrentColumns;
+ window->DrawList->ChannelsSetCurrent(columns->Current + 1);
+ PopClipRect();
+}
+
ImGuiColumns* ImGui::FindOrCreateColumns(ImGuiWindow* window, ImGuiID id)
{
// We have few columns per window so for now we don't need bother much with turning this into a faster lookup.
@@ -8577,9 +8832,8 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag
IM_ASSERT(columns_count >= 1);
IM_ASSERT(window->DC.CurrentColumns == NULL); // Nested columns are currently not supported
- ImGuiID id = GetColumnsID(str_id, columns_count);
-
// Acquire storage for the columns set
+ ImGuiID id = GetColumnsID(str_id, columns_count);
ImGuiColumns* columns = FindOrCreateColumns(window, id);
IM_ASSERT(columns->ID == id);
columns->Current = 0;
@@ -8588,11 +8842,11 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag
window->DC.CurrentColumns = columns;
// Set state for first column
- const float content_region_width = (window->SizeContentsExplicit.x != 0.0f) ? (window->SizeContentsExplicit.x) : (window->InnerClipRect.Max.x - window->Pos.x);
- columns->MinX = window->DC.Indent.x - g.Style.ItemSpacing.x; // Lock our horizontal range
- columns->MaxX = ImMax(content_region_width - window->Scroll.x, columns->MinX + 1.0f);
- columns->BackupCursorPosY = window->DC.CursorPos.y;
- columns->BackupCursorMaxPosX = window->DC.CursorMaxPos.x;
+ columns->OffMinX = window->DC.Indent.x - g.Style.ItemSpacing.x;
+ columns->OffMaxX = ImMax(window->WorkRect.Max.x - window->Pos.x, columns->OffMinX + 1.0f);
+ columns->HostCursorPosY = window->DC.CursorPos.y;
+ columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x;
+ columns->HostClipRect = window->ClipRect;
columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y;
window->DC.ColumnsOffset.x = 0.0f;
window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
@@ -8601,7 +8855,7 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag
if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1)
columns->Columns.resize(0);
- // Initialize defaults
+ // Initialize default widths
columns->IsFirstFrame = (columns->Columns.Size == 0);
if (columns->Columns.Size == 0)
{
@@ -8626,8 +8880,9 @@ void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlag
if (columns->Count > 1)
{
- window->DrawList->ChannelsSplit(columns->Count);
- PushColumnClipRect();
+ window->DrawList->ChannelsSplit(1 + columns->Count);
+ window->DrawList->ChannelsSetCurrent(1);
+ PushColumnClipRect(0);
}
PushItemWidth(GetColumnWidth() * 0.65f);
}
@@ -8646,17 +8901,19 @@ void ImGui::EndColumns()
window->DrawList->ChannelsMerge();
}
+ const ImGuiColumnsFlags flags = columns->Flags;
columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y);
window->DC.CursorPos.y = columns->LineMaxY;
- if (!(columns->Flags & ImGuiColumnsFlags_GrowParentContentsSize))
- window->DC.CursorMaxPos.x = columns->BackupCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent
+ if (!(flags & ImGuiColumnsFlags_GrowParentContentsSize))
+ window->DC.CursorMaxPos.x = columns->HostCursorMaxPosX; // Restore cursor max pos, as columns don't grow parent
// Draw columns borders and handle resize
+ // The IsBeingResized flag ensure we preserve pre-resize columns width so back-and-forth are not lossy
bool is_being_resized = false;
- if (!(columns->Flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems)
+ if (!(flags & ImGuiColumnsFlags_NoBorder) && !window->SkipItems)
{
// We clip Y boundaries CPU side because very long triangles are mishandled by some GPU drivers.
- const float y1 = ImMax(columns->BackupCursorPosY, window->ClipRect.Min.y);
+ const float y1 = ImMax(columns->HostCursorPosY, window->ClipRect.Min.y);
const float y2 = ImMin(window->DC.CursorPos.y, window->ClipRect.Max.y);
int dragging_column = -1;
for (int n = 1; n < columns->Count; n++)
@@ -8671,7 +8928,7 @@ void ImGui::EndColumns()
continue;
bool hovered = false, held = false;
- if (!(columns->Flags & ImGuiColumnsFlags_NoResize))
+ if (!(flags & ImGuiColumnsFlags_NoResize))
{
ButtonBehavior(column_hit_rect, column_id, &hovered, &held);
if (hovered || held)
@@ -8723,6 +8980,7 @@ void ImGui::Columns(int columns_count, const char* id, bool border)
BeginColumns(id, columns_count, flags);
}
+
//-----------------------------------------------------------------------------
// [SECTION] DRAG AND DROP
//-----------------------------------------------------------------------------
@@ -9464,15 +9722,17 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
#else
#include <windows.h>
#endif
+#elif defined(__APPLE__)
+#include <TargetConditionals.h>
#endif
-// Win32 API clipboard implementation
#if defined(_WIN32) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_CLIPBOARD_FUNCTIONS)
#ifdef _MSC_VER
#pragma comment(lib, "user32")
#endif
+// Win32 clipboard implementation
static const char* GetClipboardTextFn_DefaultImpl(void*)
{
static ImVector<char> buf_local;
@@ -9516,16 +9776,66 @@ static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
::CloseClipboard();
}
+#elif defined(__APPLE__) && TARGET_OS_OSX && !defined(IMGUI_DISABLE_OSX_FUNCTIONS)
+
+#include <Carbon/Carbon.h> // Use old API to avoid need for separate .mm file
+static PasteboardRef main_clipboard = 0;
+
+// OSX clipboard implementation
+static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
+{
+ if (!main_clipboard)
+ PasteboardCreate(kPasteboardClipboard, &main_clipboard);
+ PasteboardClear(main_clipboard);
+ CFDataRef cf_data = CFDataCreate(kCFAllocatorDefault, (const UInt8*)text, strlen(text));
+ if (cf_data)
+ {
+ PasteboardPutItemFlavor(main_clipboard, (PasteboardItemID)1, CFSTR("public.utf8-plain-text"), cf_data, 0);
+ CFRelease(cf_data);
+ }
+}
+
+static const char* GetClipboardTextFn_DefaultImpl(void*)
+{
+ if (!main_clipboard)
+ PasteboardCreate(kPasteboardClipboard, &main_clipboard);
+ PasteboardSynchronize(main_clipboard);
+
+ ItemCount item_count = 0;
+ PasteboardGetItemCount(main_clipboard, &item_count);
+ for (int i = 0; i < item_count; i++)
+ {
+ PasteboardItemID item_id = 0;
+ PasteboardGetItemIdentifier(main_clipboard, i + 1, &item_id);
+ CFArrayRef flavor_type_array = 0;
+ PasteboardCopyItemFlavors(main_clipboard, item_id, &flavor_type_array);
+ for (CFIndex j = 0, nj = CFArrayGetCount(flavor_type_array); j < nj; j++)
+ {
+ CFDataRef cf_data;
+ if (PasteboardCopyItemFlavorData(main_clipboard, item_id, CFSTR("public.utf8-plain-text"), &cf_data) == noErr)
+ {
+ static ImVector<char> clipboard_text;
+ int length = (int)CFDataGetLength(cf_data);
+ clipboard_text.resize(length + 1);
+ CFDataGetBytes(cf_data, CFRangeMake(0, length), (UInt8*)clipboard_text.Data);
+ clipboard_text[length] = 0;
+ CFRelease(cf_data);
+ return clipboard_text.Data;
+ }
+ }
+ }
+ return NULL;
+}
+
#else
-// Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers
+// Local Dear ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers.
static const char* GetClipboardTextFn_DefaultImpl(void*)
{
ImGuiContext& g = *GImGui;
return g.PrivateClipboard.empty() ? NULL : g.PrivateClipboard.begin();
}
-// Local ImGui-only clipboard implementation, if user hasn't defined better clipboard handlers
static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
{
ImGuiContext& g = *GImGui;
@@ -9539,7 +9849,7 @@ static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
#endif
// Win32 API IME support (for Asian languages, etc.)
-#if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
+#if defined(_WIN32) && !defined(__GNUC__) && !defined(IMGUI_DISABLE_WIN32_FUNCTIONS) && !defined(IMGUI_DISABLE_WIN32_DEFAULT_IME_FUNCTIONS)
#include <imm.h>
#ifdef _MSC_VER
@@ -9573,16 +9883,16 @@ static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {}
void ImGui::ShowMetricsWindow(bool* p_open)
{
- if (!ImGui::Begin("ImGui Metrics", p_open))
+ if (!ImGui::Begin("Dear ImGui Metrics", p_open))
{
ImGui::End();
return;
}
- enum { RT_OuterRect, RT_OuterRectClipped, RT_InnerMainRect, RT_InnerClipRect, RT_ContentsRegionRect, RT_ContentsFullRect };
+ enum { RT_OuterRect, RT_OuterRectClipped, RT_InnerRect, RT_InnerClipRect, RT_WorkRect, RT_Contents, RT_ContentsRegionRect, RT_Count };
static bool show_windows_begin_order = false;
static bool show_windows_rects = false;
- static int show_windows_rect_type = RT_ContentsRegionRect;
+ static int show_windows_rect_type = RT_WorkRect;
static bool show_drawcmd_clip_rects = true;
ImGuiIO& io = ImGui::GetIO();
@@ -9595,6 +9905,19 @@ void ImGui::ShowMetricsWindow(bool* p_open)
struct Funcs
{
+ static ImRect GetRect(ImGuiWindow* window, int rect_type)
+ {
+ if (rect_type == RT_OuterRect) { return window->Rect(); }
+ else if (rect_type == RT_OuterRectClipped) { return window->OuterRectClipped; }
+ else if (rect_type == RT_InnerRect) { return window->InnerRect; }
+ else if (rect_type == RT_InnerClipRect) { return window->InnerClipRect; }
+ else if (rect_type == RT_WorkRect) { return window->WorkRect; }
+ else if (rect_type == RT_Contents) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); }
+ else if (rect_type == RT_ContentsRegionRect) { return window->ContentsRegionRect; }
+ IM_ASSERT(0);
+ return ImRect();
+ }
+
static void NodeDrawList(ImGuiWindow* window, ImDrawList* draw_list, const char* label)
{
bool node_open = ImGui::TreeNode(draw_list, "%s: '%s' %d vtx, %d indices, %d cmds", label, draw_list->_OwnerName ? draw_list->_OwnerName : "", draw_list->VtxBuffer.Size, draw_list->IdxBuffer.Size, draw_list->CmdBuffer.Size);
@@ -9623,25 +9946,28 @@ void ImGui::ShowMetricsWindow(bool* p_open)
continue;
}
ImDrawIdx* idx_buffer = (draw_list->IdxBuffer.Size > 0) ? draw_list->IdxBuffer.Data : NULL;
- bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "Draw %4d %s vtx, tex 0x%p, clip_rect (%4.0f,%4.0f)-(%4.0f,%4.0f)", pcmd->ElemCount, draw_list->IdxBuffer.Size > 0 ? "indexed" : "non-indexed", pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
+ char buf[300];
+ ImFormatString(buf, IM_ARRAYSIZE(buf), "Draw %4d triangles, tex 0x%p, clip_rect (%4.0f,%4.0f)-(%4.0f,%4.0f)",
+ pcmd->ElemCount/3, (void*)(intptr_t)pcmd->TextureId, pcmd->ClipRect.x, pcmd->ClipRect.y, pcmd->ClipRect.z, pcmd->ClipRect.w);
+ bool pcmd_node_open = ImGui::TreeNode((void*)(pcmd - draw_list->CmdBuffer.begin()), "%s", buf);
if (show_drawcmd_clip_rects && fg_draw_list && ImGui::IsItemHovered())
{
ImRect clip_rect = pcmd->ClipRect;
ImRect vtxs_rect;
for (int i = elem_offset; i < elem_offset + (int)pcmd->ElemCount; i++)
vtxs_rect.Add(draw_list->VtxBuffer[idx_buffer ? idx_buffer[i] : i].pos);
- clip_rect.Floor(); fg_draw_list->AddRect(clip_rect.Min, clip_rect.Max, IM_COL32(255,255,0,255));
- vtxs_rect.Floor(); fg_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, IM_COL32(255,0,255,255));
+ clip_rect.Floor(); fg_draw_list->AddRect(clip_rect.Min, clip_rect.Max, IM_COL32(255,0,255,255));
+ vtxs_rect.Floor(); fg_draw_list->AddRect(vtxs_rect.Min, vtxs_rect.Max, IM_COL32(255,255,0,255));
}
if (!pcmd_node_open)
continue;
// Display individual triangles/vertices. Hover on to get the corresponding triangle highlighted.
+ ImGui::Text("ElemCount: %d, ElemCount/3: %d, VtxOffset: +%d, IdxOffset: +%d", pcmd->ElemCount, pcmd->ElemCount/3, pcmd->VtxOffset, pcmd->IdxOffset);
ImGuiListClipper clipper(pcmd->ElemCount/3); // Manually coarse clip our print out of individual vertices to save CPU, only items that may be visible.
while (clipper.Step())
for (int prim = clipper.DisplayStart, idx_i = elem_offset + clipper.DisplayStart*3; prim < clipper.DisplayEnd; prim++)
{
- char buf[300];
char *buf_p = buf, *buf_end = buf + IM_ARRAYSIZE(buf);
ImVec2 triangles_pos[3];
for (int n = 0; n < 3; n++, idx_i++)
@@ -9650,7 +9976,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImDrawVert& v = draw_list->VtxBuffer[vtx_i];
triangles_pos[n] = v.pos;
buf_p += ImFormatString(buf_p, buf_end - buf_p, "%s %04d: pos (%8.2f,%8.2f), uv (%.6f,%.6f), col %08X\n",
- (n == 0) ? "idx" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
+ (n == 0) ? "elem" : " ", idx_i, v.pos.x, v.pos.y, v.uv.x, v.uv.y, v.col);
}
ImGui::Selectable(buf, false);
if (fg_draw_list && ImGui::IsItemHovered())
@@ -9670,7 +9996,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
{
if (!ImGui::TreeNode((void*)(uintptr_t)columns->ID, "Columns Id: 0x%08X, Count: %d, Flags: 0x%04X", columns->ID, columns->Count, columns->Flags))
return;
- ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->MaxX - columns->MinX, columns->MinX, columns->MaxX);
+ ImGui::BulletText("Width: %.1f (MinX: %.1f, MaxX: %.1f)", columns->OffMaxX - columns->OffMinX, columns->OffMinX, columns->OffMaxX);
for (int column_n = 0; column_n < columns->Columns.Size; column_n++)
ImGui::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, OffsetNormToPixels(columns, columns->Columns[column_n].OffsetNorm));
ImGui::TreePop();
@@ -9691,12 +10017,12 @@ void ImGui::ShowMetricsWindow(bool* p_open)
return;
ImGuiWindowFlags flags = window->Flags;
NodeDrawList(window, window->DrawList, "DrawList");
- ImGui::BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), SizeContents (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->SizeContents.x, window->SizeContents.y);
+ ImGui::BulletText("Pos: (%.1f,%.1f), Size: (%.1f,%.1f), ContentSize (%.1f,%.1f)", window->Pos.x, window->Pos.y, window->Size.x, window->Size.y, window->ContentSize.x, window->ContentSize.y);
ImGui::BulletText("Flags: 0x%08X (%s%s%s%s%s%s%s%s%s..)", flags,
(flags & ImGuiWindowFlags_ChildWindow) ? "Child " : "", (flags & ImGuiWindowFlags_Tooltip) ? "Tooltip " : "", (flags & ImGuiWindowFlags_Popup) ? "Popup " : "",
(flags & ImGuiWindowFlags_Modal) ? "Modal " : "", (flags & ImGuiWindowFlags_ChildMenu) ? "ChildMenu " : "", (flags & ImGuiWindowFlags_NoSavedSettings) ? "NoSavedSettings " : "",
(flags & ImGuiWindowFlags_NoMouseInputs)? "NoMouseInputs":"", (flags & ImGuiWindowFlags_NoNavInputs) ? "NoNavInputs" : "", (flags & ImGuiWindowFlags_AlwaysAutoResize) ? "AlwaysAutoResize" : "");
- ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f)", window->Scroll.x, GetWindowScrollMaxX(window), window->Scroll.y, GetWindowScrollMaxY(window));
+ ImGui::BulletText("Scroll: (%.2f/%.2f,%.2f/%.2f)", window->Scroll.x, window->ScrollMax.x, window->Scroll.y, window->ScrollMax.y);
ImGui::BulletText("Active: %d/%d, WriteAccessed: %d, BeginOrderWithinContext: %d", window->Active, window->WasActive, window->WriteAccessed, (window->Active || window->WasActive) ? window->BeginOrderWithinContext : -1);
ImGui::BulletText("Appearing: %d, Hidden: %d (CanSkip %d Cannot %d), SkipItems: %d", window->Appearing, window->Hidden, window->HiddenFramesCanSkipItems, window->HiddenFramesCannotSkipItems, window->SkipItems);
ImGui::BulletText("NavLastIds: 0x%08X,0x%08X, NavLayerActiveMask: %X", window->NavLastIds[0], window->NavLastIds[1], window->DC.NavLayerActiveMask);
@@ -9794,7 +10120,19 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImGui::Checkbox("Show windows rectangles", &show_windows_rects);
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 12);
- show_windows_rects |= ImGui::Combo("##rects_type", &show_windows_rect_type, "OuterRect\0" "OuterRectClipped\0" "InnerMainRect\0" "InnerClipRect\0" "ContentsRegionRect\0");
+ const char* rects_names[RT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Contents", "ContentsRegionRect" };
+ show_windows_rects |= ImGui::Combo("##rects_type", &show_windows_rect_type, rects_names, RT_Count);
+ if (show_windows_rects && g.NavWindow)
+ {
+ ImGui::BulletText("'%s':", g.NavWindow->Name);
+ ImGui::Indent();
+ for (int n = 0; n < RT_Count; n++)
+ {
+ ImRect r = Funcs::GetRect(g.NavWindow, n);
+ ImGui::Text("(%6.1f,%6.1f) (%6.1f,%6.1f) Size (%6.1f,%6.1f) %s", r.Min.x, r.Min.y, r.Max.x, r.Max.y, r.GetWidth(), r.GetHeight(), rects_names[n]);
+ }
+ ImGui::Unindent();
+ }
ImGui::Checkbox("Show clipping rectangle when hovering ImDrawCmd node", &show_drawcmd_clip_rects);
ImGui::TreePop();
}
@@ -9809,12 +10147,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImDrawList* draw_list = GetForegroundDrawList(window);
if (show_windows_rects)
{
- ImRect r;
- if (show_windows_rect_type == RT_OuterRect) { r = window->Rect(); }
- else if (show_windows_rect_type == RT_OuterRectClipped) { r = window->OuterRectClipped; }
- else if (show_windows_rect_type == RT_InnerMainRect) { r = window->InnerMainRect; }
- else if (show_windows_rect_type == RT_InnerClipRect) { r = window->InnerClipRect; }
- else if (show_windows_rect_type == RT_ContentsRegionRect) { r = window->ContentsRegionRect; }
+ ImRect r = Funcs::GetRect(window, show_windows_rect_type);
draw_list->AddRect(r.Min, r.Max, IM_COL32(255, 0, 128, 255));
}
if (show_windows_begin_order && !(window->Flags & ImGuiWindowFlags_ChildWindow))
diff --git a/imgui/imgui.h b/imgui/imgui.h
index 423ba3ac..d5de1102 100644
--- a/imgui/imgui.h
+++ b/imgui/imgui.h
@@ -1,4 +1,4 @@
-// dear imgui, v1.70
+// dear imgui, v1.71
// (headers)
// See imgui.cpp file for documentation.
@@ -20,7 +20,7 @@ Index of this file:
// Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiPayload)
// Obsolete functions
// Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor)
-// Draw List API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListFlags, ImDrawList, ImDrawData)
+// Draw List API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData)
// Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont)
*/
@@ -46,12 +46,13 @@ Index of this file:
// Version
// (Integer encoded as XYYZZ for use in #if preprocessor conditionals. Work in progress versions typically starts at XYY99 then bounce up to XYY00, XYY01 etc. when release tagging happens)
-#define IMGUI_VERSION "1.70"
-#define IMGUI_VERSION_NUM 17000
+#define IMGUI_VERSION "1.71"
+#define IMGUI_VERSION_NUM 17100
#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx))
// Define attributes of all API symbols declarations (e.g. for DLL under Windows)
// IMGUI_API is used for core imgui functions, IMGUI_IMPL_API is used for the default bindings files (imgui_impl_xxx.h)
+// Using dear imgui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
#ifndef IMGUI_API
#define IMGUI_API
#endif
@@ -91,11 +92,12 @@ Index of this file:
// Forward declarations and basic types
//-----------------------------------------------------------------------------
-struct ImDrawChannel; // Temporary storage for ImDrawList ot output draw commands out of order, used by ImDrawList::ChannelsSplit()
+struct ImDrawChannel; // Temporary storage to output draw commands out of order, used by ImDrawListSplitter and ImDrawList::ChannelsSplit()
struct ImDrawCmd; // A single draw command within a parent ImDrawList (generally maps to 1 GPU draw call, unless it is a callback)
struct ImDrawData; // All draw command lists required to render the frame + pos/size coordinates to use for the projection matrix.
struct ImDrawList; // A single draw command list (generally one per window, conceptually you may see this as a dynamic "mesh" builder)
struct ImDrawListSharedData; // Data shared among multiple draw lists (typically owned by parent ImGui context, but you may create one yourself)
+struct ImDrawListSplitter; // Helper to split a draw list into different layers which can be drawn into out of order, then flattened back.
struct ImDrawVert; // A single vertex (pos + uv + col = 20 bytes by default. Override layout with IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT)
struct ImFont; // Runtime data for a single font within a parent ImFontAtlas
struct ImFontAtlas; // Runtime data for multiple fonts, bake multiple fonts into a single texture, TTF/OTF font loader
@@ -218,9 +220,9 @@ namespace ImGui
IMGUI_API ImDrawData* GetDrawData(); // valid after Render() and until the next call to NewFrame(). this is what you have to render.
// Demo, Debug, Information
- IMGUI_API void ShowDemoWindow(bool* p_open = NULL); // create demo/test window (previously called ShowTestWindow). demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application!
- IMGUI_API void ShowAboutWindow(bool* p_open = NULL); // create about window. display Dear ImGui version, credits and build/system information.
- IMGUI_API void ShowMetricsWindow(bool* p_open = NULL); // create metrics/debug window. display Dear ImGui internals: draw commands (with individual draw calls and vertices), window list, basic internal state, etc.
+ IMGUI_API void ShowDemoWindow(bool* p_open = NULL); // create Demo window (previously called ShowTestWindow). demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application!
+ IMGUI_API void ShowAboutWindow(bool* p_open = NULL); // create About window. display Dear ImGui version, credits and build/system information.
+ IMGUI_API void ShowMetricsWindow(bool* p_open = NULL); // create Metrics/Debug window. display Dear ImGui internals: draw commands (with individual draw calls and vertices), window list, basic internal state, etc.
IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // add style editor block (not a window). you can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it uses the default style)
IMGUI_API bool ShowStyleSelector(const char* label); // add style selector block (not a window), essentially a combo listing the default styles.
IMGUI_API void ShowFontSelector(const char* label); // add font selector block (not a window), essentially a combo listing the loaded fonts.
@@ -270,7 +272,7 @@ namespace ImGui
IMGUI_API void SetNextWindowPos(const ImVec2& pos, ImGuiCond cond = 0, const ImVec2& pivot = ImVec2(0,0)); // set next window position. call before Begin(). use pivot=(0.5f,0.5f) to center on given point, etc.
IMGUI_API void SetNextWindowSize(const ImVec2& size, ImGuiCond cond = 0); // set next window size. set axis to 0.0f to force an auto-fit on this axis. call before Begin()
IMGUI_API void SetNextWindowSizeConstraints(const ImVec2& size_min, const ImVec2& size_max, ImGuiSizeCallback custom_callback = NULL, void* custom_callback_data = NULL); // set next window size limits. use -1,-1 on either X/Y axis to preserve the current size. Sizes will be rounded down. Use callback to apply non-trivial programmatic constraints.
- IMGUI_API void SetNextWindowContentSize(const ImVec2& size); // set next window content size (~ enforce the range of scrollbars). not including window decorations (title bar, menu bar, etc.). set an axis to 0.0f to leave it automatic. call before Begin()
+ IMGUI_API void SetNextWindowContentSize(const ImVec2& size); // set next window content size (~ scrollable client area, which enforce the range of scrollbars). Not including window decorations (title bar, menu bar, etc.) nor WindowPadding. set an axis to 0.0f to leave it automatic. call before Begin()
IMGUI_API void SetNextWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // set next window collapsed state. call before Begin()
IMGUI_API void SetNextWindowFocus(); // set next window to be focused / front-most. call before Begin()
IMGUI_API void SetNextWindowBgAlpha(float alpha); // set next window background color alpha. helper to easily modify ImGuiCol_WindowBg/ChildBg/PopupBg. you may also use ImGuiWindowFlags_NoBackground.
@@ -494,9 +496,9 @@ namespace ImGui
IMGUI_API void TreePop(); // ~ Unindent()+PopId()
IMGUI_API void TreeAdvanceToLabelPos(); // advance cursor x position by GetTreeNodeToLabelSpacing()
IMGUI_API float GetTreeNodeToLabelSpacing(); // horizontal distance preceding label when using TreeNode*() or Bullet() == (g.FontSize + style.FramePadding.x*2) for a regular unframed TreeNode
- IMGUI_API void SetNextTreeNodeOpen(bool is_open, ImGuiCond cond = 0); // set next TreeNode/CollapsingHeader open state.
IMGUI_API bool CollapsingHeader(const char* label, ImGuiTreeNodeFlags flags = 0); // if returning 'true' the header is open. doesn't indent nor push on ID stack. user doesn't have to call TreePop().
IMGUI_API bool CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags flags = 0); // when 'p_open' isn't NULL, display an additional small close button on upper right of the header
+ IMGUI_API void SetNextItemOpen(bool is_open, ImGuiCond cond = 0); // set next TreeNode/CollapsingHeader open state.
// Widgets: Selectables
// - A selectable highlights when hovered, and can display another color when selected.
@@ -763,7 +765,8 @@ enum ImGuiInputTextFlags_
ImGuiInputTextFlags_CharsScientific = 1 << 17, // Allow 0123456789.+-*/eE (Scientific notation input)
ImGuiInputTextFlags_CallbackResize = 1 << 18, // Callback on buffer capacity changes request (beyond 'buf_size' parameter value), allowing the string to grow. Notify when the string wants to be resized (for string types which hold a cache of their Size). You will be provided a new BufSize in the callback and NEED to honor it. (see misc/cpp/imgui_stdlib.h for an example of using this)
// [Internal]
- ImGuiInputTextFlags_Multiline = 1 << 20 // For internal use by InputTextMultiline()
+ ImGuiInputTextFlags_Multiline = 1 << 20, // For internal use by InputTextMultiline()
+ ImGuiInputTextFlags_NoMarkEdited = 1 << 21 // For internal use by functions using InputText() before reformatting data
};
// Flags for ImGui::TreeNodeEx(), ImGui::CollapsingHeader*()
@@ -788,7 +791,7 @@ enum ImGuiTreeNodeFlags_
// Obsolete names (will be removed)
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
- , ImGuiTreeNodeFlags_AllowOverlapMode = ImGuiTreeNodeFlags_AllowItemOverlap
+ , ImGuiTreeNodeFlags_AllowOverlapMode = ImGuiTreeNodeFlags_AllowItemOverlap // [renamed in 1.53]
#endif
};
@@ -799,7 +802,7 @@ enum ImGuiSelectableFlags_
ImGuiSelectableFlags_DontClosePopups = 1 << 0, // Clicking this don't close parent popup window
ImGuiSelectableFlags_SpanAllColumns = 1 << 1, // Selectable frame can span all columns (text will still fit in current column)
ImGuiSelectableFlags_AllowDoubleClick = 1 << 2, // Generate press events on double clicks too
- ImGuiSelectableFlags_Disabled = 1 << 3 // Cannot be selected, display greyed out text
+ ImGuiSelectableFlags_Disabled = 1 << 3 // Cannot be selected, display grayed out text
};
// Flags for ImGui::BeginCombo()
@@ -822,9 +825,9 @@ enum ImGuiTabBarFlags_
ImGuiTabBarFlags_None = 0,
ImGuiTabBarFlags_Reorderable = 1 << 0, // Allow manually dragging tabs to re-order them + New tabs are appended at the end of list
ImGuiTabBarFlags_AutoSelectNewTabs = 1 << 1, // Automatically select new tabs when they appear
- ImGuiTabBarFlags_TabListPopupButton = 1 << 2,
+ ImGuiTabBarFlags_TabListPopupButton = 1 << 2, // Disable buttons to open the tab list popup
ImGuiTabBarFlags_NoCloseWithMiddleMouseButton = 1 << 3, // Disable behavior of closing tabs (that are submitted with p_open != NULL) with middle mouse button. You can still repro this behavior on user's side with if (IsItemHovered() && IsMouseClicked(2)) *p_open = false.
- ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4,
+ ImGuiTabBarFlags_NoTabListScrollingButtons = 1 << 4, // Disable scrolling buttons (apply when fitting policy is ImGuiTabBarFlags_FittingPolicyScroll)
ImGuiTabBarFlags_NoTooltip = 1 << 5, // Disable tooltips when hovering a tab
ImGuiTabBarFlags_FittingPolicyResizeDown = 1 << 6, // Resize tabs when they don't fit
ImGuiTabBarFlags_FittingPolicyScroll = 1 << 7, // Add scroll buttons when tabs don't fit
@@ -879,7 +882,7 @@ enum ImGuiDragDropFlags_
ImGuiDragDropFlags_SourceNoDisableHover = 1 << 1, // By default, when dragging we clear data so that IsItemHovered() will return false, to avoid subsequent user code submitting tooltips. This flag disable this behavior so you can still call IsItemHovered() on the source item.
ImGuiDragDropFlags_SourceNoHoldToOpenOthers = 1 << 2, // Disable the behavior that allows to open tree nodes and collapsing header by holding over them while dragging a source item.
ImGuiDragDropFlags_SourceAllowNullID = 1 << 3, // Allow items such as Text(), Image() that have no unique identifier to be used as drag source, by manufacturing a temporary identifier based on their window-relative position. This is extremely unusual within the dear imgui ecosystem and so we made it explicit.
- ImGuiDragDropFlags_SourceExtern = 1 << 4, // External source (from outside of imgui), won't attempt to read current item/window info. Will always return true. Only one Extern source can be active simultaneously.
+ ImGuiDragDropFlags_SourceExtern = 1 << 4, // External source (from outside of dear imgui), won't attempt to read current item/window info. Will always return true. Only one Extern source can be active simultaneously.
ImGuiDragDropFlags_SourceAutoExpirePayload = 1 << 5, // Automatically expire the payload if the source cease to be submitted (otherwise payloads are persisting while being dragged)
// AcceptDragDropPayload() flags
ImGuiDragDropFlags_AcceptBeforeDelivery = 1 << 10, // AcceptDragDropPayload() will returns true even before the mouse button is released. You can then call IsDelivery() to test if the payload needs to be delivered.
@@ -993,7 +996,7 @@ enum ImGuiConfigFlags_
ImGuiConfigFlags_NoMouse = 1 << 4, // Instruct imgui to clear mouse position/buttons in NewFrame(). This allows ignoring the mouse information set by the back-end.
ImGuiConfigFlags_NoMouseCursorChange = 1 << 5, // Instruct back-end to not alter mouse cursor shape and visibility. Use if the back-end cursor changes are interfering with yours and you don't want to use SetMouseCursor() to change mouse cursor. You may want to honor requests from imgui by reading GetMouseCursor() yourself instead.
- // User storage (to allow your back-end/engine to communicate to code that may be shared between multiple projects. Those flags are not used by core ImGui)
+ // User storage (to allow your back-end/engine to communicate to code that may be shared between multiple projects. Those flags are not used by core Dear ImGui)
ImGuiConfigFlags_IsSRGB = 1 << 20, // Application is SRGB-aware.
ImGuiConfigFlags_IsTouchScreen = 1 << 21 // Application is using a touch screen instead of a mouse.
};
@@ -1002,9 +1005,10 @@ enum ImGuiConfigFlags_
enum ImGuiBackendFlags_
{
ImGuiBackendFlags_None = 0,
- ImGuiBackendFlags_HasGamepad = 1 << 0, // Back-end supports gamepad and currently has one connected.
- ImGuiBackendFlags_HasMouseCursors = 1 << 1, // Back-end supports honoring GetMouseCursor() value to change the OS cursor shape.
- ImGuiBackendFlags_HasSetMousePos = 1 << 2 // Back-end supports io.WantSetMousePos requests to reposition the OS mouse position (only used if ImGuiConfigFlags_NavEnableSetMousePos is set).
+ ImGuiBackendFlags_HasGamepad = 1 << 0, // Back-end Platform supports gamepad and currently has one connected.
+ ImGuiBackendFlags_HasMouseCursors = 1 << 1, // Back-end Platform supports honoring GetMouseCursor() value to change the OS cursor shape.
+ ImGuiBackendFlags_HasSetMousePos = 1 << 2, // Back-end Platform supports io.WantSetMousePos requests to reposition the OS mouse position (only used if ImGuiConfigFlags_NavEnableSetMousePos is set).
+ ImGuiBackendFlags_RendererHasVtxOffset = 1 << 3 // Back-end Renderer supports ImDrawCmd::VtxOffset. This enables output of large meshes (64K+ vertices) while still using 16-bits indices.
};
// Enumeration for PushStyleColor() / PopStyleColor()
@@ -1103,7 +1107,8 @@ enum ImGuiStyleVar_
// Obsolete names (will be removed)
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
- , ImGuiStyleVar_Count_ = ImGuiStyleVar_COUNT, ImGuiStyleVar_ChildWindowRounding = ImGuiStyleVar_ChildRounding
+ , ImGuiStyleVar_Count_ = ImGuiStyleVar_COUNT // [renamed in 1.60]
+ , ImGuiStyleVar_ChildWindowRounding = ImGuiStyleVar_ChildRounding // [renamed in 1.53]
#endif
};
@@ -1148,7 +1153,7 @@ enum ImGuiColorEditFlags_
// Obsolete names (will be removed)
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
- , ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex
+ , ImGuiColorEditFlags_RGB = ImGuiColorEditFlags_DisplayRGB, ImGuiColorEditFlags_HSV = ImGuiColorEditFlags_DisplayHSV, ImGuiColorEditFlags_HEX = ImGuiColorEditFlags_DisplayHex // [renamed in 1.69]
#endif
};
@@ -1159,21 +1164,21 @@ enum ImGuiMouseCursor_
ImGuiMouseCursor_None = -1,
ImGuiMouseCursor_Arrow = 0,
ImGuiMouseCursor_TextInput, // When hovering over InputText, etc.
- ImGuiMouseCursor_ResizeAll, // (Unused by imgui functions)
+ ImGuiMouseCursor_ResizeAll, // (Unused by Dear ImGui functions)
ImGuiMouseCursor_ResizeNS, // When hovering over an horizontal border
ImGuiMouseCursor_ResizeEW, // When hovering over a vertical border or a column
ImGuiMouseCursor_ResizeNESW, // When hovering over the bottom-left corner of a window
ImGuiMouseCursor_ResizeNWSE, // When hovering over the bottom-right corner of a window
- ImGuiMouseCursor_Hand, // (Unused by imgui functions. Use for e.g. hyperlinks)
+ ImGuiMouseCursor_Hand, // (Unused by Dear ImGui functions. Use for e.g. hyperlinks)
ImGuiMouseCursor_COUNT
// Obsolete names (will be removed)
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
- , ImGuiMouseCursor_Count_ = ImGuiMouseCursor_COUNT
+ , ImGuiMouseCursor_Count_ = ImGuiMouseCursor_COUNT // [renamed in 1.60]
#endif
};
-// Enumateration for ImGui::SetWindow***(), SetNextWindow***(), SetNextTreeNode***() functions
+// Enumateration for ImGui::SetWindow***(), SetNextWindow***(), SetNextItem***() functions
// Represent a condition.
// Important: Treat as a regular enum! Do NOT combine multiple values using binary operators! All the functions above treat 0 as a shortcut to ImGuiCond_Always.
enum ImGuiCond_
@@ -1185,7 +1190,7 @@ enum ImGuiCond_
// Obsolete names (will be removed)
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
- , ImGuiSetCond_Always = ImGuiCond_Always, ImGuiSetCond_Once = ImGuiCond_Once, ImGuiSetCond_FirstUseEver = ImGuiCond_FirstUseEver, ImGuiSetCond_Appearing = ImGuiCond_Appearing
+ , ImGuiSetCond_Always = ImGuiCond_Always, ImGuiSetCond_Once = ImGuiCond_Once, ImGuiSetCond_FirstUseEver = ImGuiCond_FirstUseEver, ImGuiSetCond_Appearing = ImGuiCond_Appearing // [renamed in 1.51]
#endif
};
@@ -1276,12 +1281,13 @@ struct ImVector
struct ImGuiStyle
{
- float Alpha; // Global alpha applies to everything in ImGui.
+ float Alpha; // Global alpha applies to everything in Dear ImGui.
ImVec2 WindowPadding; // Padding within a window.
float WindowRounding; // Radius of window corners rounding. Set to 0.0f to have rectangular windows.
float WindowBorderSize; // Thickness of border around windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).
ImVec2 WindowMinSize; // Minimum window size. This is a global setting. If you want to constraint individual windows, use SetNextWindowSizeConstraints().
ImVec2 WindowTitleAlign; // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered.
+ ImGuiDir WindowMenuButtonPosition; // Side of the collapsing/docking button in the title bar (left/right). Defaults to ImGuiDir_Left.
float ChildRounding; // Radius of child window corners rounding. Set to 0.0f to have rectangular windows.
float ChildBorderSize; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).
float PopupRounding; // Radius of popup window corners rounding. (Note that tooltip windows use WindowRounding)
@@ -1293,7 +1299,7 @@ struct ImGuiStyle
ImVec2 ItemInnerSpacing; // Horizontal and vertical spacing between within elements of a composed widget (e.g. a slider and its label).
ImVec2 TouchExtraPadding; // Expand reactive bounding box for touch-based system where touch position is not accurate enough. Unfortunately we don't sort widgets so priority on overlap will always be given to the first widget. So don't grow this too much!
float IndentSpacing; // Horizontal indentation when e.g. entering a tree node. Generally == (FontSize + FramePadding.x*2).
- float ColumnsMinSpacing; // Minimum horizontal spacing between two columns.
+ float ColumnsMinSpacing; // Minimum horizontal spacing between two columns. Preferably > (FramePadding.x + 1).
float ScrollbarSize; // Width of the vertical scrollbar, Height of the horizontal scrollbar.
float ScrollbarRounding; // Radius of grab corners for scrollbar.
float GrabMinSize; // Minimum width/height of a grab box for slider/scrollbar.
@@ -1402,7 +1408,7 @@ struct ImGuiIO
float NavInputs[ImGuiNavInput_COUNT]; // Gamepad inputs. Cleared back to zero by EndFrame(). Keyboard keys will be auto-mapped and be written here by NewFrame().
// Functions
- IMGUI_API void AddInputCharacter(ImWchar c); // Queue new character input
+ IMGUI_API void AddInputCharacter(unsigned int c); // Queue new character input
IMGUI_API void AddInputCharactersUTF8(const char* str); // Queue new characters input from an UTF-8 string
IMGUI_API void ClearInputCharacters(); // Clear the text input buffer manually
@@ -1435,7 +1441,7 @@ struct ImGuiIO
bool MouseClicked[5]; // Mouse button went from !Down to Down
bool MouseDoubleClicked[5]; // Has mouse button been double-clicked?
bool MouseReleased[5]; // Mouse button went from Down to !Down
- bool MouseDownOwned[5]; // Track if button was clicked inside an imgui window. We don't request mouse capture from the application if click started outside ImGui bounds.
+ bool MouseDownOwned[5]; // Track if button was clicked inside a dear imgui window. We don't request mouse capture from the application if click started outside ImGui bounds.
bool MouseDownWasDoubleClick[5]; // Track if button down was a double-click
float MouseDownDuration[5]; // Duration the mouse button has been down (0.0f == just clicked)
float MouseDownDurationPrev[5]; // Previous time the mouse button has been down
@@ -1529,6 +1535,8 @@ struct ImGuiPayload
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
namespace ImGui
{
+ // OBSOLETED in 1.71 (from June 2019)
+ static inline void SetNextTreeNodeOpen(bool open, ImGuiCond cond = 0) { SetNextItemOpen(open, cond); }
// OBSOLETED in 1.70 (from May 2019)
static inline float GetContentRegionAvailWidth() { return GetContentRegionAvail().x; }
// OBSOLETED in 1.69 (from Mar 2019)
@@ -1563,7 +1571,7 @@ namespace ImGui
static inline bool IsMouseHoveringAnyWindow() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); }
static inline bool IsMouseHoveringWindow() { return IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); }
}
-typedef ImGuiInputTextCallback ImGuiTextEditCallback; // OBSOLETE in 1.63 (from Aug 2018): made the names consistent
+typedef ImGuiInputTextCallback ImGuiTextEditCallback; // OBSOLETED in 1.63 (from Aug 2018): made the names consistent
typedef ImGuiInputTextCallbackData ImGuiTextEditCallbackData;
#endif
@@ -1754,7 +1762,7 @@ struct ImColor
};
//-----------------------------------------------------------------------------
-// Draw List API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListFlags, ImDrawList, ImDrawData)
+// Draw List API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData)
// Hold a series of drawing commands. The user provides a renderer for ImDrawData which essentially contains an array of ImDrawList.
//-----------------------------------------------------------------------------
@@ -1764,27 +1772,36 @@ struct ImColor
// A) Change your GPU render state,
// B) render a complex 3D scene inside a UI element without an intermediate texture/render target, etc.
// The expected behavior from your rendering function is 'if (cmd.UserCallback != NULL) { cmd.UserCallback(parent_list, cmd); } else { RenderTriangles() }'
+// If you want to override the signature of ImDrawCallback, you can simply use e.g. '#define ImDrawCallback MyDrawCallback' (in imconfig.h) + update rendering back-end accordingly.
+#ifndef ImDrawCallback
typedef void (*ImDrawCallback)(const ImDrawList* parent_list, const ImDrawCmd* cmd);
+#endif
-// Special Draw Callback value to request renderer back-end to reset the graphics/render state.
+// Special Draw callback value to request renderer back-end to reset the graphics/render state.
// The renderer back-end needs to handle this special value, otherwise it will crash trying to call a function at this address.
// This is useful for example if you submitted callbacks which you know have altered the render state and you want it to be restored.
// It is not done by default because they are many perfectly useful way of altering render state for imgui contents (e.g. changing shader/blending settings before an Image call).
#define ImDrawCallback_ResetRenderState (ImDrawCallback)(-1)
// Typically, 1 command = 1 GPU draw call (unless command is a callback)
+// Pre 1.71 back-ends will typically ignore the VtxOffset/IdxOffset fields. When 'io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset'
+// is enabled, those fields allow us to render meshes larger than 64K vertices while keeping 16-bits indices.
struct ImDrawCmd
{
unsigned int ElemCount; // Number of indices (multiple of 3) to be rendered as triangles. Vertices are stored in the callee ImDrawList's vtx_buffer[] array, indices in idx_buffer[].
ImVec4 ClipRect; // Clipping rectangle (x1, y1, x2, y2). Subtract ImDrawData->DisplayPos to get clipping rectangle in "viewport" coordinates
ImTextureID TextureId; // User-provided texture ID. Set by user in ImfontAtlas::SetTexID() for fonts or passed to Image*() functions. Ignore if never using images or multiple fonts atlas.
+ unsigned int VtxOffset; // Start offset in vertex buffer. Pre-1.71 or without ImGuiBackendFlags_RendererHasVtxOffset: always 0. With ImGuiBackendFlags_RendererHasVtxOffset: may be >0 to support meshes larger than 64K vertices with 16-bits indices.
+ unsigned int IdxOffset; // Start offset in index buffer. Always equal to sum of ElemCount drawn so far.
ImDrawCallback UserCallback; // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally.
void* UserCallbackData; // The draw callback code can access this.
- ImDrawCmd() { ElemCount = 0; ClipRect.x = ClipRect.y = ClipRect.z = ClipRect.w = 0.0f; TextureId = (ImTextureID)NULL; UserCallback = NULL; UserCallbackData = NULL; }
+ ImDrawCmd() { ElemCount = 0; ClipRect.x = ClipRect.y = ClipRect.z = ClipRect.w = 0.0f; TextureId = (ImTextureID)NULL; VtxOffset = IdxOffset = 0; UserCallback = NULL; UserCallbackData = NULL; }
};
-// Vertex index (override with '#define ImDrawIdx unsigned int' in imconfig.h)
+// Vertex index
+// (to allow large meshes with 16-bits indices: set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset in the renderer back-end)
+// (to use 32-bits indices: override with '#define ImDrawIdx unsigned int' in imconfig.h)
#ifndef ImDrawIdx
typedef unsigned short ImDrawIdx;
#endif
@@ -1800,17 +1817,32 @@ struct ImDrawVert
#else
// You can override the vertex format layout by defining IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT in imconfig.h
// The code expect ImVec2 pos (8 bytes), ImVec2 uv (8 bytes), ImU32 col (4 bytes), but you can re-order them or add other fields as needed to simplify integration in your engine.
-// The type has to be described within the macro (you can either declare the struct or use a typedef)
+// The type has to be described within the macro (you can either declare the struct or use a typedef). This is because ImVec2/ImU32 are likely not declared a the time you'd want to set your type up.
// NOTE: IMGUI DOESN'T CLEAR THE STRUCTURE AND DOESN'T CALL A CONSTRUCTOR SO ANY CUSTOM FIELD WILL BE UNINITIALIZED. IF YOU ADD EXTRA FIELDS (SUCH AS A 'Z' COORDINATES) YOU WILL NEED TO CLEAR THEM DURING RENDER OR TO IGNORE THEM.
IMGUI_OVERRIDE_DRAWVERT_STRUCT_LAYOUT;
#endif
-// Draw channels are used by the Columns API to "split" the render list into different channels while building, so items of each column can be batched together.
-// You can also use them to simulate drawing layers and submit primitives in a different order than how they will be rendered.
+// For use by ImDrawListSplitter.
struct ImDrawChannel
{
- ImVector<ImDrawCmd> CmdBuffer;
- ImVector<ImDrawIdx> IdxBuffer;
+ ImVector<ImDrawCmd> _CmdBuffer;
+ ImVector<ImDrawIdx> _IdxBuffer;
+};
+
+// Split/Merge functions are used to split the draw list into different layers which can be drawn into out of order.
+// This is used by the Columns api, so items of each column can be batched together in a same draw call.
+struct ImDrawListSplitter
+{
+ int _Current; // Current channel number (0)
+ int _Count; // Number of active channels (1+)
+ ImVector<ImDrawChannel> _Channels; // Draw channels (not resized down so _Count might be < Channels.Size)
+
+ inline ImDrawListSplitter() { Clear(); }
+ inline void Clear() { _Current = 0; _Count = 1; } // Do not clear Channels[] so our allocations are reused next frame
+ IMGUI_API void ClearFreeMemory();
+ IMGUI_API void Split(ImDrawList* draw_list, int count);
+ IMGUI_API void Merge(ImDrawList* draw_list);
+ IMGUI_API void SetCurrentChannel(ImDrawList* draw_list, int channel_idx);
};
enum ImDrawCornerFlags_
@@ -1830,12 +1862,15 @@ enum ImDrawListFlags_
{
ImDrawListFlags_None = 0,
ImDrawListFlags_AntiAliasedLines = 1 << 0, // Lines are anti-aliased (*2 the number of triangles for 1.0f wide line, otherwise *3 the number of triangles)
- ImDrawListFlags_AntiAliasedFill = 1 << 1 // Filled shapes have anti-aliased edges (*2 the number of vertices)
+ ImDrawListFlags_AntiAliasedFill = 1 << 1, // Filled shapes have anti-aliased edges (*2 the number of vertices)
+ ImDrawListFlags_AllowVtxOffset = 1 << 2 // Can emit 'VtxOffset > 0' to allow large meshes. Set when 'ImGuiBackendFlags_RendererHasVtxOffset' is enabled.
};
// Draw command list
-// This is the low-level list of polygons that ImGui functions are filling. At the end of the frame, all command lists are passed to your ImGuiIO::RenderDrawListFn function for rendering.
-// Each ImGui window contains its own ImDrawList. You can use ImGui::GetWindowDrawList() to access the current window draw list and draw custom primitives.
+// This is the low-level list of polygons that ImGui:: functions are filling. At the end of the frame,
+// all command lists are passed to your ImGuiIO::RenderDrawListFn function for rendering.
+// Each dear imgui window contains its own ImDrawList. You can use ImGui::GetWindowDrawList() to
+// access the current window draw list and draw custom primitives.
// You can interleave normal ImGui:: calls and adding primitives to the current draw list.
// All positions are generally in pixel coordinates (top-left at (0,0), bottom-right at io.DisplaySize), but you are totally free to apply whatever transformation matrix to want to the data (if you apply such transformation you'll want to apply it to ClipRect as well)
// Important: Primitives are always added to the list and not culled (culling is done at higher-level by ImGui:: functions), if you use this API a lot consider coarse culling your drawn objects.
@@ -1850,15 +1885,14 @@ struct ImDrawList
// [Internal, used while building lists]
const ImDrawListSharedData* _Data; // Pointer to shared draw data (you can use ImGui::GetDrawListSharedData() to get the one from current ImGui context)
const char* _OwnerName; // Pointer to owner window's name for debugging
- unsigned int _VtxCurrentIdx; // [Internal] == VtxBuffer.Size
+ unsigned int _VtxCurrentOffset; // [Internal] Always 0 unless 'Flags & ImDrawListFlags_AllowVtxOffset'.
+ unsigned int _VtxCurrentIdx; // [Internal] Generally == VtxBuffer.Size unless we are past 64K vertices, in which case this gets reset to 0.
ImDrawVert* _VtxWritePtr; // [Internal] point within VtxBuffer.Data after each add command (to avoid using the ImVector<> operators too much)
ImDrawIdx* _IdxWritePtr; // [Internal] point within IdxBuffer.Data after each add command (to avoid using the ImVector<> operators too much)
ImVector<ImVec4> _ClipRectStack; // [Internal]
ImVector<ImTextureID> _TextureIdStack; // [Internal]
ImVector<ImVec2> _Path; // [Internal] current path building
- int _ChannelsCurrent; // [Internal] current channel number (0)
- int _ChannelsCount; // [Internal] number of active channels (1+)
- ImVector<ImDrawChannel> _Channels; // [Internal] draw channels for columns API (not resized down so _ChannelsCount may be smaller than _Channels.Size)
+ ImDrawListSplitter _Splitter; // [Internal] for channels api
// If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData() or create and use your own ImDrawListSharedData (so you can use ImDrawList without ImGui)
ImDrawList(const ImDrawListSharedData* shared_data) { _Data = shared_data; _OwnerName = NULL; Clear(); }
@@ -1902,18 +1936,18 @@ struct ImDrawList
IMGUI_API void PathBezierCurveTo(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, int num_segments = 0);
IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, int rounding_corners_flags = ImDrawCornerFlags_All);
- // Channels
- // - Use to simulate layers. By switching channels to can render out-of-order (e.g. submit foreground primitives before background primitives)
- // - Use to minimize draw calls (e.g. if going back-and-forth between multiple non-overlapping clipping rectangles, prefer to append into separate channels then merge at the end)
- IMGUI_API void ChannelsSplit(int channels_count);
- IMGUI_API void ChannelsMerge();
- IMGUI_API void ChannelsSetCurrent(int channel_index);
-
// Advanced
IMGUI_API void AddCallback(ImDrawCallback callback, void* callback_data); // Your rendering function must check for 'UserCallback' in ImDrawCmd and call the function instead of rendering triangles.
IMGUI_API void AddDrawCmd(); // This is useful if you need to forcefully create a new draw call (to allow for dependent rendering / blending). Otherwise primitives are merged into the same draw-call as much as possible
IMGUI_API ImDrawList* CloneOutput() const; // Create a clone of the CmdBuffer/IdxBuffer/VtxBuffer.
+ // Advanced: Channels
+ // - Use to split render into layers. By switching channels to can render out-of-order (e.g. submit foreground primitives before background primitives)
+ // - Use to minimize draw calls (e.g. if going back-and-forth between multiple non-overlapping clipping rectangles, prefer to append into separate channels then merge at the end)
+ inline void ChannelsSplit(int count) { _Splitter.Split(this, count); }
+ inline void ChannelsMerge() { _Splitter.Merge(this); }
+ inline void ChannelsSetCurrent(int n) { _Splitter.SetCurrentChannel(this, n); }
+
// Internal helpers
// NB: all primitives needs to be reserved via PrimReserve() beforehand!
IMGUI_API void Clear();
@@ -1929,7 +1963,7 @@ struct ImDrawList
IMGUI_API void UpdateTextureID();
};
-// All draw data to render an ImGui frame
+// All draw data to render a Dear ImGui frame
// (NB: the style and the naming convention here is a little inconsistent, we currently preserve them for backward compatibility purpose,
// as this is one of the oldest structure exposed by the library! Basically, ImDrawList == CmdList)
struct ImDrawData
@@ -1948,7 +1982,7 @@ struct ImDrawData
~ImDrawData() { Clear(); }
void Clear() { Valid = false; CmdLists = NULL; CmdListsCount = TotalVtxCount = TotalIdxCount = 0; DisplayPos = DisplaySize = FramebufferScale = ImVec2(0.f, 0.f); } // The ImDrawList are owned by ImGuiContext!
IMGUI_API void DeIndexAllBuffers(); // Helper to convert all buffers from indexed to non-indexed, in case you cannot render indexed. Note: this is slow and most likely a waste of resources. Always prefer indexed rendering!
- IMGUI_API void ScaleClipRects(const ImVec2& fb_scale); // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than ImGui expects, or if there is a difference between your window resolution and framebuffer resolution.
+ IMGUI_API void ScaleClipRects(const ImVec2& fb_scale); // Helper to scale the ClipRect field of each ImDrawCmd. Use if your final output buffer is at a different scale than Dear ImGui expects, or if there is a difference between your window resolution and framebuffer resolution.
};
//-----------------------------------------------------------------------------
@@ -1993,12 +2027,13 @@ struct ImFontGlyph
// This is essentially a tightly packed of vector of 64k booleans = 8KB storage.
struct ImFontGlyphRangesBuilder
{
- ImVector<int> UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used)
+ ImVector<ImU32> UsedChars; // Store 1-bit per Unicode code point (0=unused, 1=used)
- ImFontGlyphRangesBuilder() { UsedChars.resize(0x10000 / sizeof(int)); memset(UsedChars.Data, 0, 0x10000 / sizeof(int)); }
- bool GetBit(int n) const { int off = (n >> 5); int mask = 1 << (n & 31); return (UsedChars[off] & mask) != 0; } // Get bit n in the array
- void SetBit(int n) { int off = (n >> 5); int mask = 1 << (n & 31); UsedChars[off] |= mask; } // Set bit n in the array
- void AddChar(ImWchar c) { SetBit(c); } // Add character
+ ImFontGlyphRangesBuilder() { Clear(); }
+ inline void Clear() { int size_in_bytes = 0x10000 / 8; UsedChars.resize(size_in_bytes / (int)sizeof(ImU32)); memset(UsedChars.Data, 0, (size_t)size_in_bytes); }
+ inline bool GetBit(int n) const { int off = (n >> 5); ImU32 mask = 1u << (n & 31); return (UsedChars[off] & mask) != 0; } // Get bit n in the array
+ inline void SetBit(int n) { int off = (n >> 5); ImU32 mask = 1u << (n & 31); UsedChars[off] |= mask; } // Set bit n in the array
+ inline void AddChar(ImWchar c) { SetBit(c); } // Add character
IMGUI_API void AddText(const char* text, const char* text_end = NULL); // Add string (each character of the UTF-8 string are added)
IMGUI_API void AddRanges(const ImWchar* ranges); // Add ranges, e.g. builder.AddRanges(ImFontAtlas::GetGlyphRangesDefault()) to force add all of ASCII/Latin+Ext
IMGUI_API void BuildRanges(ImVector<ImWchar>* out_ranges); // Output new ranges
@@ -2071,11 +2106,14 @@ struct ImFontAtlas
IMGUI_API const ImWchar* GetGlyphRangesVietnamese(); // Default + Vietname characters
//-------------------------------------------
- // Custom Rectangles/Glyphs API
+ // [BETA] Custom Rectangles/Glyphs API
//-------------------------------------------
- // You can request arbitrary rectangles to be packed into the atlas, for your own purposes. After calling Build(), you can query the rectangle position and render your pixels.
- // You can also request your rectangles to be mapped as font glyph (given a font + Unicode point), so you can render e.g. custom colorful icons and use them as regular glyphs.
+ // You can request arbitrary rectangles to be packed into the atlas, for your own purposes.
+ // After calling Build(), you can query the rectangle position and render your pixels.
+ // You can also request your rectangles to be mapped as font glyph (given a font + Unicode point),
+ // so you can render e.g. custom colorful icons and use them as regular glyphs.
+ // Read misc/fonts/README.txt for more details about using colorful icons.
struct CustomRect
{
unsigned int ID; // Input // User ID. Use <0x10000 to map into a font glyph, >=0x10000 for other/internal/custom texture data.
@@ -2087,7 +2125,6 @@ struct ImFontAtlas
CustomRect() { ID = 0xFFFFFFFF; Width = Height = 0; X = Y = 0xFFFF; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0,0); Font = NULL; }
bool IsPacked() const { return X != 0xFFFF; }
};
-
IMGUI_API int AddCustomRectRegular(unsigned int id, int width, int height); // Id needs to be >= 0x10000. Id >= 0x80000000 are reserved for ImGui and ImDrawList
IMGUI_API int AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int height, float advance_x, const ImVec2& offset = ImVec2(0,0)); // Id needs to be < 0x10000 to register a rectangle to map into a specific font.
const CustomRect* GetCustomRectByIndex(int index) const { if (index < 0) return NULL; return &CustomRects[index]; }
@@ -2120,7 +2157,7 @@ struct ImFontAtlas
int CustomRectIds[1]; // Identifiers of custom texture rectangle used by ImFontAtlas/ImDrawList
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
- typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETE 1.67+
+ typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+
#endif
};
@@ -2174,7 +2211,7 @@ struct ImFont
IMGUI_API void SetFallbackChar(ImWchar c);
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
- typedef ImFontGlyph Glyph; // OBSOLETE 1.52+
+ typedef ImFontGlyph Glyph; // OBSOLETED in 1.52+
#endif
};
diff --git a/imgui/imgui_demo.cpp b/imgui/imgui_demo.cpp
index 62196c64..df875b23 100644
--- a/imgui/imgui_demo.cpp
+++ b/imgui/imgui_demo.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.70
+// dear imgui, v1.71
// (demo code)
// Message to the person tempted to delete this file when integrating Dear ImGui into their code base:
@@ -17,9 +17,18 @@
// In this demo code, we frequently we use 'static' variables inside functions. A static variable persist across calls, so it is
// essentially like a global variable but declared inside the scope of the function. We do this as a way to gather code and data
// in the same place, to make the demo source code faster to read, faster to write, and smaller in size.
-// It also happens to be a convenient way of storing simple UI related information as long as your function doesn't need to be reentrant
-// or used in threads. This might be a pattern you will want to use in your code, but most of the real data you would be editing is
-// likely going to be stored outside your functions.
+// It also happens to be a convenient way of storing simple UI related information as long as your function doesn't need to be
+// reentrant or used in multiple threads. This might be a pattern you will want to use in your code, but most of the real data
+// you would be editing is likely going to be stored outside your functions.
+
+// The Demo code is this file is designed to be easy to copy-and-paste in into your application!
+// Because of this:
+// - We never omit the ImGui:: namespace when calling functions, even though most of our code is already in the same namespace.
+// - We try to declare static variables in the local scope, as close as possible to the code using them.
+// - We never use any of the helpers/facilities used internally by dear imgui, unless it has been exposed in the public API (imgui.h).
+// - We never use maths operators on ImVec2/ImVec4. For other imgui sources files, they are provided by imgui_internal.h w/ IMGUI_DEFINE_MATH_OPERATORS,
+// for your own sources file they are optional and require you either enable those, either provide your own via IM_VEC2_CLASS_EXTRA in imconfig.h.
+// Because we don't want to assume anything about your support of maths operators, we don't use them in imgui_demo.cpp.
/*
@@ -63,7 +72,7 @@ Index of this file:
#ifdef _MSC_VER
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
#endif
-#ifdef __clang__
+#if defined(__clang__)
#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse.
#pragma clang diagnostic ignored "-Wdeprecated-declarations" // warning : 'xx' is deprecated: The POSIX name for this item.. // for strdup used in demo code (so user can copy & paste the code)
#pragma clang diagnostic ignored "-Wint-to-void-pointer-cast" // warning : cast to 'void *' from smaller integer type 'int'
@@ -246,7 +255,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::SetNextWindowSize(ImVec2(550, 680), ImGuiCond_FirstUseEver);
// Main body of the Demo window starts here.
- if (!ImGui::Begin("ImGui Demo", p_open, window_flags))
+ if (!ImGui::Begin("Dear ImGui Demo", p_open, window_flags))
{
// Early out if the window is collapsed, as an optimization.
ImGui::End();
@@ -350,6 +359,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::CheckboxFlags("io.BackendFlags: HasGamepad", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasGamepad);
ImGui::CheckboxFlags("io.BackendFlags: HasMouseCursors", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasMouseCursors);
ImGui::CheckboxFlags("io.BackendFlags: HasSetMousePos", (unsigned int *)&backend_flags, ImGuiBackendFlags_HasSetMousePos);
+ ImGui::CheckboxFlags("io.BackendFlags: RendererHasVtxOffset", (unsigned int *)&backend_flags, ImGuiBackendFlags_RendererHasVtxOffset);
ImGui::TreePop();
ImGui::Separator();
}
@@ -568,13 +578,20 @@ static void ShowDemoWindowWidgets()
if (ImGui::TreeNode("Basic trees"))
{
for (int i = 0; i < 5; i++)
+ {
+ // Use SetNextItemOpen() so set the default state of a node to be open.
+ // We could also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing!
+ if (i == 0)
+ ImGui::SetNextItemOpen(true, ImGuiCond_Once);
+
if (ImGui::TreeNode((void*)(intptr_t)i, "Child %d", i))
{
ImGui::Text("blah blah");
ImGui::SameLine();
- if (ImGui::SmallButton("button")) { };
+ if (ImGui::SmallButton("button")) {};
ImGui::TreePop();
}
+ }
ImGui::TreePop();
}
@@ -1228,8 +1245,8 @@ static void ShowDemoWindowWidgets()
ImGui::Text("HSV encoded colors");
ImGui::SameLine(); HelpMarker("By default, colors are given to ColorEdit and ColorPicker in RGB, but ImGuiColorEditFlags_InputHSV allows you to store colors as HSV and pass them to ColorEdit and ColorPicker as HSV. This comes with the added benefit that you can manipulate hue values with the picker even when saturation or value are zero.");
ImGui::Text("Color widget with InputHSV:");
- ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_stored_as_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
- ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_stored_as_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
+ ImGui::ColorEdit4("HSV shown as RGB##1", (float*)&color_stored_as_hsv, ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
+ ImGui::ColorEdit4("HSV shown as HSV##1", (float*)&color_stored_as_hsv, ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_InputHSV | ImGuiColorEditFlags_Float);
ImGui::DragFloat4("Raw HSV values", (float*)&color_stored_as_hsv, 0.01f, 0.0f, 1.0f);
ImGui::TreePop();
@@ -1533,10 +1550,11 @@ static void ShowDemoWindowWidgets()
ImGui::RadioButton("Checkbox", &item_type, 2);
ImGui::RadioButton("SliderFloat", &item_type, 3);
ImGui::RadioButton("InputText", &item_type, 4);
- ImGui::RadioButton("ColorEdit4", &item_type, 5);
- ImGui::RadioButton("MenuItem", &item_type, 6);
- ImGui::RadioButton("TreeNode (w/ double-click)", &item_type, 7);
- ImGui::RadioButton("ListBox", &item_type, 8);
+ ImGui::RadioButton("InputFloat3", &item_type, 5);
+ ImGui::RadioButton("ColorEdit4", &item_type, 6);
+ ImGui::RadioButton("MenuItem", &item_type, 7);
+ ImGui::RadioButton("TreeNode (w/ double-click)", &item_type, 8);
+ ImGui::RadioButton("ListBox", &item_type, 9);
ImGui::Separator();
bool ret = false;
if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction
@@ -1544,10 +1562,11 @@ static void ShowDemoWindowWidgets()
if (item_type == 2) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox
if (item_type == 3) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item
if (item_type == 4) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing)
- if (item_type == 5) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
- if (item_type == 6) { ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy)
- if (item_type == 7) { ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy.
- if (item_type == 8) { 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 == 5) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
+ if (item_type == 6) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
+ if (item_type == 7) { ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy)
+ if (item_type == 8) { ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy.
+ if (item_type == 9) { const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); }
ImGui::BulletText(
"Return value = %d\n"
"IsItemFocused() = %d\n"
@@ -1628,6 +1647,9 @@ static void ShowDemoWindowWidgets()
if (embed_all_inside_a_child_window)
ImGui::EndChild();
+ static char dummy_str[] = "This is a dummy field to be able to tab-out of the widgets above.";
+ ImGui::InputText("dummy", dummy_str, IM_ARRAYSIZE(dummy_str), ImGuiInputTextFlags_ReadOnly);
+
// Calling IsItemHovered() after begin returns the hovered status of the title bar.
// This is useful in particular if you want to create a context menu (with BeginPopupContextItem) associated to the title bar of a window.
static bool test_window = false;
@@ -2037,23 +2059,37 @@ static void ShowDemoWindowLayout()
HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given position.");
static bool track = true;
- static int track_line = 50, scroll_to_px = 200;
+ static int track_line = 50;
+ static float scroll_to_off_px = 0.0f;
+ static float scroll_to_pos_px = 200.0f;
ImGui::Checkbox("Track", &track);
ImGui::PushItemWidth(100);
- ImGui::SameLine(130); track |= ImGui::DragInt("##line", &track_line, 0.25f, 0, 99, "Line = %d");
- bool scroll_to = ImGui::Button("Scroll To Pos");
- ImGui::SameLine(130); scroll_to |= ImGui::DragInt("##pos_y", &scroll_to_px, 1.00f, 0, 9999, "Y = %d px");
+ ImGui::SameLine(140); track |= ImGui::DragInt("##line", &track_line, 0.25f, 0, 99, "Line = %d");
+
+ bool scroll_to_off = ImGui::Button("Scroll Offset");
+ ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off_y", &scroll_to_off_px, 1.00f, 0, 9999, "+%.0f px");
+
+ bool scroll_to_pos = ImGui::Button("Scroll To Pos");
+ ImGui::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos_y", &scroll_to_pos_px, 1.00f, 0, 9999, "Y = %.0f px");
+
ImGui::PopItemWidth();
- if (scroll_to) track = false;
+ if (scroll_to_off || scroll_to_pos)
+ track = false;
+ ImGuiStyle& style = ImGui::GetStyle();
+ float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5;
for (int i = 0; i < 5; i++)
{
if (i > 0) ImGui::SameLine();
ImGui::BeginGroup();
ImGui::Text("%s", i == 0 ? "Top" : i == 1 ? "25%" : i == 2 ? "Center" : i == 3 ? "75%" : "Bottom");
- ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(ImGui::GetWindowWidth() * 0.17f, 200.0f), true);
- if (scroll_to)
- ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_px, i * 0.25f);
+
+ ImGuiWindowFlags child_flags = ImGuiWindowFlags_MenuBar;
+ ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(child_w, 200.0f), true, child_flags);
+ if (scroll_to_off)
+ ImGui::SetScrollY(scroll_to_off_px);
+ if (scroll_to_pos)
+ ImGui::SetScrollFromPosY(ImGui::GetCursorStartPos().y + scroll_to_pos_px, i * 0.25f);
for (int line = 0; line < 100; line++)
{
if (track && line == track_line)
@@ -2066,9 +2102,10 @@ static void ShowDemoWindowLayout()
ImGui::Text("Line %d", line);
}
}
- float scroll_y = ImGui::GetScrollY(), scroll_max_y = ImGui::GetScrollMaxY();
+ float scroll_y = ImGui::GetScrollY();
+ float scroll_max_y = ImGui::GetScrollMaxY();
ImGui::EndChild();
- ImGui::Text("%.0f/%0.f", scroll_y, scroll_max_y);
+ ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y);
ImGui::EndGroup();
}
ImGui::TreePop();
@@ -2118,6 +2155,97 @@ static void ShowDemoWindowLayout()
ImGui::SetScrollX(ImGui::GetScrollX() + scroll_x_delta);
ImGui::EndChild();
}
+ ImGui::Spacing();
+
+ static bool show_horizontal_contents_size_demo_window = false;
+ ImGui::Checkbox("Show Horizontal contents size demo window", &show_horizontal_contents_size_demo_window);
+
+ if (show_horizontal_contents_size_demo_window)
+ {
+ static bool show_h_scrollbar = true;
+ static bool show_button = true;
+ static bool show_tree_nodes = true;
+ static bool show_text_wrapped = false;
+ static bool show_columns = true;
+ static bool show_tab_bar = true;
+ static bool show_child = false;
+ static bool explicit_content_size = false;
+ static float contents_size_x = 300.0f;
+ if (explicit_content_size)
+ ImGui::SetNextWindowContentSize(ImVec2(contents_size_x, 0.0f));
+ ImGui::Begin("Horizontal contents size demo window", &show_horizontal_contents_size_demo_window, show_h_scrollbar ? ImGuiWindowFlags_HorizontalScrollbar : 0);
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(2, 0));
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(2, 0));
+ HelpMarker("Test of different widgets react and impact the work rectangle growing when horizontal scrolling is enabled.\n\nUse 'Metrics->Tools->Show windows rectangles' to visualize rectangles.");
+ ImGui::Checkbox("H-scrollbar", &show_h_scrollbar);
+ ImGui::Checkbox("Button", &show_button); // Will grow contents size (unless explicitly overwritten)
+ ImGui::Checkbox("Tree nodes", &show_tree_nodes); // Will grow contents size and display highlight over full width
+ ImGui::Checkbox("Text wrapped", &show_text_wrapped);// Will grow and use contents size
+ ImGui::Checkbox("Columns", &show_columns); // Will use contents size
+ ImGui::Checkbox("Tab bar", &show_tab_bar); // Will use contents size
+ ImGui::Checkbox("Child", &show_child); // Will grow and use contents size
+ ImGui::Checkbox("Explicit content size", &explicit_content_size);
+ ImGui::Text("Scroll %.1f/%.1f %.1f/%.1f", ImGui::GetScrollX(), ImGui::GetScrollMaxX(), ImGui::GetScrollY(), ImGui::GetScrollMaxY());
+ if (explicit_content_size)
+ {
+ ImGui::SameLine();
+ ImGui::SetNextItemWidth(100);
+ ImGui::DragFloat("##csx", &contents_size_x);
+ ImVec2 p = ImGui::GetCursorScreenPos();
+ ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE);
+ ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE);
+ ImGui::Dummy(ImVec2(0, 10));
+ }
+ ImGui::PopStyleVar(2);
+ ImGui::Separator();
+ if (show_button)
+ {
+ ImGui::Button("this is a 300-wide button", ImVec2(300, 0));
+ }
+ if (show_tree_nodes)
+ {
+ bool open = true;
+ if (ImGui::TreeNode("this is a tree node"))
+ {
+ if (ImGui::TreeNode("another one of those tree node..."))
+ {
+ ImGui::Text("Some tree contents");
+ ImGui::TreePop();
+ }
+ ImGui::TreePop();
+ }
+ ImGui::CollapsingHeader("CollapsingHeader", &open);
+ }
+ if (show_text_wrapped)
+ {
+ ImGui::TextWrapped("This text should automatically wrap on the edge of the work rectangle.");
+ }
+ if (show_columns)
+ {
+ ImGui::Columns(4);
+ for (int n = 0; n < 4; n++)
+ {
+ ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
+ ImGui::NextColumn();
+ }
+ ImGui::Columns(1);
+ }
+ if (show_tab_bar && ImGui::BeginTabBar("Hello"))
+ {
+ if (ImGui::BeginTabItem("OneOneOne")) { ImGui::EndTabItem(); }
+ if (ImGui::BeginTabItem("TwoTwoTwo")) { ImGui::EndTabItem(); }
+ if (ImGui::BeginTabItem("ThreeThreeThree")) { ImGui::EndTabItem(); }
+ if (ImGui::BeginTabItem("FourFourFour")) { ImGui::EndTabItem(); }
+ ImGui::EndTabBar();
+ }
+ if (show_child)
+ {
+ ImGui::BeginChild("child", ImVec2(0,0), true);
+ ImGui::EndChild();
+ }
+ ImGui::End();
+ }
+
ImGui::TreePop();
}
@@ -2145,7 +2273,7 @@ static void ShowDemoWindowPopups()
// The properties of popups windows are:
// - They block normal mouse hovering detection outside them. (*)
// - Unless modal, they can be closed by clicking anywhere outside them, or by pressing ESCAPE.
- // - Their visibility state (~bool) is held internally by imgui instead of being held by the programmer as we are used to with regular Begin() calls.
+ // - Their visibility state (~bool) is held internally by Dear ImGui instead of being held by the programmer as we are used to with regular Begin() calls.
// User can manipulate the visibility state by calling OpenPopup().
// (*) One can use IsItemHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup) to bypass it and detect hovering even when normally blocked by a popup.
// Those three properties are connected. The library needs to hold their visibility state because it can close popups at any time.
@@ -2426,6 +2554,32 @@ static void ShowDemoWindowColumns()
ImGui::TreePop();
}
+ if (ImGui::TreeNode("Borders"))
+ {
+ // NB: Future columns API should allow automatic horizontal borders.
+ static bool h_borders = true;
+ static bool v_borders = true;
+ ImGui::Checkbox("horizontal", &h_borders);
+ ImGui::SameLine();
+ ImGui::Checkbox("vertical", &v_borders);
+ ImGui::Columns(4, NULL, v_borders);
+ for (int i = 0; i < 4 * 3; i++)
+ {
+ if (h_borders && ImGui::GetColumnIndex() == 0)
+ ImGui::Separator();
+ ImGui::Text("%c%c%c", 'a' + i, 'a' + i, 'a' + i);
+ ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
+ ImGui::Text("Offset %.2f", ImGui::GetColumnOffset());
+ ImGui::Text("Long text that is likely to clip");
+ ImGui::Button("Button", ImVec2(-1.0f, 0.0f));
+ ImGui::NextColumn();
+ }
+ ImGui::Columns(1);
+ if (h_borders)
+ ImGui::Separator();
+ ImGui::TreePop();
+ }
+
// Create multiple items in a same cell before switching to next column
if (ImGui::TreeNode("Mixed items"))
{
@@ -2472,32 +2626,6 @@ static void ShowDemoWindowColumns()
ImGui::TreePop();
}
- if (ImGui::TreeNode("Borders"))
- {
- // NB: Future columns API should allow automatic horizontal borders.
- static bool h_borders = true;
- static bool v_borders = true;
- ImGui::Checkbox("horizontal", &h_borders);
- ImGui::SameLine();
- ImGui::Checkbox("vertical", &v_borders);
- ImGui::Columns(4, NULL, v_borders);
- for (int i = 0; i < 4*3; i++)
- {
- if (h_borders && ImGui::GetColumnIndex() == 0)
- ImGui::Separator();
- ImGui::Text("%c%c%c", 'a'+i, 'a'+i, 'a'+i);
- ImGui::Text("Width %.2f", ImGui::GetColumnWidth());
- ImGui::Text("Offset %.2f", ImGui::GetColumnOffset());
- ImGui::Text("Long text that is likely to clip");
- ImGui::Button("Button", ImVec2(-1.0f, 0.0f));
- ImGui::NextColumn();
- }
- ImGui::Columns(1);
- if (h_borders)
- ImGui::Separator();
- ImGui::TreePop();
- }
-
// Scrolling columns
/*
if (ImGui::TreeNode("Vertical Scrolling"))
@@ -2556,7 +2684,7 @@ static void ShowDemoWindowColumns()
ImGui::NextColumn();
if (open1)
{
- for (int y = 0; y < 5; y++)
+ for (int y = 0; y < 3; y++)
{
bool open2 = ImGui::TreeNode((void*)(intptr_t)y, "Node%d.%d", x, y);
ImGui::NextColumn();
@@ -2745,7 +2873,7 @@ static void ShowDemoWindowMisc()
//-----------------------------------------------------------------------------
// [SECTION] About Window / ShowAboutWindow()
-// Access from ImGui Demo -> Help -> About
+// Access from Dear ImGui Demo -> Help -> About
//-----------------------------------------------------------------------------
void ImGui::ShowAboutWindow(bool* p_open)
@@ -2846,6 +2974,7 @@ void ImGui::ShowAboutWindow(bool* p_open)
if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad");
if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors");
if (io.BackendFlags & ImGuiBackendFlags_HasSetMousePos) ImGui::Text(" HasSetMousePos");
+ if (io.BackendFlags & ImGuiBackendFlags_RendererHasVtxOffset) ImGui::Text(" RendererHasVtxOffset");
ImGui::Separator();
ImGui::Text("io.Fonts: %d fonts, Flags: 0x%08X, TexSize: %d,%d", io.Fonts->Fonts.Size, io.Fonts->Flags, io.Fonts->TexWidth, io.Fonts->TexHeight);
ImGui::Text("io.DisplaySize: %.2f,%.2f", io.DisplaySize.x, io.DisplaySize.y);
@@ -2983,6 +3112,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f");
ImGui::Text("Alignment");
ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
+ ImGui::Combo("WindowMenuButtonPosition", (int*)&style.WindowMenuButtonPosition, "Left\0Right\0");
ImGui::SliderFloat2("ButtonTextAlign", (float*)&style.ButtonTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Alignment applies when a button is larger than its text content.");
ImGui::SliderFloat2("SelectableTextAlign", (float*)&style.SelectableTextAlign, 0.0f, 1.0f, "%.2f"); ImGui::SameLine(); HelpMarker("Alignment applies when a selectable is larger than its text content.");
ImGui::Text("Safe Area Padding"); ImGui::SameLine(); HelpMarker("Adjust if you cannot see the edges of your screen (e.g. on a TV where scaling has not been configured).");
diff --git a/imgui/imgui_draw.cpp b/imgui/imgui_draw.cpp
index 63d99a29..8d0c31de 100644
--- a/imgui/imgui_draw.cpp
+++ b/imgui/imgui_draw.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.70
+// dear imgui, v1.71
// (drawing and font code)
/*
@@ -8,6 +8,7 @@ Index of this file:
// [SECTION] STB libraries implementation
// [SECTION] Style functions
// [SECTION] ImDrawList
+// [SECTION] ImDrawListSplitter
// [SECTION] ImDrawData
// [SECTION] Helpers ShadeVertsXXX functions
// [SECTION] ImFontConfig
@@ -33,7 +34,7 @@ Index of this file:
#include <stdio.h> // vsnprintf, sscanf, printf
#if !defined(alloca)
-#if defined(__GLIBC__) || defined(__sun) || defined(__CYGWIN__) || defined(__APPLE__)
+#if defined(__GLIBC__) || defined(__sun) || defined(__CYGWIN__) || defined(__APPLE__) || defined(__SWITCH__)
#include <alloca.h> // alloca (glibc uses <alloca.h>. Note that Cygwin may have _WIN32 defined, so the order matters here)
#elif defined(_WIN32)
#include <malloc.h> // alloca
@@ -47,12 +48,13 @@ Index of this file:
// Visual Studio warnings
#ifdef _MSC_VER
+#pragma warning (disable: 4127) // condition expression is constant
#pragma warning (disable: 4505) // unreferenced local function has been removed (stb stuff)
#pragma warning (disable: 4996) // 'This function or variable may be unsafe': strcpy, strdup, sprintf, vsnprintf, sscanf, fopen
#endif
// Clang/GCC warnings with -Weverything
-#ifdef __clang__
+#if defined(__clang__)
#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse.
#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants ok.
#pragma clang diagnostic ignored "-Wglobal-constructors" // warning : declaration requires a global destructor // similar to above, not sure what the exact difference is.
@@ -100,7 +102,7 @@ namespace IMGUI_STB_NAMESPACE
#pragma warning (disable: 4456) // declaration of 'xx' hides previous local declaration
#endif
-#ifdef __clang__
+#if defined(__clang__)
#pragma clang diagnostic push
#pragma clang diagnostic ignored "-Wunused-function"
#pragma clang diagnostic ignored "-Wmissing-prototypes"
@@ -108,7 +110,7 @@ namespace IMGUI_STB_NAMESPACE
#pragma clang diagnostic ignored "-Wcast-qual" // warning : cast from 'const xxxx *' to 'xxx *' drops const qualifier //
#endif
-#ifdef __GNUC__
+#if defined(__GNUC__)
#pragma GCC diagnostic push
#pragma GCC diagnostic ignored "-Wtype-limits" // warning: comparison is always true due to limited range of data type [-Wtype-limits]
#pragma GCC diagnostic ignored "-Wcast-qual" // warning: cast from type 'const xxxx *' to type 'xxxx *' casts away qualifiers
@@ -151,15 +153,15 @@ namespace IMGUI_STB_NAMESPACE
#endif
#endif
-#ifdef __GNUC__
+#if defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
-#ifdef __clang__
+#if defined(__clang__)
#pragma clang diagnostic pop
#endif
-#ifdef _MSC_VER
+#if defined(_MSC_VER)
#pragma warning (pop)
#endif
@@ -348,6 +350,7 @@ ImDrawListSharedData::ImDrawListSharedData()
FontSize = 0.0f;
CurveTessellationTol = 0.0f;
ClipRectFullscreen = ImVec4(-8192.0f, -8192.0f, +8192.0f, +8192.0f);
+ InitialFlags = ImDrawListFlags_None;
// Const data
for (int i = 0; i < IM_ARRAYSIZE(CircleVtx12); i++)
@@ -362,16 +365,15 @@ void ImDrawList::Clear()
CmdBuffer.resize(0);
IdxBuffer.resize(0);
VtxBuffer.resize(0);
- Flags = ImDrawListFlags_AntiAliasedLines | ImDrawListFlags_AntiAliasedFill;
+ Flags = _Data->InitialFlags;
+ _VtxCurrentOffset = 0;
_VtxCurrentIdx = 0;
_VtxWritePtr = NULL;
_IdxWritePtr = NULL;
_ClipRectStack.resize(0);
_TextureIdStack.resize(0);
_Path.resize(0);
- _ChannelsCurrent = 0;
- _ChannelsCount = 1;
- // NB: Do not clear channels so our allocations are re-used after the first frame.
+ _Splitter.Clear();
}
void ImDrawList::ClearFreeMemory()
@@ -385,15 +387,7 @@ void ImDrawList::ClearFreeMemory()
_ClipRectStack.clear();
_TextureIdStack.clear();
_Path.clear();
- _ChannelsCurrent = 0;
- _ChannelsCount = 1;
- for (int i = 0; i < _Channels.Size; i++)
- {
- if (i == 0) memset(&_Channels[0], 0, sizeof(_Channels[0])); // channel 0 is a copy of CmdBuffer/IdxBuffer, don't destruct again
- _Channels[i].CmdBuffer.clear();
- _Channels[i].IdxBuffer.clear();
- }
- _Channels.clear();
+ _Splitter.ClearFreeMemory();
}
ImDrawList* ImDrawList::CloneOutput() const
@@ -415,6 +409,8 @@ void ImDrawList::AddDrawCmd()
ImDrawCmd draw_cmd;
draw_cmd.ClipRect = GetCurrentClipRect();
draw_cmd.TextureId = GetCurrentTextureId();
+ draw_cmd.VtxOffset = _VtxCurrentOffset;
+ draw_cmd.IdxOffset = IdxBuffer.Size;
IM_ASSERT(draw_cmd.ClipRect.x <= draw_cmd.ClipRect.z && draw_cmd.ClipRect.y <= draw_cmd.ClipRect.w);
CmdBuffer.push_back(draw_cmd);
@@ -521,88 +517,17 @@ void ImDrawList::PopTextureID()
UpdateTextureID();
}
-void ImDrawList::ChannelsSplit(int channels_count)
-{
- IM_ASSERT(_ChannelsCurrent == 0 && _ChannelsCount == 1);
- int old_channels_count = _Channels.Size;
- if (old_channels_count < channels_count)
- _Channels.resize(channels_count);
- _ChannelsCount = channels_count;
-
- // _Channels[] (24/32 bytes each) hold storage that we'll swap with this->_CmdBuffer/_IdxBuffer
- // The content of _Channels[0] at this point doesn't matter. We clear it to make state tidy in a debugger but we don't strictly need to.
- // When we switch to the next channel, we'll copy _CmdBuffer/_IdxBuffer into _Channels[0] and then _Channels[1] into _CmdBuffer/_IdxBuffer
- memset(&_Channels[0], 0, sizeof(ImDrawChannel));
- for (int i = 1; i < channels_count; i++)
- {
- if (i >= old_channels_count)
- {
- IM_PLACEMENT_NEW(&_Channels[i]) ImDrawChannel();
- }
- else
- {
- _Channels[i].CmdBuffer.resize(0);
- _Channels[i].IdxBuffer.resize(0);
- }
- if (_Channels[i].CmdBuffer.Size == 0)
- {
- ImDrawCmd draw_cmd;
- draw_cmd.ClipRect = _ClipRectStack.back();
- draw_cmd.TextureId = _TextureIdStack.back();
- _Channels[i].CmdBuffer.push_back(draw_cmd);
- }
- }
-}
-
-void ImDrawList::ChannelsMerge()
+// NB: this can be called with negative count for removing primitives (as long as the result does not underflow)
+void ImDrawList::PrimReserve(int idx_count, int vtx_count)
{
- // Note that we never use or rely on channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use.
- if (_ChannelsCount <= 1)
- return;
-
- ChannelsSetCurrent(0);
- if (CmdBuffer.Size && CmdBuffer.back().ElemCount == 0)
- CmdBuffer.pop_back();
-
- int new_cmd_buffer_count = 0, new_idx_buffer_count = 0;
- for (int i = 1; i < _ChannelsCount; i++)
+ // Large mesh support (when enabled)
+ if (sizeof(ImDrawIdx) == 2 && (_VtxCurrentIdx + vtx_count >= (1 << 16)) && (Flags & ImDrawListFlags_AllowVtxOffset))
{
- ImDrawChannel& ch = _Channels[i];
- if (ch.CmdBuffer.Size && ch.CmdBuffer.back().ElemCount == 0)
- ch.CmdBuffer.pop_back();
- new_cmd_buffer_count += ch.CmdBuffer.Size;
- new_idx_buffer_count += ch.IdxBuffer.Size;
- }
- CmdBuffer.resize(CmdBuffer.Size + new_cmd_buffer_count);
- IdxBuffer.resize(IdxBuffer.Size + new_idx_buffer_count);
-
- ImDrawCmd* cmd_write = CmdBuffer.Data + CmdBuffer.Size - new_cmd_buffer_count;
- _IdxWritePtr = IdxBuffer.Data + IdxBuffer.Size - new_idx_buffer_count;
- for (int i = 1; i < _ChannelsCount; i++)
- {
- ImDrawChannel& ch = _Channels[i];
- if (int sz = ch.CmdBuffer.Size) { memcpy(cmd_write, ch.CmdBuffer.Data, sz * sizeof(ImDrawCmd)); cmd_write += sz; }
- if (int sz = ch.IdxBuffer.Size) { memcpy(_IdxWritePtr, ch.IdxBuffer.Data, sz * sizeof(ImDrawIdx)); _IdxWritePtr += sz; }
+ _VtxCurrentOffset = VtxBuffer.Size;
+ _VtxCurrentIdx = 0;
+ AddDrawCmd();
}
- UpdateClipRect(); // We call this instead of AddDrawCmd(), so that empty channels won't produce an extra draw call.
- _ChannelsCount = 1;
-}
-void ImDrawList::ChannelsSetCurrent(int idx)
-{
- IM_ASSERT(idx < _ChannelsCount);
- if (_ChannelsCurrent == idx) return;
- memcpy(&_Channels.Data[_ChannelsCurrent].CmdBuffer, &CmdBuffer, sizeof(CmdBuffer)); // copy 12 bytes, four times
- memcpy(&_Channels.Data[_ChannelsCurrent].IdxBuffer, &IdxBuffer, sizeof(IdxBuffer));
- _ChannelsCurrent = idx;
- memcpy(&CmdBuffer, &_Channels.Data[_ChannelsCurrent].CmdBuffer, sizeof(CmdBuffer));
- memcpy(&IdxBuffer, &_Channels.Data[_ChannelsCurrent].IdxBuffer, sizeof(IdxBuffer));
- _IdxWritePtr = IdxBuffer.Data + IdxBuffer.Size;
-}
-
-// NB: this can be called with negative count for removing primitives (as long as the result does not underflow)
-void ImDrawList::PrimReserve(int idx_count, int vtx_count)
-{
ImDrawCmd& draw_cmd = CmdBuffer.Data[CmdBuffer.Size-1];
draw_cmd.ElemCount += idx_count;
@@ -1265,6 +1190,133 @@ void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, c
PopTextureID();
}
+
+//-----------------------------------------------------------------------------
+// ImDrawListSplitter
+//-----------------------------------------------------------------------------
+// FIXME: This may be a little confusing, trying to be a little too low-level/optimal instead of just doing vector swap..
+//-----------------------------------------------------------------------------
+
+void ImDrawListSplitter::ClearFreeMemory()
+{
+ for (int i = 0; i < _Channels.Size; i++)
+ {
+ if (i == _Current)
+ memset(&_Channels[i], 0, sizeof(_Channels[i])); // Current channel is a copy of CmdBuffer/IdxBuffer, don't destruct again
+ _Channels[i]._CmdBuffer.clear();
+ _Channels[i]._IdxBuffer.clear();
+ }
+ _Current = 0;
+ _Count = 1;
+ _Channels.clear();
+}
+
+void ImDrawListSplitter::Split(ImDrawList* draw_list, int channels_count)
+{
+ IM_ASSERT(_Current == 0 && _Count <= 1);
+ int old_channels_count = _Channels.Size;
+ if (old_channels_count < channels_count)
+ _Channels.resize(channels_count);
+ _Count = channels_count;
+
+ // Channels[] (24/32 bytes each) hold storage that we'll swap with draw_list->_CmdBuffer/_IdxBuffer
+ // The content of Channels[0] at this point doesn't matter. We clear it to make state tidy in a debugger but we don't strictly need to.
+ // When we switch to the next channel, we'll copy draw_list->_CmdBuffer/_IdxBuffer into Channels[0] and then Channels[1] into draw_list->CmdBuffer/_IdxBuffer
+ memset(&_Channels[0], 0, sizeof(ImDrawChannel));
+ for (int i = 1; i < channels_count; i++)
+ {
+ if (i >= old_channels_count)
+ {
+ IM_PLACEMENT_NEW(&_Channels[i]) ImDrawChannel();
+ }
+ else
+ {
+ _Channels[i]._CmdBuffer.resize(0);
+ _Channels[i]._IdxBuffer.resize(0);
+ }
+ if (_Channels[i]._CmdBuffer.Size == 0)
+ {
+ ImDrawCmd draw_cmd;
+ draw_cmd.ClipRect = draw_list->_ClipRectStack.back();
+ draw_cmd.TextureId = draw_list->_TextureIdStack.back();
+ _Channels[i]._CmdBuffer.push_back(draw_cmd);
+ }
+ }
+}
+
+static inline bool CanMergeDrawCommands(ImDrawCmd* a, ImDrawCmd* b)
+{
+ return memcmp(&a->ClipRect, &b->ClipRect, sizeof(a->ClipRect)) == 0 && a->TextureId == b->TextureId && a->VtxOffset == b->VtxOffset && !a->UserCallback && !b->UserCallback;
+}
+
+void ImDrawListSplitter::Merge(ImDrawList* draw_list)
+{
+ // Note that we never use or rely on channels.Size because it is merely a buffer that we never shrink back to 0 to keep all sub-buffers ready for use.
+ if (_Count <= 1)
+ return;
+
+ SetCurrentChannel(draw_list, 0);
+ if (draw_list->CmdBuffer.Size != 0 && draw_list->CmdBuffer.back().ElemCount == 0)
+ draw_list->CmdBuffer.pop_back();
+
+ // Calculate our final buffer sizes. Also fix the incorrect IdxOffset values in each command.
+ int new_cmd_buffer_count = 0;
+ int new_idx_buffer_count = 0;
+ ImDrawCmd* last_cmd = (_Count > 0 && _Channels[0]._CmdBuffer.Size > 0) ? &_Channels[0]._CmdBuffer.back() : NULL;
+ int idx_offset = last_cmd ? last_cmd->IdxOffset + last_cmd->ElemCount : 0;
+ for (int i = 1; i < _Count; i++)
+ {
+ ImDrawChannel& ch = _Channels[i];
+ if (ch._CmdBuffer.Size > 0 && ch._CmdBuffer.back().ElemCount == 0)
+ ch._CmdBuffer.pop_back();
+ if (ch._CmdBuffer.Size > 0 && last_cmd != NULL && CanMergeDrawCommands(last_cmd, &ch._CmdBuffer[0]))
+ {
+ // Merge previous channel last draw command with current channel first draw command if matching.
+ last_cmd->ElemCount += ch._CmdBuffer[0].ElemCount;
+ idx_offset += ch._CmdBuffer[0].ElemCount;
+ ch._CmdBuffer.erase(ch._CmdBuffer.Data);
+ }
+ if (ch._CmdBuffer.Size > 0)
+ last_cmd = &ch._CmdBuffer.back();
+ new_cmd_buffer_count += ch._CmdBuffer.Size;
+ new_idx_buffer_count += ch._IdxBuffer.Size;
+ for (int cmd_n = 0; cmd_n < ch._CmdBuffer.Size; cmd_n++)
+ {
+ ch._CmdBuffer.Data[cmd_n].IdxOffset = idx_offset;
+ idx_offset += ch._CmdBuffer.Data[cmd_n].ElemCount;
+ }
+ }
+ draw_list->CmdBuffer.resize(draw_list->CmdBuffer.Size + new_cmd_buffer_count);
+ draw_list->IdxBuffer.resize(draw_list->IdxBuffer.Size + new_idx_buffer_count);
+
+ // Write commands and indices in order (they are fairly small structures, we don't copy vertices only indices)
+ ImDrawCmd* cmd_write = draw_list->CmdBuffer.Data + draw_list->CmdBuffer.Size - new_cmd_buffer_count;
+ ImDrawIdx* idx_write = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size - new_idx_buffer_count;
+ for (int i = 1; i < _Count; i++)
+ {
+ ImDrawChannel& ch = _Channels[i];
+ if (int sz = ch._CmdBuffer.Size) { memcpy(cmd_write, ch._CmdBuffer.Data, sz * sizeof(ImDrawCmd)); cmd_write += sz; }
+ if (int sz = ch._IdxBuffer.Size) { memcpy(idx_write, ch._IdxBuffer.Data, sz * sizeof(ImDrawIdx)); idx_write += sz; }
+ }
+ draw_list->_IdxWritePtr = idx_write;
+ draw_list->UpdateClipRect(); // We call this instead of AddDrawCmd(), so that empty channels won't produce an extra draw call.
+ _Count = 1;
+}
+
+void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx)
+{
+ IM_ASSERT(idx < _Count);
+ if (_Current == idx)
+ return;
+ // Overwrite ImVector (12/16 bytes), four times. This is merely a silly optimization instead of doing .swap()
+ memcpy(&_Channels.Data[_Current]._CmdBuffer, &draw_list->CmdBuffer, sizeof(draw_list->CmdBuffer));
+ memcpy(&_Channels.Data[_Current]._IdxBuffer, &draw_list->IdxBuffer, sizeof(draw_list->IdxBuffer));
+ _Current = idx;
+ memcpy(&draw_list->CmdBuffer, &_Channels.Data[idx]._CmdBuffer, sizeof(draw_list->CmdBuffer));
+ memcpy(&draw_list->IdxBuffer, &_Channels.Data[idx]._IdxBuffer, sizeof(draw_list->IdxBuffer));
+ draw_list->_IdxWritePtr = draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size;
+}
+
//-----------------------------------------------------------------------------
// [SECTION] ImDrawData
//-----------------------------------------------------------------------------
@@ -1382,7 +1434,7 @@ ImFontConfig::ImFontConfig()
//-----------------------------------------------------------------------------
// A work of art lies ahead! (. = white layer, X = black layer, others are blank)
-// The white texels on the top left are the ones we'll use everywhere in ImGui to render filled shapes.
+// The white texels on the top left are the ones we'll use everywhere in Dear ImGui to render filled shapes.
const int FONT_ATLAS_DEFAULT_TEX_DATA_W_HALF = 108;
const int FONT_ATLAS_DEFAULT_TEX_DATA_H = 27;
const unsigned int FONT_ATLAS_DEFAULT_TEX_DATA_ID = 0x80000000;
@@ -1779,7 +1831,7 @@ static void UnpackBoolVectorToFlatIndexList(const ImBoolVector* in, ImVector<int
for (const int* it = it_begin; it < it_end; it++)
if (int entries_32 = *it)
for (int bit_n = 0; bit_n < 32; bit_n++)
- if (entries_32 & (1 << bit_n))
+ if (entries_32 & (1u << bit_n))
out->push_back((int)((it - it_begin) << 5) + bit_n);
}
@@ -2391,11 +2443,12 @@ void ImFontGlyphRangesBuilder::AddRanges(const ImWchar* ranges)
void ImFontGlyphRangesBuilder::BuildRanges(ImVector<ImWchar>* out_ranges)
{
- for (int n = 0; n < 0x10000; n++)
+ int max_codepoint = 0x10000;
+ for (int n = 0; n < max_codepoint; n++)
if (GetBit(n))
{
out_ranges->push_back((ImWchar)n);
- while (n < 0x10000 && GetBit(n + 1))
+ while (n < max_codepoint - 1 && GetBit(n + 1))
n++;
out_ranges->push_back((ImWchar)n);
}
@@ -2765,7 +2818,7 @@ void ImFont::RenderChar(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col, const ImVec4& clip_rect, const char* text_begin, const char* text_end, float wrap_width, bool cpu_fine_clip) const
{
if (!text_end)
- text_end = text_begin + strlen(text_begin); // ImGui functions generally already provides a valid text_end, so this is merely to handle direct calls.
+ text_end = text_begin + strlen(text_begin); // ImGui:: functions generally already provides a valid text_end, so this is merely to handle direct calls.
// Align to be pixel perfect
pos.x = (float)(int)pos.x + DisplayOffset.x;
@@ -2948,7 +3001,7 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
draw_list->CmdBuffer[draw_list->CmdBuffer.Size-1].ElemCount -= (idx_expected_size - draw_list->IdxBuffer.Size);
draw_list->_VtxWritePtr = vtx_write;
draw_list->_IdxWritePtr = idx_write;
- draw_list->_VtxCurrentIdx = (unsigned int)draw_list->VtxBuffer.Size;
+ draw_list->_VtxCurrentIdx = vtx_current_idx;
}
//-----------------------------------------------------------------------------
@@ -3071,7 +3124,7 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im
// FIXME: Rendering an ellipsis "..." is a surprisingly tricky problem for us... we cannot rely on font glyph having it,
// and regular dot are typically too wide. If we render a dot/shape ourselves it comes with the risk that it wouldn't match
// the boldness or positioning of what the font uses...
-void ImGui::RenderPixelEllipsis(ImDrawList* draw_list, ImVec2 pos, int count, ImU32 col)
+void ImGui::RenderPixelEllipsis(ImDrawList* draw_list, ImVec2 pos, ImU32 col, int count)
{
ImFont* font = draw_list->_Data->Font;
const float font_scale = draw_list->_Data->FontSize / font->FontSize;
diff --git a/imgui/imgui_internal.h b/imgui/imgui_internal.h
index cc98c20b..f82225e3 100644
--- a/imgui/imgui_internal.h
+++ b/imgui/imgui_internal.h
@@ -1,4 +1,4 @@
-// dear imgui, v1.70
+// dear imgui, v1.71
// (internal structures/api)
// You may use this file to debug, understand or extend ImGui features but we don't provide any guarantee of forward compatibility!
@@ -36,15 +36,17 @@ Index of this file:
#include <math.h> // sqrtf, fabsf, fmodf, powf, floorf, ceilf, cosf, sinf
#include <limits.h> // INT_MIN, INT_MAX
+// Visual Studio warnings
#ifdef _MSC_VER
#pragma warning (push)
#pragma warning (disable: 4251) // class 'xxx' needs to have dll-interface to be used by clients of struct 'xxx' // when IMGUI_API is set to__declspec(dllexport)
#endif
-#ifdef __clang__
+// Clang/GCC warnings with -Weverything
+#if defined(__clang__)
#pragma clang diagnostic push
-#pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h
-#pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h
+#pragma clang diagnostic ignored "-Wunused-function" // for stb_textedit.h
+#pragma clang diagnostic ignored "-Wmissing-prototypes" // for stb_textedit.h
#pragma clang diagnostic ignored "-Wold-style-cast"
#if __has_warning("-Wzero-as-null-pointer-constant")
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
@@ -52,6 +54,11 @@ Index of this file:
#if __has_warning("-Wdouble-promotion")
#pragma clang diagnostic ignored "-Wdouble-promotion"
#endif
+#elif defined(__GNUC__)
+#pragma GCC diagnostic push
+#if __GNUC__ >= 8
+#pragma GCC diagnostic ignored "-Wclass-memaccess" // warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
+#endif
#endif
//-----------------------------------------------------------------------------
@@ -64,14 +71,15 @@ struct ImDrawListSharedData; // Data shared between all ImDrawList instan
struct ImGuiColorMod; // Stacked color modifier, backup of modified data so we can restore it
struct ImGuiColumnData; // Storage data for a single column
struct ImGuiColumns; // Storage data for a columns set
-struct ImGuiContext; // Main imgui context
+struct ImGuiContext; // Main Dear ImGui context
struct ImGuiDataTypeInfo; // Type information associated to a ImGuiDataType enum
struct ImGuiGroupData; // Stacked storage data for BeginGroup()/EndGroup()
struct ImGuiInputTextState; // Internal state of the currently focused/edited text input box
struct ImGuiItemHoveredDataBackup; // Backup and restore IsItemHovered() internal data
struct ImGuiMenuColumns; // Simple column measurement, currently used for MenuItem() only
struct ImGuiNavMoveResult; // Result of a directional navigation move query result
-struct ImGuiNextWindowData; // Storage for SetNexWindow** functions
+struct ImGuiNextWindowData; // Storage for SetNextWindow** functions
+struct ImGuiNextItemData; // Storage for SetNextItem** functions
struct ImGuiPopupData; // Storage for current popup stack
struct ImGuiSettingsHandler; // Storage for one type registered in the .ini file
struct ImGuiStyleMod; // Stacked style modifier, backup of modified data so we can restore it
@@ -82,17 +90,19 @@ struct ImGuiWindowTempData; // Temporary storage for one window (that's
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)
// Use your programming IDE "Go to definition" facility on the names of the center columns to find the actual flags/enum lists.
-typedef int ImGuiLayoutType; // -> enum ImGuiLayoutType_ // Enum: Horizontal or vertical
-typedef int ImGuiButtonFlags; // -> enum ImGuiButtonFlags_ // Flags: for ButtonEx(), ButtonBehavior()
-typedef int ImGuiDragFlags; // -> enum ImGuiDragFlags_ // Flags: for DragBehavior()
-typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag()
-typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for DC.LastItemStatusFlags
-typedef int ImGuiNavHighlightFlags; // -> enum ImGuiNavHighlightFlags_ // Flags: for RenderNavHighlight()
-typedef int ImGuiNavDirSourceFlags; // -> enum ImGuiNavDirSourceFlags_ // Flags: for GetNavInputAmount2d()
-typedef int ImGuiNavMoveFlags; // -> enum ImGuiNavMoveFlags_ // Flags: for navigation requests
-typedef int ImGuiSeparatorFlags; // -> enum ImGuiSeparatorFlags_ // Flags: for Separator() - internal
-typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags: for SliderBehavior()
-typedef int ImGuiTextFlags; // -> enum ImGuiTextFlags_ // Flags: for TextEx()
+typedef int ImGuiLayoutType; // -> enum ImGuiLayoutType_ // Enum: Horizontal or vertical
+typedef int ImGuiButtonFlags; // -> enum ImGuiButtonFlags_ // Flags: for ButtonEx(), ButtonBehavior()
+typedef int ImGuiDragFlags; // -> enum ImGuiDragFlags_ // Flags: for DragBehavior()
+typedef int ImGuiItemFlags; // -> enum ImGuiItemFlags_ // Flags: for PushItemFlag()
+typedef int ImGuiItemStatusFlags; // -> enum ImGuiItemStatusFlags_ // Flags: for DC.LastItemStatusFlags
+typedef int ImGuiNavHighlightFlags; // -> enum ImGuiNavHighlightFlags_ // Flags: for RenderNavHighlight()
+typedef int ImGuiNavDirSourceFlags; // -> enum ImGuiNavDirSourceFlags_ // Flags: for GetNavInputAmount2d()
+typedef int ImGuiNavMoveFlags; // -> enum ImGuiNavMoveFlags_ // Flags: for navigation requests
+typedef int ImGuiNextItemDataFlags; // -> enum ImGuiNextItemDataFlags_ // Flags: for SetNextItemXXX() functions
+typedef int ImGuiNextWindowDataFlags; // -> enum ImGuiNextWindowDataFlags_// Flags: for SetNextWindowXXX() functions
+typedef int ImGuiSeparatorFlags; // -> enum ImGuiSeparatorFlags_ // Flags: for SeparatorEx()
+typedef int ImGuiSliderFlags; // -> enum ImGuiSliderFlags_ // Flags: for SliderBehavior()
+typedef int ImGuiTextFlags; // -> enum ImGuiTextFlags_ // Flags: for TextEx()
//-------------------------------------------------------------------------
// STB libraries includes
@@ -117,7 +127,7 @@ namespace ImStb
//-----------------------------------------------------------------------------
#ifndef GImGui
-extern IMGUI_API ImGuiContext* GImGui; // Current implicit ImGui context pointer
+extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer
#endif
//-----------------------------------------------------------------------------
@@ -340,21 +350,29 @@ enum ImGuiColumnsFlags_
ImGuiColumnsFlags_GrowParentContentsSize= 1 << 4 // (WIP) Restore pre-1.51 behavior of extending the parent window contents size but _without affecting the columns width at all_. Will eventually remove.
};
+// Extend ImGuiSelectableFlags_
enum ImGuiSelectableFlagsPrivate_
{
// NB: need to be in sync with last value of ImGuiSelectableFlags_
- ImGuiSelectableFlags_NoHoldingActiveID = 1 << 10,
- ImGuiSelectableFlags_PressedOnClick = 1 << 11,
- ImGuiSelectableFlags_PressedOnRelease = 1 << 12,
- ImGuiSelectableFlags_DrawFillAvailWidth = 1 << 13, // FIXME: We may be able to remove this (added in 6251d379 for menus)
- ImGuiSelectableFlags_AllowItemOverlap = 1 << 14
+ ImGuiSelectableFlags_NoHoldingActiveID = 1 << 20,
+ ImGuiSelectableFlags_PressedOnClick = 1 << 21,
+ ImGuiSelectableFlags_PressedOnRelease = 1 << 22,
+ ImGuiSelectableFlags_DrawFillAvailWidth = 1 << 23, // FIXME: We may be able to remove this (added in 6251d379 for menus)
+ ImGuiSelectableFlags_AllowItemOverlap = 1 << 24
+};
+
+// Extend ImGuiTreeNodeFlags_
+enum ImGuiTreeNodeFlagsPrivate_
+{
+ ImGuiTreeNodeFlags_ClipLabelForTrailingButton = 1 << 20
};
enum ImGuiSeparatorFlags_
{
ImGuiSeparatorFlags_None = 0,
ImGuiSeparatorFlags_Horizontal = 1 << 0, // Axis default to current layout type, so generally Horizontal unless e.g. in a menu bar
- ImGuiSeparatorFlags_Vertical = 1 << 1
+ ImGuiSeparatorFlags_Vertical = 1 << 1,
+ ImGuiSeparatorFlags_SpanAllColumns = 1 << 2
};
// Transient per-window flags, reset at the beginning of the frame. For child window, inherited from parent on first Begin().
@@ -377,7 +395,9 @@ enum ImGuiItemStatusFlags_
ImGuiItemStatusFlags_HoveredRect = 1 << 0,
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_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_Deactivated = 1 << 5 // Only valid if ImGuiItemStatusFlags_HasDeactivated is set.
#ifdef IMGUI_ENABLE_TEST_ENGINE
, // [imgui-test only]
@@ -570,11 +590,11 @@ struct ImGuiGroupData
ImVec2 BackupCursorMaxPos;
ImVec1 BackupIndent;
ImVec1 BackupGroupOffset;
- ImVec2 BackupCurrentLineSize;
- float BackupCurrentLineTextBaseOffset;
+ ImVec2 BackupCurrLineSize;
+ float BackupCurrLineTextBaseOffset;
ImGuiID BackupActiveIdIsAlive;
bool BackupActiveIdPreviousFrameIsAlive;
- bool AdvanceCursor;
+ bool EmitItem;
};
// Simple column measurement, currently used for MenuItem() only.. This is very short-sighted/throw-away code and NOT a generic helper.
@@ -679,10 +699,11 @@ struct ImGuiColumns
bool IsBeingResized;
int Current;
int Count;
- float MinX, MaxX;
+ float OffMinX, OffMaxX; // Offsets from HostWorkRect.Min.x
float LineMinY, LineMaxY;
- float BackupCursorPosY; // Backup of CursorPos at the time of BeginColumns()
- float BackupCursorMaxPosX; // Backup of CursorMaxPos at the time of BeginColumns()
+ float HostCursorPosY; // Backup of CursorPos at the time of BeginColumns()
+ float HostCursorMaxPosX; // Backup of CursorMaxPos at the time of BeginColumns()
+ ImRect HostClipRect; // Backup of ClipRect at the time of BeginColumns()
ImVector<ImGuiColumnData> Columns;
ImGuiColumns() { Clear(); }
@@ -694,10 +715,10 @@ struct ImGuiColumns
IsBeingResized = false;
Current = 0;
Count = 1;
- MinX = MaxX = 0.0f;
+ OffMinX = OffMaxX = 0.0f;
LineMinY = LineMaxY = 0.0f;
- BackupCursorPosY = 0.0f;
- BackupCursorMaxPosX = 0.0f;
+ HostCursorPosY = 0.0f;
+ HostCursorMaxPosX = 0.0f;
Columns.clear();
}
};
@@ -710,6 +731,7 @@ struct IMGUI_API ImDrawListSharedData
float FontSize; // Current/default font size (optional, for simplified AddText overload)
float CurveTessellationTol;
ImVec4 ClipRectFullscreen; // Value for PushClipRectFullscreen()
+ ImDrawListFlags InitialFlags; // Initial flags at the beginning of the frame (it is possible to alter flags on a per-drawlist basis afterwards)
// Const data
// FIXME: Bake rounded corners fill/borders in atlas
@@ -741,51 +763,63 @@ struct ImGuiNavMoveResult
void Clear() { ID = SelectScopeId = 0; Window = NULL; DistBox = DistCenter = DistAxial = FLT_MAX; RectRel = ImRect(); }
};
+enum ImGuiNextWindowDataFlags_
+{
+ ImGuiNextWindowDataFlags_None = 0,
+ ImGuiNextWindowDataFlags_HasPos = 1 << 0,
+ ImGuiNextWindowDataFlags_HasSize = 1 << 1,
+ ImGuiNextWindowDataFlags_HasContentSize = 1 << 2,
+ ImGuiNextWindowDataFlags_HasCollapsed = 1 << 3,
+ ImGuiNextWindowDataFlags_HasSizeConstraint = 1 << 4,
+ ImGuiNextWindowDataFlags_HasFocus = 1 << 5,
+ ImGuiNextWindowDataFlags_HasBgAlpha = 1 << 6
+};
+
// Storage for SetNexWindow** functions
struct ImGuiNextWindowData
{
- ImGuiCond PosCond;
- ImGuiCond SizeCond;
- ImGuiCond ContentSizeCond;
- ImGuiCond CollapsedCond;
- ImGuiCond SizeConstraintCond;
- ImGuiCond FocusCond;
- ImGuiCond BgAlphaCond;
- ImVec2 PosVal;
- ImVec2 PosPivotVal;
- ImVec2 SizeVal;
- ImVec2 ContentSizeVal;
- bool CollapsedVal;
- ImRect SizeConstraintRect;
- ImGuiSizeCallback SizeCallback;
- void* SizeCallbackUserData;
- float BgAlphaVal;
- ImVec2 MenuBarOffsetMinVal; // This is not exposed publicly, so we don't clear it.
-
- ImGuiNextWindowData()
- {
- PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = 0;
- PosVal = PosPivotVal = SizeVal = ImVec2(0.0f, 0.0f);
- ContentSizeVal = ImVec2(0.0f, 0.0f);
- CollapsedVal = false;
- SizeConstraintRect = ImRect();
- SizeCallback = NULL;
- SizeCallbackUserData = NULL;
- BgAlphaVal = FLT_MAX;
- MenuBarOffsetMinVal = ImVec2(0.0f, 0.0f);
- }
+ ImGuiNextWindowDataFlags Flags;
+ ImGuiCond PosCond;
+ ImGuiCond SizeCond;
+ ImGuiCond CollapsedCond;
+ ImVec2 PosVal;
+ ImVec2 PosPivotVal;
+ ImVec2 SizeVal;
+ ImVec2 ContentSizeVal;
+ bool CollapsedVal;
+ ImRect SizeConstraintRect;
+ ImGuiSizeCallback SizeCallback;
+ void* SizeCallbackUserData;
+ float BgAlphaVal;
+ ImVec2 MenuBarOffsetMinVal; // *Always on* This is not exposed publicly, so we don't clear it.
+
+ ImGuiNextWindowData() { memset(this, 0, sizeof(*this)); }
+ inline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; }
+};
- void Clear()
- {
- PosCond = SizeCond = ContentSizeCond = CollapsedCond = SizeConstraintCond = FocusCond = BgAlphaCond = 0;
- }
+enum ImGuiNextItemDataFlags_
+{
+ ImGuiNextItemDataFlags_None = 0,
+ ImGuiNextItemDataFlags_HasWidth = 1 << 0,
+ ImGuiNextItemDataFlags_HasOpen = 1 << 1
+};
+
+struct ImGuiNextItemData
+{
+ ImGuiNextItemDataFlags Flags;
+ float Width; // Set by SetNextItemWidth().
+ bool OpenVal; // Set by SetNextItemOpen() function.
+ ImGuiCond OpenCond;
+
+ ImGuiNextItemData() { memset(this, 0, sizeof(*this)); }
+ inline void ClearFlags() { Flags = ImGuiNextItemDataFlags_None; }
};
//-----------------------------------------------------------------------------
// Tabs
//-----------------------------------------------------------------------------
-struct ImGuiTabBarSortItem
+struct ImGuiShrinkWidthItem
{
int Index;
float Width;
@@ -816,11 +850,12 @@ struct ImGuiContext
float FontSize; // (Shortcut) == FontBaseSize * g.CurrentWindow->FontWindowScale == window->FontSize(). Text height for current window.
float FontBaseSize; // (Shortcut) == IO.FontGlobalScale * Font->Scale * Font->FontSize. Base text height.
ImDrawListSharedData DrawListSharedData;
-
double Time;
int FrameCount;
int FrameCountEnded;
int FrameCountRendered;
+
+ // Windows state
ImVector<ImGuiWindow*> Windows; // Windows, sorted in display order, back to front
ImVector<ImGuiWindow*> WindowsFocusOrder; // Windows, sorted in focus order, back to front
ImVector<ImGuiWindow*> WindowsSortBuffer;
@@ -830,39 +865,45 @@ struct ImGuiContext
ImGuiWindow* CurrentWindow; // Being drawn into
ImGuiWindow* HoveredWindow; // Will catch mouse inputs
ImGuiWindow* HoveredRootWindow; // Will catch mouse inputs (for focus/move only)
+ ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actually window that is moved is generally MovingWindow->RootWindow.
+
+ // Item/widgets state and tracking information
ImGuiID HoveredId; // Hovered widget
bool HoveredIdAllowOverlap;
ImGuiID HoveredIdPreviousFrame;
float HoveredIdTimer; // Measure contiguous hovering time
float HoveredIdNotActiveTimer; // Measure contiguous hovering time where the item has not been active
ImGuiID ActiveId; // Active widget
- ImGuiID ActiveIdPreviousFrame;
ImGuiID ActiveIdIsAlive; // Active widget has been seen this frame (we can't use a bool as the ActiveId may change within the frame)
float ActiveIdTimer;
bool ActiveIdIsJustActivated; // Set at the time of activation for one frame
bool ActiveIdAllowOverlap; // Active widget allows another widget to steal active id (generally for overlapping widgets, but not always)
- bool ActiveIdHasBeenPressed; // Track whether the active id led to a press (this is to allow changing between PressOnClick and PressOnRelease without pressing twice). Used by range_select branch.
- bool ActiveIdHasBeenEdited; // Was the value associated to the widget Edited over the course of the Active state.
- bool ActiveIdPreviousFrameIsAlive;
- bool ActiveIdPreviousFrameHasBeenEdited;
+ bool ActiveIdHasBeenPressedBefore; // Track whether the active id led to a press (this is to allow changing between PressOnClick and PressOnRelease without pressing twice). Used by range_select branch.
+ bool ActiveIdHasBeenEditedBefore; // Was the value associated to the widget Edited over the course of the Active state.
+ bool ActiveIdHasBeenEditedThisFrame;
int ActiveIdAllowNavDirFlags; // Active widget allows using directional navigation (e.g. can activate a button and move away from it)
int ActiveIdBlockNavInputFlags;
ImVec2 ActiveIdClickOffset; // Clicked offset from upper-left corner, if applicable (currently only set by ButtonBehavior)
ImGuiWindow* ActiveIdWindow;
- ImGuiWindow* ActiveIdPreviousFrameWindow;
ImGuiInputSource ActiveIdSource; // Activating with mouse or nav (gamepad/keyboard)
+ ImGuiID ActiveIdPreviousFrame;
+ bool ActiveIdPreviousFrameIsAlive;
+ bool ActiveIdPreviousFrameHasBeenEditedBefore;
+ ImGuiWindow* ActiveIdPreviousFrameWindow;
+
ImGuiID LastActiveId; // Store the last non-zero ActiveId, useful for animation.
float LastActiveIdTimer; // Store the last non-zero ActiveId timer since the beginning of activation, useful for animation.
- ImVec2 LastValidMousePos;
- ImGuiWindow* MovingWindow; // Track the window we clicked on (in order to preserve focus). The actually window that is moved is generally MovingWindow->RootWindow.
+
+ // Next window/item data
+ ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions
+ ImGuiNextItemData NextItemData; // Storage for SetNextItem** functions
+
+ // Shared stacks
ImVector<ImGuiColorMod> ColorModifiers; // Stack for PushStyleColor()/PopStyleColor()
ImVector<ImGuiStyleMod> StyleModifiers; // Stack for PushStyleVar()/PopStyleVar()
ImVector<ImFont*> FontStack; // Stack for PushFont()/PopFont()
ImVector<ImGuiPopupData>OpenPopupStack; // Which popups are open (persistent)
ImVector<ImGuiPopupData>BeginPopupStack; // Which level of BeginPopup() we are in (reset every frame)
- ImGuiNextWindowData NextWindowData; // Storage for SetNextWindow** functions
- bool NextTreeNodeOpenVal; // Storage for SetNextTreeNode** functions
- ImGuiCond NextTreeNodeOpenCond;
// Navigation data (for gamepad/keyboard)
ImGuiWindow* NavWindow; // Focused window for navigation. Could be called 'FocusWindow'
@@ -943,9 +984,10 @@ struct ImGuiContext
ImPool<ImGuiTabBar> TabBars;
ImGuiTabBar* CurrentTabBar;
ImVector<ImGuiTabBarRef> CurrentTabBarStack;
- ImVector<ImGuiTabBarSortItem> TabSortByWidthBuffer;
+ ImVector<ImGuiShrinkWidthItem> ShrinkWidthBuffer;
// Widget state
+ ImVec2 LastValidMousePos;
ImGuiInputTextState InputTextState;
ImFont InputTextPasswordFont;
ImGuiID TempInputTextId; // Temporary text input when CTRL+clicking on a slider, etc.
@@ -954,7 +996,7 @@ struct ImGuiContext
bool DragCurrentAccumDirty;
float DragCurrentAccum; // Accumulator for dragging modification. Always high-precision, not rounded by end-user precision settings
float DragSpeedDefaultRatio; // If speed == 0.0f, uses (max-min) * DragSpeedDefaultRatio
- ImVec2 ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage?
+ float ScrollbarClickDeltaToGrabCenter; // Distance between mouse and center of grab box, normalized in parent space. Use storage?
int TooltipOverrideCount;
ImVector<char> PrivateClipboard; // If no custom clipboard handler is defined
@@ -993,7 +1035,7 @@ struct ImGuiContext
int WantTextInputNextFrame;
char TempBuffer[1024*3+1]; // Temporary text buffer
- ImGuiContext(ImFontAtlas* shared_font_atlas) : BackgroundDrawList(NULL), ForegroundDrawList(NULL)
+ ImGuiContext(ImFontAtlas* shared_font_atlas) : BackgroundDrawList(&DrawListSharedData), ForegroundDrawList(&DrawListSharedData)
{
Initialized = false;
FrameScopeActive = FrameScopePushedImplicitWindow = false;
@@ -1001,39 +1043,41 @@ struct ImGuiContext
FontSize = FontBaseSize = 0.0f;
FontAtlasOwnedByContext = shared_font_atlas ? false : true;
IO.Fonts = shared_font_atlas ? shared_font_atlas : IM_NEW(ImFontAtlas)();
-
Time = 0.0f;
FrameCount = 0;
FrameCountEnded = FrameCountRendered = -1;
+
WindowsActiveCount = 0;
CurrentWindow = NULL;
HoveredWindow = NULL;
HoveredRootWindow = NULL;
+ MovingWindow = NULL;
+
HoveredId = 0;
HoveredIdAllowOverlap = false;
HoveredIdPreviousFrame = 0;
HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f;
ActiveId = 0;
- ActiveIdPreviousFrame = 0;
ActiveIdIsAlive = 0;
ActiveIdTimer = 0.0f;
ActiveIdIsJustActivated = false;
ActiveIdAllowOverlap = false;
- ActiveIdHasBeenPressed = false;
- ActiveIdHasBeenEdited = false;
- ActiveIdPreviousFrameIsAlive = false;
- ActiveIdPreviousFrameHasBeenEdited = false;
+ ActiveIdHasBeenPressedBefore = false;
+ ActiveIdHasBeenEditedBefore = false;
+ ActiveIdHasBeenEditedThisFrame = false;
ActiveIdAllowNavDirFlags = 0x00;
ActiveIdBlockNavInputFlags = 0x00;
ActiveIdClickOffset = ImVec2(-1,-1);
- ActiveIdWindow = ActiveIdPreviousFrameWindow = NULL;
+ ActiveIdWindow = NULL;
ActiveIdSource = ImGuiInputSource_None;
+
+ ActiveIdPreviousFrame = 0;
+ ActiveIdPreviousFrameIsAlive = false;
+ ActiveIdPreviousFrameHasBeenEditedBefore = false;
+ ActiveIdPreviousFrameWindow = NULL;
+
LastActiveId = 0;
LastActiveIdTimer = 0.0f;
- LastValidMousePos = ImVec2(0.0f, 0.0f);
- MovingWindow = NULL;
- NextTreeNodeOpenVal = false;
- NextTreeNodeOpenCond = 0;
NavWindow = NULL;
NavId = NavActivateId = NavActivateDownId = NavActivatePressedId = NavInputId = 0;
@@ -1066,9 +1110,7 @@ struct ImGuiContext
FocusTabPressed = false;
DimBgRatio = 0.0f;
- BackgroundDrawList._Data = &DrawListSharedData;
BackgroundDrawList._OwnerName = "##Background"; // Give it a name for debugging
- ForegroundDrawList._Data = &DrawListSharedData;
ForegroundDrawList._OwnerName = "##Foreground"; // Give it a name for debugging
MouseCursor = ImGuiMouseCursor_Arrow;
@@ -1085,12 +1127,13 @@ struct ImGuiContext
CurrentTabBar = NULL;
+ LastValidMousePos = ImVec2(0.0f, 0.0f);
TempInputTextId = 0;
ColorEditOptions = ImGuiColorEditFlags__OptionsDefault;
DragCurrentAccumDirty = false;
DragCurrentAccum = 0.0f;
DragSpeedDefaultRatio = 1.0f / 100.0f;
- ScrollbarClickDeltaToGrabCenter = ImVec2(0.0f, 0.0f);
+ ScrollbarClickDeltaToGrabCenter = 0.0f;
TooltipOverrideCount = 0;
MultiSelectScopeId = 0;
@@ -1127,10 +1170,10 @@ struct IMGUI_API ImGuiWindowTempData
ImVec2 CursorPos;
ImVec2 CursorPosPrevLine;
ImVec2 CursorStartPos; // Initial position in client area with padding
- ImVec2 CursorMaxPos; // Used to implicitly calculate the size of our contents, always growing during the frame. Turned into window->SizeContents at the beginning of next frame
- ImVec2 CurrentLineSize;
- float CurrentLineTextBaseOffset;
+ ImVec2 CursorMaxPos; // Used to implicitly calculate the size of our contents, always growing during the frame. Used to calculate window->ContentSize at the beginning of next frame
+ ImVec2 CurrLineSize;
ImVec2 PrevLineSize;
+ float CurrLineTextBaseOffset;
float PrevLineTextBaseOffset;
int TreeDepth;
ImU32 TreeStoreMayJumpToParentOnPop; // Store a copy of !g.NavIdIsAlive for TreeDepth 0..31.. Could be turned into a ImU64 if necessary.
@@ -1156,7 +1199,6 @@ struct IMGUI_API ImGuiWindowTempData
// We store the current settings outside of the vectors to increase memory locality (reduce cache misses). The vectors are rarely modified. Also it allows us to not heap allocate for short-lived windows which are not using those settings.
ImGuiItemFlags ItemFlags; // == ItemFlagsStack.back() [empty == ImGuiItemFlags_Default]
float ItemWidth; // == ItemWidthStack.back(). 0.0: default, >0.0: width in pixels, <0.0: align xx pixels to the right of window
- float NextItemWidth;
float TextWrapPos; // == TextWrapPosStack.back() [empty == -1.0f]
ImVector<ImGuiItemFlags>ItemFlagsStack;
ImVector<float> ItemWidthStack;
@@ -1172,8 +1214,8 @@ struct IMGUI_API ImGuiWindowTempData
ImGuiWindowTempData()
{
CursorPos = CursorPosPrevLine = CursorStartPos = CursorMaxPos = ImVec2(0.0f, 0.0f);
- CurrentLineSize = PrevLineSize = ImVec2(0.0f, 0.0f);
- CurrentLineTextBaseOffset = PrevLineTextBaseOffset = 0.0f;
+ CurrLineSize = PrevLineSize = ImVec2(0.0f, 0.0f);
+ CurrLineTextBaseOffset = PrevLineTextBaseOffset = 0.0f;
TreeDepth = 0;
TreeStoreMayJumpToParentOnPop = 0x00;
LastItemId = 0;
@@ -1192,7 +1234,6 @@ struct IMGUI_API ImGuiWindowTempData
ItemFlags = ImGuiItemFlags_Default_;
ItemWidth = 0.0f;
- NextItemWidth = +FLT_MAX;
TextWrapPos = -1.0f;
memset(StackSizesBackup, 0, sizeof(StackSizesBackup));
@@ -1212,9 +1253,8 @@ struct IMGUI_API ImGuiWindow
ImVec2 Pos; // Position (always rounded-up to nearest pixel)
ImVec2 Size; // Current size (==SizeFull or collapsed title bar size)
ImVec2 SizeFull; // Size when non collapsed
- ImVec2 SizeFullAtLastBegin; // Copy of SizeFull at the end of Begin. This is the reference value we'll use on the next frame to decide if we need scrollbars.
- ImVec2 SizeContents; // Size of contents (== extents reach of the drawing cursor) from previous frame. Include decoration, window title, border, menu, etc.
- ImVec2 SizeContentsExplicit; // Size of contents explicitly set by the user via SetNextWindowContentSize()
+ ImVec2 ContentSize; // Size of contents/scrollable client area (calculated from the extents reach of the cursor) from previous frame. Does not include window decoration or window padding.
+ ImVec2 ContentSizeExplicit; // Size of contents/scrollable client area explicitly request by the user via SetNextWindowContentSize().
ImVec2 WindowPadding; // Window padding at the time of begin.
float WindowRounding; // Window rounding at the time of begin.
float WindowBorderSize; // Window border size at the time of begin.
@@ -1222,6 +1262,7 @@ struct IMGUI_API ImGuiWindow
ImGuiID MoveId; // == window->GetID("#MOVE")
ImGuiID ChildId; // ID of corresponding item in parent window (for navigation to return from child window to parent window)
ImVec2 Scroll;
+ ImVec2 ScrollMax;
ImVec2 ScrollTarget; // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (FLT_MAX for no change)
ImVec2 ScrollTargetCenterRatio; // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered
ImVec2 ScrollbarSizes; // Size taken by scrollbars on each axis
@@ -1254,10 +1295,16 @@ struct IMGUI_API ImGuiWindow
ImGuiWindowTempData DC; // Temporary per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the "DC" variable name.
ImVector<ImGuiID> IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack
- ImRect ClipRect; // Current clipping rectangle. = DrawList->clip_rect_stack.back(). Scissoring / clipping rectangle. x1, y1, x2, y2.
- ImRect OuterRectClipped; // = WindowRect just after setup in Begin(). == window->Rect() for root window.
- ImRect InnerMainRect, InnerClipRect;
- ImRect ContentsRegionRect; // FIXME: This is currently confusing/misleading. Maximum visible content position ~~ Pos + (SizeContentsExplicit ? SizeContentsExplicit : Size - ScrollbarSizes) - CursorStartPos, per axis
+
+ // The best way to understand what those rectangles are is to use the 'Metrics -> Tools -> Show windows rectangles' viewer.
+ // The main 'OuterRect', omitted as a field, is window->Rect().
+ ImRect OuterRectClipped; // == Window->Rect() just after setup in Begin(). == window->Rect() for root window.
+ ImRect InnerRect; // Inner rectangle (omit title bar, menu bar)
+ ImRect InnerClipRect; // == InnerRect shrunk by WindowPadding*0.5f on each side, clipped within viewport or parent clip rect.
+ ImRect WorkRect; // Cover the whole scrolling region, shrunk by WindowPadding*1.0f on each side. This is meant to replace ContentsRegionRect over time (from 1.71+ onward).
+ ImRect ClipRect; // Current clipping/scissoring rectangle, evolve as we are using PushClipRect(), etc. == DrawList->clip_rect_stack.back().
+ ImRect ContentsRegionRect; // FIXME: This is currently confusing/misleading. It is essentially WorkRect but not handling of scrolling. We currently rely on it as right/bottom aligned sizing operation need some size to rely on.
+
int LastFrameActive; // Last frame number the window was Active.
float ItemWidthDefault;
ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items
@@ -1283,8 +1330,10 @@ public:
ImGuiID GetID(const char* str, const char* str_end = NULL);
ImGuiID GetID(const void* ptr);
+ ImGuiID GetID(int n);
ImGuiID GetIDNoKeepAlive(const char* str, const char* str_end = NULL);
ImGuiID GetIDNoKeepAlive(const void* ptr);
+ ImGuiID GetIDNoKeepAlive(int n);
ImGuiID GetIDFromRectangle(const ImRect& r_abs);
// We don't use g.FontSize because the window may be != g.CurrentWidow.
@@ -1313,6 +1362,7 @@ struct ImGuiItemHoveredDataBackup
// Tab bar, tab item
//-----------------------------------------------------------------------------
+// Extend ImGuiTabBarFlags_
enum ImGuiTabBarFlagsPrivate_
{
ImGuiTabBarFlags_DockNode = 1 << 20, // Part of a dock node [we don't use this in the master branch but it facilitate branch syncing to keep this around]
@@ -1320,6 +1370,7 @@ enum ImGuiTabBarFlagsPrivate_
ImGuiTabBarFlags_SaveSettings = 1 << 22 // FIXME: Settings are handled by the docking system, this only request the tab bar to mark settings dirty when reordering tabs
};
+// Extend ImGuiTabItemFlags_
enum ImGuiTabItemFlagsPrivate_
{
ImGuiTabItemFlags_NoCloseButton = 1 << 20 // Store whether p_open is set or not, which we need to recompute WidthContents during layout.
@@ -1402,12 +1453,10 @@ namespace ImGui
IMGUI_API bool IsWindowNavFocusable(ImGuiWindow* window);
IMGUI_API void SetWindowScrollX(ImGuiWindow* window, float new_scroll_x);
IMGUI_API void SetWindowScrollY(ImGuiWindow* window, float new_scroll_y);
- IMGUI_API float GetWindowScrollMaxX(ImGuiWindow* window);
- IMGUI_API float GetWindowScrollMaxY(ImGuiWindow* window);
IMGUI_API ImRect GetWindowAllowedExtentRect(ImGuiWindow* window);
- IMGUI_API void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond);
- IMGUI_API void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond);
- IMGUI_API void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond);
+ IMGUI_API void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond = 0);
+ IMGUI_API void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond = 0);
+ IMGUI_API void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond = 0);
IMGUI_API void SetCurrentFont(ImFont* font);
inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; }
@@ -1451,14 +1500,14 @@ namespace ImGui
IMGUI_API bool IsClippedEx(const ImRect& bb, ImGuiID id, bool clip_even_when_logged);
IMGUI_API bool FocusableItemRegister(ImGuiWindow* window, ImGuiID id); // Return true if focus is requested
IMGUI_API void FocusableItemUnregister(ImGuiWindow* window);
- IMGUI_API float GetNextItemWidth();
IMGUI_API ImVec2 CalcItemSize(ImVec2 size, float default_w, float default_h);
IMGUI_API float CalcWrapWidthForPos(const ImVec2& pos, float wrap_pos_x);
IMGUI_API void PushMultiItemsWidths(int components, float width_full);
IMGUI_API void PushItemFlag(ImGuiItemFlags option, bool enabled);
IMGUI_API void PopItemFlag();
- IMGUI_API bool IsItemToggledSelection(); // was the last item selection toggled? (after Selectable(), TreeNode() etc. We only returns toggle _event_ in order to handle clipping correctly)
- IMGUI_API ImVec2 GetWorkRectMax();
+ IMGUI_API bool IsItemToggledSelection(); // Was the last item selection toggled? (after Selectable(), TreeNode() etc. We only returns toggle _event_ in order to handle clipping correctly)
+ IMGUI_API ImVec2 GetContentRegionMaxAbs();
+ IMGUI_API void ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess);
// Logging/Capture
IMGUI_API void LogBegin(ImGuiLogType type, int auto_open_depth); // -> BeginCapture() when we design v2 api, for now stay under the radar by using the old name.
@@ -1502,7 +1551,9 @@ namespace ImGui
// New Columns API (FIXME-WIP)
IMGUI_API void BeginColumns(const char* str_id, int count, ImGuiColumnsFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns().
IMGUI_API void EndColumns(); // close columns
- IMGUI_API void PushColumnClipRect(int column_index = -1);
+ IMGUI_API void PushColumnClipRect(int column_index);
+ IMGUI_API void PushColumnsBackground();
+ IMGUI_API void PopColumnsBackground();
IMGUI_API ImGuiID GetColumnsID(const char* str_id, int count);
IMGUI_API ImGuiColumns* FindOrCreateColumns(ImGuiWindow* window, ImGuiID id);
@@ -1524,31 +1575,39 @@ namespace ImGui
IMGUI_API void RenderTextWrapped(ImVec2 pos, const char* text, const char* text_end, float wrap_width);
IMGUI_API void RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0,0), const ImRect* clip_rect = NULL);
IMGUI_API void RenderTextClippedEx(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, const char* text, const char* text_end, const ImVec2* text_size_if_known, const ImVec2& align = ImVec2(0, 0), const ImRect* clip_rect = NULL);
+ IMGUI_API void RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end, const ImVec2* text_size_if_known);
IMGUI_API void RenderFrame(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, bool border = true, float rounding = 0.0f);
IMGUI_API void RenderFrameBorder(ImVec2 p_min, ImVec2 p_max, float rounding = 0.0f);
IMGUI_API void RenderColorRectWithAlphaCheckerboard(ImVec2 p_min, ImVec2 p_max, ImU32 fill_col, float grid_step, ImVec2 grid_off, float rounding = 0.0f, int rounding_corners_flags = ~0);
- IMGUI_API void RenderArrow(ImVec2 pos, ImGuiDir dir, float scale = 1.0f);
- IMGUI_API void RenderBullet(ImVec2 pos);
IMGUI_API void RenderCheckMark(ImVec2 pos, ImU32 col, float sz);
IMGUI_API void RenderNavHighlight(const ImRect& bb, ImGuiID id, ImGuiNavHighlightFlags flags = ImGuiNavHighlightFlags_TypeDefault); // Navigation highlight
IMGUI_API const char* FindRenderedTextEnd(const char* text, const char* text_end = NULL); // Find the optional ## from which we stop displaying text.
IMGUI_API void LogRenderedText(const ImVec2* ref_pos, const char* text, const char* text_end = NULL);
// Render helpers (those functions don't access any ImGui state!)
+ IMGUI_API void RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale = 1.0f);
+ IMGUI_API void RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col);
IMGUI_API void RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor = ImGuiMouseCursor_Arrow);
IMGUI_API void RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col);
IMGUI_API void RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding);
- IMGUI_API void RenderPixelEllipsis(ImDrawList* draw_list, ImVec2 pos, int count, ImU32 col);
+ IMGUI_API void RenderPixelEllipsis(ImDrawList* draw_list, ImVec2 pos, ImU32 col, int count);
+
+#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+ // 2019/06/07: Updating prototypes of some of the internal functions. Leaving those for reference for a short while.
+ inline void RenderArrow(ImVec2 pos, ImGuiDir dir, float scale=1.0f) { ImGuiWindow* window = GetCurrentWindow(); RenderArrow(window->DrawList, pos, GetColorU32(ImGuiCol_Text), dir, scale); }
+ inline void RenderBullet(ImVec2 pos) { ImGuiWindow* window = GetCurrentWindow(); RenderBullet(window->DrawList, pos, GetColorU32(ImGuiCol_Text)); }
+#endif
// Widgets
IMGUI_API void TextEx(const char* text, const char* text_end = NULL, ImGuiTextFlags flags = 0);
IMGUI_API bool ButtonEx(const char* label, const ImVec2& size_arg = ImVec2(0,0), ImGuiButtonFlags flags = 0);
- IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos, float radius);
+ IMGUI_API bool CloseButton(ImGuiID id, const ImVec2& pos);
IMGUI_API bool CollapseButton(ImGuiID id, const ImVec2& pos);
IMGUI_API bool ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size_arg, ImGuiButtonFlags flags);
IMGUI_API void Scrollbar(ImGuiAxis axis);
+ IMGUI_API bool ScrollbarEx(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* p_scroll_v, float avail_v, float contents_v, ImDrawCornerFlags rounding_corners);
IMGUI_API ImGuiID GetScrollbarID(ImGuiWindow* window, ImGuiAxis axis);
- IMGUI_API void VerticalSeparator(); // Vertical separator, for menu bars (use current line height). Not exposed because it is misleading and it doesn't have an effect on regular layout.
+ IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags);
// Widgets low-level behaviors
IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0);
@@ -1556,7 +1615,7 @@ namespace ImGui
IMGUI_API bool SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type, void* v, const void* v_min, const void* v_max, const char* format, float power, ImGuiSliderFlags flags, ImRect* out_grab_bb);
IMGUI_API bool SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float* size1, float* size2, float min_size1, float min_size2, float hover_extend = 0.0f, float hover_visibility_delay = 0.0f);
IMGUI_API bool TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* label, const char* label_end = NULL);
- IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextTreeNodeOpened() data, if any. May return true when logging
+ IMGUI_API bool TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags = 0); // Consume previous SetNextItemOpen() data, if any. May return true when logging
IMGUI_API void TreePushOverrideID(ImGuiID id);
// Template functions are instantiated in imgui_widgets.cpp for a finite number of types.
@@ -1608,15 +1667,20 @@ extern void ImGuiTestEngineHook_PreNewFrame(ImGuiContext* ctx);
extern void ImGuiTestEngineHook_PostNewFrame(ImGuiContext* ctx);
extern void ImGuiTestEngineHook_ItemAdd(ImGuiContext* ctx, const ImRect& bb, ImGuiID id);
extern void ImGuiTestEngineHook_ItemInfo(ImGuiContext* ctx, ImGuiID id, const char* label, ImGuiItemStatusFlags flags);
-#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB, _ID) ImGuiTestEngineHook_ItemAdd(&g, _BB, _ID) // Register status flags
-#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register status flags
+extern void ImGuiTestEngineHook_Log(ImGuiContext* ctx, const char* fmt, ...);
+#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB, _ID) ImGuiTestEngineHook_ItemAdd(&g, _BB, _ID) // Register item bounding box
+#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) ImGuiTestEngineHook_ItemInfo(&g, _ID, _LABEL, _FLAGS) // Register item label and status flags (optional)
+#define IMGUI_TEST_ENGINE_LOG(_FMT, ...) ImGuiTestEngineHook_Log(&g, _FMT, __VA_ARGS__) // Custom log entry from user land into test log
#else
#define IMGUI_TEST_ENGINE_ITEM_ADD(_BB, _ID) do { } while (0)
-#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) do { } while (0)
+#define IMGUI_TEST_ENGINE_ITEM_INFO(_ID, _LABEL, _FLAGS) do { } while (0)
+#define IMGUI_TEST_ENGINE_LOG(_FMT, ...) do { } while (0)
#endif
-#ifdef __clang__
+#if defined(__clang__)
#pragma clang diagnostic pop
+#elif defined(__GNUC__)
+#pragma GCC diagnostic pop
#endif
#ifdef _MSC_VER
diff --git a/imgui/imgui_widgets.cpp b/imgui/imgui_widgets.cpp
index 5b3ea581..698809b0 100644
--- a/imgui/imgui_widgets.cpp
+++ b/imgui/imgui_widgets.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.70
+// dear imgui, v1.71
// (widgets code)
/*
@@ -51,7 +51,7 @@ Index of this file:
#endif
// Clang/GCC warnings with -Weverything
-#ifdef __clang__
+#if defined(__clang__)
#pragma clang diagnostic ignored "-Wold-style-cast" // warning : use of old-style cast // yes, they are more terse.
#pragma clang diagnostic ignored "-Wfloat-equal" // warning : comparing floating point with == or != is unsafe // storing and comparing against same constants (typically 0.0f) is ok.
#pragma clang diagnostic ignored "-Wformat-nonliteral" // warning : format string is not a string literal // passing non-literal to vsnformat(). yes, user passing incorrect format strings can crash the code.
@@ -139,7 +139,7 @@ void ImGui::TextEx(const char* text, const char* text_end, ImGuiTextFlags flags)
if (text_end == NULL)
text_end = text + strlen(text); // FIXME-OPT
- const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrentLineTextBaseOffset);
+ const ImVec2 text_pos(window->DC.CursorPos.x, window->DC.CursorPos.y + window->DC.CurrLineTextBaseOffset);
const float wrap_pos_x = window->DC.TextWrapPos;
const bool wrap_enabled = (wrap_pos_x >= 0.0f);
if (text_end - text > 2000 && !wrap_enabled)
@@ -320,7 +320,7 @@ void ImGui::LabelTextV(const char* label, const char* fmt, va_list args)
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
- const float w = GetNextItemWidth();
+ const float w = CalcItemWidth();
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImRect value_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2));
@@ -358,15 +358,16 @@ void ImGui::BulletTextV(const char* fmt, va_list args)
const char* text_begin = g.TempBuffer;
const char* text_end = text_begin + ImFormatStringV(g.TempBuffer, IM_ARRAYSIZE(g.TempBuffer), fmt, args);
const ImVec2 label_size = CalcTextSize(text_begin, text_end, false);
- const float text_base_offset_y = ImMax(0.0f, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it
- const float line_height = ImMax(ImMin(window->DC.CurrentLineSize.y, g.FontSize + g.Style.FramePadding.y*2), g.FontSize);
+ const float text_base_offset_y = ImMax(0.0f, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it
+ const float line_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + g.Style.FramePadding.y*2), g.FontSize);
const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize + (label_size.x > 0.0f ? (label_size.x + style.FramePadding.x*2) : 0.0f), ImMax(line_height, label_size.y))); // Empty text doesn't add padding
ItemSize(bb);
if (!ItemAdd(bb, 0))
return;
// Render
- RenderBullet(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f));
+ ImU32 text_col = GetColorU32(ImGuiCol_Text);
+ RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f), text_col);
RenderText(bb.Min+ImVec2(g.FontSize + style.FramePadding.x*2, text_base_offset_y), text_begin, text_end, false);
}
@@ -380,6 +381,7 @@ void ImGui::BulletTextV(const char* fmt, va_list args)
// - ArrowButton()
// - CloseButton() [Internal]
// - CollapseButton() [Internal]
+// - ScrollbarEx() [Internal]
// - Scrollbar() [Internal]
// - Image()
// - ImageButton()
@@ -462,7 +464,8 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
flags |= ImGuiButtonFlags_PressedOnClickRelease;
ImGuiWindow* backup_hovered_window = g.HoveredWindow;
- if ((flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredRootWindow == window)
+ const bool flatten_hovered_children = (flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredRootWindow == window;
+ if (flatten_hovered_children)
g.HoveredWindow = window;
#ifdef IMGUI_ENABLE_TEST_ENGINE
@@ -490,7 +493,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
}
}
- if ((flags & ImGuiButtonFlags_FlattenChildren) && g.HoveredRootWindow == window)
+ if (flatten_hovered_children)
g.HoveredWindow = backup_hovered_window;
// AllowOverlap mode (rarely used) requires previous frame HoveredId to be null or to match. This allows using patterns where a later submitted widget overlaps a previous one.
@@ -562,7 +565,7 @@ bool ImGui::ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool
if (g.ActiveId == id)
{
if (pressed)
- g.ActiveIdHasBeenPressed = true;
+ g.ActiveIdHasBeenPressedBefore = true;
if (g.ActiveIdSource == ImGuiInputSource_Mouse)
{
if (g.ActiveIdIsJustActivated)
@@ -610,8 +613,8 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags
const ImVec2 label_size = CalcTextSize(label, NULL, true);
ImVec2 pos = window->DC.CursorPos;
- if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrentLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag)
- pos.y += window->DC.CurrentLineTextBaseOffset - style.FramePadding.y;
+ if ((flags & ImGuiButtonFlags_AlignTextBaseLine) && style.FramePadding.y < window->DC.CurrLineTextBaseOffset) // Try to vertically align buttons that are smaller/have no padding so that text baseline matches (bit hacky, since it shouldn't be a flag)
+ pos.y += window->DC.CurrLineTextBaseOffset - style.FramePadding.y;
ImVec2 size = CalcItemSize(size_arg, label_size.x + style.FramePadding.x * 2.0f, label_size.y + style.FramePadding.y * 2.0f);
const ImRect bb(pos, pos + size);
@@ -701,10 +704,11 @@ bool ImGui::ArrowButtonEx(const char* str_id, ImGuiDir dir, ImVec2 size, ImGuiBu
bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
// Render
- const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
+ const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
+ const ImU32 text_col = GetColorU32(ImGuiCol_Text);
RenderNavHighlight(bb, id);
- RenderFrame(bb.Min, bb.Max, col, true, g.Style.FrameRounding);
- RenderArrow(bb.Min + ImVec2(ImMax(0.0f, (size.x - g.FontSize) * 0.5f), ImMax(0.0f, (size.y - g.FontSize) * 0.5f)), dir);
+ RenderFrame(bb.Min, bb.Max, bg_col, true, g.Style.FrameRounding);
+ RenderArrow(window->DrawList, bb.Min + ImVec2(ImMax(0.0f, (size.x - g.FontSize) * 0.5f), ImMax(0.0f, (size.y - g.FontSize) * 0.5f)), text_col, dir);
return pressed;
}
@@ -716,14 +720,14 @@ bool ImGui::ArrowButton(const char* str_id, ImGuiDir dir)
}
// Button to close a window
-bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos, float radius)
+bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos)//, float size)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
// We intentionally allow interaction when clipped so that a mechanical Alt,Right,Validate sequence close a window.
// (this isn't the regular behavior of buttons, but it doesn't affect the user much because navigation tends to keep items visible).
- const ImRect bb(pos - ImVec2(radius,radius), pos + ImVec2(radius,radius));
+ const ImRect bb(pos, pos + ImVec2(g.FontSize, g.FontSize) + g.Style.FramePadding * 2.0f);
bool is_clipped = !ItemAdd(bb, id);
bool hovered, held;
@@ -732,11 +736,12 @@ bool ImGui::CloseButton(ImGuiID id, const ImVec2& pos, float radius)
return pressed;
// Render
+ ImU32 col = GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered);
ImVec2 center = bb.GetCenter();
if (hovered)
- window->DrawList->AddCircleFilled(center, ImMax(2.0f, radius), GetColorU32(held ? ImGuiCol_ButtonActive : ImGuiCol_ButtonHovered), 9);
+ window->DrawList->AddCircleFilled(center, ImMax(2.0f, g.FontSize * 0.5f + 1.0f), col, 12);
- float cross_extent = (radius * 0.7071f) - 1.0f;
+ float cross_extent = g.FontSize * 0.5f * 0.7071f - 1.0f;
ImU32 cross_col = GetColorU32(ImGuiCol_Text);
center -= ImVec2(0.5f, 0.5f);
window->DrawList->AddLine(center + ImVec2(+cross_extent,+cross_extent), center + ImVec2(-cross_extent,-cross_extent), cross_col, 1.0f);
@@ -755,10 +760,13 @@ bool ImGui::CollapseButton(ImGuiID id, const ImVec2& pos)
bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_None);
- ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
+ // Render
+ ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
+ ImU32 text_col = GetColorU32(ImGuiCol_Text);
+ ImVec2 center = bb.GetCenter();
if (hovered || held)
- window->DrawList->AddCircleFilled(bb.GetCenter() + ImVec2(0.0f, -0.5f), g.FontSize * 0.5f + 1.0f, col, 9);
- RenderArrow(bb.Min + g.Style.FramePadding, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f);
+ window->DrawList->AddCircleFilled(center/*+ ImVec2(0.0f, -0.5f)*/, g.FontSize * 0.5f + 1.0f, bg_col, 12);
+ RenderArrow(window->DrawList, bb.Min + g.Style.FramePadding, text_col, window->Collapsed ? ImGuiDir_Right : ImGuiDir_Down, 1.0f);
// Switch to moving the window after mouse is moved beyond the initial drag threshold
if (IsItemActive() && IsMouseDragging())
@@ -777,125 +785,128 @@ ImGuiID ImGui::GetScrollbarID(ImGuiWindow* window, ImGuiAxis axis)
// - We handle absolute seeking (when first clicking outside the grab) and relative manipulation (afterward or when clicking inside the grab)
// - We store values as normalized ratio and in a form that allows the window content to change while we are holding on a scrollbar
// - We handle both horizontal and vertical scrollbars, which makes the terminology not ideal.
-void ImGui::Scrollbar(ImGuiAxis axis)
+// Still, the code should probably be made simpler..
+bool ImGui::ScrollbarEx(const ImRect& bb_frame, ImGuiID id, ImGuiAxis axis, float* p_scroll_v, float size_avail_v, float size_contents_v, ImDrawCornerFlags rounding_corners)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
+ if (window->SkipItems)
+ return false;
- const bool horizontal = (axis == ImGuiAxis_X);
- const ImGuiStyle& style = g.Style;
- const ImGuiID id = GetScrollbarID(window, axis);
- KeepAliveID(id);
-
- // Render background
- bool other_scrollbar = (horizontal ? window->ScrollbarY : window->ScrollbarX);
- float other_scrollbar_size_w = other_scrollbar ? style.ScrollbarSize : 0.0f;
- const ImRect host_rect = window->Rect();
- const float border_size = window->WindowBorderSize;
- ImRect bb = horizontal
- ? ImRect(host_rect.Min.x + border_size, host_rect.Max.y - style.ScrollbarSize, host_rect.Max.x - other_scrollbar_size_w - border_size, host_rect.Max.y - border_size)
- : ImRect(host_rect.Max.x - style.ScrollbarSize, host_rect.Min.y + border_size, host_rect.Max.x - border_size, host_rect.Max.y - other_scrollbar_size_w - border_size);
- bb.Min.x = ImMax(host_rect.Min.x, bb.Min.x); // Handle case where the host rectangle is smaller than the scrollbar
- bb.Min.y = ImMax(host_rect.Min.y, bb.Min.y);
- if (!horizontal)
- bb.Min.y += window->TitleBarHeight() + ((window->Flags & ImGuiWindowFlags_MenuBar) ? window->MenuBarHeight() : 0.0f); // FIXME: InnerRect?
-
- const float bb_width = bb.GetWidth();
- const float bb_height = bb.GetHeight();
- if (bb_width <= 0.0f || bb_height <= 0.0f)
- return;
+ const float bb_frame_width = bb_frame.GetWidth();
+ const float bb_frame_height = bb_frame.GetHeight();
+ if (bb_frame_width <= 0.0f || bb_frame_height <= 0.0f)
+ return false;
// When we are too small, start hiding and disabling the grab (this reduce visual noise on very small window and facilitate using the resize grab)
float alpha = 1.0f;
- if ((axis == ImGuiAxis_Y) && bb_height < g.FontSize + g.Style.FramePadding.y * 2.0f)
- {
- alpha = ImSaturate((bb_height - g.FontSize) / (g.Style.FramePadding.y * 2.0f));
- if (alpha <= 0.0f)
- return;
- }
+ if ((axis == ImGuiAxis_Y) && bb_frame_height < g.FontSize + g.Style.FramePadding.y * 2.0f)
+ alpha = ImSaturate((bb_frame_height - g.FontSize) / (g.Style.FramePadding.y * 2.0f));
+ if (alpha <= 0.0f)
+ return false;
+
+ const ImGuiStyle& style = g.Style;
const bool allow_interaction = (alpha >= 1.0f);
+ const bool horizontal = (axis == ImGuiAxis_X);
- int window_rounding_corners;
- if (horizontal)
- window_rounding_corners = ImDrawCornerFlags_BotLeft | (other_scrollbar ? 0 : ImDrawCornerFlags_BotRight);
- else
- window_rounding_corners = (((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? ImDrawCornerFlags_TopRight : 0) | (other_scrollbar ? 0 : ImDrawCornerFlags_BotRight);
- window->DrawList->AddRectFilled(bb.Min, bb.Max, GetColorU32(ImGuiCol_ScrollbarBg), window->WindowRounding, window_rounding_corners);
- bb.Expand(ImVec2(-ImClamp((float)(int)((bb_width - 2.0f) * 0.5f), 0.0f, 3.0f), -ImClamp((float)(int)((bb_height - 2.0f) * 0.5f), 0.0f, 3.0f)));
+ ImRect bb = bb_frame;
+ bb.Expand(ImVec2(-ImClamp((float)(int)((bb_frame_width - 2.0f) * 0.5f), 0.0f, 3.0f), -ImClamp((float)(int)((bb_frame_height - 2.0f) * 0.5f), 0.0f, 3.0f)));
// V denote the main, longer axis of the scrollbar (= height for a vertical scrollbar)
- float scrollbar_size_v = horizontal ? bb.GetWidth() : bb.GetHeight();
- float scroll_v = horizontal ? window->Scroll.x : window->Scroll.y;
- float win_size_avail_v = (horizontal ? window->SizeFull.x : window->SizeFull.y) - other_scrollbar_size_w;
- float win_size_contents_v = horizontal ? window->SizeContents.x : window->SizeContents.y;
+ const float scrollbar_size_v = horizontal ? bb.GetWidth() : bb.GetHeight();
// Calculate the height of our grabbable box. It generally represent the amount visible (vs the total scrollable amount)
// But we maintain a minimum size in pixel to allow for the user to still aim inside.
- IM_ASSERT(ImMax(win_size_contents_v, win_size_avail_v) > 0.0f); // Adding this assert to check if the ImMax(XXX,1.0f) is still needed. PLEASE CONTACT ME if this triggers.
- const float win_size_v = ImMax(ImMax(win_size_contents_v, win_size_avail_v), 1.0f);
- const float grab_h_pixels = ImClamp(scrollbar_size_v * (win_size_avail_v / win_size_v), style.GrabMinSize, scrollbar_size_v);
+ IM_ASSERT(ImMax(size_contents_v, size_avail_v) > 0.0f); // Adding this assert to check if the ImMax(XXX,1.0f) is still needed. PLEASE CONTACT ME if this triggers.
+ const float win_size_v = ImMax(ImMax(size_contents_v, size_avail_v), 1.0f);
+ const float grab_h_pixels = ImClamp(scrollbar_size_v * (size_avail_v / win_size_v), style.GrabMinSize, scrollbar_size_v);
const float grab_h_norm = grab_h_pixels / scrollbar_size_v;
// Handle input right away. None of the code of Begin() is relying on scrolling position before calling Scrollbar().
bool held = false;
bool hovered = false;
- const bool previously_held = (g.ActiveId == id);
ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_NoNavFocus);
- float scroll_max = ImMax(1.0f, win_size_contents_v - win_size_avail_v);
- float scroll_ratio = ImSaturate(scroll_v / scroll_max);
+ float scroll_max = ImMax(1.0f, size_contents_v - size_avail_v);
+ float scroll_ratio = ImSaturate(*p_scroll_v / scroll_max);
float grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v;
if (held && allow_interaction && grab_h_norm < 1.0f)
{
float scrollbar_pos_v = horizontal ? bb.Min.x : bb.Min.y;
float mouse_pos_v = horizontal ? g.IO.MousePos.x : g.IO.MousePos.y;
- float* click_delta_to_grab_center_v = horizontal ? &g.ScrollbarClickDeltaToGrabCenter.x : &g.ScrollbarClickDeltaToGrabCenter.y;
// Click position in scrollbar normalized space (0.0f->1.0f)
const float clicked_v_norm = ImSaturate((mouse_pos_v - scrollbar_pos_v) / scrollbar_size_v);
SetHoveredID(id);
bool seek_absolute = false;
- if (!previously_held)
+ if (g.ActiveIdIsJustActivated)
{
// On initial click calculate the distance between mouse and the center of the grab
- if (clicked_v_norm >= grab_v_norm && clicked_v_norm <= grab_v_norm + grab_h_norm)
- {
- *click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm*0.5f;
- }
+ seek_absolute = (clicked_v_norm < grab_v_norm || clicked_v_norm > grab_v_norm + grab_h_norm);
+ if (seek_absolute)
+ g.ScrollbarClickDeltaToGrabCenter = 0.0f;
else
- {
- seek_absolute = true;
- *click_delta_to_grab_center_v = 0.0f;
- }
+ g.ScrollbarClickDeltaToGrabCenter = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f;
}
// Apply scroll
- // It is ok to modify Scroll here because we are being called in Begin() after the calculation of SizeContents and before setting up our starting position
- const float scroll_v_norm = ImSaturate((clicked_v_norm - *click_delta_to_grab_center_v - grab_h_norm*0.5f) / (1.0f - grab_h_norm));
- scroll_v = (float)(int)(0.5f + scroll_v_norm * scroll_max);//(win_size_contents_v - win_size_v));
- if (horizontal)
- window->Scroll.x = scroll_v;
- else
- window->Scroll.y = scroll_v;
+ // It is ok to modify Scroll here because we are being called in Begin() after the calculation of ContentSize and before setting up our starting position
+ const float scroll_v_norm = ImSaturate((clicked_v_norm - g.ScrollbarClickDeltaToGrabCenter - grab_h_norm * 0.5f) / (1.0f - grab_h_norm));
+ *p_scroll_v = (float)(int)(0.5f + scroll_v_norm * scroll_max);//(win_size_contents_v - win_size_v));
// Update values for rendering
- scroll_ratio = ImSaturate(scroll_v / scroll_max);
+ scroll_ratio = ImSaturate(*p_scroll_v / scroll_max);
grab_v_norm = scroll_ratio * (scrollbar_size_v - grab_h_pixels) / scrollbar_size_v;
// Update distance to grab now that we have seeked and saturated
if (seek_absolute)
- *click_delta_to_grab_center_v = clicked_v_norm - grab_v_norm - grab_h_norm*0.5f;
+ g.ScrollbarClickDeltaToGrabCenter = clicked_v_norm - grab_v_norm - grab_h_norm * 0.5f;
}
- // Render grab
+ // Render
+ window->DrawList->AddRectFilled(bb_frame.Min, bb_frame.Max, GetColorU32(ImGuiCol_ScrollbarBg), window->WindowRounding, rounding_corners);
const ImU32 grab_col = GetColorU32(held ? ImGuiCol_ScrollbarGrabActive : hovered ? ImGuiCol_ScrollbarGrabHovered : ImGuiCol_ScrollbarGrab, alpha);
ImRect grab_rect;
if (horizontal)
- grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImMin(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, host_rect.Max.x), bb.Max.y);
+ grab_rect = ImRect(ImLerp(bb.Min.x, bb.Max.x, grab_v_norm), bb.Min.y, ImLerp(bb.Min.x, bb.Max.x, grab_v_norm) + grab_h_pixels, bb.Max.y);
else
- grab_rect = ImRect(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm), bb.Max.x, ImMin(ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels, host_rect.Max.y));
+ grab_rect = ImRect(bb.Min.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm), bb.Max.x, ImLerp(bb.Min.y, bb.Max.y, grab_v_norm) + grab_h_pixels);
window->DrawList->AddRectFilled(grab_rect.Min, grab_rect.Max, grab_col, style.ScrollbarRounding);
+
+ return held;
+}
+
+void ImGui::Scrollbar(ImGuiAxis axis)
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
+
+ const ImGuiID id = GetScrollbarID(window, axis);
+ KeepAliveID(id);
+
+ // Calculate scrollbar bounding box
+ const ImRect outer_rect = window->Rect();
+ const ImRect inner_rect = window->InnerRect;
+ const float border_size = window->WindowBorderSize;
+ const float scrollbar_size = window->ScrollbarSizes[axis ^ 1];
+ IM_ASSERT(scrollbar_size > 0.0f);
+ const float other_scrollbar_size = window->ScrollbarSizes[axis];
+ ImDrawCornerFlags rounding_corners = (other_scrollbar_size <= 0.0f) ? ImDrawCornerFlags_BotRight : 0;
+ ImRect bb;
+ if (axis == ImGuiAxis_X)
+ {
+ bb.Min = ImVec2(inner_rect.Min.x, outer_rect.Max.y - border_size - scrollbar_size);
+ bb.Max = ImVec2(inner_rect.Max.x, outer_rect.Max.y);
+ rounding_corners |= ImDrawCornerFlags_BotLeft;
+ }
+ else
+ {
+ bb.Min = ImVec2(outer_rect.Max.x - border_size - scrollbar_size, inner_rect.Min.y);
+ bb.Max = ImVec2(outer_rect.Max.x, window->InnerRect.Max.y);
+ rounding_corners |= ((window->Flags & ImGuiWindowFlags_NoTitleBar) && !(window->Flags & ImGuiWindowFlags_MenuBar)) ? ImDrawCornerFlags_TopRight : 0;
+ }
+ ScrollbarEx(bb, id, axis, &window->Scroll[axis], inner_rect.Max[axis] - inner_rect.Min[axis], window->ContentSize[axis] + window->WindowPadding[axis] * 2.0f, rounding_corners);
}
void ImGui::Image(ImTextureID user_texture_id, const ImVec2& size, const ImVec2& uv0, const ImVec2& uv1, const ImVec4& tint_col, const ImVec4& border_col)
@@ -1091,7 +1102,7 @@ void ImGui::ProgressBar(float fraction, const ImVec2& size_arg, const char* over
const ImGuiStyle& style = g.Style;
ImVec2 pos = window->DC.CursorPos;
- ImVec2 size = CalcItemSize(size_arg, GetNextItemWidth(), g.FontSize + style.FramePadding.y*2.0f);
+ ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), g.FontSize + style.FramePadding.y*2.0f);
ImRect bb(pos, pos + size);
ItemSize(size, style.FramePadding.y);
if (!ItemAdd(bb, 0))
@@ -1125,7 +1136,7 @@ void ImGui::Bullet()
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
- const float line_height = ImMax(ImMin(window->DC.CurrentLineSize.y, g.FontSize + g.Style.FramePadding.y*2), g.FontSize);
+ const float line_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + g.Style.FramePadding.y*2), g.FontSize);
const ImRect bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(g.FontSize, line_height));
ItemSize(bb);
if (!ItemAdd(bb, 0))
@@ -1135,8 +1146,9 @@ void ImGui::Bullet()
}
// Render and stay on same line
- RenderBullet(bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f));
- SameLine(0, style.FramePadding.x*2);
+ ImU32 text_col = GetColorU32(ImGuiCol_Text);
+ RenderBullet(window->DrawList, bb.Min + ImVec2(style.FramePadding.x + g.FontSize*0.5f, line_height*0.5f), text_col);
+ SameLine(0, style.FramePadding.x * 2.0f);
}
//-------------------------------------------------------------------------
@@ -1146,9 +1158,10 @@ void ImGui::Bullet()
// - Dummy()
// - NewLine()
// - AlignTextToFramePadding()
+// - SeparatorEx() [Internal]
// - Separator()
-// - VerticalSeparator() [Internal]
// - SplitterBehavior() [Internal]
+// - ShrinkWidths() [Internal]
//-------------------------------------------------------------------------
void ImGui::Spacing()
@@ -1179,7 +1192,7 @@ void ImGui::NewLine()
ImGuiContext& g = *GImGui;
const ImGuiLayoutType backup_layout_type = window->DC.LayoutType;
window->DC.LayoutType = ImGuiLayoutType_Vertical;
- if (window->DC.CurrentLineSize.y > 0.0f) // In the event that we are on a line with items that is smaller that FontSize high, we will preserve its height.
+ if (window->DC.CurrLineSize.y > 0.0f) // In the event that we are on a line with items that is smaller that FontSize high, we will preserve its height.
ItemSize(ImVec2(0,0));
else
ItemSize(ImVec2(0.0f, g.FontSize));
@@ -1193,74 +1206,83 @@ void ImGui::AlignTextToFramePadding()
return;
ImGuiContext& g = *GImGui;
- window->DC.CurrentLineSize.y = ImMax(window->DC.CurrentLineSize.y, g.FontSize + g.Style.FramePadding.y * 2);
- window->DC.CurrentLineTextBaseOffset = ImMax(window->DC.CurrentLineTextBaseOffset, g.Style.FramePadding.y);
+ window->DC.CurrLineSize.y = ImMax(window->DC.CurrLineSize.y, g.FontSize + g.Style.FramePadding.y * 2);
+ window->DC.CurrLineTextBaseOffset = ImMax(window->DC.CurrLineTextBaseOffset, g.Style.FramePadding.y);
}
// Horizontal/vertical separating line
-void ImGui::Separator()
+void ImGui::SeparatorEx(ImGuiSeparatorFlags flags)
{
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return;
- ImGuiContext& g = *GImGui;
- // Those flags should eventually be overrideable by the user
- ImGuiSeparatorFlags flags = (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal;
+ ImGuiContext& g = *GImGui;
IM_ASSERT(ImIsPowerOfTwo(flags & (ImGuiSeparatorFlags_Horizontal | ImGuiSeparatorFlags_Vertical))); // Check that only 1 option is selected
+
+ float thickness_draw = 1.0f;
+ float thickness_layout = 0.0f;
if (flags & ImGuiSeparatorFlags_Vertical)
{
- VerticalSeparator();
- return;
- }
-
- // Horizontal Separator
- if (window->DC.CurrentColumns)
- PopClipRect();
-
- float x1 = window->Pos.x;
- float x2 = window->Pos.x + window->Size.x;
- if (!window->DC.GroupStack.empty())
- x1 += window->DC.Indent.x;
+ // Vertical separator, for menu bars (use current line height). Not exposed because it is misleading and it doesn't have an effect on regular layout.
+ float y1 = window->DC.CursorPos.y;
+ float y2 = window->DC.CursorPos.y + window->DC.CurrLineSize.y;
+ const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + thickness_draw, y2));
+ ItemSize(ImVec2(thickness_layout, 0.0f));
+ if (!ItemAdd(bb, 0))
+ return;
- const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y+1.0f));
- ItemSize(ImVec2(0.0f, 1.0f)); // NB: we don't provide our width so that it doesn't get feed back into AutoFit
- if (!ItemAdd(bb, 0))
- {
- if (window->DC.CurrentColumns)
- PushColumnClipRect();
- return;
+ // Draw
+ window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y), ImVec2(bb.Min.x, bb.Max.y), GetColorU32(ImGuiCol_Separator));
+ if (g.LogEnabled)
+ LogText(" |");
}
+ else if (flags & ImGuiSeparatorFlags_Horizontal)
+ {
+ // Horizontal Separator
+ float x1 = window->Pos.x;
+ float x2 = window->Pos.x + window->Size.x;
+ if (!window->DC.GroupStack.empty())
+ x1 += window->DC.Indent.x;
- window->DrawList->AddLine(bb.Min, ImVec2(bb.Max.x,bb.Min.y), GetColorU32(ImGuiCol_Separator));
+ ImGuiColumns* columns = (flags & ImGuiSeparatorFlags_SpanAllColumns) ? window->DC.CurrentColumns : NULL;
+ if (columns)
+ PushColumnsBackground();
- if (g.LogEnabled)
- LogRenderedText(&bb.Min, "--------------------------------");
+ // We don't provide our width to the layout so that it doesn't get feed back into AutoFit
+ const ImRect bb(ImVec2(x1, window->DC.CursorPos.y), ImVec2(x2, window->DC.CursorPos.y + thickness_draw));
+ ItemSize(ImVec2(0.0f, thickness_layout));
+ if (!ItemAdd(bb, 0))
+ {
+ if (columns)
+ PopColumnsBackground();
+ return;
+ }
- if (window->DC.CurrentColumns)
- {
- PushColumnClipRect();
- window->DC.CurrentColumns->LineMinY = window->DC.CursorPos.y;
+ // Draw
+ window->DrawList->AddLine(bb.Min, ImVec2(bb.Max.x, bb.Min.y), GetColorU32(ImGuiCol_Separator));
+ if (g.LogEnabled)
+ LogRenderedText(&bb.Min, "--------------------------------");
+
+ if (columns)
+ {
+ PopColumnsBackground();
+ columns->LineMinY = window->DC.CursorPos.y;
+ }
}
}
-void ImGui::VerticalSeparator()
+void ImGui::Separator()
{
- ImGuiWindow* window = GetCurrentWindow();
- if (window->SkipItems)
- return;
ImGuiContext& g = *GImGui;
-
- float y1 = window->DC.CursorPos.y;
- float y2 = window->DC.CursorPos.y + window->DC.CurrentLineSize.y;
- const ImRect bb(ImVec2(window->DC.CursorPos.x, y1), ImVec2(window->DC.CursorPos.x + 1.0f, y2));
- ItemSize(ImVec2(1.0f, 0.0f));
- if (!ItemAdd(bb, 0))
+ ImGuiWindow* window = g.CurrentWindow;
+ if (window->SkipItems)
return;
- window->DrawList->AddLine(ImVec2(bb.Min.x, bb.Min.y), ImVec2(bb.Min.x, bb.Max.y), GetColorU32(ImGuiCol_Separator));
- if (g.LogEnabled)
- LogText(" |");
+ // Those flags should eventually be overridable by the user
+ ImGuiSeparatorFlags flags = (window->DC.LayoutType == ImGuiLayoutType_Horizontal) ? ImGuiSeparatorFlags_Vertical : ImGuiSeparatorFlags_Horizontal;
+ flags |= ImGuiSeparatorFlags_SpanAllColumns;
+ SeparatorEx(flags);
}
// Using 'hover_visibility_delay' allows us to hide the highlight and mouse cursor for a short time, which can be convenient to reduce visual noise.
@@ -1321,6 +1343,33 @@ bool ImGui::SplitterBehavior(const ImRect& bb, ImGuiID id, ImGuiAxis axis, float
return held;
}
+static int IMGUI_CDECL ShrinkWidthItemComparer(const void* lhs, const void* rhs)
+{
+ const ImGuiShrinkWidthItem* a = (const ImGuiShrinkWidthItem*)lhs;
+ const ImGuiShrinkWidthItem* b = (const ImGuiShrinkWidthItem*)rhs;
+ if (int d = (int)(b->Width - a->Width))
+ return d;
+ return (b->Index - a->Index);
+}
+
+// Shrink excess width from a set of item, by removing width from the larger items first.
+void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess)
+{
+ if (count > 1)
+ ImQsort(items, (size_t)count, sizeof(ImGuiShrinkWidthItem), ShrinkWidthItemComparer);
+ int count_same_width = 1;
+ while (width_excess > 0.0f && count_same_width < count)
+ {
+ while (count_same_width < count && items[0].Width == items[count_same_width].Width)
+ count_same_width++;
+ float width_to_remove_per_item_max = (count_same_width < count) ? (items[0].Width - items[count_same_width].Width) : (items[0].Width - 1.0f);
+ float width_to_remove_per_item = ImMin(width_excess / count_same_width, width_to_remove_per_item_max);
+ for (int item_n = 0; item_n < count_same_width; item_n++)
+ items[item_n].Width -= width_to_remove_per_item;
+ width_excess -= width_to_remove_per_item * count_same_width;
+ }
+}
+
//-------------------------------------------------------------------------
// [SECTION] Widgets: ComboBox
//-------------------------------------------------------------------------
@@ -1341,8 +1390,8 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
{
// Always consume the SetNextWindowSizeConstraint() call in our early return paths
ImGuiContext& g = *GImGui;
- ImGuiCond backup_next_window_size_constraint = g.NextWindowData.SizeConstraintCond;
- g.NextWindowData.SizeConstraintCond = 0;
+ bool has_window_size_constraint = (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint) != 0;
+ g.NextWindowData.Flags &= ~ImGuiNextWindowDataFlags_HasSizeConstraint;
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
@@ -1355,7 +1404,7 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
const float arrow_size = (flags & ImGuiComboFlags_NoArrowButton) ? 0.0f : GetFrameHeight();
const ImVec2 label_size = CalcTextSize(label, NULL, true);
- const float expected_w = GetNextItemWidth();
+ const float expected_w = CalcItemWidth();
const float w = (flags & ImGuiComboFlags_NoPreview) ? arrow_size : expected_w;
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f));
const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
@@ -1371,11 +1420,13 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
const float value_x2 = ImMax(frame_bb.Min.x, frame_bb.Max.x - arrow_size);
RenderNavHighlight(frame_bb, id);
if (!(flags & ImGuiComboFlags_NoPreview))
- window->DrawList->AddRectFilled(frame_bb.Min, ImVec2(value_x2, frame_bb.Max.y), frame_col, style.FrameRounding, ImDrawCornerFlags_Left);
+ window->DrawList->AddRectFilled(frame_bb.Min, ImVec2(value_x2, frame_bb.Max.y), frame_col, style.FrameRounding, (flags & ImGuiComboFlags_NoArrowButton) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Left);
if (!(flags & ImGuiComboFlags_NoArrowButton))
{
- window->DrawList->AddRectFilled(ImVec2(value_x2, frame_bb.Min.y), frame_bb.Max, GetColorU32((popup_open || hovered) ? ImGuiCol_ButtonHovered : ImGuiCol_Button), style.FrameRounding, (w <= arrow_size) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Right);
- RenderArrow(ImVec2(value_x2 + style.FramePadding.y, frame_bb.Min.y + style.FramePadding.y), ImGuiDir_Down);
+ ImU32 bg_col = GetColorU32((popup_open || hovered) ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
+ ImU32 text_col = GetColorU32(ImGuiCol_Text);
+ window->DrawList->AddRectFilled(ImVec2(value_x2, frame_bb.Min.y), frame_bb.Max, bg_col, style.FrameRounding, (w <= arrow_size) ? ImDrawCornerFlags_All : ImDrawCornerFlags_Right);
+ RenderArrow(window->DrawList, ImVec2(value_x2 + style.FramePadding.y, frame_bb.Min.y + style.FramePadding.y), text_col, ImGuiDir_Down);
}
RenderFrameBorder(frame_bb.Min, frame_bb.Max, style.FrameRounding);
if (preview_value != NULL && !(flags & ImGuiComboFlags_NoPreview))
@@ -1394,9 +1445,9 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
if (!popup_open)
return false;
- if (backup_next_window_size_constraint)
+ if (has_window_size_constraint)
{
- g.NextWindowData.SizeConstraintCond = backup_next_window_size_constraint;
+ g.NextWindowData.Flags |= ImGuiNextWindowDataFlags_HasSizeConstraint;
g.NextWindowData.SizeConstraintRect.Min.x = ImMax(g.NextWindowData.SizeConstraintRect.Min.x, w);
}
else
@@ -1486,7 +1537,7 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi
items_getter(data, *current_item, &preview_value);
// The old Combo() API exposed "popup_max_height_in_items". The new more general BeginCombo() API doesn't have/need it, but we emulate it here.
- if (popup_max_height_in_items != -1 && !g.NextWindowData.SizeConstraintCond)
+ if (popup_max_height_in_items != -1 && !(g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint))
SetNextWindowSizeConstraints(ImVec2(0,0), ImVec2(FLT_MAX, CalcMaxPopupHeightFromItemCount(popup_max_height_in_items)));
if (!BeginCombo(label, preview_value, ImGuiComboFlags_None))
@@ -1982,8 +2033,7 @@ bool ImGui::DragScalar(const char* label, ImGuiDataType data_type, void* v, floa
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
- const float w = GetNextItemWidth();
-
+ const float w = CalcItemWidth();
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f));
const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
@@ -2055,20 +2105,27 @@ bool ImGui::DragScalarN(const char* label, ImGuiDataType data_type, void* v, int
bool value_changed = false;
BeginGroup();
PushID(label);
- PushMultiItemsWidths(components, GetNextItemWidth());
+ PushMultiItemsWidths(components, CalcItemWidth());
size_t type_size = GDataTypeInfo[data_type].Size;
for (int i = 0; i < components; i++)
{
PushID(i);
+ if (i > 0)
+ SameLine(0, g.Style.ItemInnerSpacing.x);
value_changed |= DragScalar("", data_type, v, v_speed, v_min, v_max, format, power);
- SameLine(0, g.Style.ItemInnerSpacing.x);
PopID();
PopItemWidth();
v = (void*)((char*)v + type_size);
}
PopID();
- TextEx(label, FindRenderedTextEnd(label));
+ const char* label_end = FindRenderedTextEnd(label);
+ if (label != label_end)
+ {
+ SameLine(0, g.Style.ItemInnerSpacing.x);
+ TextEx(label, label_end);
+ }
+
EndGroup();
return value_changed;
}
@@ -2102,7 +2159,7 @@ bool ImGui::DragFloatRange2(const char* label, float* v_current_min, float* v_cu
ImGuiContext& g = *GImGui;
PushID(label);
BeginGroup();
- PushMultiItemsWidths(2, GetNextItemWidth());
+ PushMultiItemsWidths(2, CalcItemWidth());
bool value_changed = DragFloat("##min", v_current_min, v_speed, (v_min >= v_max) ? -FLT_MAX : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), format, power);
PopItemWidth();
@@ -2147,7 +2204,7 @@ bool ImGui::DragIntRange2(const char* label, int* v_current_min, int* v_current_
ImGuiContext& g = *GImGui;
PushID(label);
BeginGroup();
- PushMultiItemsWidths(2, GetNextItemWidth());
+ PushMultiItemsWidths(2, CalcItemWidth());
bool value_changed = DragInt("##min", v_current_min, v_speed, (v_min >= v_max) ? INT_MIN : v_min, (v_min >= v_max) ? *v_current_max : ImMin(v_max, *v_current_max), format);
PopItemWidth();
@@ -2425,7 +2482,7 @@ bool ImGui::SliderScalar(const char* label, ImGuiDataType data_type, void* v, co
ImGuiContext& g = *GImGui;
const ImGuiStyle& style = g.Style;
const ImGuiID id = window->GetID(label);
- const float w = GetNextItemWidth();
+ const float w = CalcItemWidth();
const ImVec2 label_size = CalcTextSize(label, NULL, true);
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + ImVec2(w, label_size.y + style.FramePadding.y*2.0f));
@@ -2503,20 +2560,27 @@ bool ImGui::SliderScalarN(const char* label, ImGuiDataType data_type, void* v, i
bool value_changed = false;
BeginGroup();
PushID(label);
- PushMultiItemsWidths(components, GetNextItemWidth());
+ PushMultiItemsWidths(components, CalcItemWidth());
size_t type_size = GDataTypeInfo[data_type].Size;
for (int i = 0; i < components; i++)
{
PushID(i);
+ if (i > 0)
+ SameLine(0, g.Style.ItemInnerSpacing.x);
value_changed |= SliderScalar("", data_type, v, v_min, v_max, format, power);
- SameLine(0, g.Style.ItemInnerSpacing.x);
PopID();
PopItemWidth();
v = (void*)((char*)v + type_size);
}
PopID();
- TextEx(label, FindRenderedTextEnd(label));
+ const char* label_end = FindRenderedTextEnd(label);
+ if (label != label_end)
+ {
+ SameLine(0, g.Style.ItemInnerSpacing.x);
+ TextEx(label, label_end);
+ }
+
EndGroup();
return value_changed;
}
@@ -2752,7 +2816,8 @@ bool ImGui::TempInputTextScalar(const ImRect& bb, ImGuiID id, const char* label,
ImStrTrimBlanks(data_buf);
g.CurrentWindow->DC.CursorPos = bb.Min;
- ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal);
+ ImGuiInputTextFlags flags = ImGuiInputTextFlags_AutoSelectAll | ImGuiInputTextFlags_NoMarkEdited;
+ flags |= ((data_type == ImGuiDataType_Float || data_type == ImGuiDataType_Double) ? ImGuiInputTextFlags_CharsScientific : ImGuiInputTextFlags_CharsDecimal);
bool value_changed = InputTextEx(label, NULL, data_buf, IM_ARRAYSIZE(data_buf), bb.GetSize(), flags);
if (init)
{
@@ -2761,8 +2826,12 @@ bool ImGui::TempInputTextScalar(const ImRect& bb, ImGuiID id, const char* label,
g.TempInputTextId = g.ActiveId;
}
if (value_changed)
- return DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, NULL);
- return false;
+ {
+ value_changed = DataTypeApplyOpFromText(data_buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, NULL);
+ if (value_changed)
+ MarkItemEdited(id);
+ }
+ return value_changed;
}
bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_ptr, const void* step, const void* step_fast, const char* format, ImGuiInputTextFlags flags)
@@ -2784,6 +2853,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p
if ((flags & (ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsScientific)) == 0)
flags |= ImGuiInputTextFlags_CharsDecimal;
flags |= ImGuiInputTextFlags_AutoSelectAll;
+ flags |= ImGuiInputTextFlags_NoMarkEdited; // We call MarkItemEdited() ourselve by comparing the actual data rather than the string.
if (step != NULL)
{
@@ -2791,7 +2861,7 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p
BeginGroup(); // The only purpose of the group here is to allow the caller to query item data e.g. IsItemActive()
PushID(label);
- SetNextItemWidth(ImMax(1.0f, GetNextItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2));
+ SetNextItemWidth(ImMax(1.0f, CalcItemWidth() - (button_size + style.ItemInnerSpacing.x) * 2));
if (InputText("", buf, IM_ARRAYSIZE(buf), flags)) // PushId(label) + "" gives us the expected ID from outside point of view
value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, format);
@@ -2813,8 +2883,13 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p
DataTypeApplyOp(data_type, '+', data_ptr, data_ptr, g.IO.KeyCtrl && step_fast ? step_fast : step);
value_changed = true;
}
- SameLine(0, style.ItemInnerSpacing.x);
- TextEx(label, FindRenderedTextEnd(label));
+
+ const char* label_end = FindRenderedTextEnd(label);
+ if (label != label_end)
+ {
+ SameLine(0, style.ItemInnerSpacing.x);
+ TextEx(label, label_end);
+ }
style.FramePadding = backup_frame_padding;
PopID();
@@ -2825,6 +2900,8 @@ bool ImGui::InputScalar(const char* label, ImGuiDataType data_type, void* data_p
if (InputText(label, buf, IM_ARRAYSIZE(buf), flags))
value_changed = DataTypeApplyOpFromText(buf, g.InputTextState.InitialTextA.Data, data_type, data_ptr, format);
}
+ if (value_changed)
+ MarkItemEdited(window->DC.LastItemId);
return value_changed;
}
@@ -2839,20 +2916,27 @@ bool ImGui::InputScalarN(const char* label, ImGuiDataType data_type, void* v, in
bool value_changed = false;
BeginGroup();
PushID(label);
- PushMultiItemsWidths(components, GetNextItemWidth());
+ PushMultiItemsWidths(components, CalcItemWidth());
size_t type_size = GDataTypeInfo[data_type].Size;
for (int i = 0; i < components; i++)
{
PushID(i);
+ if (i > 0)
+ SameLine(0, g.Style.ItemInnerSpacing.x);
value_changed |= InputScalar("", data_type, v, step, step_fast, format, flags);
- SameLine(0, g.Style.ItemInnerSpacing.x);
PopID();
PopItemWidth();
v = (void*)((char*)v + type_size);
}
PopID();
- TextEx(label, FindRenderedTextEnd(label));
+ const char* label_end = FindRenderedTextEnd(label);
+ if (label != label_end)
+ {
+ SameLine(0.0f, g.Style.ItemInnerSpacing.x);
+ TextEx(label, label_end);
+ }
+
EndGroup();
return value_changed;
}
@@ -3289,7 +3373,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
BeginGroup();
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
- ImVec2 size = CalcItemSize(size_arg, GetNextItemWidth(), (is_multiline ? GetTextLineHeight() * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line
+ ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? GetTextLineHeight() * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size);
const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? (style.ItemInnerSpacing.x + label_size.x) : 0.0f, 0.0f));
@@ -4004,7 +4088,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (label_size.x > 0)
RenderText(ImVec2(frame_bb.Max.x + style.ItemInnerSpacing.x, frame_bb.Min.y + style.FramePadding.y), label);
- if (value_changed)
+ if (value_changed && !(flags & ImGuiInputTextFlags_NoMarkEdited))
MarkItemEdited(id);
IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags);
@@ -4047,8 +4131,9 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
const ImGuiStyle& style = g.Style;
const float square_sz = GetFrameHeight();
const float w_extra = (flags & ImGuiColorEditFlags_NoSmallPreview) ? 0.0f : (square_sz + style.ItemInnerSpacing.x);
- const float w_items_all = GetNextItemWidth() - w_extra;
+ const float w_items_all = CalcItemWidth() - w_extra;
const char* label_display_end = FindRenderedTextEnd(label);
+ g.NextItemData.ClearFlags();
BeginGroup();
PushID(label);
@@ -4184,7 +4269,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
Spacing();
}
ImGuiColorEditFlags picker_flags_to_forward = ImGuiColorEditFlags__DataTypeMask | ImGuiColorEditFlags__PickerMask | ImGuiColorEditFlags__InputMask | ImGuiColorEditFlags_HDR | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaBar;
- ImGuiColorEditFlags picker_flags = (flags_untouched & picker_flags_to_forward) | ImGuiColorEditFlags_DisplayHSV | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf;
+ ImGuiColorEditFlags picker_flags = (flags_untouched & picker_flags_to_forward) | ImGuiColorEditFlags__DisplayMask | ImGuiColorEditFlags_NoLabel | ImGuiColorEditFlags_AlphaPreviewHalf;
SetNextItemWidth(square_sz * 12.0f); // Use 256 + bar sizes?
value_changed |= ColorPicker4("##picker", col, picker_flags, &g.ColorPickerRef.x);
EndPopup();
@@ -4328,6 +4413,9 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
ImGuiStyle& style = g.Style;
ImGuiIO& io = g.IO;
+ const float width = CalcItemWidth();
+ g.NextItemData.ClearFlags();
+
PushID(label);
BeginGroup();
@@ -4354,7 +4442,7 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
ImVec2 picker_pos = window->DC.CursorPos;
float square_sz = GetFrameHeight();
float bars_width = square_sz; // Arbitrary smallish width of Hue/Alpha picking bars
- float sv_picker_size = ImMax(bars_width * 1, GetNextItemWidth() - (alpha_bar ? 2 : 1) * (bars_width + style.ItemInnerSpacing.x)); // Saturation/Value picking box
+ float sv_picker_size = ImMax(bars_width * 1, width - (alpha_bar ? 2 : 1) * (bars_width + style.ItemInnerSpacing.x)); // Saturation/Value picking box
float bar0_pos_x = picker_pos.x + sv_picker_size + style.ItemInnerSpacing.x;
float bar1_pos_x = bar0_pos_x + bars_width + style.ItemInnerSpacing.x;
float bars_triangles_half_sz = (float)(int)(bars_width * 0.20f);
@@ -4897,7 +4985,7 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl
// - TreePop()
// - TreeAdvanceToLabelPos()
// - GetTreeNodeToLabelSpacing()
-// - SetNextTreeNodeOpen()
+// - SetNextItemOpen()
// - CollapsingHeader()
//-------------------------------------------------------------------------
@@ -4991,17 +5079,17 @@ bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags)
if (flags & ImGuiTreeNodeFlags_Leaf)
return true;
- // We only write to the tree storage if the user clicks (or explicitly use SetNextTreeNode*** functions)
+ // We only write to the tree storage if the user clicks (or explicitly use the SetNextItemOpen function)
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
ImGuiStorage* storage = window->DC.StateStorage;
bool is_open;
- if (g.NextTreeNodeOpenCond != 0)
+ if (g.NextItemData.Flags & ImGuiNextItemDataFlags_HasOpen)
{
- if (g.NextTreeNodeOpenCond & ImGuiCond_Always)
+ if (g.NextItemData.OpenCond & ImGuiCond_Always)
{
- is_open = g.NextTreeNodeOpenVal;
+ is_open = g.NextItemData.OpenVal;
storage->SetInt(id, is_open);
}
else
@@ -5010,7 +5098,7 @@ bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags)
const int stored_value = storage->GetInt(id, -1);
if (stored_value == -1)
{
- is_open = g.NextTreeNodeOpenVal;
+ is_open = g.NextItemData.OpenVal;
storage->SetInt(id, is_open);
}
else
@@ -5018,7 +5106,6 @@ bool ImGui::TreeNodeBehaviorIsOpen(ImGuiID id, ImGuiTreeNodeFlags flags)
is_open = stored_value != 0;
}
}
- g.NextTreeNodeOpenCond = 0;
}
else
{
@@ -5049,14 +5136,14 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
const ImVec2 label_size = CalcTextSize(label, label_end, false);
// We vertically grow up to current line height up the typical widget height.
- const float text_base_offset_y = ImMax(padding.y, window->DC.CurrentLineTextBaseOffset); // Latch before ItemSize changes it
- const float frame_height = ImMax(ImMin(window->DC.CurrentLineSize.y, g.FontSize + style.FramePadding.y*2), label_size.y + padding.y*2);
- ImRect frame_bb = ImRect(window->DC.CursorPos, ImVec2(GetWorkRectMax().x, window->DC.CursorPos.y + frame_height));
+ const float text_base_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it
+ const float frame_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y*2), label_size.y + padding.y*2);
+ ImRect frame_bb = ImRect(window->DC.CursorPos, ImVec2(window->WorkRect.Max.x, window->DC.CursorPos.y + frame_height));
if (display_frame)
{
// Framed header expand a little outside the default padding
- frame_bb.Min.x -= (float)(int)(window->WindowPadding.x*0.5f) - 1;
- frame_bb.Max.x += (float)(int)(window->WindowPadding.x*0.5f) - 1;
+ frame_bb.Min.x -= (float)(int)(window->WindowPadding.x * 0.5f - 1.0f);
+ frame_bb.Max.x += (float)(int)(window->WindowPadding.x * 0.5f);
}
const float text_offset_x = (g.FontSize + (display_frame ? padding.x*3 : padding.x*2)); // Collapser arrow width + Spacing
@@ -5144,15 +5231,18 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledSelection;
// Render
- const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
+ const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
+ const ImU32 text_col = GetColorU32(ImGuiCol_Text);
const ImVec2 text_pos = frame_bb.Min + ImVec2(text_offset_x, text_base_offset_y);
ImGuiNavHighlightFlags nav_highlight_flags = ImGuiNavHighlightFlags_TypeThin;
if (display_frame)
{
// Framed type
- RenderFrame(frame_bb.Min, frame_bb.Max, col, true, style.FrameRounding);
+ RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, true, style.FrameRounding);
RenderNavHighlight(frame_bb, id, nav_highlight_flags);
- RenderArrow(frame_bb.Min + ImVec2(padding.x, text_base_offset_y), is_open ? ImGuiDir_Down : ImGuiDir_Right, 1.0f);
+ RenderArrow(window->DrawList, frame_bb.Min + ImVec2(padding.x, text_base_offset_y), text_col, is_open ? ImGuiDir_Down : ImGuiDir_Right, 1.0f);
+ if (flags & ImGuiTreeNodeFlags_ClipLabelForTrailingButton)
+ frame_bb.Max.x -= g.FontSize + style.FramePadding.x;
if (g.LogEnabled)
{
// NB: '##' is normally used to hide text (as a library-wide feature), so we need to specify the text range to make sure the ## aren't stripped out here.
@@ -5172,14 +5262,14 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
// Unframed typed for tree nodes
if (hovered || selected)
{
- RenderFrame(frame_bb.Min, frame_bb.Max, col, false);
+ RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false);
RenderNavHighlight(frame_bb, id, nav_highlight_flags);
}
if (flags & ImGuiTreeNodeFlags_Bullet)
- RenderBullet(frame_bb.Min + ImVec2(text_offset_x * 0.5f, g.FontSize*0.50f + text_base_offset_y));
+ RenderBullet(window->DrawList, frame_bb.Min + ImVec2(text_offset_x * 0.5f, g.FontSize*0.50f + text_base_offset_y), text_col);
else if (!is_leaf)
- RenderArrow(frame_bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), is_open ? ImGuiDir_Down : ImGuiDir_Right, 0.70f);
+ RenderArrow(window->DrawList, frame_bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), text_col, is_open ? ImGuiDir_Down : ImGuiDir_Right, 0.70f);
if (g.LogEnabled)
LogRenderedText(&text_pos, ">");
RenderText(text_pos, label, label_end, false);
@@ -5247,13 +5337,15 @@ float ImGui::GetTreeNodeToLabelSpacing()
return g.FontSize + (g.Style.FramePadding.x * 2.0f);
}
-void ImGui::SetNextTreeNodeOpen(bool is_open, ImGuiCond cond)
+// Set next TreeNode/CollapsingHeader open state.
+void ImGui::SetNextItemOpen(bool is_open, ImGuiCond cond)
{
ImGuiContext& g = *GImGui;
if (g.CurrentWindow->SkipItems)
return;
- g.NextTreeNodeOpenVal = is_open;
- g.NextTreeNodeOpenCond = cond ? cond : ImGuiCond_Always;
+ g.NextItemData.Flags |= ImGuiNextItemDataFlags_HasOpen;
+ g.NextItemData.OpenVal = is_open;
+ g.NextItemData.OpenCond = cond ? cond : ImGuiCond_Always;
}
// CollapsingHeader returns true when opened but do not indent nor push into the ID stack (because of the ImGuiTreeNodeFlags_NoTreePushOnOpen flag).
@@ -5277,15 +5369,19 @@ bool ImGui::CollapsingHeader(const char* label, bool* p_open, ImGuiTreeNodeFlags
return false;
ImGuiID id = window->GetID(label);
- bool is_open = TreeNodeBehavior(id, flags | ImGuiTreeNodeFlags_CollapsingHeader | (p_open ? ImGuiTreeNodeFlags_AllowItemOverlap : 0), label);
+ flags |= ImGuiTreeNodeFlags_CollapsingHeader | (p_open ? ImGuiTreeNodeFlags_AllowItemOverlap | ImGuiTreeNodeFlags_ClipLabelForTrailingButton : 0);
+ bool is_open = TreeNodeBehavior(id, flags, label);
if (p_open)
{
- // Create a small overlapping close button // FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc.
+ // Create a small overlapping close button
+ // FIXME: We can evolve this into user accessible helpers to add extra buttons on title bars, headers, etc.
+ // FIXME: CloseButton can overlap into text, need find a way to clip the text somehow.
ImGuiContext& g = *GImGui;
ImGuiItemHoveredDataBackup last_item_backup;
- float button_radius = g.FontSize * 0.5f;
- ImVec2 button_center = ImVec2(ImMin(window->DC.LastItemRect.Max.x, window->ClipRect.Max.x) - g.Style.FramePadding.x - button_radius, window->DC.LastItemRect.GetCenter().y);
- if (CloseButton(window->GetID((void*)((intptr_t)id+1)), button_center, button_radius))
+ float button_size = g.FontSize;
+ float button_x = ImMax(window->DC.LastItemRect.Min.x, window->DC.LastItemRect.Max.x - g.Style.FramePadding.x * 2.0f - button_size);
+ float button_y = window->DC.LastItemRect.Min.y;
+ if (CloseButton(window->GetID((void*)((intptr_t)id + 1)), ImVec2(button_x, button_y)))
*p_open = false;
last_item_backup.Restore();
}
@@ -5311,13 +5407,13 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
const ImGuiStyle& style = g.Style;
if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.CurrentColumns) // FIXME-OPT: Avoid if vertically clipped.
- PopClipRect();
+ PushColumnsBackground();
ImGuiID id = window->GetID(label);
ImVec2 label_size = CalcTextSize(label, NULL, true);
ImVec2 size(size_arg.x != 0.0f ? size_arg.x : label_size.x, size_arg.y != 0.0f ? size_arg.y : label_size.y);
ImVec2 pos = window->DC.CursorPos;
- pos.y += window->DC.CurrentLineTextBaseOffset;
+ pos.y += window->DC.CurrLineTextBaseOffset;
ImRect bb_inner(pos, pos + size);
ItemSize(size);
@@ -5355,7 +5451,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
if (!item_add)
{
if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.CurrentColumns)
- PushColumnClipRect();
+ PopColumnsBackground();
return false;
}
@@ -5401,7 +5497,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
if ((flags & ImGuiSelectableFlags_SpanAllColumns) && window->DC.CurrentColumns)
{
- PushColumnClipRect();
+ PopColumnsBackground();
bb.Max.x -= (GetContentRegionMax().x - max_x);
}
@@ -5443,20 +5539,22 @@ bool ImGui::Selectable(const char* label, bool* p_selected, ImGuiSelectableFlags
// Tip: To have a list filling the entire window width, PushItemWidth(-1) and pass an non-visible label e.g. "##empty"
bool ImGui::ListBoxHeader(const char* label, const ImVec2& size_arg)
{
+ ImGuiContext& g = *GImGui;
ImGuiWindow* window = GetCurrentWindow();
if (window->SkipItems)
return false;
- const ImGuiStyle& style = GetStyle();
+ const ImGuiStyle& style = g.Style;
const ImGuiID id = GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
// Size default to hold ~7 items. Fractional number of items helps seeing that we can scroll down/up without looking at scrollbar.
- ImVec2 size = CalcItemSize(size_arg, GetNextItemWidth(), GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y);
+ ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), GetTextLineHeightWithSpacing() * 7.4f + style.ItemSpacing.y);
ImVec2 frame_size = ImVec2(size.x, ImMax(size.y, label_size.y));
ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + frame_size);
ImRect bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f, 0.0f));
window->DC.LastItemRect = bb; // Forward storage for ListBoxFooter.. dodgy.
+ g.NextItemData.ClearFlags();
if (!IsRectVisible(bb.Min, bb.Max))
{
@@ -5569,7 +5667,7 @@ void ImGui::PlotEx(ImGuiPlotType plot_type, const char* label, float (*values_ge
const ImVec2 label_size = CalcTextSize(label, NULL, true);
if (frame_size.x == 0.0f)
- frame_size.x = GetNextItemWidth();
+ frame_size.x = CalcItemWidth();
if (frame_size.y == 0.0f)
frame_size.y = label_size.y + (style.FramePadding.y * 2);
@@ -5827,7 +5925,7 @@ void ImGui::EndMainMenuBar()
// When the user has left the menu layer (typically: closed menus through activation of an item), we restore focus to the previous window
// FIXME: With this strategy we won't be able to restore a NULL focus.
ImGuiContext& g = *GImGui;
- if (g.CurrentWindow == g.NavWindow && g.NavLayer == 0)
+ if (g.CurrentWindow == g.NavWindow && g.NavLayer == 0 && !g.NavAnyRequest)
FocusTopMostWindowUnderOne(g.NavWindow, NULL);
End();
@@ -5894,7 +5992,7 @@ void ImGui::EndMenuBar()
PopClipRect();
PopID();
window->DC.MenuBarOffset.x = window->DC.CursorPos.x - window->MenuBarRect().Min.x; // Save horizontal position so next append can reuse it. This is kinda equivalent to a per-layer CursorPos.
- window->DC.GroupStack.back().AdvanceCursor = false;
+ window->DC.GroupStack.back().EmitItem = false;
EndGroup(); // Restore position on layer 0
window->DC.LayoutType = ImGuiLayoutType_Vertical;
window->DC.NavLayerCurrent = ImGuiNavLayer_Main;
@@ -5945,9 +6043,8 @@ bool ImGui::BeginMenu(const char* label, bool enabled)
float w = window->MenuColumns.DeclColumns(label_size.x, 0.0f, (float)(int)(g.FontSize * 1.20f)); // Feedback to next frame
float extra_w = ImMax(0.0f, GetContentRegionAvail().x - w);
pressed = Selectable(label, menu_is_open, ImGuiSelectableFlags_NoHoldingActiveID | ImGuiSelectableFlags_PressedOnClick | ImGuiSelectableFlags_DontClosePopups | ImGuiSelectableFlags_DrawFillAvailWidth | (!enabled ? ImGuiSelectableFlags_Disabled : 0), ImVec2(w, 0.0f));
- if (!enabled) PushStyleColor(ImGuiCol_Text, g.Style.Colors[ImGuiCol_TextDisabled]);
- RenderArrow(pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.30f, 0.0f), ImGuiDir_Right);
- if (!enabled) PopStyleColor();
+ ImU32 text_col = GetColorU32(enabled ? ImGuiCol_Text : ImGuiCol_TextDisabled);
+ RenderArrow(window->DrawList, pos + ImVec2(window->MenuColumns.Pos[2] + extra_w + g.FontSize * 0.30f, 0.0f), text_col, ImGuiDir_Right);
}
const bool hovered = enabled && ItemHoverable(window->DC.LastItemRect, id);
@@ -6172,15 +6269,6 @@ static int IMGUI_CDECL TabItemComparerByVisibleOffset(const void* lhs, const voi
return (int)(a->Offset - b->Offset);
}
-static int IMGUI_CDECL TabBarSortItemComparer(const void* lhs, const void* rhs)
-{
- const ImGuiTabBarSortItem* a = (const ImGuiTabBarSortItem*)lhs;
- const ImGuiTabBarSortItem* b = (const ImGuiTabBarSortItem*)rhs;
- if (int d = (int)(b->Width - a->Width))
- return d;
- return (b->Index - a->Index);
-}
-
static ImGuiTabBar* GetTabBarFromTabBarRef(const ImGuiTabBarRef& ref)
{
ImGuiContext& g = *GImGui;
@@ -6204,7 +6292,7 @@ bool ImGui::BeginTabBar(const char* str_id, ImGuiTabBarFlags flags)
ImGuiID id = window->GetID(str_id);
ImGuiTabBar* tab_bar = g.TabBars.GetOrAddByKey(id);
- ImRect tab_bar_bb = ImRect(window->DC.CursorPos.x, window->DC.CursorPos.y, window->InnerClipRect.Max.x, window->DC.CursorPos.y + g.FontSize + g.Style.FramePadding.y * 2);
+ ImRect tab_bar_bb = ImRect(window->DC.CursorPos.x, window->DC.CursorPos.y, window->WorkRect.Max.x, window->DC.CursorPos.y + g.FontSize + g.Style.FramePadding.y * 2);
tab_bar->ID = id;
return BeginTabBarEx(tab_bar, tab_bar_bb, flags | ImGuiTabBarFlags_IsFocused);
}
@@ -6247,15 +6335,15 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
tab_bar->FramePadding = g.Style.FramePadding;
// Layout
- ItemSize(ImVec2(tab_bar->OffsetMax, tab_bar->BarRect.GetHeight()));
+ ItemSize(ImVec2(0.0f /*tab_bar->OffsetMax*/, tab_bar->BarRect.GetHeight())); // Don't feed width back
window->DC.CursorPos.x = tab_bar->BarRect.Min.x;
// Draw separator
const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_Tab);
const float y = tab_bar->BarRect.Max.y - 1.0f;
{
- const float separator_min_x = tab_bar->BarRect.Min.x - window->WindowPadding.x;
- const float separator_max_x = tab_bar->BarRect.Max.x + window->WindowPadding.x;
+ const float separator_min_x = tab_bar->BarRect.Min.x - ImFloor(window->WindowPadding.x * 0.5f);
+ const float separator_max_x = tab_bar->BarRect.Max.x + ImFloor(window->WindowPadding.x * 0.5f);
window->DrawList->AddLine(ImVec2(separator_min_x, y), ImVec2(separator_max_x, y), col, 1.0f);
}
return true;
@@ -6354,10 +6442,8 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
if (ImGuiTabItem* tab_to_select = TabBarTabListPopupButton(tab_bar)) // NB: Will alter BarRect.Max.x!
scroll_track_selected_tab_id = tab_bar->SelectedTabId = tab_to_select->ID;
- ImVector<ImGuiTabBarSortItem>& width_sort_buffer = g.TabSortByWidthBuffer;
- width_sort_buffer.resize(tab_bar->Tabs.Size);
-
// Compute ideal widths
+ g.ShrinkWidthBuffer.resize(tab_bar->Tabs.Size);
float width_total_contents = 0.0f;
ImGuiTabItem* most_recently_selected_tab = NULL;
bool found_selected_tab_id = false;
@@ -6375,36 +6461,26 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
// Additionally, when using TabBarAddTab() to manipulate tab bar order we occasionally insert new tabs that don't have a width yet,
// and we cannot wait for the next BeginTabItem() call. We cannot compute this width within TabBarAddTab() because font size depends on the active window.
const char* tab_name = tab_bar->GetTabName(tab);
- tab->WidthContents = TabItemCalcSize(tab_name, (tab->Flags & ImGuiTabItemFlags_NoCloseButton) ? false : true).x;
+ const bool has_close_button = (tab->Flags & ImGuiTabItemFlags_NoCloseButton) ? false : true;
+ tab->WidthContents = TabItemCalcSize(tab_name, has_close_button).x;
width_total_contents += (tab_n > 0 ? g.Style.ItemInnerSpacing.x : 0.0f) + tab->WidthContents;
// Store data so we can build an array sorted by width if we need to shrink tabs down
- width_sort_buffer[tab_n].Index = tab_n;
- width_sort_buffer[tab_n].Width = tab->WidthContents;
+ g.ShrinkWidthBuffer[tab_n].Index = tab_n;
+ g.ShrinkWidthBuffer[tab_n].Width = tab->WidthContents;
}
// Compute width
- const float width_avail = tab_bar->BarRect.GetWidth();
+ const float initial_offset_x = 0.0f; // g.Style.ItemInnerSpacing.x;
+ const float width_avail = ImMax(tab_bar->BarRect.GetWidth() - initial_offset_x, 0.0f);
float width_excess = (width_avail < width_total_contents) ? (width_total_contents - width_avail) : 0.0f;
if (width_excess > 0.0f && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyResizeDown))
{
// If we don't have enough room, resize down the largest tabs first
- if (tab_bar->Tabs.Size > 1)
- ImQsort(width_sort_buffer.Data, (size_t)width_sort_buffer.Size, sizeof(ImGuiTabBarSortItem), TabBarSortItemComparer);
- int tab_count_same_width = 1;
- while (width_excess > 0.0f && tab_count_same_width < tab_bar->Tabs.Size)
- {
- while (tab_count_same_width < tab_bar->Tabs.Size && width_sort_buffer[0].Width == width_sort_buffer[tab_count_same_width].Width)
- tab_count_same_width++;
- float width_to_remove_per_tab_max = (tab_count_same_width < tab_bar->Tabs.Size) ? (width_sort_buffer[0].Width - width_sort_buffer[tab_count_same_width].Width) : (width_sort_buffer[0].Width - 1.0f);
- float width_to_remove_per_tab = ImMin(width_excess / tab_count_same_width, width_to_remove_per_tab_max);
- for (int tab_n = 0; tab_n < tab_count_same_width; tab_n++)
- width_sort_buffer[tab_n].Width -= width_to_remove_per_tab;
- width_excess -= width_to_remove_per_tab * tab_count_same_width;
- }
+ ShrinkWidths(g.ShrinkWidthBuffer.Data, g.ShrinkWidthBuffer.Size, width_excess);
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
- tab_bar->Tabs[width_sort_buffer[tab_n].Index].Width = (float)(int)width_sort_buffer[tab_n].Width;
+ tab_bar->Tabs[g.ShrinkWidthBuffer[tab_n].Index].Width = (float)(int)g.ShrinkWidthBuffer[tab_n].Width;
}
else
{
@@ -6417,7 +6493,8 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
}
// Layout all active tabs
- float offset_x = 0.0f;
+ float offset_x = initial_offset_x;
+ tab_bar->OffsetNextTab = offset_x; // This is used by non-reorderable tab bar where the submission order is always honored.
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
{
ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
@@ -6427,7 +6504,6 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
offset_x += tab->Width + g.Style.ItemInnerSpacing.x;
}
tab_bar->OffsetMax = ImMax(offset_x - g.Style.ItemInnerSpacing.x, 0.0f);
- tab_bar->OffsetNextTab = 0.0f;
// Horizontal scrolling buttons
const bool scrolling_buttons = (tab_bar->OffsetMax > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll);
@@ -6810,7 +6886,10 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
if (want_clip_rect)
PushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->BarRect.Min.x), bb.Min.y - 1), ImVec2(tab_bar->BarRect.Max.x, bb.Max.y), true);
- ItemSize(bb, style.FramePadding.y);
+ ImVec2 backup_cursor_max_pos = window->DC.CursorMaxPos;
+ ItemSize(bb.GetSize(), style.FramePadding.y);
+ window->DC.CursorMaxPos = backup_cursor_max_pos;
+
if (!ItemAdd(bb, id))
{
if (want_clip_rect)
@@ -6984,47 +7063,22 @@ bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb,
if (close_button_visible)
{
ImGuiItemHoveredDataBackup last_item_backup;
- const float close_button_sz = g.FontSize * 0.5f;
- if (CloseButton(close_button_id, ImVec2(bb.Max.x - frame_padding.x - close_button_sz, bb.Min.y + frame_padding.y + close_button_sz), close_button_sz))
+ const float close_button_sz = g.FontSize;
+ PushStyleVar(ImGuiStyleVar_FramePadding, frame_padding);
+ if (CloseButton(close_button_id, ImVec2(bb.Max.x - frame_padding.x * 2.0f - close_button_sz, bb.Min.y)))
close_button_pressed = true;
+ PopStyleVar();
last_item_backup.Restore();
// Close with middle mouse button
if (!(flags & ImGuiTabItemFlags_NoCloseWithMiddleMouseButton) && IsMouseClicked(2))
close_button_pressed = true;
- text_pixel_clip_bb.Max.x -= close_button_sz * 2.0f;
+ text_pixel_clip_bb.Max.x -= close_button_sz;
}
- // Label with ellipsis
- // FIXME: This should be extracted into a helper but the use of text_pixel_clip_bb and !close_button_visible makes it tricky to abstract at the moment
- const char* label_display_end = FindRenderedTextEnd(label);
- if (label_size.x > text_ellipsis_clip_bb.GetWidth())
- {
- const int ellipsis_dot_count = 3;
- const float ellipsis_width = (1.0f + 1.0f) * ellipsis_dot_count - 1.0f;
- const char* label_end = NULL;
- float label_size_clipped_x = g.Font->CalcTextSizeA(g.FontSize, text_ellipsis_clip_bb.GetWidth() - ellipsis_width + 1.0f, 0.0f, label, label_display_end, &label_end).x;
- if (label_end == label && label_end < label_display_end) // Always display at least 1 character if there's no room for character + ellipsis
- {
- label_end = label + ImTextCountUtf8BytesFromChar(label, label_display_end);
- label_size_clipped_x = g.Font->CalcTextSizeA(g.FontSize, FLT_MAX, 0.0f, label, label_end).x;
- }
- while (label_end > label && ImCharIsBlankA(label_end[-1])) // Trim trailing space
- {
- label_end--;
- label_size_clipped_x -= g.Font->CalcTextSizeA(g.FontSize, FLT_MAX, 0.0f, label_end, label_end + 1).x; // Ascii blanks are always 1 byte
- }
- RenderTextClippedEx(draw_list, text_pixel_clip_bb.Min, text_pixel_clip_bb.Max, label, label_end, &label_size, ImVec2(0.0f, 0.0f));
-
- const float ellipsis_x = text_pixel_clip_bb.Min.x + label_size_clipped_x + 1.0f;
- if (!close_button_visible && ellipsis_x + ellipsis_width <= bb.Max.x)
- RenderPixelEllipsis(draw_list, ImVec2(ellipsis_x, text_pixel_clip_bb.Min.y), ellipsis_dot_count, GetColorU32(ImGuiCol_Text));
- }
- else
- {
- RenderTextClippedEx(draw_list, text_pixel_clip_bb.Min, text_pixel_clip_bb.Max, label, label_display_end, &label_size, ImVec2(0.0f, 0.0f));
- }
+ float ellipsis_max_x = close_button_visible ? text_pixel_clip_bb.Max.x : bb.Max.x - 1.0f;
+ RenderTextEllipsis(draw_list, text_ellipsis_clip_bb.Min, text_ellipsis_clip_bb.Max, text_pixel_clip_bb.Max.x, ellipsis_max_x, label, NULL, &label_size);
return close_button_pressed;
}