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-07-30 23:53:52 +0300
committerBartosz Taudul <wolf.pld@gmail.com>2019-07-30 23:53:52 +0300
commit526f3a55bc0d0f2e6fa922c7dac5707f894d1960 (patch)
tree89b55aeb814c0e2fb43ba002662d3d144167e0b9 /imgui
parentca3571fd2bfa6879641c5aaec28de09210964adf (diff)
Update imgui to 1.72.
Diffstat (limited to 'imgui')
-rw-r--r--imgui/imconfig.h11
-rw-r--r--imgui/imgui.cpp1034
-rw-r--r--imgui/imgui.h160
-rw-r--r--imgui/imgui_demo.cpp196
-rw-r--r--imgui/imgui_draw.cpp49
-rw-r--r--imgui/imgui_internal.h94
-rw-r--r--imgui/imgui_widgets.cpp516
7 files changed, 1196 insertions, 864 deletions
diff --git a/imgui/imconfig.h b/imgui/imconfig.h
index f4b64cb8..78d38d27 100644
--- a/imgui/imconfig.h
+++ b/imgui/imconfig.h
@@ -28,12 +28,13 @@
//---- 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.
//#define IMGUI_DISABLE_DEMO_WINDOWS
+//#define IMGUI_DISABLE_METRICS_WINDOW
//---- 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 (clipboard, ime).
-//#define IMGUI_DISABLE_OSX_FUNCTIONS // [OSX] Won't use and link with any OSX function (clipboard).
+//#define IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS // [OSX] Implement default OSX clipboard handler (need to link with '-framework ApplicationServices').
//#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().
@@ -75,6 +76,14 @@
//typedef void (*MyImDrawCallback)(const ImDrawList* draw_list, const ImDrawCmd* cmd, void* my_renderer_user_data);
//#define ImDrawCallback MyImDrawCallback
+//---- Debug Tools
+// Use 'Metrics->Tools->Item Picker' to pick widgets with the mouse and break into them for easy debugging.
+//#define IM_DEBUG_BREAK IM_ASSERT(0)
+//#define IM_DEBUG_BREAK __debugbreak()
+// Have the Item Picker break in the ItemAdd() function instead of ItemHoverable() - which is earlier in the code, will catch a few extra items, allow picking items other than Hovered one.
+// This adds a small runtime cost which is why it is not enabled by default.
+//#define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
+
//---- 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 72ea25e7..ce9e1c1e 100644
--- a/imgui/imgui.cpp
+++ b/imgui/imgui.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.71
+// dear imgui, v1.72
// (main code and documentation)
// Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code.
@@ -6,7 +6,7 @@
// Get latest version at https://github.com/ocornut/imgui
// Releases change-log at https://github.com/ocornut/imgui/releases
// Technical Support for Getting Started https://discourse.dearimgui.org/c/getting-started
-// Gallery (please post your screenshots/video there!): https://github.com/ocornut/imgui/issues/1269
+// Gallery (please post your screenshots/video there!): https://github.com/ocornut/imgui/issues/2529
// Developed by Omar Cornut and every direct or indirect contributors to the GitHub.
// See LICENSE.txt for copyright and licensing details (standard MIT License).
@@ -75,7 +75,6 @@ CODE
// [SECTION] TOOLTIPS
// [SECTION] POPUPS
// [SECTION] KEYBOARD/GAMEPAD NAVIGATION
-// [SECTION] COLUMNS
// [SECTION] DRAG AND DROP
// [SECTION] LOGGING/CAPTURING
// [SECTION] SETTINGS
@@ -369,6 +368,9 @@ 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/07/15 (1.72) - removed TreeAdvanceToLabelPos() which is rarely used and only does SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()). Kept redirection function (will obsolete).
+ - 2019/07/12 (1.72) - renamed ImFontAtlas::CustomRect to ImFontAtlasCustomRect. Kept redirection typedef (will obsolete).
+ - 2019/06/14 (1.72) - removed redirecting functions/enums names that were marked obsolete in 1.51 (June 2017): ImGuiCol_Column*, ImGuiSetCond_*, IsItemHoveredRect(), IsPosHoveringAnyWindow(), IsMouseHoveringAnyWindow(), IsMouseHoveringWindow(), IMGUI_ONCE_UPON_A_FRAME. Grep this log for details and new names.
- 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.
@@ -382,7 +384,7 @@ CODE
- 2019/02/14 (1.68) - made it illegal/assert when io.DisplayTime == 0.0f (with an exception for the first frame). If for some reason your time step calculation gives you a zero value, replace it with a dummy small value!
- 2019/02/01 (1.68) - removed io.DisplayVisibleMin/DisplayVisibleMax (which were marked obsolete and removed from viewport/docking branch already).
- 2019/01/06 (1.67) - renamed io.InputCharacters[], marked internal as was always intended. Please don't access directly, and use AddInputCharacter() instead!
- - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Keep redirection typedef (will obsolete).
+ - 2019/01/06 (1.67) - renamed ImFontAtlas::GlyphRangesBuilder to ImFontGlyphRangesBuilder. Kept redirection typedef (will obsolete).
- 2018/12/20 (1.67) - made it illegal to call Begin("") with an empty string. This somehow half-worked before but had various undesirable side-effects.
- 2018/12/10 (1.67) - renamed io.ConfigResizeWindowsFromEdges to io.ConfigWindowsResizeFromEdges as we are doing a large pass on configuration flags.
- 2018/10/12 (1.66) - renamed misc/stl/imgui_stl.* to misc/cpp/imgui_stdlib.* in prevision for other C++ helper files.
@@ -450,9 +452,12 @@ CODE
- 2017/10/20 (1.52) - changed IsWindowHovered() default parameters behavior to return false if an item is active in another window (e.g. click-dragging item from another window to this window). You can use the newly introduced IsWindowHovered() flags to requests this specific behavior if you need it.
- 2017/10/20 (1.52) - marked IsItemHoveredRect()/IsMouseHoveringWindow() as obsolete, in favor of using the newly introduced flags for IsItemHovered() and IsWindowHovered(). See https://github.com/ocornut/imgui/issues/1382 for details.
removed the IsItemRectHovered()/IsWindowRectHovered() names introduced in 1.51 since they were merely more consistent names for the two functions we are now obsoleting.
+ IsItemHoveredRect() --> IsItemHovered(ImGuiHoveredFlags_RectOnly)
+ IsMouseHoveringAnyWindow() --> IsWindowHovered(ImGuiHoveredFlags_AnyWindow)
+ IsMouseHoveringWindow() --> IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem) [weird, old behavior]
- 2017/10/17 (1.52) - marked the old 5-parameters version of Begin() as obsolete (still available). Use SetNextWindowSize()+Begin() instead!
- 2017/10/11 (1.52) - renamed AlignFirstTextHeightToWidgets() to AlignTextToFramePadding(). Kept inline redirection function (will obsolete).
- - 2017/09/26 (1.52) - renamed ImFont::Glyph to ImFontGlyph. Keep redirection typedef (will obsolete).
+ - 2017/09/26 (1.52) - renamed ImFont::Glyph to ImFontGlyph. Kept redirection typedef (will obsolete).
- 2017/09/25 (1.52) - removed SetNextWindowPosCenter() because SetNextWindowPos() now has the optional pivot information to do the same and more. Kept redirection function (will obsolete).
- 2017/08/25 (1.52) - io.MousePos needs to be set to ImVec2(-FLT_MAX,-FLT_MAX) when mouse is unavailable/missing. Previously ImVec2(-1,-1) was enough but we now accept negative mouse coordinates. In your binding if you need to support unavailable mouse, make sure to replace "io.MousePos = ImVec2(-1,-1)" with "io.MousePos = ImVec2(-FLT_MAX,-FLT_MAX)".
- 2017/08/22 (1.51) - renamed IsItemHoveredRect() to IsItemRectHovered(). Kept inline redirection function (will obsolete). -> (1.52) use IsItemHovered(ImGuiHoveredFlags_RectOnly)!
@@ -460,10 +465,10 @@ CODE
- renamed IsMouseHoveringWindow() to IsWindowRectHovered() for consistency. Kept inline redirection function (will obsolete).
- 2017/08/20 (1.51) - renamed GetStyleColName() to GetStyleColorName() for consistency.
- 2017/08/20 (1.51) - added PushStyleColor(ImGuiCol idx, ImU32 col) overload, which _might_ cause an "ambiguous call" compilation error if you are using ImColor() with implicit cast. Cast to ImU32 or ImVec4 explicily to fix.
- - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame.
+ - 2017/08/15 (1.51) - marked the weird IMGUI_ONCE_UPON_A_FRAME helper macro as obsolete. prefer using the more explicit ImGuiOnceUponAFrame type.
- 2017/08/15 (1.51) - changed parameter order for BeginPopupContextWindow() from (const char*,int buttons,bool also_over_items) to (const char*,int buttons,bool also_over_items). Note that most calls relied on default parameters completely.
- - 2017/08/13 (1.51) - renamed ImGuiCol_Columns*** to ImGuiCol_Separator***. Kept redirection enums (will obsolete).
- - 2017/08/11 (1.51) - renamed ImGuiSetCond_*** types and flags to ImGuiCond_***. Kept redirection enums (will obsolete).
+ - 2017/08/13 (1.51) - renamed ImGuiCol_Column to ImGuiCol_Separator, ImGuiCol_ColumnHovered to ImGuiCol_SeparatorHovered, ImGuiCol_ColumnActive to ImGuiCol_SeparatorActive. Kept redirection enums (will obsolete).
+ - 2017/08/11 (1.51) - renamed ImGuiSetCond_Always to ImGuiCond_Always, ImGuiSetCond_Once to ImGuiCond_Once, ImGuiSetCond_FirstUseEver to ImGuiCond_FirstUseEver, ImGuiSetCond_Appearing to ImGuiCond_Appearing. Kept redirection enums (will obsolete).
- 2017/08/09 (1.51) - removed ValueColor() helpers, they are equivalent to calling Text(label) + SameLine() + ColorButton().
- 2017/08/08 (1.51) - removed ColorEditMode() and ImGuiColorEditMode in favor of ImGuiColorEditFlags and parameters to the various Color*() functions. The SetColorEditOptions() allows to initialize default but the user can still change them with right-click context menu.
- changed prototype of 'ColorEdit4(const char* label, float col[4], bool show_alpha = true)' to 'ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flags = 0)', where passing flags = 0x01 is a safe no-op (hello dodgy backward compatibility!). - check and run the demo window, under "Color/Picker Widgets", to understand the various new options.
@@ -840,6 +845,8 @@ CODE
main font. Then you can refer to icons within your strings.
You may want to see ImFontConfig::GlyphMinAdvanceX to make your icon look monospace to facilitate alignment.
(Read the 'misc/fonts/README.txt' file for more details about icons font loading.)
+ With some extra effort, you may use colorful icon by registering custom rectangle space inside the font atlas,
+ and copying your own graphics data into it. See misc/fonts/README.txt about using the AddCustomRectFontGlyph API.
Q: How can I load multiple fonts?
A: Use the font atlas to pack them into a single texture:
@@ -991,6 +998,7 @@ CODE
// Debug options
#define IMGUI_DEBUG_NAV_SCORING 0 // Display navigation scoring preview when hovering items. Display last moving direction matches when holding CTRL
#define IMGUI_DEBUG_NAV_RECTS 0 // Display the reference navigation rectangle for each window
+#define IMGUI_DEBUG_INI_SETTINGS 0 // Save additional comments in .ini file
// Visual Studio warnings
#ifdef _MSC_VER
@@ -1016,6 +1024,8 @@ CODE
#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
#endif
#elif defined(__GNUC__)
+// We disable -Wpragmas because GCC doesn't provide an has_warning equivalent and some forks/patches may not following the warning/version association.
+#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
#pragma GCC diagnostic ignored "-Wformat" // warning: format '%p' expects argument of type 'void*', but argument 6 has type 'ImGuiWindow*'
@@ -1023,9 +1033,7 @@ CODE
#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked
#pragma GCC diagnostic ignored "-Wstrict-overflow" // warning: assuming signed overflow does not occur when assuming that (X - c) > X is always false
-#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
+#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
#endif
// When using CTRL+TAB (or Gamepad Square+L/R) we delay the visual a little in order to reduce visual noise doing a fast switch.
@@ -1035,6 +1043,7 @@ static const float NAV_WINDOWING_LIST_APPEAR_DELAY = 0.15f; // Time
// Window resizing from edges (when io.ConfigWindowsResizeFromEdges = true and ImGuiBackendFlags_HasMouseCursors is set in io.BackendFlags by back-end)
static const float WINDOWS_RESIZE_FROM_EDGES_HALF_THICKNESS = 4.0f; // Extend outside and inside windows. Affect FindHoveredWindow().
static const float WINDOWS_RESIZE_FROM_EDGES_FEEDBACK_TIMER = 0.04f; // Reduce visual noise by only highlighting the border after a certain time.
+static const float WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER = 2.00f; // Lock scrolled window (so it doesn't pick child windows that are scrolling through) for a certaint time, unless mouse moved.
//-------------------------------------------------------------------------
// [SECTION] FORWARD DECLARATIONS
@@ -1082,6 +1091,7 @@ static int FindWindowFocusIndex(ImGuiWindow* window);
static void UpdateMouseInputs();
static void UpdateMouseWheel();
static bool UpdateManualResize(ImGuiWindow* window, const ImVec2& size_auto_fit, int* border_held, int resize_grip_count, ImU32 resize_grip_col[4]);
+static void UpdateDebugToolItemPicker();
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);
@@ -1156,6 +1166,7 @@ ImGuiStyle::ImGuiStyle()
GrabRounding = 0.0f; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
TabRounding = 4.0f; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
TabBorderSize = 0.0f; // Thickness of border around tabs.
+ ColorButtonPosition = ImGuiDir_Right; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
ButtonTextAlign = ImVec2(0.5f,0.5f);// Alignment of button text when button is larger than text.
SelectableTextAlign = ImVec2(0.0f,0.0f);// Alignment of selectable text when button is larger than text.
DisplayWindowPadding = ImVec2(19,19); // Window position are clamped to be visible within the display area by at least this amount. Only applies to regular windows.
@@ -1917,15 +1928,15 @@ ImU32 ImGui::GetColorU32(ImU32 col)
//-----------------------------------------------------------------------------
// std::lower_bound but without the bullshit
-static ImGuiStorage::Pair* LowerBound(ImVector<ImGuiStorage::Pair>& data, ImGuiID key)
+static ImGuiStorage::ImGuiStoragePair* LowerBound(ImVector<ImGuiStorage::ImGuiStoragePair>& data, ImGuiID key)
{
- ImGuiStorage::Pair* first = data.Data;
- ImGuiStorage::Pair* last = data.Data + data.Size;
+ ImGuiStorage::ImGuiStoragePair* first = data.Data;
+ ImGuiStorage::ImGuiStoragePair* last = data.Data + data.Size;
size_t count = (size_t)(last - first);
while (count > 0)
{
size_t count2 = count >> 1;
- ImGuiStorage::Pair* mid = first + count2;
+ ImGuiStorage::ImGuiStoragePair* mid = first + count2;
if (mid->key < key)
{
first = ++mid;
@@ -1947,18 +1958,18 @@ void ImGuiStorage::BuildSortByKey()
static int IMGUI_CDECL PairCompareByID(const void* lhs, const void* rhs)
{
// We can't just do a subtraction because qsort uses signed integers and subtracting our ID doesn't play well with that.
- if (((const Pair*)lhs)->key > ((const Pair*)rhs)->key) return +1;
- if (((const Pair*)lhs)->key < ((const Pair*)rhs)->key) return -1;
+ if (((const ImGuiStoragePair*)lhs)->key > ((const ImGuiStoragePair*)rhs)->key) return +1;
+ if (((const ImGuiStoragePair*)lhs)->key < ((const ImGuiStoragePair*)rhs)->key) return -1;
return 0;
}
};
if (Data.Size > 1)
- ImQsort(Data.Data, (size_t)Data.Size, sizeof(Pair), StaticFunc::PairCompareByID);
+ ImQsort(Data.Data, (size_t)Data.Size, sizeof(ImGuiStoragePair), StaticFunc::PairCompareByID);
}
int ImGuiStorage::GetInt(ImGuiID key, int default_val) const
{
- ImGuiStorage::Pair* it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
+ ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
if (it == Data.end() || it->key != key)
return default_val;
return it->val_i;
@@ -1971,7 +1982,7 @@ bool ImGuiStorage::GetBool(ImGuiID key, bool default_val) const
float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
{
- ImGuiStorage::Pair* it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
+ ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
if (it == Data.end() || it->key != key)
return default_val;
return it->val_f;
@@ -1979,7 +1990,7 @@ float ImGuiStorage::GetFloat(ImGuiID key, float default_val) const
void* ImGuiStorage::GetVoidPtr(ImGuiID key) const
{
- ImGuiStorage::Pair* it = LowerBound(const_cast<ImVector<ImGuiStorage::Pair>&>(Data), key);
+ ImGuiStoragePair* it = LowerBound(const_cast<ImVector<ImGuiStoragePair>&>(Data), key);
if (it == Data.end() || it->key != key)
return NULL;
return it->val_p;
@@ -1988,9 +1999,9 @@ void* ImGuiStorage::GetVoidPtr(ImGuiID key) const
// References are only valid until a new value is added to the storage. Calling a Set***() function or a Get***Ref() function invalidates the pointer.
int* ImGuiStorage::GetIntRef(ImGuiID key, int default_val)
{
- ImGuiStorage::Pair* it = LowerBound(Data, key);
+ ImGuiStoragePair* it = LowerBound(Data, key);
if (it == Data.end() || it->key != key)
- it = Data.insert(it, Pair(key, default_val));
+ it = Data.insert(it, ImGuiStoragePair(key, default_val));
return &it->val_i;
}
@@ -2001,27 +2012,27 @@ bool* ImGuiStorage::GetBoolRef(ImGuiID key, bool default_val)
float* ImGuiStorage::GetFloatRef(ImGuiID key, float default_val)
{
- ImGuiStorage::Pair* it = LowerBound(Data, key);
+ ImGuiStoragePair* it = LowerBound(Data, key);
if (it == Data.end() || it->key != key)
- it = Data.insert(it, Pair(key, default_val));
+ it = Data.insert(it, ImGuiStoragePair(key, default_val));
return &it->val_f;
}
void** ImGuiStorage::GetVoidPtrRef(ImGuiID key, void* default_val)
{
- ImGuiStorage::Pair* it = LowerBound(Data, key);
+ ImGuiStoragePair* it = LowerBound(Data, key);
if (it == Data.end() || it->key != key)
- it = Data.insert(it, Pair(key, default_val));
+ it = Data.insert(it, ImGuiStoragePair(key, default_val));
return &it->val_p;
}
// FIXME-OPT: Need a way to reuse the result of lower_bound when doing GetInt()/SetInt() - not too bad because it only happens on explicit interaction (maximum one a frame)
void ImGuiStorage::SetInt(ImGuiID key, int val)
{
- ImGuiStorage::Pair* it = LowerBound(Data, key);
+ ImGuiStoragePair* it = LowerBound(Data, key);
if (it == Data.end() || it->key != key)
{
- Data.insert(it, Pair(key, val));
+ Data.insert(it, ImGuiStoragePair(key, val));
return;
}
it->val_i = val;
@@ -2034,10 +2045,10 @@ void ImGuiStorage::SetBool(ImGuiID key, bool val)
void ImGuiStorage::SetFloat(ImGuiID key, float val)
{
- ImGuiStorage::Pair* it = LowerBound(Data, key);
+ ImGuiStoragePair* it = LowerBound(Data, key);
if (it == Data.end() || it->key != key)
{
- Data.insert(it, Pair(key, val));
+ Data.insert(it, ImGuiStoragePair(key, val));
return;
}
it->val_f = val;
@@ -2045,10 +2056,10 @@ void ImGuiStorage::SetFloat(ImGuiID key, float val)
void ImGuiStorage::SetVoidPtr(ImGuiID key, void* val)
{
- ImGuiStorage::Pair* it = LowerBound(Data, key);
+ ImGuiStoragePair* it = LowerBound(Data, key);
if (it == Data.end() || it->key != key)
{
- Data.insert(it, Pair(key, val));
+ Data.insert(it, ImGuiStoragePair(key, val));
return;
}
it->val_p = val;
@@ -2089,7 +2100,7 @@ bool ImGuiTextFilter::Draw(const char* label, float width)
return value_changed;
}
-void ImGuiTextFilter::TextRange::split(char separator, ImVector<TextRange>* out) const
+void ImGuiTextFilter::ImGuiTextRange::split(char separator, ImVector<ImGuiTextRange>* out) const
{
out->resize(0);
const char* wb = b;
@@ -2098,25 +2109,25 @@ void ImGuiTextFilter::TextRange::split(char separator, ImVector<TextRange>* out)
{
if (*we == separator)
{
- out->push_back(TextRange(wb, we));
+ out->push_back(ImGuiTextRange(wb, we));
wb = we + 1;
}
we++;
}
if (wb != we)
- out->push_back(TextRange(wb, we));
+ out->push_back(ImGuiTextRange(wb, we));
}
void ImGuiTextFilter::Build()
{
Filters.resize(0);
- TextRange input_range(InputBuf, InputBuf+strlen(InputBuf));
+ ImGuiTextRange input_range(InputBuf, InputBuf+strlen(InputBuf));
input_range.split(',', &Filters);
CountGrep = 0;
for (int i = 0; i != Filters.Size; i++)
{
- TextRange& f = Filters[i];
+ ImGuiTextRange& f = Filters[i];
while (f.b < f.e && ImCharIsBlankA(f.b[0]))
f.b++;
while (f.e > f.b && ImCharIsBlankA(f.e[-1]))
@@ -2138,19 +2149,19 @@ bool ImGuiTextFilter::PassFilter(const char* text, const char* text_end) const
for (int i = 0; i != Filters.Size; i++)
{
- const TextRange& f = Filters[i];
+ const ImGuiTextRange& f = Filters[i];
if (f.empty())
continue;
if (f.b[0] == '-')
{
// Subtract
- if (ImStristr(text, text_end, f.begin()+1, f.end()) != NULL)
+ if (ImStristr(text, text_end, f.b + 1, f.e) != NULL)
return false;
}
else
{
// Grep
- if (ImStristr(text, text_end, f.begin(), f.end()) != NULL)
+ if (ImStristr(text, text_end, f.b, f.e) != NULL)
return true;
}
}
@@ -2233,20 +2244,64 @@ void ImGuiTextBuffer::appendfv(const char* fmt, va_list args)
//-----------------------------------------------------------------------------
// [SECTION] ImGuiListClipper
-// This is currently not as flexible/powerful as it should be, needs some rework (see TODO)
+// This is currently not as flexible/powerful as it should be and really confusing/spaghetti, mostly because we changed
+// the API mid-way through development and support two ways to using the clipper, needs some rework (see TODO)
//-----------------------------------------------------------------------------
+// Helper to calculate coarse clipping of large list of evenly sized items.
+// NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern.
+// NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX
+void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end)
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
+ if (g.LogEnabled)
+ {
+ // If logging is active, do not perform any clipping
+ *out_items_display_start = 0;
+ *out_items_display_end = items_count;
+ return;
+ }
+ if (window->SkipItems)
+ {
+ *out_items_display_start = *out_items_display_end = 0;
+ return;
+ }
+
+ // We create the union of the ClipRect and the NavScoringRect which at worst should be 1 page away from ClipRect
+ ImRect unclipped_rect = window->ClipRect;
+ if (g.NavMoveRequest)
+ unclipped_rect.Add(g.NavScoringRectScreen);
+
+ const ImVec2 pos = window->DC.CursorPos;
+ int start = (int)((unclipped_rect.Min.y - pos.y) / items_height);
+ int end = (int)((unclipped_rect.Max.y - pos.y) / items_height);
+
+ // When performing a navigation request, ensure we have one item extra in the direction we are moving to
+ if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Up)
+ start--;
+ if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Down)
+ end++;
+
+ start = ImClamp(start, 0, items_count);
+ end = ImClamp(end + 1, start, items_count);
+ *out_items_display_start = start;
+ *out_items_display_end = end;
+}
+
static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height)
{
// Set cursor position and a few other things so that SetScrollHereY() and Columns() can work when seeking cursor.
// FIXME: It is problematic that we have to do that here, because custom/equivalent end-user code would stumble on the same issue.
// The clipper should probably have a 4th step to display the last item in a regular manner.
- ImGui::SetCursorPosY(pos_y);
- ImGuiWindow* window = ImGui::GetCurrentWindow();
- window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHereY() can properly function after the end of our clipper usage.
- window->DC.PrevLineSize.y = (line_height - GImGui->Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list.
- if (window->DC.CurrentColumns)
- window->DC.CurrentColumns->LineMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
+ window->DC.CursorPos.y = pos_y;
+ window->DC.CursorMaxPos.y = ImMax(window->DC.CursorMaxPos.y, pos_y);
+ window->DC.CursorPosPrevLine.y = window->DC.CursorPos.y - line_height; // Setting those fields so that SetScrollHereY() can properly function after the end of our clipper usage.
+ window->DC.PrevLineSize.y = (line_height - g.Style.ItemSpacing.y); // If we end up needing more accurate data (to e.g. use SameLine) we may as well make the clipper have a fourth step to let user process and display the last item in their list.
+ if (ImGuiColumns* columns = window->DC.CurrentColumns)
+ columns->LineMinY = window->DC.CursorPos.y; // Setting this so that cell Y position are set properly
}
// Use case A: Begin() called from constructor with items_height<0, then called again from Sync() in StepNo 1
@@ -2254,7 +2309,10 @@ static void SetCursorPosYAndSetupDummyPrevLine(float pos_y, float line_height)
// FIXME-LEGACY: Ideally we should remove the Begin/End functions but they are part of the legacy API we still support. This is why some of the code in Step() calling Begin() and reassign some fields, spaghetti style.
void ImGuiListClipper::Begin(int count, float items_height)
{
- StartPosY = ImGui::GetCursorPosY();
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
+
+ StartPosY = window->DC.CursorPos.y;
ItemsHeight = items_height;
ItemsCount = count;
StepNo = 0;
@@ -2281,7 +2339,10 @@ void ImGuiListClipper::End()
bool ImGuiListClipper::Step()
{
- if (ItemsCount == 0 || ImGui::GetCurrentWindowRead()->SkipItems)
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
+
+ if (ItemsCount == 0 || window->SkipItems)
{
ItemsCount = -1;
return false;
@@ -2290,16 +2351,16 @@ bool ImGuiListClipper::Step()
{
DisplayStart = 0;
DisplayEnd = 1;
- StartPosY = ImGui::GetCursorPosY();
+ StartPosY = window->DC.CursorPos.y;
StepNo = 1;
return true;
}
if (StepNo == 1) // Step 1: the clipper infer height from first element, calculate the actual range of elements to display, and position the cursor before the first element.
{
if (ItemsCount == 1) { ItemsCount = -1; return false; }
- float items_height = ImGui::GetCursorPosY() - StartPosY;
+ float items_height = window->DC.CursorPos.y - StartPosY;
IM_ASSERT(items_height > 0.0f); // If this triggers, it means Item 0 hasn't moved the cursor vertically
- Begin(ItemsCount-1, items_height);
+ Begin(ItemsCount - 1, items_height);
DisplayStart++;
DisplayEnd++;
StepNo = 3;
@@ -2911,6 +2972,15 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
if (g.NavWindow->RootWindowForNav == window->RootWindowForNav)
if (window == g.NavWindow || ((window->Flags | g.NavWindow->Flags) & ImGuiWindowFlags_NavFlattened))
NavProcessItem(window, nav_bb_arg ? *nav_bb_arg : bb, id);
+
+ // [DEBUG] Item Picker tool, when enabling the "extended" version we perform the check in ItemAdd()
+#ifdef IMGUI_DEBUG_TOOL_ITEM_PICKER_EX
+ if (id == g.DebugItemPickerBreakID)
+ {
+ IM_DEBUG_BREAK();
+ g.DebugItemPickerBreakID = 0;
+ }
+#endif
}
window->DC.LastItemId = id;
@@ -2999,6 +3069,17 @@ bool ImGui::ItemHoverable(const ImRect& bb, ImGuiID id)
return false;
SetHoveredID(id);
+
+ // [DEBUG] Item Picker tool!
+ // We perform the check here because SetHoveredID() is not frequently called (1~ time a frame), making
+ // the cost of this tool near-zero. We can get slightly better call-stack and support picking non-hovered
+ // items if we perform the test in ItemAdd(), but that would incur a small runtime cost.
+ // #define IMGUI_DEBUG_TOOL_ITEM_PICKER_EX in imconfig.h if you want this check to also be performed in ItemAdd().
+ if (g.DebugItemPickerActive && g.HoveredIdPreviousFrame == id)
+ GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 255, 0, 255));
+ if (g.DebugItemPickerBreakID == id)
+ IM_DEBUG_BREAK();
+
return true;
}
@@ -3294,7 +3375,7 @@ void ImGui::UpdateMouseMovingWindowEndFrame()
if (!g.HoveredRootWindow->TitleBarRect().Contains(g.IO.MouseClickedPos[0]))
g.MovingWindow = NULL;
}
- else if (g.NavWindow != NULL && GetFrontMostPopupModal() == NULL)
+ else if (g.NavWindow != NULL && GetTopMostPopupModal() == NULL)
{
// Clicking on void disable focus
FocusWindow(NULL);
@@ -3306,9 +3387,9 @@ void ImGui::UpdateMouseMovingWindowEndFrame()
// (The left mouse button path calls FocusWindow on the hovered window, which will lead NewFrame->ClosePopupsOverWindow to trigger)
if (g.IO.MouseClicked[1])
{
- // Find the top-most window between HoveredWindow and the front most Modal Window.
+ // Find the top-most window between HoveredWindow and the top-most Modal Window.
// This is where we can trim the popup stack.
- ImGuiWindow* modal = GetFrontMostPopupModal();
+ ImGuiWindow* modal = GetTopMostPopupModal();
bool hovered_window_above_modal = false;
if (modal == NULL)
hovered_window_above_modal = true;
@@ -3386,19 +3467,45 @@ static void ImGui::UpdateMouseInputs()
}
}
-void ImGui::UpdateMouseWheel()
+static void StartLockWheelingWindow(ImGuiWindow* window)
{
ImGuiContext& g = *GImGui;
- if (!g.HoveredWindow || g.HoveredWindow->Collapsed)
+ if (g.WheelingWindow == window)
return;
+ g.WheelingWindow = window;
+ g.WheelingWindowRefMousePos = g.IO.MousePos;
+ g.WheelingWindowTimer = WINDOWS_MOUSE_WHEEL_SCROLL_LOCK_TIMER;
+}
+
+void ImGui::UpdateMouseWheel()
+{
+ ImGuiContext& g = *GImGui;
+
+ // Reset the locked window if we move the mouse or after the timer elapses
+ if (g.WheelingWindow != NULL)
+ {
+ g.WheelingWindowTimer -= g.IO.DeltaTime;
+ if (IsMousePosValid() && ImLengthSqr(g.IO.MousePos - g.WheelingWindowRefMousePos) > g.IO.MouseDragThreshold * g.IO.MouseDragThreshold)
+ g.WheelingWindowTimer = 0.0f;
+ if (g.WheelingWindowTimer <= 0.0f)
+ {
+ g.WheelingWindow = NULL;
+ g.WheelingWindowTimer = 0.0f;
+ }
+ }
+
if (g.IO.MouseWheel == 0.0f && g.IO.MouseWheelH == 0.0f)
return;
- ImGuiWindow* window = g.HoveredWindow;
+
+ ImGuiWindow* window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow;
+ if (!window || window->Collapsed)
+ return;
// 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 && !window->Collapsed)
+ if (g.IO.MouseWheel != 0.0f && g.IO.KeyCtrl && g.IO.FontAllowUserScaling)
{
+ StartLockWheelingWindow(window);
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;
window->FontWindowScale = new_font_scale;
@@ -3413,31 +3520,35 @@ void ImGui::UpdateMouseWheel()
}
// Mouse wheel scrolling
- // If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent (unless either ImGuiWindowFlags_NoInputs or ImGuiWindowFlags_NoScrollbar are also set).
- while ((window->Flags & ImGuiWindowFlags_ChildWindow) && (window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs) && window->ParentWindow)
- window = window->ParentWindow;
- const bool scroll_allowed = !(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs);
- if (scroll_allowed && (g.IO.MouseWheel != 0.0f || g.IO.MouseWheelH != 0.0f) && !g.IO.KeyCtrl)
- {
- ImVec2 max_step = (window->ContentsRegionRect.GetSize() + window->WindowPadding * 2.0f) * 0.67f;
+ // If a child window has the ImGuiWindowFlags_NoScrollWithMouse flag, we give a chance to scroll its parent
- // Vertical Mouse Wheel Scrolling (hold Shift to scroll horizontally)
- if (g.IO.MouseWheel != 0.0f && !g.IO.KeyShift)
- {
- float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step.y));
- SetWindowScrollY(window, window->Scroll.y - g.IO.MouseWheel * scroll_step);
- }
- else if (g.IO.MouseWheel != 0.0f && g.IO.KeyShift)
+ // Vertical Mouse Wheel scrolling
+ const float wheel_y = (g.IO.MouseWheel != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f;
+ if (wheel_y != 0.0f && !g.IO.KeyCtrl)
+ {
+ StartLockWheelingWindow(window);
+ while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.y == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))))
+ window = window->ParentWindow;
+ if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))
{
- float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step.x));
- SetWindowScrollX(window, window->Scroll.x - g.IO.MouseWheel * scroll_step);
+ float max_step = window->InnerRect.GetHeight() * 0.67f;
+ float scroll_step = ImFloor(ImMin(5 * window->CalcFontSize(), max_step));
+ SetScrollY(window, window->Scroll.y - wheel_y * scroll_step);
}
+ }
- // Horizontal Mouse Wheel Scrolling (for hardware that supports it)
- if (g.IO.MouseWheelH != 0.0f && !g.IO.KeyShift)
+ // Horizontal Mouse Wheel scrolling, or Vertical Mouse Wheel w/ Shift held
+ const float wheel_x = (g.IO.MouseWheelH != 0.0f && !g.IO.KeyShift) ? g.IO.MouseWheelH : (g.IO.MouseWheel != 0.0f && g.IO.KeyShift) ? g.IO.MouseWheel : 0.0f;
+ if (wheel_x != 0.0f && !g.IO.KeyCtrl)
+ {
+ StartLockWheelingWindow(window);
+ while ((window->Flags & ImGuiWindowFlags_ChildWindow) && ((window->ScrollMax.x == 0.0f) || ((window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))))
+ window = window->ParentWindow;
+ if (!(window->Flags & ImGuiWindowFlags_NoScrollWithMouse) && !(window->Flags & ImGuiWindowFlags_NoMouseInputs))
{
- float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step.x));
- SetWindowScrollX(window, window->Scroll.x - g.IO.MouseWheelH * scroll_step);
+ float max_step = window->InnerRect.GetWidth() * 0.67f;
+ float scroll_step = ImFloor(ImMin(2 * window->CalcFontSize(), max_step));
+ SetScrollX(window, window->Scroll.x - wheel_x * scroll_step);
}
}
}
@@ -3454,7 +3565,7 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags()
FindHoveredWindow();
// Modal windows prevents cursor from hovering behind them.
- ImGuiWindow* modal_window = GetFrontMostPopupModal();
+ ImGuiWindow* modal_window = GetTopMostPopupModal();
if (modal_window)
if (g.HoveredRootWindow && !IsWindowChildOf(g.HoveredRootWindow, modal_window))
g.HoveredRootWindow = g.HoveredWindow = NULL;
@@ -3501,15 +3612,10 @@ void ImGui::UpdateHoveredWindowAndCaptureFlags()
g.IO.WantTextInput = (g.WantTextInputNextFrame != -1) ? (g.WantTextInputNextFrame != 0) : false;
}
-void ImGui::NewFrame()
+static void NewFrameSanityChecks()
{
- IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
ImGuiContext& g = *GImGui;
-#ifdef IMGUI_ENABLE_TEST_ENGINE
- ImGuiTestEngineHook_PreNewFrame(&g);
-#endif
-
// Check user data
// (We pass an error message in the assert expression to make it visible to programmers who are not using a debugger, as most assert handlers display their argument)
IM_ASSERT(g.Initialized);
@@ -3522,7 +3628,6 @@ void ImGui::NewFrame()
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)");
@@ -3533,6 +3638,19 @@ void ImGui::NewFrame()
// Perform simple check: the beta io.ConfigWindowsResizeFromEdges option requires back-end to honor mouse cursor changes and set the ImGuiBackendFlags_HasMouseCursors flag accordingly.
if (g.IO.ConfigWindowsResizeFromEdges && !(g.IO.BackendFlags & ImGuiBackendFlags_HasMouseCursors))
g.IO.ConfigWindowsResizeFromEdges = false;
+}
+
+void ImGui::NewFrame()
+{
+ IM_ASSERT(GImGui != NULL && "No current context. Did you call ImGui::CreateContext() and ImGui::SetCurrentContext() ?");
+ ImGuiContext& g = *GImGui;
+
+#ifdef IMGUI_ENABLE_TEST_ENGINE
+ ImGuiTestEngineHook_PreNewFrame(&g);
+#endif
+
+ // Check and assert for various common IO and Configuration mistakes
+ NewFrameSanityChecks();
// Load settings on first frame (if not explicitly loaded manually before)
if (!g.SettingsLoaded)
@@ -3650,7 +3768,7 @@ void ImGui::NewFrame()
UpdateMouseMovingWindowNewFrame();
// Background darkening/whitening
- if (GetFrontMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f))
+ if (GetTopMostPopupModal() != NULL || (g.NavWindowingTarget != NULL && g.NavWindowingHighlightAlpha > 0.0f))
g.DimBgRatio = ImMin(g.DimBgRatio + g.IO.DeltaTime * 6.0f, 1.0f);
else
g.DimBgRatio = ImMax(g.DimBgRatio - g.IO.DeltaTime * 10.0f, 0.0f);
@@ -3714,6 +3832,9 @@ void ImGui::NewFrame()
g.BeginPopupStack.resize(0);
ClosePopupsOverWindow(g.NavWindow, false);
+ // [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack.
+ UpdateDebugToolItemPicker();
+
// Create implicit/fallback window - which we will only render it if the user has added something to it.
// We don't use "Debug" to avoid colliding with user trying to create a "Debug" window with custom flags.
// This fallback is particularly important as it avoid ImGui:: calls from crashing.
@@ -3726,6 +3847,31 @@ void ImGui::NewFrame()
#endif
}
+// [DEBUG] Item picker tool - start with DebugStartItemPicker() - useful to visually select an item and break into its call-stack.
+void ImGui::UpdateDebugToolItemPicker()
+{
+ ImGuiContext& g = *GImGui;
+ g.DebugItemPickerBreakID = 0;
+ if (g.DebugItemPickerActive)
+ {
+ const ImGuiID hovered_id = g.HoveredIdPreviousFrame;
+ ImGui::SetMouseCursor(ImGuiMouseCursor_Hand);
+ if (ImGui::IsKeyPressedMap(ImGuiKey_Escape))
+ g.DebugItemPickerActive = false;
+ if (ImGui::IsMouseClicked(0) && hovered_id)
+ {
+ g.DebugItemPickerBreakID = hovered_id;
+ g.DebugItemPickerActive = false;
+ }
+ ImGui::SetNextWindowBgAlpha(0.60f);
+ ImGui::BeginTooltip();
+ ImGui::Text("HoveredId: 0x%08X", hovered_id);
+ ImGui::Text("Press ESC to abort picking.");
+ ImGui::TextColored(GetStyleColorVec4(hovered_id ? ImGuiCol_Text : ImGuiCol_TextDisabled), "Click to break in debugger!");
+ ImGui::EndTooltip();
+ }
+}
+
void ImGui::Initialize(ImGuiContext* context)
{
ImGuiContext& g = *context;
@@ -3789,6 +3935,11 @@ void ImGui::Shutdown(ImGuiContext* context)
g.DrawDataBuilder.ClearFreeMemory();
g.BackgroundDrawList.ClearFreeMemory();
g.ForegroundDrawList.ClearFreeMemory();
+
+ g.TabBars.Clear();
+ g.CurrentTabBarStack.clear();
+ g.ShrinkWidthBuffer.clear();
+
g.PrivateClipboard.clear();
g.InputTextState.ClearFreeMemory();
@@ -4058,18 +4209,18 @@ void ImGui::Render()
if (!g.BackgroundDrawList.VtxBuffer.empty())
AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.BackgroundDrawList);
- ImGuiWindow* windows_to_render_front_most[2];
- windows_to_render_front_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL;
- windows_to_render_front_most[1] = g.NavWindowingTarget ? g.NavWindowingList : NULL;
+ ImGuiWindow* windows_to_render_top_most[2];
+ windows_to_render_top_most[0] = (g.NavWindowingTarget && !(g.NavWindowingTarget->Flags & ImGuiWindowFlags_NoBringToFrontOnFocus)) ? g.NavWindowingTarget->RootWindow : NULL;
+ windows_to_render_top_most[1] = g.NavWindowingTarget ? g.NavWindowingList : NULL;
for (int n = 0; n != g.Windows.Size; n++)
{
ImGuiWindow* window = g.Windows[n];
- if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_front_most[0] && window != windows_to_render_front_most[1])
+ if (IsWindowActiveAndVisible(window) && (window->Flags & ImGuiWindowFlags_ChildWindow) == 0 && window != windows_to_render_top_most[0] && window != windows_to_render_top_most[1])
AddRootWindowToDrawData(window);
}
- for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_front_most); n++)
- if (windows_to_render_front_most[n] && IsWindowActiveAndVisible(windows_to_render_front_most[n])) // NavWindowingTarget is always temporarily displayed as the front-most window
- AddRootWindowToDrawData(windows_to_render_front_most[n]);
+ for (int n = 0; n < IM_ARRAYSIZE(windows_to_render_top_most); n++)
+ if (windows_to_render_top_most[n] && IsWindowActiveAndVisible(windows_to_render_top_most[n])) // NavWindowingTarget is always temporarily displayed as the top-most window
+ AddRootWindowToDrawData(windows_to_render_top_most[n]);
g.DrawDataBuilder.FlattenIntoSingleLayer();
// Draw software mouse cursor if requested
@@ -4115,47 +4266,6 @@ ImVec2 ImGui::CalcTextSize(const char* text, const char* text_end, bool hide_tex
return text_size;
}
-// Helper to calculate coarse clipping of large list of evenly sized items.
-// NB: Prefer using the ImGuiListClipper higher-level helper if you can! Read comments and instructions there on how those use this sort of pattern.
-// NB: 'items_count' is only used to clamp the result, if you don't know your count you can use INT_MAX
-void ImGui::CalcListClipping(int items_count, float items_height, int* out_items_display_start, int* out_items_display_end)
-{
- ImGuiContext& g = *GImGui;
- ImGuiWindow* window = g.CurrentWindow;
- if (g.LogEnabled)
- {
- // If logging is active, do not perform any clipping
- *out_items_display_start = 0;
- *out_items_display_end = items_count;
- return;
- }
- if (window->SkipItems)
- {
- *out_items_display_start = *out_items_display_end = 0;
- return;
- }
-
- // We create the union of the ClipRect and the NavScoringRect which at worst should be 1 page away from ClipRect
- ImRect unclipped_rect = window->ClipRect;
- if (g.NavMoveRequest)
- unclipped_rect.Add(g.NavScoringRectScreen);
-
- const ImVec2 pos = window->DC.CursorPos;
- int start = (int)((unclipped_rect.Min.y - pos.y) / items_height);
- int end = (int)((unclipped_rect.Max.y - pos.y) / items_height);
-
- // When performing a navigation request, ensure we have one item extra in the direction we are moving to
- if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Up)
- start--;
- if (g.NavMoveRequest && g.NavMoveClipDir == ImGuiDir_Down)
- end++;
-
- start = ImClamp(start, 0, items_count);
- end = ImClamp(end + 1, start, items_count);
- *out_items_display_start = start;
- *out_items_display_end = end;
-}
-
// Find window given position, search front-to-back
// FIXME: Note that we have an inconsequential lag here: OuterRectClipped is updated in Begin(), so windows moved programatically
// with SetWindowPos() and not SetNextWindowPos() will have that rectangle lagging by a frame at the time FindHoveredWindow() is
@@ -4323,17 +4433,25 @@ bool ImGui::IsMouseDoubleClicked(int button)
return g.IO.MouseDoubleClicked[button];
}
-bool ImGui::IsMouseDragging(int button, float lock_threshold)
+// [Internal] This doesn't test if the button is presed
+bool ImGui::IsMouseDragPastThreshold(int button, float lock_threshold)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
- if (!g.IO.MouseDown[button])
- return false;
if (lock_threshold < 0.0f)
lock_threshold = g.IO.MouseDragThreshold;
return g.IO.MouseDragMaxDistanceSqr[button] >= lock_threshold * lock_threshold;
}
+bool ImGui::IsMouseDragging(int button, float lock_threshold)
+{
+ ImGuiContext& g = *GImGui;
+ IM_ASSERT(button >= 0 && button < IM_ARRAYSIZE(g.IO.MouseDown));
+ if (!g.IO.MouseDown[button])
+ return false;
+ return IsMouseDragPastThreshold(button, lock_threshold);
+}
+
ImVec2 ImGui::GetMousePos()
{
return GImGui->IO.MousePos;
@@ -4686,6 +4804,7 @@ ImGuiWindow* ImGui::FindWindowByName(const char* name)
static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFlags flags)
{
ImGuiContext& g = *GImGui;
+ //IMGUI_DEBUG_LOG("CreateNewWindow '%s', flags = 0x%08X\n", name, flags);
// Create window the first time
ImGuiWindow* window = IM_NEW(ImGuiWindow)(&g, name);
@@ -4826,7 +4945,12 @@ 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->InnerRect.GetWidth();
+ float target_x = window->ScrollTarget.x;
+ if (snap_on_edges && cr_x <= 0.0f && target_x <= window->WindowPadding.x)
+ target_x = 0.0f;
+ else if (snap_on_edges && cr_x >= 1.0f && target_x >= window->ContentSize.x + window->WindowPadding.x + GImGui->Style.ItemSpacing.x)
+ target_x = window->ContentSize.x + window->WindowPadding.x * 2.0f;
+ scroll.x = target_x - cr_x * window->InnerRect.GetWidth();
}
if (window->ScrollTarget.y < FLT_MAX)
{
@@ -5513,7 +5637,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
const bool window_pos_with_pivot = (window->SetWindowPosVal.x != FLT_MAX && window->HiddenFramesCannotSkipItems == 0);
if (window_pos_with_pivot)
- SetWindowPos(window, ImMax(style.DisplaySafeAreaPadding, window->SetWindowPosVal - window->SizeFull * window->SetWindowPosPivot), 0); // Position given a pivot (e.g. for centering)
+ SetWindowPos(window, window->SetWindowPosVal - window->SizeFull * window->SetWindowPosPivot, 0); // Position given a pivot (e.g. for centering)
else if ((flags & ImGuiWindowFlags_ChildMenu) != 0)
window->Pos = FindBestWindowPosForPopup(window);
else if ((flags & ImGuiWindowFlags_Popup) != 0 && !window_pos_set_by_api && window_just_appearing_after_hidden_for_resize)
@@ -5614,7 +5738,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
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.x = ImFloor(0.5f + window->InnerRect.Max.x - ImMax(ImFloor(window->WindowPadding.x * 0.5f), window->WindowBorderSize));
window->InnerClipRect.Max.y = ImFloor(0.5f + window->InnerRect.Max.y - window->WindowBorderSize);
window->InnerClipRect.ClipWithFull(host_rect);
@@ -5644,7 +5768,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
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;
+ const bool dim_bg_for_modal = (flags & ImGuiWindowFlags_Modal) && window == GetTopMostPopupModal() && window->HiddenFramesCannotSkipItems <= 0;
const bool dim_bg_for_window_list = g.NavWindowingTargetAnim && (window == g.NavWindowingTargetAnim->RootWindow);
if (dim_bg_for_modal || dim_bg_for_window_list)
{
@@ -5673,6 +5797,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
if (render_decorations_in_parent)
window->DrawList = parent_window->DrawList;
+ // Handle title bar, scrollbar, resize grips and resize borders
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);
RenderWindowDecorations(window, title_bar_rect, title_bar_is_highlight, resize_grip_count, resize_grip_col, resize_grip_draw_size);
@@ -5817,9 +5942,11 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
if (window->OuterRectClipped.Min.x >= window->OuterRectClipped.Max.x || window->OuterRectClipped.Min.y >= window->OuterRectClipped.Max.y)
window->HiddenFramesCanSkipItems = 1;
- // Completely hide along with parent or if parent is collapsed
- if (parent_window && (parent_window->Collapsed || parent_window->Hidden))
+ // Hide along with parent or if parent is collapsed
+ if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCanSkipItems > 0))
window->HiddenFramesCanSkipItems = 1;
+ if (parent_window && (parent_window->Collapsed || parent_window->HiddenFramesCannotSkipItems > 0))
+ window->HiddenFramesCannotSkipItems = 1;
}
// Don't render if style alpha is 0.0 at the time of Begin(). This is arbitrary and inconsistent but has been there for a long while (may remove at some point)
@@ -5868,7 +5995,7 @@ void ImGui::End()
ImGuiWindow* window = g.CurrentWindow;
- if (window->DC.CurrentColumns != NULL)
+ if (window->DC.CurrentColumns)
EndColumns();
PopClipRect(); // Inner window clip rectangle
@@ -5889,7 +6016,7 @@ void ImGui::BringWindowToFocusFront(ImGuiWindow* window)
ImGuiContext& g = *GImGui;
if (g.WindowsFocusOrder.back() == window)
return;
- for (int i = g.WindowsFocusOrder.Size - 2; i >= 0; i--) // We can ignore the front most window
+ for (int i = g.WindowsFocusOrder.Size - 2; i >= 0; i--) // We can ignore the top-most window
if (g.WindowsFocusOrder[i] == window)
{
memmove(&g.WindowsFocusOrder[i], &g.WindowsFocusOrder[i + 1], (size_t)(g.WindowsFocusOrder.Size - i - 1) * sizeof(ImGuiWindow*));
@@ -5904,7 +6031,7 @@ void ImGui::BringWindowToDisplayFront(ImGuiWindow* window)
ImGuiWindow* current_front_window = g.Windows.back();
if (current_front_window == window || current_front_window->RootWindow == window)
return;
- for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the front most window
+ for (int i = g.Windows.Size - 2; i >= 0; i--) // We can ignore the top-most window
if (g.Windows[i] == window)
{
memmove(&g.Windows[i], &g.Windows[i + 1], (size_t)(g.Windows.Size - i - 1) * sizeof(ImGuiWindow*));
@@ -6438,16 +6565,6 @@ ImVec2 ImGui::GetWindowPos()
return window->Pos;
}
-void ImGui::SetWindowScrollX(ImGuiWindow* window, float new_scroll_x)
-{
- window->Scroll.x = new_scroll_x;
-}
-
-void ImGui::SetWindowScrollY(ImGuiWindow* window, float new_scroll_y)
-{
- window->Scroll.y = new_scroll_y;
-}
-
void ImGui::SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond)
{
// Test condition (NB: bit 0 is always true) and clear flags for next time
@@ -6642,20 +6759,22 @@ void ImGui::SetNextWindowBgAlpha(float alpha)
// FIXME: This is in window space (not screen space!). We should try to obsolete all those functions.
ImVec2 ImGui::GetContentRegionMax()
{
- ImGuiWindow* window = GImGui->CurrentWindow;
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
ImVec2 mx = window->ContentsRegionRect.Max - window->Pos;
if (window->DC.CurrentColumns)
- mx.x = GetColumnOffset(window->DC.CurrentColumns->Current + 1) - window->WindowPadding.x;
+ mx.x = window->WorkRect.Max.x - window->Pos.x;
return mx;
}
// [Internal] Absolute coordinate. Saner. This is not exposed until we finishing refactoring work rect features.
ImVec2 ImGui::GetContentRegionMaxAbs()
{
- ImGuiWindow* window = GImGui->CurrentWindow;
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
ImVec2 mx = window->ContentsRegionRect.Max;
if (window->DC.CurrentColumns)
- mx.x = window->Pos.x + GetColumnOffset(window->DC.CurrentColumns->Current + 1) - window->WindowPadding.x;
+ mx.x = window->WorkRect.Max.x;
return mx;
}
@@ -6668,19 +6787,19 @@ ImVec2 ImGui::GetContentRegionAvail()
// In window space (not screen space!)
ImVec2 ImGui::GetWindowContentRegionMin()
{
- ImGuiWindow* window = GetCurrentWindowRead();
+ ImGuiWindow* window = GImGui->CurrentWindow;
return window->ContentsRegionRect.Min - window->Pos;
}
ImVec2 ImGui::GetWindowContentRegionMax()
{
- ImGuiWindow* window = GetCurrentWindowRead();
+ ImGuiWindow* window = GImGui->CurrentWindow;
return window->ContentsRegionRect.Max - window->Pos;
}
float ImGui::GetWindowContentRegionWidth()
{
- ImGuiWindow* window = GetCurrentWindowRead();
+ ImGuiWindow* window = GImGui->CurrentWindow;
return window->ContentsRegionRect.GetWidth();
}
@@ -6835,6 +6954,27 @@ void ImGui::SetScrollY(float scroll_y)
window->ScrollTargetCenterRatio.y = 0.0f;
}
+void ImGui::SetScrollX(ImGuiWindow* window, float new_scroll_x)
+{
+ window->ScrollTarget.x = new_scroll_x;
+ window->ScrollTargetCenterRatio.x = 0.0f;
+}
+
+void ImGui::SetScrollY(ImGuiWindow* window, float new_scroll_y)
+{
+ window->ScrollTarget.y = new_scroll_y;
+ window->ScrollTargetCenterRatio.y = 0.0f;
+}
+
+void ImGui::SetScrollFromPosX(float local_x, float center_x_ratio)
+{
+ // We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size
+ ImGuiWindow* window = GetCurrentWindow();
+ IM_ASSERT(center_x_ratio >= 0.0f && center_x_ratio <= 1.0f);
+ window->ScrollTarget.x = (float)(int)(local_x + window->Scroll.x);
+ window->ScrollTargetCenterRatio.x = center_x_ratio;
+}
+
void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio)
{
// We store a target position so centering can occur on the next frame when we are guaranteed to have a known window size
@@ -6844,6 +6984,16 @@ void ImGui::SetScrollFromPosY(float local_y, float center_y_ratio)
window->ScrollTargetCenterRatio.y = center_y_ratio;
}
+// center_x_ratio: 0.0f left of last item, 0.5f horizontal center of last item, 1.0f right of last item.
+void ImGui::SetScrollHereX(float center_x_ratio)
+{
+ ImGuiWindow* window = GetCurrentWindow();
+ float target_x = window->DC.LastItemRect.Min.x - window->Pos.x; // Left of last item, in window space
+ float last_item_width = window->DC.LastItemRect.GetWidth();
+ target_x += (last_item_width * center_x_ratio) + (GImGui->Style.ItemSpacing.x * (center_x_ratio - 0.5f) * 2.0f); // Precisely aim before, in the middle or after the last item.
+ SetScrollFromPosX(target_x, center_x_ratio);
+}
+
// center_y_ratio: 0.0f top of last item, 0.5f vertical center of last item, 1.0f bottom of last item.
void ImGui::SetScrollHereY(float center_y_ratio)
{
@@ -7174,7 +7324,7 @@ bool ImGui::IsPopupOpen(const char* str_id)
return g.OpenPopupStack.Size > g.BeginPopupStack.Size && g.OpenPopupStack[g.BeginPopupStack.Size].PopupId == g.CurrentWindow->GetID(str_id);
}
-ImGuiWindow* ImGui::GetFrontMostPopupModal()
+ImGuiWindow* ImGui::GetTopMostPopupModal()
{
ImGuiContext& g = *GImGui;
for (int n = g.OpenPopupStack.Size-1; n >= 0; n--)
@@ -8029,7 +8179,7 @@ static void ImGui::NavUpdate()
// Update Keyboard->Nav inputs mapping
if (nav_keyboard_active)
{
- #define NAV_MAP_KEY(_KEY, _NAV_INPUT) if (IsKeyDown(g.IO.KeyMap[_KEY])) { g.IO.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_NavKeyboard; }
+ #define NAV_MAP_KEY(_KEY, _NAV_INPUT) do { if (IsKeyDown(g.IO.KeyMap[_KEY])) { g.IO.NavInputs[_NAV_INPUT] = 1.0f; g.NavInputSource = ImGuiInputSource_NavKeyboard; } } while (0)
NAV_MAP_KEY(ImGuiKey_Space, ImGuiNavInput_Activate );
NAV_MAP_KEY(ImGuiKey_Enter, ImGuiNavInput_Input );
NAV_MAP_KEY(ImGuiKey_Escape, ImGuiNavInput_Cancel );
@@ -8228,9 +8378,9 @@ static void ImGui::NavUpdate()
if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll && g.NavMoveRequest)
{
if (g.NavMoveDir == ImGuiDir_Left || g.NavMoveDir == ImGuiDir_Right)
- SetWindowScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
+ SetScrollX(window, ImFloor(window->Scroll.x + ((g.NavMoveDir == ImGuiDir_Left) ? -1.0f : +1.0f) * scroll_speed));
if (g.NavMoveDir == ImGuiDir_Up || g.NavMoveDir == ImGuiDir_Down)
- SetWindowScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed));
+ SetScrollY(window, ImFloor(window->Scroll.y + ((g.NavMoveDir == ImGuiDir_Up) ? -1.0f : +1.0f) * scroll_speed));
}
// *Normal* Manual scroll with NavScrollXXX keys
@@ -8238,12 +8388,12 @@ static void ImGui::NavUpdate()
ImVec2 scroll_dir = GetNavInputAmount2d(ImGuiNavDirSourceFlags_PadLStick, ImGuiInputReadMode_Down, 1.0f/10.0f, 10.0f);
if (scroll_dir.x != 0.0f && window->ScrollbarX)
{
- SetWindowScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed));
+ SetScrollX(window, ImFloor(window->Scroll.x + scroll_dir.x * scroll_speed));
g.NavMoveFromClampedRefRect = true;
}
if (scroll_dir.y != 0.0f)
{
- SetWindowScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed));
+ SetScrollY(window, ImFloor(window->Scroll.y + scroll_dir.y * scroll_speed));
g.NavMoveFromClampedRefRect = true;
}
}
@@ -8347,42 +8497,44 @@ static void ImGui::NavUpdateMoveResult()
static float ImGui::NavUpdatePageUpPageDown(int allowed_dir_flags)
{
ImGuiContext& g = *GImGui;
- if (g.NavMoveDir == ImGuiDir_None && g.NavWindow && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) && !g.NavWindowingTarget && g.NavLayer == 0)
+ if (g.NavMoveDir != ImGuiDir_None || g.NavWindow == NULL)
+ return 0.0f;
+ if ((g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs) || g.NavWindowingTarget != NULL || g.NavLayer != 0)
+ return 0.0f;
+
+ ImGuiWindow* window = g.NavWindow;
+ bool page_up_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageUp]) && (allowed_dir_flags & (1 << ImGuiDir_Up));
+ bool page_down_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageDown]) && (allowed_dir_flags & (1 << ImGuiDir_Down));
+ if (page_up_held != page_down_held) // If either (not both) are pressed
{
- ImGuiWindow* window = g.NavWindow;
- bool page_up_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageUp]) && (allowed_dir_flags & (1 << ImGuiDir_Up));
- bool page_down_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageDown]) && (allowed_dir_flags & (1 << ImGuiDir_Down));
- if (page_up_held != page_down_held) // If either (not both) are pressed
+ if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll)
{
- if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll)
+ // Fallback manual-scroll when window has no navigable item
+ if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageUp], true))
+ SetScrollY(window, window->Scroll.y - window->InnerRect.GetHeight());
+ else if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageDown], true))
+ SetScrollY(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->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))
{
- // Fallback manual-scroll when window has no navigable item
- if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageUp], true))
- SetWindowScrollY(window, window->Scroll.y - window->InnerRect.GetHeight());
- else if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageDown], true))
- SetWindowScrollY(window, window->Scroll.y + window->InnerRect.GetHeight());
+ nav_scoring_rect_offset_y = -page_offset_y;
+ g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset, we intentionally request the opposite direction (so we can always land on the last item)
+ g.NavMoveClipDir = ImGuiDir_Up;
+ g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
}
- else
+ else if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageDown], true))
{
- const ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer];
- 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))
- {
- nav_scoring_rect_offset_y = -page_offset_y;
- g.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset, we intentionally request the opposite direction (so we can always land on the last item)
- g.NavMoveClipDir = ImGuiDir_Up;
- g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
- }
- else if (IsKeyPressed(g.IO.KeyMap[ImGuiKey_PageDown], true))
- {
- nav_scoring_rect_offset_y = +page_offset_y;
- g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset, we intentionally request the opposite direction (so we can always land on the last item)
- g.NavMoveClipDir = ImGuiDir_Down;
- g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
- }
- return nav_scoring_rect_offset_y;
+ nav_scoring_rect_offset_y = +page_offset_y;
+ g.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset, we intentionally request the opposite direction (so we can always land on the last item)
+ g.NavMoveClipDir = ImGuiDir_Down;
+ g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
}
+ return nav_scoring_rect_offset_y;
}
}
return 0.0f;
@@ -8431,7 +8583,7 @@ static void ImGui::NavUpdateWindowing()
ImGuiWindow* apply_focus_window = NULL;
bool apply_toggle_layer = false;
- ImGuiWindow* modal_window = GetFrontMostPopupModal();
+ ImGuiWindow* modal_window = GetTopMostPopupModal();
if (modal_window != NULL)
{
g.NavWindowingTarget = NULL;
@@ -8473,7 +8625,7 @@ static void ImGui::NavUpdateWindowing()
g.NavWindowingHighlightAlpha = 1.0f;
}
- // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered front-most)
+ // Single press toggles NavLayer, long press with L/R apply actual focus on release (until then the window was merely rendered top-most)
if (!IsNavInputDown(ImGuiNavInput_Menu))
{
g.NavWindowingToggleLayer &= (g.NavWindowingHighlightAlpha < 1.0f); // Once button was held long enough we don't consider it a tap-to-toggle-layer press anymore.
@@ -8605,381 +8757,6 @@ void ImGui::NavUpdateWindowingList()
PopStyleVar();
}
-//-----------------------------------------------------------------------------
-// [SECTION] COLUMNS
-// In the current version, Columns are very weak. Needs to be replaced with a more full-featured system.
-//-----------------------------------------------------------------------------
-
-void ImGui::NextColumn()
-{
- ImGuiWindow* window = GetCurrentWindow();
- if (window->SkipItems || window->DC.CurrentColumns == NULL)
- return;
-
- ImGuiContext& g = *GImGui;
- ImGuiColumns* columns = window->DC.CurrentColumns;
-
- if (columns->Count == 1)
- {
- window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
- IM_ASSERT(columns->Current == 0);
- return;
- }
-
- PopItemWidth();
- PopClipRect();
-
- columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y);
- if (++columns->Current < columns->Count)
- {
- // 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 + 1);
- }
- else
- {
- // New row/line
- window->DC.ColumnsOffset.x = 0.0f;
- 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.CurrLineSize = ImVec2(0.0f, 0.0f);
- window->DC.CurrLineTextBaseOffset = 0.0f;
-
- PushColumnClipRect(columns->Current); // FIXME-COLUMNS: Could it be an overwrite?
- PushItemWidth(GetColumnWidth() * 0.65f); // FIXME-COLUMNS: Move on columns setup
-}
-
-int ImGui::GetColumnIndex()
-{
- ImGuiWindow* window = GetCurrentWindowRead();
- return window->DC.CurrentColumns ? window->DC.CurrentColumns->Current : 0;
-}
-
-int ImGui::GetColumnsCount()
-{
- ImGuiWindow* window = GetCurrentWindowRead();
- return window->DC.CurrentColumns ? window->DC.CurrentColumns->Count : 1;
-}
-
-static float OffsetNormToPixels(const ImGuiColumns* columns, float offset_norm)
-{
- return offset_norm * (columns->OffMaxX - columns->OffMinX);
-}
-
-static float PixelsToOffsetNorm(const ImGuiColumns* columns, float offset)
-{
- return offset / (columns->OffMaxX - columns->OffMinX);
-}
-
-static const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f;
-
-static float GetDraggedColumnOffset(ImGuiColumns* columns, int column_index)
-{
- // Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing
- // window creates a feedback loop because we store normalized positions. So while dragging we enforce absolute positioning.
- ImGuiContext& g = *GImGui;
- ImGuiWindow* window = g.CurrentWindow;
- IM_ASSERT(column_index > 0); // We are not supposed to drag column 0.
- IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index));
-
- float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + COLUMNS_HIT_RECT_HALF_WIDTH - window->Pos.x;
- x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing);
- if ((columns->Flags & ImGuiColumnsFlags_NoPreserveWidths))
- x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing);
-
- return x;
-}
-
-float ImGui::GetColumnOffset(int column_index)
-{
- ImGuiWindow* window = GetCurrentWindowRead();
- ImGuiColumns* columns = window->DC.CurrentColumns;
- IM_ASSERT(columns != NULL);
-
- if (column_index < 0)
- column_index = columns->Current;
- IM_ASSERT(column_index < columns->Columns.Size);
-
- const float t = columns->Columns[column_index].OffsetNorm;
- const float x_offset = ImLerp(columns->OffMinX, columns->OffMaxX, t);
- return x_offset;
-}
-
-static float GetColumnWidthEx(ImGuiColumns* columns, int column_index, bool before_resize = false)
-{
- if (column_index < 0)
- column_index = columns->Current;
-
- float offset_norm;
- if (before_resize)
- offset_norm = columns->Columns[column_index + 1].OffsetNormBeforeResize - columns->Columns[column_index].OffsetNormBeforeResize;
- else
- offset_norm = columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm;
- return OffsetNormToPixels(columns, offset_norm);
-}
-
-float ImGui::GetColumnWidth(int column_index)
-{
- ImGuiWindow* window = GetCurrentWindowRead();
- ImGuiColumns* columns = window->DC.CurrentColumns;
- IM_ASSERT(columns != NULL);
-
- if (column_index < 0)
- column_index = columns->Current;
- return OffsetNormToPixels(columns, columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm);
-}
-
-void ImGui::SetColumnOffset(int column_index, float offset)
-{
- ImGuiContext& g = *GImGui;
- ImGuiWindow* window = g.CurrentWindow;
- ImGuiColumns* columns = window->DC.CurrentColumns;
- IM_ASSERT(columns != NULL);
-
- if (column_index < 0)
- column_index = columns->Current;
- IM_ASSERT(column_index < columns->Columns.Size);
-
- const bool preserve_width = !(columns->Flags & ImGuiColumnsFlags_NoPreserveWidths) && (column_index < columns->Count-1);
- const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f;
-
- if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow))
- 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));
-}
-
-void ImGui::SetColumnWidth(int column_index, float width)
-{
- ImGuiWindow* window = GetCurrentWindowRead();
- ImGuiColumns* columns = window->DC.CurrentColumns;
- IM_ASSERT(columns != NULL);
-
- if (column_index < 0)
- column_index = columns->Current;
- SetColumnOffset(column_index + 1, GetColumnOffset(column_index) + width);
-}
-
-void ImGui::PushColumnClipRect(int column_index)
-{
- ImGuiWindow* window = GetCurrentWindowRead();
- ImGuiColumns* columns = window->DC.CurrentColumns;
- if (column_index < 0)
- column_index = columns->Current;
-
- ImGuiColumnData* column = &columns->Columns[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.
- for (int n = 0; n < window->ColumnsStorage.Size; n++)
- if (window->ColumnsStorage[n].ID == id)
- return &window->ColumnsStorage[n];
-
- window->ColumnsStorage.push_back(ImGuiColumns());
- ImGuiColumns* columns = &window->ColumnsStorage.back();
- columns->ID = id;
- return columns;
-}
-
-ImGuiID ImGui::GetColumnsID(const char* str_id, int columns_count)
-{
- ImGuiWindow* window = GetCurrentWindow();
-
- // Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget.
- // In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer.
- PushID(0x11223347 + (str_id ? 0 : columns_count));
- ImGuiID id = window->GetID(str_id ? str_id : "columns");
- PopID();
-
- return id;
-}
-
-void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlags flags)
-{
- ImGuiContext& g = *GImGui;
- ImGuiWindow* window = GetCurrentWindow();
-
- IM_ASSERT(columns_count >= 1);
- IM_ASSERT(window->DC.CurrentColumns == NULL); // Nested columns are currently not supported
-
- // 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;
- columns->Count = columns_count;
- columns->Flags = flags;
- window->DC.CurrentColumns = columns;
-
- // Set state for first column
- 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);
-
- // Clear data if columns count changed
- if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1)
- columns->Columns.resize(0);
-
- // Initialize default widths
- columns->IsFirstFrame = (columns->Columns.Size == 0);
- if (columns->Columns.Size == 0)
- {
- columns->Columns.reserve(columns_count + 1);
- for (int n = 0; n < columns_count + 1; n++)
- {
- ImGuiColumnData column;
- column.OffsetNorm = n / (float)columns_count;
- columns->Columns.push_back(column);
- }
- }
-
- for (int n = 0; n < columns_count; n++)
- {
- // Compute clipping rectangle
- ImGuiColumnData* column = &columns->Columns[n];
- float clip_x1 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n));
- float clip_x2 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n + 1) - 1.0f);
- column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX);
- column->ClipRect.ClipWith(window->ClipRect);
- }
-
- if (columns->Count > 1)
- {
- window->DrawList->ChannelsSplit(1 + columns->Count);
- window->DrawList->ChannelsSetCurrent(1);
- PushColumnClipRect(0);
- }
- PushItemWidth(GetColumnWidth() * 0.65f);
-}
-
-void ImGui::EndColumns()
-{
- ImGuiContext& g = *GImGui;
- ImGuiWindow* window = GetCurrentWindow();
- ImGuiColumns* columns = window->DC.CurrentColumns;
- IM_ASSERT(columns != NULL);
-
- PopItemWidth();
- if (columns->Count > 1)
- {
- PopClipRect();
- window->DrawList->ChannelsMerge();
- }
-
- const ImGuiColumnsFlags flags = columns->Flags;
- columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y);
- window->DC.CursorPos.y = columns->LineMaxY;
- 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 (!(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->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++)
- {
- ImGuiColumnData* column = &columns->Columns[n];
- float x = window->Pos.x + GetColumnOffset(n);
- const ImGuiID column_id = columns->ID + ImGuiID(n);
- const float column_hit_hw = COLUMNS_HIT_RECT_HALF_WIDTH;
- const ImRect column_hit_rect(ImVec2(x - column_hit_hw, y1), ImVec2(x + column_hit_hw, y2));
- KeepAliveID(column_id);
- if (IsClippedEx(column_hit_rect, column_id, false))
- continue;
-
- bool hovered = false, held = false;
- if (!(flags & ImGuiColumnsFlags_NoResize))
- {
- ButtonBehavior(column_hit_rect, column_id, &hovered, &held);
- if (hovered || held)
- g.MouseCursor = ImGuiMouseCursor_ResizeEW;
- if (held && !(column->Flags & ImGuiColumnsFlags_NoResize))
- dragging_column = n;
- }
-
- // Draw column
- const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator);
- const float xi = (float)(int)x;
- window->DrawList->AddLine(ImVec2(xi, y1 + 1.0f), ImVec2(xi, y2), col);
- }
-
- // Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame.
- if (dragging_column != -1)
- {
- if (!columns->IsBeingResized)
- for (int n = 0; n < columns->Count + 1; n++)
- columns->Columns[n].OffsetNormBeforeResize = columns->Columns[n].OffsetNorm;
- columns->IsBeingResized = is_being_resized = true;
- float x = GetDraggedColumnOffset(columns, dragging_column);
- SetColumnOffset(dragging_column, x);
- }
- }
- columns->IsBeingResized = is_being_resized;
-
- window->DC.CurrentColumns = NULL;
- window->DC.ColumnsOffset.x = 0.0f;
- window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
-}
-
-// [2018-03: This is currently the only public API, while we are working on making BeginColumns/EndColumns user-facing]
-void ImGui::Columns(int columns_count, const char* id, bool border)
-{
- ImGuiWindow* window = GetCurrentWindow();
- IM_ASSERT(columns_count >= 1);
-
- ImGuiColumnsFlags flags = (border ? 0 : ImGuiColumnsFlags_NoBorder);
- //flags |= ImGuiColumnsFlags_NoPreserveWidths; // NB: Legacy behavior
- ImGuiColumns* columns = window->DC.CurrentColumns;
- if (columns != NULL && columns->Count == columns_count && columns->Flags == flags)
- return;
-
- if (columns != NULL)
- EndColumns();
-
- if (columns_count != 1)
- BeginColumns(id, columns_count, flags);
-}
-
//-----------------------------------------------------------------------------
// [SECTION] DRAG AND DROP
@@ -9498,6 +9275,12 @@ ImGuiWindowSettings* ImGui::CreateNewWindowSettings(const char* name)
ImGuiContext& g = *GImGui;
g.SettingsWindows.push_back(ImGuiWindowSettings());
ImGuiWindowSettings* settings = &g.SettingsWindows.back();
+#if !IMGUI_DEBUG_INI_SETTINGS
+ // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID()
+ // Preserve the full string when IMGUI_DEBUG_INI_SETTINGS is set to make .ini inspection easier.
+ if (const char* p = strstr(name, "###"))
+ name = p;
+#endif
settings->Name = ImStrdup(name);
settings->ID = ImHashStr(name);
return settings;
@@ -9683,10 +9466,7 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
const ImGuiWindowSettings* settings = &g.SettingsWindows[i];
if (settings->Pos.x == FLT_MAX)
continue;
- const char* name = settings->Name;
- if (const char* p = strstr(name, "###")) // Skip to the "###" marker if any. We don't skip past to match the behavior of GetID()
- name = p;
- buf->appendf("[%s][%s]\n", handler->TypeName, name);
+ buf->appendf("[%s][%s]\n", handler->TypeName, settings->Name);
buf->appendf("Pos=%d,%d\n", (int)settings->Pos.x, (int)settings->Pos.y);
buf->appendf("Size=%d,%d\n", (int)settings->Size.x, (int)settings->Size.y);
buf->appendf("Collapsed=%d\n", settings->Collapsed);
@@ -9776,12 +9556,13 @@ static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
::CloseClipboard();
}
-#elif defined(__APPLE__) && TARGET_OS_OSX && !defined(IMGUI_DISABLE_OSX_FUNCTIONS)
+#elif defined(__APPLE__) && TARGET_OS_OSX && defined(IMGUI_ENABLE_OSX_DEFAULT_CLIPBOARD_FUNCTIONS)
#include <Carbon/Carbon.h> // Use old API to avoid need for separate .mm file
static PasteboardRef main_clipboard = 0;
// OSX clipboard implementation
+// If you enable this you will need to add '-framework ApplicationServices' to your linker command-line!
static void SetClipboardTextFn_DefaultImpl(void*, const char* text)
{
if (!main_clipboard)
@@ -9881,6 +9662,7 @@ static void ImeSetInputScreenPosFn_DefaultImpl(int, int) {}
// [SECTION] METRICS/DEBUG WINDOW
//-----------------------------------------------------------------------------
+#ifndef IMGUI_DISABLE_METRICS_WINDOW
void ImGui::ShowMetricsWindow(bool* p_open)
{
if (!ImGui::Begin("Dear ImGui Metrics", p_open))
@@ -9889,12 +9671,16 @@ void ImGui::ShowMetricsWindow(bool* p_open)
return;
}
- enum { RT_OuterRect, RT_OuterRectClipped, RT_InnerRect, RT_InnerClipRect, RT_WorkRect, RT_Contents, RT_ContentsRegionRect, RT_Count };
- static bool show_windows_begin_order = false;
+ // State
+ enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Contents, WRT_ContentsRegionRect, WRT_Count }; // Windows Rect Type
+ const char* wrt_rects_names[WRT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Contents", "ContentsRegionRect" };
static bool show_windows_rects = false;
- static int show_windows_rect_type = RT_WorkRect;
+ static int show_windows_rect_type = WRT_WorkRect;
+ static bool show_windows_begin_order = false;
static bool show_drawcmd_clip_rects = true;
+ // Basic info
+ ImGuiContext& g = *GImGui;
ImGuiIO& io = ImGui::GetIO();
ImGui::Text("Dear ImGui %s", ImGui::GetVersion());
ImGui::Text("Application average %.3f ms/frame (%.1f FPS)", 1000.0f / io.Framerate, io.Framerate);
@@ -9903,17 +9689,23 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImGui::Text("%d active allocations", io.MetricsActiveAllocations);
ImGui::Separator();
+ // Helper functions to display common structures:
+ // - NodeDrawList
+ // - NodeColumns
+ // - NodeWindow
+ // - NodeWindows
+ // - NodeTabBar
struct Funcs
{
- static ImRect GetRect(ImGuiWindow* window, int rect_type)
+ static ImRect GetWindowRect(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; }
+ if (rect_type == WRT_OuterRect) { return window->Rect(); }
+ else if (rect_type == WRT_OuterRectClipped) { return window->OuterRectClipped; }
+ else if (rect_type == WRT_InnerRect) { return window->InnerRect; }
+ else if (rect_type == WRT_InnerClipRect) { return window->InnerClipRect; }
+ else if (rect_type == WRT_WorkRect) { return window->WorkRect; }
+ else if (rect_type == WRT_Contents) { ImVec2 min = window->InnerRect.Min - window->Scroll + window->WindowPadding; return ImRect(min, min + window->ContentSize); }
+ else if (rect_type == WRT_ContentsRegionRect) { return window->ContentsRegionRect; }
IM_ASSERT(0);
return ImRect();
}
@@ -9935,6 +9727,9 @@ void ImGui::ShowMetricsWindow(bool* p_open)
if (!node_open)
return;
+ if (window && !window->WasActive)
+ ImGui::Text("(Note: owning Window is inactive: DrawList is not being rendered!)");
+
int elem_offset = 0;
for (const ImDrawCmd* pcmd = draw_list->CmdBuffer.begin(); pcmd < draw_list->CmdBuffer.end(); elem_offset += pcmd->ElemCount, pcmd++)
{
@@ -9998,7 +9793,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
return;
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::BulletText("Column %02d: OffsetNorm %.3f (= %.1f px)", column_n, columns->Columns[column_n].OffsetNorm, GetColumnOffsetFromNorm(columns, columns->Columns[column_n].OffsetNorm));
ImGui::TreePop();
}
@@ -10013,7 +9808,12 @@ void ImGui::ShowMetricsWindow(bool* p_open)
static void NodeWindow(ImGuiWindow* window, const char* label)
{
- if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, window->Active || window->WasActive, window))
+ if (window == NULL)
+ {
+ ImGui::BulletText("%s: NULL", label);
+ return;
+ }
+ if (!ImGui::TreeNode(window, "%s '%s', %d @ 0x%p", label, window->Name, (window->Active || window->WasActive), window))
return;
ImGuiWindowFlags flags = window->Flags;
NodeDrawList(window, window->DrawList, "DrawList");
@@ -10040,7 +9840,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
NodeColumns(&window->ColumnsStorage[n]);
ImGui::TreePop();
}
- ImGui::BulletText("Storage: %d bytes", window->StateStorage.Data.Size * (int)sizeof(ImGuiStorage::Pair));
+ ImGui::BulletText("Storage: %d bytes", window->StateStorage.Data.size_in_bytes());
ImGui::TreePop();
}
@@ -10067,8 +9867,6 @@ void ImGui::ShowMetricsWindow(bool* p_open)
}
};
- // Access private state, we are going to display the draw lists from last frame
- ImGuiContext& g = *GImGui;
Funcs::NodeWindows(g.Windows, "Windows");
if (ImGui::TreeNode("DrawList", "Active DrawLists (%d)", g.DrawDataBuilder.Layers[0].Size))
{
@@ -10094,6 +9892,20 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImGui::TreePop();
}
+#if 0
+ if (ImGui::TreeNode("Docking"))
+ {
+ ImGui::TreePop();
+ }
+#endif
+
+#if 0
+ if (ImGui::TreeNode("Tables", "Tables (%d)", g.Tables.Data.Size))
+ {
+ ImGui::TreePop();
+ }
+#endif
+
if (ImGui::TreeNode("Internal state"))
{
const char* input_source_names[] = { "None", "Mouse", "Nav", "NavKeyboard", "NavGamepad" }; IM_ASSERT(IM_ARRAYSIZE(input_source_names) == ImGuiInputSource_COUNT);
@@ -10116,20 +9928,23 @@ void ImGui::ShowMetricsWindow(bool* p_open)
if (ImGui::TreeNode("Tools"))
{
+ // The Item Picker tool is super useful to visually select an item and break into the call-stack of where it was submitted.
+ if (ImGui::Button("Item Picker.."))
+ ImGui::DebugStartItemPicker();
+
ImGui::Checkbox("Show windows begin order", &show_windows_begin_order);
ImGui::Checkbox("Show windows rectangles", &show_windows_rects);
ImGui::SameLine();
ImGui::SetNextItemWidth(ImGui::GetFontSize() * 12);
- 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);
+ show_windows_rects |= ImGui::Combo("##show_windows_rect_type", &show_windows_rect_type, wrt_rects_names, WRT_Count);
if (show_windows_rects && g.NavWindow)
{
ImGui::BulletText("'%s':", g.NavWindow->Name);
ImGui::Indent();
- for (int n = 0; n < RT_Count; n++)
+ for (int rect_n = 0; rect_n < WRT_Count; rect_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]);
+ ImRect r = Funcs::GetWindowRect(g.NavWindow, rect_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(), wrt_rects_names[rect_n]);
}
ImGui::Unindent();
}
@@ -10137,6 +9952,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImGui::TreePop();
}
+ // Tool: Display windows Rectangles and Begin Order
if (show_windows_rects || show_windows_begin_order)
{
for (int n = 0; n < g.Windows.Size; n++)
@@ -10147,7 +9963,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImDrawList* draw_list = GetForegroundDrawList(window);
if (show_windows_rects)
{
- ImRect r = Funcs::GetRect(window, show_windows_rect_type);
+ ImRect r = Funcs::GetWindowRect(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))
@@ -10163,6 +9979,12 @@ void ImGui::ShowMetricsWindow(bool* p_open)
ImGui::End();
}
+#else
+
+void ImGui::ShowMetricsWindow(bool*) { }
+
+#endif
+
//-----------------------------------------------------------------------------
// Include imgui_user.inl at the end of imgui.cpp to access private data/functions that aren't exposed.
diff --git a/imgui/imgui.h b/imgui/imgui.h
index d5de1102..23efa5d6 100644
--- a/imgui/imgui.h
+++ b/imgui/imgui.h
@@ -1,4 +1,4 @@
-// dear imgui, v1.71
+// dear imgui, v1.72
// (headers)
// See imgui.cpp file for documentation.
@@ -46,8 +46,8 @@ 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.71"
-#define IMGUI_VERSION_NUM 17100
+#define IMGUI_VERSION "1.72"
+#define IMGUI_VERSION_NUM 17200
#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)
@@ -83,9 +83,10 @@ Index of this file:
#if __has_warning("-Wzero-as-null-pointer-constant")
#pragma clang diagnostic ignored "-Wzero-as-null-pointer-constant"
#endif
-#elif defined(__GNUC__) && __GNUC__ >= 8
+#elif defined(__GNUC__)
#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wclass-memaccess"
+#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
+#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
#endif
//-----------------------------------------------------------------------------
@@ -125,30 +126,29 @@ typedef void* ImTextureID; // User data to identify a texture (this is
typedef unsigned int ImGuiID; // Unique ID used by widgets (typically hashed from a stack of string)
typedef unsigned short ImWchar; // A single U16 character for keyboard input/display. We encode them as multi bytes UTF-8 when used in strings.
typedef int ImGuiCol; // -> enum ImGuiCol_ // Enum: A color identifier for styling
-typedef int ImGuiCond; // -> enum ImGuiCond_ // Enum: A condition for Set*()
+typedef int ImGuiCond; // -> enum ImGuiCond_ // Enum: A condition for many Set*() functions
typedef int ImGuiDataType; // -> enum ImGuiDataType_ // Enum: A primary data type
typedef int ImGuiDir; // -> enum ImGuiDir_ // Enum: A cardinal direction
typedef int ImGuiKey; // -> enum ImGuiKey_ // Enum: A key identifier (ImGui-side enum)
typedef int ImGuiNavInput; // -> enum ImGuiNavInput_ // Enum: An input identifier for navigation
typedef int ImGuiMouseCursor; // -> enum ImGuiMouseCursor_ // Enum: A mouse cursor identifier
typedef int ImGuiStyleVar; // -> enum ImGuiStyleVar_ // Enum: A variable identifier for styling
-typedef int ImDrawCornerFlags; // -> enum ImDrawCornerFlags_ // Flags: for ImDrawList::AddRect*() etc.
+typedef int ImDrawCornerFlags; // -> enum ImDrawCornerFlags_ // Flags: for ImDrawList::AddRect(), AddRectFilled() etc.
typedef int ImDrawListFlags; // -> enum ImDrawListFlags_ // Flags: for ImDrawList
typedef int ImFontAtlasFlags; // -> enum ImFontAtlasFlags_ // Flags: for ImFontAtlas
typedef int ImGuiBackendFlags; // -> enum ImGuiBackendFlags_ // Flags: for io.BackendFlags
-typedef int ImGuiColorEditFlags; // -> enum ImGuiColorEditFlags_ // Flags: for ColorEdit*(), ColorPicker*()
-typedef int ImGuiColumnsFlags; // -> enum ImGuiColumnsFlags_ // Flags: for Columns(), BeginColumns()
+typedef int ImGuiColorEditFlags; // -> enum ImGuiColorEditFlags_ // Flags: for ColorEdit4(), ColorPicker4() etc.
typedef int ImGuiConfigFlags; // -> enum ImGuiConfigFlags_ // Flags: for io.ConfigFlags
typedef int ImGuiComboFlags; // -> enum ImGuiComboFlags_ // Flags: for BeginCombo()
-typedef int ImGuiDragDropFlags; // -> enum ImGuiDragDropFlags_ // Flags: for *DragDrop*()
+typedef int ImGuiDragDropFlags; // -> enum ImGuiDragDropFlags_ // Flags: for BeginDragDropSource(), AcceptDragDropPayload()
typedef int ImGuiFocusedFlags; // -> enum ImGuiFocusedFlags_ // Flags: for IsWindowFocused()
typedef int ImGuiHoveredFlags; // -> enum ImGuiHoveredFlags_ // Flags: for IsItemHovered(), IsWindowHovered() etc.
-typedef int ImGuiInputTextFlags; // -> enum ImGuiInputTextFlags_ // Flags: for InputText*()
+typedef int ImGuiInputTextFlags; // -> enum ImGuiInputTextFlags_ // Flags: for InputText(), InputTextMultiline()
typedef int ImGuiSelectableFlags; // -> enum ImGuiSelectableFlags_ // Flags: for Selectable()
typedef int ImGuiTabBarFlags; // -> enum ImGuiTabBarFlags_ // Flags: for BeginTabBar()
typedef int ImGuiTabItemFlags; // -> enum ImGuiTabItemFlags_ // Flags: for BeginTabItem()
-typedef int ImGuiTreeNodeFlags; // -> enum ImGuiTreeNodeFlags_ // Flags: for TreeNode*(),CollapsingHeader()
-typedef int ImGuiWindowFlags; // -> enum ImGuiWindowFlags_ // Flags: for Begin*()
+typedef int ImGuiTreeNodeFlags; // -> enum ImGuiTreeNodeFlags_ // Flags: for TreeNode(), TreeNodeEx(), CollapsingHeader()
+typedef int ImGuiWindowFlags; // -> enum ImGuiWindowFlags_ // Flags: for Begin(), BeginChild()
typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData *data);
typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data);
@@ -274,17 +274,17 @@ namespace ImGui
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 (~ 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 SetNextWindowFocus(); // set next window to be focused / top-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.
IMGUI_API void SetWindowPos(const ImVec2& pos, ImGuiCond cond = 0); // (not recommended) set current window position - call within Begin()/End(). prefer using SetNextWindowPos(), as this may incur tearing and side-effects.
IMGUI_API void SetWindowSize(const ImVec2& size, ImGuiCond cond = 0); // (not recommended) set current window size - call within Begin()/End(). set to ImVec2(0,0) to force an auto-fit. prefer using SetNextWindowSize(), as this may incur tearing and minor side-effects.
IMGUI_API void SetWindowCollapsed(bool collapsed, ImGuiCond cond = 0); // (not recommended) set current window collapsed state. prefer using SetNextWindowCollapsed().
- IMGUI_API void SetWindowFocus(); // (not recommended) set current window to be focused / front-most. prefer using SetNextWindowFocus().
- IMGUI_API void SetWindowFontScale(float scale); // set font scale. Adjust IO.FontGlobalScale if you want to scale all windows
+ IMGUI_API void SetWindowFocus(); // (not recommended) set current window to be focused / top-most. prefer using SetNextWindowFocus().
+ IMGUI_API void SetWindowFontScale(float scale); // set font scale. Adjust IO.FontGlobalScale if you want to scale all windows. This is an old API! For correct scaling, prefer to reload font + rebuild ImFontAtlas + call style.ScaleAllSizes().
IMGUI_API void SetWindowPos(const char* name, const ImVec2& pos, ImGuiCond cond = 0); // set named window position.
IMGUI_API void SetWindowSize(const char* name, const ImVec2& size, ImGuiCond cond = 0); // set named window size. set axis to 0.0f to force an auto-fit on this axis.
IMGUI_API void SetWindowCollapsed(const char* name, bool collapsed, ImGuiCond cond = 0); // set named window collapsed state
- IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / front-most. use NULL to remove focus.
+ IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / top-most. use NULL to remove focus.
// Content region
// - Those functions are bound to be redesigned soon (they are confusing, incomplete and return values in local window coordinates which increases confusion)
@@ -301,7 +301,9 @@ namespace ImGui
IMGUI_API float GetScrollMaxY(); // get maximum scrolling amount ~~ ContentSize.Y - WindowSize.Y
IMGUI_API void SetScrollX(float scroll_x); // set scrolling amount [0..GetScrollMaxX()]
IMGUI_API void SetScrollY(float scroll_y); // set scrolling amount [0..GetScrollMaxY()]
+ IMGUI_API void SetScrollHereX(float center_x_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_x_ratio=0.0: left, 0.5: center, 1.0: right. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead.
IMGUI_API void SetScrollHereY(float center_y_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_y_ratio=0.0: top, 0.5: center, 1.0: bottom. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead.
+ IMGUI_API void SetScrollFromPosX(float local_x, float center_x_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position.
IMGUI_API void SetScrollFromPosY(float local_y, float center_y_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position.
// Parameters stacks (shared)
@@ -325,7 +327,7 @@ namespace ImGui
IMGUI_API void PushItemWidth(float item_width); // set width of items for common large "item+label" widgets. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side). 0.0f = default to ~2/3 of windows width,
IMGUI_API void PopItemWidth();
IMGUI_API void SetNextItemWidth(float item_width); // set width of the _next_ common large "item+label" widget. >0.0f: width in pixels, <0.0f align xx pixels to the right of window (so -1.0f always align width to the right side)
- IMGUI_API float CalcItemWidth(); // width of item given pushed settings and current cursor position
+ IMGUI_API float CalcItemWidth(); // width of item given pushed settings and current cursor position. NOT necessarily the width of last item unlike most 'Item' functions.
IMGUI_API void PushTextWrapPos(float wrap_local_pos_x = 0.0f); // word-wrapping for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space
IMGUI_API void PopTextWrapPos();
IMGUI_API void PushAllowKeyboardFocus(bool allow_keyboard_focus); // allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets
@@ -494,7 +496,6 @@ namespace ImGui
IMGUI_API void TreePush(const char* str_id); // ~ Indent()+PushId(). Already called by TreeNode() when returning true, but you can call TreePush/TreePop yourself if desired.
IMGUI_API void TreePush(const void* ptr_id = NULL); // "
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 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
@@ -867,7 +868,7 @@ enum ImGuiHoveredFlags_
ImGuiHoveredFlags_AllowWhenBlockedByPopup = 1 << 3, // Return true even if a popup window is normally blocking access to this item/window
//ImGuiHoveredFlags_AllowWhenBlockedByModal = 1 << 4, // Return true even if a modal popup window is normally blocking access to this item/window. FIXME-TODO: Unavailable yet.
ImGuiHoveredFlags_AllowWhenBlockedByActiveItem = 1 << 5, // Return true even if an active item is blocking access to this item/window. Useful for Drag and Drop patterns.
- ImGuiHoveredFlags_AllowWhenOverlapped = 1 << 6, // Return true even if the position is overlapped by another window
+ ImGuiHoveredFlags_AllowWhenOverlapped = 1 << 6, // Return true even if the position is obstructed or overlapped by another window
ImGuiHoveredFlags_AllowWhenDisabled = 1 << 7, // Return true even if the item is disabled
ImGuiHoveredFlags_RectOnly = ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem | ImGuiHoveredFlags_AllowWhenOverlapped,
ImGuiHoveredFlags_RootAndChildWindows = ImGuiHoveredFlags_RootWindow | ImGuiHoveredFlags_ChildWindows
@@ -898,7 +899,7 @@ enum ImGuiDragDropFlags_
// A primary data type
enum ImGuiDataType_
{
- ImGuiDataType_S8, // char
+ ImGuiDataType_S8, // signed char / char (with sensible compilers)
ImGuiDataType_U8, // unsigned char
ImGuiDataType_S16, // short
ImGuiDataType_U16, // unsigned short
@@ -940,6 +941,7 @@ enum ImGuiKey_
ImGuiKey_Space,
ImGuiKey_Enter,
ImGuiKey_Escape,
+ ImGuiKey_KeyPadEnter,
ImGuiKey_A, // for text edit CTRL+A: select all
ImGuiKey_C, // for text edit CTRL+C: copy
ImGuiKey_V, // for text edit CTRL+V: paste
@@ -1038,7 +1040,7 @@ enum ImGuiCol_
ImGuiCol_Button,
ImGuiCol_ButtonHovered,
ImGuiCol_ButtonActive,
- ImGuiCol_Header,
+ ImGuiCol_Header, // Header* colors are used for CollapsingHeader, TreeNode, Selectable, MenuItem
ImGuiCol_HeaderHovered,
ImGuiCol_HeaderActive,
ImGuiCol_Separator,
@@ -1068,7 +1070,6 @@ enum ImGuiCol_
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
, ImGuiCol_ModalWindowDarkening = ImGuiCol_ModalWindowDimBg // [renamed in 1.63]
, ImGuiCol_ChildWindowBg = ImGuiCol_ChildBg // [renamed in 1.53]
- , ImGuiCol_Column = ImGuiCol_Separator, ImGuiCol_ColumnHovered = ImGuiCol_SeparatorHovered, ImGuiCol_ColumnActive = ImGuiCol_SeparatorActive // [renamed in 1.51]
//ImGuiCol_CloseButton, ImGuiCol_CloseButtonActive, ImGuiCol_CloseButtonHovered, // [unused since 1.60+] the close button now uses regular button colors.
//ImGuiCol_ComboBg, // [unused since 1.53+] ComboBg has been merged with PopupBg, so a redirect isn't accurate.
#endif
@@ -1187,11 +1188,6 @@ enum ImGuiCond_
ImGuiCond_Once = 1 << 1, // Set the variable once per runtime session (only the first call with succeed)
ImGuiCond_FirstUseEver = 1 << 2, // Set the variable if the object/window has no persistently saved data (no entry in .ini file)
ImGuiCond_Appearing = 1 << 3 // Set the variable if the object/window is appearing after being hidden/inactive (or the first time)
-
- // 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 // [renamed in 1.51]
-#endif
};
//-----------------------------------------------------------------------------
@@ -1306,6 +1302,7 @@ struct ImGuiStyle
float GrabRounding; // Radius of grabs corners rounding. Set to 0.0f to have rectangular slider grabs.
float TabRounding; // Radius of upper corners of a tab. Set to 0.0f to have rectangular tabs.
float TabBorderSize; // Thickness of border around tabs.
+ ImGuiDir ColorButtonPosition; // Side of the color button in the ColorEdit4 widget (left/right). Defaults to ImGuiDir_Right.
ImVec2 ButtonTextAlign; // Alignment of button text when button is larger than text. Defaults to (0.5f, 0.5f) (centered).
ImVec2 SelectableTextAlign; // Alignment of selectable text when selectable is larger than text. Defaults to (0.0f, 0.0f) (top-left aligned).
ImVec2 DisplayWindowPadding; // Window position are clamped to be visible within the display area by at least this amount. Only applies to regular windows.
@@ -1347,7 +1344,7 @@ struct ImGuiIO
float KeyRepeatRate; // = 0.050f // When holding a key/button, rate at which it repeats, in seconds.
void* UserData; // = NULL // Store your own data for retrieval by callbacks.
- ImFontAtlas*Fonts; // <auto> // Load, rasterize and pack one or more fonts into a single texture.
+ ImFontAtlas*Fonts; // <auto> // Font atlas: load, rasterize and pack one or more fonts into a single texture.
float FontGlobalScale; // = 1.0f // Global scale all fonts
bool FontAllowUserScaling; // = false // Allow user scaling text of individual window with CTRL+Wheel.
ImFont* FontDefault; // = NULL // Font to use on NewFrame(). Use NULL to uses Fonts->Fonts[0].
@@ -1535,8 +1532,10 @@ struct ImGuiPayload
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
namespace ImGui
{
+ // OBSOLETED in 1.72 (from July 2019)
+ static inline void TreeAdvanceToLabelPos() { SetCursorPosX(GetCursorPosX() + GetTreeNodeToLabelSpacing()); }
// OBSOLETED in 1.71 (from June 2019)
- static inline void SetNextTreeNodeOpen(bool open, ImGuiCond cond = 0) { SetNextItemOpen(open, cond); }
+ 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)
@@ -1565,11 +1564,6 @@ namespace ImGui
static inline bool IsRootWindowOrAnyChildHovered() { return IsWindowHovered(ImGuiHoveredFlags_RootAndChildWindows); }
static inline void AlignFirstTextHeightToWidgets() { AlignTextToFramePadding(); }
static inline void SetNextWindowPosCenter(ImGuiCond c=0) { ImGuiIO& io = GetIO(); SetNextWindowPos(ImVec2(io.DisplaySize.x * 0.5f, io.DisplaySize.y * 0.5f), c, ImVec2(0.5f, 0.5f)); }
- // OBSOLETED in 1.51 (between Jun 2017 and Aug 2017)
- static inline bool IsItemHoveredRect() { return IsItemHovered(ImGuiHoveredFlags_RectOnly); }
- static inline bool IsPosHoveringAnyWindow(const ImVec2&) { IM_ASSERT(0); return false; } // This was misleading and partly broken. You probably want to use the ImGui::GetIO().WantCaptureMouse flag instead.
- static inline bool IsMouseHoveringAnyWindow() { return IsWindowHovered(ImGuiHoveredFlags_AnyWindow); }
- static inline bool IsMouseHoveringWindow() { return IsWindowHovered(ImGuiHoveredFlags_AllowWhenBlockedByPopup | ImGuiHoveredFlags_AllowWhenBlockedByActiveItem); }
}
typedef ImGuiInputTextCallback ImGuiTextEditCallback; // OBSOLETED in 1.63 (from Aug 2018): made the names consistent
typedef ImGuiInputTextCallbackData ImGuiTextEditCallbackData;
@@ -1588,11 +1582,6 @@ struct ImGuiOnceUponAFrame
operator bool() const { int current_frame = ImGui::GetFrameCount(); if (RefFrame == current_frame) return false; RefFrame = current_frame; return true; }
};
-// Helper: Macro for ImGuiOnceUponAFrame. Attention: The macro expands into 2 statement so make sure you don't use it within e.g. an if() statement without curly braces.
-#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
-#define IMGUI_ONCE_UPON_A_FRAME static ImGuiOnceUponAFrame imgui_oaf; if (imgui_oaf) // OBSOLETED in 1.51, will remove!
-#endif
-
// Helper: Parse and apply text filters. In format "aaaaa[,bbbb][,ccccc]"
struct ImGuiTextFilter
{
@@ -1604,21 +1593,19 @@ struct ImGuiTextFilter
bool IsActive() const { return !Filters.empty(); }
// [Internal]
- struct TextRange
+ struct ImGuiTextRange
{
- const char* b;
- const char* e;
-
- TextRange() { b = e = NULL; }
- TextRange(const char* _b, const char* _e) { b = _b; e = _e; }
- const char* begin() const { return b; }
- const char* end () const { return e; }
- bool empty() const { return b == e; }
- IMGUI_API void split(char separator, ImVector<TextRange>* out) const;
+ const char* b;
+ const char* e;
+
+ ImGuiTextRange() { b = e = NULL; }
+ ImGuiTextRange(const char* _b, const char* _e) { b = _b; e = _e; }
+ bool empty() const { return b == e; }
+ IMGUI_API void split(char separator, ImVector<ImGuiTextRange>* out) const;
};
- char InputBuf[256];
- ImVector<TextRange> Filters;
- int CountGrep;
+ char InputBuf[256];
+ ImVector<ImGuiTextRange>Filters;
+ int CountGrep;
};
// Helper: Growable text buffer for logging/accumulating text
@@ -1626,7 +1613,7 @@ struct ImGuiTextFilter
struct ImGuiTextBuffer
{
ImVector<char> Buf;
- static char EmptyString[1];
+ IMGUI_API static char EmptyString[1];
ImGuiTextBuffer() { }
inline char operator[](int i) { IM_ASSERT(Buf.Data != NULL); return Buf.Data[i]; }
@@ -1652,15 +1639,17 @@ struct ImGuiTextBuffer
// Types are NOT stored, so it is up to you to make sure your Key don't collide with different types.
struct ImGuiStorage
{
- struct Pair
+ // [Internal]
+ struct ImGuiStoragePair
{
ImGuiID key;
union { int val_i; float val_f; void* val_p; };
- Pair(ImGuiID _key, int _val_i) { key = _key; val_i = _val_i; }
- Pair(ImGuiID _key, float _val_f) { key = _key; val_f = _val_f; }
- Pair(ImGuiID _key, void* _val_p) { key = _key; val_p = _val_p; }
+ ImGuiStoragePair(ImGuiID _key, int _val_i) { key = _key; val_i = _val_i; }
+ ImGuiStoragePair(ImGuiID _key, float _val_f) { key = _key; val_f = _val_f; }
+ ImGuiStoragePair(ImGuiID _key, void* _val_p) { key = _key; val_p = _val_p; }
};
- ImVector<Pair> Data;
+
+ ImVector<ImGuiStoragePair> Data;
// - Get***() functions find pair, never add/allocate. Pairs are sorted so a query is O(log N)
// - Set***() functions find pair, insertion on demand if missing.
@@ -1837,7 +1826,8 @@ struct ImDrawListSplitter
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 ImDrawListSplitter() { Clear(); }
+ inline ~ImDrawListSplitter() { ClearFreeMemory(); }
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);
@@ -1847,6 +1837,7 @@ struct ImDrawListSplitter
enum ImDrawCornerFlags_
{
+ ImDrawCornerFlags_None = 0,
ImDrawCornerFlags_TopLeft = 1 << 0, // 0x1
ImDrawCornerFlags_TopRight = 1 << 1, // 0x2
ImDrawCornerFlags_BotLeft = 1 << 2, // 0x4
@@ -1907,8 +1898,8 @@ struct ImDrawList
// Primitives
IMGUI_API void AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness = 1.0f);
- IMGUI_API void AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners_flags = ImDrawCornerFlags_All, float thickness = 1.0f); // a: upper-left, b: lower-right (== upper-left + size), rounding_corners_flags: 4-bits corresponding to which corner to round
- IMGUI_API void AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, int rounding_corners_flags = ImDrawCornerFlags_All); // a: upper-left, b: lower-right (== upper-left + size)
+ IMGUI_API void AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All, float thickness = 1.0f); // a: upper-left, b: lower-right (== upper-left + size), rounding_corners_flags: 4-bits corresponding to which corner to round
+ IMGUI_API void AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All); // a: upper-left, b: lower-right (== upper-left + size)
IMGUI_API void AddRectFilledMultiColor(const ImVec2& a, const ImVec2& b, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left);
IMGUI_API void AddQuad(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col, float thickness = 1.0f);
IMGUI_API void AddQuadFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col);
@@ -1920,7 +1911,7 @@ struct ImDrawList
IMGUI_API void AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL);
IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a = ImVec2(0,0), const ImVec2& uv_b = ImVec2(1,1), ImU32 col = IM_COL32_WHITE);
IMGUI_API void AddImageQuad(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a = ImVec2(0,0), const ImVec2& uv_b = ImVec2(1,0), const ImVec2& uv_c = ImVec2(1,1), const ImVec2& uv_d = ImVec2(0,1), ImU32 col = IM_COL32_WHITE);
- IMGUI_API void AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col, float rounding, int rounding_corners = ImDrawCornerFlags_All);
+ IMGUI_API void AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All);
IMGUI_API void AddPolyline(const ImVec2* points, int num_points, ImU32 col, bool closed, float thickness);
IMGUI_API void AddConvexPolyFilled(const ImVec2* points, int num_points, ImU32 col); // Note: Anti-aliased filling requires points to be in clockwise order.
IMGUI_API void AddBezierCurve(const ImVec2& pos0, const ImVec2& cp0, const ImVec2& cp1, const ImVec2& pos1, ImU32 col, float thickness, int num_segments = 0);
@@ -1934,7 +1925,7 @@ struct ImDrawList
IMGUI_API void PathArcTo(const ImVec2& centre, float radius, float a_min, float a_max, int num_segments = 10);
IMGUI_API void PathArcToFast(const ImVec2& centre, float radius, int a_min_of_12, int a_max_of_12); // Use precomputed angles for a 12 steps circle
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);
+ IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All);
// 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.
@@ -2039,6 +2030,19 @@ struct ImFontGlyphRangesBuilder
IMGUI_API void BuildRanges(ImVector<ImWchar>* out_ranges); // Output new ranges
};
+// See ImFontAtlas::AddCustomRectXXX functions.
+struct ImFontAtlasCustomRect
+{
+ unsigned int ID; // Input // User ID. Use <0x10000 to map into a font glyph, >=0x10000 for other/internal/custom texture data.
+ unsigned short Width, Height; // Input // Desired rectangle dimension
+ unsigned short X, Y; // Output // Packed position in Atlas
+ float GlyphAdvanceX; // Input // For custom font glyphs only (ID<0x10000): glyph xadvance
+ ImVec2 GlyphOffset; // Input // For custom font glyphs only (ID<0x10000): glyph display offset
+ ImFont* Font; // Input // For custom font glyphs only (ID<0x10000): target font
+ ImFontAtlasCustomRect() { ID = 0xFFFFFFFF; Width = Height = 0; X = Y = 0xFFFF; GlyphAdvanceX = 0.0f; GlyphOffset = ImVec2(0,0); Font = NULL; }
+ bool IsPacked() const { return X != 0xFFFF; }
+};
+
enum ImFontAtlasFlags_
{
ImFontAtlasFlags_None = 0,
@@ -2103,7 +2107,7 @@ struct ImFontAtlas
IMGUI_API const ImWchar* GetGlyphRangesChineseSimplifiedCommon();// Default + Half-Width + Japanese Hiragana/Katakana + set of 2500 CJK Unified Ideographs for common simplified Chinese
IMGUI_API const ImWchar* GetGlyphRangesCyrillic(); // Default + about 400 Cyrillic characters
IMGUI_API const ImWchar* GetGlyphRangesThai(); // Default + Thai characters
- IMGUI_API const ImWchar* GetGlyphRangesVietnamese(); // Default + Vietname characters
+ IMGUI_API const ImWchar* GetGlyphRangesVietnamese(); // Default + Vietnamese characters
//-------------------------------------------
// [BETA] Custom Rectangles/Glyphs API
@@ -2114,24 +2118,13 @@ struct ImFontAtlas
// 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.
- unsigned short Width, Height; // Input // Desired rectangle dimension
- unsigned short X, Y; // Output // Packed position in Atlas
- float GlyphAdvanceX; // Input // For custom font glyphs only (ID<0x10000): glyph xadvance
- ImVec2 GlyphOffset; // Input // For custom font glyphs only (ID<0x10000): glyph display offset
- ImFont* Font; // Input // For custom font glyphs only (ID<0x10000): target font
- 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]; }
+ 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 ImFontAtlasCustomRect*GetCustomRectByIndex(int index) const { if (index < 0) return NULL; return &CustomRects[index]; }
// [Internal]
- IMGUI_API void CalcCustomRectUV(const CustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max);
- IMGUI_API bool GetMouseCursorTexData(ImGuiMouseCursor cursor, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]);
+ IMGUI_API void CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max);
+ IMGUI_API bool GetMouseCursorTexData(ImGuiMouseCursor cursor, ImVec2* out_offset, ImVec2* out_size, ImVec2 out_uv_border[2], ImVec2 out_uv_fill[2]);
//-------------------------------------------
// Members
@@ -2152,11 +2145,12 @@ struct ImFontAtlas
ImVec2 TexUvScale; // = (1.0f/TexWidth, 1.0f/TexHeight)
ImVec2 TexUvWhitePixel; // Texture coordinates to a white pixel
ImVector<ImFont*> Fonts; // Hold all the fonts returned by AddFont*. Fonts[0] is the default font upon calling ImGui::NewFrame(), use ImGui::PushFont()/PopFont() to change the current font.
- ImVector<CustomRect> CustomRects; // Rectangles for packing custom texture data into the atlas.
+ ImVector<ImFontAtlasCustomRect> CustomRects; // Rectangles for packing custom texture data into the atlas.
ImVector<ImFontConfig> ConfigData; // Internal data
int CustomRectIds[1]; // Identifiers of custom texture rectangle used by ImFontAtlas/ImDrawList
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+ typedef ImFontAtlasCustomRect CustomRect; // OBSOLETED in 1.72+
typedef ImFontGlyphRangesBuilder GlyphRangesBuilder; // OBSOLETED in 1.67+
#endif
};
@@ -2217,7 +2211,7 @@ struct ImFont
#if defined(__clang__)
#pragma clang diagnostic pop
-#elif defined(__GNUC__) && __GNUC__ >= 8
+#elif defined(__GNUC__)
#pragma GCC diagnostic pop
#endif
diff --git a/imgui/imgui_demo.cpp b/imgui/imgui_demo.cpp
index df875b23..af8b422b 100644
--- a/imgui/imgui_demo.cpp
+++ b/imgui/imgui_demo.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.71
+// dear imgui, v1.72
// (demo code)
// Message to the person tempted to delete this file when integrating Dear ImGui into their code base:
@@ -89,13 +89,12 @@ Index of this file:
#pragma clang diagnostic ignored "-Wreserved-id-macro" // warning : macro name is a reserved identifier //
#endif
#elif defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
#pragma GCC diagnostic ignored "-Wint-to-pointer-cast" // warning: cast to pointer from integer of different size
#pragma GCC diagnostic ignored "-Wformat-security" // warning : format string is not a string literal (potentially insecure)
#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
-#if (__GNUC__ >= 6)
-#pragma GCC diagnostic ignored "-Wmisleading-indentation" // warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on GitHub.
-#endif
+#pragma GCC diagnostic ignored "-Wmisleading-indentation" // [__GNUC__ >= 6] warning: this 'if' clause does not guard this statement // GCC 6.0+ only. See #883 on GitHub.
#endif
// Play it nice with Windows users. Notepad in 2017 still doesn't display text data with Unix-style \n.
@@ -540,8 +539,19 @@ static void ShowDemoWindowWidgets()
static float f1=0.123f, f2=0.0f;
ImGui::SliderFloat("slider float", &f1, 0.0f, 1.0f, "ratio = %.3f");
ImGui::SliderFloat("slider float (curve)", &f2, -10.0f, 10.0f, "%.4f", 2.0f);
+
static float angle = 0.0f;
ImGui::SliderAngle("slider angle", &angle);
+
+ // Using the format string to display a name instead of an integer.
+ // Here we completely omit '%d' from the format string, so it'll only display a name.
+ // This technique can also be used with DragInt().
+ enum Element { Element_Fire, Element_Earth, Element_Air, Element_Water, Element_COUNT };
+ const char* element_names[Element_COUNT] = { "Fire", "Earth", "Air", "Water" };
+ static int current_element = Element_Fire;
+ const char* current_element_name = (current_element >= 0 && current_element < Element_COUNT) ? element_names[current_element] : "Unknown";
+ ImGui::SliderInt("slider enum", &current_element, 0, Element_COUNT - 1, current_element_name);
+ ImGui::SameLine(); HelpMarker("Using the format string parameter to display a name instead of the underlying integer.");
}
{
@@ -629,7 +639,7 @@ static void ShowDemoWindowWidgets()
{
// Items 3..5 are Tree Leaves
// The only reason we use TreeNode at all is to allow selection of the leaf.
- // Otherwise we can use BulletText() or TreeAdvanceToLabelPos()+Text().
+ // Otherwise we can use BulletText() or advance the cursor by GetTreeNodeToLabelSpacing() and call Text().
node_flags |= ImGuiTreeNodeFlags_Leaf | ImGuiTreeNodeFlags_NoTreePushOnOpen; // ImGuiTreeNodeFlags_Bullet
ImGui::TreeNodeEx((void*)(intptr_t)i, node_flags, "Selectable Leaf %d", i);
if (ImGui::IsItemClicked())
@@ -969,7 +979,7 @@ static void ShowDemoWindowWidgets()
ImGui::CheckboxFlags("ImGuiInputTextFlags_ReadOnly", (unsigned int*)&flags, ImGuiInputTextFlags_ReadOnly);
ImGui::CheckboxFlags("ImGuiInputTextFlags_AllowTabInput", (unsigned int*)&flags, ImGuiInputTextFlags_AllowTabInput);
ImGui::CheckboxFlags("ImGuiInputTextFlags_CtrlEnterForNewLine", (unsigned int*)&flags, ImGuiInputTextFlags_CtrlEnterForNewLine);
- ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-1.0f, ImGui::GetTextLineHeight() * 16), flags);
+ ImGui::InputTextMultiline("##source", text, IM_ARRAYSIZE(text), ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16), flags);
ImGui::TreePop();
}
@@ -1025,7 +1035,7 @@ static void ShowDemoWindowWidgets()
static ImVector<char> my_str;
if (my_str.empty())
my_str.push_back(0);
- Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-1.0f, ImGui::GetTextLineHeight() * 16));
+ Funcs::MyInputTextMultiline("##MyStr", &my_str, ImVec2(-FLT_MIN, ImGui::GetTextLineHeight() * 16));
ImGui::Text("Data: %p\nSize: %d\nCapacity: %d", (void*)my_str.begin(), my_str.size(), my_str.capacity());
ImGui::TreePop();
}
@@ -1086,7 +1096,8 @@ static void ShowDemoWindowWidgets()
if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; }
}
- // Typically we would use ImVec2(-1.0f,0.0f) to use all available width, or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth.
+ // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width,
+ // or ImVec2(width,0.0f) for a specified width. ImVec2(0.0f,0.0f) uses ItemWidth.
ImGui::ProgressBar(progress, ImVec2(0.0f,0.0f));
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::Text("Progress Bar");
@@ -1112,7 +1123,7 @@ static void ShowDemoWindowWidgets()
ImGui::Checkbox("With Drag and Drop", &drag_and_drop);
ImGui::Checkbox("With Options Menu", &options_menu); ImGui::SameLine(); HelpMarker("Right-click on the individual color widget to show options.");
ImGui::Checkbox("With HDR", &hdr); ImGui::SameLine(); HelpMarker("Currently all this does is to lift the 0..1 limits on dragging widgets.");
- int misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (drag_and_drop ? 0 : ImGuiColorEditFlags_NoDragDrop) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions);
+ ImGuiColorEditFlags misc_flags = (hdr ? ImGuiColorEditFlags_HDR : 0) | (drag_and_drop ? 0 : ImGuiColorEditFlags_NoDragDrop) | (alpha_half_preview ? ImGuiColorEditFlags_AlphaPreviewHalf : (alpha_preview ? ImGuiColorEditFlags_AlphaPreview : 0)) | (options_menu ? 0 : ImGuiColorEditFlags_NoOptions);
ImGui::Text("Color widget:");
ImGui::SameLine(); HelpMarker("Click on the colored square to open a color picker.\nCTRL+click on individual component to input value.\n");
@@ -1145,7 +1156,7 @@ static void ShowDemoWindowWidgets()
static ImVec4 backup_color;
bool open_popup = ImGui::ColorButton("MyColor##3b", color, misc_flags);
- ImGui::SameLine();
+ ImGui::SameLine(0, ImGui::GetStyle().ItemInnerSpacing.x);
open_popup |= ImGui::Button("Palette");
if (open_popup)
{
@@ -1545,28 +1556,22 @@ static void ShowDemoWindowWidgets()
static bool b = false;
static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f };
static char str[16] = {};
- ImGui::RadioButton("Text", &item_type, 0);
- ImGui::RadioButton("Button", &item_type, 1);
- ImGui::RadioButton("Checkbox", &item_type, 2);
- ImGui::RadioButton("SliderFloat", &item_type, 3);
- ImGui::RadioButton("InputText", &item_type, 4);
- 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();
+ ImGui::Combo("Item Type", &item_type, "Text\0Button\0Button (w/ repeat)\0Checkbox\0SliderFloat\0InputText\0InputFloat\0InputFloat3\0ColorEdit4\0MenuItem\0TreeNode (w/ double-click)\0ListBox\0");
+ ImGui::SameLine();
+ HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions.");
bool ret = false;
if (item_type == 0) { ImGui::Text("ITEM: Text"); } // Testing text items with no identifier/interaction
if (item_type == 1) { ret = ImGui::Button("ITEM: Button"); } // Testing button
- 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::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)); }
+ if (item_type == 2) { ImGui::PushButtonRepeat(true); ret = ImGui::Button("ITEM: Button"); ImGui::PopButtonRepeat(); } // Testing button (with repeater)
+ if (item_type == 3) { ret = ImGui::Checkbox("ITEM: Checkbox", &b); } // Testing checkbox
+ if (item_type == 4) { ret = ImGui::SliderFloat("ITEM: SliderFloat", &col4f[0], 0.0f, 1.0f); } // Testing basic item
+ if (item_type == 5) { ret = ImGui::InputText("ITEM: InputText", &str[0], IM_ARRAYSIZE(str)); } // Testing input text (which handles tabbing)
+ if (item_type == 6) { ret = ImGui::InputFloat("ITEM: InputFloat", col4f, 1.0f); } // Testing +/- buttons on scalar input
+ if (item_type == 7) { ret = ImGui::InputFloat3("ITEM: InputFloat3", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
+ if (item_type == 8) { ret = ImGui::ColorEdit4("ITEM: ColorEdit4", col4f); } // Testing multi-component items (IsItemXXX flags are reported merged)
+ if (item_type == 9) { ret = ImGui::MenuItem("ITEM: MenuItem"); } // Testing menu item (they use ImGuiButtonFlags_PressedOnRelease button policy)
+ if (item_type == 10){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy.
+ if (item_type == 11){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); }
ImGui::BulletText(
"Return value = %d\n"
"IsItemFocused() = %d\n"
@@ -1728,7 +1733,7 @@ static void ShowDemoWindowLayout()
{
char buf[32];
sprintf(buf, "%03d", i);
- ImGui::Button(buf, ImVec2(-1.0f, 0.0f));
+ ImGui::Button(buf, ImVec2(-FLT_MIN, 0.0f));
ImGui::NextColumn();
}
ImGui::EndChild();
@@ -1744,7 +1749,7 @@ static void ShowDemoWindowLayout()
// - Using ImGui::GetItemRectMin/Max() to query the "item" state (because the child window is an item from the POV of the parent window)
// See "Widgets" -> "Querying Status (Active/Focused/Hovered etc.)" section for more details about this.
{
- ImGui::SetCursorPosX(50);
+ ImGui::SetCursorPosX(ImGui::GetCursorPosX() + 10);
ImGui::PushStyleColor(ImGuiCol_ChildBg, IM_COL32(255, 0, 0, 100));
ImGui::BeginChild("blah", ImVec2(200, 100), true, ImGuiWindowFlags_None);
for (int n = 0; n < 50; n++)
@@ -1788,9 +1793,9 @@ static void ShowDemoWindowLayout()
ImGui::Text("SetNextItemWidth/PushItemWidth(-1)");
ImGui::SameLine(); HelpMarker("Align to right edge");
ImGui::PushItemWidth(-1);
- ImGui::DragFloat("float##5a", &f);
- ImGui::DragFloat("float##5b", &f);
- ImGui::DragFloat("float##5c", &f);
+ ImGui::DragFloat("##float5a", &f);
+ ImGui::DragFloat("##float5b", &f);
+ ImGui::DragFloat("##float5c", &f);
ImGui::PopItemWidth();
ImGui::TreePop();
@@ -1957,7 +1962,7 @@ static void ShowDemoWindowLayout()
if (ImGui::TreeNode("Groups"))
{
- HelpMarker("Using ImGui::BeginGroup()/EndGroup() to layout items. BeginGroup() basically locks the horizontal position. EndGroup() bundles the whole group so that you can use functions such as IsItemHovered() on it.");
+ HelpMarker("BeginGroup() basically locks the horizontal position for new line. EndGroup() bundles the whole group so that you can use \"item\" functions such as IsItemHovered()/IsItemActive() or SameLine() etc. on the whole group.");
ImGui::BeginGroup();
{
ImGui::BeginGroup();
@@ -2056,21 +2061,22 @@ static void ShowDemoWindowLayout()
if (ImGui::TreeNode("Scrolling"))
{
- HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given position.");
+ // Vertical scroll functions
+ HelpMarker("Use SetScrollHereY() or SetScrollFromPosY() to scroll to a given vertical position.");
static bool track = true;
- static int track_line = 50;
+ static int track_item = 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(140); track |= ImGui::DragInt("##line", &track_line, 0.25f, 0, 99, "Line = %d");
+ ImGui::SameLine(140); track |= ImGui::DragInt("##item", &track_item, 0.25f, 0, 99, "Item = %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");
+ ImGui::SameLine(140); scroll_to_off |= ImGui::DragFloat("##off", &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::SameLine(140); scroll_to_pos |= ImGui::DragFloat("##pos", &scroll_to_pos_px, 1.00f, 0, 9999, "X/Y = %.0f px");
ImGui::PopItemWidth();
if (scroll_to_off || scroll_to_pos)
@@ -2078,28 +2084,31 @@ static void ShowDemoWindowLayout()
ImGuiStyle& style = ImGui::GetStyle();
float child_w = (ImGui::GetContentRegionAvail().x - 4 * style.ItemSpacing.x) / 5;
+ if (child_w < 1.0f)
+ child_w = 1.0f;
+ ImGui::PushID("##VerticalScrolling");
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");
+ const char* names[] = { "Top", "25%", "Center", "75%", "Bottom" };
+ ImGui::TextUnformatted(names[i]);
- ImGuiWindowFlags child_flags = ImGuiWindowFlags_MenuBar;
- ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(child_w, 200.0f), true, child_flags);
+ ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(child_w, 200.0f), true, ImGuiWindowFlags_None);
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++)
+ for (int item = 0; item < 100; item++)
{
- if (track && line == track_line)
+ if (track && item == track_item)
{
- ImGui::TextColored(ImVec4(1,1,0,1), "Line %d", line);
+ ImGui::TextColored(ImVec4(1,1,0,1), "Item %d", item);
ImGui::SetScrollHereY(i * 0.25f); // 0.0f:top, 0.5f:center, 1.0f:bottom
}
else
{
- ImGui::Text("Line %d", line);
+ ImGui::Text("Item %d", item);
}
}
float scroll_y = ImGui::GetScrollY();
@@ -2108,11 +2117,44 @@ static void ShowDemoWindowLayout()
ImGui::Text("%.0f/%.0f", scroll_y, scroll_max_y);
ImGui::EndGroup();
}
- ImGui::TreePop();
- }
+ ImGui::PopID();
- if (ImGui::TreeNode("Horizontal Scrolling"))
- {
+ // Horizontal scroll functions
+ ImGui::Spacing();
+ HelpMarker("Use SetScrollHereX() or SetScrollFromPosX() to scroll to a given horizontal position.\n\nUsing the \"Scroll To Pos\" button above will make the discontinuity at edges visible: scrolling to the top/bottom/left/right-most item will add an additional WindowPadding to reflect on reaching the edge of the list.\n\nBecause the clipping rectangle of most window hides half worth of WindowPadding on the left/right, using SetScrollFromPosX(+1) will usually result in clipped text whereas the equivalent SetScrollFromPosY(+1) wouldn't.");
+ ImGui::PushID("##HorizontalScrolling");
+ for (int i = 0; i < 5; i++)
+ {
+ float child_height = ImGui::GetTextLineHeight() + style.ScrollbarSize + style.WindowPadding.y * 2.0f;
+ ImGui::BeginChild(ImGui::GetID((void*)(intptr_t)i), ImVec2(-100, child_height), true, ImGuiWindowFlags_HorizontalScrollbar);
+ if (scroll_to_off)
+ ImGui::SetScrollX(scroll_to_off_px);
+ if (scroll_to_pos)
+ ImGui::SetScrollFromPosX(ImGui::GetCursorStartPos().x + scroll_to_pos_px, i * 0.25f);
+ for (int item = 0; item < 100; item++)
+ {
+ if (track && item == track_item)
+ {
+ ImGui::TextColored(ImVec4(1, 1, 0, 1), "Item %d", item);
+ ImGui::SetScrollHereX(i * 0.25f); // 0.0f:left, 0.5f:center, 1.0f:right
+ }
+ else
+ {
+ ImGui::Text("Item %d", item);
+ }
+ ImGui::SameLine();
+ }
+ float scroll_x = ImGui::GetScrollX();
+ float scroll_max_x = ImGui::GetScrollMaxX();
+ ImGui::EndChild();
+ ImGui::SameLine();
+ const char* names[] = { "Left", "25%", "Center", "75%", "Right" };
+ ImGui::Text("%s\n%.0f/%.0f", names[i], scroll_x, scroll_max_x);
+ ImGui::Spacing();
+ }
+ ImGui::PopID();
+
+ // Miscellaneous Horizontal Scrolling Demo
HelpMarker("Horizontal scrolling for a window has to be enabled explicitly via the ImGuiWindowFlags_HorizontalScrollbar flag.\n\nYou may want to explicitly specify content width by calling SetNextWindowContentWidth() before Begin().");
static int lines = 7;
ImGui::SliderInt("Lines", &lines, 1, 15);
@@ -2520,7 +2562,7 @@ static void ShowDemoWindowColumns()
char label[32];
sprintf(label, "Item %d", n);
if (ImGui::Selectable(label)) {}
- //if (ImGui::Button(label, ImVec2(-1,0))) {}
+ //if (ImGui::Button(label, ImVec2(-FLT_MIN,0.0f))) {}
ImGui::NextColumn();
}
ImGui::Columns(1);
@@ -2559,19 +2601,27 @@ static void ShowDemoWindowColumns()
// NB: Future columns API should allow automatic horizontal borders.
static bool h_borders = true;
static bool v_borders = true;
+ static int columns_count = 4;
+ const int lines_count = 3;
+ ImGui::SetNextItemWidth(ImGui::GetFontSize() * 8);
+ ImGui::DragInt("##columns_count", &columns_count, 0.1f, 2, 10, "%d columns");
+ if (columns_count < 2)
+ columns_count = 2;
+ ImGui::SameLine();
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++)
+ ImGui::Columns(columns_count, NULL, v_borders);
+ for (int i = 0; i < columns_count * lines_count; 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("Avail %.2f", ImGui::GetContentRegionAvail().x);
ImGui::Text("Offset %.2f", ImGui::GetColumnOffset());
ImGui::Text("Long text that is likely to clip");
- ImGui::Button("Button", ImVec2(-1.0f, 0.0f));
+ ImGui::Button("Button", ImVec2(-FLT_MIN, 0.0f));
ImGui::NextColumn();
}
ImGui::Columns(1);
@@ -3113,6 +3163,7 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::Text("Alignment");
ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
ImGui::Combo("WindowMenuButtonPosition", (int*)&style.WindowMenuButtonPosition, "Left\0Right\0");
+ ImGui::Combo("ColorButtonPosition", (int*)&style.ColorButtonPosition, "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).");
@@ -3256,8 +3307,9 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::TreePop();
}
+ HelpMarker("Those are old settings provided for convenience.\nHowever, the _correct_ way of scaling your UI is currently to reload your font at the designed size, rebuild the font atlas, and call style.ScaleAllSizes() on a reference ImGuiStyle structure.");
static float window_scale = 1.0f;
- if (ImGui::DragFloat("this window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.2f")) // scale only this window
+ if (ImGui::DragFloat("window scale", &window_scale, 0.005f, 0.3f, 2.0f, "%.2f")) // scale only this window
ImGui::SetWindowFontScale(window_scale);
ImGui::DragFloat("global scale", &io.FontGlobalScale, 0.005f, 0.3f, 2.0f, "%.2f"); // scale everything
ImGui::PopItemWidth();
@@ -3408,7 +3460,7 @@ struct ExampleAppConsole
Commands.push_back("CLEAR");
Commands.push_back("CLASSIFY"); // "classify" is only here to provide an example of "C"+[tab] completing to "CL" and displaying matches.
AutoScroll = true;
- ScrollToBottom = true;
+ ScrollToBottom = false;
AddLog("Welcome to Dear ImGui!");
}
~ExampleAppConsole()
@@ -3429,7 +3481,6 @@ struct ExampleAppConsole
for (int i = 0; i < Items.Size; i++)
free(Items[i]);
Items.clear();
- ScrollToBottom = true;
}
void AddLog(const char* fmt, ...) IM_FMTARGS(2)
@@ -3442,8 +3493,6 @@ struct ExampleAppConsole
buf[IM_ARRAYSIZE(buf)-1] = 0;
va_end(args);
Items.push_back(Strdup(buf));
- if (AutoScroll)
- ScrollToBottom = true;
}
void Draw(const char* title, bool* p_open)
@@ -3472,8 +3521,7 @@ struct ExampleAppConsole
if (ImGui::SmallButton("Add Dummy Text")) { AddLog("%d some text", Items.Size); AddLog("some more text"); AddLog("display very important message here!"); } ImGui::SameLine();
if (ImGui::SmallButton("Add Dummy Error")) { AddLog("[error] something went wrong"); } ImGui::SameLine();
if (ImGui::SmallButton("Clear")) { ClearLog(); } ImGui::SameLine();
- bool copy_to_clipboard = ImGui::SmallButton("Copy"); ImGui::SameLine();
- if (ImGui::SmallButton("Scroll to bottom")) ScrollToBottom = true;
+ bool copy_to_clipboard = ImGui::SmallButton("Copy");
//static float t = 0.0f; if (ImGui::GetTime() - t > 0.02f) { t = ImGui::GetTime(); AddLog("Spam %f", t); }
ImGui::Separator();
@@ -3481,9 +3529,7 @@ struct ExampleAppConsole
// Options menu
if (ImGui::BeginPopup("Options"))
{
- if (ImGui::Checkbox("Auto-scroll", &AutoScroll))
- if (AutoScroll)
- ScrollToBottom = true;
+ ImGui::Checkbox("Auto-scroll", &AutoScroll);
ImGui::EndPopup();
}
@@ -3532,9 +3578,11 @@ struct ExampleAppConsole
}
if (copy_to_clipboard)
ImGui::LogFinish();
- if (ScrollToBottom)
+
+ if (ScrollToBottom || (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY()))
ImGui::SetScrollHereY(1.0f);
ScrollToBottom = false;
+
ImGui::PopStyleVar();
ImGui::EndChild();
ImGui::Separator();
@@ -3726,13 +3774,11 @@ struct ExampleAppLog
ImGuiTextBuffer Buf;
ImGuiTextFilter Filter;
ImVector<int> LineOffsets; // Index to lines offset. We maintain this with AddLog() calls, allowing us to have a random access on lines
- bool AutoScroll;
- bool ScrollToBottom;
+ bool AutoScroll; // Keep scrolling if already at the bottom
ExampleAppLog()
{
AutoScroll = true;
- ScrollToBottom = false;
Clear();
}
@@ -3753,8 +3799,6 @@ struct ExampleAppLog
for (int new_size = Buf.size(); old_size < new_size; old_size++)
if (Buf[old_size] == '\n')
LineOffsets.push_back(old_size + 1);
- if (AutoScroll)
- ScrollToBottom = true;
}
void Draw(const char* title, bool* p_open = NULL)
@@ -3768,9 +3812,7 @@ struct ExampleAppLog
// Options menu
if (ImGui::BeginPopup("Options"))
{
- if (ImGui::Checkbox("Auto-scroll", &AutoScroll))
- if (AutoScroll)
- ScrollToBottom = true;
+ ImGui::Checkbox("Auto-scroll", &AutoScroll);
ImGui::EndPopup();
}
@@ -3835,9 +3877,9 @@ struct ExampleAppLog
}
ImGui::PopStyleVar();
- if (ScrollToBottom)
+ if (AutoScroll && ImGui::GetScrollY() >= ImGui::GetScrollMaxY())
ImGui::SetScrollHereY(1.0f);
- ScrollToBottom = false;
+
ImGui::EndChild();
ImGui::End();
}
@@ -4022,7 +4064,7 @@ static void ShowExampleAppLongText(bool* p_open)
static ImGuiTextBuffer log;
static int lines = 0;
ImGui::Text("Printing unusually long amount of text.");
- ImGui::Combo("Test type", &test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped manually\0Multiple calls to Text(), not clipped (slow)\0");
+ ImGui::Combo("Test type", &test_type, "Single call to TextUnformatted()\0Multiple calls to Text(), clipped\0Multiple calls to Text(), not clipped (slow)\0");
ImGui::Text("Buffer contents: %d lines, %d bytes", lines, log.size());
if (ImGui::Button("Clear")) { log.clear(); lines = 0; }
ImGui::SameLine();
diff --git a/imgui/imgui_draw.cpp b/imgui/imgui_draw.cpp
index 8d0c31de..a03f5855 100644
--- a/imgui/imgui_draw.cpp
+++ b/imgui/imgui_draw.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.71
+// dear imgui, v1.72
// (drawing and font code)
/*
@@ -72,13 +72,12 @@ Index of this file:
#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
#endif
#elif defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
#pragma GCC diagnostic ignored "-Wunused-function" // warning: 'xxxx' defined but not used
#pragma GCC diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function
#pragma GCC diagnostic ignored "-Wconversion" // warning: conversion to 'xxxx' from 'xxxx' may alter its value
#pragma GCC diagnostic ignored "-Wstack-protector" // warning: stack protector not protecting local variables: variable length buffer
-#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
+#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
#endif
//-------------------------------------------------------------------------
@@ -261,7 +260,7 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst)
colors[ImGuiCol_Header] = ImVec4(0.40f, 0.40f, 0.90f, 0.45f);
colors[ImGuiCol_HeaderHovered] = ImVec4(0.45f, 0.45f, 0.90f, 0.80f);
colors[ImGuiCol_HeaderActive] = ImVec4(0.53f, 0.53f, 0.87f, 0.80f);
- colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 1.00f);
+ colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 0.60f);
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.60f, 0.60f, 0.70f, 1.00f);
colors[ImGuiCol_SeparatorActive] = ImVec4(0.70f, 0.70f, 0.90f, 1.00f);
colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.16f);
@@ -317,7 +316,7 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst)
colors[ImGuiCol_Header] = ImVec4(0.26f, 0.59f, 0.98f, 0.31f);
colors[ImGuiCol_HeaderHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.80f);
colors[ImGuiCol_HeaderActive] = ImVec4(0.26f, 0.59f, 0.98f, 1.00f);
- colors[ImGuiCol_Separator] = ImVec4(0.39f, 0.39f, 0.39f, 1.00f);
+ colors[ImGuiCol_Separator] = ImVec4(0.39f, 0.39f, 0.39f, 0.62f);
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.14f, 0.44f, 0.80f, 0.78f);
colors[ImGuiCol_SeparatorActive] = ImVec4(0.14f, 0.44f, 0.80f, 1.00f);
colors[ImGuiCol_ResizeGrip] = ImVec4(0.80f, 0.80f, 0.80f, 0.56f);
@@ -365,7 +364,7 @@ void ImDrawList::Clear()
CmdBuffer.resize(0);
IdxBuffer.resize(0);
VtxBuffer.resize(0);
- Flags = _Data->InitialFlags;
+ Flags = _Data ? _Data->InitialFlags : ImDrawListFlags_None;
_VtxCurrentOffset = 0;
_VtxCurrentIdx = 0;
_VtxWritePtr = NULL;
@@ -392,7 +391,7 @@ void ImDrawList::ClearFreeMemory()
ImDrawList* ImDrawList::CloneOutput() const
{
- ImDrawList* dst = IM_NEW(ImDrawList(NULL));
+ ImDrawList* dst = IM_NEW(ImDrawList(_Data));
dst->CmdBuffer = CmdBuffer;
dst->IdxBuffer = IdxBuffer;
dst->VtxBuffer = VtxBuffer;
@@ -944,7 +943,7 @@ void ImDrawList::PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImV
}
}
-void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, int rounding_corners)
+void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDrawCornerFlags rounding_corners)
{
rounding = ImMin(rounding, ImFabs(b.x - a.x) * ( ((rounding_corners & ImDrawCornerFlags_Top) == ImDrawCornerFlags_Top) || ((rounding_corners & ImDrawCornerFlags_Bot) == ImDrawCornerFlags_Bot) ? 0.5f : 1.0f ) - 1.0f);
rounding = ImMin(rounding, ImFabs(b.y - a.y) * ( ((rounding_corners & ImDrawCornerFlags_Left) == ImDrawCornerFlags_Left) || ((rounding_corners & ImDrawCornerFlags_Right) == ImDrawCornerFlags_Right) ? 0.5f : 1.0f ) - 1.0f);
@@ -979,24 +978,24 @@ void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thic
}
// a: upper-left, b: lower-right. we don't render 1 px sized rectangles properly.
-void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners_flags, float thickness)
+void ImDrawList::AddRect(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners, float thickness)
{
if ((col & IM_COL32_A_MASK) == 0)
return;
if (Flags & ImDrawListFlags_AntiAliasedLines)
- PathRect(a + ImVec2(0.5f,0.5f), b - ImVec2(0.50f,0.50f), rounding, rounding_corners_flags);
+ PathRect(a + ImVec2(0.5f,0.5f), b - ImVec2(0.50f,0.50f), rounding, rounding_corners);
else
- PathRect(a + ImVec2(0.5f,0.5f), b - ImVec2(0.49f,0.49f), rounding, rounding_corners_flags); // Better looking lower-right corner and rounded non-AA shapes.
+ PathRect(a + ImVec2(0.5f,0.5f), b - ImVec2(0.49f,0.49f), rounding, rounding_corners); // Better looking lower-right corner and rounded non-AA shapes.
PathStroke(col, true, thickness);
}
-void ImDrawList::AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, int rounding_corners_flags)
+void ImDrawList::AddRectFilled(const ImVec2& a, const ImVec2& b, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners)
{
if ((col & IM_COL32_A_MASK) == 0)
return;
if (rounding > 0.0f)
{
- PathRect(a, b, rounding, rounding_corners_flags);
+ PathRect(a, b, rounding, rounding_corners);
PathFillConvex(col);
}
else
@@ -1165,7 +1164,7 @@ void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& a, cons
PopTextureID();
}
-void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col, float rounding, int rounding_corners)
+void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners)
{
if ((col & IM_COL32_A_MASK) == 0)
return;
@@ -1262,7 +1261,7 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list)
// 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;
+ ImDrawCmd* last_cmd = (_Count > 0 && draw_list->CmdBuffer.Size > 0) ? &draw_list->CmdBuffer.back() : NULL;
int idx_offset = last_cmd ? last_cmd->IdxOffset + last_cmd->ElemCount : 0;
for (int i = 1; i < _Count; i++)
{
@@ -1305,7 +1304,7 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list)
void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx)
{
- IM_ASSERT(idx < _Count);
+ IM_ASSERT(idx >= 0 && idx < _Count);
if (_Current == idx)
return;
// Overwrite ImVector (12/16 bytes), four times. This is merely a silly optimization instead of doing .swap()
@@ -1721,7 +1720,7 @@ int ImFontAtlas::AddCustomRectRegular(unsigned int id, int width, int height)
IM_ASSERT(id >= 0x10000);
IM_ASSERT(width > 0 && width <= 0xFFFF);
IM_ASSERT(height > 0 && height <= 0xFFFF);
- CustomRect r;
+ ImFontAtlasCustomRect r;
r.ID = id;
r.Width = (unsigned short)width;
r.Height = (unsigned short)height;
@@ -1734,7 +1733,7 @@ int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int
IM_ASSERT(font != NULL);
IM_ASSERT(width > 0 && width <= 0xFFFF);
IM_ASSERT(height > 0 && height <= 0xFFFF);
- CustomRect r;
+ ImFontAtlasCustomRect r;
r.ID = id;
r.Width = (unsigned short)width;
r.Height = (unsigned short)height;
@@ -1745,7 +1744,7 @@ int ImFontAtlas::AddCustomRectFontGlyph(ImFont* font, ImWchar id, int width, int
return CustomRects.Size - 1; // Return index
}
-void ImFontAtlas::CalcCustomRectUV(const CustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max)
+void ImFontAtlas::CalcCustomRectUV(const ImFontAtlasCustomRect* rect, ImVec2* out_uv_min, ImVec2* out_uv_max)
{
IM_ASSERT(TexWidth > 0 && TexHeight > 0); // Font atlas needs to be built before we can calculate UV coordinates
IM_ASSERT(rect->IsPacked()); // Make sure the rectangle has been packed
@@ -1761,7 +1760,7 @@ bool ImFontAtlas::GetMouseCursorTexData(ImGuiMouseCursor cursor_type, ImVec2* ou
return false;
IM_ASSERT(CustomRectIds[0] != -1);
- ImFontAtlas::CustomRect& r = CustomRects[CustomRectIds[0]];
+ ImFontAtlasCustomRect& r = CustomRects[CustomRectIds[0]];
IM_ASSERT(r.ID == FONT_ATLAS_DEFAULT_TEX_DATA_ID);
ImVec2 pos = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][0] + ImVec2((float)r.X, (float)r.Y);
ImVec2 size = FONT_ATLAS_DEFAULT_TEX_CURSOR_DATA[cursor_type][1];
@@ -2120,7 +2119,7 @@ void ImFontAtlasBuildPackCustomRects(ImFontAtlas* atlas, void* stbrp_context_opa
stbrp_context* pack_context = (stbrp_context*)stbrp_context_opaque;
IM_ASSERT(pack_context != NULL);
- ImVector<ImFontAtlas::CustomRect>& user_rects = atlas->CustomRects;
+ ImVector<ImFontAtlasCustomRect>& user_rects = atlas->CustomRects;
IM_ASSERT(user_rects.Size >= 1); // We expect at least the default custom rects to be registered, else something went wrong.
ImVector<stbrp_rect> pack_rects;
@@ -2146,7 +2145,7 @@ static void ImFontAtlasBuildRenderDefaultTexData(ImFontAtlas* atlas)
{
IM_ASSERT(atlas->CustomRectIds[0] >= 0);
IM_ASSERT(atlas->TexPixelsAlpha8 != NULL);
- ImFontAtlas::CustomRect& r = atlas->CustomRects[atlas->CustomRectIds[0]];
+ ImFontAtlasCustomRect& r = atlas->CustomRects[atlas->CustomRectIds[0]];
IM_ASSERT(r.ID == FONT_ATLAS_DEFAULT_TEX_DATA_ID);
IM_ASSERT(r.IsPacked());
@@ -2181,7 +2180,7 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas)
// Register custom rectangle glyphs
for (int i = 0; i < atlas->CustomRects.Size; i++)
{
- const ImFontAtlas::CustomRect& r = atlas->CustomRects[i];
+ const ImFontAtlasCustomRect& r = atlas->CustomRects[i];
if (r.Font == NULL || r.ID > 0x10000)
continue;
@@ -2693,7 +2692,7 @@ const char* ImFont::CalcWordWrapPositionA(float scale, const char* text, const c
}
// We ignore blank width at the end of the line (they can be skipped)
- if (line_width + word_width >= wrap_width)
+ if (line_width + word_width > wrap_width)
{
// Words that cannot possibly fit within an entire line will be cut anywhere.
if (word_width < wrap_width)
diff --git a/imgui/imgui_internal.h b/imgui/imgui_internal.h
index f82225e3..eef74b0f 100644
--- a/imgui/imgui_internal.h
+++ b/imgui/imgui_internal.h
@@ -1,4 +1,4 @@
-// dear imgui, v1.71
+// dear imgui, v1.72
// (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!
@@ -56,9 +56,8 @@ Index of this file:
#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
+#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
+#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
#endif
//-----------------------------------------------------------------------------
@@ -92,6 +91,7 @@ struct ImGuiWindowSettings; // Storage for window settings stored in .in
// 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 ImGuiColumnsFlags; // -> enum ImGuiColumnsFlags_ // Flags: BeginColumns()
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
@@ -141,12 +141,15 @@ extern IMGUI_API ImGuiContext* GImGui; // Current implicit context pointer
#define IM_NEWLINE "\n"
#endif
#define IM_TABSIZE (4)
-
-#define IMGUI_DEBUG_LOG(_FMT,...) printf("[%05d] " _FMT, GImGui->FrameCount, __VA_ARGS__)
#define IM_STATIC_ASSERT(_COND) typedef char static_assertion_##__line__[(_COND)?1:-1]
#define IM_F32_TO_INT8_UNBOUND(_VAL) ((int)((_VAL) * 255.0f + ((_VAL)>=0 ? 0.5f : -0.5f))) // Unsaturated, for display purpose
#define IM_F32_TO_INT8_SAT(_VAL) ((int)(ImSaturate(_VAL) * 255.0f + 0.5f)) // Saturated, always output 0..255
+// Debug Logging
+#ifndef IMGUI_DEBUG_LOG
+#define IMGUI_DEBUG_LOG(_FMT,...) printf("[%05d] " _FMT, GImGui->FrameCount, __VA_ARGS__)
+#endif
+
// Enforce cdecl calling convention for functions called by the standard library, in case compilation settings changed the default to e.g. __vectorcall
#ifdef _MSC_VER
#define IMGUI_CDECL __cdecl
@@ -358,7 +361,8 @@ enum ImGuiSelectableFlagsPrivate_
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
+ ImGuiSelectableFlags_AllowItemOverlap = 1 << 24,
+ ImGuiSelectableFlags_DrawHoveredWhenHeld= 1 << 25 // Always show active when held, even is not hovered. This concept could probably be renamed/formalized somehow.
};
// Extend ImGuiTreeNodeFlags_
@@ -385,6 +389,7 @@ enum ImGuiItemFlags_
ImGuiItemFlags_NoNav = 1 << 3, // false
ImGuiItemFlags_NoNavDefaultFocus = 1 << 4, // false
ImGuiItemFlags_SelectableDontClosePopup = 1 << 5, // false // MenuItem/Selectable() automatically closes current Popup window
+ ImGuiItemFlags_MixedValue = 1 << 6, // false // [BETA] Represent a mixed/indeterminate value, generally multi-selection where values differ. Currently only supported by Checkbox() (later should support all sorts of widgets)
ImGuiItemFlags_Default_ = 0
};
@@ -400,7 +405,7 @@ enum ImGuiItemStatusFlags_
ImGuiItemStatusFlags_Deactivated = 1 << 5 // Only valid if ImGuiItemStatusFlags_HasDeactivated is set.
#ifdef IMGUI_ENABLE_TEST_ENGINE
- , // [imgui-test only]
+ , // [imgui_tests only]
ImGuiItemStatusFlags_Openable = 1 << 10, //
ImGuiItemStatusFlags_Opened = 1 << 11, //
ImGuiItemStatusFlags_Checkable = 1 << 12, //
@@ -704,6 +709,7 @@ struct ImGuiColumns
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()
+ ImRect HostWorkRect; // Backup of WorkRect at the time of BeginColumns()
ImVector<ImGuiColumnData> Columns;
ImGuiColumns() { Clear(); }
@@ -825,13 +831,13 @@ struct ImGuiShrinkWidthItem
float Width;
};
-struct ImGuiTabBarRef
+struct ImGuiPtrOrIndex
{
- ImGuiTabBar* Ptr; // Either field can be set, not both. Dock node tab bars are loose while BeginTabBar() ones are in a pool.
- int IndexInMainPool;
+ void* Ptr; // Either field can be set, not both. e.g. Dock node tab bars are loose while BeginTabBar() ones are in a pool.
+ int Index; // Usually index in a main pool.
- ImGuiTabBarRef(ImGuiTabBar* ptr) { Ptr = ptr; IndexInMainPool = -1; }
- ImGuiTabBarRef(int index_in_main_pool) { Ptr = NULL; IndexInMainPool = index_in_main_pool; }
+ ImGuiPtrOrIndex(void* ptr) { Ptr = ptr; Index = -1; }
+ ImGuiPtrOrIndex(int index) { Ptr = NULL; Index = index; }
};
//-----------------------------------------------------------------------------
@@ -866,6 +872,9 @@ struct ImGuiContext
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.
+ ImGuiWindow* WheelingWindow;
+ ImVec2 WheelingWindowRefMousePos;
+ float WheelingWindowTimer;
// Item/widgets state and tracking information
ImGuiID HoveredId; // Hovered widget
@@ -919,7 +928,7 @@ struct ImGuiContext
ImGuiInputSource NavInputSource; // Keyboard or Gamepad mode? THIS WILL ONLY BE None or NavGamepad or NavKeyboard.
ImRect NavScoringRectScreen; // Rectangle used for scoring, in screen space. Based of window->DC.NavRefRectRel[], modified for directional navigation scoring.
int NavScoringCount; // Metrics for debugging
- ImGuiWindow* NavWindowingTarget; // When selecting a window (holding Menu+FocusPrev/Next, or equivalent of CTRL-TAB) this window is temporarily displayed front-most.
+ ImGuiWindow* NavWindowingTarget; // When selecting a window (holding Menu+FocusPrev/Next, or equivalent of CTRL-TAB) this window is temporarily displayed top-most.
ImGuiWindow* NavWindowingTargetAnim; // Record of last valid NavWindowingTarget until DimBgRatio and NavWindowingHighlightAlpha becomes 0.0f
ImGuiWindow* NavWindowingList;
float NavWindowingTimer;
@@ -981,9 +990,9 @@ struct ImGuiContext
unsigned char DragDropPayloadBufLocal[8]; // Local buffer for small payloads
// Tab bars
- ImPool<ImGuiTabBar> TabBars;
ImGuiTabBar* CurrentTabBar;
- ImVector<ImGuiTabBarRef> CurrentTabBarStack;
+ ImPool<ImGuiTabBar> TabBars;
+ ImVector<ImGuiPtrOrIndex> CurrentTabBarStack;
ImVector<ImGuiShrinkWidthItem> ShrinkWidthBuffer;
// Widget state
@@ -1026,6 +1035,10 @@ struct ImGuiContext
int LogDepthToExpand;
int LogDepthToExpandDefault; // Default/stored value for LogDepthMaxExpand if not specified in the LogXXX function call.
+ // Debug Tools
+ bool DebugItemPickerActive;
+ ImGuiID DebugItemPickerBreakID; // Will call IM_DEBUG_BREAK() when encountering this id
+
// Misc
float FramerateSecPerFrame[120]; // Calculate estimate of framerate for user over the last 2 seconds.
int FramerateSecPerFrameIdx;
@@ -1052,6 +1065,8 @@ struct ImGuiContext
HoveredWindow = NULL;
HoveredRootWindow = NULL;
MovingWindow = NULL;
+ WheelingWindow = NULL;
+ WheelingWindowTimer = 0.0f;
HoveredId = 0;
HoveredIdAllowOverlap = false;
@@ -1151,6 +1166,9 @@ struct ImGuiContext
LogDepthRef = 0;
LogDepthToExpand = LogDepthToExpandDefault = 2;
+ DebugItemPickerActive = false;
+ DebugItemPickerBreakID = 0;
+
memset(FramerateSecPerFrame, 0, sizeof(FramerateSecPerFrame));
FramerateSecPerFrameIdx = 0;
FramerateSecPerFrameAccum = 0.0f;
@@ -1299,7 +1317,7 @@ struct IMGUI_API ImGuiWindow
// 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 InnerRect; // Inner rectangle (omit title bar, menu bar, scroll 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().
@@ -1310,7 +1328,7 @@ struct IMGUI_API ImGuiWindow
ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items
ImGuiStorage StateStorage;
ImVector<ImGuiColumns> ColumnsStorage;
- float FontWindowScale; // User scale multiplier per-window
+ float FontWindowScale; // User scale multiplier per-window, via SetWindowFontScale()
int SettingsIdx; // Index into SettingsWindow[] (indices are always valid as we only grow the array from the back)
ImDrawList* DrawList; // == &DrawListInst (for backward compatibility reason with code using imgui_internal.h we keep this a pointer)
@@ -1337,12 +1355,12 @@ public:
ImGuiID GetIDFromRectangle(const ImRect& r_abs);
// We don't use g.FontSize because the window may be != g.CurrentWidow.
- ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x+Size.x, Pos.y+Size.y); }
- float CalcFontSize() const { return GImGui->FontBaseSize * FontWindowScale; }
- float TitleBarHeight() const { return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f; }
- ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); }
- float MenuBarHeight() const { return (Flags & ImGuiWindowFlags_MenuBar) ? DC.MenuBarOffset.y + CalcFontSize() + GImGui->Style.FramePadding.y * 2.0f : 0.0f; }
- ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); }
+ ImRect Rect() const { return ImRect(Pos.x, Pos.y, Pos.x+Size.x, Pos.y+Size.y); }
+ float CalcFontSize() const { ImGuiContext& g = *GImGui; float scale = g.FontBaseSize * FontWindowScale; if (ParentWindow) scale *= ParentWindow->FontWindowScale; return scale; }
+ float TitleBarHeight() const { ImGuiContext& g = *GImGui; return (Flags & ImGuiWindowFlags_NoTitleBar) ? 0.0f : CalcFontSize() + g.Style.FramePadding.y * 2.0f; }
+ ImRect TitleBarRect() const { return ImRect(Pos, ImVec2(Pos.x + SizeFull.x, Pos.y + TitleBarHeight())); }
+ float MenuBarHeight() const { ImGuiContext& g = *GImGui; return (Flags & ImGuiWindowFlags_MenuBar) ? DC.MenuBarOffset.y + CalcFontSize() + g.Style.FramePadding.y * 2.0f : 0.0f; }
+ ImRect MenuBarRect() const { float y1 = Pos.y + TitleBarHeight(); return ImRect(Pos.x, y1, Pos.x + SizeFull.x, y1 + MenuBarHeight()); }
};
// Backup and restore just enough data to be able to use IsItemHovered() on item A after another B in the same window has overwritten the data.
@@ -1411,7 +1429,7 @@ struct ImGuiTabBar
float ScrollingSpeed;
ImGuiTabBarFlags Flags;
ImGuiID ReorderRequestTabId;
- int ReorderRequestDir;
+ ImS8 ReorderRequestDir;
bool WantLayout;
bool VisibleTabWasSubmitted;
short LastTabItemIdx; // For BeginTabItem()/EndTabItem()
@@ -1451,8 +1469,8 @@ namespace ImGui
IMGUI_API ImVec2 CalcWindowExpectedSize(ImGuiWindow* window);
IMGUI_API bool IsWindowChildOf(ImGuiWindow* window, ImGuiWindow* potential_parent);
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 void SetScrollX(ImGuiWindow* window, float new_scroll_x);
+ IMGUI_API void SetScrollY(ImGuiWindow* window, float new_scroll_y);
IMGUI_API ImRect GetWindowAllowedExtentRect(ImGuiWindow* window);
IMGUI_API void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond = 0);
IMGUI_API void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond = 0);
@@ -1520,7 +1538,7 @@ namespace ImGui
IMGUI_API bool IsPopupOpen(ImGuiID id); // Test for id within current popup stack level (currently begin-ed into); this doesn't scan the whole popup stack!
IMGUI_API bool BeginPopupEx(ImGuiID id, ImGuiWindowFlags extra_flags);
IMGUI_API void BeginTooltipEx(ImGuiWindowFlags extra_flags, bool override_previous_tooltip = true);
- IMGUI_API ImGuiWindow* GetFrontMostPopupModal();
+ IMGUI_API ImGuiWindow* GetTopMostPopupModal();
IMGUI_API ImVec2 FindBestWindowPosForPopup(ImGuiWindow* window);
IMGUI_API ImVec2 FindBestWindowPosForPopupEx(const ImVec2& ref_pos, const ImVec2& size, ImGuiDir* last_dir, const ImRect& r_outer, const ImRect& r_avoid, ImGuiPopupPositionPolicy policy = ImGuiPopupPositionPolicy_Default);
@@ -1538,6 +1556,7 @@ namespace ImGui
IMGUI_API void SetNavIDWithRectRel(ImGuiID id, int nav_layer, const ImRect& rect_rel);
// Inputs
+ inline bool IsMouseDragPastThreshold(int button, float lock_threshold = -1.0f);
inline bool IsKeyPressedMap(ImGuiKey key, bool repeat = true) { const int key_index = GImGui->IO.KeyMap[key]; return (key_index >= 0) ? IsKeyPressed(key_index, repeat) : false; }
inline bool IsNavInputDown(ImGuiNavInput n) { return GImGui->IO.NavInputs[n] > 0.0f; }
inline bool IsNavInputPressed(ImGuiNavInput n, ImGuiInputReadMode mode) { return GetNavInputAmount(n, mode) > 0.0f; }
@@ -1556,6 +1575,8 @@ namespace ImGui
IMGUI_API void PopColumnsBackground();
IMGUI_API ImGuiID GetColumnsID(const char* str_id, int count);
IMGUI_API ImGuiColumns* FindOrCreateColumns(ImGuiWindow* window, ImGuiID id);
+ IMGUI_API float GetColumnOffsetFromNorm(const ImGuiColumns* columns, float offset_norm);
+ IMGUI_API float GetColumnNormFromOffset(const ImGuiColumns* columns, float offset);
// Tab Bars
IMGUI_API bool BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& bb, ImGuiTabBarFlags flags);
@@ -1649,6 +1670,9 @@ namespace ImGui
IMGUI_API void ShadeVertsLinearColorGradientKeepAlpha(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, ImVec2 gradient_p0, ImVec2 gradient_p1, ImU32 col0, ImU32 col1);
IMGUI_API void ShadeVertsLinearUV(ImDrawList* draw_list, int vert_start_idx, int vert_end_idx, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, bool clamp);
+ // Debug Tools
+ inline void DebugStartItemPicker() { GImGui->DebugItemPickerActive = true; }
+
} // namespace ImGui
// ImFontAtlas internals
@@ -1660,7 +1684,19 @@ IMGUI_API void ImFontAtlasBuildFinish(ImFontAtlas* atlas);
IMGUI_API void ImFontAtlasBuildMultiplyCalcLookupTable(unsigned char out_table[256], float in_multiply_factor);
IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned char table[256], unsigned char* pixels, int x, int y, int w, int h, int stride);
-// Test engine hooks (imgui-test)
+// Debug Tools
+// Use 'Metrics->Tools->Item Picker' to break into the call-stack of a specific item.
+#ifndef IM_DEBUG_BREAK
+#if defined(__clang__)
+#define IM_DEBUG_BREAK() __builtin_debugtrap()
+#elif defined (_MSC_VER)
+#define IM_DEBUG_BREAK() __debugbreak()
+#else
+#define IM_DEBUG_BREAK() IM_ASSERT(0) // It is expected that you define IM_DEBUG_BREAK() into something that will break nicely in a debugger!
+#endif
+#endif // #ifndef IM_DEBUG_BREAK
+
+// Test Engine Hooks (imgui_tests)
//#define IMGUI_ENABLE_TEST_ENGINE
#ifdef IMGUI_ENABLE_TEST_ENGINE
extern void ImGuiTestEngineHook_PreNewFrame(ImGuiContext* ctx);
diff --git a/imgui/imgui_widgets.cpp b/imgui/imgui_widgets.cpp
index 698809b0..f06dec60 100644
--- a/imgui/imgui_widgets.cpp
+++ b/imgui/imgui_widgets.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.71
+// dear imgui, v1.72
// (widgets code)
/*
@@ -24,6 +24,7 @@ Index of this file:
// [SECTION] Widgets: MenuItem, BeginMenu, EndMenu, etc.
// [SECTION] Widgets: BeginTabBar, EndTabBar, etc.
// [SECTION] Widgets: BeginTabItem, EndTabItem, etc.
+// [SECTION] Widgets: Columns, BeginColumns, EndColumns, etc.
*/
@@ -63,10 +64,9 @@ Index of this file:
#pragma clang diagnostic ignored "-Wdouble-promotion" // warning: implicit conversion from 'float' to 'double' when passing argument to function // using printf() is a misery with this as C++ va_arg ellipsis changes float to double.
#endif
#elif defined(__GNUC__)
+#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
#pragma GCC diagnostic ignored "-Wformat-nonliteral" // warning: format not a string literal, format string not checked
-#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
+#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
#endif
//-------------------------------------------------------------------------
@@ -626,8 +626,6 @@ bool ImGui::ButtonEx(const char* label, const ImVec2& size_arg, ImGuiButtonFlags
flags |= ImGuiButtonFlags_Repeat;
bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, flags);
- if (pressed)
- MarkItemEdited(id);
// Render
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_ButtonActive : hovered ? ImGuiCol_ButtonHovered : ImGuiCol_Button);
@@ -896,13 +894,13 @@ void ImGui::Scrollbar(ImGuiAxis axis)
ImRect bb;
if (axis == ImGuiAxis_X)
{
- bb.Min = ImVec2(inner_rect.Min.x, outer_rect.Max.y - border_size - scrollbar_size);
+ bb.Min = ImVec2(inner_rect.Min.x, ImMax(outer_rect.Min.y, 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.Min = ImVec2(ImMax(outer_rect.Min.x, 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;
}
@@ -1002,10 +1000,17 @@ bool ImGui::Checkbox(const char* label, bool* v)
const ImRect check_bb(pos, pos + ImVec2(square_sz, square_sz));
RenderNavHighlight(total_bb, id);
RenderFrame(check_bb.Min, check_bb.Max, GetColorU32((held && hovered) ? ImGuiCol_FrameBgActive : hovered ? ImGuiCol_FrameBgHovered : ImGuiCol_FrameBg), true, style.FrameRounding);
- if (*v)
+ ImU32 check_col = GetColorU32(ImGuiCol_CheckMark);
+ if (window->DC.ItemFlags & ImGuiItemFlags_MixedValue)
+ {
+ // Undocumented tristate/mixed/indeterminate checkbox (#2644)
+ ImVec2 pad(ImMax(1.0f, (float)(int)(square_sz / 3.6f)), ImMax(1.0f, (float)(int)(square_sz / 3.6f)));
+ window->DrawList->AddRectFilled(check_bb.Min + pad, check_bb.Max - pad, check_col, style.FrameRounding);
+ }
+ else if (*v)
{
const float pad = ImMax(1.0f, (float)(int)(square_sz / 6.0f));
- RenderCheckMark(check_bb.Min + ImVec2(pad, pad), GetColorU32(ImGuiCol_CheckMark), square_sz - pad*2.0f);
+ RenderCheckMark(check_bb.Min + ImVec2(pad, pad), check_col, square_sz - pad*2.0f);
}
if (g.LogEnabled)
@@ -1083,6 +1088,7 @@ bool ImGui::RadioButton(const char* label, bool active)
return pressed;
}
+// FIXME: This would work nicely if it was a public template, e.g. 'template<T> RadioButton(const char* label, T* v, T v_button)', but I'm not sure how we would expose it..
bool ImGui::RadioButton(const char* label, int* v, int v_button)
{
const bool pressed = RadioButton(label, *v == v_button);
@@ -1426,7 +1432,8 @@ bool ImGui::BeginCombo(const char* label, const char* preview_value, ImGuiComboF
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);
+ if (value_x2 + arrow_size - style.FramePadding.x <= frame_bb.Max.x)
+ RenderArrow(window->DrawList, ImVec2(value_x2 + style.FramePadding.y, frame_bb.Min.y + style.FramePadding.y), text_col, ImGuiDir_Down, 1.0f);
}
RenderFrameBorder(frame_bb.Min, frame_bb.Max, style.FrameRounding);
if (preview_value != NULL && !(flags & ImGuiComboFlags_NoPreview))
@@ -3631,8 +3638,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
if (IsKeyPressedMap(ImGuiKey_LeftArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINESTART : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDLEFT : STB_TEXTEDIT_K_LEFT) | k_mask); }
else if (IsKeyPressedMap(ImGuiKey_RightArrow)) { state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_LINEEND : is_wordmove_key_down ? STB_TEXTEDIT_K_WORDRIGHT : STB_TEXTEDIT_K_RIGHT) | k_mask); }
- else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); }
- else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetWindowScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); }
+ else if (IsKeyPressedMap(ImGuiKey_UpArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMax(draw_window->Scroll.y - g.FontSize, 0.0f)); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTSTART : STB_TEXTEDIT_K_UP) | k_mask); }
+ else if (IsKeyPressedMap(ImGuiKey_DownArrow) && is_multiline) { if (io.KeyCtrl) SetScrollY(draw_window, ImMin(draw_window->Scroll.y + g.FontSize, GetScrollMaxY())); else state->OnKeyPressed((is_startend_key_down ? STB_TEXTEDIT_K_TEXTEND : STB_TEXTEDIT_K_DOWN) | k_mask); }
else if (IsKeyPressedMap(ImGuiKey_Home)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTSTART | k_mask : STB_TEXTEDIT_K_LINESTART | k_mask); }
else if (IsKeyPressedMap(ImGuiKey_End)) { state->OnKeyPressed(io.KeyCtrl ? STB_TEXTEDIT_K_TEXTEND | k_mask : STB_TEXTEDIT_K_LINEEND | k_mask); }
else if (IsKeyPressedMap(ImGuiKey_Delete) && !is_readonly) { state->OnKeyPressed(STB_TEXTEDIT_K_DELETE | k_mask); }
@@ -3647,7 +3654,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
}
state->OnKeyPressed(STB_TEXTEDIT_K_BACKSPACE | k_mask);
}
- else if (IsKeyPressedMap(ImGuiKey_Enter))
+ else if (IsKeyPressedMap(ImGuiKey_Enter) || IsKeyPressedMap(ImGuiKey_KeyPadEnter))
{
bool ctrl_enter_for_new_line = (flags & ImGuiInputTextFlags_CtrlEnterForNewLine) != 0;
if (!is_multiline || (ctrl_enter_for_new_line && !io.KeyCtrl) || (!ctrl_enter_for_new_line && io.KeyCtrl))
@@ -3987,9 +3994,8 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
scroll_y = ImMax(0.0f, cursor_offset.y - g.FontSize);
else if (cursor_offset.y - size.y >= scroll_y)
scroll_y = cursor_offset.y - size.y;
- draw_window->DC.CursorPos.y += (draw_window->Scroll.y - scroll_y); // Manipulate cursor pos immediately avoid a frame of lag
+ draw_pos.y += (draw_window->Scroll.y - scroll_y); // Manipulate cursor pos immediately avoid a frame of lag
draw_window->Scroll.y = scroll_y;
- draw_pos.y = draw_window->DC.CursorPos.y;
}
state->CursorFollow = false;
@@ -4130,8 +4136,9 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
ImGuiContext& g = *GImGui;
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 = CalcItemWidth() - w_extra;
+ const float w_full = CalcItemWidth();
+ const float w_button = (flags & ImGuiColorEditFlags_NoSmallPreview) ? 0.0f : (square_sz + style.ItemInnerSpacing.x);
+ const float w_inputs = w_full - w_button;
const char* label_display_end = FindRenderedTextEnd(label);
g.NextItemData.ClearFlags();
@@ -4175,11 +4182,15 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
bool value_changed = false;
bool value_changed_as_float = false;
+ const ImVec2 pos = window->DC.CursorPos;
+ const float inputs_offset_x = (style.ColorButtonPosition == ImGuiDir_Left) ? w_button : 0.0f;
+ window->DC.CursorPos.x = pos.x + inputs_offset_x;
+
if ((flags & (ImGuiColorEditFlags_DisplayRGB | ImGuiColorEditFlags_DisplayHSV)) != 0 && (flags & ImGuiColorEditFlags_NoInputs) == 0)
{
// RGB/HSV 0..255 Sliders
- const float w_item_one = ImMax(1.0f, (float)(int)((w_items_all - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
- const float w_item_last = ImMax(1.0f, (float)(int)(w_items_all - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
+ const float w_item_one = ImMax(1.0f, (float)(int)((w_inputs - (style.ItemInnerSpacing.x) * (components-1)) / (float)components));
+ const float w_item_last = ImMax(1.0f, (float)(int)(w_inputs - (w_item_one + style.ItemInnerSpacing.x) * (components-1)));
const bool hide_prefix = (w_item_one <= CalcTextSize((flags & ImGuiColorEditFlags_Float) ? "M:0.000" : "M:000").x);
static const char* ids[4] = { "##X", "##Y", "##Z", "##W" };
@@ -4223,7 +4234,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X%02X", ImClamp(i[0],0,255), ImClamp(i[1],0,255), ImClamp(i[2],0,255), ImClamp(i[3],0,255));
else
ImFormatString(buf, IM_ARRAYSIZE(buf), "#%02X%02X%02X", ImClamp(i[0],0,255), ImClamp(i[1],0,255), ImClamp(i[2],0,255));
- SetNextItemWidth(w_items_all);
+ SetNextItemWidth(w_inputs);
if (InputText("##Text", buf, IM_ARRAYSIZE(buf), ImGuiInputTextFlags_CharsHexadecimal | ImGuiInputTextFlags_CharsUppercase))
{
value_changed = true;
@@ -4243,8 +4254,8 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
ImGuiWindow* picker_active_window = NULL;
if (!(flags & ImGuiColorEditFlags_NoSmallPreview))
{
- if (!(flags & ImGuiColorEditFlags_NoInputs))
- SameLine(0, style.ItemInnerSpacing.x);
+ const float button_offset_x = ((flags & ImGuiColorEditFlags_NoInputs) || (style.ColorButtonPosition == ImGuiDir_Left)) ? 0.0f : w_inputs + style.ItemInnerSpacing.x;
+ window->DC.CursorPos = ImVec2(pos.x + button_offset_x, pos.y);
const ImVec4 col_v4(col[0], col[1], col[2], alpha ? col[3] : 1.0f);
if (ColorButton("##ColorButton", col_v4, flags))
@@ -4278,7 +4289,7 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
if (label != label_display_end && !(flags & ImGuiColorEditFlags_NoLabel))
{
- SameLine(0, style.ItemInnerSpacing.x);
+ window->DC.CursorPos = ImVec2(pos.x + w_full + style.ItemInnerSpacing.x, pos.y + style.FramePadding.y);
TextEx(label, label_display_end);
}
@@ -4827,9 +4838,6 @@ bool ImGui::ColorButton(const char* desc_id, const ImVec4& col, ImGuiColorEditFl
if (!(flags & ImGuiColorEditFlags_NoTooltip) && hovered)
ColorTooltip(desc_id, &col.x, flags & (ImGuiColorEditFlags__InputMask | ImGuiColorEditFlags_NoAlpha | ImGuiColorEditFlags_AlphaPreview | ImGuiColorEditFlags_AlphaPreviewHalf));
- if (pressed)
- MarkItemEdited(id);
-
return pressed;
}
@@ -4983,7 +4991,6 @@ void ImGui::ColorPickerOptionsPopup(const float* ref_col, ImGuiColorEditFlags fl
// - TreeNodeBehavior() [Internal]
// - TreePush()
// - TreePop()
-// - TreeAdvanceToLabelPos()
// - GetTreeNodeToLabelSpacing()
// - SetNextItemOpen()
// - CollapsingHeader()
@@ -5231,13 +5238,13 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledSelection;
// Render
- 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
+ const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, true, style.FrameRounding);
RenderNavHighlight(frame_bb, id, nav_highlight_flags);
RenderArrow(window->DrawList, frame_bb.Min + ImVec2(padding.x, text_base_offset_y), text_col, is_open ? ImGuiDir_Down : ImGuiDir_Right, 1.0f);
@@ -5262,6 +5269,7 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
// Unframed typed for tree nodes
if (hovered || selected)
{
+ const ImU32 bg_col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false);
RenderNavHighlight(frame_bb, id, nav_highlight_flags);
}
@@ -5324,12 +5332,6 @@ void ImGui::TreePop()
PopID();
}
-void ImGui::TreeAdvanceToLabelPos()
-{
- ImGuiContext& g = *GImGui;
- g.CurrentWindow->DC.CursorPos.x += GetTreeNodeToLabelSpacing();
-}
-
// Horizontal distance preceding label when using TreeNode() or Bullet()
float ImGui::GetTreeNodeToLabelSpacing()
{
@@ -5488,6 +5490,8 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_ToggledSelection;
// Render
+ if (held && (flags & ImGuiSelectableFlags_DrawHoveredWhenHeld))
+ hovered = true;
if (hovered || selected)
{
const ImU32 col = GetColorU32((held && hovered) ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
@@ -5931,6 +5935,10 @@ void ImGui::EndMainMenuBar()
End();
}
+// FIXME: Provided a rectangle perhaps e.g. a BeginMenuBarEx() could be used anywhere..
+// Currently the main responsibility of this function being to setup clip-rect + horizontal layout + menu navigation layer.
+// Ideally we also want this to be responsible for claiming space out of the main window scrolling rectangle, in which case ImGuiWindowFlags_MenuBar will become unnecessary.
+// Then later the same system could be used for multiple menu-bars, scrollbars, side-bars.
bool ImGui::BeginMenuBar()
{
ImGuiWindow* window = GetCurrentWindow();
@@ -5940,7 +5948,7 @@ bool ImGui::BeginMenuBar()
return false;
IM_ASSERT(!window->DC.MenuBarAppending);
- BeginGroup(); // Backup position on layer 0
+ BeginGroup(); // Backup position on layer 0 // FIXME: Misleading to use a group for that backup/restore
PushID("##menubar");
// We don't clip with current window clipping rectangle as it is already set to the area below. However we clip with window full rect.
@@ -6269,18 +6277,18 @@ static int IMGUI_CDECL TabItemComparerByVisibleOffset(const void* lhs, const voi
return (int)(a->Offset - b->Offset);
}
-static ImGuiTabBar* GetTabBarFromTabBarRef(const ImGuiTabBarRef& ref)
+static ImGuiTabBar* GetTabBarFromTabBarRef(const ImGuiPtrOrIndex& ref)
{
ImGuiContext& g = *GImGui;
- return ref.Ptr ? ref.Ptr : g.TabBars.GetByIndex(ref.IndexInMainPool);
+ return ref.Ptr ? (ImGuiTabBar*)ref.Ptr : g.TabBars.GetByIndex(ref.Index);
}
-static ImGuiTabBarRef GetTabBarRefFromTabBar(ImGuiTabBar* tab_bar)
+static ImGuiPtrOrIndex GetTabBarRefFromTabBar(ImGuiTabBar* tab_bar)
{
ImGuiContext& g = *GImGui;
if (g.TabBars.Contains(tab_bar))
- return ImGuiTabBarRef(g.TabBars.GetIndex(tab_bar));
- return ImGuiTabBarRef(tab_bar);
+ return ImGuiPtrOrIndex(g.TabBars.GetIndex(tab_bar));
+ return ImGuiPtrOrIndex(tab_bar);
}
bool ImGui::BeginTabBar(const char* str_id, ImGuiTabBarFlags flags)
@@ -6339,7 +6347,7 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
window->DC.CursorPos.x = tab_bar->BarRect.Min.x;
// Draw separator
- const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_Tab);
+ const ImU32 col = GetColorU32((flags & ImGuiTabBarFlags_IsFocused) ? ImGuiCol_TabActive : ImGuiCol_TabUnfocusedActive);
const float y = tab_bar->BarRect.Max.y - 1.0f;
{
const float separator_min_x = tab_bar->BarRect.Min.x - ImFloor(window->WindowPadding.x * 0.5f);
@@ -6635,7 +6643,7 @@ void ImGui::TabBarQueueChangeTabOrder(ImGuiTabBar* tab_bar, const ImGuiTabItem*
IM_ASSERT(dir == -1 || dir == +1);
IM_ASSERT(tab_bar->ReorderRequestTabId == 0);
tab_bar->ReorderRequestTabId = tab->ID;
- tab_bar->ReorderRequestDir = dir;
+ tab_bar->ReorderRequestDir = (ImS8)dir;
}
static ImGuiTabItem* ImGui::TabBarScrollingButtons(ImGuiTabBar* tab_bar)
@@ -7082,3 +7090,425 @@ bool ImGui::TabItemLabelAndCloseButton(ImDrawList* draw_list, const ImRect& bb,
return close_button_pressed;
}
+
+
+//-------------------------------------------------------------------------
+// [SECTION] Widgets: Columns, BeginColumns, EndColumns, etc.
+// In the current version, Columns are very weak. Needs to be replaced with a more full-featured system.
+//-------------------------------------------------------------------------
+// - GetColumnIndex()
+// - GetColumnCount()
+// - GetColumnOffset()
+// - GetColumnWidth()
+// - SetColumnOffset()
+// - SetColumnWidth()
+// - PushColumnClipRect() [Internal]
+// - PushColumnsBackground() [Internal]
+// - PopColumnsBackground() [Internal]
+// - FindOrCreateColumns() [Internal]
+// - GetColumnsID() [Internal]
+// - BeginColumns()
+// - NextColumn()
+// - EndColumns()
+// - Columns()
+//-------------------------------------------------------------------------
+
+int ImGui::GetColumnIndex()
+{
+ ImGuiWindow* window = GetCurrentWindowRead();
+ return window->DC.CurrentColumns ? window->DC.CurrentColumns->Current : 0;
+}
+
+int ImGui::GetColumnsCount()
+{
+ ImGuiWindow* window = GetCurrentWindowRead();
+ return window->DC.CurrentColumns ? window->DC.CurrentColumns->Count : 1;
+}
+
+float ImGui::GetColumnOffsetFromNorm(const ImGuiColumns* columns, float offset_norm)
+{
+ return offset_norm * (columns->OffMaxX - columns->OffMinX);
+}
+
+float ImGui::GetColumnNormFromOffset(const ImGuiColumns* columns, float offset)
+{
+ return offset / (columns->OffMaxX - columns->OffMinX);
+}
+
+static const float COLUMNS_HIT_RECT_HALF_WIDTH = 4.0f;
+
+static float GetDraggedColumnOffset(ImGuiColumns* columns, int column_index)
+{
+ // Active (dragged) column always follow mouse. The reason we need this is that dragging a column to the right edge of an auto-resizing
+ // window creates a feedback loop because we store normalized positions. So while dragging we enforce absolute positioning.
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
+ IM_ASSERT(column_index > 0); // We are not supposed to drag column 0.
+ IM_ASSERT(g.ActiveId == columns->ID + ImGuiID(column_index));
+
+ float x = g.IO.MousePos.x - g.ActiveIdClickOffset.x + COLUMNS_HIT_RECT_HALF_WIDTH - window->Pos.x;
+ x = ImMax(x, ImGui::GetColumnOffset(column_index - 1) + g.Style.ColumnsMinSpacing);
+ if ((columns->Flags & ImGuiColumnsFlags_NoPreserveWidths))
+ x = ImMin(x, ImGui::GetColumnOffset(column_index + 1) - g.Style.ColumnsMinSpacing);
+
+ return x;
+}
+
+float ImGui::GetColumnOffset(int column_index)
+{
+ ImGuiWindow* window = GetCurrentWindowRead();
+ ImGuiColumns* columns = window->DC.CurrentColumns;
+ if (columns == NULL)
+ return 0.0f;
+
+ if (column_index < 0)
+ column_index = columns->Current;
+ IM_ASSERT(column_index < columns->Columns.Size);
+
+ const float t = columns->Columns[column_index].OffsetNorm;
+ const float x_offset = ImLerp(columns->OffMinX, columns->OffMaxX, t);
+ return x_offset;
+}
+
+static float GetColumnWidthEx(ImGuiColumns* columns, int column_index, bool before_resize = false)
+{
+ if (column_index < 0)
+ column_index = columns->Current;
+
+ float offset_norm;
+ if (before_resize)
+ offset_norm = columns->Columns[column_index + 1].OffsetNormBeforeResize - columns->Columns[column_index].OffsetNormBeforeResize;
+ else
+ offset_norm = columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm;
+ return ImGui::GetColumnOffsetFromNorm(columns, offset_norm);
+}
+
+float ImGui::GetColumnWidth(int column_index)
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
+ ImGuiColumns* columns = window->DC.CurrentColumns;
+ if (columns == NULL)
+ return GetContentRegionAvail().x;
+
+ if (column_index < 0)
+ column_index = columns->Current;
+ return GetColumnOffsetFromNorm(columns, columns->Columns[column_index + 1].OffsetNorm - columns->Columns[column_index].OffsetNorm);
+}
+
+void ImGui::SetColumnOffset(int column_index, float offset)
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = g.CurrentWindow;
+ ImGuiColumns* columns = window->DC.CurrentColumns;
+ IM_ASSERT(columns != NULL);
+
+ if (column_index < 0)
+ column_index = columns->Current;
+ IM_ASSERT(column_index < columns->Columns.Size);
+
+ const bool preserve_width = !(columns->Flags & ImGuiColumnsFlags_NoPreserveWidths) && (column_index < columns->Count-1);
+ const float width = preserve_width ? GetColumnWidthEx(columns, column_index, columns->IsBeingResized) : 0.0f;
+
+ if (!(columns->Flags & ImGuiColumnsFlags_NoForceWithinWindow))
+ offset = ImMin(offset, columns->OffMaxX - g.Style.ColumnsMinSpacing * (columns->Count - column_index));
+ columns->Columns[column_index].OffsetNorm = GetColumnNormFromOffset(columns, offset - columns->OffMinX);
+
+ if (preserve_width)
+ SetColumnOffset(column_index + 1, offset + ImMax(g.Style.ColumnsMinSpacing, width));
+}
+
+void ImGui::SetColumnWidth(int column_index, float width)
+{
+ ImGuiWindow* window = GetCurrentWindowRead();
+ ImGuiColumns* columns = window->DC.CurrentColumns;
+ IM_ASSERT(columns != NULL);
+
+ if (column_index < 0)
+ column_index = columns->Current;
+ SetColumnOffset(column_index + 1, GetColumnOffset(column_index) + width);
+}
+
+void ImGui::PushColumnClipRect(int column_index)
+{
+ ImGuiWindow* window = GetCurrentWindowRead();
+ ImGuiColumns* columns = window->DC.CurrentColumns;
+ if (column_index < 0)
+ column_index = columns->Current;
+
+ ImGuiColumnData* column = &columns->Columns[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;
+ if (columns->Count == 1)
+ return;
+ 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;
+ if (columns->Count == 1)
+ return;
+ 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.
+ for (int n = 0; n < window->ColumnsStorage.Size; n++)
+ if (window->ColumnsStorage[n].ID == id)
+ return &window->ColumnsStorage[n];
+
+ window->ColumnsStorage.push_back(ImGuiColumns());
+ ImGuiColumns* columns = &window->ColumnsStorage.back();
+ columns->ID = id;
+ return columns;
+}
+
+ImGuiID ImGui::GetColumnsID(const char* str_id, int columns_count)
+{
+ ImGuiWindow* window = GetCurrentWindow();
+
+ // Differentiate column ID with an arbitrary prefix for cases where users name their columns set the same as another widget.
+ // In addition, when an identifier isn't explicitly provided we include the number of columns in the hash to make it uniquer.
+ PushID(0x11223347 + (str_id ? 0 : columns_count));
+ ImGuiID id = window->GetID(str_id ? str_id : "columns");
+ PopID();
+
+ return id;
+}
+
+void ImGui::BeginColumns(const char* str_id, int columns_count, ImGuiColumnsFlags flags)
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = GetCurrentWindow();
+
+ IM_ASSERT(columns_count >= 1);
+ IM_ASSERT(window->DC.CurrentColumns == NULL); // Nested columns are currently not supported
+
+ // 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;
+ columns->Count = columns_count;
+ columns->Flags = flags;
+ window->DC.CurrentColumns = columns;
+
+ columns->HostCursorPosY = window->DC.CursorPos.y;
+ columns->HostCursorMaxPosX = window->DC.CursorMaxPos.x;
+ columns->HostClipRect = window->ClipRect;
+ columns->HostWorkRect = window->WorkRect;
+
+ // Set state for first column
+ // We aim so that the right-most column will have the same clipping width as other after being clipped by parent ClipRect
+ const float column_padding = g.Style.ItemSpacing.x;
+ const float half_clip_extend_x = ImFloor(ImMax(window->WindowPadding.x * 0.5f, window->WindowBorderSize));
+ const float max_1 = window->WorkRect.Max.x + column_padding - ImMax(column_padding - window->WindowPadding.x, 0.0f);
+ const float max_2 = window->WorkRect.Max.x + half_clip_extend_x;
+ columns->OffMinX = window->DC.Indent.x - column_padding + ImMax(column_padding - window->WindowPadding.x, 0.0f);
+ columns->OffMaxX = ImMax(ImMin(max_1, max_2) - window->Pos.x, columns->OffMinX + 1.0f);
+ columns->LineMinY = columns->LineMaxY = window->DC.CursorPos.y;
+
+ // Clear data if columns count changed
+ if (columns->Columns.Size != 0 && columns->Columns.Size != columns_count + 1)
+ columns->Columns.resize(0);
+
+ // Initialize default widths
+ columns->IsFirstFrame = (columns->Columns.Size == 0);
+ if (columns->Columns.Size == 0)
+ {
+ columns->Columns.reserve(columns_count + 1);
+ for (int n = 0; n < columns_count + 1; n++)
+ {
+ ImGuiColumnData column;
+ column.OffsetNorm = n / (float)columns_count;
+ columns->Columns.push_back(column);
+ }
+ }
+
+ for (int n = 0; n < columns_count; n++)
+ {
+ // Compute clipping rectangle
+ ImGuiColumnData* column = &columns->Columns[n];
+ float clip_x1 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n));
+ float clip_x2 = ImFloor(0.5f + window->Pos.x + GetColumnOffset(n + 1) - 1.0f);
+ column->ClipRect = ImRect(clip_x1, -FLT_MAX, clip_x2, +FLT_MAX);
+ column->ClipRect.ClipWith(window->ClipRect);
+ }
+
+ if (columns->Count > 1)
+ {
+ window->DrawList->ChannelsSplit(1 + columns->Count);
+ window->DrawList->ChannelsSetCurrent(1);
+ PushColumnClipRect(0);
+ }
+
+ // We don't generally store Indent.x inside ColumnsOffset because it may be manipulated by the user.
+ float offset_0 = GetColumnOffset(columns->Current);
+ float offset_1 = GetColumnOffset(columns->Current + 1);
+ float width = offset_1 - offset_0;
+ PushItemWidth(width * 0.65f);
+ window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f);
+ window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
+ window->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding;
+}
+
+void ImGui::NextColumn()
+{
+ ImGuiWindow* window = GetCurrentWindow();
+ if (window->SkipItems || window->DC.CurrentColumns == NULL)
+ return;
+
+ ImGuiContext& g = *GImGui;
+ ImGuiColumns* columns = window->DC.CurrentColumns;
+
+ if (columns->Count == 1)
+ {
+ window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
+ IM_ASSERT(columns->Current == 0);
+ return;
+ }
+ PopItemWidth();
+ PopClipRect();
+
+ const float column_padding = g.Style.ItemSpacing.x;
+ columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y);
+ if (++columns->Current < columns->Count)
+ {
+ // Columns 1+ ignore IndentX (by canceling it out)
+ // FIXME-COLUMNS: Unnecessary, could be locked?
+ window->DC.ColumnsOffset.x = GetColumnOffset(columns->Current) - window->DC.Indent.x + column_padding;
+ window->DrawList->ChannelsSetCurrent(columns->Current + 1);
+ }
+ else
+ {
+ // New row/line
+ // Column 0 honor IndentX
+ window->DC.ColumnsOffset.x = ImMax(column_padding - window->WindowPadding.x, 0.0f);
+ 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.CurrLineSize = ImVec2(0.0f, 0.0f);
+ window->DC.CurrLineTextBaseOffset = 0.0f;
+
+ PushColumnClipRect(columns->Current); // FIXME-COLUMNS: Could it be an overwrite?
+
+ // FIXME-COLUMNS: Share code with BeginColumns() - move code on columns setup.
+ float offset_0 = GetColumnOffset(columns->Current);
+ float offset_1 = GetColumnOffset(columns->Current + 1);
+ float width = offset_1 - offset_0;
+ PushItemWidth(width * 0.65f);
+ window->WorkRect.Max.x = window->Pos.x + offset_1 - column_padding;
+}
+
+void ImGui::EndColumns()
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiWindow* window = GetCurrentWindow();
+ ImGuiColumns* columns = window->DC.CurrentColumns;
+ IM_ASSERT(columns != NULL);
+
+ PopItemWidth();
+ if (columns->Count > 1)
+ {
+ PopClipRect();
+ window->DrawList->ChannelsMerge();
+ }
+
+ const ImGuiColumnsFlags flags = columns->Flags;
+ columns->LineMaxY = ImMax(columns->LineMaxY, window->DC.CursorPos.y);
+ window->DC.CursorPos.y = columns->LineMaxY;
+ 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 (!(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->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++)
+ {
+ ImGuiColumnData* column = &columns->Columns[n];
+ float x = window->Pos.x + GetColumnOffset(n);
+ const ImGuiID column_id = columns->ID + ImGuiID(n);
+ const float column_hit_hw = COLUMNS_HIT_RECT_HALF_WIDTH;
+ const ImRect column_hit_rect(ImVec2(x - column_hit_hw, y1), ImVec2(x + column_hit_hw, y2));
+ KeepAliveID(column_id);
+ if (IsClippedEx(column_hit_rect, column_id, false))
+ continue;
+
+ bool hovered = false, held = false;
+ if (!(flags & ImGuiColumnsFlags_NoResize))
+ {
+ ButtonBehavior(column_hit_rect, column_id, &hovered, &held);
+ if (hovered || held)
+ g.MouseCursor = ImGuiMouseCursor_ResizeEW;
+ if (held && !(column->Flags & ImGuiColumnsFlags_NoResize))
+ dragging_column = n;
+ }
+
+ // Draw column
+ const ImU32 col = GetColorU32(held ? ImGuiCol_SeparatorActive : hovered ? ImGuiCol_SeparatorHovered : ImGuiCol_Separator);
+ const float xi = (float)(int)x;
+ window->DrawList->AddLine(ImVec2(xi, y1 + 1.0f), ImVec2(xi, y2), col);
+ }
+
+ // Apply dragging after drawing the column lines, so our rendered lines are in sync with how items were displayed during the frame.
+ if (dragging_column != -1)
+ {
+ if (!columns->IsBeingResized)
+ for (int n = 0; n < columns->Count + 1; n++)
+ columns->Columns[n].OffsetNormBeforeResize = columns->Columns[n].OffsetNorm;
+ columns->IsBeingResized = is_being_resized = true;
+ float x = GetDraggedColumnOffset(columns, dragging_column);
+ SetColumnOffset(dragging_column, x);
+ }
+ }
+ columns->IsBeingResized = is_being_resized;
+
+ window->WorkRect = columns->HostWorkRect;
+ window->DC.CurrentColumns = NULL;
+ window->DC.ColumnsOffset.x = 0.0f;
+ window->DC.CursorPos.x = (float)(int)(window->Pos.x + window->DC.Indent.x + window->DC.ColumnsOffset.x);
+}
+
+// [2018-03: This is currently the only public API, while we are working on making BeginColumns/EndColumns user-facing]
+void ImGui::Columns(int columns_count, const char* id, bool border)
+{
+ ImGuiWindow* window = GetCurrentWindow();
+ IM_ASSERT(columns_count >= 1);
+
+ ImGuiColumnsFlags flags = (border ? 0 : ImGuiColumnsFlags_NoBorder);
+ //flags |= ImGuiColumnsFlags_NoPreserveWidths; // NB: Legacy behavior
+ ImGuiColumns* columns = window->DC.CurrentColumns;
+ if (columns != NULL && columns->Count == columns_count && columns->Flags == flags)
+ return;
+
+ if (columns != NULL)
+ EndColumns();
+
+ if (columns_count != 1)
+ BeginColumns(id, columns_count, flags);
+}
+
+//-------------------------------------------------------------------------