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-09-25 00:32:03 +0300
committerBartosz Taudul <wolf.pld@gmail.com>2019-09-25 00:32:03 +0300
commite7578777c3c1221c13fd9035a28247cd8b48ee6c (patch)
tree9c5d2de4d7c4740e6597279edb1fd49fd3f1d1d7 /imgui
parent63184f876274d4402f18fd5b1c82b0da916abf32 (diff)
Update ImGui to 1.73.
Diffstat (limited to 'imgui')
-rw-r--r--imgui/imconfig.h6
-rw-r--r--imgui/imgui.cpp375
-rw-r--r--imgui/imgui.h85
-rw-r--r--imgui/imgui_demo.cpp141
-rw-r--r--imgui/imgui_draw.cpp157
-rw-r--r--imgui/imgui_internal.h88
-rw-r--r--imgui/imgui_widgets.cpp285
-rw-r--r--imgui/imstb_rectpack.h17
8 files changed, 722 insertions, 432 deletions
diff --git a/imgui/imconfig.h b/imgui/imconfig.h
index 78d38d27..3c88b3af 100644
--- a/imgui/imconfig.h
+++ b/imgui/imconfig.h
@@ -17,7 +17,7 @@
//#define IM_ASSERT(_EXPR) MyAssert(_EXPR)
//#define IM_ASSERT(_EXPR) ((void)(_EXPR)) // Disable asserts
-//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
+//---- Define attributes of all API symbols declarations, e.g. for DLL under Windows
// Using dear imgui via a shared library is not recommended, because of function call overhead and because we don't guarantee backward nor forward ABI compatibility.
//#define IMGUI_API __declspec( dllexport )
//#define IMGUI_API __declspec( dllimport )
@@ -64,9 +64,9 @@
operator MyVec4() const { return MyVec4(x,y,z,w); }
*/
-//---- Using 32-bits vertex indices (default is 16-bits) is one way to allow large meshes with more than 64K vertices.
+//---- Using 32-bits vertex indices (default is 16-bits) is one way to allow large meshes with more than 64K vertices.
// Your renderer back-end will need to support it (most example renderer back-ends support both 16/32-bits indices).
-// Another way to allow large meshes while keeping 16-bits indices is to handle ImDrawCmd::VtxOffset in your renderer.
+// Another way to allow large meshes while keeping 16-bits indices is to handle ImDrawCmd::VtxOffset in your renderer.
// Read about ImGuiBackendFlags_RendererHasVtxOffset for details.
#define ImDrawIdx unsigned int
diff --git a/imgui/imgui.cpp b/imgui/imgui.cpp
index 6e6da3b1..93b15ddb 100644
--- a/imgui/imgui.cpp
+++ b/imgui/imgui.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.72b
+// dear imgui, v1.73
// (main code and documentation)
// Call and read ImGui::ShowDemoWindow() in imgui_demo.cpp for demo code.
@@ -176,7 +176,7 @@ CODE
- When using Dear ImGui, your programming IDE is your friend: follow the declaration of variables, functions and types to find comments about them.
- Dear ImGui never touches or knows about your GPU state. The only function that knows about GPU is the draw function that you provide.
Effectively it means you can create widgets at any time in your code, regardless of considerations of being in "update" vs "render"
- phases of your own application. All rendering informatioe are stored into command-lists that you will retrieve after calling ImGui::Render().
+ phases of your own application. All rendering information are stored into command-lists that you will retrieve after calling ImGui::Render().
- Refer to the bindings and demo applications in the examples/ folder for instruction on how to setup your code.
- If you are running over a standard OS with a common graphics API, you should be able to use unmodified imgui_impl_*** files from the examples/ folder.
@@ -575,17 +575,17 @@ CODE
Q: Where is the documentation?
A: This library is poorly documented at the moment and expects of the user to be acquainted with C/C++.
- Run the examples/ and explore them.
- - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
- - The demo covers most features of Dear ImGui, so you can read the code and see its output.
+ - See demo code in imgui_demo.cpp and particularly the ImGui::ShowDemoWindow() function.
+ - The demo covers most features of Dear ImGui, so you can read the code and see its output.
- See documentation and comments at the top of imgui.cpp + effectively imgui.h.
- - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/
+ - Dozens of standalone example applications using e.g. OpenGL/DirectX are provided in the examples/
folder to explain how to integrate Dear ImGui with your own engine/application.
- - Your programming IDE is your friend, find the type or function declaration to find comments
+ - Your programming IDE is your friend, find the type or function declaration to find comments
associated to it.
Q: Which version should I get?
- A: I occasionally tag Releases (https://github.com/ocornut/imgui/releases) but it is generally safe
- and recommended to sync to master/latest. The library is fairly stable and regressions tend to be
+ A: I occasionally tag Releases (https://github.com/ocornut/imgui/releases) but it is generally safe
+ and recommended to sync to master/latest. The library is fairly stable and regressions tend to be
fixed fast when reported. You may also peak at the 'docking' branch which includes:
- Docking/Merging features (https://github.com/ocornut/imgui/issues/2109)
- Multi-viewport features (https://github.com/ocornut/imgui/issues/1542)
@@ -597,11 +597,11 @@ CODE
for a list of games/software which are publicly known to use dear imgui. Please add yours if you can!
Q: Why the odd dual naming, "Dear ImGui" vs "ImGui"?
- A: The library started its life as "ImGui" due to the fact that I didn't give it a proper name when
- when I released 1.0, and had no particular expectation that it would take off. However, the term IMGUI
- (immediate-mode graphical user interface) was coined before and is being used in variety of other
- situations (e.g. Unity uses it own implementation of the IMGUI paradigm).
- To reduce the ambiguity without affecting existing code bases, I have decided on an alternate,
+ A: The library started its life as "ImGui" due to the fact that I didn't give it a proper name when
+ when I released 1.0, and had no particular expectation that it would take off. However, the term IMGUI
+ (immediate-mode graphical user interface) was coined before and is being used in variety of other
+ situations (e.g. Unity uses it own implementation of the IMGUI paradigm).
+ To reduce the ambiguity without affecting existing code bases, I have decided on an alternate,
longer name "Dear ImGui" that people can use to refer to this specific library.
Please try to refer to this library as "Dear ImGui".
@@ -622,6 +622,7 @@ CODE
Q: How can I display an image? What is ImTextureID, how does it works?
A: Short explanation:
+ - Please read Wiki entry for examples: https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
- You may use functions such as ImGui::Image(), ImGui::ImageButton() or lower-level ImDrawList::AddImage() to emit draw calls that will use your own textures.
- Actual textures are identified in a way that is up to the user/engine. Those identifiers are stored and passed as ImTextureID (void*) value.
- Loading image files from the disk and turning them into a texture is not within the scope of Dear ImGui (for a good reason).
@@ -638,7 +639,7 @@ CODE
- In the examples/ bindings, for each graphics API binding we decided on a type that is likely to be a good representation for specifying
an image from the end-user perspective. This is what the _examples_ rendering functions are using:
- OpenGL: ImTextureID = GLuint (see ImGui_ImplGlfwGL3_RenderDrawData() function in imgui_impl_glfw_gl3.cpp)
+ OpenGL: ImTextureID = GLuint (see ImGui_ImplOpenGL3_RenderDrawData() function in imgui_impl_opengl3.cpp)
DirectX9: ImTextureID = LPDIRECT3DTEXTURE9 (see ImGui_ImplDX9_RenderDrawData() function in imgui_impl_dx9.cpp)
DirectX11: ImTextureID = ID3D11ShaderResourceView* (see ImGui_ImplDX11_RenderDrawData() function in imgui_impl_dx11.cpp)
DirectX12: ImTextureID = D3D12_GPU_DESCRIPTOR_HANDLE (see ImGui_ImplDX12_RenderDrawData() function in imgui_impl_dx12.cpp)
@@ -669,26 +670,9 @@ CODE
This is by design and is actually a good thing, because it means your code has full control over your data types and how you display them.
If you want to display an image file (e.g. PNG file) into the screen, please refer to documentation and tutorials for the graphics API you are using.
- Here's a simplified OpenGL example using stb_image.h:
+ Refer to the Wiki to find simplified examples for loading textures with OpenGL, DirectX9 and DirectX11:
- // Use stb_image.h to load a PNG from disk and turn it into raw RGBA pixel data:
- #define STB_IMAGE_IMPLEMENTATION
- #include <stb_image.h>
- [...]
- int my_image_width, my_image_height;
- unsigned char* my_image_data = stbi_load("my_image.png", &my_image_width, &my_image_height, NULL, 4);
-
- // Turn the RGBA pixel data into an OpenGL texture:
- GLuint my_opengl_texture;
- glGenTextures(1, &my_opengl_texture);
- glBindTexture(GL_TEXTURE_2D, my_opengl_texture);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MIN_FILTER, GL_LINEAR);
- glTexParameteri(GL_TEXTURE_2D, GL_TEXTURE_MAG_FILTER, GL_LINEAR);
- glPixelStorei(GL_UNPACK_ROW_LENGTH, 0);
- glTexImage2D(GL_TEXTURE_2D, 0, GL_RGBA, image_width, image_height, 0, GL_RGBA, GL_UNSIGNED_BYTE, image_data);
-
- // Now that we have an OpenGL texture, assuming our imgui rendering function (imgui_impl_xxx.cpp file) takes GLuint as ImTextureID, we can display it:
- ImGui::Image((void*)(intptr_t)my_opengl_texture, ImVec2(my_image_width, my_image_height));
+ https://github.com/ocornut/imgui/wiki/Image-Loading-and-Displaying-Examples
C/C++ tip: a void* is pointer-sized storage. You may safely store any pointer or integer into it by casting your value to ImTextureID / void*, and vice-versa.
Because both end-points (user code and rendering function) are under your control, you know exactly what is stored inside the ImTextureID / void*.
@@ -1078,10 +1062,11 @@ static bool BeginChildEx(const char* name, ImGuiID id, const ImVec2&
// Navigation
static void NavUpdate();
static void NavUpdateWindowing();
-static void NavUpdateWindowingList();
+static void NavUpdateWindowingOverlay();
static void NavUpdateMoveResult();
static float NavUpdatePageUpPageDown(int allowed_dir_flags);
static inline void NavUpdateAnyRequestFlag();
+static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand);
static void NavProcessItem(ImGuiWindow* window, const ImRect& nav_bb, ImGuiID id);
static ImVec2 NavCalcPreferredRefPos();
static void NavSaveLastChildNavWindowIntoParent(ImGuiWindow* nav_window);
@@ -1244,6 +1229,7 @@ ImGuiIO::ImGuiIO()
ConfigInputTextCursorBlink = true;
ConfigWindowsResizeFromEdges = true;
ConfigWindowsMoveFromTitleBarOnly = false;
+ ConfigWindowsMemoryCompactTimer = 60.0f;
// Platform Functions
BackendPlatformName = BackendRendererName = NULL;
@@ -2487,14 +2473,18 @@ void ImGui::RenderTextClipped(const ImVec2& pos_min, const ImVec2& pos_max, cons
// Another overly complex function until we reorganize everything into a nice all-in-one helper.
// This is made more complex because we have dissociated the layout rectangle (pos_min..pos_max) which define _where_ the ellipsis is, from actual clipping of text and limit of the ellipsis display.
-// This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move.
-void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known)
+// This is because in the context of tabs we selectively hide part of the text when the Close Button appears, but we don't want the ellipsis to move.
+void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min, const ImVec2& pos_max, float clip_max_x, float ellipsis_max_x, const char* text, const char* text_end_full, const ImVec2* text_size_if_known)
{
ImGuiContext& g = *GImGui;
if (text_end_full == NULL)
text_end_full = FindRenderedTextEnd(text);
const ImVec2 text_size = text_size_if_known ? *text_size_if_known : CalcTextSize(text, text_end_full, false, 0.0f);
+ //draw_list->AddLine(ImVec2(pos_max.x, pos_min.y - 4), ImVec2(pos_max.x, pos_max.y + 4), IM_COL32(0, 0, 255, 255));
+ //draw_list->AddLine(ImVec2(ellipsis_max_x, pos_min.y-2), ImVec2(ellipsis_max_x, pos_max.y+2), IM_COL32(0, 255, 0, 255));
+ //draw_list->AddLine(ImVec2(clip_max_x, pos_min.y), ImVec2(clip_max_x, pos_max.y), IM_COL32(255, 0, 0, 255));
+ // FIXME: We could technically remove (last_glyph->AdvanceX - last_glyph->X1) from text_size.x here and save a few pixels.
if (text_size.x > pos_max.x - pos_min.x)
{
// Hello wo...
@@ -2502,15 +2492,33 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min,
// min max ellipsis_max
// <-> this is generally some padding value
- // FIXME-STYLE: RenderPixelEllipsis() style should use actual font data.
const ImFont* font = draw_list->_Data->Font;
const float font_size = draw_list->_Data->FontSize;
- const int ellipsis_dot_count = 3;
- const float ellipsis_width = (1.0f + 1.0f) * ellipsis_dot_count - 1.0f;
const char* text_end_ellipsis = NULL;
- float text_width = ImMax((pos_max.x - ellipsis_width) - pos_min.x, 1.0f);
- float text_size_clipped_x = font->CalcTextSizeA(font_size, text_width, 0.0f, text, text_end_full, &text_end_ellipsis).x;
+ ImWchar ellipsis_char = font->EllipsisChar;
+ int ellipsis_char_count = 1;
+ if (ellipsis_char == (ImWchar)-1)
+ {
+ ellipsis_char = (ImWchar)'.';
+ ellipsis_char_count = 3;
+ }
+ const ImFontGlyph* glyph = font->FindGlyph(ellipsis_char);
+
+ float ellipsis_glyph_width = glyph->X1; // Width of the glyph with no padding on either side
+ float ellipsis_total_width = ellipsis_glyph_width; // Full width of entire ellipsis
+
+ if (ellipsis_char_count > 1)
+ {
+ // Full ellipsis size without free spacing after it.
+ const float spacing_between_dots = 1.0f * (draw_list->_Data->FontSize / font->FontSize);
+ ellipsis_glyph_width = glyph->X1 - glyph->X0 + spacing_between_dots;
+ ellipsis_total_width = ellipsis_glyph_width * (float)ellipsis_char_count - spacing_between_dots;
+ }
+
+ // We can now claim the space between pos_max.x and ellipsis_max.x
+ const float text_avail_width = ImMax((ImMax(pos_max.x, ellipsis_max_x) - ellipsis_total_width) - pos_min.x, 1.0f);
+ float text_size_clipped_x = font->CalcTextSizeA(font_size, text_avail_width, 0.0f, text, text_end_full, &text_end_ellipsis).x;
if (text == text_end_ellipsis && text_end_ellipsis < text_end_full)
{
// Always display at least 1 character if there's no room for character + ellipsis
@@ -2519,15 +2527,20 @@ void ImGui::RenderTextEllipsis(ImDrawList* draw_list, const ImVec2& pos_min,
}
while (text_end_ellipsis > text && ImCharIsBlankA(text_end_ellipsis[-1]))
{
- // Trim trailing space before ellipsis
+ // Trim trailing space before ellipsis (FIXME: Supporting non-ascii blanks would be nice, for this we need a function to backtrack in UTF-8 text)
text_end_ellipsis--;
text_size_clipped_x -= font->CalcTextSizeA(font_size, FLT_MAX, 0.0f, text_end_ellipsis, text_end_ellipsis + 1).x; // Ascii blanks are always 1 byte
}
- RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f));
- const float ellipsis_x = pos_min.x + text_size_clipped_x + 1.0f;
- if (ellipsis_x + ellipsis_width - 1.0f <= ellipsis_max_x)
- RenderPixelEllipsis(draw_list, ImVec2(ellipsis_x, pos_min.y), GetColorU32(ImGuiCol_Text), ellipsis_dot_count);
+ // Render text, render ellipsis
+ RenderTextClippedEx(draw_list, pos_min, ImVec2(clip_max_x, pos_max.y), text, text_end_ellipsis, &text_size, ImVec2(0.0f, 0.0f));
+ float ellipsis_x = pos_min.x + text_size_clipped_x;
+ if (ellipsis_x + ellipsis_total_width <= ellipsis_max_x)
+ for (int i = 0; i < ellipsis_char_count; i++)
+ {
+ font->RenderChar(draw_list, font_size, ImVec2(ellipsis_x, pos_min.y), GetColorU32(ImGuiCol_Text), ellipsis_char);
+ ellipsis_x += ellipsis_glyph_width;
+ }
}
else
{
@@ -2691,14 +2704,15 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name)
BeginOrderWithinContext = -1;
PopupId = 0;
AutoFitFramesX = AutoFitFramesY = -1;
- AutoFitOnlyGrows = false;
AutoFitChildAxises = 0x00;
+ AutoFitOnlyGrows = false;
AutoPosLastDirection = ImGuiDir_None;
HiddenFramesCanSkipItems = HiddenFramesCannotSkipItems = 0;
SetWindowPosAllowFlags = SetWindowSizeAllowFlags = SetWindowCollapsedAllowFlags = ImGuiCond_Always | ImGuiCond_Once | ImGuiCond_FirstUseEver | ImGuiCond_Appearing;
SetWindowPosVal = SetWindowPosPivot = ImVec2(FLT_MAX, FLT_MAX);
LastFrameActive = -1;
+ LastTimeActive = -1.0f;
ItemWidthDefault = 0.0f;
FontWindowScale = 1.0f;
SettingsIdx = -1;
@@ -2713,6 +2727,9 @@ ImGuiWindow::ImGuiWindow(ImGuiContext* context, const char* name)
NavLastIds[0] = NavLastIds[1] = 0;
NavRectRel[0] = NavRectRel[1] = ImRect();
NavLastChildNavWindow = NULL;
+
+ MemoryCompacted = false;
+ MemoryDrawListIdxCapacity = MemoryDrawListVtxCapacity = 0;
}
ImGuiWindow::~ImGuiWindow()
@@ -2783,6 +2800,36 @@ static void SetCurrentWindow(ImGuiWindow* window)
g.FontSize = g.DrawListSharedData.FontSize = window->CalcFontSize();
}
+// Free up/compact internal window buffers, we can use this when a window becomes unused.
+// This is currently unused by the library, but you may call this yourself for easy GC.
+// Not freed:
+// - ImGuiWindow, ImGuiWindowSettings, Name
+// - StateStorage, ColumnsStorage (may hold useful data)
+// This should have no noticeable visual effect. When the window reappear however, expect new allocation/buffer growth/copy cost.
+void ImGui::GcCompactTransientWindowBuffers(ImGuiWindow* window)
+{
+ window->MemoryCompacted = true;
+ window->MemoryDrawListIdxCapacity = window->DrawList->IdxBuffer.Capacity;
+ window->MemoryDrawListVtxCapacity = window->DrawList->VtxBuffer.Capacity;
+ window->IDStack.clear();
+ window->DrawList->ClearFreeMemory();
+ window->DC.ChildWindows.clear();
+ window->DC.ItemFlagsStack.clear();
+ window->DC.ItemWidthStack.clear();
+ window->DC.TextWrapPosStack.clear();
+ window->DC.GroupStack.clear();
+}
+
+void ImGui::GcAwakeTransientWindowBuffers(ImGuiWindow* window)
+{
+ // We stored capacity of the ImDrawList buffer to reduce growth-caused allocation/copy when awakening.
+ // The other buffers tends to amortize much faster.
+ window->MemoryCompacted = false;
+ window->DrawList->IdxBuffer.reserve(window->MemoryDrawListIdxCapacity);
+ window->DrawList->VtxBuffer.reserve(window->MemoryDrawListVtxCapacity);
+ window->MemoryDrawListIdxCapacity = window->MemoryDrawListVtxCapacity = 0;
+}
+
void ImGui::SetNavID(ImGuiID id, int nav_layer)
{
ImGuiContext& g = *GImGui;
@@ -2961,8 +3008,8 @@ bool ImGui::ItemAdd(const ImRect& bb, ImGuiID id, const ImRect* nav_bb_arg)
{
// Navigation processing runs prior to clipping early-out
// (a) So that NavInitRequest can be honored, for newly opened windows to select a default widget
- // (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests
- // unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of
+ // (b) So that we can scroll up/down past clipped items. This adds a small O(N) cost to regular navigation requests
+ // unfortunately, but it is still limited to one window. It may not scale very well for windows with ten of
// thousands of item, but at least NavMoveRequest is only set on user interaction, aka maximum once a frame.
// We could early out with "if (is_clipped && !g.NavInitRequest) return false;" but when we wouldn't be able
// to reach unclipped widgets. This would work if user had explicit scrolling control (e.g. mapped on a stick).
@@ -3282,12 +3329,6 @@ ImDrawList* ImGui::GetBackgroundDrawList()
return &GImGui->BackgroundDrawList;
}
-static ImDrawList* GetForegroundDrawList(ImGuiWindow*)
-{
- // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches.
- return &GImGui->ForegroundDrawList;
-}
-
ImDrawList* ImGui::GetForegroundDrawList()
{
return &GImGui->ForegroundDrawList;
@@ -3630,7 +3671,7 @@ static void NewFrameSanityChecks()
IM_ASSERT(g.Style.CurveTessellationTol > 0.0f && "Invalid style setting!");
IM_ASSERT(g.Style.Alpha >= 0.0f && g.Style.Alpha <= 1.0f && "Invalid style setting. Alpha cannot be negative (allows us to avoid a few clamps in color computations)!");
IM_ASSERT(g.Style.WindowMinSize.x >= 1.0f && g.Style.WindowMinSize.y >= 1.0f && "Invalid style setting.");
- IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_Left || g.Style.WindowMenuButtonPosition == ImGuiDir_Right);
+ IM_ASSERT(g.Style.WindowMenuButtonPosition == ImGuiDir_None || 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)");
@@ -3814,8 +3855,9 @@ void ImGui::NewFrame()
g.NavIdTabCounter = INT_MAX;
- // Mark all windows as not visible
+ // Mark all windows as not visible and compact unused memory.
IM_ASSERT(g.WindowsFocusOrder.Size == g.Windows.Size);
+ const float memory_compact_start_time = (g.IO.ConfigWindowsMemoryCompactTimer >= 0.0f) ? (float)g.Time - g.IO.ConfigWindowsMemoryCompactTimer : FLT_MAX;
for (int i = 0; i != g.Windows.Size; i++)
{
ImGuiWindow* window = g.Windows[i];
@@ -3823,6 +3865,10 @@ void ImGui::NewFrame()
window->BeginCount = 0;
window->Active = false;
window->WriteAccessed = false;
+
+ // Garbage collect (this is totally functional but we may need decide if the side-effects are desirable)
+ if (!window->WasActive && !window->MemoryCompacted && window->LastTimeActive < memory_compact_start_time)
+ GcCompactTransientWindowBuffers(window);
}
// Closing the focused window restore focus to the first active root window in descending z-order
@@ -4004,7 +4050,7 @@ static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* d
return;
}
- // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc.
+ // Draw list sanity check. Detect mismatch between PrimReserve() calls and incrementing _VtxCurrentIdx, _VtxWritePtr etc.
// May trigger for you if you are using PrimXXX functions incorrectly.
IM_ASSERT(draw_list->VtxBuffer.Size == 0 || draw_list->_VtxWritePtr == draw_list->VtxBuffer.Data + draw_list->VtxBuffer.Size);
IM_ASSERT(draw_list->IdxBuffer.Size == 0 || draw_list->_IdxWritePtr == draw_list->IdxBuffer.Data + draw_list->IdxBuffer.Size);
@@ -4013,7 +4059,7 @@ static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* d
// Check that draw_list doesn't use more vertices than indexable (default ImDrawIdx = unsigned short = 2 bytes = 64K vertices per ImDrawList = per window)
// If this assert triggers because you are drawing lots of stuff manually:
- // - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds.
+ // - First, make sure you are coarse clipping yourself and not trying to draw many things outside visible bounds.
// Be mindful that the ImDrawList API doesn't filter vertices. Use the Metrics window to inspect draw list contents.
// - If you want large meshes with more than 64K vertices, you can either:
// (A) Handle the ImDrawCmd::VtxOffset value in your renderer back-end, and set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset'.
@@ -4022,9 +4068,9 @@ static void AddDrawListToDrawData(ImVector<ImDrawList*>* out_list, ImDrawList* d
// (B) Or handle 32-bits indices in your renderer back-end, and uncomment '#define ImDrawIdx unsigned int' line in imconfig.h.
// Most example back-ends already support this. For example, the OpenGL example code detect index size at compile-time:
// glDrawElements(GL_TRIANGLES, (GLsizei)pcmd->ElemCount, sizeof(ImDrawIdx) == 2 ? GL_UNSIGNED_SHORT : GL_UNSIGNED_INT, idx_buffer_offset);
- // Your own engine or render API may use different parameters or function calls to specify index sizes.
+ // Your own engine or render API may use different parameters or function calls to specify index sizes.
// 2 and 4 bytes indices are generally supported by most graphics API.
- // - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() before reaching
+ // - If for some reason neither of those solutions works for you, a workaround is to call BeginChild()/EndChild() before reaching
// the 64K limit to split your draw commands in multiple draw lists.
if (sizeof(ImDrawIdx) == 2)
IM_ASSERT(draw_list->_VtxCurrentIdx < (1 << 16) && "Too many vertices in ImDrawList using 16-bit indices. Read comment above");
@@ -4144,8 +4190,8 @@ void ImGui::EndFrame()
End();
// Show CTRL+TAB list window
- if (g.NavWindowingTarget)
- NavUpdateWindowingList();
+ if (g.NavWindowingTarget != NULL)
+ NavUpdateWindowingOverlay();
// Drag and Drop: Elapse payload (if delivered, or if source stops being submitted)
if (g.DragDropActive)
@@ -4228,7 +4274,7 @@ void ImGui::Render()
// Draw software mouse cursor if requested
if (g.IO.MouseDrawCursor)
- RenderMouseCursor(&g.ForegroundDrawList, g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor);
+ RenderMouseCursor(&g.ForegroundDrawList, g.IO.MousePos, g.Style.MouseCursorScale, g.MouseCursor, IM_COL32_WHITE, IM_COL32_BLACK, IM_COL32(0, 0, 0, 48));
if (!g.ForegroundDrawList.VtxBuffer.empty())
AddDrawListToDrawData(&g.DrawDataBuilder.Layers[0], &g.ForegroundDrawList);
@@ -4341,7 +4387,7 @@ int ImGui::GetKeyIndex(ImGuiKey imgui_key)
// Note that imgui doesn't know the semantic of each entry of io.KeysDown[]. Use your own indices/enums according to how your back-end/engine stored them into io.KeysDown[]!
bool ImGui::IsKeyDown(int user_key_index)
{
- if (user_key_index < 0)
+ if (user_key_index < 0)
return false;
ImGuiContext& g = *GImGui;
IM_ASSERT(user_key_index >= 0 && user_key_index < IM_ARRAYSIZE(g.IO.KeysDown));
@@ -4439,7 +4485,7 @@ bool ImGui::IsMouseDoubleClicked(int button)
return g.IO.MouseDoubleClicked[button];
}
-// [Internal] This doesn't test if the button is presed
+// [Internal] This doesn't test if the button is pressed
bool ImGui::IsMouseDragPastThreshold(int button, float lock_threshold)
{
ImGuiContext& g = *GImGui;
@@ -4683,7 +4729,7 @@ static bool ImGui::BeginChildEx(const char* name, ImGuiID id, const ImVec2& size
ImGuiWindow* child_window = g.CurrentWindow;
child_window->ChildId = id;
- child_window->AutoFitChildAxises = auto_fit_axises;
+ child_window->AutoFitChildAxises = (ImS8)auto_fit_axises;
// Set the cursor to handle case where the user called SetNextWindowPos()+BeginChild() manually.
// While this is not really documented/defined, it seems that the expected thing to do.
@@ -4827,10 +4873,10 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl
// Retrieve settings from .ini file
window->SettingsIdx = g.SettingsWindows.index_from_ptr(settings);
SetWindowConditionAllowFlags(window, ImGuiCond_FirstUseEver, false);
- window->Pos = ImFloor(settings->Pos);
+ window->Pos = ImVec2(settings->Pos.x, settings->Pos.y);
window->Collapsed = settings->Collapsed;
- if (ImLengthSqr(settings->Size) > 0.00001f)
- size = ImFloor(settings->Size);
+ if (settings->Size.x > 0 && settings->Size.y > 0)
+ size = ImVec2(settings->Size.x, settings->Size.y);
}
window->Size = window->SizeFull = ImFloor(size);
window->DC.CursorStartPos = window->DC.CursorMaxPos = window->Pos; // So first call to CalcContentSize() doesn't return crazy values
@@ -4857,7 +4903,7 @@ static ImGuiWindow* CreateNewWindow(const char* name, ImVec2 size, ImGuiWindowFl
return window;
}
-static ImVec2 CalcSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size)
+static ImVec2 CalcWindowSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size)
{
ImGuiContext& g = *GImGui;
if (g.NextWindowData.Flags & ImGuiNextWindowDataFlags_HasSizeConstraint)
@@ -4889,7 +4935,7 @@ static ImVec2 CalcSizeAfterConstraint(ImGuiWindow* window, ImVec2 new_size)
return new_size;
}
-static ImVec2 CalcContentSize(ImGuiWindow* window)
+static ImVec2 CalcWindowContentSize(ImGuiWindow* window)
{
if (window->Collapsed)
if (window->AutoFitFramesX <= 0 && window->AutoFitFramesY <= 0)
@@ -4903,7 +4949,7 @@ static ImVec2 CalcContentSize(ImGuiWindow* window)
return sz;
}
-static ImVec2 CalcSizeAutoFit(ImGuiWindow* window, const ImVec2& size_contents)
+static ImVec2 CalcWindowAutoFitSize(ImGuiWindow* window, const ImVec2& size_contents)
{
ImGuiContext& g = *GImGui;
ImGuiStyle& style = g.Style;
@@ -4927,7 +4973,7 @@ static ImVec2 CalcSizeAutoFit(ImGuiWindow* window, const ImVec2& size_contents)
// When the window cannot fit all contents (either because of constraints, either because screen is too small),
// we are growing the size on the other axis to compensate for expected scrollbar. FIXME: Might turn bigger than ViewportSize-WindowPadding.
- ImVec2 size_auto_fit_after_constraint = CalcSizeAfterConstraint(window, size_auto_fit);
+ ImVec2 size_auto_fit_after_constraint = CalcWindowSizeAfterConstraint(window, size_auto_fit);
bool will_have_scrollbar_x = (size_auto_fit_after_constraint.x - size_pad.x - size_decorations.x < size_contents.x && !(window->Flags & ImGuiWindowFlags_NoScrollbar) && (window->Flags & ImGuiWindowFlags_HorizontalScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysHorizontalScrollbar);
bool will_have_scrollbar_y = (size_auto_fit_after_constraint.y - size_pad.y - size_decorations.y < size_contents.y && !(window->Flags & ImGuiWindowFlags_NoScrollbar)) || (window->Flags & ImGuiWindowFlags_AlwaysVerticalScrollbar);
if (will_have_scrollbar_x)
@@ -4940,8 +4986,10 @@ static ImVec2 CalcSizeAutoFit(ImGuiWindow* window, const ImVec2& size_contents)
ImVec2 ImGui::CalcWindowExpectedSize(ImGuiWindow* window)
{
- ImVec2 size_contents = CalcContentSize(window);
- return CalcSizeAfterConstraint(window, CalcSizeAutoFit(window, size_contents));
+ ImVec2 size_contents = CalcWindowContentSize(window);
+ ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, size_contents);
+ ImVec2 size_final = CalcWindowSizeAfterConstraint(window, size_auto_fit);
+ return size_final;
}
static ImGuiCol GetWindowBgColorIdxFromFlags(ImGuiWindowFlags flags)
@@ -4958,7 +5006,7 @@ static void CalcResizePosSizeFromAnyCorner(ImGuiWindow* window, const ImVec2& co
ImVec2 pos_min = ImLerp(corner_target, window->Pos, corner_norm); // Expected window upper-left
ImVec2 pos_max = ImLerp(window->Pos + window->Size, corner_target, corner_norm); // Expected window lower-right
ImVec2 size_expected = pos_max - pos_min;
- ImVec2 size_constrained = CalcSizeAfterConstraint(window, size_expected);
+ ImVec2 size_constrained = CalcWindowSizeAfterConstraint(window, size_expected);
*out_pos = pos_min;
if (corner_norm.x == 0.0f)
out_pos->x -= (size_constrained.x - size_expected.x);
@@ -5039,7 +5087,7 @@ static bool ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
if (held && g.IO.MouseDoubleClicked[0] && resize_grip_n == 0)
{
// Manual auto-fit when double-clicking
- size_target = CalcSizeAfterConstraint(window, size_auto_fit);
+ size_target = CalcWindowSizeAfterConstraint(window, size_auto_fit);
ret_auto_fit = true;
ClearActiveID();
}
@@ -5094,7 +5142,7 @@ static bool ImGui::UpdateManualResize(ImGuiWindow* window, const ImVec2& size_au
g.NavDisableMouseHover = true;
resize_grip_col[0] = GetColorU32(ImGuiCol_ResizeGripActive);
// FIXME-NAV: Should store and accumulate into a separate size buffer to handle sizing constraints properly, right now a constraint will make us stuck.
- size_target = CalcSizeAfterConstraint(window, window->SizeFull + nav_resize_delta);
+ size_target = CalcWindowSizeAfterConstraint(window, window->SizeFull + nav_resize_delta);
}
}
@@ -5245,7 +5293,7 @@ void ImGui::RenderWindowTitleBarContents(ImGuiWindow* window, const ImRect& titl
ImGuiWindowFlags flags = window->Flags;
const bool has_close_button = (p_open != NULL);
- const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse);
+ const bool has_collapse_button = !(flags & ImGuiWindowFlags_NoCollapse) && (style.WindowMenuButtonPosition != ImGuiDir_None);
// Close & Collapse button are on the Menu NavLayer and don't default focus (unless there's nothing else on that layer)
const ImGuiItemFlags item_flags_backup = window->DC.ItemFlags;
@@ -5389,6 +5437,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
{
window->Flags = (ImGuiWindowFlags)flags;
window->LastFrameActive = current_frame;
+ window->LastTimeActive = (float)g.Time;
window->BeginOrderWithinParent = 0;
window->BeginOrderWithinContext = (short)(g.WindowsActiveCount++);
}
@@ -5402,6 +5451,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
ImGuiWindow* parent_window = first_begin_of_the_frame ? ((flags & (ImGuiWindowFlags_ChildWindow | ImGuiWindowFlags_Popup)) ? parent_window_in_stack : NULL) : window->ParentWindow;
IM_ASSERT(parent_window != NULL || !(flags & ImGuiWindowFlags_ChildWindow));
+ // We allow window memory to be compacted so recreate the base stack when needed.
+ if (window->IDStack.Size == 0)
+ window->IDStack.push_back(window->ID);
+
// Add to stack
// We intentionally set g.CurrentWindow to NULL to prevent usage until when the viewport is set, then will call SetCurrentWindow()
g.CurrentWindowStack.push_back(window);
@@ -5466,6 +5519,10 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->ClipRect = ImVec4(-FLT_MAX,-FLT_MAX,+FLT_MAX,+FLT_MAX);
window->IDStack.resize(1);
+ // Restore buffer capacity when woken from a compacted state, to avoid
+ if (window->MemoryCompacted)
+ GcAwakeTransientWindowBuffers(window);
+
// Update stored window name when it changes (which can _only_ happen with the "###" operator, so the ID would stay unchanged).
// The title bar always display the 'name' parameter, so we only update the string storage if it needs to be visible to the end-user elsewhere.
bool window_title_visible_elsewhere = false;
@@ -5481,7 +5538,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// UPDATE CONTENTS SIZE, UPDATE HIDDEN STATUS
// Update contents size from last frame for auto-fitting (or use explicit size)
- window->ContentSize = CalcContentSize(window);
+ window->ContentSize = CalcWindowContentSize(window);
if (window->HiddenFramesCanSkipItems > 0)
window->HiddenFramesCanSkipItems--;
if (window->HiddenFramesCannotSkipItems > 0)
@@ -5545,7 +5602,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
// SIZE
// Calculate auto-fit size, handle automatic resize
- const ImVec2 size_auto_fit = CalcSizeAutoFit(window, window->ContentSize);
+ const ImVec2 size_auto_fit = CalcWindowAutoFitSize(window, window->ContentSize);
bool use_current_size_for_scrollbar_x = window_just_created;
bool use_current_size_for_scrollbar_y = window_just_created;
if ((flags & ImGuiWindowFlags_AlwaysAutoResize) && !window->Collapsed)
@@ -5581,7 +5638,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
}
// Apply minimum/maximum window size constraints and final size
- window->SizeFull = CalcSizeAfterConstraint(window, window->SizeFull);
+ window->SizeFull = CalcWindowSizeAfterConstraint(window, window->SizeFull);
window->Size = window->Collapsed && !(flags & ImGuiWindowFlags_ChildWindow) ? window->TitleBarRect().GetSize() : window->SizeFull;
// Decoration size
@@ -5690,7 +5747,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->OuterRectClipped.ClipWith(host_rect);
// Inner rectangle
- // Not affected by window border size. Used by:
+ // Not affected by window border size. Used by:
// - InnerClipRect
// - ScrollToBringRectIntoView()
// - NavUpdatePageUpPageDown()
@@ -5768,7 +5825,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
render_decorations_in_parent = true;
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);
@@ -5844,7 +5901,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->DC.TextWrapPosStack.resize(0);
window->DC.CurrentColumns = NULL;
window->DC.TreeDepth = 0;
- window->DC.TreeStoreMayJumpToParentOnPop = 0x00;
+ window->DC.TreeMayJumpToParentOnPopMask = 0x00;
window->DC.StateStorage = &window->StateStorage;
window->DC.GroupStack.resize(0);
window->MenuColumns.Update(3, style.ItemSpacing.x, window_just_activated_by_user);
@@ -7165,22 +7222,33 @@ static ImVec2 CalcNextScrollFromScrollTargetAndClamp(ImGuiWindow* window, bool s
}
// Scroll to keep newly navigated item fully into view
-void ImGui::ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect)
+ImVec2 ImGui::ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect)
{
+ ImGuiContext& g = *GImGui;
ImRect window_rect(window->InnerRect.Min - ImVec2(1, 1), window->InnerRect.Max + ImVec2(1, 1));
//GetForegroundDrawList(window)->AddRect(window_rect.Min, window_rect.Max, IM_COL32_WHITE); // [DEBUG]
- if (window_rect.Contains(item_rect))
- return;
- ImGuiContext& g = *GImGui;
- if (window->ScrollbarX && item_rect.Min.x < window_rect.Min.x)
- SetScrollFromPosX(window, item_rect.Min.x - window->Pos.x + g.Style.ItemSpacing.x, 0.0f);
- else if (window->ScrollbarX && item_rect.Max.x >= window_rect.Max.x)
- SetScrollFromPosX(window, item_rect.Max.x - window->Pos.x + g.Style.ItemSpacing.x, 1.0f);
- if (item_rect.Min.y < window_rect.Min.y)
- SetScrollFromPosY(window, item_rect.Min.y - window->Pos.y - g.Style.ItemSpacing.y, 0.0f);
- else if (item_rect.Max.y >= window_rect.Max.y)
- SetScrollFromPosY(window, item_rect.Max.y - window->Pos.y + g.Style.ItemSpacing.y, 1.0f);
+ ImVec2 delta_scroll;
+ if (!window_rect.Contains(item_rect))
+ {
+ if (window->ScrollbarX && item_rect.Min.x < window_rect.Min.x)
+ SetScrollFromPosX(window, item_rect.Min.x - window->Pos.x + g.Style.ItemSpacing.x, 0.0f);
+ else if (window->ScrollbarX && item_rect.Max.x >= window_rect.Max.x)
+ SetScrollFromPosX(window, item_rect.Max.x - window->Pos.x + g.Style.ItemSpacing.x, 1.0f);
+ if (item_rect.Min.y < window_rect.Min.y)
+ SetScrollFromPosY(window, item_rect.Min.y - window->Pos.y - g.Style.ItemSpacing.y, 0.0f);
+ else if (item_rect.Max.y >= window_rect.Max.y)
+ SetScrollFromPosY(window, item_rect.Max.y - window->Pos.y + g.Style.ItemSpacing.y, 1.0f);
+
+ ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(window, false);
+ delta_scroll = next_scroll - window->Scroll;
+ }
+
+ // Also scroll parent window to keep us into view if necessary
+ if (window->Flags & ImGuiWindowFlags_ChildWindow)
+ delta_scroll += ScrollToBringRectIntoView(window->ParentWindow, ImRect(item_rect.Min - delta_scroll, item_rect.Max - delta_scroll));
+
+ return delta_scroll;
}
float ImGui::GetScrollX()
@@ -7793,7 +7861,7 @@ static void inline NavClampRectToVisibleAreaForMoveDir(ImGuiDir move_dir, ImRect
}
// Scoring function for directional navigation. Based on https://gist.github.com/rygorous/6981057
-static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand)
+static bool ImGui::NavScoreItem(ImGuiNavMoveResult* result, ImRect cand)
{
ImGuiContext& g = *GImGui;
ImGuiWindow* window = g.CurrentWindow;
@@ -7856,22 +7924,22 @@ static bool NavScoreItem(ImGuiNavMoveResult* result, ImRect cand)
#if IMGUI_DEBUG_NAV_SCORING
char buf[128];
- if (ImGui::IsMouseHoveringRect(cand.Min, cand.Max))
+ if (IsMouseHoveringRect(cand.Min, cand.Max))
{
ImFormatString(buf, IM_ARRAYSIZE(buf), "dbox (%.2f,%.2f->%.4f)\ndcen (%.2f,%.2f->%.4f)\nd (%.2f,%.2f->%.4f)\nnav %c, quadrant %c", dbx, dby, dist_box, dcx, dcy, dist_center, dax, day, dist_axial, "WENS"[g.NavMoveDir], "WENS"[quadrant]);
- ImDrawList* draw_list = ImGui::GetForegroundDrawList(window);
+ ImDrawList* draw_list = GetForegroundDrawList(window);
draw_list->AddRect(curr.Min, curr.Max, IM_COL32(255,200,0,100));
draw_list->AddRect(cand.Min, cand.Max, IM_COL32(255,255,0,200));
- draw_list->AddRectFilled(cand.Max-ImVec2(4,4), cand.Max+ImGui::CalcTextSize(buf)+ImVec2(4,4), IM_COL32(40,0,0,150));
+ draw_list->AddRectFilled(cand.Max - ImVec2(4,4), cand.Max + CalcTextSize(buf) + ImVec2(4,4), IM_COL32(40,0,0,150));
draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Max, ~0U, buf);
}
else if (g.IO.KeyCtrl) // Hold to preview score in matching quadrant. Press C to rotate.
{
- if (ImGui::IsKeyPressedMap(ImGuiKey_C)) { g.NavMoveDirLast = (ImGuiDir)((g.NavMoveDirLast + 1) & 3); g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_C]] = 0.01f; }
+ if (IsKeyPressedMap(ImGuiKey_C)) { g.NavMoveDirLast = (ImGuiDir)((g.NavMoveDirLast + 1) & 3); g.IO.KeysDownDuration[g.IO.KeyMap[ImGuiKey_C]] = 0.01f; }
if (quadrant == g.NavMoveDir)
{
ImFormatString(buf, IM_ARRAYSIZE(buf), "%.0f/%.0f", dist_box, dist_center);
- ImDrawList* draw_list = ImGui::GetForegroundDrawList(window);
+ ImDrawList* draw_list = GetForegroundDrawList(window);
draw_list->AddRectFilled(cand.Min, cand.Max, IM_COL32(255, 0, 0, 200));
draw_list->AddText(g.IO.FontDefault, 13.0f, cand.Min, IM_COL32(255, 255, 255, 255), buf);
}
@@ -8012,7 +8080,7 @@ void ImGui::NavMoveRequestForward(ImGuiDir move_dir, ImGuiDir clip_dir, const Im
{
ImGuiContext& g = *GImGui;
IM_ASSERT(g.NavMoveRequestForward == ImGuiNavForward_None);
- ImGui::NavMoveRequestCancel();
+ NavMoveRequestCancel();
g.NavMoveDir = move_dir;
g.NavMoveClipDir = clip_dir;
g.NavMoveRequestForward = ImGuiNavForward_ForwardQueued;
@@ -8348,10 +8416,10 @@ static void ImGui::NavUpdate()
g.NavMoveRequestFlags = ImGuiNavMoveFlags_None;
if (g.NavWindow && !g.NavWindowingTarget && allowed_dir_flags && !(g.NavWindow->Flags & ImGuiWindowFlags_NoNavInputs))
{
- if ((allowed_dir_flags & (1<<ImGuiDir_Left)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadLeft, ImGuiNavInput_KeyLeft_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Left;
- if ((allowed_dir_flags & (1<<ImGuiDir_Right)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadRight,ImGuiNavInput_KeyRight_,ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Right;
- if ((allowed_dir_flags & (1<<ImGuiDir_Up)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadUp, ImGuiNavInput_KeyUp_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Up;
- if ((allowed_dir_flags & (1<<ImGuiDir_Down)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadDown, ImGuiNavInput_KeyDown_, ImGuiInputReadMode_Repeat)) g.NavMoveDir = ImGuiDir_Down;
+ if ((allowed_dir_flags & (1 << ImGuiDir_Left)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadLeft, ImGuiNavInput_KeyLeft_, ImGuiInputReadMode_Repeat)) { g.NavMoveDir = ImGuiDir_Left; }
+ if ((allowed_dir_flags & (1 << ImGuiDir_Right)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadRight,ImGuiNavInput_KeyRight_,ImGuiInputReadMode_Repeat)) { g.NavMoveDir = ImGuiDir_Right; }
+ if ((allowed_dir_flags & (1 << ImGuiDir_Up)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadUp, ImGuiNavInput_KeyUp_, ImGuiInputReadMode_Repeat)) { g.NavMoveDir = ImGuiDir_Up; }
+ if ((allowed_dir_flags & (1 << ImGuiDir_Down)) && IsNavInputPressedAnyOfTwo(ImGuiNavInput_DpadDown, ImGuiNavInput_KeyDown_, ImGuiInputReadMode_Repeat)) { g.NavMoveDir = ImGuiDir_Down; }
}
g.NavMoveClipDir = g.NavMoveDir;
}
@@ -8364,7 +8432,8 @@ static void ImGui::NavUpdate()
g.NavMoveRequestForward = ImGuiNavForward_ForwardActive;
}
- // Update PageUp/PageDown scroll
+ // Update PageUp/PageDown/Home/End scroll
+ // FIXME-NAV: Consider enabling those keys even without the master ImGuiConfigFlags_NavEnableKeyboard flag?
float nav_scoring_rect_offset_y = 0.0f;
if (nav_keyboard_active)
nav_scoring_rect_offset_y = NavUpdatePageUpPageDown(allowed_dir_flags);
@@ -8483,17 +8552,22 @@ static void ImGui::NavUpdateMoveResult()
// Scroll to keep newly navigated item fully into view.
if (g.NavLayer == 0)
{
- ImRect rect_abs = ImRect(result->RectRel.Min + result->Window->Pos, result->RectRel.Max + result->Window->Pos);
- ScrollToBringRectIntoView(result->Window, rect_abs);
-
- // Estimate upcoming scroll so we can offset our result position so mouse position can be applied immediately after in NavUpdate()
- ImVec2 next_scroll = CalcNextScrollFromScrollTargetAndClamp(result->Window, false);
- ImVec2 delta_scroll = result->Window->Scroll - next_scroll;
- result->RectRel.Translate(delta_scroll);
+ ImVec2 delta_scroll;
+ if (g.NavMoveRequestFlags & ImGuiNavMoveFlags_ScrollToEdge)
+ {
+ float scroll_target = (g.NavMoveDir == ImGuiDir_Up) ? result->Window->ScrollMax.y : 0.0f;
+ delta_scroll.y = result->Window->Scroll.y - scroll_target;
+ SetScrollY(result->Window, scroll_target);
+ }
+ else
+ {
+ ImRect rect_abs = ImRect(result->RectRel.Min + result->Window->Pos, result->RectRel.Max + result->Window->Pos);
+ delta_scroll = ScrollToBringRectIntoView(result->Window, rect_abs);
+ }
- // Also scroll parent window to keep us into view if necessary (we could/should technically recurse back the whole the parent hierarchy).
- if (result->Window->Flags & ImGuiWindowFlags_ChildWindow)
- ScrollToBringRectIntoView(result->Window->ParentWindow, ImRect(rect_abs.Min + delta_scroll, rect_abs.Max + delta_scroll));
+ // Offset our result position so mouse position can be applied immediately after in NavUpdate()
+ result->RectRel.TranslateX(-delta_scroll.x);
+ result->RectRel.TranslateY(-delta_scroll.y);
}
ClearActiveID();
@@ -8508,6 +8582,7 @@ static void ImGui::NavUpdateMoveResult()
g.NavMoveFromClampedRefRect = false;
}
+// Handle PageUp/PageDown/Home/End keys
static float ImGui::NavUpdatePageUpPageDown(int allowed_dir_flags)
{
ImGuiContext& g = *GImGui;
@@ -8517,9 +8592,11 @@ static float ImGui::NavUpdatePageUpPageDown(int allowed_dir_flags)
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
+ const bool page_up_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageUp]) && (allowed_dir_flags & (1 << ImGuiDir_Up));
+ const bool page_down_held = IsKeyDown(g.IO.KeyMap[ImGuiKey_PageDown]) && (allowed_dir_flags & (1 << ImGuiDir_Down));
+ const bool home_pressed = IsKeyPressed(g.IO.KeyMap[ImGuiKey_Home]) && (allowed_dir_flags & (1 << ImGuiDir_Up));
+ const bool end_pressed = IsKeyPressed(g.IO.KeyMap[ImGuiKey_End]) && (allowed_dir_flags & (1 << ImGuiDir_Down));
+ if (page_up_held != page_down_held || home_pressed != end_pressed) // If either (not both) are pressed
{
if (window->DC.NavLayerActiveMask == 0x00 && window->DC.NavHasScroll)
{
@@ -8528,26 +8605,49 @@ static float ImGui::NavUpdatePageUpPageDown(int allowed_dir_flags)
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 if (home_pressed)
+ SetScrollY(window, 0.0f);
+ else if (end_pressed)
+ SetScrollY(window, window->ScrollMax.y);
}
else
{
- const ImRect& nav_rect_rel = window->NavRectRel[g.NavLayer];
+ 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.NavMoveDir = ImGuiDir_Down; // Because our scoring rect is offset up, we request the down 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.NavMoveDir = ImGuiDir_Up; // Because our scoring rect is offset down, we request the up direction (so we can always land on the last item)
g.NavMoveClipDir = ImGuiDir_Down;
g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_AlsoScoreVisibleSet;
}
+ else if (home_pressed)
+ {
+ // FIXME-NAV: handling of Home/End is assuming that the top/bottom most item will be visible with Scroll.y == 0/ScrollMax.y
+ // Scrolling will be handled via the ImGuiNavMoveFlags_ScrollToEdge flag, we don't scroll immediately to avoid scrolling happening before nav result.
+ // Preserve current horizontal position if we have any.
+ nav_rect_rel.Min.y = nav_rect_rel.Max.y = -window->Scroll.y;
+ if (nav_rect_rel.IsInverted())
+ nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
+ g.NavMoveDir = ImGuiDir_Down;
+ g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
+ }
+ else if (end_pressed)
+ {
+ nav_rect_rel.Min.y = nav_rect_rel.Max.y = window->ScrollMax.y + window->SizeFull.y - window->Scroll.y;
+ if (nav_rect_rel.IsInverted())
+ nav_rect_rel.Min.x = nav_rect_rel.Max.x = 0.0f;
+ g.NavMoveDir = ImGuiDir_Up;
+ g.NavMoveRequestFlags = ImGuiNavMoveFlags_AllowCurrentNavId | ImGuiNavMoveFlags_ScrollToEdge;
+ }
return nav_scoring_rect_offset_y;
}
}
@@ -8743,7 +8843,7 @@ static const char* GetFallbackWindowNameForWindowingList(ImGuiWindow* window)
}
// Overlay displayed when using CTRL+TAB. Called by EndFrame().
-void ImGui::NavUpdateWindowingList()
+void ImGui::NavUpdateWindowingOverlay()
{
ImGuiContext& g = *GImGui;
IM_ASSERT(g.NavWindowingTarget != NULL);
@@ -9439,14 +9539,13 @@ static void* SettingsHandlerWindow_ReadOpen(ImGuiContext*, ImGuiSettingsHandler*
return (void*)settings;
}
-static void SettingsHandlerWindow_ReadLine(ImGuiContext* ctx, ImGuiSettingsHandler*, void* entry, const char* line)
+static void SettingsHandlerWindow_ReadLine(ImGuiContext*, ImGuiSettingsHandler*, void* entry, const char* line)
{
- ImGuiContext& g = *ctx;
ImGuiWindowSettings* settings = (ImGuiWindowSettings*)entry;
- float x, y;
+ int x, y;
int i;
- if (sscanf(line, "Pos=%f,%f", &x, &y) == 2) settings->Pos = ImVec2(x, y);
- else if (sscanf(line, "Size=%f,%f", &x, &y) == 2) settings->Size = ImMax(ImVec2(x, y), g.Style.WindowMinSize);
+ if (sscanf(line, "Pos=%i,%i", &x, &y) == 2) settings->Pos = ImVec2ih((short)x, (short)y);
+ else if (sscanf(line, "Size=%i,%i", &x, &y) == 2) settings->Size = ImVec2ih((short)x, (short)y);
else if (sscanf(line, "Collapsed=%d", &i) == 1) settings->Collapsed = (i != 0);
}
@@ -9468,8 +9567,8 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
window->SettingsIdx = g.SettingsWindows.index_from_ptr(settings);
}
IM_ASSERT(settings->ID == window->ID);
- settings->Pos = window->Pos;
- settings->Size = window->SizeFull;
+ settings->Pos = ImVec2ih((short)window->Pos.x, (short)window->Pos.y);
+ settings->Size = ImVec2ih((short)window->SizeFull.x, (short)window->SizeFull.y);
settings->Collapsed = window->Collapsed;
}
@@ -9478,11 +9577,9 @@ static void SettingsHandlerWindow_WriteAll(ImGuiContext* ctx, ImGuiSettingsHandl
for (int i = 0; i != g.SettingsWindows.Size; i++)
{
const ImGuiWindowSettings* settings = &g.SettingsWindows[i];
- if (settings->Pos.x == FLT_MAX)
- continue;
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("Pos=%d,%d\n", settings->Pos.x, settings->Pos.y);
+ buf->appendf("Size=%d,%d\n", settings->Size.x, settings->Size.y);
buf->appendf("Collapsed=%d\n", settings->Collapsed);
buf->appendf("\n");
}
@@ -9598,7 +9695,7 @@ static const char* GetClipboardTextFn_DefaultImpl(void*)
ItemCount item_count = 0;
PasteboardGetItemCount(main_clipboard, &item_count);
- for (int i = 0; i < item_count; i++)
+ for (ItemCount i = 0; i < item_count; i++)
{
PasteboardItemID item_id = 0;
PasteboardGetItemIdentifier(main_clipboard, i + 1, &item_id);
diff --git a/imgui/imgui.h b/imgui/imgui.h
index b7d25947..9697c80d 100644
--- a/imgui/imgui.h
+++ b/imgui/imgui.h
@@ -1,4 +1,4 @@
-// dear imgui, v1.72b
+// dear imgui, v1.73
// (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.72b"
-#define IMGUI_VERSION_NUM 17202
+#define IMGUI_VERSION "1.73"
+#define IMGUI_VERSION_NUM 17300
#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)
@@ -73,8 +73,12 @@ Index of this file:
#define IM_FMTLIST(FMT)
#endif
#define IM_ARRAYSIZE(_ARR) ((int)(sizeof(_ARR)/sizeof(*_ARR))) // Size of a static C-style array. Don't use on pointers!
-#define IM_OFFSETOF(_TYPE,_MEMBER) ((size_t)&(((_TYPE*)0)->_MEMBER)) // Offset of _MEMBER within _TYPE. Standardized as offsetof() in modern C++.
#define IM_UNUSED(_VAR) ((void)_VAR) // Used to silence "unused variable warnings". Often useful as asserts may be stripped out from final builds.
+#if (__cplusplus >= 201100)
+#define IM_OFFSETOF(_TYPE,_MEMBER) offsetof(_TYPE, _MEMBER) // Offset of _MEMBER within _TYPE. Standardized as offsetof() in C++11
+#else
+#define IM_OFFSETOF(_TYPE,_MEMBER) ((size_t)&(((_TYPE*)0)->_MEMBER)) // Offset of _MEMBER within _TYPE. Old style macro.
+#endif
// Warnings
#if defined(__clang__)
@@ -324,7 +328,7 @@ namespace ImGui
IMGUI_API ImU32 GetColorU32(ImU32 col); // retrieve given color with style alpha applied
// Parameters stacks (current window)
- 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 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. NOT necessarily the width of last item unlike most 'Item' functions.
@@ -422,6 +426,8 @@ namespace ImGui
// - For all the Float2/Float3/Float4/Int2/Int3/Int4 versions of every functions, note that a 'float v[X]' function argument is the same as 'float* v', the array syntax is just a way to document the number of elements that are expected to be accessible. You can pass address of your first element out of a contiguous set, e.g. &myvector.x
// - Adjust format string to decorate the value with a prefix, a suffix, or adapt the editing and display precision e.g. "%.3f" -> 1.234; "%5.2f secs" -> 01.23 secs; "Biscuit: %.0f" -> Biscuit: 1; etc.
// - Speed are per-pixel of mouse movement (v_speed=0.2f: mouse needs to move by 5 pixels to increase value by 1). For gamepad/keyboard navigation, minimum speed is Max(v_speed, minimum_step_at_given_precision).
+ // - Use v_min < v_max to clamp edits to given limits. Note that CTRL+Click manual input can override those limits.
+ // - Use v_min > v_max to lock edits.
IMGUI_API bool DragFloat(const char* label, float* v, float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f); // If v_min >= v_max we have no bound
IMGUI_API bool DragFloat2(const char* label, float v[2], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f);
IMGUI_API bool DragFloat3(const char* label, float v[3], float v_speed = 1.0f, float v_min = 0.0f, float v_max = 0.0f, const char* format = "%.3f", float power = 1.0f);
@@ -785,9 +791,10 @@ enum ImGuiTreeNodeFlags_
ImGuiTreeNodeFlags_Leaf = 1 << 8, // No collapsing, no arrow (use as a convenience for leaf nodes).
ImGuiTreeNodeFlags_Bullet = 1 << 9, // Display a bullet instead of arrow
ImGuiTreeNodeFlags_FramePadding = 1 << 10, // Use FramePadding (even for an unframed text node) to vertically align text baseline to regular widget height. Equivalent to calling AlignTextToFramePadding().
- //ImGuiTreeNodeFlags_SpanAllAvailWidth = 1 << 11, // FIXME: TODO: Extend hit box horizontally even if not framed
- //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 12, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible
+ ImGuiTreeNodeFlags_SpanAvailWidth = 1 << 11, // Extend hit box to the right-most edge, even if not framed. This is not the default in order to allow adding other items on the same line. In the future we may refactor the hit system to be front-to-back, allowing natural overlaps and then this can become the default.
+ ImGuiTreeNodeFlags_SpanFullWidth = 1 << 12, // Extend hit box to the left-most and right-most edges (bypass the indented area).
ImGuiTreeNodeFlags_NavLeftJumpsBackHere = 1 << 13, // (WIP) Nav: left direction may move to this TreeNode() from any of its child (items submitted between TreeNode and TreePop)
+ //ImGuiTreeNodeFlags_NoScrollOnOpen = 1 << 14, // FIXME: TODO: Disable automatic scroll on TreePop() if node got just open and contents is not visible
ImGuiTreeNodeFlags_CollapsingHeader = ImGuiTreeNodeFlags_Framed | ImGuiTreeNodeFlags_NoTreePushOnOpen | ImGuiTreeNodeFlags_NoAutoOpenOnLog
// Obsolete names (will be removed)
@@ -803,7 +810,8 @@ enum ImGuiSelectableFlags_
ImGuiSelectableFlags_DontClosePopups = 1 << 0, // Clicking this don't close parent popup window
ImGuiSelectableFlags_SpanAllColumns = 1 << 1, // Selectable frame can span all columns (text will still fit in current column)
ImGuiSelectableFlags_AllowDoubleClick = 1 << 2, // Generate press events on double clicks too
- ImGuiSelectableFlags_Disabled = 1 << 3 // Cannot be selected, display grayed out text
+ ImGuiSelectableFlags_Disabled = 1 << 3, // Cannot be selected, display grayed out text
+ ImGuiSelectableFlags_AllowItemOverlap = 1 << 4 // (WIP) Hit testing to allow subsequent widgets to overlap this one
};
// Flags for ImGui::BeginCombo()
@@ -1265,6 +1273,10 @@ struct ImVector
inline T* erase_unsorted(const T* it) { IM_ASSERT(it >= Data && it < Data+Size); const ptrdiff_t off = it - Data; if (it < Data+Size-1) memcpy(Data + off, Data + Size - 1, sizeof(T)); Size--; return Data + off; }
inline T* insert(const T* it, const T& v) { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; if (Size == Capacity) reserve(_grow_capacity(Size + 1)); if (off < (int)Size) memmove(Data + off + 1, Data + off, ((size_t)Size - (size_t)off) * sizeof(T)); memcpy(&Data[off], &v, sizeof(v)); Size++; return Data + off; }
inline bool contains(const T& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data++ == v) return true; return false; }
+ inline T* find(const T& v) { T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data == v) break; else ++data; return data; }
+ inline const T* find(const T& v) const { const T* data = Data; const T* data_end = Data + Size; while (data < data_end) if (*data == v) break; else ++data; return data; }
+ inline bool find_erase(const T& v) { const T* it = find(v); if (it < Data + Size) { erase(it); return true; } return false; }
+ inline bool find_erase_unsorted(const T& v) { const T* it = find(v); if (it < Data + Size) { erase_unsorted(it); return true; } return false; }
inline int index_from_ptr(const T* it) const { IM_ASSERT(it >= Data && it <= Data+Size); const ptrdiff_t off = it - Data; return (int)off; }
};
@@ -1283,7 +1295,7 @@ struct ImGuiStyle
float WindowBorderSize; // Thickness of border around windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).
ImVec2 WindowMinSize; // Minimum window size. This is a global setting. If you want to constraint individual windows, use SetNextWindowSizeConstraints().
ImVec2 WindowTitleAlign; // Alignment for title bar text. Defaults to (0.0f,0.5f) for left-aligned,vertically centered.
- ImGuiDir WindowMenuButtonPosition; // Side of the collapsing/docking button in the title bar (left/right). Defaults to ImGuiDir_Left.
+ ImGuiDir WindowMenuButtonPosition; // Side of the collapsing/docking button in the title bar (None/Left/Right). Defaults to ImGuiDir_Left.
float ChildRounding; // Radius of child window corners rounding. Set to 0.0f to have rectangular windows.
float ChildBorderSize; // Thickness of border around child windows. Generally set to 0.0f or 1.0f. (Other values are not well tested and more CPU/GPU costly).
float PopupRounding; // Radius of popup window corners rounding. (Note that tooltip windows use WindowRounding)
@@ -1356,6 +1368,7 @@ struct ImGuiIO
bool ConfigInputTextCursorBlink; // = true // Set to false to disable blinking cursor, for users who consider it distracting. (was called: io.OptCursorBlink prior to 1.63)
bool ConfigWindowsResizeFromEdges; // = true // Enable resizing of windows from their edges and from the lower-left corner. This requires (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) because it needs mouse cursor feedback. (This used to be a per-window ImGuiWindowFlags_ResizeFromAnySide flag)
bool ConfigWindowsMoveFromTitleBarOnly; // = false // [BETA] Set to true to only allow moving windows when clicked+dragged from the title bar. Windows without a title bar are not affected.
+ float ConfigWindowsMemoryCompactTimer;// = 60.0f // [BETA] Compact window memory usage when unused. Set to -1.0f to disable.
//------------------------------------------------------------------
// Platform Functions
@@ -1757,7 +1770,7 @@ struct ImColor
// Draw callbacks for advanced uses.
// NB: You most likely do NOT need to use draw callbacks just to create your own widget or customized UI rendering,
-// you can poke into the draw list for that! Draw callback may be useful for example to:
+// you can poke into the draw list for that! Draw callback may be useful for example to:
// A) Change your GPU render state,
// B) render a complex 3D scene inside a UI element without an intermediate texture/render target, etc.
// The expected behavior from your rendering function is 'if (cmd.UserCallback != NULL) { cmd.UserCallback(parent_list, cmd); } else { RenderTriangles() }'
@@ -1785,10 +1798,10 @@ struct ImDrawCmd
ImDrawCallback UserCallback; // If != NULL, call the function instead of rendering the vertices. clip_rect and texture_id will be set normally.
void* UserCallbackData; // The draw callback code can access this.
- ImDrawCmd() { ElemCount = 0; ClipRect.x = ClipRect.y = ClipRect.z = ClipRect.w = 0.0f; TextureId = (ImTextureID)NULL; VtxOffset = IdxOffset = 0; UserCallback = NULL; UserCallbackData = NULL; }
+ ImDrawCmd() { ElemCount = 0; TextureId = (ImTextureID)NULL; VtxOffset = IdxOffset = 0; UserCallback = NULL; UserCallbackData = NULL; }
};
-// Vertex index
+// Vertex index
// (to allow large meshes with 16-bits indices: set 'io.BackendFlags |= ImGuiBackendFlags_RendererHasVtxOffset' and handle ImDrawCmd::VtxOffset in the renderer back-end)
// (to use 32-bits indices: override with '#define ImDrawIdx unsigned int' in imconfig.h)
#ifndef ImDrawIdx
@@ -1819,7 +1832,7 @@ struct ImDrawChannel
};
// Split/Merge functions are used to split the draw list into different layers which can be drawn into out of order.
-// This is used by the Columns api, so items of each column can be batched together in a same draw call.
+// This is used by the Columns api, so items of each column can be batched together in a same draw call.
struct ImDrawListSplitter
{
int _Current; // Current channel number (0)
@@ -1860,7 +1873,7 @@ enum ImDrawListFlags_
// Draw command list
// This is the low-level list of polygons that ImGui:: functions are filling. At the end of the frame,
// all command lists are passed to your ImGuiIO::RenderDrawListFn function for rendering.
-// Each dear imgui window contains its own ImDrawList. You can use ImGui::GetWindowDrawList() to
+// Each dear imgui window contains its own ImDrawList. You can use ImGui::GetWindowDrawList() to
// access the current window draw list and draw custom primitives.
// You can interleave normal ImGui:: calls and adding primitives to the current draw list.
// All positions are generally in pixel coordinates (top-left at (0,0), bottom-right at io.DisplaySize), but you are totally free to apply whatever transformation matrix to want to the data (if you apply such transformation you'll want to apply it to ClipRect as well)
@@ -1897,33 +1910,39 @@ struct ImDrawList
inline ImVec2 GetClipRectMax() const { const ImVec4& cr = _ClipRectStack.back(); return ImVec2(cr.z, cr.w); }
// 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, 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);
- IMGUI_API void AddTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col, float thickness = 1.0f);
- IMGUI_API void AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col);
- IMGUI_API void AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments = 12, float thickness = 1.0f);
- IMGUI_API void AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments = 12);
+ // - For rectangular primitives, "p_min" and "p_max" represent the upper-left and lower-right corners.
+ IMGUI_API void AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness = 1.0f);
+ IMGUI_API void AddRect(const ImVec2& p_min, const ImVec2& p_max, 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& p_min, const ImVec2& p_max, 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& p_min, const ImVec2& p_max, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left);
+ IMGUI_API void AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness = 1.0f);
+ IMGUI_API void AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col);
+ IMGUI_API void AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness = 1.0f);
+ IMGUI_API void AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col);
+ IMGUI_API void AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments = 12, float thickness = 1.0f);
+ IMGUI_API void AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments = 12);
IMGUI_API void AddText(const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL);
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, 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);
+ // Image primitives
+ // - Read FAQ to understand what ImTextureID is.
+ // - "p_min" and "p_max" represent the upper-left and lower-right corners of the rectangle.
+ // - "uv_min" and "uv_max" represent the normalized texture coordinates to use for those corners. Using (0,0)->(1,1) texture coordinates will generally display the entire texture.
+ IMGUI_API void AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min = ImVec2(0, 0), const ImVec2& uv_max = ImVec2(1, 1), ImU32 col = IM_COL32_WHITE);
+ IMGUI_API void AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1 = ImVec2(0, 0), const ImVec2& uv2 = ImVec2(1, 0), const ImVec2& uv3 = ImVec2(1, 1), const ImVec2& uv4 = ImVec2(0, 1), ImU32 col = IM_COL32_WHITE);
+ IMGUI_API void AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All);
+
// Stateful path API, add points then finish with PathFillConvex() or PathStroke()
inline void PathClear() { _Path.Size = 0; }
inline void PathLineTo(const ImVec2& pos) { _Path.push_back(pos); }
inline void PathLineToMergeDuplicate(const ImVec2& pos) { if (_Path.Size == 0 || memcmp(&_Path.Data[_Path.Size-1], &pos, 8) != 0) _Path.push_back(pos); }
inline void PathFillConvex(ImU32 col) { AddConvexPolyFilled(_Path.Data, _Path.Size, col); _Path.Size = 0; } // Note: Anti-aliased filling requires points to be in clockwise order.
inline void PathStroke(ImU32 col, bool closed, float thickness = 1.0f) { AddPolyline(_Path.Data, _Path.Size, col, closed, thickness); _Path.Size = 0; }
- 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 PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments = 10);
+ IMGUI_API void PathArcToFast(const ImVec2& center, 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, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All);
@@ -1998,6 +2017,7 @@ struct ImFontConfig
bool MergeMode; // false // Merge into previous ImFont, so you can combine multiple inputs font into one ImFont (e.g. ASCII font + icons + Japanese glyphs). You may want to use GlyphOffset.y when merge font of different heights.
unsigned int RasterizerFlags; // 0x00 // Settings for custom font rasterizer (e.g. ImGuiFreeType). Leave as zero if you aren't using one.
float RasterizerMultiply; // 1.0f // Brighten (>1.0f) or darken (<1.0f) font output. Brightening small fonts may be a good workaround to make them more readable.
+ ImWchar EllipsisChar; // -1 // Explicitly specify unicode codepoint of ellipsis character. When fonts are being merged first specified ellipsis will be used.
// [Internal]
char Name[40]; // Name (strictly to ease debugging)
@@ -2113,9 +2133,9 @@ struct ImFontAtlas
// [BETA] Custom Rectangles/Glyphs API
//-------------------------------------------
- // You can request arbitrary rectangles to be packed into the atlas, for your own purposes.
+ // You can request arbitrary rectangles to be packed into the atlas, for your own purposes.
// After calling Build(), you can query the rectangle position and render your pixels.
- // You can also request your rectangles to be mapped as font glyph (given a font + Unicode point),
+ // 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.
IMGUI_API int AddCustomRectRegular(unsigned int id, int width, int height); // Id needs to be >= 0x10000. Id >= 0x80000000 are reserved for ImGui and ImDrawList
@@ -2174,7 +2194,8 @@ struct ImFont
ImFontAtlas* ContainerAtlas; // 4-8 // out // // What we has been loaded into
const ImFontConfig* ConfigData; // 4-8 // in // // Pointer within ContainerAtlas->ConfigData
short ConfigDataCount; // 2 // in // ~ 1 // Number of ImFontConfig involved in creating this font. Bigger than 1 when merging multiple font sources into one ImFont.
- ImWchar FallbackChar; // 2 // in // = '?' // Replacement glyph if one isn't found. Only set via SetFallbackChar()
+ ImWchar FallbackChar; // 2 // in // = '?' // Replacement character if a glyph isn't found. Only set via SetFallbackChar()
+ ImWchar EllipsisChar; // 2 // out // = -1 // Character used for ellipsis rendering.
float Scale; // 4 // in // = 1.f // Base font scale, multiplied by the per-window font scale which you can adjust with SetWindowFontScale()
float Ascent, Descent; // 4+4 // out // // Ascent: distance from top to bottom of e.g. 'A' [0..FontSize]
int MetricsTotalSurface;// 4 // out // // Total surface in pixels to get an idea of the font rasterization/texture cost (not exact, we approximate the cost of padding between glyphs)
diff --git a/imgui/imgui_demo.cpp b/imgui/imgui_demo.cpp
index 89e0f302..ec1ada82 100644
--- a/imgui/imgui_demo.cpp
+++ b/imgui/imgui_demo.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.72b
+// dear imgui, v1.73
// (demo code)
// Message to the person tempted to delete this file when integrating Dear ImGui into their code base:
@@ -17,7 +17,7 @@
// In this demo code, we frequently we use 'static' variables inside functions. A static variable persist across calls, so it is
// essentially like a global variable but declared inside the scope of the function. We do this as a way to gather code and data
// in the same place, to make the demo source code faster to read, faster to write, and smaller in size.
-// It also happens to be a convenient way of storing simple UI related information as long as your function doesn't need to be
+// It also happens to be a convenient way of storing simple UI related information as long as your function doesn't need to be
// reentrant or used in multiple threads. This might be a pattern you will want to use in your code, but most of the real data
// you would be editing is likely going to be stored outside your functions.
@@ -106,8 +106,6 @@ Index of this file:
#define IM_NEWLINE "\n"
#endif
-#define IM_MAX(_A,_B) (((_A) >= (_B)) ? (_A) : (_B))
-
//-----------------------------------------------------------------------------
// [SECTION] Forward Declarations, Helpers
//-----------------------------------------------------------------------------
@@ -153,8 +151,11 @@ void ImGui::ShowUserGuide()
{
ImGuiIO& io = ImGui::GetIO();
ImGui::BulletText("Double-click on title bar to collapse window.");
- ImGui::BulletText("Click and drag on lower right corner to resize window\n(double-click to auto fit window to its contents).");
- ImGui::BulletText("Click and drag on any empty space to move window.");
+ ImGui::BulletText("Click and drag on lower corner to resize window\n(double-click to auto fit window to its contents).");
+ if (io.ConfigWindowsMoveFromTitleBarOnly)
+ ImGui::BulletText("Click and drag on title bar to move window.");
+ else
+ ImGui::BulletText("Click and drag on any empty space to move window.");
ImGui::BulletText("TAB/SHIFT+TAB to cycle through keyboard editable fields.");
ImGui::BulletText("CTRL+Click on a slider or drag box to input value as text.");
if (io.FontAllowUserScaling)
@@ -175,6 +176,12 @@ void ImGui::ShowUserGuide()
//-----------------------------------------------------------------------------
// [SECTION] Demo Window / ShowDemoWindow()
//-----------------------------------------------------------------------------
+// - ShowDemoWindowWidgets()
+// - ShowDemoWindowLayout()
+// - ShowDemoWindowPopups()
+// - ShowDemoWindowColumns()
+// - ShowDemoWindowMisc()
+//-----------------------------------------------------------------------------
// We split the contents of the big ShowDemoWindow() function into smaller functions (because the link time of very large functions grow non-linearly)
static void ShowDemoWindowWidgets();
@@ -216,7 +223,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
if (show_app_window_titles) ShowExampleAppWindowTitles(&show_app_window_titles);
if (show_app_custom_rendering) ShowExampleAppCustomRendering(&show_app_custom_rendering);
- // Dear ImGui Apps (accessible from the "Help" menu)
+ // Dear ImGui Apps (accessible from the "Tools" menu)
static bool show_app_metrics = false;
static bool show_app_style_editor = false;
static bool show_app_about = false;
@@ -289,7 +296,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::MenuItem("Documents", NULL, &show_app_documents);
ImGui::EndMenu();
}
- if (ImGui::BeginMenu("Help"))
+ if (ImGui::BeginMenu("Tools"))
{
ImGui::MenuItem("Metrics", NULL, &show_app_metrics);
ImGui::MenuItem("Style Editor", NULL, &show_app_style_editor);
@@ -307,7 +314,7 @@ void ImGui::ShowDemoWindow(bool* p_open)
ImGui::Text("PROGRAMMER GUIDE:");
ImGui::BulletText("Please see the ShowDemoWindow() code in imgui_demo.cpp. <- you are here!");
ImGui::BulletText("Please see the comments in imgui.cpp.");
- ImGui::BulletText("Please see the examples/ in application.");
+ ImGui::BulletText("Please see the examples/ application.");
ImGui::BulletText("Enable 'io.ConfigFlags |= NavEnableKeyboard' for keyboard controls.");
ImGui::BulletText("Enable 'io.ConfigFlags |= NavEnableGamepad' for gamepad controls.");
ImGui::Separator();
@@ -589,7 +596,7 @@ static void ShowDemoWindowWidgets()
{
for (int i = 0; i < 5; i++)
{
- // Use SetNextItemOpen() so set the default state of a node to be open.
+ // Use SetNextItemOpen() so set the default state of a node to be open.
// We could also use TreeNodeEx() with the ImGuiTreeNodeFlags_DefaultOpen flag to achieve the same thing!
if (i == 0)
ImGui::SetNextItemOpen(true, ImGuiCond_Once);
@@ -608,7 +615,12 @@ static void ShowDemoWindowWidgets()
if (ImGui::TreeNode("Advanced, with Selectable nodes"))
{
HelpMarker("This is a more typical looking tree with selectable nodes.\nClick to select, CTRL+Click to toggle, click on arrows or double-click to open.");
+ static ImGuiTreeNodeFlags base_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_SpanAvailWidth;
static bool align_label_with_current_x_position = false;
+ ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnArrow", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_OpenOnArrow);
+ ImGui::CheckboxFlags("ImGuiTreeNodeFlags_OpenOnDoubleClick", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_OpenOnDoubleClick);
+ ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanAvailWidth", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_SpanAvailWidth);
+ ImGui::CheckboxFlags("ImGuiTreeNodeFlags_SpanFullWidth", (unsigned int*)&base_flags, ImGuiTreeNodeFlags_SpanFullWidth);
ImGui::Checkbox("Align label with current X position)", &align_label_with_current_x_position);
ImGui::Text("Hello!");
if (align_label_with_current_x_position)
@@ -616,12 +628,12 @@ static void ShowDemoWindowWidgets()
static int selection_mask = (1 << 2); // Dumb representation of what may be user-side selection state. You may carry selection state inside or outside your objects in whatever format you see fit.
int node_clicked = -1; // Temporary storage of what node we have clicked to process selection at the end of the loop. May be a pointer to your own node type, etc.
- ImGui::PushStyleVar(ImGuiStyleVar_IndentSpacing, ImGui::GetFontSize()*3); // Increase spacing to differentiate leaves from expanded contents.
for (int i = 0; i < 6; i++)
{
// Disable the default open on single-click behavior and pass in Selected flag according to our selection state.
- ImGuiTreeNodeFlags node_flags = ImGuiTreeNodeFlags_OpenOnArrow | ImGuiTreeNodeFlags_OpenOnDoubleClick;
- if (selection_mask & (1 << i))
+ ImGuiTreeNodeFlags node_flags = base_flags;
+ const bool is_selected = (selection_mask & (1 << i)) != 0;
+ if (is_selected)
node_flags |= ImGuiTreeNodeFlags_Selected;
if (i < 3)
{
@@ -631,7 +643,7 @@ static void ShowDemoWindowWidgets()
node_clicked = i;
if (node_open)
{
- ImGui::Text("Blah blah\nBlah Blah");
+ ImGui::BulletText("Blah blah\nBlah Blah");
ImGui::TreePop();
}
}
@@ -654,7 +666,6 @@ static void ShowDemoWindowWidgets()
else //if (!(selection_mask & (1 << node_clicked))) // Depending on selection behavior you want, this commented bit preserve selection when clicking on item that is part of the selection
selection_mask = (1 << node_clicked); // Click to single-select
}
- ImGui::PopStyleVar();
if (align_label_with_current_x_position)
ImGui::Indent(ImGui::GetTreeNodeToLabelSpacing());
ImGui::TreePop();
@@ -666,7 +677,7 @@ static void ShowDemoWindowWidgets()
{
static bool closable_group = true;
ImGui::Checkbox("Show 2nd header", &closable_group);
- if (ImGui::CollapsingHeader("Header"))
+ if (ImGui::CollapsingHeader("Header", ImGuiTreeNodeFlags_None))
{
ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
for (int i = 0; i < 5; i++)
@@ -678,6 +689,10 @@ static void ShowDemoWindowWidgets()
for (int i = 0; i < 5; i++)
ImGui::Text("More content %d", i);
}
+ /*
+ if (ImGui::CollapsingHeader("Header with a bullet", ImGuiTreeNodeFlags_Bullet))
+ ImGui::Text("IsItemHovered: %d", ImGui::IsItemHovered());
+ */
ImGui::TreePop();
}
@@ -685,6 +700,11 @@ static void ShowDemoWindowWidgets()
{
ImGui::BulletText("Bullet point 1");
ImGui::BulletText("Bullet point 2\nOn multiple lines");
+ if (ImGui::TreeNode("Tree node"))
+ {
+ ImGui::BulletText("Another bullet point");
+ ImGui::TreePop();
+ }
ImGui::Bullet(); ImGui::Text("Bullet point 3 (two calls)");
ImGui::Bullet(); ImGui::SmallButton("Button");
ImGui::TreePop();
@@ -759,7 +779,7 @@ static void ShowDemoWindowWidgets()
// Here we are grabbing the font texture because that's the only one we have access to inside the demo code.
// Remember that ImTextureID is just storage for whatever you want it to be, it is essentially a value that will be passed to the render function inside the ImDrawCmd structure.
// If you use one of the default imgui_impl_XXXX.cpp renderer, they all have comments at the top of their file to specify what they expect to be stored in ImTextureID.
- // (for example, the imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer. The imgui_impl_glfw_gl3.cpp renderer expect a GLuint OpenGL texture identifier etc.)
+ // (for example, the imgui_impl_dx11.cpp renderer expect a 'ID3D11ShaderResourceView*' pointer. The imgui_impl_opengl3.cpp renderer expect a GLuint OpenGL texture identifier etc.)
// If you decided that ImTextureID = MyEngineTexture*, then you can pass your MyEngineTexture* pointers to ImGui::Image(), and gather width/height through your own functions, etc.
// Using ShowMetricsWindow() as a "debugger" to inspect the draw data that are being passed to your render will help you debug issues if you are confused about this.
// Consider using the lower-level ImDrawList::AddImage() API, via ImGui::GetWindowDrawList()->AddImage().
@@ -1043,6 +1063,8 @@ static void ShowDemoWindowWidgets()
ImGui::TreePop();
}
+ // Plot/Graph widgets are currently fairly limited.
+ // Consider writing your own plotting widget, or using a third-party one (see "Wiki->Useful Widgets", or github.com/ocornut/imgui/issues/2747)
if (ImGui::TreeNode("Plots Widgets"))
{
static bool animate = true;
@@ -1066,7 +1088,18 @@ static void ShowDemoWindowWidgets()
phase += 0.10f*values_offset;
refresh_time += 1.0f/60.0f;
}
- ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, "avg 0.0", -1.0f, 1.0f, ImVec2(0,80));
+
+ // Plots can display overlay texts
+ // (in this example, we will display an average value)
+ {
+ float average = 0.0f;
+ for (int n = 0; n < IM_ARRAYSIZE(values); n++)
+ average += values[n];
+ average /= (float)IM_ARRAYSIZE(values);
+ char overlay[32];
+ sprintf(overlay, "avg %f", average);
+ ImGui::PlotLines("Lines", values, IM_ARRAYSIZE(values), values_offset, overlay, -1.0f, 1.0f, ImVec2(0,80));
+ }
ImGui::PlotHistogram("Histogram", arr, IM_ARRAYSIZE(arr), 0, NULL, 0.0f, 1.0f, ImVec2(0,80));
// Use functions to generate output
@@ -1096,7 +1129,7 @@ static void ShowDemoWindowWidgets()
if (progress <= -0.1f) { progress = -0.1f; progress_dir *= -1.0f; }
}
- // Typically we would use ImVec2(-1.0f,0.0f) or ImVec2(-FLT_MIN,0.0f) to use all available width,
+ // 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);
@@ -1438,7 +1471,7 @@ static void ShowDemoWindowWidgets()
ImGui::PushID("set2");
static float values2[4] = { 0.20f, 0.80f, 0.40f, 0.25f };
const int rows = 3;
- const ImVec2 small_slider_size(18, (160.0f-(rows-1)*spacing)/rows);
+ const ImVec2 small_slider_size(18, (float)(int)((160.0f - (rows - 1) * spacing) / rows));
for (int nx = 0; nx < 4; nx++)
{
if (nx > 0) ImGui::SameLine();
@@ -1478,6 +1511,8 @@ static void ShowDemoWindowWidgets()
// They are using standardized payload strings IMGUI_PAYLOAD_TYPE_COLOR_3F and IMGUI_PAYLOAD_TYPE_COLOR_4F to allow your own widgets
// to use colors in their drag and drop interaction. Also see the demo in Color Picker -> Palette demo.
ImGui::BulletText("Drag and drop in standard widgets");
+ ImGui::SameLine();
+ HelpMarker("You can drag from the colored squares.");
ImGui::Indent();
static float col1[3] = { 1.0f,0.0f,0.2f };
static float col2[4] = { 0.4f,0.7f,0.0f,0.5f };
@@ -1510,8 +1545,8 @@ static void ShowDemoWindowWidgets()
// Our buttons are both drag sources and drag targets here!
if (ImGui::BeginDragDropSource(ImGuiDragDropFlags_None))
{
- ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int)); // Set payload to carry the index of our item (could be anything)
- if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); } // Display preview (could be anything, e.g. when dragging an image we could decide to display the filename and a small preview of the image, etc.)
+ ImGui::SetDragDropPayload("DND_DEMO_CELL", &n, sizeof(int)); // Set payload to carry the index of our item (could be anything)
+ if (mode == Mode_Copy) { ImGui::Text("Copy %s", names[n]); } // Display preview (could be anything, e.g. when dragging an image we could decide to display the filename and a small preview of the image, etc.)
if (mode == Mode_Move) { ImGui::Text("Move %s", names[n]); }
if (mode == Mode_Swap) { ImGui::Text("Swap %s", names[n]); }
ImGui::EndDragDropSource();
@@ -1550,19 +1585,18 @@ static void ShowDemoWindowWidgets()
if (ImGui::TreeNode("Querying Status (Active/Focused/Hovered etc.)"))
{
- // Display the value of IsItemHovered() and other common item state functions. Note that the flags can be combined.
- // (because BulletText is an item itself and that would affect the output of IsItemHovered() we pass all state in a single call to simplify the code).
+ // Submit an item (various types available) so we can query their status in the following block.
static int item_type = 1;
- static bool b = false;
- static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f };
- static char str[16] = {};
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;
+ static bool b = false;
+ static float col4f[4] = { 1.0f, 0.5, 0.0f, 1.0f };
+ static char str[16] = {};
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) { ImGui::PushButtonRepeat(true); ret = ImGui::Button("ITEM: Button"); ImGui::PopButtonRepeat(); } // Testing button (with repeater)
+ 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)
@@ -1572,6 +1606,11 @@ static void ShowDemoWindowWidgets()
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)); }
+
+ // Display the value of IsItemHovered() and other common item state functions.
+ // Note that the ImGuiHoveredFlags_XXX flags can be combined.
+ // Because BulletText is an item itself and that would affect the output of IsItemXXX functions,
+ // we query every state in a single call to avoid storing them and to simplify the code
ImGui::BulletText(
"Return value = %d\n"
"IsItemFocused() = %d\n"
@@ -1614,7 +1653,8 @@ static void ShowDemoWindowWidgets()
if (embed_all_inside_a_child_window)
ImGui::BeginChild("outer_child", ImVec2(0, ImGui::GetFontSize() * 20), true);
- // Testing IsWindowFocused() function with its various flags. Note that the flags can be combined.
+ // Testing IsWindowFocused() function with its various flags.
+ // Note that the ImGuiFocusedFlags_XXX flags can be combined.
ImGui::BulletText(
"IsWindowFocused() = %d\n"
"IsWindowFocused(_ChildWindows) = %d\n"
@@ -1627,7 +1667,8 @@ static void ShowDemoWindowWidgets()
ImGui::IsWindowFocused(ImGuiFocusedFlags_RootWindow),
ImGui::IsWindowFocused(ImGuiFocusedFlags_AnyWindow));
- // Testing IsWindowHovered() function with its various flags. Note that the flags can be combined.
+ // Testing IsWindowHovered() function with its various flags.
+ // Note that the ImGuiHoveredFlags_XXX flags can be combined.
ImGui::BulletText(
"IsWindowHovered() = %d\n"
"IsWindowHovered(_AllowWhenBlockedByPopup) = %d\n"
@@ -2246,7 +2287,7 @@ static void ShowDemoWindowLayout()
ImGui::SameLine();
ImGui::SetNextItemWidth(100);
ImGui::DragFloat("##csx", &contents_size_x);
- ImVec2 p = ImGui::GetCursorScreenPos();
+ ImVec2 p = ImGui::GetCursorScreenPos();
ImGui::GetWindowDrawList()->AddRectFilled(p, ImVec2(p.x + 10, p.y + 10), IM_COL32_WHITE);
ImGui::GetWindowDrawList()->AddRectFilled(ImVec2(p.x + contents_size_x - 10, p.y), ImVec2(p.x + contents_size_x, p.y + 10), IM_COL32_WHITE);
ImGui::Dummy(ImVec2(0, 10));
@@ -2781,6 +2822,8 @@ static void ShowDemoWindowMisc()
{
if (ImGui::CollapsingHeader("Filtering"))
{
+ // Helper class to easy setup a text filter.
+ // You may want to implement a more feature-full filtering scheme in your own application.
static ImGuiTextFilter filter;
ImGui::Text("Filter usage:\n"
" \"\" display all lines\n"
@@ -2798,12 +2841,14 @@ static void ShowDemoWindowMisc()
{
ImGuiIO& io = ImGui::GetIO();
+ // Display ImGuiIO output flags
ImGui::Text("WantCaptureMouse: %d", io.WantCaptureMouse);
ImGui::Text("WantCaptureKeyboard: %d", io.WantCaptureKeyboard);
ImGui::Text("WantTextInput: %d", io.WantTextInput);
ImGui::Text("WantSetMousePos: %d", io.WantSetMousePos);
ImGui::Text("NavActive: %d, NavVisible: %d", io.NavActive, io.NavVisible);
+ // Display Keyboard/Mouse state
if (ImGui::TreeNode("Keyboard, Mouse & Navigation State"))
{
if (ImGui::IsMousePosValid())
@@ -2936,7 +2981,7 @@ static void ShowDemoWindowMisc()
//-----------------------------------------------------------------------------
// [SECTION] About Window / ShowAboutWindow()
-// Access from Dear ImGui Demo -> Help -> About
+// Access from Dear ImGui Demo -> Tools -> About
//-----------------------------------------------------------------------------
void ImGui::ShowAboutWindow(bool* p_open)
@@ -2948,7 +2993,7 @@ void ImGui::ShowAboutWindow(bool* p_open)
}
ImGui::Text("Dear ImGui %s", ImGui::GetVersion());
ImGui::Separator();
- ImGui::Text("By Omar Cornut and all dear imgui contributors.");
+ ImGui::Text("By Omar Cornut and all Dear ImGui contributors.");
ImGui::Text("Dear ImGui is licensed under the MIT License, see LICENSE for more information.");
static bool show_config_info = false;
@@ -2961,7 +3006,10 @@ void ImGui::ShowAboutWindow(bool* p_open)
bool copy_to_clipboard = ImGui::Button("Copy to clipboard");
ImGui::BeginChildFrame(ImGui::GetID("cfginfos"), ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 18), ImGuiWindowFlags_NoMove);
if (copy_to_clipboard)
+ {
ImGui::LogToClipboard();
+ ImGui::LogText("```\n"); // Back quotes will make the text appears without formatting when pasting to GitHub
+ }
ImGui::Text("Dear ImGui %s (%d)", IMGUI_VERSION, IMGUI_VERSION_NUM);
ImGui::Separator();
@@ -3033,6 +3081,7 @@ void ImGui::ShowAboutWindow(bool* p_open)
if (io.ConfigInputTextCursorBlink) ImGui::Text("io.ConfigInputTextCursorBlink");
if (io.ConfigWindowsResizeFromEdges) ImGui::Text("io.ConfigWindowsResizeFromEdges");
if (io.ConfigWindowsMoveFromTitleBarOnly) ImGui::Text("io.ConfigWindowsMoveFromTitleBarOnly");
+ if (io.ConfigWindowsMemoryCompactTimer >= 0.0f) ImGui::Text("io.ConfigWindowsMemoryCompactTimer = %.1ff", io.ConfigWindowsMemoryCompactTimer);
ImGui::Text("io.BackendFlags: 0x%08X", io.BackendFlags);
if (io.BackendFlags & ImGuiBackendFlags_HasGamepad) ImGui::Text(" HasGamepad");
if (io.BackendFlags & ImGuiBackendFlags_HasMouseCursors) ImGui::Text(" HasMouseCursors");
@@ -3052,7 +3101,10 @@ void ImGui::ShowAboutWindow(bool* p_open)
ImGui::Text("style.ItemInnerSpacing: %.2f,%.2f", style.ItemInnerSpacing.x, style.ItemInnerSpacing.y);
if (copy_to_clipboard)
+ {
+ ImGui::LogText("\n```\n");
ImGui::LogFinish();
+ }
ImGui::EndChildFrame();
}
ImGui::End();
@@ -3061,6 +3113,10 @@ void ImGui::ShowAboutWindow(bool* p_open)
//-----------------------------------------------------------------------------
// [SECTION] Style Editor / ShowStyleEditor()
//-----------------------------------------------------------------------------
+// - ShowStyleSelector()
+// - ShowFontSelector()
+// - ShowStyleEditor()
+//-----------------------------------------------------------------------------
// Demo helper function to select among default colors. See ShowStyleEditor() for more advanced options.
// Here we use the simplified Combo() api that packs items into a single literal string. Useful for quick combo boxes where the choices are known locally.
@@ -3175,7 +3231,9 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::SliderFloat("TabRounding", &style.TabRounding, 0.0f, 12.0f, "%.0f");
ImGui::Text("Alignment");
ImGui::SliderFloat2("WindowTitleAlign", (float*)&style.WindowTitleAlign, 0.0f, 1.0f, "%.2f");
- ImGui::Combo("WindowMenuButtonPosition", (int*)&style.WindowMenuButtonPosition, "Left\0Right\0");
+ int window_menu_button_position = style.WindowMenuButtonPosition + 1;
+ if (ImGui::Combo("WindowMenuButtonPosition", (int*)&window_menu_button_position, "None\0Left\0Right\0"))
+ style.WindowMenuButtonPosition = window_menu_button_position - 1;
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.");
@@ -3263,7 +3321,8 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
ImGui::SameLine(); HelpMarker("Note than the default embedded font is NOT meant to be scaled.\n\nFont are currently rendered into bitmaps at a given size at the time of building the atlas. You may oversample them to get some flexibility with scaling. You can also render at multiple sizes and select which one to use at runtime.\n\n(Glimmer of hope: the atlas system should hopefully be rewritten in the future to make scaling more natural and automatic.)");
ImGui::InputFloat("Font offset", &font->DisplayOffset.y, 1, 1, "%.0f");
ImGui::Text("Ascent: %f, Descent: %f, Height: %f", font->Ascent, font->Descent, font->Ascent - font->Descent);
- ImGui::Text("Fallback character: '%c' (%d)", font->FallbackChar, font->FallbackChar);
+ ImGui::Text("Fallback character: '%c' (U+%04X)", font->FallbackChar, font->FallbackChar);
+ ImGui::Text("Ellipsis character: '%c' (U+%04X)", font->EllipsisChar, font->EllipsisChar);
const float surface_sqrt = sqrtf((float)font->MetricsTotalSurface);
ImGui::Text("Texture surface: %d pixels (approx) ~ %dx%d", font->MetricsTotalSurface, (int)surface_sqrt, (int)surface_sqrt);
for (int config_i = 0; config_i < font->ConfigDataCount; config_i++)
@@ -3352,6 +3411,9 @@ void ImGui::ShowStyleEditor(ImGuiStyle* ref)
//-----------------------------------------------------------------------------
// [SECTION] Example App: Main Menu Bar / ShowExampleAppMainMenuBar()
//-----------------------------------------------------------------------------
+// - ShowExampleAppMainMenuBar()
+// - ShowExampleMenuFile()
+//-----------------------------------------------------------------------------
// Demonstrate creating a "main" fullscreen menu bar and populating it.
// Note the difference between BeginMainMenuBar() and BeginMenuBar():
@@ -4147,7 +4209,7 @@ static void ShowExampleAppConstrainedResize(bool* p_open)
{
struct CustomConstraints // Helper functions to demonstrate programmatic constraints
{
- static void Square(ImGuiSizeCallbackData* data) { data->DesiredSize = ImVec2(IM_MAX(data->DesiredSize.x, data->DesiredSize.y), IM_MAX(data->DesiredSize.x, data->DesiredSize.y)); }
+ static void Square(ImGuiSizeCallbackData* data) { data->DesiredSize.x = data->DesiredSize.y = (data->DesiredSize.x > data->DesiredSize.y ? data->DesiredSize.x : data->DesiredSize.y); }
static void Step(ImGuiSizeCallbackData* data) { float step = (float)(int)(intptr_t)data->UserData; data->DesiredSize = ImVec2((int)(data->DesiredSize.x / step + 0.5f) * step, (int)(data->DesiredSize.y / step + 0.5f) * step); }
};
@@ -4266,7 +4328,6 @@ static void ShowExampleAppWindowTitles(bool*)
// Demonstrate using the low-level ImDrawList to draw custom shapes.
static void ShowExampleAppCustomRendering(bool* p_open)
{
- ImGui::SetNextWindowSize(ImVec2(350, 560), ImGuiCond_FirstUseEver);
if (!ImGui::Begin("Example: Custom rendering", p_open))
{
ImGui::End();
@@ -4386,14 +4447,16 @@ static void ShowExampleAppCustomRendering(bool* p_open)
static bool draw_bg = true;
static bool draw_fg = true;
ImGui::Checkbox("Draw in Background draw list", &draw_bg);
+ ImGui::SameLine(); HelpMarker("The Background draw list will be rendered below every Dear ImGui windows.");
ImGui::Checkbox("Draw in Foreground draw list", &draw_fg);
+ ImGui::SameLine(); HelpMarker("The Foreground draw list will be rendered over every Dear ImGui windows.");
ImVec2 window_pos = ImGui::GetWindowPos();
ImVec2 window_size = ImGui::GetWindowSize();
ImVec2 window_center = ImVec2(window_pos.x + window_size.x * 0.5f, window_pos.y + window_size.y * 0.5f);
if (draw_bg)
- ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), 32, 10+4);
+ ImGui::GetBackgroundDrawList()->AddCircle(window_center, window_size.x * 0.6f, IM_COL32(255, 0, 0, 200), 48, 10+4);
if (draw_fg)
- ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), 32, 10);
+ ImGui::GetForegroundDrawList()->AddCircle(window_center, window_size.y * 0.6f, IM_COL32(0, 255, 0, 200), 48, 10);
ImGui::EndTabItem();
}
diff --git a/imgui/imgui_draw.cpp b/imgui/imgui_draw.cpp
index 45f997b1..845cd04e 100644
--- a/imgui/imgui_draw.cpp
+++ b/imgui/imgui_draw.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.72b
+// dear imgui, v1.73
// (drawing and font code)
/*
@@ -860,26 +860,26 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun
}
}
-void ImDrawList::PathArcToFast(const ImVec2& centre, float radius, int a_min_of_12, int a_max_of_12)
+void ImDrawList::PathArcToFast(const ImVec2& center, float radius, int a_min_of_12, int a_max_of_12)
{
if (radius == 0.0f || a_min_of_12 > a_max_of_12)
{
- _Path.push_back(centre);
+ _Path.push_back(center);
return;
}
_Path.reserve(_Path.Size + (a_max_of_12 - a_min_of_12 + 1));
for (int a = a_min_of_12; a <= a_max_of_12; a++)
{
const ImVec2& c = _Data->CircleVtx12[a % IM_ARRAYSIZE(_Data->CircleVtx12)];
- _Path.push_back(ImVec2(centre.x + c.x * radius, centre.y + c.y * radius));
+ _Path.push_back(ImVec2(center.x + c.x * radius, center.y + c.y * radius));
}
}
-void ImDrawList::PathArcTo(const ImVec2& centre, float radius, float a_min, float a_max, int num_segments)
+void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, float a_max, int num_segments)
{
if (radius == 0.0f)
{
- _Path.push_back(centre);
+ _Path.push_back(center);
return;
}
@@ -889,7 +889,7 @@ void ImDrawList::PathArcTo(const ImVec2& centre, float radius, float a_min, floa
for (int i = 0; i <= num_segments; i++)
{
const float a = a_min + ((float)i / (float)num_segments) * (a_max - a_min);
- _Path.push_back(ImVec2(centre.x + ImCos(a) * radius, centre.y + ImSin(a) * radius));
+ _Path.push_back(ImVec2(center.x + ImCos(a) * radius, center.y + ImSin(a) * radius));
}
}
@@ -968,44 +968,46 @@ void ImDrawList::PathRect(const ImVec2& a, const ImVec2& b, float rounding, ImDr
}
}
-void ImDrawList::AddLine(const ImVec2& a, const ImVec2& b, ImU32 col, float thickness)
+void ImDrawList::AddLine(const ImVec2& p1, const ImVec2& p2, ImU32 col, float thickness)
{
if ((col & IM_COL32_A_MASK) == 0)
return;
- PathLineTo(a + ImVec2(0.5f,0.5f));
- PathLineTo(b + ImVec2(0.5f,0.5f));
+ PathLineTo(p1 + ImVec2(0.5f, 0.5f));
+ PathLineTo(p2 + ImVec2(0.5f, 0.5f));
PathStroke(col, false, thickness);
}
-// 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, ImDrawCornerFlags rounding_corners, float thickness)
+// p_min = upper-left, p_max = lower-right
+// Note we don't render 1 pixels sized rectangles properly.
+void ImDrawList::AddRect(const ImVec2& p_min, const ImVec2& p_max, 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);
+ PathRect(p_min + ImVec2(0.50f,0.50f), p_max - 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); // Better looking lower-right corner and rounded non-AA shapes.
+ PathRect(p_min + ImVec2(0.50f,0.50f), p_max - 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, ImDrawCornerFlags rounding_corners)
+void ImDrawList::AddRectFilled(const ImVec2& p_min, const ImVec2& p_max, 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);
+ PathRect(p_min, p_max, rounding, rounding_corners);
PathFillConvex(col);
}
else
{
PrimReserve(6, 4);
- PrimRect(a, b, col);
+ PrimRect(p_min, p_max, col);
}
}
-void ImDrawList::AddRectFilledMultiColor(const ImVec2& a, const ImVec2& c, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left)
+// p_min = upper-left, p_max = lower-right
+void ImDrawList::AddRectFilledMultiColor(const ImVec2& p_min, const ImVec2& p_max, ImU32 col_upr_left, ImU32 col_upr_right, ImU32 col_bot_right, ImU32 col_bot_left)
{
if (((col_upr_left | col_upr_right | col_bot_right | col_bot_left) & IM_COL32_A_MASK) == 0)
return;
@@ -1014,77 +1016,77 @@ void ImDrawList::AddRectFilledMultiColor(const ImVec2& a, const ImVec2& c, ImU32
PrimReserve(6, 4);
PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+1)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+2));
PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+2)); PrimWriteIdx((ImDrawIdx)(_VtxCurrentIdx+3));
- PrimWriteVtx(a, uv, col_upr_left);
- PrimWriteVtx(ImVec2(c.x, a.y), uv, col_upr_right);
- PrimWriteVtx(c, uv, col_bot_right);
- PrimWriteVtx(ImVec2(a.x, c.y), uv, col_bot_left);
+ PrimWriteVtx(p_min, uv, col_upr_left);
+ PrimWriteVtx(ImVec2(p_max.x, p_min.y), uv, col_upr_right);
+ PrimWriteVtx(p_max, uv, col_bot_right);
+ PrimWriteVtx(ImVec2(p_min.x, p_max.y), uv, col_bot_left);
}
-void ImDrawList::AddQuad(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col, float thickness)
+void ImDrawList::AddQuad(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness)
{
if ((col & IM_COL32_A_MASK) == 0)
return;
- PathLineTo(a);
- PathLineTo(b);
- PathLineTo(c);
- PathLineTo(d);
+ PathLineTo(p1);
+ PathLineTo(p2);
+ PathLineTo(p3);
+ PathLineTo(p4);
PathStroke(col, true, thickness);
}
-void ImDrawList::AddQuadFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, ImU32 col)
+void ImDrawList::AddQuadFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col)
{
if ((col & IM_COL32_A_MASK) == 0)
return;
- PathLineTo(a);
- PathLineTo(b);
- PathLineTo(c);
- PathLineTo(d);
+ PathLineTo(p1);
+ PathLineTo(p2);
+ PathLineTo(p3);
+ PathLineTo(p4);
PathFillConvex(col);
}
-void ImDrawList::AddTriangle(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col, float thickness)
+void ImDrawList::AddTriangle(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness)
{
if ((col & IM_COL32_A_MASK) == 0)
return;
- PathLineTo(a);
- PathLineTo(b);
- PathLineTo(c);
+ PathLineTo(p1);
+ PathLineTo(p2);
+ PathLineTo(p3);
PathStroke(col, true, thickness);
}
-void ImDrawList::AddTriangleFilled(const ImVec2& a, const ImVec2& b, const ImVec2& c, ImU32 col)
+void ImDrawList::AddTriangleFilled(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col)
{
if ((col & IM_COL32_A_MASK) == 0)
return;
- PathLineTo(a);
- PathLineTo(b);
- PathLineTo(c);
+ PathLineTo(p1);
+ PathLineTo(p2);
+ PathLineTo(p3);
PathFillConvex(col);
}
-void ImDrawList::AddCircle(const ImVec2& centre, float radius, ImU32 col, int num_segments, float thickness)
+void ImDrawList::AddCircle(const ImVec2& center, float radius, ImU32 col, int num_segments, float thickness)
{
if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
return;
// Because we are filling a closed shape we remove 1 from the count of segments/points
- const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
- PathArcTo(centre, radius-0.5f, 0.0f, a_max, num_segments - 1);
+ const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
+ PathArcTo(center, radius - 0.5f, 0.0f, a_max, num_segments - 1);
PathStroke(col, true, thickness);
}
-void ImDrawList::AddCircleFilled(const ImVec2& centre, float radius, ImU32 col, int num_segments)
+void ImDrawList::AddCircleFilled(const ImVec2& center, float radius, ImU32 col, int num_segments)
{
if ((col & IM_COL32_A_MASK) == 0 || num_segments <= 2)
return;
// Because we are filling a closed shape we remove 1 from the count of segments/points
- const float a_max = IM_PI*2.0f * ((float)num_segments - 1.0f) / (float)num_segments;
- PathArcTo(centre, radius, 0.0f, a_max, num_segments - 1);
+ const float a_max = (IM_PI * 2.0f) * ((float)num_segments - 1.0f) / (float)num_segments;
+ PathArcTo(center, radius, 0.0f, a_max, num_segments - 1);
PathFillConvex(col);
}
@@ -1132,7 +1134,7 @@ void ImDrawList::AddText(const ImVec2& pos, ImU32 col, const char* text_begin, c
AddText(NULL, 0.0f, pos, col, text_begin, text_end);
}
-void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& uv_a, const ImVec2& uv_b, ImU32 col)
+void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col)
{
if ((col & IM_COL32_A_MASK) == 0)
return;
@@ -1142,13 +1144,13 @@ void ImDrawList::AddImage(ImTextureID user_texture_id, const ImVec2& a, const Im
PushTextureID(user_texture_id);
PrimReserve(6, 4);
- PrimRectUV(a, b, uv_a, uv_b, col);
+ PrimRectUV(p_min, p_max, uv_min, uv_max, col);
if (push_texture_id)
PopTextureID();
}
-void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& d, const ImVec2& uv_a, const ImVec2& uv_b, const ImVec2& uv_c, const ImVec2& uv_d, ImU32 col)
+void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& uv1, const ImVec2& uv2, const ImVec2& uv3, const ImVec2& uv4, ImU32 col)
{
if ((col & IM_COL32_A_MASK) == 0)
return;
@@ -1158,20 +1160,20 @@ void ImDrawList::AddImageQuad(ImTextureID user_texture_id, const ImVec2& a, cons
PushTextureID(user_texture_id);
PrimReserve(6, 4);
- PrimQuadUV(a, b, c, d, uv_a, uv_b, uv_c, uv_d, col);
+ PrimQuadUV(p1, p2, p3, p4, uv1, uv2, uv3, uv4, col);
if (push_texture_id)
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, ImDrawCornerFlags rounding_corners)
+void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& p_min, const ImVec2& p_max, const ImVec2& uv_min, const ImVec2& uv_max, ImU32 col, float rounding, ImDrawCornerFlags rounding_corners)
{
if ((col & IM_COL32_A_MASK) == 0)
return;
if (rounding <= 0.0f || (rounding_corners & ImDrawCornerFlags_All) == 0)
{
- AddImage(user_texture_id, a, b, uv_a, uv_b, col);
+ AddImage(user_texture_id, p_min, p_max, uv_min, uv_max, col);
return;
}
@@ -1180,10 +1182,10 @@ void ImDrawList::AddImageRounded(ImTextureID user_texture_id, const ImVec2& a, c
PushTextureID(user_texture_id);
int vert_start_idx = VtxBuffer.Size;
- PathRect(a, b, rounding, rounding_corners);
+ PathRect(p_min, p_max, rounding, rounding_corners);
PathFillConvex(col);
int vert_end_idx = VtxBuffer.Size;
- ImGui::ShadeVertsLinearUV(this, vert_start_idx, vert_end_idx, a, b, uv_a, uv_b, true);
+ ImGui::ShadeVertsLinearUV(this, vert_start_idx, vert_end_idx, p_min, p_max, uv_min, uv_max, true);
if (push_texture_id)
PopTextureID();
@@ -1200,7 +1202,7 @@ void ImDrawListSplitter::ClearFreeMemory()
{
for (int i = 0; i < _Channels.Size; i++)
{
- if (i == _Current)
+ if (i == _Current)
memset(&_Channels[i], 0, sizeof(_Channels[i])); // Current channel is a copy of CmdBuffer/IdxBuffer, don't destruct again
_Channels[i]._CmdBuffer.clear();
_Channels[i]._IdxBuffer.clear();
@@ -1299,13 +1301,14 @@ void ImDrawListSplitter::Merge(ImDrawList* draw_list)
}
draw_list->_IdxWritePtr = idx_write;
draw_list->UpdateClipRect(); // We call this instead of AddDrawCmd(), so that empty channels won't produce an extra draw call.
+ draw_list->UpdateTextureID();
_Count = 1;
}
void ImDrawListSplitter::SetCurrentChannel(ImDrawList* draw_list, int idx)
{
IM_ASSERT(idx >= 0 && idx < _Count);
- if (_Current == idx)
+ if (_Current == idx)
return;
// Overwrite ImVector (12/16 bytes), four times. This is merely a silly optimization instead of doing .swap()
memcpy(&_Channels.Data[_Current]._CmdBuffer, &draw_list->CmdBuffer, sizeof(draw_list->CmdBuffer));
@@ -1424,6 +1427,7 @@ ImFontConfig::ImFontConfig()
MergeMode = false;
RasterizerFlags = 0x00;
RasterizerMultiply = 1.0f;
+ EllipsisChar = (ImWchar)-1;
memset(Name, 0, sizeof(Name));
DstFont = NULL;
}
@@ -1616,6 +1620,9 @@ ImFont* ImFontAtlas::AddFont(const ImFontConfig* font_cfg)
memcpy(new_font_cfg.FontData, font_cfg->FontData, (size_t)new_font_cfg.FontDataSize);
}
+ if (new_font_cfg.DstFont->EllipsisChar == (ImWchar)-1)
+ new_font_cfg.DstFont->EllipsisChar = font_cfg->EllipsisChar;
+
// Invalidate texture
ClearTexData();
return new_font_cfg.DstFont;
@@ -1650,6 +1657,7 @@ ImFont* ImFontAtlas::AddFontDefault(const ImFontConfig* font_cfg_template)
font_cfg.SizePixels = 13.0f * 1.0f;
if (font_cfg.Name[0] == '\0')
ImFormatString(font_cfg.Name, IM_ARRAYSIZE(font_cfg.Name), "ProggyClean.ttf, %dpx", (int)font_cfg.SizePixels);
+ font_cfg.EllipsisChar = (ImWchar)0x0085;
const char* ttf_compressed_base85 = GetDefaultCompressedFontDataTTFBase85();
const ImWchar* glyph_ranges = font_cfg.GlyphRanges != NULL ? font_cfg.GlyphRanges : GetGlyphRangesDefault();
@@ -2194,6 +2202,23 @@ void ImFontAtlasBuildFinish(ImFontAtlas* atlas)
for (int i = 0; i < atlas->Fonts.Size; i++)
if (atlas->Fonts[i]->DirtyLookupTables)
atlas->Fonts[i]->BuildLookupTable();
+
+ // Ellipsis character is required for rendering elided text. We prefer using U+2026 (horizontal ellipsis).
+ // However some old fonts may contain ellipsis at U+0085. Here we auto-detect most suitable ellipsis character.
+ // FIXME: Also note that 0x2026 is currently seldomly included in our font ranges. Because of this we are more likely to use three individual dots.
+ for (int i = 0; i < atlas->Fonts.size(); i++)
+ {
+ ImFont* font = atlas->Fonts[i];
+ if (font->EllipsisChar != (ImWchar)-1)
+ continue;
+ const ImWchar ellipsis_variants[] = { (ImWchar)0x2026, (ImWchar)0x0085 };
+ for (int j = 0; j < IM_ARRAYSIZE(ellipsis_variants); j++)
+ if (font->FindGlyphNoFallback(ellipsis_variants[j]) != NULL) // Verify glyph exists
+ {
+ font->EllipsisChar = ellipsis_variants[j];
+ break;
+ }
+ }
}
// Retrieve list of range (2 int per range, values are inclusive)
@@ -2463,6 +2488,7 @@ ImFont::ImFont()
FontSize = 0.0f;
FallbackAdvanceX = 0.0f;
FallbackChar = (ImWchar)'?';
+ EllipsisChar = (ImWchar)-1;
DisplayOffset = ImVec2(0.0f, 0.0f);
FallbackGlyph = NULL;
ContainerAtlas = NULL;
@@ -3010,19 +3036,14 @@ void ImFont::RenderText(ImDrawList* draw_list, float size, ImVec2 pos, ImU32 col
// - RenderMouseCursor()
// - RenderArrowPointingAt()
// - RenderRectFilledRangeH()
-// - RenderPixelEllipsis()
//-----------------------------------------------------------------------------
-void ImGui::RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor)
+void ImGui::RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow)
{
if (mouse_cursor == ImGuiMouseCursor_None)
return;
IM_ASSERT(mouse_cursor > ImGuiMouseCursor_None && mouse_cursor < ImGuiMouseCursor_COUNT);
- const ImU32 col_shadow = IM_COL32(0, 0, 0, 48);
- const ImU32 col_border = IM_COL32(0, 0, 0, 255); // Black
- const ImU32 col_fill = IM_COL32(255, 255, 255, 255); // White
-
ImFontAtlas* font_atlas = draw_list->_Data->Font->ContainerAtlas;
ImVec2 offset, size, uv[4];
if (font_atlas->GetMouseCursorTexData(mouse_cursor, &offset, &size, &uv[0], &uv[2]))
@@ -3120,18 +3141,6 @@ void ImGui::RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, Im
draw_list->PathFillConvex(col);
}
-// FIXME: Rendering an ellipsis "..." is a surprisingly tricky problem for us... we cannot rely on font glyph having it,
-// and regular dot are typically too wide. If we render a dot/shape ourselves it comes with the risk that it wouldn't match
-// the boldness or positioning of what the font uses...
-void ImGui::RenderPixelEllipsis(ImDrawList* draw_list, ImVec2 pos, ImU32 col, int count)
-{
- ImFont* font = draw_list->_Data->Font;
- const float font_scale = draw_list->_Data->FontSize / font->FontSize;
- pos.y += (float)(int)(font->DisplayOffset.y + font->Ascent * font_scale + 0.5f - 1.0f);
- for (int dot_n = 0; dot_n < count; dot_n++)
- draw_list->AddRectFilled(ImVec2(pos.x + dot_n * 2.0f, pos.y), ImVec2(pos.x + dot_n * 2.0f + 1.0f, pos.y + 1.0f), col);
-}
-
//-----------------------------------------------------------------------------
// [SECTION] Decompression code
//-----------------------------------------------------------------------------
diff --git a/imgui/imgui_internal.h b/imgui/imgui_internal.h
index 77328281..6d393103 100644
--- a/imgui/imgui_internal.h
+++ b/imgui/imgui_internal.h
@@ -1,4 +1,4 @@
-// dear imgui, v1.72b
+// dear imgui, v1.73
// (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!
@@ -361,9 +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_DrawHoveredWhenHeld= 1 << 25, // Always show active when held, even is not hovered. This concept could probably be renamed/formalized somehow.
- ImGuiSelectableFlags_SetNavIdOnHover = 1 << 26
+ ImGuiSelectableFlags_DrawHoveredWhenHeld= 1 << 24, // Always show active when held, even is not hovered. This concept could probably be renamed/formalized somehow.
+ ImGuiSelectableFlags_SetNavIdOnHover = 1 << 25
};
// Extend ImGuiTreeNodeFlags_
@@ -497,7 +496,8 @@ enum ImGuiNavMoveFlags_
ImGuiNavMoveFlags_WrapX = 1 << 2, // On failed request, request from opposite side one line down (when NavDir==right) or one line up (when NavDir==left)
ImGuiNavMoveFlags_WrapY = 1 << 3, // This is not super useful for provided for completeness
ImGuiNavMoveFlags_AllowCurrentNavId = 1 << 4, // Allow scoring and considering the current NavId as a move target candidate. This is used when the move source is offset (e.g. pressing PageDown actually needs to send a Up move request, if we are pressing PageDown from the bottom-most item we need to stay in place)
- ImGuiNavMoveFlags_AlsoScoreVisibleSet = 1 << 5 // Store alternate result in NavMoveResultLocalVisibleSet that only comprise elements that are already fully visible.
+ ImGuiNavMoveFlags_AlsoScoreVisibleSet = 1 << 5, // Store alternate result in NavMoveResultLocalVisibleSet that only comprise elements that are already fully visible.
+ ImGuiNavMoveFlags_ScrollToEdge = 1 << 6
};
enum ImGuiNavForward
@@ -528,6 +528,14 @@ struct ImVec1
ImVec1(float _x) { x = _x; }
};
+// 2D vector (half-size integer)
+struct ImVec2ih
+{
+ short x, y;
+ ImVec2ih() { x = y = 0; }
+ ImVec2ih(short _x, short _y) { x = _x; y = _y; }
+};
+
// 2D axis aligned bounding-box
// NB: we can't rely on ImVec2 math operators being available here
struct IMGUI_API ImRect
@@ -655,11 +663,11 @@ struct ImGuiWindowSettings
{
char* Name;
ImGuiID ID;
- ImVec2 Pos;
- ImVec2 Size;
+ ImVec2ih Pos;
+ ImVec2ih Size;
bool Collapsed;
- ImGuiWindowSettings() { Name = NULL; ID = 0; Pos = Size = ImVec2(0,0); Collapsed = false; }
+ ImGuiWindowSettings() { Name = NULL; ID = 0; Pos = Size = ImVec2ih(0, 0); Collapsed = false; }
};
struct ImGuiSettingsHandler
@@ -800,7 +808,7 @@ struct ImGuiNextWindowData
void* SizeCallbackUserData;
float BgAlphaVal;
ImVec2 MenuBarOffsetMinVal; // *Always on* This is not exposed publicly, so we don't clear it.
-
+
ImGuiNextWindowData() { memset(this, 0, sizeof(*this)); }
inline void ClearFlags() { Flags = ImGuiNextWindowDataFlags_None; }
};
@@ -952,7 +960,7 @@ struct ImGuiContext
ImGuiNavMoveFlags NavMoveRequestFlags;
ImGuiNavForward NavMoveRequestForward; // None / ForwardQueued / ForwardActive (this is used to navigate sibling parent menus from a child menu)
ImGuiDir NavMoveDir, NavMoveDirLast; // Direction of the move request (left/right/up/down), direction of the previous move request
- ImGuiDir NavMoveClipDir;
+ ImGuiDir NavMoveClipDir; // FIXME-NAV: Describe the purpose of this better. Might want to rename?
ImGuiNavMoveResult NavMoveResultLocal; // Best move request candidate within NavWindow
ImGuiNavMoveResult NavMoveResultLocalVisibleSet; // Best move request candidate within NavWindow that are mostly visible (when using ImGuiNavMoveFlags_AlsoScoreVisibleSet flag)
ImGuiNavMoveResult NavMoveResultOther; // Best move request candidate within NavWindow's flattened hierarchy (when using ImGuiWindowFlags_NavFlattened flag)
@@ -1003,6 +1011,8 @@ struct ImGuiContext
ImFont InputTextPasswordFont;
ImGuiID TempInputTextId; // Temporary text input when CTRL+clicking on a slider, etc.
ImGuiColorEditFlags ColorEditOptions; // Store user options for color edit widgets
+ float ColorEditLastHue;
+ float ColorEditLastColor[3];
ImVec4 ColorPickerRef;
bool DragCurrentAccumDirty;
float DragCurrentAccum; // Accumulator for dragging modification. Always high-precision, not rounded by end-user precision settings
@@ -1147,6 +1157,8 @@ struct ImGuiContext
LastValidMousePos = ImVec2(0.0f, 0.0f);
TempInputTextId = 0;
ColorEditOptions = ImGuiColorEditFlags__OptionsDefault;
+ ColorEditLastHue = 0.0f;
+ ColorEditLastColor[0] = ColorEditLastColor[1] = ColorEditLastColor[2] = FLT_MAX;
DragCurrentAccumDirty = false;
DragCurrentAccum = 0.0f;
DragSpeedDefaultRatio = 1.0f / 100.0f;
@@ -1187,20 +1199,20 @@ struct ImGuiContext
// FIXME: That's theory, in practice the delimitation between ImGuiWindow and ImGuiWindowTempData is quite tenuous and could be reconsidered.
struct IMGUI_API ImGuiWindowTempData
{
- ImVec2 CursorPos;
+ ImVec2 CursorPos; // Current emitting position, in absolute coordinates.
ImVec2 CursorPosPrevLine;
- ImVec2 CursorStartPos; // Initial position in client area with padding
+ ImVec2 CursorStartPos; // Initial position after Begin(), generally ~ window position + WindowPadding.
ImVec2 CursorMaxPos; // Used to implicitly calculate the size of our contents, always growing during the frame. Used to calculate window->ContentSize at the beginning of next frame
ImVec2 CurrLineSize;
ImVec2 PrevLineSize;
- float CurrLineTextBaseOffset;
+ float CurrLineTextBaseOffset; // Baseline offset (0.0f by default on a new line, generally == style.FramePadding.y when a framed item has been added).
float PrevLineTextBaseOffset;
- int TreeDepth;
- ImU32 TreeStoreMayJumpToParentOnPop; // Store a copy of !g.NavIdIsAlive for TreeDepth 0..31.. Could be turned into a ImU64 if necessary.
- ImGuiID LastItemId;
- ImGuiItemStatusFlags LastItemStatusFlags;
- ImRect LastItemRect; // Interaction rect
- ImRect LastItemDisplayRect; // End-user display rect (only valid if LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect)
+ int TreeDepth; // Current tree depth.
+ ImU32 TreeMayJumpToParentOnPopMask; // Store a copy of !g.NavIdIsAlive for TreeDepth 0..31.. Could be turned into a ImU64 if necessary.
+ ImGuiID LastItemId; // ID for last item
+ ImGuiItemStatusFlags LastItemStatusFlags; // Status flags for last item (see ImGuiItemStatusFlags_)
+ ImRect LastItemRect; // Interaction rect for last item
+ ImRect LastItemDisplayRect; // End-user display rect for last item (only valid if LastItemStatusFlags & ImGuiItemStatusFlags_HasDisplayRect)
ImGuiNavLayer NavLayerCurrent; // Current layer, 0..31 (we currently only use 0..1)
int NavLayerCurrentMask; // = (1 << NavLayerCurrent) used by ItemAdd prior to clipping.
int NavLayerActiveMask; // Which layer have been written to (result from previous frame)
@@ -1210,7 +1222,7 @@ struct IMGUI_API ImGuiWindowTempData
bool MenuBarAppending; // FIXME: Remove this
ImVec2 MenuBarOffset; // MenuBarOffset.x is sort of equivalent of a per-layer CursorPos.x, saved/restored as we switch to the menu bar. The only situation when MenuBarOffset.y is > 0 if when (SafeAreaPadding.y > FramePadding.y), often used on TVs.
ImVector<ImGuiWindow*> ChildWindows;
- ImGuiStorage* StateStorage;
+ ImGuiStorage* StateStorage; // Current persistent per-window storage (store e.g. tree node open/close state)
ImGuiLayoutType LayoutType;
ImGuiLayoutType ParentLayoutType; // Layout type of parent window at the time of Begin()
int FocusCounterAll; // Counter for focus/tabbing system. Start at -1 and increase as assigned via FocusableItemRegister() (FIXME-NAV: Needs redesign)
@@ -1237,7 +1249,7 @@ struct IMGUI_API ImGuiWindowTempData
CurrLineSize = PrevLineSize = ImVec2(0.0f, 0.0f);
CurrLineTextBaseOffset = PrevLineTextBaseOffset = 0.0f;
TreeDepth = 0;
- TreeStoreMayJumpToParentOnPop = 0x00;
+ TreeMayJumpToParentOnPopMask = 0x00;
LastItemId = 0;
LastItemStatusFlags = 0;
LastItemRect = LastItemDisplayRect = ImRect();
@@ -1275,9 +1287,9 @@ struct IMGUI_API ImGuiWindow
ImVec2 SizeFull; // Size when non collapsed
ImVec2 ContentSize; // Size of contents/scrollable client area (calculated from the extents reach of the cursor) from previous frame. Does not include window decoration or window padding.
ImVec2 ContentSizeExplicit; // Size of contents/scrollable client area explicitly request by the user via SetNextWindowContentSize().
- ImVec2 WindowPadding; // Window padding at the time of begin.
- float WindowRounding; // Window rounding at the time of begin.
- float WindowBorderSize; // Window border size at the time of begin.
+ ImVec2 WindowPadding; // Window padding at the time of Begin().
+ float WindowRounding; // Window rounding at the time of Begin().
+ float WindowBorderSize; // Window border size at the time of Begin().
int NameBufLen; // Size of buffer storing Name. May be larger than strlen(Name)!
ImGuiID MoveId; // == window->GetID("#MOVE")
ImGuiID ChildId; // ID of corresponding item in parent window (for navigation to return from child window to parent window)
@@ -1286,7 +1298,7 @@ struct IMGUI_API ImGuiWindow
ImVec2 ScrollTarget; // target scroll position. stored as cursor position with scrolling canceled out, so the highest point is always 0.0f. (FLT_MAX for no change)
ImVec2 ScrollTargetCenterRatio; // 0.0f = scroll so that target position is at top, 0.5f = scroll so that target position is centered
ImVec2 ScrollbarSizes; // Size taken by scrollbars on each axis
- bool ScrollbarX, ScrollbarY;
+ bool ScrollbarX, ScrollbarY; // Are scrollbars visible?
bool Active; // Set to true on Begin(), unless Collapsed
bool WasActive;
bool WriteAccessed; // Set to true when any widget access the current window
@@ -1301,9 +1313,9 @@ struct IMGUI_API ImGuiWindow
short BeginOrderWithinParent; // Order within immediate parent window, if we are a child window. Otherwise 0.
short BeginOrderWithinContext; // Order within entire imgui context. This is mostly used for debugging submission order related issues.
ImGuiID PopupId; // ID in the popup stack when this window is used as a popup/menu (because we use generic Name/ID for recycling)
- int AutoFitFramesX, AutoFitFramesY;
+ ImS8 AutoFitFramesX, AutoFitFramesY;
+ ImS8 AutoFitChildAxises;
bool AutoFitOnlyGrows;
- int AutoFitChildAxises;
ImGuiDir AutoPosLastDirection;
int HiddenFramesCanSkipItems; // Hide the window for N frames
int HiddenFramesCannotSkipItems; // Hide the window for N frames while allowing items to be submitted so we can measure their size
@@ -1313,8 +1325,8 @@ struct IMGUI_API ImGuiWindow
ImVec2 SetWindowPosVal; // store window position when using a non-zero Pivot (position set needs to be processed when we know the window size)
ImVec2 SetWindowPosPivot; // store window pivot for positioning. ImVec2(0,0) when positioning from top-left corner; ImVec2(0.5f,0.5f) for centering; ImVec2(1,1) for bottom right.
+ ImVector<ImGuiID> IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack. (In theory this should be in the TempData structure)
ImGuiWindowTempData DC; // Temporary per-window data, reset at the beginning of the frame. This used to be called ImGuiDrawContext, hence the "DC" variable name.
- ImVector<ImGuiID> IDStack; // ID stack. ID are hashes seeded with the value at the top of the stack
// 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().
@@ -1326,6 +1338,7 @@ struct IMGUI_API ImGuiWindow
ImRect ContentsRegionRect; // FIXME: This is currently confusing/misleading. It is essentially WorkRect but not handling of scrolling. We currently rely on it as right/bottom aligned sizing operation need some size to rely on.
int LastFrameActive; // Last frame number the window was Active.
+ float LastTimeActive; // Last timestamp the window was Active (using float as we don't need high precision there)
float ItemWidthDefault;
ImGuiMenuColumns MenuColumns; // Simplified columns storage for menu items
ImGuiStorage StateStorage;
@@ -1344,6 +1357,10 @@ struct IMGUI_API ImGuiWindow
ImGuiID NavLastIds[ImGuiNavLayer_COUNT]; // Last known NavId for this window, per layer (0/1)
ImRect NavRectRel[ImGuiNavLayer_COUNT]; // Reference rectangle, in window relative space
+ bool MemoryCompacted;
+ int MemoryDrawListIdxCapacity;
+ int MemoryDrawListVtxCapacity;
+
public:
ImGuiWindow(ImGuiContext* context, const char* name);
~ImGuiWindow();
@@ -1422,8 +1439,9 @@ struct ImGuiTabBar
int CurrFrameVisible;
int PrevFrameVisible;
ImRect BarRect;
- float ContentsHeight;
+ float LastTabContentHeight; // Record the height of contents submitted below the tab bar
float OffsetMax; // Distance from BarRect.Min.x, locked during layout
+ float OffsetMaxIdeal; // Ideal offset if all tabs were visible and not clipped
float OffsetNextTab; // Distance from BarRect.Min.x, incremented with each BeginTabItem() call, not used if ImGuiTabBarFlags_Reorderable if set.
float ScrollingAnim;
float ScrollingTarget;
@@ -1475,9 +1493,12 @@ namespace ImGui
IMGUI_API void SetWindowPos(ImGuiWindow* window, const ImVec2& pos, ImGuiCond cond = 0);
IMGUI_API void SetWindowSize(ImGuiWindow* window, const ImVec2& size, ImGuiCond cond = 0);
IMGUI_API void SetWindowCollapsed(ImGuiWindow* window, bool collapsed, ImGuiCond cond = 0);
+ IMGUI_API void GcCompactTransientWindowBuffers(ImGuiWindow* window);
+ IMGUI_API void GcAwakeTransientWindowBuffers(ImGuiWindow* window);
IMGUI_API void SetCurrentFont(ImFont* font);
inline ImFont* GetDefaultFont() { ImGuiContext& g = *GImGui; return g.IO.FontDefault ? g.IO.FontDefault : g.IO.Fonts->Fonts[0]; }
+ inline ImDrawList* GetForegroundDrawList(ImGuiWindow*) { ImGuiContext& g = *GImGui; return &g.ForegroundDrawList; } // This seemingly unnecessary wrapper simplifies compatibility between the 'master' and 'docking' branches.
// Init
IMGUI_API void Initialize(ImGuiContext* context);
@@ -1502,7 +1523,7 @@ namespace ImGui
IMGUI_API void SetScrollY(ImGuiWindow* window, float new_scroll_y);
IMGUI_API void SetScrollFromPosX(ImGuiWindow* window, float local_x, float center_x_ratio = 0.5f);
IMGUI_API void SetScrollFromPosY(ImGuiWindow* window, float local_y, float center_y_ratio = 0.5f);
- IMGUI_API void ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect);
+ IMGUI_API ImVec2 ScrollToBringRectIntoView(ImGuiWindow* window, const ImRect& item_rect);
// Basic Accessors
inline ImGuiID GetItemID() { ImGuiContext& g = *GImGui; return g.CurrentWindow->DC.LastItemId; }
@@ -1563,7 +1584,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);
+ IMGUI_API 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; }
@@ -1615,10 +1636,9 @@ namespace ImGui
// Render helpers (those functions don't access any ImGui state!)
IMGUI_API void RenderArrow(ImDrawList* draw_list, ImVec2 pos, ImU32 col, ImGuiDir dir, float scale = 1.0f);
IMGUI_API void RenderBullet(ImDrawList* draw_list, ImVec2 pos, ImU32 col);
- IMGUI_API void RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor = ImGuiMouseCursor_Arrow);
+ IMGUI_API void RenderMouseCursor(ImDrawList* draw_list, ImVec2 pos, float scale, ImGuiMouseCursor mouse_cursor, ImU32 col_fill, ImU32 col_border, ImU32 col_shadow);
IMGUI_API void RenderArrowPointingAt(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, ImGuiDir direction, ImU32 col);
IMGUI_API void RenderRectFilledRangeH(ImDrawList* draw_list, const ImRect& rect, ImU32 col, float x_start_norm, float x_end_norm, float rounding);
- IMGUI_API void RenderPixelEllipsis(ImDrawList* draw_list, ImVec2 pos, ImU32 col, int count);
#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
// 2019/06/07: Updating prototypes of some of the internal functions. Leaving those for reference for a short while.
@@ -1693,7 +1713,7 @@ IMGUI_API void ImFontAtlasBuildMultiplyRectAlpha8(const unsigned ch
// Debug Tools
// Use 'Metrics->Tools->Item Picker' to break into the call-stack of a specific item.
-#ifndef IM_DEBUG_BREAK
+#ifndef IM_DEBUG_BREAK
#if defined(__clang__)
#define IM_DEBUG_BREAK() __builtin_debugtrap()
#elif defined (_MSC_VER)
diff --git a/imgui/imgui_widgets.cpp b/imgui/imgui_widgets.cpp
index ba58bce0..bcd051e5 100644
--- a/imgui/imgui_widgets.cpp
+++ b/imgui/imgui_widgets.cpp
@@ -1,4 +1,4 @@
-// dear imgui, v1.72b
+// dear imgui, v1.73
// (widgets code)
/*
@@ -399,37 +399,37 @@ void ImGui::BulletTextV(const char* fmt, va_list args)
// See the series of events below and the corresponding state reported by dear imgui:
//------------------------------------------------------------------------------------------------------------------------------------------------
// with PressedOnClickRelease: return-value IsItemHovered() IsItemActive() IsItemActivated() IsItemDeactivated() IsItemClicked()
-// Frame N+0 (mouse is outside bb) - - - - - -
-// Frame N+1 (mouse moves inside bb) - true - - - -
+// Frame N+0 (mouse is outside bb) - - - - - -
+// Frame N+1 (mouse moves inside bb) - true - - - -
// Frame N+2 (mouse button is down) - true true true - true
-// Frame N+3 (mouse button is down) - true true - - -
+// Frame N+3 (mouse button is down) - true true - - -
// Frame N+4 (mouse moves outside bb) - - true - - -
// Frame N+5 (mouse moves inside bb) - true true - - -
-// Frame N+6 (mouse button is released) true true - - true -
-// Frame N+7 (mouse button is released) - true - - - -
-// Frame N+8 (mouse moves outside bb) - - - - - -
+// Frame N+6 (mouse button is released) true true - - true -
+// Frame N+7 (mouse button is released) - true - - - -
+// Frame N+8 (mouse moves outside bb) - - - - - -
//------------------------------------------------------------------------------------------------------------------------------------------------
// with PressedOnClick: return-value IsItemHovered() IsItemActive() IsItemActivated() IsItemDeactivated() IsItemClicked()
// Frame N+2 (mouse button is down) true true true true - true
-// Frame N+3 (mouse button is down) - true true - - -
-// Frame N+6 (mouse button is released) - true - - true -
-// Frame N+7 (mouse button is released) - true - - - -
+// Frame N+3 (mouse button is down) - true true - - -
+// Frame N+6 (mouse button is released) - true - - true -
+// Frame N+7 (mouse button is released) - true - - - -
//------------------------------------------------------------------------------------------------------------------------------------------------
// with PressedOnRelease: return-value IsItemHovered() IsItemActive() IsItemActivated() IsItemDeactivated() IsItemClicked()
// Frame N+2 (mouse button is down) - true - - - true
-// Frame N+3 (mouse button is down) - true - - - -
+// Frame N+3 (mouse button is down) - true - - - -
// Frame N+6 (mouse button is released) true true - - - -
-// Frame N+7 (mouse button is released) - true - - - -
+// Frame N+7 (mouse button is released) - true - - - -
//------------------------------------------------------------------------------------------------------------------------------------------------
// with PressedOnDoubleClick: return-value IsItemHovered() IsItemActive() IsItemActivated() IsItemDeactivated() IsItemClicked()
// Frame N+0 (mouse button is down) - true - - - true
-// Frame N+1 (mouse button is down) - true - - - -
+// Frame N+1 (mouse button is down) - true - - - -
// Frame N+2 (mouse button is released) - true - - - -
-// Frame N+3 (mouse button is released) - true - - - -
+// Frame N+3 (mouse button is released) - true - - - -
// Frame N+4 (mouse button is down) true true true true - true
-// Frame N+5 (mouse button is down) - true true - - -
+// Frame N+5 (mouse button is down) - true true - - -
// Frame N+6 (mouse button is released) - true - - true -
-// Frame N+7 (mouse button is released) - true - - - -
+// Frame N+7 (mouse button is released) - true - - - -
//------------------------------------------------------------------------------------------------------------------------------------------------
// Note that some combinations are supported,
// - PressedOnDragDropHold can generally be associated with any flag.
@@ -439,7 +439,7 @@ void ImGui::BulletTextV(const char* fmt, va_list args)
// Repeat+ Repeat+ Repeat+ Repeat+
// PressedOnClickRelease PressedOnClick PressedOnRelease PressedOnDoubleClick
//-------------------------------------------------------------------------------------------------------------------------------------------------
-// Frame N+0 (mouse button is down) - true - true
+// Frame N+0 (mouse button is down) - true - true
// ... - - - -
// Frame N + RepeatDelay true true - true
// ... - - - -
@@ -1261,7 +1261,10 @@ void ImGui::SeparatorEx(ImGuiSeparatorFlags flags)
if (!ItemAdd(bb, 0))
{
if (columns)
+ {
PopColumnsBackground();
+ columns->LineMinY = window->DC.CursorPos.y;
+ }
return;
}
@@ -1361,19 +1364,37 @@ static int IMGUI_CDECL ShrinkWidthItemComparer(const void* lhs, const void* rhs)
// Shrink excess width from a set of item, by removing width from the larger items first.
void ImGui::ShrinkWidths(ImGuiShrinkWidthItem* items, int count, float width_excess)
{
- if (count > 1)
- ImQsort(items, (size_t)count, sizeof(ImGuiShrinkWidthItem), ShrinkWidthItemComparer);
+ if (count == 1)
+ {
+ items[0].Width = ImMax(items[0].Width - width_excess, 1.0f);
+ return;
+ }
+ ImQsort(items, (size_t)count, sizeof(ImGuiShrinkWidthItem), ShrinkWidthItemComparer);
int count_same_width = 1;
while (width_excess > 0.0f && count_same_width < count)
{
- while (count_same_width < count && items[0].Width == items[count_same_width].Width)
+ while (count_same_width < count && items[0].Width <= items[count_same_width].Width)
count_same_width++;
- float width_to_remove_per_item_max = (count_same_width < count) ? (items[0].Width - items[count_same_width].Width) : (items[0].Width - 1.0f);
- float width_to_remove_per_item = ImMin(width_excess / count_same_width, width_to_remove_per_item_max);
+ float max_width_to_remove_per_item = (count_same_width < count) ? (items[0].Width - items[count_same_width].Width) : (items[0].Width - 1.0f);
+ float width_to_remove_per_item = ImMin(width_excess / count_same_width, max_width_to_remove_per_item);
for (int item_n = 0; item_n < count_same_width; item_n++)
items[item_n].Width -= width_to_remove_per_item;
width_excess -= width_to_remove_per_item * count_same_width;
}
+
+ // Round width and redistribute remainder left-to-right (could make it an option of the function?)
+ // Ensure that e.g. the right-most tab of a shrunk tab-bar always reaches exactly at the same distance from the right-most edge of the tab bar separator.
+ width_excess = 0.0f;
+ for (int n = 0; n < count; n++)
+ {
+ float width_rounded = ImFloor(items[n].Width);
+ width_excess += items[n].Width - width_rounded;
+ items[n].Width = width_rounded;
+ }
+ if (width_excess > 0.0f)
+ for (int n = 0; n < count; n++)
+ if (items[n].Index < (int)(width_excess + 0.01f))
+ items[n].Width += 1.0f;
}
//-------------------------------------------------------------------------
@@ -1898,11 +1919,14 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
ImGuiContext& g = *GImGui;
const ImGuiAxis axis = (flags & ImGuiDragFlags_Vertical) ? ImGuiAxis_Y : ImGuiAxis_X;
const bool is_decimal = (data_type == ImGuiDataType_Float) || (data_type == ImGuiDataType_Double);
- const bool has_min_max = (v_min != v_max);
- const bool is_power = (power != 1.0f && is_decimal && has_min_max && (v_max - v_min < FLT_MAX));
+ const bool is_clamped = (v_min < v_max);
+ const bool is_power = (power != 1.0f && is_decimal && is_clamped && (v_max - v_min < FLT_MAX));
+ const bool is_locked = (v_min > v_max);
+ if (is_locked)
+ return false;
// Default tweak speed
- if (v_speed == 0.0f && has_min_max && (v_max - v_min < FLT_MAX))
+ if (v_speed == 0.0f && is_clamped && (v_max - v_min < FLT_MAX))
v_speed = (float)((v_max - v_min) * g.DragSpeedDefaultRatio);
// Inputs accumulates into g.DragCurrentAccum, which is flushed into the current value as soon as it makes a difference with our precision settings
@@ -1930,7 +1954,7 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
// Clear current value on activation
// Avoid altering values and clamping when we are _already_ past the limits and heading in the same direction, so e.g. if range is 0..255, current value is 300 and we are pushing to the right side, keep the 300.
bool is_just_activated = g.ActiveIdIsJustActivated;
- bool is_already_past_limits_and_pushing_outward = has_min_max && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f));
+ bool is_already_past_limits_and_pushing_outward = is_clamped && ((*v >= v_max && adjust_delta > 0.0f) || (*v <= v_min && adjust_delta < 0.0f));
bool is_drag_direction_change_with_power = is_power && ((adjust_delta < 0 && g.DragCurrentAccum > 0) || (adjust_delta > 0 && g.DragCurrentAccum < 0));
if (is_just_activated || is_already_past_limits_and_pushing_outward || is_drag_direction_change_with_power)
{
@@ -1954,12 +1978,12 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
// Offset + round to user desired precision, with a curve on the v_min..v_max range to get more precision on one side of the range
FLOATTYPE v_old_norm_curved = ImPow((FLOATTYPE)(v_cur - v_min) / (FLOATTYPE)(v_max - v_min), (FLOATTYPE)1.0f / power);
FLOATTYPE v_new_norm_curved = v_old_norm_curved + (g.DragCurrentAccum / (v_max - v_min));
- v_cur = v_min + (TYPE)ImPow(ImSaturate((float)v_new_norm_curved), power) * (v_max - v_min);
+ v_cur = v_min + (SIGNEDTYPE)ImPow(ImSaturate((float)v_new_norm_curved), power) * (v_max - v_min);
v_old_ref_for_accum_remainder = v_old_norm_curved;
}
else
{
- v_cur += (TYPE)g.DragCurrentAccum;
+ v_cur += (SIGNEDTYPE)g.DragCurrentAccum;
}
// Round to user desired precision based on format string
@@ -1982,7 +2006,7 @@ bool ImGui::DragBehaviorT(ImGuiDataType data_type, TYPE* v, float v_speed, const
v_cur = (TYPE)0;
// Clamp values (+ handle overflow/wrap-around for integer types)
- if (*v != v_cur && has_min_max)
+ if (*v != v_cur && is_clamped)
{
if (v_cur < v_min || (v_cur > *v && adjust_delta < 0.0f && !is_decimal))
v_cur = v_min;
@@ -2460,13 +2484,13 @@ bool ImGui::SliderBehavior(const ImRect& bb, ImGuiID id, ImGuiDataType data_type
IM_ASSERT(*(const ImS32*)v_min >= IM_S32_MIN/2 && *(const ImS32*)v_max <= IM_S32_MAX/2);
return SliderBehaviorT<ImS32, ImS32, float >(bb, id, data_type, (ImS32*)v, *(const ImS32*)v_min, *(const ImS32*)v_max, format, power, flags, out_grab_bb);
case ImGuiDataType_U32:
- IM_ASSERT(*(const ImU32*)v_min <= IM_U32_MAX/2);
+ IM_ASSERT(*(const ImU32*)v_max <= IM_U32_MAX/2);
return SliderBehaviorT<ImU32, ImS32, float >(bb, id, data_type, (ImU32*)v, *(const ImU32*)v_min, *(const ImU32*)v_max, format, power, flags, out_grab_bb);
case ImGuiDataType_S64:
IM_ASSERT(*(const ImS64*)v_min >= IM_S64_MIN/2 && *(const ImS64*)v_max <= IM_S64_MAX/2);
return SliderBehaviorT<ImS64, ImS64, double>(bb, id, data_type, (ImS64*)v, *(const ImS64*)v_min, *(const ImS64*)v_max, format, power, flags, out_grab_bb);
case ImGuiDataType_U64:
- IM_ASSERT(*(const ImU64*)v_min <= IM_U64_MAX/2);
+ IM_ASSERT(*(const ImU64*)v_max <= IM_U64_MAX/2);
return SliderBehaviorT<ImU64, ImS64, double>(bb, id, data_type, (ImU64*)v, *(const ImU64*)v_min, *(const ImU64*)v_max, format, power, flags, out_grab_bb);
case ImGuiDataType_Float:
IM_ASSERT(*(const float*)v_min >= -FLT_MAX/2.0f && *(const float*)v_max <= FLT_MAX/2.0f);
@@ -3198,21 +3222,21 @@ static bool STB_TEXTEDIT_INSERTCHARS(STB_TEXTEDIT_STRING* obj, int pos, const Im
}
// We don't use an enum so we can build even with conflicting symbols (if another user of stb_textedit.h leak their STB_TEXTEDIT_K_* symbols)
-#define STB_TEXTEDIT_K_LEFT 0x10000 // keyboard input to move cursor left
-#define STB_TEXTEDIT_K_RIGHT 0x10001 // keyboard input to move cursor right
-#define STB_TEXTEDIT_K_UP 0x10002 // keyboard input to move cursor up
-#define STB_TEXTEDIT_K_DOWN 0x10003 // keyboard input to move cursor down
-#define STB_TEXTEDIT_K_LINESTART 0x10004 // keyboard input to move cursor to start of line
-#define STB_TEXTEDIT_K_LINEEND 0x10005 // keyboard input to move cursor to end of line
-#define STB_TEXTEDIT_K_TEXTSTART 0x10006 // keyboard input to move cursor to start of text
-#define STB_TEXTEDIT_K_TEXTEND 0x10007 // keyboard input to move cursor to end of text
-#define STB_TEXTEDIT_K_DELETE 0x10008 // keyboard input to delete selection or character under cursor
-#define STB_TEXTEDIT_K_BACKSPACE 0x10009 // keyboard input to delete selection or character left of cursor
-#define STB_TEXTEDIT_K_UNDO 0x1000A // keyboard input to perform undo
-#define STB_TEXTEDIT_K_REDO 0x1000B // keyboard input to perform redo
-#define STB_TEXTEDIT_K_WORDLEFT 0x1000C // keyboard input to move cursor left one word
-#define STB_TEXTEDIT_K_WORDRIGHT 0x1000D // keyboard input to move cursor right one word
-#define STB_TEXTEDIT_K_SHIFT 0x20000
+#define STB_TEXTEDIT_K_LEFT 0x200000 // keyboard input to move cursor left
+#define STB_TEXTEDIT_K_RIGHT 0x200001 // keyboard input to move cursor right
+#define STB_TEXTEDIT_K_UP 0x200002 // keyboard input to move cursor up
+#define STB_TEXTEDIT_K_DOWN 0x200003 // keyboard input to move cursor down
+#define STB_TEXTEDIT_K_LINESTART 0x200004 // keyboard input to move cursor to start of line
+#define STB_TEXTEDIT_K_LINEEND 0x200005 // keyboard input to move cursor to end of line
+#define STB_TEXTEDIT_K_TEXTSTART 0x200006 // keyboard input to move cursor to start of text
+#define STB_TEXTEDIT_K_TEXTEND 0x200007 // keyboard input to move cursor to end of text
+#define STB_TEXTEDIT_K_DELETE 0x200008 // keyboard input to delete selection or character under cursor
+#define STB_TEXTEDIT_K_BACKSPACE 0x200009 // keyboard input to delete selection or character left of cursor
+#define STB_TEXTEDIT_K_UNDO 0x20000A // keyboard input to perform undo
+#define STB_TEXTEDIT_K_REDO 0x20000B // keyboard input to perform redo
+#define STB_TEXTEDIT_K_WORDLEFT 0x20000C // keyboard input to move cursor left one word
+#define STB_TEXTEDIT_K_WORDRIGHT 0x20000D // keyboard input to move cursor right one word
+#define STB_TEXTEDIT_K_SHIFT 0x400000
#define STB_TEXTEDIT_IMPLEMENTATION
#include "imstb_textedit.h"
@@ -3380,7 +3404,7 @@ bool ImGui::InputTextEx(const char* label, const char* hint, char* buf, int buf_
BeginGroup();
const ImGuiID id = window->GetID(label);
const ImVec2 label_size = CalcTextSize(label, NULL, true);
- ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? GetTextLineHeight() * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line
+ ImVec2 size = CalcItemSize(size_arg, CalcItemWidth(), (is_multiline ? g.FontSize * 8.0f : label_size.y) + style.FramePadding.y*2.0f); // Arbitrary default of 8 lines high for multi-line
const ImRect frame_bb(window->DC.CursorPos, window->DC.CursorPos + size);
const ImRect total_bb(frame_bb.Min, frame_bb.Max + ImVec2(label_size.x > 0.0f ? (style.ItemInnerSpacing.x + label_size.x) : 0.0f, 0.0f));
@@ -4176,7 +4200,12 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
if ((flags & ImGuiColorEditFlags_InputHSV) && (flags & ImGuiColorEditFlags_DisplayRGB))
ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]);
else if ((flags & ImGuiColorEditFlags_InputRGB) && (flags & ImGuiColorEditFlags_DisplayHSV))
+ {
+ // Hue is lost when converting from greyscale rgb (saturation=0). Restore it.
ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]);
+ if (f[1] == 0 && memcmp(g.ColorEditLastColor, col, sizeof(float) * 3) == 0)
+ f[0] = g.ColorEditLastHue;
+ }
int i[4] = { IM_F32_TO_INT8_UNBOUND(f[0]), IM_F32_TO_INT8_UNBOUND(f[1]), IM_F32_TO_INT8_UNBOUND(f[2]), IM_F32_TO_INT8_UNBOUND(f[3]) };
bool value_changed = false;
@@ -4213,14 +4242,17 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
if (n > 0)
SameLine(0, style.ItemInnerSpacing.x);
SetNextItemWidth((n + 1 < components) ? w_item_one : w_item_last);
+
+ // Disable Hue edit when Saturation is zero
+ const bool disable_hue_edit = (n == 0 && (flags & ImGuiColorEditFlags_DisplayHSV) && i[1] == 0);
if (flags & ImGuiColorEditFlags_Float)
{
- value_changed |= DragFloat(ids[n], &f[n], 1.0f/255.0f, 0.0f, hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]);
+ value_changed |= DragFloat(ids[n], &f[n], 1.0f/255.0f, disable_hue_edit ? +FLT_MAX : 0.0f, disable_hue_edit ? -FLT_MAX : hdr ? 0.0f : 1.0f, fmt_table_float[fmt_idx][n]);
value_changed_as_float |= value_changed;
}
else
{
- value_changed |= DragInt(ids[n], &i[n], 1.0f, 0, hdr ? 0 : 255, fmt_table_int[fmt_idx][n]);
+ value_changed |= DragInt(ids[n], &i[n], 1.0f, disable_hue_edit ? INT_MAX : 0, disable_hue_edit ? INT_MIN : hdr ? 0 : 255, fmt_table_int[fmt_idx][n]);
}
if (!(flags & ImGuiColorEditFlags_NoOptions))
OpenPopupOnItemClick("context");
@@ -4300,7 +4332,11 @@ bool ImGui::ColorEdit4(const char* label, float col[4], ImGuiColorEditFlags flag
for (int n = 0; n < 4; n++)
f[n] = i[n] / 255.0f;
if ((flags & ImGuiColorEditFlags_DisplayHSV) && (flags & ImGuiColorEditFlags_InputRGB))
+ {
+ g.ColorEditLastHue = f[0];
ColorConvertHSVtoRGB(f[0], f[1], f[2], f[0], f[1], f[2]);
+ memcpy(g.ColorEditLastColor, f, sizeof(float) * 3);
+ }
if ((flags & ImGuiColorEditFlags_DisplayRGB) && (flags & ImGuiColorEditFlags_InputHSV))
ColorConvertRGBtoHSV(f[0], f[1], f[2], f[0], f[1], f[2]);
@@ -4402,17 +4438,19 @@ void ImGui::RenderColorRectWithAlphaCheckerboard(ImVec2 p_min, ImVec2 p_max, ImU
}
// Helper for ColorPicker4()
-static void RenderArrowsForVerticalBar(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, float bar_w)
+static void RenderArrowsForVerticalBar(ImDrawList* draw_list, ImVec2 pos, ImVec2 half_sz, float bar_w, float alpha)
{
- ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x + 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Right, IM_COL32_BLACK);
- ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x, pos.y), half_sz, ImGuiDir_Right, IM_COL32_WHITE);
- ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x - 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Left, IM_COL32_BLACK);
- ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x, pos.y), half_sz, ImGuiDir_Left, IM_COL32_WHITE);
+ ImU32 alpha8 = IM_F32_TO_INT8_SAT(alpha);
+ ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x + 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Right, IM_COL32(0,0,0,alpha8));
+ ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + half_sz.x, pos.y), half_sz, ImGuiDir_Right, IM_COL32(255,255,255,alpha8));
+ ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x - 1, pos.y), ImVec2(half_sz.x + 2, half_sz.y + 1), ImGuiDir_Left, IM_COL32(0,0,0,alpha8));
+ ImGui::RenderArrowPointingAt(draw_list, ImVec2(pos.x + bar_w - half_sz.x, pos.y), half_sz, ImGuiDir_Left, IM_COL32(255,255,255,alpha8));
}
// Note: ColorPicker4() only accesses 3 floats if ImGuiColorEditFlags_NoAlpha flag is set.
// (In C++ the 'float col[4]' notation for a function argument is equivalent to 'float* col', we only specify a size to facilitate understanding of the code.)
// FIXME: we adjust the big color square height based on item width, which may cause a flickering feedback loop (if automatic height makes a vertical scrollbar appears, affecting automatic width..)
+// FIXME: this is trying to be aware of style.Alpha but not fully correct. Also, the color wheel will have overlapping glitches with (style.Alpha < 1.0)
bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags flags, const float* ref_col)
{
ImGuiContext& g = *GImGui;
@@ -4475,9 +4513,16 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
float H = col[0], S = col[1], V = col[2];
float R = col[0], G = col[1], B = col[2];
if (flags & ImGuiColorEditFlags_InputRGB)
+ {
+ // Hue is lost when converting from greyscale rgb (saturation=0). Restore it.
ColorConvertRGBtoHSV(R, G, B, H, S, V);
+ if (S == 0 && memcmp(g.ColorEditLastColor, col, sizeof(float) * 3) == 0)
+ H = g.ColorEditLastHue;
+ }
else if (flags & ImGuiColorEditFlags_InputHSV)
+ {
ColorConvertHSVtoRGB(H, S, V, R, G, B);
+ }
bool value_changed = false, value_changed_h = false, value_changed_sv = false;
@@ -4599,6 +4644,8 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
if (flags & ImGuiColorEditFlags_InputRGB)
{
ColorConvertHSVtoRGB(H >= 1.0f ? H - 10 * 1e-6f : H, S > 0.0f ? S : 10*1e-6f, V > 0.0f ? V : 1e-6f, col[0], col[1], col[2]);
+ g.ColorEditLastHue = H;
+ memcpy(g.ColorEditLastColor, col, sizeof(float) * 3);
}
else if (flags & ImGuiColorEditFlags_InputHSV)
{
@@ -4652,6 +4699,8 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
G = col[1];
B = col[2];
ColorConvertRGBtoHSV(R, G, B, H, S, V);
+ if (S == 0 && memcmp(g.ColorEditLastColor, col, sizeof(float) * 3) == 0) // Fix local Hue as display below will use it immediately.
+ H = g.ColorEditLastHue;
}
else if (flags & ImGuiColorEditFlags_InputHSV)
{
@@ -4662,17 +4711,22 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
}
}
- ImVec4 hue_color_f(1, 1, 1, 1); ColorConvertHSVtoRGB(H, 1, 1, hue_color_f.x, hue_color_f.y, hue_color_f.z);
+ const int style_alpha8 = IM_F32_TO_INT8_SAT(style.Alpha);
+ const ImU32 col_black = IM_COL32(0,0,0,style_alpha8);
+ const ImU32 col_white = IM_COL32(255,255,255,style_alpha8);
+ const ImU32 col_midgrey = IM_COL32(128,128,128,style_alpha8);
+ const ImU32 col_hues[6 + 1] = { IM_COL32(255,0,0,style_alpha8), IM_COL32(255,255,0,style_alpha8), IM_COL32(0,255,0,style_alpha8), IM_COL32(0,255,255,style_alpha8), IM_COL32(0,0,255,style_alpha8), IM_COL32(255,0,255,style_alpha8), IM_COL32(255,0,0,style_alpha8) };
+
+ ImVec4 hue_color_f(1, 1, 1, style.Alpha); ColorConvertHSVtoRGB(H, 1, 1, hue_color_f.x, hue_color_f.y, hue_color_f.z);
ImU32 hue_color32 = ColorConvertFloat4ToU32(hue_color_f);
- ImU32 col32_no_alpha = ColorConvertFloat4ToU32(ImVec4(R, G, B, 1.0f));
+ ImU32 user_col32_striped_of_alpha = ColorConvertFloat4ToU32(ImVec4(R, G, B, style.Alpha)); // Important: this is still including the main rendering/style alpha!!
- const ImU32 hue_colors[6+1] = { IM_COL32(255,0,0,255), IM_COL32(255,255,0,255), IM_COL32(0,255,0,255), IM_COL32(0,255,255,255), IM_COL32(0,0,255,255), IM_COL32(255,0,255,255), IM_COL32(255,0,0,255) };
ImVec2 sv_cursor_pos;
if (flags & ImGuiColorEditFlags_PickerHueWheel)
{
// Render Hue Wheel
- const float aeps = 1.5f / wheel_r_outer; // Half a pixel arc length in radians (2pi cancels out).
+ const float aeps = 0.5f / wheel_r_outer; // Half a pixel arc length in radians (2pi cancels out).
const int segment_per_arc = ImMax(4, (int)wheel_r_outer / 12);
for (int n = 0; n < 6; n++)
{
@@ -4680,13 +4734,13 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
const float a1 = (n+1.0f)/6.0f * 2.0f * IM_PI + aeps;
const int vert_start_idx = draw_list->VtxBuffer.Size;
draw_list->PathArcTo(wheel_center, (wheel_r_inner + wheel_r_outer)*0.5f, a0, a1, segment_per_arc);
- draw_list->PathStroke(IM_COL32_WHITE, false, wheel_thickness);
+ draw_list->PathStroke(col_white, false, wheel_thickness);
const int vert_end_idx = draw_list->VtxBuffer.Size;
// Paint colors over existing vertices
ImVec2 gradient_p0(wheel_center.x + ImCos(a0) * wheel_r_inner, wheel_center.y + ImSin(a0) * wheel_r_inner);
ImVec2 gradient_p1(wheel_center.x + ImCos(a1) * wheel_r_inner, wheel_center.y + ImSin(a1) * wheel_r_inner);
- ShadeVertsLinearColorGradientKeepAlpha(draw_list, vert_start_idx, vert_end_idx, gradient_p0, gradient_p1, hue_colors[n], hue_colors[n+1]);
+ ShadeVertsLinearColorGradientKeepAlpha(draw_list, vert_start_idx, vert_end_idx, gradient_p0, gradient_p1, col_hues[n], col_hues[n+1]);
}
// Render Cursor + preview on Hue Wheel
@@ -4696,8 +4750,8 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
float hue_cursor_rad = value_changed_h ? wheel_thickness * 0.65f : wheel_thickness * 0.55f;
int hue_cursor_segments = ImClamp((int)(hue_cursor_rad / 1.4f), 9, 32);
draw_list->AddCircleFilled(hue_cursor_pos, hue_cursor_rad, hue_color32, hue_cursor_segments);
- draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad+1, IM_COL32(128,128,128,255), hue_cursor_segments);
- draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad, IM_COL32_WHITE, hue_cursor_segments);
+ draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad+1, col_midgrey, hue_cursor_segments);
+ draw_list->AddCircle(hue_cursor_pos, hue_cursor_rad, col_white, hue_cursor_segments);
// Render SV triangle (rotated according to hue)
ImVec2 tra = wheel_center + ImRotate(triangle_pa, cos_hue_angle, sin_hue_angle);
@@ -4707,46 +4761,46 @@ bool ImGui::ColorPicker4(const char* label, float col[4], ImGuiColorEditFlags fl
draw_list->PrimReserve(6, 6);
draw_list->PrimVtx(tra, uv_white, hue_color32);
draw_list->PrimVtx(trb, uv_white, hue_color32);
- draw_list->PrimVtx(trc, uv_white, IM_COL32_WHITE);
- draw_list->PrimVtx(tra, uv_white, IM_COL32_BLACK_TRANS);
- draw_list->PrimVtx(trb, uv_white, IM_COL32_BLACK);
- draw_list->PrimVtx(trc, uv_white, IM_COL32_BLACK_TRANS);
- draw_list->AddTriangle(tra, trb, trc, IM_COL32(128,128,128,255), 1.5f);
+ draw_list->PrimVtx(trc, uv_white, col_white);
+ draw_list->PrimVtx(tra, uv_white, 0);
+ draw_list->PrimVtx(trb, uv_white, col_white);
+ draw_list->PrimVtx(trc, uv_white, 0);
+ draw_list->AddTriangle(tra, trb, trc, col_midgrey, 1.5f);
sv_cursor_pos = ImLerp(ImLerp(trc, tra, ImSaturate(S)), trb, ImSaturate(1 - V));
}
else if (flags & ImGuiColorEditFlags_PickerHueBar)
{
// Render SV Square
- draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size,sv_picker_size), IM_COL32_WHITE, hue_color32, hue_color32, IM_COL32_WHITE);
- draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size,sv_picker_size), IM_COL32_BLACK_TRANS, IM_COL32_BLACK_TRANS, IM_COL32_BLACK, IM_COL32_BLACK);
- RenderFrameBorder(picker_pos, picker_pos + ImVec2(sv_picker_size,sv_picker_size), 0.0f);
+ draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), col_white, hue_color32, hue_color32, col_white);
+ draw_list->AddRectFilledMultiColor(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0, 0, col_black, col_black);
+ RenderFrameBorder(picker_pos, picker_pos + ImVec2(sv_picker_size, sv_picker_size), 0.0f);
sv_cursor_pos.x = ImClamp((float)(int)(picker_pos.x + ImSaturate(S) * sv_picker_size + 0.5f), picker_pos.x + 2, picker_pos.x + sv_picker_size - 2); // Sneakily prevent the circle to stick out too much
sv_cursor_pos.y = ImClamp((float)(int)(picker_pos.y + ImSaturate(1 - V) * sv_picker_size + 0.5f), picker_pos.y + 2, picker_pos.y + sv_picker_size - 2);
// Render Hue Bar
for (int i = 0; i < 6; ++i)
- draw_list->AddRectFilledMultiColor(ImVec2(bar0_pos_x, picker_pos.y + i * (sv_picker_size / 6)), ImVec2(bar0_pos_x + bars_width, picker_pos.y + (i + 1) * (sv_picker_size / 6)), hue_colors[i], hue_colors[i], hue_colors[i + 1], hue_colors[i + 1]);
+ draw_list->AddRectFilledMultiColor(ImVec2(bar0_pos_x, picker_pos.y + i * (sv_picker_size / 6)), ImVec2(bar0_pos_x + bars_width, picker_pos.y + (i + 1) * (sv_picker_size / 6)), col_hues[i], col_hues[i], col_hues[i + 1], col_hues[i + 1]);
float bar0_line_y = (float)(int)(picker_pos.y + H * sv_picker_size + 0.5f);
RenderFrameBorder(ImVec2(bar0_pos_x, picker_pos.y), ImVec2(bar0_pos_x + bars_width, picker_pos.y + sv_picker_size), 0.0f);
- RenderArrowsForVerticalBar(draw_list, ImVec2(bar0_pos_x - 1, bar0_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f);
+ RenderArrowsForVerticalBar(draw_list, ImVec2(bar0_pos_x - 1, bar0_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f, style.Alpha);
}
// Render cursor/preview circle (clamp S/V within 0..1 range because floating points colors may lead HSV values to be out of range)
float sv_cursor_rad = value_changed_sv ? 10.0f : 6.0f;
- draw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, col32_no_alpha, 12);
- draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad+1, IM_COL32(128,128,128,255), 12);
- draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, IM_COL32_WHITE, 12);
+ draw_list->AddCircleFilled(sv_cursor_pos, sv_cursor_rad, user_col32_striped_of_alpha, 12);
+ draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad+1, col_midgrey, 12);
+ draw_list->AddCircle(sv_cursor_pos, sv_cursor_rad, col_white, 12);
// Render alpha bar
if (alpha_bar)
{
float alpha = ImSaturate(col[3]);
ImRect bar1_bb(bar1_pos_x, picker_pos.y, bar1_pos_x + bars_width, picker_pos.y + sv_picker_size);
- RenderColorRectWithAlphaCheckerboard(bar1_bb.Min, bar1_bb.Max, IM_COL32(0,0,0,0), bar1_bb.GetWidth() / 2.0f, ImVec2(0.0f, 0.0f));
- draw_list->AddRectFilledMultiColor(bar1_bb.Min, bar1_bb.Max, col32_no_alpha, col32_no_alpha, col32_no_alpha & ~IM_COL32_A_MASK, col32_no_alpha & ~IM_COL32_A_MASK);
+ RenderColorRectWithAlphaCheckerboard(bar1_bb.Min, bar1_bb.Max, 0, bar1_bb.GetWidth() / 2.0f, ImVec2(0.0f, 0.0f));
+ draw_list->AddRectFilledMultiColor(bar1_bb.Min, bar1_bb.Max, user_col32_striped_of_alpha, user_col32_striped_of_alpha, user_col32_striped_of_alpha & ~IM_COL32_A_MASK, user_col32_striped_of_alpha & ~IM_COL32_A_MASK);
float bar1_line_y = (float)(int)(picker_pos.y + (1.0f - alpha) * sv_picker_size + 0.5f);
RenderFrameBorder(bar1_bb.Min, bar1_bb.Max, 0.0f);
- RenderArrowsForVerticalBar(draw_list, ImVec2(bar1_pos_x - 1, bar1_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f);
+ RenderArrowsForVerticalBar(draw_list, ImVec2(bar1_pos_x - 1, bar1_line_y), ImVec2(bars_triangles_half_sz + 1, bars_triangles_half_sz), bars_width + 2.0f, style.Alpha);
}
EndGroup();
@@ -5143,31 +5197,38 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
const ImVec2 label_size = CalcTextSize(label, label_end, false);
// We vertically grow up to current line height up the typical widget height.
- const float text_base_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it
const float frame_height = ImMax(ImMin(window->DC.CurrLineSize.y, g.FontSize + style.FramePadding.y*2), label_size.y + padding.y*2);
- ImRect frame_bb = ImRect(window->DC.CursorPos, ImVec2(window->WorkRect.Max.x, window->DC.CursorPos.y + frame_height));
+ ImRect frame_bb;
+ frame_bb.Min.x = (flags & ImGuiTreeNodeFlags_SpanFullWidth) ? window->WorkRect.Min.x : window->DC.CursorPos.x;
+ frame_bb.Min.y = window->DC.CursorPos.y;
+ frame_bb.Max.x = window->WorkRect.Max.x;
+ frame_bb.Max.y = window->DC.CursorPos.y + frame_height;
if (display_frame)
{
- // Framed header expand a little outside the default padding
+ // Framed header expand a little outside the default padding, to the edge of InnerClipRect
+ // (FIXME: May remove this at some point and make InnerClipRect align with WindowPadding.x instead of WindowPadding.x*0.5f)
frame_bb.Min.x -= (float)(int)(window->WindowPadding.x * 0.5f - 1.0f);
frame_bb.Max.x += (float)(int)(window->WindowPadding.x * 0.5f);
}
- const float text_offset_x = (g.FontSize + (display_frame ? padding.x*3 : padding.x*2)); // Collapser arrow width + Spacing
- const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x*2 : 0.0f); // Include collapser
- ItemSize(ImVec2(text_width, frame_height), text_base_offset_y);
+ const float text_offset_x = g.FontSize + (display_frame ? padding.x*3 : padding.x*2); // Collapser arrow width + Spacing
+ const float text_offset_y = ImMax(padding.y, window->DC.CurrLineTextBaseOffset); // Latch before ItemSize changes it
+ const float text_width = g.FontSize + (label_size.x > 0.0f ? label_size.x + padding.x*2 : 0.0f); // Include collapser
+ ImVec2 text_pos(window->DC.CursorPos.x + text_offset_x, window->DC.CursorPos.y + text_offset_y);
+ ItemSize(ImVec2(text_width, frame_height), text_offset_y);
// For regular tree nodes, we arbitrary allow to click past 2 worth of ItemSpacing
- // (Ideally we'd want to add a flag for the user to specify if we want the hit test to be done up to the right side of the content or not)
- const ImRect interact_bb = display_frame ? frame_bb : ImRect(frame_bb.Min.x, frame_bb.Min.y, frame_bb.Min.x + text_width + style.ItemSpacing.x*2, frame_bb.Max.y);
- bool is_open = TreeNodeBehaviorIsOpen(id, flags);
- bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0;
-
+ ImRect interact_bb = frame_bb;
+ if (!display_frame && (flags & (ImGuiTreeNodeFlags_SpanAvailWidth | ImGuiTreeNodeFlags_SpanFullWidth)) == 0)
+ interact_bb.Max.x = frame_bb.Min.x + text_width + style.ItemSpacing.x * 2.0f;
+
// Store a flag for the current depth to tell if we will allow closing this node when navigating one of its child.
// For this purpose we essentially compare if g.NavIdIsAlive went from 0 to 1 between TreeNode() and TreePop().
// This is currently only support 32 level deep and we are fine with (1 << Depth) overflowing into a zero.
+ const bool is_leaf = (flags & ImGuiTreeNodeFlags_Leaf) != 0;
+ bool is_open = TreeNodeBehaviorIsOpen(id, flags);
if (is_open && !g.NavIdIsAlive && (flags & ImGuiTreeNodeFlags_NavLeftJumpsBackHere) && !(flags & ImGuiTreeNodeFlags_NoTreePushOnOpen))
- window->DC.TreeStoreMayJumpToParentOnPop |= (1 << window->DC.TreeDepth);
+ window->DC.TreeMayJumpToParentOnPopMask |= (1 << window->DC.TreeDepth);
bool item_add = ItemAdd(interact_bb, id);
window->DC.LastItemStatusFlags |= ImGuiItemStatusFlags_HasDisplayRect;
@@ -5239,7 +5300,6 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
// Render
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)
{
@@ -5247,7 +5307,12 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
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);
+ if (flags & ImGuiTreeNodeFlags_Bullet)
+ RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.60f, text_pos.y + g.FontSize * 0.5f), text_col);
+ else if (!is_leaf)
+ RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y), text_col, is_open ? ImGuiDir_Down : ImGuiDir_Right, 1.0f);
+ else // Leaf without bullet, left-adjusted text
+ text_pos.x -= text_offset_x;
if (flags & ImGuiTreeNodeFlags_ClipLabelForTrailingButton)
frame_bb.Max.x -= g.FontSize + style.FramePadding.x;
if (g.LogEnabled)
@@ -5273,11 +5338,10 @@ bool ImGui::TreeNodeBehavior(ImGuiID id, ImGuiTreeNodeFlags flags, const char* l
RenderFrame(frame_bb.Min, frame_bb.Max, bg_col, false);
RenderNavHighlight(frame_bb, id, nav_highlight_flags);
}
-
if (flags & ImGuiTreeNodeFlags_Bullet)
- RenderBullet(window->DrawList, frame_bb.Min + ImVec2(text_offset_x * 0.5f, g.FontSize*0.50f + text_base_offset_y), text_col);
+ RenderBullet(window->DrawList, ImVec2(text_pos.x - text_offset_x * 0.5f, text_pos.y + g.FontSize * 0.5f), text_col);
else if (!is_leaf)
- RenderArrow(window->DrawList, frame_bb.Min + ImVec2(padding.x, g.FontSize*0.15f + text_base_offset_y), text_col, is_open ? ImGuiDir_Down : ImGuiDir_Right, 0.70f);
+ RenderArrow(window->DrawList, ImVec2(text_pos.x - text_offset_x + padding.x, text_pos.y + g.FontSize * 0.15f), text_col, is_open ? ImGuiDir_Down : ImGuiDir_Right, 0.70f);
if (g.LogEnabled)
LogRenderedText(&text_pos, ">");
RenderText(text_pos, label, label_end, false);
@@ -5320,13 +5384,16 @@ void ImGui::TreePop()
Unindent();
window->DC.TreeDepth--;
+ ImU32 tree_depth_mask = (1 << window->DC.TreeDepth);
+
+ // Handle Left arrow to move to parent tree node (when ImGuiTreeNodeFlags_NavLeftJumpsBackHere is enabled)
if (g.NavMoveDir == ImGuiDir_Left && g.NavWindow == window && NavMoveRequestButNoResultYet())
- if (g.NavIdIsAlive && (window->DC.TreeStoreMayJumpToParentOnPop & (1 << window->DC.TreeDepth)))
+ if (g.NavIdIsAlive && (window->DC.TreeMayJumpToParentOnPopMask & tree_depth_mask))
{
SetNavID(window->IDStack.back(), g.NavLayer);
NavMoveRequestCancel();
}
- window->DC.TreeStoreMayJumpToParentOnPop &= (1 << window->DC.TreeDepth) - 1;
+ window->DC.TreeMayJumpToParentOnPopMask &= tree_depth_mask - 1;
IM_ASSERT(window->IDStack.Size > 1); // There should always be 1 element in the IDStack (pushed during window creation). If this triggers you called TreePop/PopID too much.
PopID();
@@ -5473,7 +5540,7 @@ bool ImGui::Selectable(const char* label, bool selected, ImGuiSelectableFlags fl
bool hovered, held;
bool pressed = ButtonBehavior(bb, id, &hovered, &held, button_flags);
- // Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed with gamepad/keyboard
+ // Update NavId when clicking or when Hovering (this doesn't happen on most widgets), so navigation can be resumed with gamepad/keyboard
if (pressed || (hovered && (flags & ImGuiSelectableFlags_SetNavIdOnHover)))
{
if (!g.NavDisableMouseHover && g.NavWindow == window && g.NavLayer == window->DC.NavLayerCurrent)
@@ -5593,7 +5660,7 @@ bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_item
// We include ItemSpacing.y so that a list sized for the exact number of items doesn't make a scrollbar appears. We could also enforce that by passing a flag to BeginChild().
ImVec2 size;
size.x = 0.0f;
- size.y = GetTextLineHeightWithSpacing() * height_in_items_f + style.FramePadding.y * 2.0f;
+ size.y = ImFloor(GetTextLineHeightWithSpacing() * height_in_items_f + style.FramePadding.y * 2.0f);
return ListBoxHeader(label, size);
}
@@ -6265,8 +6332,8 @@ ImGuiTabBar::ImGuiTabBar()
ID = 0;
SelectedTabId = NextSelectedTabId = VisibleTabId = 0;
CurrFrameVisible = PrevFrameVisible = -1;
- ContentsHeight = 0.0f;
- OffsetMax = OffsetNextTab = 0.0f;
+ LastTabContentHeight = 0.0f;
+ OffsetMax = OffsetMaxIdeal = OffsetNextTab = 0.0f;
ScrollingAnim = ScrollingTarget = ScrollingTargetDistToVisibility = ScrollingSpeed = 0.0f;
Flags = ImGuiTabBarFlags_None;
ReorderRequestTabId = 0;
@@ -6348,7 +6415,7 @@ bool ImGui::BeginTabBarEx(ImGuiTabBar* tab_bar, const ImRect& tab_bar_bb, ImG
tab_bar->FramePadding = g.Style.FramePadding;
// Layout
- ItemSize(ImVec2(0.0f /*tab_bar->OffsetMax*/, tab_bar->BarRect.GetHeight())); // Don't feed width back
+ ItemSize(ImVec2(tab_bar->OffsetMaxIdeal, tab_bar->BarRect.GetHeight()));
window->DC.CursorPos.x = tab_bar->BarRect.Min.x;
// Draw separator
@@ -6381,9 +6448,9 @@ void ImGui::EndTabBar()
// Restore the last visible height if no tab is visible, this reduce vertical flicker/movement when a tabs gets removed without calling SetTabItemClosed().
const bool tab_bar_appearing = (tab_bar->PrevFrameVisible + 1 < g.FrameCount);
if (tab_bar->VisibleTabWasSubmitted || tab_bar->VisibleTabId == 0 || tab_bar_appearing)
- tab_bar->ContentsHeight = ImMax(window->DC.CursorPos.y - tab_bar->BarRect.Max.y, 0.0f);
+ tab_bar->LastTabContentHeight = ImMax(window->DC.CursorPos.y - tab_bar->BarRect.Max.y, 0.0f);
else
- window->DC.CursorPos.y = tab_bar->BarRect.Max.y + tab_bar->ContentsHeight;
+ window->DC.CursorPos.y = tab_bar->BarRect.Max.y + tab_bar->LastTabContentHeight;
if ((tab_bar->Flags & ImGuiTabBarFlags_DockNode) == 0)
PopID();
@@ -6502,11 +6569,13 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
{
ImGuiTabItem* tab = &tab_bar->Tabs[tab_n];
tab->Width = ImMin(tab->WidthContents, tab_max_width);
+ IM_ASSERT(tab->Width > 0.0f);
}
}
// Layout all active tabs
float offset_x = initial_offset_x;
+ float offset_x_ideal = offset_x;
tab_bar->OffsetNextTab = offset_x; // This is used by non-reorderable tab bar where the submission order is always honored.
for (int tab_n = 0; tab_n < tab_bar->Tabs.Size; tab_n++)
{
@@ -6515,8 +6584,10 @@ static void ImGui::TabBarLayout(ImGuiTabBar* tab_bar)
if (scroll_track_selected_tab_id == 0 && g.NavJustMovedToId == tab->ID)
scroll_track_selected_tab_id = tab->ID;
offset_x += tab->Width + g.Style.ItemInnerSpacing.x;
+ offset_x_ideal += tab->WidthContents + g.Style.ItemInnerSpacing.x;
}
tab_bar->OffsetMax = ImMax(offset_x - g.Style.ItemInnerSpacing.x, 0.0f);
+ tab_bar->OffsetMaxIdeal = ImMax(offset_x_ideal - g.Style.ItemInnerSpacing.x, 0.0f);
// Horizontal scrolling buttons
const bool scrolling_buttons = (tab_bar->OffsetMax > tab_bar->BarRect.GetWidth() && tab_bar->Tabs.Size > 1) && !(tab_bar->Flags & ImGuiTabBarFlags_NoTabListScrollingButtons) && (tab_bar->Flags & ImGuiTabBarFlags_FittingPolicyScroll);
@@ -6631,7 +6702,7 @@ static void ImGui::TabBarScrollToTab(ImGuiTabBar* tab_bar, ImGuiTabItem* tab)
float tab_x1 = tab->Offset + (order > 0 ? -margin : 0.0f);
float tab_x2 = tab->Offset + tab->Width + (order + 1 < tab_bar->Tabs.Size ? margin : 1.0f);
tab_bar->ScrollingTargetDistToVisibility = 0.0f;
- if (tab_bar->ScrollingTarget > tab_x1)
+ if (tab_bar->ScrollingTarget > tab_x1 || (tab_x2 - tab_x1 >= tab_bar->BarRect.GetWidth()))
{
tab_bar->ScrollingTargetDistToVisibility = ImMax(tab_bar->ScrollingAnim - tab_x2, 0.0f);
tab_bar->ScrollingTarget = tab_x1;
@@ -6895,7 +6966,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
ImRect bb(pos, pos + size);
// We don't have CPU clipping primitives to clip the CloseButton (until it becomes a texture), so need to add an extra draw call (temporary in the case of vertical animation)
- bool want_clip_rect = (bb.Min.x < tab_bar->BarRect.Min.x) || (bb.Max.x >= tab_bar->BarRect.Max.x);
+ bool want_clip_rect = (bb.Min.x < tab_bar->BarRect.Min.x) || (bb.Max.x > tab_bar->BarRect.Max.x);
if (want_clip_rect)
PushClipRect(ImVec2(ImMax(bb.Min.x, tab_bar->BarRect.Min.x), bb.Min.y - 1), ImVec2(tab_bar->BarRect.Max.x, bb.Max.y), true);
@@ -7254,7 +7325,7 @@ void ImGui::PushColumnsBackground()
return;
window->DrawList->ChannelsSetCurrent(0);
int cmd_size = window->DrawList->CmdBuffer.Size;
- PushClipRect(columns->HostClipRect.Min, columns->HostClipRect.Max, false);
+ 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
}
diff --git a/imgui/imstb_rectpack.h b/imgui/imstb_rectpack.h
index 23f922a5..ff2a85df 100644
--- a/imgui/imstb_rectpack.h
+++ b/imgui/imstb_rectpack.h
@@ -1,10 +1,10 @@
-// [DEAR IMGUI]
-// This is a slightly modified version of stb_rect_pack.h 0.99.
+// [DEAR IMGUI]
+// This is a slightly modified version of stb_rect_pack.h 1.00.
// Those changes would need to be pushed into nothings/stb:
// - Added STBRP__CDECL
// Grep for [DEAR IMGUI] to find the changes.
-// stb_rect_pack.h - v0.99 - public domain - rectangle packing
+// stb_rect_pack.h - v1.00 - public domain - rectangle packing
// Sean Barrett 2014
//
// Useful for e.g. packing rectangular textures into an atlas.
@@ -37,9 +37,11 @@
//
// Bugfixes / warning fixes
// Jeremy Jaussaud
+// Fabian Giesen
//
// Version history:
//
+// 1.00 (2019-02-25) avoid small space waste; gracefully fail too-wide rectangles
// 0.99 (2019-02-07) warning fixes
// 0.11 (2017-03-03) return packing success/fail result
// 0.10 (2016-10-25) remove cast-away-const to avoid warnings
@@ -357,6 +359,13 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt
width -= width % c->align;
STBRP_ASSERT(width % c->align == 0);
+ // if it can't possibly fit, bail immediately
+ if (width > c->width || height > c->height) {
+ fr.prev_link = NULL;
+ fr.x = fr.y = 0;
+ return fr;
+ }
+
node = c->active_head;
prev = &c->active_head;
while (node->x + width <= c->width) {
@@ -420,7 +429,7 @@ static stbrp__findresult stbrp__skyline_find_best_pos(stbrp_context *c, int widt
}
STBRP_ASSERT(node->next->x > xpos && node->x <= xpos);
y = stbrp__skyline_find_min_y(c, node, xpos, width, &waste);
- if (y + height < c->height) {
+ if (y + height <= c->height) {
if (y <= best_y) {
if (y < best_y || waste < best_waste || (waste==best_waste && xpos < best_x)) {
best_x = xpos;