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>2021-01-08 21:32:46 +0300
committerBartosz Taudul <wolf.pld@gmail.com>2021-01-08 21:33:04 +0300
commitcc5c20db46f9cb9eea1862390bdee9b55b4d9646 (patch)
treebee4b741882435884d949b78e28dbfc29f554e01 /imgui
parent3d37c686cfcd77ed37f33ea92d8dd195ef1f28ff (diff)
Bump ImGui.
Diffstat (limited to 'imgui')
-rw-r--r--imgui/LICENSE.txt2
-rw-r--r--imgui/imgui.cpp83
-rw-r--r--imgui/imgui.h303
-rw-r--r--imgui/imgui_demo.cpp701
-rw-r--r--imgui/imgui_draw.cpp121
-rw-r--r--imgui/imgui_internal.h95
-rw-r--r--imgui/imgui_tables.cpp1610
-rw-r--r--imgui/imgui_widgets.cpp22
8 files changed, 1706 insertions, 1231 deletions
diff --git a/imgui/LICENSE.txt b/imgui/LICENSE.txt
index d8763995..780533dc 100644
--- a/imgui/LICENSE.txt
+++ b/imgui/LICENSE.txt
@@ -1,6 +1,6 @@
The MIT License (MIT)
-Copyright (c) 2014-2020 Omar Cornut
+Copyright (c) 2014-2021 Omar Cornut
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
diff --git a/imgui/imgui.cpp b/imgui/imgui.cpp
index 34b7634a..bbe9a7fa 100644
--- a/imgui/imgui.cpp
+++ b/imgui/imgui.cpp
@@ -126,7 +126,7 @@ CODE
- You can apply arithmetic operators +,*,/ on numerical values. Use +- to subtract (because - would set a negative value!)
- Controls are automatically adjusted for OSX to match standard OSX text editing operations.
- General Keyboard controls: enable with ImGuiConfigFlags_NavEnableKeyboard.
- - General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://goo.gl/9LgVZW
+ - General Gamepad controls: enable with ImGuiConfigFlags_NavEnableGamepad. See suggested mappings in imgui.h ImGuiNavInput_ + download PNG/PSD at http://dearimgui.org/controls_sheets
PROGRAMMER GUIDE
@@ -158,18 +158,20 @@ CODE
HOW TO UPDATE TO A NEWER VERSION OF DEAR IMGUI
----------------------------------------------
- Overwrite all the sources files except for imconfig.h (if you have made modification to your copy of imconfig.h)
- - Or maintain your own branch where you have imconfig.h modified.
+ - Or maintain your own branch where you have imconfig.h modified as a top-most commit which you can regularly rebase over master.
+ - You can also use '#define IMGUI_USER_CONFIG "my_config_file.h" to redirect configuration to your own file.
- Read the "API BREAKING CHANGES" section (below). This is where we list occasional API breaking changes.
If a function/type has been renamed / or marked obsolete, try to fix the name in your code before it is permanently removed
from the public API. If you have a problem with a missing function/symbols, search for its name in the code, there will
likely be a comment about it. Please report any issue to the GitHub page!
- - Try to keep your copy of dear imgui reasonably up to date.
+ - To find out usage of old API, you can add '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in your configuration file.
+ - Try to keep your copy of Dear ImGui reasonably up to date.
GETTING STARTED WITH INTEGRATING DEAR IMGUI IN YOUR CODE/ENGINE
---------------------------------------------------------------
- Run and study the examples and demo in imgui_demo.cpp to get acquainted with the library.
- - In the majority of cases you should be able to use unmodified backends files available in the examples/ folder.
+ - In the majority of cases you should be able to use unmodified backends files available in the backends/ folder.
- Add the Dear ImGui source files + selected backend source files to your projects or using your preferred build system.
It is recommended you build and statically link the .cpp files as part of your project and NOT as shared library (DLL).
- You can later customize the imconfig.h file to tweak some compile-time behavior, such as integrating Dear ImGui types with your own maths types.
@@ -350,7 +352,7 @@ CODE
0.0f= not held. 1.0f= fully held. Pass intermediate 0.0f..1.0f values for analog triggers/sticks.
- We uses a simple >0.0f test for activation testing, and won't attempt to test for a dead-zone.
Your code will probably need to transform your raw inputs (such as e.g. remapping your 0.2..0.9 raw input range to 0.0..1.0 imgui range, etc.).
- - You can download PNG/PSD files depicting the gamepad controls for common controllers at: http://goo.gl/9LgVZW.
+ - You can download PNG/PSD files depicting the gamepad controls for common controllers at: http://dearimgui.org/controls_sheets
- If you need to share inputs between your game and the imgui parts, the easiest approach is to go all-or-nothing, with a buttons combo
to toggle the target. Please reach out if you think the game vs navigation input sharing could be improved.
- Mouse:
@@ -382,6 +384,12 @@ CODE
- 2020/XX/XX (1.XX) - Moved IME support functions from io.ImeSetInputScreenPosFn, io.ImeWindowHandle to the PlatformIO api.
+ - 2020/12/21 (1.80) - removed redirecting functions/enums that were marked obsolete in 1.63 (August 2018):
+ - ImGui::IsItemDeactivatedAfterChange() -> use ImGui::IsItemDeactivatedAfterEdit().
+ - ImGuiCol_ModalWindowDarkening -> use ImGuiCol_ModalWindowDimBg
+ - ImGuiInputTextCallback -> use ImGuiTextEditCallback
+ - ImGuiInputTextCallbackData -> use ImGuiTextEditCallbackData
+ - 2020/12/21 (1.80) - renamed ImDrawList::AddBezierCurve() to AddBezierCubic(), and PathBezierCurveTo() to PathBezierCubicCurveTo(). Kept inline redirection function (will obsolete).
- 2020/12/04 (1.80) - added imgui_tables.cpp file! Manually constructed project files will need the new file added!
- 2020/11/18 (1.80) - renamed undocumented/internals ImGuiColumnsFlags_* to ImGuiOldColumnFlags_* in prevision of incoming Tables API.
- 2020/11/03 (1.80) - renamed io.ConfigWindowsMemoryCompactTimer to io.ConfigMemoryCompactTimer as the feature will apply to other data structures
@@ -960,7 +968,7 @@ ImGuiStyle::ImGuiStyle()
{
Alpha = 1.0f; // Global alpha applies to everything in ImGui
WindowPadding = ImVec2(8,8); // Padding within a window
- WindowRounding = 7.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended.
+ WindowRounding = 0.0f; // Radius of window corners rounding. Set to 0.0f to have rectangular windows. Large values tend to lead to variety of artifacts and are not recommended.
WindowBorderSize = 1.0f; // Thickness of border around windows. Generally set to 0.0f or 1.0f. Other values not well tested.
WindowMinSize = ImVec2(32,32); // Minimum window size
WindowTitleAlign = ImVec2(0.0f,0.5f);// Alignment for title bar text
@@ -1157,7 +1165,7 @@ void ImGuiIO::ClearInputCharacters()
// [SECTION] MISC HELPERS/UTILITIES (Geometry functions)
//-----------------------------------------------------------------------------
-ImVec2 ImBezierClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments)
+ImVec2 ImBezierCubicClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments)
{
IM_ASSERT(num_segments > 0); // Use ImBezierClosestPointCasteljau()
ImVec2 p_last = p1;
@@ -1166,7 +1174,7 @@ ImVec2 ImBezierClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3
float t_step = 1.0f / (float)num_segments;
for (int i_step = 1; i_step <= num_segments; i_step++)
{
- ImVec2 p_current = ImBezierCalc(p1, p2, p3, p4, t_step * i_step);
+ ImVec2 p_current = ImBezierCubicCalc(p1, p2, p3, p4, t_step * i_step);
ImVec2 p_line = ImLineClosestPoint(p_last, p_current, p);
float dist2 = ImLengthSqr(p - p_line);
if (dist2 < p_closest_dist2)
@@ -1180,7 +1188,7 @@ ImVec2 ImBezierClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3
}
// Closely mimics PathBezierToCasteljau() in imgui_draw.cpp
-static void BezierClosestPointCasteljauStep(const ImVec2& p, ImVec2& p_closest, ImVec2& p_last, float& p_closest_dist2, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level)
+static void ImBezierCubicClosestPointCasteljauStep(const ImVec2& p, ImVec2& p_closest, ImVec2& p_last, float& p_closest_dist2, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level)
{
float dx = x4 - x1;
float dy = y4 - y1;
@@ -1208,20 +1216,20 @@ static void BezierClosestPointCasteljauStep(const ImVec2& p, ImVec2& p_closest,
float x123 = (x12 + x23)*0.5f, y123 = (y12 + y23)*0.5f;
float x234 = (x23 + x34)*0.5f, y234 = (y23 + y34)*0.5f;
float x1234 = (x123 + x234)*0.5f, y1234 = (y123 + y234)*0.5f;
- BezierClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
- BezierClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
+ ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
+ ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
}
}
// tess_tol is generally the same value you would find in ImGui::GetStyle().CurveTessellationTol
// Because those ImXXX functions are lower-level than ImGui:: we cannot access this value automatically.
-ImVec2 ImBezierClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol)
+ImVec2 ImBezierCubicClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol)
{
IM_ASSERT(tess_tol > 0.0f);
ImVec2 p_last = p1;
ImVec2 p_closest;
float p_closest_dist2 = FLT_MAX;
- BezierClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, tess_tol, 0);
+ ImBezierCubicClosestPointCasteljauStep(p, p_closest, p_last, p_closest_dist2, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, tess_tol, 0);
return p_closest;
}
@@ -2303,8 +2311,8 @@ bool ImGuiListClipper::Step()
if (table && table->IsInsideRow)
ImGui::TableEndRow(table);
- // Reached end of list
- if (DisplayEnd >= ItemsCount || GetSkipItemForListClipping())
+ // No items
+ if (ItemsCount == 0 || GetSkipItemForListClipping())
{
End();
return false;
@@ -2315,7 +2323,7 @@ bool ImGuiListClipper::Step()
{
// While we are in frozen row state, keep displaying items one by one, unclipped
// FIXME: Could be stored as a table-agnostic state.
- if (table != NULL && !table->IsUnfrozen)
+ if (table != NULL && !table->IsUnfrozenRows)
{
DisplayStart = ItemsFrozen;
DisplayEnd = ItemsFrozen + 1;
@@ -2357,6 +2365,13 @@ bool ImGuiListClipper::Step()
StepNo = 2;
}
+ // Reached end of list
+ if (DisplayEnd >= ItemsCount)
+ {
+ End();
+ return false;
+ }
+
// Step 2: calculate the actual range of elements to display, and position the cursor before the first element
if (StepNo == 2)
{
@@ -3054,6 +3069,7 @@ void ImGui::SetActiveID(ImGuiID id, ImGuiWindow* window)
// Clear declaration of inputs claimed by the widget
// (Please note that this is WIP and not all keys/inputs are thoroughly declared by all widgets yet)
+ g.ActiveIdUsingMouseWheel = false;
g.ActiveIdUsingNavDirMask = 0x00;
g.ActiveIdUsingNavInputMask = 0x00;
g.ActiveIdUsingKeyInputMask = 0x00;
@@ -3069,6 +3085,7 @@ void ImGui::SetHoveredID(ImGuiID id)
ImGuiContext& g = *GImGui;
g.HoveredId = id;
g.HoveredIdAllowOverlap = false;
+ g.HoveredIdUsingMouseWheel = false;
if (id != 0 && g.HoveredIdPreviousFrame != id)
g.HoveredIdTimer = g.HoveredIdNotActiveTimer = 0.0f;
}
@@ -3749,6 +3766,9 @@ void ImGui::UpdateMouseWheel()
if (g.IO.MouseWheel == 0.0f && g.IO.MouseWheelH == 0.0f)
return;
+ if ((g.ActiveId != 0 && g.ActiveIdUsingMouseWheel) || (g.HoveredIdPreviousFrame != 0 && g.HoveredIdPreviousFrameUsingMouseWheel))
+ return;
+
ImGuiWindow* window = g.WheelingWindow ? g.WheelingWindow : g.HoveredWindow;
if (!window || window->Collapsed)
return;
@@ -3988,8 +4008,10 @@ void ImGui::NewFrame()
if (g.HoveredId && g.ActiveId != g.HoveredId)
g.HoveredIdNotActiveTimer += g.IO.DeltaTime;
g.HoveredIdPreviousFrame = g.HoveredId;
+ g.HoveredIdPreviousFrameUsingMouseWheel = g.HoveredIdUsingMouseWheel;
g.HoveredId = 0;
g.HoveredIdAllowOverlap = false;
+ g.HoveredIdUsingMouseWheel = false;
g.HoveredIdDisabled = false;
// Update ActiveId data (clear reference to active widget if the widget isn't alive anymore)
@@ -5062,15 +5084,27 @@ bool ImGui::IsItemEdited()
}
// Allow last item to be overlapped by a subsequent item. Both may be activated during the same frame before the later one takes priority.
+// FIXME: Although this is exposed, its interaction and ideal idiom with using ImGuiButtonFlags_AllowItemOverlap flag are extremely confusing, need rework.
void ImGui::SetItemAllowOverlap()
{
ImGuiContext& g = *GImGui;
- if (g.HoveredId == g.CurrentWindow->DC.LastItemId)
+ ImGuiID id = g.CurrentWindow->DC.LastItemId;
+ if (g.HoveredId == id)
g.HoveredIdAllowOverlap = true;
- if (g.ActiveId == g.CurrentWindow->DC.LastItemId)
+ if (g.ActiveId == id)
g.ActiveIdAllowOverlap = true;
}
+void ImGui::SetItemUsingMouseWheel()
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiID id = g.CurrentWindow->DC.LastItemId;
+ if (g.HoveredId == id)
+ g.HoveredIdUsingMouseWheel = true;
+ if (g.ActiveId == id)
+ g.ActiveIdUsingMouseWheel = true;
+}
+
ImVec2 ImGui::GetItemRectMin()
{
ImGuiWindow* window = GetCurrentWindowRead();
@@ -6089,6 +6123,8 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->HiddenFramesCanSkipItems--;
if (window->HiddenFramesCannotSkipItems > 0)
window->HiddenFramesCannotSkipItems--;
+ if (window->HiddenFramesForRenderOnly > 0)
+ window->HiddenFramesForRenderOnly--;
// Hide new windows for one frame until they calculate their size
if (window_just_created && (!window_size_x_set_by_api || !window_size_y_set_by_api))
@@ -6384,7 +6420,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
int border_held = -1;
ImU32 resize_grip_col[4] = {};
const int resize_grip_count = g.IO.ConfigWindowsResizeFromEdges ? 2 : 1; // Allow resize from lower-left if we have the mouse cursor feedback for it.
- const float resize_grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.35f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
+ const float resize_grip_draw_size = IM_FLOOR(ImMax(g.FontSize * 1.10f, window->WindowRounding + 1.0f + g.FontSize * 0.2f));
if (handle_borders_and_resize_grips && !window->Collapsed)
if (UpdateWindowManualResize(window, size_auto_fit, &border_held, resize_grip_count, &resize_grip_col[0], visibility_rect))
use_current_size_for_scrollbar_x = use_current_size_for_scrollbar_y = true;
@@ -6730,7 +6766,7 @@ bool ImGui::Begin(const char* name, bool* p_open, ImGuiWindowFlags flags)
window->HiddenFramesCanSkipItems = 1;
// Update the Hidden flag
- window->Hidden = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0);
+ window->Hidden = (window->HiddenFramesCanSkipItems > 0) || (window->HiddenFramesCannotSkipItems > 0) || (window->HiddenFramesForRenderOnly > 0);
// Update the SkipItems flag, used to early out of all items functions (no layout required)
bool skip_items = false;
@@ -8505,7 +8541,7 @@ void ImGui::BeginTooltipEx(ImGuiWindowFlags extra_flags, ImGuiTooltipFlags toolt
{
// Hide previous tooltip from being displayed. We can't easily "reset" the content of a window so we create a new one.
window->Hidden = true;
- window->HiddenFramesCanSkipItems = 1;
+ window->HiddenFramesCanSkipItems = 1; // FIXME: This may not be necessary?
ImFormatString(window_name, IM_ARRAYSIZE(window_name), "##Tooltip_%02d", ++g.TooltipOverrideCount);
}
ImGuiWindowFlags flags = ImGuiWindowFlags_Tooltip | ImGuiWindowFlags_NoInputs | ImGuiWindowFlags_NoTitleBar | ImGuiWindowFlags_NoMove | ImGuiWindowFlags_NoResize | ImGuiWindowFlags_NoSavedSettings | ImGuiWindowFlags_AlwaysAutoResize | ImGuiWindowFlags_NoDocking;
@@ -15702,8 +15738,8 @@ void ImGui::ShowMetricsWindow(bool* p_open)
// Debugging enums
enum { WRT_OuterRect, WRT_OuterRectClipped, WRT_InnerRect, WRT_InnerClipRect, WRT_WorkRect, WRT_Content, WRT_ContentRegionRect, WRT_Count }; // Windows Rect Type
const char* wrt_rects_names[WRT_Count] = { "OuterRect", "OuterRectClipped", "InnerRect", "InnerClipRect", "WorkRect", "Content", "ContentRegionRect" };
- enum { TRT_OuterRect, TRT_WorkRect, TRT_HostClipRect, TRT_InnerClipRect, TRT_BackgroundClipRect, TRT_ColumnsRect, TRT_ColumnsClipRect, TRT_ColumnsContentHeadersUsed, TRT_ColumnsContentHeadersIdeal, TRT_ColumnsContentFrozen, TRT_ColumnsContentUnfrozen, TRT_Count }; // Tables Rect Type
- const char* trt_rects_names[TRT_Count] = { "OuterRect", "WorkRect", "HostClipRect", "InnerClipRect", "BackgroundClipRect", "ColumnsRect", "ColumnsClipRect", "ColumnsContentHeadersUsed", "ColumnsContentHeadersIdeal", "ColumnsContentFrozen", "ColumnsContentUnfrozen" };
+ enum { TRT_OuterRect, TRT_InnerRect, TRT_WorkRect, TRT_HostClipRect, TRT_InnerClipRect, TRT_BackgroundClipRect, TRT_ColumnsRect, TRT_ColumnsClipRect, TRT_ColumnsContentHeadersUsed, TRT_ColumnsContentHeadersIdeal, TRT_ColumnsContentFrozen, TRT_ColumnsContentUnfrozen, TRT_Count }; // Tables Rect Type
+ const char* trt_rects_names[TRT_Count] = { "OuterRect", "InnerRect", "WorkRect", "HostClipRect", "InnerClipRect", "BackgroundClipRect", "ColumnsRect", "ColumnsClipRect", "ColumnsContentHeadersUsed", "ColumnsContentHeadersIdeal", "ColumnsContentFrozen", "ColumnsContentUnfrozen" };
if (cfg->ShowWindowsRectsType < 0)
cfg->ShowWindowsRectsType = WRT_WorkRect;
if (cfg->ShowTablesRectsType < 0)
@@ -15714,6 +15750,7 @@ void ImGui::ShowMetricsWindow(bool* p_open)
static ImRect GetTableRect(ImGuiTable* table, int rect_type, int n)
{
if (rect_type == TRT_OuterRect) { return table->OuterRect; }
+ else if (rect_type == TRT_InnerRect) { return table->InnerRect; }
else if (rect_type == TRT_WorkRect) { return table->WorkRect; }
else if (rect_type == TRT_HostClipRect) { return table->HostClipRect; }
else if (rect_type == TRT_InnerClipRect) { return table->InnerClipRect; }
diff --git a/imgui/imgui.h b/imgui/imgui.h
index 52110b8d..26ba8ecc 100644
--- a/imgui/imgui.h
+++ b/imgui/imgui.h
@@ -19,28 +19,25 @@
/*
Index of this file:
-// Header mess
-// Forward declarations and basic types
-// ImGui API (Dear ImGui end-user API)
-// Flags & Enumerations
-// Memory allocations macros
-// ImVector<>
-// ImGuiStyle
-// ImGuiIO
-// Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiWindowClass, ImGuiPayload)
-// Obsolete functions
-// Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor)
-// Draw List API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData)
-// Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont)
-// Platform interface for multi-viewport support (ImGuiPlatformIO, ImGuiPlatformMonitor, ImGuiViewportFlags, ImGuiViewport)
-
-// FIXME-TABLE: Add ImGuiTableSortSpecs and ImGuiTableColumnSortSpecs in "Misc data structures" section above (we don't do it right now to facilitate merging various branches)
+// [SECTION] Header mess
+// [SECTION] Forward declarations and basic types
+// [SECTION] Dear ImGui end-user API functions
+// [SECTION] Flags & Enumerations
+// [SECTION] Helpers: Memory allocations macros, ImVector<>
+// [SECTION] ImGuiStyle
+// [SECTION] ImGuiIO
+// [SECTION] Misc data structures (ImGuiInputTextCallbackData, ImGuiSizeCallbackData, ImGuiWindowClass, ImGuiPayload, ImGuiTableSortSpecs, ImGuiTableColumnSortSpecs)
+// [SECTION] Obsolete functions
+// [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor)
+// [SECTION] Drawing API (ImDrawCallback, ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData)
+// [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontGlyphRangesBuilder, ImFontAtlasFlags, ImFontAtlas, ImFont)
+// [SECTION] Platform interface for multi-viewport support (ImGuiPlatformIO, ImGuiPlatformMonitor, ImGuiViewportFlags, ImGuiViewport)
*/
#pragma once
-// Configuration file with compile-time options (edit imconfig.h or #define IMGUI_USER_CONFIG to your own filename)
+// Configuration file with compile-time options (edit imconfig.h or '#define IMGUI_USER_CONFIG "myfilename.h" from your build system')
#ifdef IMGUI_USER_CONFIG
#include IMGUI_USER_CONFIG
#endif
@@ -51,7 +48,7 @@ Index of this file:
#ifndef IMGUI_DISABLE
//-----------------------------------------------------------------------------
-// Header mess
+// [SECTION] Header mess
//-----------------------------------------------------------------------------
// Includes
@@ -63,10 +60,11 @@ 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.80 WIP"
-#define IMGUI_VERSION_NUM 17906
+#define IMGUI_VERSION_NUM 17909
#define IMGUI_CHECKVERSION() ImGui::DebugCheckVersionAndDataLayout(IMGUI_VERSION, sizeof(ImGuiIO), sizeof(ImGuiStyle), sizeof(ImVec2), sizeof(ImVec4), sizeof(ImDrawVert), sizeof(ImDrawIdx))
-#define IMGUI_HAS_VIEWPORT 1 // Viewport WIP branch
-#define IMGUI_HAS_DOCK 1 // Docking WIP branch
+#define IMGUI_HAS_TABLE
+#define IMGUI_HAS_VIEWPORT // Viewport WIP branch
+#define IMGUI_HAS_DOCK // Docking WIP branch
// Define attributes of all API symbols declarations (e.g. for DLL under Windows)
// IMGUI_API is used for core imgui functions, IMGUI_IMPL_API is used for the default backends files (imgui_impl_xxx.h)
@@ -90,11 +88,13 @@ Index of this file:
#else
#define IM_OFFSETOF(_TYPE,_MEMBER) ((size_t)&(((_TYPE*)0)->_MEMBER)) // Offset of _MEMBER within _TYPE. Old style macro.
#endif
+
+// Helper Macros - IM_FMTARGS, IM_FMTLIST: Apply printf-style warnings to our formatting functions.
#if !defined(IMGUI_USE_STB_SPRINTF) && defined(__clang__)
-#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1))) // Apply printf-style warnings to our formatting functions.
+#define IM_FMTARGS(FMT) __attribute__((format(printf, FMT, FMT+1)))
#define IM_FMTLIST(FMT) __attribute__((format(printf, FMT, 0)))
#elif !defined(IMGUI_USE_STB_SPRINTF) && defined(__GNUC__) && defined(__MINGW32__)
-#define IM_FMTARGS(FMT) __attribute__((format(gnu_printf, FMT, FMT+1))) // Apply printf-style warnings to our formatting functions.
+#define IM_FMTARGS(FMT) __attribute__((format(gnu_printf, FMT, FMT+1)))
#define IM_FMTLIST(FMT) __attribute__((format(gnu_printf, FMT, 0)))
#else
#define IM_FMTARGS(FMT)
@@ -110,12 +110,12 @@ Index of this file:
#endif
#elif defined(__GNUC__)
#pragma GCC diagnostic push
-#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
-#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
+#pragma GCC diagnostic ignored "-Wpragmas" // warning: unknown option after '#pragma GCC diagnostic' kind
+#pragma GCC diagnostic ignored "-Wclass-memaccess" // [__GNUC__ >= 8] warning: 'memset/memcpy' clearing/writing an object of type 'xxxx' with no trivial copy-assignment; use assignment or value-initialization instead
#endif
//-----------------------------------------------------------------------------
-// Forward declarations and basic types
+// [SECTION] Forward declarations and basic types
//-----------------------------------------------------------------------------
// Forward declarations
@@ -196,10 +196,10 @@ typedef int ImGuiWindowFlags; // -> enum ImGuiWindowFlags_ // Flags: f
typedef void* ImTextureID; // User data for rendering backend to identify a texture. This is whatever to you want it to be! read the FAQ about ImTextureID for details.
#endif
typedef unsigned int ImGuiID; // A unique ID used by widgets, typically hashed from a stack of string.
-typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data);
-typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data);
+typedef int (*ImGuiInputTextCallback)(ImGuiInputTextCallbackData* data); // Callback function for ImGui::InputText()
+typedef void (*ImGuiSizeCallback)(ImGuiSizeCallbackData* data); // Callback function for ImGui::SetNextWindowSizeConstraints()
-// Decoded character types
+// Character types
// (we generally use UTF-8 encoded string in the API. This is storage specifically for a decoded character used for keyboard input and display)
typedef unsigned short ImWchar16; // A single decoded U16 character/code point. We encode them as multi bytes UTF-8 when used in strings.
typedef unsigned int ImWchar32; // A single decoded U32 character/code point. We encode them as multi bytes UTF-8 when used in strings.
@@ -244,8 +244,8 @@ struct ImVec2
// 4D vector (often used to store floating-point colors)
struct ImVec4
{
- float x, y, z, w;
- ImVec4() { x = y = z = w = 0.0f; }
+ float x, y, z, w;
+ ImVec4() { x = y = z = w = 0.0f; }
ImVec4(float _x, float _y, float _z, float _w) { x = _x; y = _y; z = _z; w = _w; }
#ifdef IM_VEC4_CLASS_EXTRA
IM_VEC4_CLASS_EXTRA // Define additional constructors and implicit cast operators in imconfig.h to convert back and forth between your math types and ImVec4.
@@ -253,8 +253,8 @@ struct ImVec4
};
//-----------------------------------------------------------------------------
-// ImGui: Dear ImGui end-user API
-// (This is a namespace. You can add extra ImGui:: functions in your own separate file. Please don't modify imgui source files!)
+// [SECTION] Dear ImGui end-user API functions
+// (Note that ImGui:: being a namespace, you can add extra ImGui:: functions in your own separate file. Please don't modify imgui source files!)
//-----------------------------------------------------------------------------
namespace ImGui
@@ -276,19 +276,19 @@ namespace ImGui
IMGUI_API ImDrawData* GetDrawData(); // valid after Render() and until the next call to NewFrame(). this is what you have to render.
// Demo, Debug, Information
- IMGUI_API void ShowDemoWindow(bool* p_open = NULL); // create Demo window (previously called ShowTestWindow). demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application!
- IMGUI_API void ShowAboutWindow(bool* p_open = NULL); // create About window. display Dear ImGui version, credits and build/system information.
+ IMGUI_API void ShowDemoWindow(bool* p_open = NULL); // create Demo window. demonstrate most ImGui features. call this to learn about the library! try to make it always available in your application!
IMGUI_API void ShowMetricsWindow(bool* p_open = NULL); // create Metrics/Debugger window. display Dear ImGui internals: windows, draw commands, various internal state, etc.
+ IMGUI_API void ShowAboutWindow(bool* p_open = NULL); // create About window. display Dear ImGui version, credits and build/system information.
IMGUI_API void ShowStyleEditor(ImGuiStyle* ref = NULL); // add style editor block (not a window). you can pass in a reference ImGuiStyle structure to compare to, revert to and save to (else it uses the default style)
IMGUI_API bool ShowStyleSelector(const char* label); // add style selector block (not a window), essentially a combo listing the default styles.
IMGUI_API void ShowFontSelector(const char* label); // add font selector block (not a window), essentially a combo listing the loaded fonts.
IMGUI_API void ShowUserGuide(); // add basic help/info block (not a window): how to manipulate ImGui as a end-user (mouse/keyboard controls).
- IMGUI_API const char* GetVersion(); // get the compiled version string e.g. "1.23" (essentially the compiled value for IMGUI_VERSION)
+ IMGUI_API const char* GetVersion(); // get the compiled version string e.g. "1.80 WIP" (essentially the value for IMGUI_VERSION from the compiled version of imgui.cpp)
// Styles
IMGUI_API void StyleColorsDark(ImGuiStyle* dst = NULL); // new, recommended style (default)
- IMGUI_API void StyleColorsClassic(ImGuiStyle* dst = NULL); // classic imgui style
IMGUI_API void StyleColorsLight(ImGuiStyle* dst = NULL); // best used with borders and a custom, thicker font
+ IMGUI_API void StyleColorsClassic(ImGuiStyle* dst = NULL); // classic imgui style
// Windows
// - Begin() = push window to the stack and start appending to it. End() = pop window from the stack.
@@ -351,20 +351,21 @@ namespace ImGui
IMGUI_API void SetWindowFocus(const char* name); // set named window to be focused / top-most. use NULL to remove focus.
// Content region
- // - Those functions are bound to be redesigned soon (they are confusing, incomplete and return values in local window coordinates which increases confusion)
- IMGUI_API ImVec2 GetContentRegionMax(); // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates
+ // - Retrieve available space from a given point. GetContentRegionAvail() is frequently useful.
+ // - Those functions are bound to be redesigned (they are confusing, incomplete and the Min/Max return values are in local window coordinates which increases confusion)
IMGUI_API ImVec2 GetContentRegionAvail(); // == GetContentRegionMax() - GetCursorPos()
+ IMGUI_API ImVec2 GetContentRegionMax(); // current content boundaries (typically window boundaries including scrolling, or current column boundaries), in windows coordinates
IMGUI_API ImVec2 GetWindowContentRegionMin(); // content boundaries min (roughly (0,0)-Scroll), in window coordinates
IMGUI_API ImVec2 GetWindowContentRegionMax(); // content boundaries max (roughly (0,0)+Size-Scroll) where Size can be override with SetNextWindowContentSize(), in window coordinates
IMGUI_API float GetWindowContentRegionWidth(); //
// Windows Scrolling
- IMGUI_API float GetScrollX(); // get scrolling amount [0..GetScrollMaxX()]
- IMGUI_API float GetScrollY(); // get scrolling amount [0..GetScrollMaxY()]
- IMGUI_API float GetScrollMaxX(); // get maximum scrolling amount ~~ ContentSize.x - WindowSize.x
- IMGUI_API float GetScrollMaxY(); // get maximum scrolling amount ~~ ContentSize.y - WindowSize.y
- IMGUI_API void SetScrollX(float scroll_x); // set scrolling amount [0..GetScrollMaxX()]
- IMGUI_API void SetScrollY(float scroll_y); // set scrolling amount [0..GetScrollMaxY()]
+ IMGUI_API float GetScrollX(); // get scrolling amount [0 .. GetScrollMaxX()]
+ IMGUI_API float GetScrollY(); // get scrolling amount [0 .. GetScrollMaxY()]
+ IMGUI_API void SetScrollX(float scroll_x); // set scrolling amount [0 .. GetScrollMaxX()]
+ IMGUI_API void SetScrollY(float scroll_y); // set scrolling amount [0 .. GetScrollMaxY()]
+ IMGUI_API float GetScrollMaxX(); // get maximum scrolling amount ~~ ContentSize.x - WindowSize.x - DecorationsSize.x
+ IMGUI_API float GetScrollMaxY(); // get maximum scrolling amount ~~ ContentSize.y - WindowSize.y - DecorationsSize.y
IMGUI_API void SetScrollHereX(float center_x_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_x_ratio=0.0: left, 0.5: center, 1.0: right. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead.
IMGUI_API void SetScrollHereY(float center_y_ratio = 0.5f); // adjust scrolling amount to make current cursor position visible. center_y_ratio=0.0: top, 0.5: center, 1.0: bottom. When using to make a "default/current item" visible, consider using SetItemDefaultFocus() instead.
IMGUI_API void SetScrollFromPosX(float local_x, float center_x_ratio = 0.5f); // adjust scrolling amount to make given position visible. Generally GetCursorStartPos() + offset to compute a valid position.
@@ -373,23 +374,16 @@ namespace ImGui
// Parameters stacks (shared)
IMGUI_API void PushFont(ImFont* font); // use NULL as a shortcut to push default font
IMGUI_API void PopFont();
- IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col);
+ IMGUI_API void PushStyleColor(ImGuiCol idx, ImU32 col); // modify a style color. always use this if you modify the style after NewFrame().
IMGUI_API void PushStyleColor(ImGuiCol idx, const ImVec4& col);
IMGUI_API void PopStyleColor(int count = 1);
- IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val);
- IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val);
+ IMGUI_API void PushStyleVar(ImGuiStyleVar idx, float val); // modify a style float variable. always use this if you modify the style after NewFrame().
+ IMGUI_API void PushStyleVar(ImGuiStyleVar idx, const ImVec2& val); // modify a style ImVec2 variable. always use this if you modify the style after NewFrame().
IMGUI_API void PopStyleVar(int count = 1);
IMGUI_API void PushAllowKeyboardFocus(bool allow_keyboard_focus); // allow focusing using TAB/Shift-TAB, enabled by default but you can disable it for certain widgets
IMGUI_API void PopAllowKeyboardFocus();
IMGUI_API void PushButtonRepeat(bool repeat); // in 'repeat' mode, Button*() functions return repeated true in a typematic manner (using io.KeyRepeatDelay/io.KeyRepeatRate setting). Note that you can call IsItemActive() after any Button() to tell if the button is held in the current frame.
IMGUI_API void PopButtonRepeat();
- IMGUI_API const ImVec4& GetStyleColorVec4(ImGuiCol idx); // retrieve style color as stored in ImGuiStyle structure. use to feed back into PushStyleColor(), otherwise use GetColorU32() to get style color with style alpha baked in.
- IMGUI_API ImFont* GetFont(); // get current font
- IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with current scale applied
- IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a while pixel, useful to draw custom shapes via the ImDrawList API
- IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f); // retrieve given style color with style alpha applied and optional extra alpha multiplier
- IMGUI_API ImU32 GetColorU32(const ImVec4& col); // retrieve given color with style alpha applied
- IMGUI_API ImU32 GetColorU32(ImU32 col); // retrieve given color with style alpha applied
// Parameters stacks (current window)
IMGUI_API void PushItemWidth(float item_width); // push 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 -FLT_MIN always align width to the right side). 0.0f = default to ~2/3 of windows width,
@@ -399,6 +393,15 @@ namespace ImGui
IMGUI_API void PushTextWrapPos(float wrap_local_pos_x = 0.0f); // push word-wrapping position for Text*() commands. < 0.0f: no wrapping; 0.0f: wrap to end of window (or column); > 0.0f: wrap at 'wrap_pos_x' position in window local space
IMGUI_API void PopTextWrapPos();
+ // Style read access
+ IMGUI_API ImFont* GetFont(); // get current font
+ IMGUI_API float GetFontSize(); // get current font size (= height in pixels) of current font with current scale applied
+ IMGUI_API ImVec2 GetFontTexUvWhitePixel(); // get UV coordinate for a while pixel, useful to draw custom shapes via the ImDrawList API
+ IMGUI_API ImU32 GetColorU32(ImGuiCol idx, float alpha_mul = 1.0f); // retrieve given style color with style alpha applied and optional extra alpha multiplier, packed as a 32-bit value suitable for ImDrawList
+ IMGUI_API ImU32 GetColorU32(const ImVec4& col); // retrieve given color with style alpha applied, packed as a 32-bit value suitable for ImDrawList
+ IMGUI_API ImU32 GetColorU32(ImU32 col); // retrieve given color with style alpha applied, packed as a 32-bit value suitable for ImDrawList
+ IMGUI_API const ImVec4& GetStyleColorVec4(ImGuiCol idx); // retrieve style color as stored in ImGuiStyle structure. use to feed back into PushStyleColor(), otherwise use GetColorU32() to get style color with style alpha baked in.
+
// Cursor / Layout
// - By "cursor" we mean the current output position.
// - The typical widget behavior is to output themselves at the current cursor position, then move the cursor one line down.
@@ -475,7 +478,7 @@ namespace ImGui
IMGUI_API bool CheckboxFlags(const char* label, unsigned int* flags, unsigned int flags_value);
IMGUI_API bool RadioButton(const char* label, bool active); // use with e.g. if (RadioButton("one", my_value==1)) { my_value = 1; }
IMGUI_API bool RadioButton(const char* label, int* v, int v_button); // shortcut to handle the above pattern when value is an integer
- IMGUI_API void ProgressBar(float fraction, const ImVec2& size_arg = ImVec2(-1, 0), const char* overlay = NULL);
+ IMGUI_API void ProgressBar(float fraction, const ImVec2& size_arg = ImVec2(-FLT_MIN, 0), const char* overlay = NULL);
IMGUI_API void Bullet(); // draw a small circle + keep the cursor on the same line. advance cursor x position by GetTreeNodeToLabelSpacing(), same distance that TreeNode() uses
// Widgets: Combo Box
@@ -621,7 +624,7 @@ namespace ImGui
IMGUI_API bool MenuItem(const char* label, const char* shortcut, bool* p_selected, bool enabled = true); // return true when activated + toggle (*p_selected) if p_selected != NULL
// Tooltips
- // - Tooltip are windows following the mouse which do not take focus away.
+ // - Tooltip are windows following the mouse. They do not take focus away.
IMGUI_API void BeginTooltip(); // begin/append a tooltip window. to create full-featured tooltip (with any kind of items).
IMGUI_API void EndTooltip();
IMGUI_API void SetTooltip(const char* fmt, ...) IM_FMTARGS(1); // set a text-only tooltip, typically use with ImGui::IsItemHovered(). override any previous call to SetTooltip().
@@ -673,7 +676,7 @@ namespace ImGui
// - 1. Call BeginTable()
// - 2. Optionally call TableSetupColumn() to submit column name/flags/defaults
// - 3. Optionally call TableSetupScrollFreeze() to request scroll freezing of columns/rows
- // - 4. Optionally call TableHeadersRow() to submit a header row (names will be pulled from data submitted to TableSetupColumns)
+ // - 4. Optionally call TableHeadersRow() to submit a header row. Names will be pulled from data provided TableSetupColumn() calls)
// - 5. Populate contents
// - In most situations you can use TableNextRow() + TableSetColumnIndex(N) to start appending into a column.
// - If you are using tables as a sort of grid, where every columns is holding the same type of contents,
@@ -692,8 +695,7 @@ namespace ImGui
// TableNextRow() -> Text("Hello 0") // Not OK! Missing TableSetColumnIndex() or TableNextColumn()! Text will not appear!
// ----------------------------------------------------------------------------------------------------------
// - 5. Call EndTable()
- #define IMGUI_HAS_TABLE 1
- IMGUI_API bool BeginTable(const char* str_id, int columns_count, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0, 0), float inner_width = 0.0f);
+ IMGUI_API bool BeginTable(const char* str_id, int columns_count, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(-FLT_MIN, 0), float inner_width = 0.0f);
IMGUI_API void EndTable(); // only call EndTable() if BeginTable() returns true!
IMGUI_API void TableNextRow(ImGuiTableRowFlags row_flags = 0, float min_row_height = 0.0f); // append into the first cell of a new row.
IMGUI_API bool TableNextColumn(); // append into the next column (or first column of next row if currently in last column). Return true when column is visible.
@@ -768,7 +770,6 @@ namespace ImGui
IMGUI_API void LogText(const char* fmt, ...) IM_FMTARGS(1); // pass text data straight to log (without being displayed)
// Drag and Drop
- // - [BETA API] API may evolve!
// - If you stop calling BeginDragDropSource() the payload is preserved however it won't have a preview tooltip (we currently display a fallback "..." tooltip as replacement)
IMGUI_API bool BeginDragDropSource(ImGuiDragDropFlags flags = 0); // call when the current item is active. If this return true, you can call SetDragDropPayload() + EndDragDropSource()
IMGUI_API bool SetDragDropPayload(const char* type, const void* data, size_t sz, ImGuiCond cond = 0); // type is a user defined string of maximum 32 characters. Strings starting with '_' are reserved for dear imgui internal types. Data is copied and held by imgui.
@@ -779,6 +780,7 @@ namespace ImGui
IMGUI_API const ImGuiPayload* GetDragDropPayload(); // peek directly into the current payload from anywhere. may return NULL. use ImGuiPayload::IsDataType() to test for the payload type.
// Clipping
+ // - Mouse hovering is affected by ImGui::PushClipRect() calls, unlike direct calls to ImDrawList::PushClipRect() which are render only.
IMGUI_API void PushClipRect(const ImVec2& clip_rect_min, const ImVec2& clip_rect_max, bool intersect_with_current_clip_rect);
IMGUI_API void PopClipRect();
@@ -901,7 +903,7 @@ namespace ImGui
} // namespace ImGui
//-----------------------------------------------------------------------------
-// Flags & Enumerations
+// [SECTION] Flags & Enumerations
//-----------------------------------------------------------------------------
// Flags for ImGui::Begin()
@@ -1077,62 +1079,80 @@ enum ImGuiTabItemFlags_
};
// Flags for ImGui::BeginTable()
-// - Important! Sizing policies have particularly complex and subtle side effects, more so than you would expect.
+// - Important! Sizing policies have complex and subtle side effects, more so than you would expect.
// Read comments/demos carefully + experiment with live demos to get acquainted with them.
-// - The default sizing policy for columns depends on whether the ScrollX flag is set on the table:
-// When ScrollX is off:
-// - Table defaults to ImGuiTableFlags_ColumnsWidthStretch -> all Columns defaults to ImGuiTableColumnFlags_WidthStretch.
-// - Columns sizing policy allowed: Stretch (default) or Fixed/Auto.
-// - Stretch Columns will share the width available in table.
-// - Fixed Columns will generally obtain their requested width unless the Table cannot fit them all.
-// When ScrollX is on:
-// - Table defaults to ImGuiTableFlags_ColumnsWidthFixed -> all Columns defaults to ImGuiTableColumnFlags_WidthFixed.
-// - Columns sizing policy allowed: Fixed/Auto mostly!
+// - The DEFAULT sizing policies are:
+// - Default to ImGuiTableFlags_SizingFixedFit if ScrollX is on, or if host window has ImGuiWindowFlags_AlwaysAutoResize.
+// - Default to ImGuiTableFlags_SizingStretchSame if ScrollX is off.
+// - When ScrollX is off:
+// - Table defaults to ImGuiTableFlags_SizingStretchSame -> all Columns defaults to ImGuiTableColumnFlags_WidthStretch with same weight.
+// - Columns sizing policy allowed: Stretch (default), Fixed/Auto.
+// - Fixed Columns will generally obtain their requested width (unless the table cannot fit them all).
+// - Stretch Columns will share the remaining width.
+// - Mixed Fixed/Stretch columns is possible but has various side-effects on resizing behaviors.
+// The typical use of mixing sizing policies is: any number of LEADING Fixed columns, followed by one or two TRAILING Stretch columns.
+// (this is because the visible order of columns have subtle but necessary effects on how they react to manual resizing).
+// - When ScrollX is on:
+// - Table defaults to ImGuiTableFlags_SizingFixedFit -> all Columns defaults to ImGuiTableColumnFlags_WidthFixed or ImGuiTableColumnFlags_WidthAuto.
+// - Columns sizing policy allowed: Fixed/Auto mostly.
// - Fixed Columns can be enlarged as needed. Table will show an horizontal scrollbar if needed.
+// - When using auto-resizing (non-resizable) fixed columns, querying the content width to use item right-alignment e.g. SetNextItemWidth(-FLT_MIN) doesn't make sense, would create a feedback loop.
// - Using Stretch columns OFTEN DOES NOT MAKE SENSE if ScrollX is on, UNLESS you have specified a value for 'inner_width' in BeginTable().
-// - Mixing up columns with different sizing policy is possible BUT can be tricky and has some side-effects and restrictions.
-// (their visible order and the scrolling state have subtle but necessary effects on how they can be manually resized).
-// The typical use of mixing sizing policies is to have ScrollX disabled, one or two Stretch Column and many Fixed Columns.
+// If you specify a value for 'inner_width' then effectively the scrolling space is known and Stretch or mixed Fixed/Stretch columns become meaningful again.
+// - Read on documentation at the top of imgui_tables.cpp for details.
enum ImGuiTableFlags_
{
// Features
ImGuiTableFlags_None = 0,
- ImGuiTableFlags_Resizable = 1 << 0, // Allow resizing columns.
- ImGuiTableFlags_Reorderable = 1 << 1, // Allow reordering columns in header row (need calling TableSetupColumn() + TableHeadersRow() to display headers)
- ImGuiTableFlags_Hideable = 1 << 2, // Allow hiding/disabling columns in context menu.
- ImGuiTableFlags_Sortable = 1 << 3, // Allow sorting on one column (sort_specs_count will always be == 1). Call TableGetSortSpecs() to obtain sort specs.
- ImGuiTableFlags_MultiSortable = 1 << 4, // Allow sorting on multiple columns by holding Shift (sort_specs_count may be > 1). Call TableGetSortSpecs() to obtain sort specs.
- ImGuiTableFlags_NoSavedSettings = 1 << 5, // Disable persisting columns order, width and sort settings in the .ini file.
- ImGuiTableFlags_ContextMenuInBody = 1 << 6, // Right-click on columns body/contents will display table context menu. By default it is available in TableHeadersRow().
+ ImGuiTableFlags_Resizable = 1 << 0, // Enable resizing columns.
+ ImGuiTableFlags_Reorderable = 1 << 1, // Enable reordering columns in header row (need calling TableSetupColumn() + TableHeadersRow() to display headers)
+ ImGuiTableFlags_Hideable = 1 << 2, // Enable hiding/disabling columns in context menu.
+ ImGuiTableFlags_Sortable = 1 << 3, // Enable sorting. Call TableGetSortSpecs() to obtain sort specs. Also see ImGuiTableFlags_SortMulti and ImGuiTableFlags_SortTristate.
+ ImGuiTableFlags_NoSavedSettings = 1 << 4, // Disable persisting columns order, width and sort settings in the .ini file.
+ ImGuiTableFlags_ContextMenuInBody = 1 << 5, // Right-click on columns body/contents will display table context menu. By default it is available in TableHeadersRow().
// Decorations
- ImGuiTableFlags_RowBg = 1 << 7, // Set each RowBg color with ImGuiCol_TableRowBg or ImGuiCol_TableRowBgAlt (equivalent of calling TableSetBgColor with ImGuiTableBgFlags_RowBg0 on each row manually)
- ImGuiTableFlags_BordersInnerH = 1 << 8, // Draw horizontal borders between rows.
- ImGuiTableFlags_BordersOuterH = 1 << 9, // Draw horizontal borders at the top and bottom.
- ImGuiTableFlags_BordersInnerV = 1 << 10, // Draw vertical borders between columns.
- ImGuiTableFlags_BordersOuterV = 1 << 11, // Draw vertical borders on the left and right sides.
+ ImGuiTableFlags_RowBg = 1 << 6, // Set each RowBg color with ImGuiCol_TableRowBg or ImGuiCol_TableRowBgAlt (equivalent of calling TableSetBgColor with ImGuiTableBgFlags_RowBg0 on each row manually)
+ ImGuiTableFlags_BordersInnerH = 1 << 7, // Draw horizontal borders between rows.
+ ImGuiTableFlags_BordersOuterH = 1 << 8, // Draw horizontal borders at the top and bottom.
+ ImGuiTableFlags_BordersInnerV = 1 << 9, // Draw vertical borders between columns.
+ ImGuiTableFlags_BordersOuterV = 1 << 10, // Draw vertical borders on the left and right sides.
ImGuiTableFlags_BordersH = ImGuiTableFlags_BordersInnerH | ImGuiTableFlags_BordersOuterH, // Draw horizontal borders.
ImGuiTableFlags_BordersV = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersOuterV, // Draw vertical borders.
ImGuiTableFlags_BordersInner = ImGuiTableFlags_BordersInnerV | ImGuiTableFlags_BordersInnerH, // Draw inner borders.
ImGuiTableFlags_BordersOuter = ImGuiTableFlags_BordersOuterV | ImGuiTableFlags_BordersOuterH, // Draw outer borders.
ImGuiTableFlags_Borders = ImGuiTableFlags_BordersInner | ImGuiTableFlags_BordersOuter, // Draw all borders.
- ImGuiTableFlags_NoBordersInBody = 1 << 12, // Disable vertical borders in columns Body (borders will always appears in Headers).
- ImGuiTableFlags_NoBordersInBodyUntilResize = 1 << 13, // Disable vertical borders in columns Body until hovered for resize (borders will always appears in Headers).
- // Sizing
- ImGuiTableFlags_ColumnsWidthStretch = 1 << 14, // Default if ScrollX is off. Columns will default to use _WidthStretch. Read description above for more details.
- ImGuiTableFlags_ColumnsWidthFixed = 1 << 15, // Default if ScrollX is on. Columns will default to use _WidthFixed or _WidthAutoResize policy (if Resizable is off). Read description above for more details.
- ImGuiTableFlags_SameWidths = 1 << 16, // Make all columns the same widths which is useful with Fixed columns policy (but granted by default with Stretch policy + no resize). Implicitly enable ImGuiTableFlags_NoKeepColumnsVisible and disable ImGuiTableFlags_Resizable.
- ImGuiTableFlags_NoHeadersWidth = 1 << 17, // Disable headers' contribution to automatic width calculation.
- ImGuiTableFlags_NoHostExtendY = 1 << 18, // Disable extending past the limit set by outer_size.y, only meaningful when neither of ScrollX|ScrollY are set (data below the limit will be clipped and not visible)
- ImGuiTableFlags_NoKeepColumnsVisible = 1 << 19, // Disable keeping column always minimally visible when ScrollX is off and table gets too small.
- ImGuiTableFlags_PreciseWidths = 1 << 20, // Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.
- ImGuiTableFlags_NoClip = 1 << 21, // Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with TableSetupScrollFreeze().
+ ImGuiTableFlags_NoBordersInBody = 1 << 11, // [ALPHA] Disable vertical borders in columns Body (borders will always appears in Headers). -> May move to style
+ ImGuiTableFlags_NoBordersInBodyUntilResize = 1 << 12, // [ALPHA] Disable vertical borders in columns Body until hovered for resize (borders will always appears in Headers). -> May move to style
+ // Sizing Policy (read above for defaults)
+ ImGuiTableFlags_SizingFixedFit = 1 << 13, // Columns default to _WidthFixed or _WidthAuto (if resizable or not resizable), matching contents width.
+ ImGuiTableFlags_SizingFixedSame = 2 << 13, // Columns default to _WidthFixed or _WidthAuto (if resizable or not resizable), matching the maximum contents width of all columns. Implicitly enable ImGuiTableFlags_NoKeepColumnsVisible.
+ ImGuiTableFlags_SizingStretchProp = 3 << 13, // Columns default to _WidthStretch with default weights proportional to each columns contents widths.
+ ImGuiTableFlags_SizingStretchSame = 4 << 13, // Columns default to _WidthStretch with default weights all equal, unless overriden by TableSetupColumn().
+ // Sizing Extra Options
+ ImGuiTableFlags_NoHostExtendY = 1 << 16, // Disable extending table past the limit set by outer_size.y. Only meaningful when neither ScrollX nor ScrollY are set (data below the limit will be clipped and not visible)
+ ImGuiTableFlags_NoKeepColumnsVisible = 1 << 17, // Disable keeping column always minimally visible when ScrollX is off and table gets too small. Not recommended if columns are resizable.
+ ImGuiTableFlags_PreciseWidths = 1 << 18, // Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.
+ // Clipping
+ ImGuiTableFlags_NoClip = 1 << 19, // Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with TableSetupScrollFreeze().
// Padding
- ImGuiTableFlags_PadOuterX = 1 << 22, // Default if BordersOuterV is on. Enable outer-most padding.
- ImGuiTableFlags_NoPadOuterX = 1 << 23, // Default if BordersOuterV is off. Disable outer-most padding.
- ImGuiTableFlags_NoPadInnerX = 1 << 24, // Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off).
+ ImGuiTableFlags_PadOuterX = 1 << 20, // Default if BordersOuterV is on. Enable outer-most padding.
+ ImGuiTableFlags_NoPadOuterX = 1 << 21, // Default if BordersOuterV is off. Disable outer-most padding.
+ ImGuiTableFlags_NoPadInnerX = 1 << 22, // Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off).
// Scrolling
- ImGuiTableFlags_ScrollX = 1 << 25, // Enable horizontal scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. Changes default sizing policy. Because this create a child window, ScrollY is currently generally recommended when using ScrollX.
- ImGuiTableFlags_ScrollY = 1 << 26 // Enable vertical scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size.
+ ImGuiTableFlags_ScrollX = 1 << 23, // Enable horizontal scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size. Changes default sizing policy. Because this create a child window, ScrollY is currently generally recommended when using ScrollX.
+ ImGuiTableFlags_ScrollY = 1 << 24, // Enable vertical scrolling. Require 'outer_size' parameter of BeginTable() to specify the container size.
+ // Sorting
+ ImGuiTableFlags_SortMulti = 1 << 25, // Hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).
+ ImGuiTableFlags_SortTristate = 1 << 26, // Allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).
+
+ // [Internal] Combinations and masks
+ ImGuiTableFlags_SizingMask_ = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_SizingFixedSame | ImGuiTableFlags_SizingStretchProp | ImGuiTableFlags_SizingStretchSame
+
+ // Obsolete names (will be removed soon)
+#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+ , ImGuiTableFlags_ColumnsWidthFixed = ImGuiTableFlags_SizingFixedFit, ImGuiTableFlags_ColumnsWidthStretch = ImGuiTableFlags_SizingStretchSame // WIP Tables 2020/12
+ , ImGuiTableFlags_SizingPolicyFixed = ImGuiTableFlags_SizingFixedFit, ImGuiTableFlags_SizingPolicyStretch = ImGuiTableFlags_SizingStretchSame // WIP Tables 2021/01
+#endif
};
// Flags for ImGui::TableSetupColumn()
@@ -1142,9 +1162,9 @@ enum ImGuiTableColumnFlags_
ImGuiTableColumnFlags_None = 0,
ImGuiTableColumnFlags_DefaultHide = 1 << 0, // Default as a hidden/disabled column.
ImGuiTableColumnFlags_DefaultSort = 1 << 1, // Default as a sorting column.
- ImGuiTableColumnFlags_WidthStretch = 1 << 2, // Column will stretch. Preferable with horizontal scrolling disabled (default if table sizing policy is _ColumnsWidthStretch).
- ImGuiTableColumnFlags_WidthFixed = 1 << 3, // Column will not stretch. Preferable with horizontal scrolling enabled (default if table sizing policy is _ColumnsWidthFixed and table is resizable).
- ImGuiTableColumnFlags_WidthAutoResize = 1 << 4, // Column will not stretch and keep resizing based on submitted contents (default if table sizing policy is _ColumnsWidthFixed and table is not resizable).
+ ImGuiTableColumnFlags_WidthStretch = 1 << 2, // Column will stretch. Preferable with horizontal scrolling disabled (default if table sizing policy is _SizingStretchSame or _SizingStretchProp).
+ ImGuiTableColumnFlags_WidthFixed = 1 << 3, // Column will not stretch. Preferable with horizontal scrolling enabled (default if table sizing policy is _SizingFixedFit and table is resizable).
+ ImGuiTableColumnFlags_WidthAuto = 1 << 4, // Column will not stretch and keep resizing based on submitted contents (default if table sizing policy is _SizingFixedFit and table is not resizable, or policy is _SizingFixedSame). Generally compatible with using right-most fitting widgets (e.g. SetNextItemWidth(-FLT_MIN))
ImGuiTableColumnFlags_NoResize = 1 << 5, // Disable manual resizing.
ImGuiTableColumnFlags_NoReorder = 1 << 6, // Disable manual reordering this column, this will also prevent other columns from crossing over this column.
ImGuiTableColumnFlags_NoHide = 1 << 7, // Disable ability to hide/disable this column.
@@ -1152,7 +1172,7 @@ enum ImGuiTableColumnFlags_
ImGuiTableColumnFlags_NoSort = 1 << 9, // Disable ability to sort on this field (even if ImGuiTableFlags_Sortable is set on the table).
ImGuiTableColumnFlags_NoSortAscending = 1 << 10, // Disable ability to sort in the ascending direction.
ImGuiTableColumnFlags_NoSortDescending = 1 << 11, // Disable ability to sort in the descending direction.
- ImGuiTableColumnFlags_NoHeaderWidth = 1 << 12, // Header width don't contribute to automatic column width.
+ ImGuiTableColumnFlags_NoHeaderWidth = 1 << 12, // Disable header text width contribution to automatic column width.
ImGuiTableColumnFlags_PreferSortAscending = 1 << 13, // Make the initial sort direction Ascending when first sorting on this column (default).
ImGuiTableColumnFlags_PreferSortDescending = 1 << 14, // Make the initial sort direction Descending when first sorting on this column.
ImGuiTableColumnFlags_IndentEnable = 1 << 15, // Use current Indent value when entering cell (default for column 0).
@@ -1165,7 +1185,7 @@ enum ImGuiTableColumnFlags_
ImGuiTableColumnFlags_IsHovered = 1 << 23, // Status: is hovered by mouse
// [Internal] Combinations and masks
- ImGuiTableColumnFlags_WidthMask_ = ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAutoResize,
+ ImGuiTableColumnFlags_WidthMask_ = ImGuiTableColumnFlags_WidthStretch | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAuto,
ImGuiTableColumnFlags_IndentMask_ = ImGuiTableColumnFlags_IndentEnable | ImGuiTableColumnFlags_IndentDisable,
ImGuiTableColumnFlags_StatusMask_ = ImGuiTableColumnFlags_IsEnabled | ImGuiTableColumnFlags_IsVisible | ImGuiTableColumnFlags_IsSorted | ImGuiTableColumnFlags_IsHovered,
ImGuiTableColumnFlags_NoDirectResize_ = 1 << 30 // [Internal] Disable user resizing this column directly (it may however we resized indirectly from its left edge)
@@ -1190,11 +1210,9 @@ enum ImGuiTableRowFlags_
enum ImGuiTableBgTarget_
{
ImGuiTableBgTarget_None = 0,
- //ImGuiTableBgTarget_ColumnBg0 = 1, // FIXME-TABLE: Todo. Set column background color 0 (generally used for background
- //ImGuiTableBgTarget_ColumnBg1 = 2, // FIXME-TABLE: Todo. Set column background color 1 (generally used for selection marking)
- ImGuiTableBgTarget_RowBg0 = 3, // Set row background color 0 (generally used for background, automatically set when ImGuiTableFlags_RowBg is used)
- ImGuiTableBgTarget_RowBg1 = 4, // Set row background color 1 (generally used for selection marking)
- ImGuiTableBgTarget_CellBg = 5 // Set cell background color (top-most color)
+ ImGuiTableBgTarget_RowBg0 = 1, // Set row background color 0 (generally used for background, automatically set when ImGuiTableFlags_RowBg is used)
+ ImGuiTableBgTarget_RowBg1 = 2, // Set row background color 1 (generally used for selection marking)
+ ImGuiTableBgTarget_CellBg = 3 // Set cell background color (top-most color)
};
// Flags for ImGui::IsWindowFocused()
@@ -1338,7 +1356,7 @@ enum ImGuiKeyModFlags_
// Gamepad/Keyboard navigation
// Keyboard: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableKeyboard to enable. NewFrame() will automatically fill io.NavInputs[] based on your io.KeysDown[] + io.KeyMap[] arrays.
// Gamepad: Set io.ConfigFlags |= ImGuiConfigFlags_NavEnableGamepad to enable. Backend: set ImGuiBackendFlags_HasGamepad and fill the io.NavInputs[] fields before calling NewFrame(). Note that io.NavInputs[] is cleared by EndFrame().
-// Read instructions in imgui.cpp for more details. Download PNG/PSD at http://goo.gl/9LgVZW.
+// Read instructions in imgui.cpp for more details. Download PNG/PSD at http://dearimgui.org/controls_sheets.
enum ImGuiNavInput_
{
// Gamepad Mapping
@@ -1469,11 +1487,6 @@ enum ImGuiCol_
ImGuiCol_NavWindowingDimBg, // Darken/colorize entire screen behind the CTRL+TAB window list, when active
ImGuiCol_ModalWindowDimBg, // Darken/colorize entire screen behind a modal window, when one is active
ImGuiCol_COUNT
-
- // Obsolete names (will be removed)
-#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
- , ImGuiCol_ModalWindowDarkening = ImGuiCol_ModalWindowDimBg // [renamed in 1.63]
-#endif
};
// Enumeration for PushStyleVar() / PopStyleVar() to temporarily modify the ImGuiStyle structure.
@@ -1629,7 +1642,10 @@ enum ImGuiCond_
};
//-----------------------------------------------------------------------------
-// Helpers: Memory allocations macros
+// [SECTION] Helpers: Memory allocations macros, ImVector<>
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
// IM_MALLOC(), IM_FREE(), IM_NEW(), IM_PLACEMENT_NEW(), IM_DELETE()
// We call C++ constructor on own allocated memory via the placement "new(ptr) Type()" syntax.
// Defining a custom placement new() with a custom parameter allows us to bypass including <new> which on some platforms complains when user has disabled exceptions.
@@ -1645,7 +1661,7 @@ inline void operator delete(void*, ImNewWrapper, void*) {} // This is only re
template<typename T> void IM_DELETE(T* p) { if (p) { p->~T(); ImGui::MemFree(p); } }
//-----------------------------------------------------------------------------
-// Helper: ImVector<>
+// ImVector<>
// Lightweight std::vector<>-like class to avoid dragging dependencies (also, some implementations of STL with debug enabled are absurdly slow, we bypass it so our code runs fast in debug).
//-----------------------------------------------------------------------------
// - You generally do NOT need to care or use this ever. But we need to make it available in imgui.h because some of our public structures are relying on it.
@@ -1715,7 +1731,8 @@ struct ImVector
};
//-----------------------------------------------------------------------------
-// ImGuiStyle
+// [SECTION] ImGuiStyle
+//-----------------------------------------------------------------------------
// You may modify the ImGui::GetStyle() main instance during initialization and before NewFrame().
// During the frame, use ImGui::PushStyleVar(ImGuiStyleVar_XXXX)/PopStyleVar() to alter the main style values,
// and ImGui::PushStyleColor(ImGuiCol_XXX)/PopStyleColor() for colors.
@@ -1769,7 +1786,8 @@ struct ImGuiStyle
};
//-----------------------------------------------------------------------------
-// ImGuiIO
+// [SECTION] ImGuiIO
+//-----------------------------------------------------------------------------
// Communicate most settings and inputs/outputs to Dear ImGui using this structure.
// Access via ImGui::GetIO(). Read 'Programmer guide' section in .cpp file for general usage.
//-----------------------------------------------------------------------------
@@ -1815,8 +1833,8 @@ struct ImGuiIO
// Miscellaneous options
bool MouseDrawCursor; // = false // Request ImGui to draw a mouse cursor for you (if you are on a platform without a mouse cursor). Cannot be easily renamed to 'io.ConfigXXX' because this is frequently used by backend implementations.
- bool ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl (was called io.OptMacOSXBehaviors prior to 1.63)
- 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 ConfigMacOSXBehaviors; // = defined(__APPLE__) // OS X style: Text editing cursor movement using Alt instead of Ctrl, Shortcuts using Cmd/Super instead of Ctrl, Line/Text Start and End using Cmd+Arrows instead of Home/End, Double click selects by word instead of selecting whole text, Multi-selection in lists uses Cmd/Super instead of Ctrl.
+ bool ConfigInputTextCursorBlink; // = true // Set to false to disable blinking cursor, for users who consider it distracting.
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 ConfigMemoryCompactTimer; // = 60.0f // [BETA] Free transient windows/tables memory buffers when unused for given amount of time. Set to -1.0f to disable.
@@ -1911,7 +1929,7 @@ struct ImGuiIO
};
//-----------------------------------------------------------------------------
-// Misc data structures
+// [SECTION] Misc data structures
//-----------------------------------------------------------------------------
// Shared state of InputText(), passed as an argument to your callback when a ImGuiInputTextFlags_Callback* flag is used.
@@ -2023,14 +2041,15 @@ struct ImGuiTableColumnSortSpecs
struct ImGuiTableSortSpecs
{
const ImGuiTableColumnSortSpecs* Specs; // Pointer to sort spec array.
- int SpecsCount; // Sort spec count. Most often 1 unless e.g. ImGuiTableFlags_MultiSortable is enabled.
+ int SpecsCount; // Sort spec count. Most often 1. May be > 1 when ImGuiTableFlags_SortMulti is enabled. May be == 0 when ImGuiTableFlags_SortTristate is enabled.
bool SpecsDirty; // Set to true when specs have changed since last time! Use this to sort again, then clear the flag.
ImGuiTableSortSpecs() { memset(this, 0, sizeof(*this)); }
};
//-----------------------------------------------------------------------------
-// Obsolete functions (Will be removed! Read 'API BREAKING CHANGES' section in imgui.cpp for details)
+// [SECTION] Obsolete functions
+// (Will be removed! Read 'API BREAKING CHANGES' section in imgui.cpp for details)
// Please keep your copy of dear imgui up to date! Occasionally set '#define IMGUI_DISABLE_OBSOLETE_FUNCTIONS' in imconfig.h to stay ahead.
//-----------------------------------------------------------------------------
@@ -2066,15 +2085,11 @@ namespace ImGui
static inline ImDrawList* GetOverlayDrawList() { return GetForegroundDrawList(); }
// OBSOLETED in 1.66 (from Sep 2018)
static inline void SetScrollHere(float center_ratio=0.5f){ SetScrollHereY(center_ratio); }
- // OBSOLETED in 1.63 (between Aug 2018 and Sept 2018)
- static inline bool IsItemDeactivatedAfterChange() { return IsItemDeactivatedAfterEdit(); }
}
-typedef ImGuiInputTextCallback ImGuiTextEditCallback; // OBSOLETED in 1.63 (from Aug 2018): made the names consistent
-typedef ImGuiInputTextCallbackData ImGuiTextEditCallbackData;
#endif
//-----------------------------------------------------------------------------
-// Helpers
+// [SECTION] Helpers (ImGuiOnceUponAFrame, ImGuiTextFilter, ImGuiTextBuffer, ImGuiStorage, ImGuiListClipper, ImColor)
//-----------------------------------------------------------------------------
// Helper: Unicode defines
@@ -2276,7 +2291,7 @@ struct ImColor
};
//-----------------------------------------------------------------------------
-// Draw List API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData)
+// [SECTION] Drawing API (ImDrawCmd, ImDrawIdx, ImDrawVert, ImDrawChannel, ImDrawListSplitter, ImDrawListFlags, ImDrawList, ImDrawData)
// Hold a series of drawing commands. The user provides a renderer for ImDrawData which essentially contains an array of ImDrawList.
//-----------------------------------------------------------------------------
@@ -2428,6 +2443,7 @@ struct ImDrawList
ImVector<ImVec2> _Path; // [Internal] current path building
ImDrawCmdHeader _CmdHeader; // [Internal] template of active commands. Fields should match those of CmdBuffer.back().
ImDrawListSplitter _Splitter; // [Internal] for channels api (note: prefer using your own persistent instance of ImDrawListSplitter!)
+ float _FringeScale; // [Internal] anti-alias fringe is scaled by this value, this helps to keep things sharp while zooming at vertex buffer content
// If you want to create ImDrawList instances, pass them ImGui::GetDrawListSharedData() or create and use your own ImDrawListSharedData (so you can use ImDrawList without ImGui)
ImDrawList(const ImDrawListSharedData* shared_data) { memset(this, 0, sizeof(*this)); _Data = shared_data; }
@@ -2463,7 +2479,8 @@ struct ImDrawList
IMGUI_API void AddText(const ImFont* font, float font_size, const ImVec2& pos, ImU32 col, const char* text_begin, const char* text_end = NULL, float wrap_width = 0.0f, const ImVec4* cpu_fine_clip_rect = NULL);
IMGUI_API void 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& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0);
+ IMGUI_API void AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0); // Cubic Bezier (4 control points)
+ IMGUI_API void AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments = 0); // Quadratic Bezier (3 control points)
// Image primitives
// - Read FAQ to understand what ImTextureID is.
@@ -2480,8 +2497,9 @@ struct ImDrawList
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& 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& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0);
+ 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 PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0); // Cubic Bezier (4 control points)
+ IMGUI_API void PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments = 0); // Quadratic Bezier (3 control points)
IMGUI_API void PathRect(const ImVec2& rect_min, const ImVec2& rect_max, float rounding = 0.0f, ImDrawCornerFlags rounding_corners = ImDrawCornerFlags_All);
// Advanced
@@ -2511,6 +2529,11 @@ struct ImDrawList
inline void PrimWriteIdx(ImDrawIdx idx) { *_IdxWritePtr = idx; _IdxWritePtr++; }
inline void PrimVtx(const ImVec2& pos, const ImVec2& uv, ImU32 col) { PrimWriteIdx((ImDrawIdx)_VtxCurrentIdx); PrimWriteVtx(pos, uv, col); } // Write vertex with unique index
+#ifndef IMGUI_DISABLE_OBSOLETE_FUNCTIONS
+ inline void AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments = 0) { AddBezierCubic(p1, p2, p3, p4, col, thickness, num_segments); }
+ inline void PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments = 0) { PathBezierCubicCurveTo(p2, p3, p4, num_segments); }
+#endif
+
// [Internal helpers]
IMGUI_API void _ResetForNewFrame();
IMGUI_API void _ClearFreeMemory();
@@ -2544,7 +2567,7 @@ struct ImDrawData
};
//-----------------------------------------------------------------------------
-// Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFontGlyphRangesBuilder, ImFont)
+// [SECTION] Font API (ImFontConfig, ImFontGlyph, ImFontAtlasFlags, ImFontAtlas, ImFontGlyphRangesBuilder, ImFont)
//-----------------------------------------------------------------------------
struct ImFontConfig
@@ -2787,9 +2810,9 @@ struct ImFont
};
//-----------------------------------------------------------------------------
-// [BETA] Platform interface for multi-viewport support
+// [SECTION] Platform interface for multi-viewport support
//-----------------------------------------------------------------------------
-// (Optional) This is completely optional, for advanced users!
+// [BETA] (Optional) This is completely optional, for advanced users!
// If you are new to Dear ImGui and trying to integrate it into your engine, you can probably ignore this for now.
//
// This feature allows you to seamlessly drag Dear ImGui windows outside of your application viewport.
diff --git a/imgui/imgui_demo.cpp b/imgui/imgui_demo.cpp
index 4df021cc..e9691bc6 100644
--- a/imgui/imgui_demo.cpp
+++ b/imgui/imgui_demo.cpp
@@ -2032,18 +2032,18 @@ static void ShowDemoWindowWidgets()
ImGui::TreePop();
}
- if (ImGui::TreeNode("Querying Status (Active/Focused/Hovered etc.)"))
+ if (ImGui::TreeNode("Querying Status (Edited/Active/Focused/Hovered etc.)"))
{
// Select an item type
const char* item_names[] =
{
"Text", "Button", "Button (w/ repeat)", "Checkbox", "SliderFloat", "InputText", "InputFloat",
- "InputFloat3", "ColorEdit4", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "ListBox"
+ "InputFloat3", "ColorEdit4", "MenuItem", "TreeNode", "TreeNode (w/ double-click)", "Combo", "ListBox"
};
static int item_type = 1;
ImGui::Combo("Item Type", &item_type, item_names, IM_ARRAYSIZE(item_names), IM_ARRAYSIZE(item_names));
ImGui::SameLine();
- HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions.");
+ HelpMarker("Testing how various types of items are interacting with the IsItemXXX functions. Note that the bool return value of most ImGui function is generally equivalent to calling ImGui::IsItemHovered().");
// Submit selected item item so we can query their status in the code following it.
bool ret = false;
@@ -2062,7 +2062,8 @@ 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::TreeNode("ITEM: TreeNode"); if (ret) ImGui::TreePop(); } // Testing tree node
if (item_type == 11){ ret = ImGui::TreeNodeEx("ITEM: TreeNode w/ ImGuiTreeNodeFlags_OpenOnDoubleClick", ImGuiTreeNodeFlags_OpenOnDoubleClick | ImGuiTreeNodeFlags_NoTreePushOnOpen); } // Testing tree node with ImGuiButtonFlags_PressedOnDoubleClick button policy.
- if (item_type == 12){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::ListBox("ITEM: ListBox", &current, items, IM_ARRAYSIZE(items), IM_ARRAYSIZE(items)); }
+ if (item_type == 12){ const char* items[] = { "Apple", "Banana", "Cherry", "Kiwi" }; static int current = 1; ret = ImGui::Combo("ITEM: Combo", &current, items, IM_ARRAYSIZE(items)); }
+ if (item_type == 13){ 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 values of IsItemHovered() and other common item state functions.
// Note that the ImGuiHoveredFlags_XXX flags can be combined.
@@ -3402,8 +3403,8 @@ const ImGuiTableSortSpecs* MyItem::s_current_sort_specs = NULL;
static void PushStyleCompact()
{
ImGuiStyle& style = ImGui::GetStyle();
- ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(style.FramePadding.x, (float)(int)(style.FramePadding.y * 0.70f)));
- ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x, (float)(int)(style.ItemSpacing.y * 0.70f)));
+ ImGui::PushStyleVar(ImGuiStyleVar_FramePadding, ImVec2(style.FramePadding.x, (float)(int)(style.FramePadding.y * 0.60f)));
+ ImGui::PushStyleVar(ImGuiStyleVar_ItemSpacing, ImVec2(style.ItemSpacing.x, (float)(int)(style.ItemSpacing.y * 0.60f)));
}
static void PopStyleCompact()
@@ -3411,6 +3412,49 @@ static void PopStyleCompact()
ImGui::PopStyleVar(2);
}
+// Show a combo box with a choice of sizing policies
+static void EditTableSizingFlags(ImGuiTableFlags* p_flags)
+{
+ struct EnumDesc { ImGuiTableFlags Value; const char* Name; const char* Tooltip; };
+ static const EnumDesc policies[] =
+ {
+ { ImGuiTableFlags_None, "Default", "Use default sizing policy:\n- ImGuiTableFlags_SizingFixedFit if ScrollX is on or if host window has ImGuiWindowFlags_AlwaysAutoResize.\n- ImGuiTableFlags_SizingStretchSame otherwise." },
+ { ImGuiTableFlags_SizingFixedFit, "ImGuiTableFlags_SizingFixedFit", "Columns default to _WidthFixed (if resizable) or _WidthAuto (if not resizable), matching contents width." },
+ { ImGuiTableFlags_SizingFixedSame, "ImGuiTableFlags_SizingFixedSame", "Columns are all the same width, matching the maximum contents width.\nImplicitly disable ImGuiTableFlags_Resizable and enable ImGuiTableFlags_NoKeepColumnsVisible." },
+ { ImGuiTableFlags_SizingStretchProp, "ImGuiTableFlags_SizingStretchProp", "Columns default to _WidthStretch with weights proportional to their widths." },
+ { ImGuiTableFlags_SizingStretchSame, "ImGuiTableFlags_SizingStretchSame", "Columns default to _WidthStretch with same weights." }
+ };
+ int idx;
+ for (idx = 0; idx < IM_ARRAYSIZE(policies); idx++)
+ if (policies[idx].Value == (*p_flags & ImGuiTableFlags_SizingMask_))
+ break;
+ const char* preview_text = (idx < IM_ARRAYSIZE(policies)) ? policies[idx].Name + (idx > 0 ? strlen("ImGuiTableFlags") : 0) : "";
+ if (ImGui::BeginCombo("Sizing Policy", preview_text))
+ {
+ for (int n = 0; n < IM_ARRAYSIZE(policies); n++)
+ if (ImGui::Selectable(policies[n].Name, idx == n))
+ *p_flags = (*p_flags & ~ImGuiTableFlags_SizingMask_) | policies[n].Value;
+ ImGui::EndCombo();
+ }
+ ImGui::SameLine();
+ ImGui::TextDisabled("(?)");
+ if (ImGui::IsItemHovered())
+ {
+ ImGui::BeginTooltip();
+ ImGui::PushTextWrapPos(ImGui::GetFontSize() * 50.0f);
+ for (int m = 0; m < IM_ARRAYSIZE(policies); m++)
+ {
+ ImGui::Separator();
+ ImGui::Text("%s:", policies[m].Name);
+ ImGui::Separator();
+ ImGui::SetCursorPosX(ImGui::GetCursorPosX() + ImGui::GetStyle().IndentSpacing * 0.5f);
+ ImGui::TextUnformatted(policies[m].Tooltip);
+ }
+ ImGui::PopTextWrapPos();
+ ImGui::EndTooltip();
+ }
+}
+
static void EditTableColumnsFlags(ImGuiTableColumnFlags* p_flags)
{
ImGui::CheckboxFlags("_DefaultHide", p_flags, ImGuiTableColumnFlags_DefaultHide);
@@ -3419,8 +3463,8 @@ static void EditTableColumnsFlags(ImGuiTableColumnFlags* p_flags)
*p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthStretch);
if (ImGui::CheckboxFlags("_WidthFixed", p_flags, ImGuiTableColumnFlags_WidthFixed))
*p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthFixed);
- if (ImGui::CheckboxFlags("_WidthAutoResize", p_flags, ImGuiTableColumnFlags_WidthAutoResize))
- *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthAutoResize);
+ if (ImGui::CheckboxFlags("_WidthAuto", p_flags, ImGuiTableColumnFlags_WidthAuto))
+ *p_flags &= ~(ImGuiTableColumnFlags_WidthMask_ ^ ImGuiTableColumnFlags_WidthAuto);
ImGui::CheckboxFlags("_NoResize", p_flags, ImGuiTableColumnFlags_NoResize);
ImGui::CheckboxFlags("_NoReorder", p_flags, ImGuiTableColumnFlags_NoReorder);
ImGui::CheckboxFlags("_NoHide", p_flags, ImGuiTableColumnFlags_NoHide);
@@ -3575,12 +3619,12 @@ static void ShowDemoWindowTables()
ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags, ImGuiTableFlags_BordersOuter);
ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags, ImGuiTableFlags_BordersInner);
ImGui::Unindent();
- ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appears in Headers");
ImGui::AlignTextToFramePadding(); ImGui::Text("Cell contents:");
ImGui::SameLine(); ImGui::RadioButton("Text", &contents_type, CT_Text);
ImGui::SameLine(); ImGui::RadioButton("FillButton", &contents_type, CT_FillButton);
ImGui::Checkbox("Display headers", &display_headers);
+ ImGui::CheckboxFlags("ImGuiTableFlags_NoBordersInBody", &flags, ImGuiTableFlags_NoBordersInBody); ImGui::SameLine(); HelpMarker("Disable vertical borders in columns Body (borders will always appears in Headers");
PopStyleCompact();
if (ImGui::BeginTable("##table1", 3, flags))
@@ -3620,11 +3664,11 @@ static void ShowDemoWindowTables()
{
// By default, if we don't enable ScrollX the sizing policy for each columns is "Stretch"
// Each columns maintain a sizing weight, and they will occupy all available width.
- static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
+ static ImGuiTableFlags flags = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
PushStyleCompact();
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
- ImGui::SameLine(); HelpMarker("Using the _Resizable flag automatically enables the _BordersV flag as well.");
+ ImGui::SameLine(); HelpMarker("Using the _Resizable flag automatically enables the _BordersInnerV flag as well, this is why the resize borders are still showing when unchecking this.");
PopStyleCompact();
if (ImGui::BeginTable("##table1", 3, flags))
@@ -3647,17 +3691,22 @@ static void ShowDemoWindowTables()
ImGui::SetNextItemOpen(open_action != 0);
if (ImGui::TreeNode("Resizable, fixed"))
{
- // Here we use ImGuiTableFlags_ColumnsWidthFixed (even though _ScrollX is not set)
+ // Here we use ImGuiTableFlags_SizingFixedFit (even though _ScrollX is not set)
// So columns will adopt the "Fixed" policy and will maintain a fixed width regardless of the whole available width (unless table is small)
// If there is not enough available width to fit all columns, they will however be resized down.
// FIXME-TABLE: Providing a stretch-on-init would make sense especially for tables which don't have saved settings
HelpMarker(
- "Using _Resizable + _ColumnsWidthFixedX flags.\n"
+ "Using _Resizable + _SizingFixedFit flags.\n"
"Fixed-width columns generally makes more sense if you want to use horizontal scrolling.\n\n"
"Double-click a column border to auto-fit the column to its contents.");
- static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_ColumnsWidthFixed | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
- //ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX); // FIXME-TABLE: Explain or fix the effect of enable Scroll on outer_size
- if (ImGui::BeginTable("##table1", 3, flags))
+ PushStyleCompact();
+ static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Resizable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_ContextMenuInBody;
+ static bool fixed_fill = true;
+ ImGui::Checkbox("fill", &fixed_fill);
+ PopStyleCompact();
+
+ ImVec2 outer_size(fixed_fill ? -FLT_MIN : 0.0f, 0.0f);
+ if (ImGui::BeginTable("##table1", 3, flags, outer_size))
{
for (int row = 0; row < 5; row++)
{
@@ -3677,8 +3726,10 @@ static void ShowDemoWindowTables()
ImGui::SetNextItemOpen(open_action != 0);
if (ImGui::TreeNode("Resizable, mixed"))
{
- HelpMarker("Using columns flag to alter resizing policy on a per-column basis.");
- static ImGuiTableFlags flags = ImGuiTableFlags_ColumnsWidthFixed | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
+ HelpMarker(
+ "Using TableSetupColumn() to alter resizing policy on a per-column basis.\n\n"
+ "When combining Fixed and Stretch columns, generally you only want one, maybe two trailing columns to use _WidthStretch.");
+ static ImGuiTableFlags flags = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable;
if (ImGui::BeginTable("##table1", 3, flags))
{
@@ -3724,8 +3775,10 @@ static void ShowDemoWindowTables()
ImGui::SetNextItemOpen(open_action != 0);
if (ImGui::TreeNode("Reorderable, hideable, with headers"))
{
- HelpMarker("Click and drag column headers to reorder columns.\n\nYou can also right-click on a header to open a context menu.");
- static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody;
+ HelpMarker(
+ "Click and drag column headers to reorder columns.\n\n"
+ "Right-click on a header to open a context menu.");
+ static ImGuiTableFlags flags = ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV;
PushStyleCompact();
ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable);
@@ -3754,7 +3807,8 @@ static void ShowDemoWindowTables()
ImGui::EndTable();
}
- if (ImGui::BeginTable("##table2", 3, flags | ImGuiTableFlags_ColumnsWidthFixed))
+ // Use outer_size.x == 0.0f instead of default to make the table as tight as possible (only valid when no scrolling and no stretch column)
+ if (ImGui::BeginTable("##table2", 3, flags | ImGuiTableFlags_SizingFixedFit, ImVec2(0.0f, 0.0f)))
{
ImGui::TableSetupColumn("One");
ImGui::TableSetupColumn("Two");
@@ -3778,29 +3832,32 @@ static void ShowDemoWindowTables()
ImGui::SetNextItemOpen(open_action != 0);
if (ImGui::TreeNode("Padding"))
{
- static ImGuiTableFlags flags = ImGuiTableFlags_BordersV;
-
+ // First example: showcase use of padding flags and effect of BorderOuterV/BorderInnerV on X padding.
+ // We don't expose BorderOuterH/BorderInnerH here because they have no effect on X padding.
HelpMarker(
"We often want outer padding activated when any using features which makes the edges of a column visible:\n"
"e.g.:\n"
"- BorderOuterV\n"
"- any form of row selection\n"
- "Because of this, activating BorderOuterV sets the default to PadOuterX. Using PadOuterX or NoPadOuterX you can override the default.\n");
+ "Because of this, activating BorderOuterV sets the default to PadOuterX. Using PadOuterX or NoPadOuterX you can override the default.\n\n"
+ "Actual padding values are using style.CellPadding.\n\n"
+ "In this demo we don't show horizontal borders to emphasis how they don't affect default horizontal padding.");
+ static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV;
PushStyleCompact();
- ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags, ImGuiTableFlags_PadOuterX);
+ ImGui::CheckboxFlags("ImGuiTableFlags_PadOuterX", &flags1, ImGuiTableFlags_PadOuterX);
ImGui::SameLine(); HelpMarker("Enable outer-most padding (default if ImGuiTableFlags_BordersOuterV is set)");
- ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags, ImGuiTableFlags_NoPadOuterX);
+ ImGui::CheckboxFlags("ImGuiTableFlags_NoPadOuterX", &flags1, ImGuiTableFlags_NoPadOuterX);
ImGui::SameLine(); HelpMarker("Disable outer-most padding (default if ImGuiTableFlags_BordersOuterV is not set)");
- ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags, ImGuiTableFlags_NoPadInnerX);
+ ImGui::CheckboxFlags("ImGuiTableFlags_NoPadInnerX", &flags1, ImGuiTableFlags_NoPadInnerX);
ImGui::SameLine(); HelpMarker("Disable inner padding between columns (double inner padding if BordersOuterV is on, single inner padding if BordersOuterV is off)");
- ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV);
- ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV);
+ ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags1, ImGuiTableFlags_BordersOuterV);
+ ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags1, ImGuiTableFlags_BordersInnerV);
static bool show_headers = false;
ImGui::Checkbox("show_headers", &show_headers);
PopStyleCompact();
- if (ImGui::BeginTable("##table1", 3, flags))
+ if (ImGui::BeginTable("##table1", 3, flags1))
{
if (show_headers)
{
@@ -3833,37 +3890,156 @@ static void ShowDemoWindowTables()
ImGui::EndTable();
}
+ // Second example: set style.CellPadding to (0.0) or a custom value.
+ // FIXME-TABLE: Vertical border effectively not displayed the same way as horizontal one...
+ HelpMarker("Setting style.CellPadding to (0,0) or a custom value.");
+ static ImGuiTableFlags flags2 = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg;
+ static ImVec2 cell_padding(0.0f, 0.0f);
+ static bool show_widget_frame_bg = true;
+
+ PushStyleCompact();
+ ImGui::CheckboxFlags("ImGuiTableFlags_Borders", &flags2, ImGuiTableFlags_Borders);
+ ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags2, ImGuiTableFlags_BordersH);
+ ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags2, ImGuiTableFlags_BordersV);
+ ImGui::CheckboxFlags("ImGuiTableFlags_BordersInner", &flags2, ImGuiTableFlags_BordersInner);
+ ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags2, ImGuiTableFlags_BordersOuter);
+ ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags2, ImGuiTableFlags_RowBg);
+ ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags2, ImGuiTableFlags_Resizable);
+ ImGui::Checkbox("show_widget_frame_bg", &show_widget_frame_bg);
+ ImGui::SliderFloat2("CellPadding", &cell_padding.x, 0.0f, 10.0f, "%.0f");
+ PopStyleCompact();
+
+ ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, cell_padding);
+ if (ImGui::BeginTable("##table2", 3, flags2))
+ {
+ static char text_bufs[3 * 5][16]; // Mini text storage for 3x5 cells
+ static bool init = true;
+ if (!show_widget_frame_bg)
+ ImGui::PushStyleColor(ImGuiCol_FrameBg, 0);
+ for (int cell = 0; cell < 3 * 5; cell++)
+ {
+ ImGui::TableNextColumn();
+ if (init)
+ strcpy(text_bufs[cell], "edit me");
+ ImGui::SetNextItemWidth(-FLT_MIN);
+ ImGui::PushID(cell);
+ ImGui::InputText("##cell", text_bufs[cell], IM_ARRAYSIZE(text_bufs[cell]));
+ ImGui::PopID();
+ }
+ if (!show_widget_frame_bg)
+ ImGui::PopStyleColor();
+ init = false;
+ ImGui::EndTable();
+ }
+ ImGui::PopStyleVar();
+
ImGui::TreePop();
}
if (open_action != -1)
ImGui::SetNextItemOpen(open_action != 0);
- if (ImGui::TreeNode("Explicit widths"))
+ if (ImGui::TreeNode("Sizing policies"))
{
- static ImGuiTableFlags flags = ImGuiTableFlags_None;
+ static bool fixed_fill = true;
+ static ImGuiTableFlags flags1 = ImGuiTableFlags_BordersV | ImGuiTableFlags_BordersOuterH | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody;
PushStyleCompact();
- ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags, ImGuiTableFlags_NoKeepColumnsVisible);
- ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV);
- ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV);
+ ImGui::Checkbox("fill", &fixed_fill);
+ ImGui::SameLine(); HelpMarker(
+ "Value passed to outer_size only affects tables with _SizingFixedFit or _SizingFixedSame sizing policies.\n\n"
+ " - outer_size.x == 0: table fit to columns total contents.\n"
+ " - outer_size.x == -FLT_MIN: table fill until right-most edge.");
+ ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags1, ImGuiTableFlags_Resizable);
PopStyleCompact();
- if (ImGui::BeginTable("##table1", 4, flags))
+ ImVec2 outer_size = ImVec2(fixed_fill ? -FLT_MIN : 0.0f, 0.0f);
+ static ImGuiTableFlags sizing_policy_flags[4] = { ImGuiTableFlags_SizingFixedFit, ImGuiTableFlags_SizingFixedSame, ImGuiTableFlags_SizingStretchProp, ImGuiTableFlags_SizingStretchSame };
+ for (int table_n = 0; table_n < 4; table_n++)
{
- // We could also set ImGuiTableFlags_ColumnsWidthFixed on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed.
- ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 100.0f);
- ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f);
- ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 30.0f);
- ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f);
- for (int row = 0; row < 5; row++)
+ ImGui::PushID(table_n);
+ ImGui::SetNextItemWidth(TEXT_BASE_WIDTH * 30);
+ EditTableSizingFlags(&sizing_policy_flags[table_n]);
+
+ // To make it easier to understand the different sizing policy,
+ // For each policy: we display one table where the columns have equal contents width, and one where the columns have different contents width.
+ if (ImGui::BeginTable("##table1", 3, sizing_policy_flags[table_n] | flags1, outer_size))
{
- ImGui::TableNextRow();
- for (int column = 0; column < 4; column++)
+ for (int row = 0; row < 3; row++)
{
- ImGui::TableSetColumnIndex(column);
- if (row == 0)
- ImGui::Text("(%.2f)", ImGui::GetContentRegionAvail().x);
- ImGui::Text("Hello %d,%d", column, row);
+ ImGui::TableNextRow();
+ ImGui::TableNextColumn(); ImGui::Text("Oh dear");
+ ImGui::TableNextColumn(); ImGui::Text("Oh dear");
+ ImGui::TableNextColumn(); ImGui::Text("Oh dear");
+ }
+ ImGui::EndTable();
+ }
+ if (ImGui::BeginTable("##table2", 3, sizing_policy_flags[table_n] | flags1, outer_size))
+ {
+ for (int row = 0; row < 3; row++)
+ {
+ ImGui::TableNextRow();
+ ImGui::TableNextColumn(); ImGui::Text("AAAA");
+ ImGui::TableNextColumn(); ImGui::Text("BBBBBBBB");
+ ImGui::TableNextColumn(); ImGui::Text("CCCCCCCCCCCC");
+ }
+ ImGui::EndTable();
+ }
+ ImGui::PopID();
+ }
+
+ ImGui::Spacing();
+ ImGui::TextUnformatted("Advanced");
+ ImGui::SameLine();
+ HelpMarker("This section allows you to interact and see the effect of various sizing policies depending on whether Scroll is enabled and the contents of your columns.");
+
+ enum ContentsType { CT_ShowWidth, CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText };
+ static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg | ImGuiTableFlags_Resizable;
+ static int contents_type = CT_ShowWidth;
+ static int column_count = 3;
+
+ PushStyleCompact();
+ ImGui::PushID("Advanced");
+ ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30);
+ EditTableSizingFlags(&flags);
+ ImGui::Combo("Contents", &contents_type, "Show width\0Short Text\0Long Text\0Button\0Fill Button\0InputText\0");
+ if (contents_type == CT_FillButton)
+ {
+ ImGui::SameLine();
+ HelpMarker("Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop where contents width can feed into auto-column width can feed into contents width.");
+ }
+ ImGui::DragInt("Columns", &column_count, 0.1f, 1, 64, "%d", ImGuiSliderFlags_AlwaysClamp);
+ ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
+ ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths);
+ ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.");
+ ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
+ ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
+ ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip);
+ ImGui::PopItemWidth();
+ ImGui::PopID();
+ PopStyleCompact();
+
+ outer_size = ImVec2(-FLT_MIN, TEXT_BASE_HEIGHT * 7);
+ if (ImGui::BeginTable("##table2", column_count, flags, outer_size))
+ {
+ for (int cell = 0; cell < 10 * column_count; cell++)
+ {
+ ImGui::TableNextColumn();
+ int column = ImGui::TableGetColumnIndex();
+ int row = ImGui::TableGetRowIndex();
+
+ ImGui::PushID(cell);
+ char label[32];
+ static char text_buf[32] = "";
+ sprintf(label, "Hello %d,%d", column, row);
+ switch (contents_type)
+ {
+ case CT_ShortText: ImGui::TextUnformatted(label); break;
+ case CT_LongText: ImGui::Text("Some %s text %d,%d\nOver two lines..", column == 0 ? "long" : "longeeer", column, row); break;
+ case CT_ShowWidth: ImGui::Text("W: %.1f", ImGui::GetContentRegionAvail().x); break;
+ case CT_Button: ImGui::Button(label); break;
+ case CT_FillButton: ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); break;
+ case CT_InputText: ImGui::SetNextItemWidth(-FLT_MIN); ImGui::InputText("##", text_buf, IM_ARRAYSIZE(text_buf)); break;
}
+ ImGui::PopID();
}
ImGui::EndTable();
}
@@ -3883,7 +4059,7 @@ static void ShowDemoWindowTables()
// When using ScrollX or ScrollY we need to specify a size for our table container!
// Otherwise by default the table will fit all available space, like a BeginChild() call.
- ImVec2 size = ImVec2(0, TEXT_BASE_HEIGHT * 8);
+ ImVec2 size = ImVec2(-FLT_MIN, TEXT_BASE_HEIGHT * 8);
if (ImGui::BeginTable("##table1", 3, flags, size))
{
ImGui::TableSetupScrollFreeze(0, 1); // Make top row always visible
@@ -3917,7 +4093,7 @@ static void ShowDemoWindowTables()
if (ImGui::TreeNode("Horizontal scrolling"))
{
HelpMarker(
- "When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_ColumnsWidthFixed,"
+ "When ScrollX is enabled, the default sizing policy becomes ImGuiTableFlags_SizingFixedFit, "
"as automatically stretching columns doesn't make much sense with horizontal scrolling.\n\n"
"Also note that as of the current version, you will almost always want to enable ScrollY along with ScrollX,"
"because the container window won't automatically extend vertically to fix contents (this may be improved in future versions).");
@@ -3926,6 +4102,7 @@ static void ShowDemoWindowTables()
static int freeze_rows = 1;
PushStyleCompact();
+ ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
ImGui::SetNextItemWidth(ImGui::GetFrameHeight());
@@ -3936,7 +4113,7 @@ static void ShowDemoWindowTables()
// When using ScrollX or ScrollY we need to specify a size for our table container!
// Otherwise by default the table will fit all available space, like a BeginChild() call.
- ImVec2 outer_size = ImVec2(0, TEXT_BASE_HEIGHT * 8);
+ ImVec2 outer_size = ImVec2(-FLT_MIN, TEXT_BASE_HEIGHT * 8);
if (ImGui::BeginTable("##table1", 7, flags, outer_size))
{
ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows);
@@ -3969,6 +4146,33 @@ static void ShowDemoWindowTables()
}
ImGui::EndTable();
}
+
+ ImGui::Spacing();
+ ImGui::TextUnformatted("Stretch + ScrollX");
+ ImGui::SameLine();
+ HelpMarker(
+ "Showcase using Stretch columns + ScrollX together: "
+ "this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n"
+ "Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns + ScrollX together doesn't make sense.");
+ static ImGuiTableFlags flags2 = ImGuiTableFlags_SizingStretchSame | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg | ImGuiTableFlags_ContextMenuInBody;
+ static float inner_width = 1000.0f;
+ PushStyleCompact();
+ ImGui::PushID("flags3");
+ ImGui::PushItemWidth(TEXT_BASE_WIDTH * 30);
+ ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags2, ImGuiTableFlags_ScrollX);
+ ImGui::DragFloat("inner_width", &inner_width, 1.0f, 0.0f, FLT_MAX, "%.1f");
+ ImGui::PopItemWidth();
+ ImGui::PopID();
+ PopStyleCompact();
+ if (ImGui::BeginTable("##table2", 7, flags2, outer_size, inner_width))
+ {
+ for (int cell = 0; cell < 20 * 7; cell++)
+ {
+ ImGui::TableNextColumn();
+ ImGui::Text("Hello world %d,%d", ImGui::TableGetColumnIndex(), ImGui::TableGetRowIndex());
+ }
+ ImGui::EndTable();
+ }
ImGui::TreePop();
}
@@ -4007,10 +4211,10 @@ static void ShowDemoWindowTables()
// We use a scrolling table to be able to showcase the difference between the _IsEnabled and _IsVisible flags above, otherwise in
// a non-scrolling table columns are always visible (unless using ImGuiTableFlags_NoKeepColumnsVisible + resizing the parent window down)
const ImGuiTableFlags flags
- = ImGuiTableFlags_ColumnsWidthFixed | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
+ = ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
| ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV
| ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable;
- ImVec2 size = ImVec2(0, TEXT_BASE_HEIGHT * 9);
+ ImVec2 size = ImVec2(-FLT_MIN, TEXT_BASE_HEIGHT * 9);
if (ImGui::BeginTable("##table", column_count, flags, size))
{
for (int column = 0; column < column_count; column++)
@@ -4038,11 +4242,47 @@ static void ShowDemoWindowTables()
if (open_action != -1)
ImGui::SetNextItemOpen(open_action != 0);
- if (ImGui::TreeNode("Recursive"))
+ if (ImGui::TreeNode("Columns widths"))
+ {
+ HelpMarker("Using TableSetupColumn() to setup explicit width.");
+
+ static ImGuiTableFlags flags = ImGuiTableFlags_None;
+ PushStyleCompact();
+ ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags, ImGuiTableFlags_NoKeepColumnsVisible);
+ ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV);
+ ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV);
+ PopStyleCompact();
+
+ if (ImGui::BeginTable("##table1", 4, flags))
+ {
+ // We could also set ImGuiTableFlags_SizingFixedFit on the table and all columns will default to ImGuiTableColumnFlags_WidthFixed.
+ ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, 100.0f);
+ ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f);
+ ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 30.0f);
+ ImGui::TableSetupColumn("", ImGuiTableColumnFlags_WidthFixed, TEXT_BASE_WIDTH * 15.0f);
+ for (int row = 0; row < 5; row++)
+ {
+ ImGui::TableNextRow();
+ for (int column = 0; column < 4; column++)
+ {
+ ImGui::TableSetColumnIndex(column);
+ if (row == 0)
+ ImGui::Text("(%.2f)", ImGui::GetContentRegionAvail().x);
+ ImGui::Text("Hello %d,%d", column, row);
+ }
+ }
+ ImGui::EndTable();
+ }
+ ImGui::TreePop();
+ }
+
+ if (open_action != -1)
+ ImGui::SetNextItemOpen(open_action != 0);
+ if (ImGui::TreeNode("Nested tables"))
{
HelpMarker("This demonstrate embedding a table into another table cell.");
- if (ImGui::BeginTable("recurse1", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable))
+ if (ImGui::BeginTable("nested1", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
{
ImGui::TableSetupColumn("A0");
ImGui::TableSetupColumn("A1");
@@ -4052,7 +4292,7 @@ static void ShowDemoWindowTables()
ImGui::Text("A0 Cell 0");
{
float rows_height = TEXT_BASE_HEIGHT * 2;
- if (ImGui::BeginTable("recurse2", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable))
+ if (ImGui::BeginTable("nested2", 2, ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable))
{
ImGui::TableSetupColumn("B0");
ImGui::TableSetupColumn("B1");
@@ -4082,206 +4322,58 @@ static void ShowDemoWindowTables()
if (open_action != -1)
ImGui::SetNextItemOpen(open_action != 0);
- if (ImGui::TreeNode("Sizing policies, cell contents"))
+ if (ImGui::TreeNode("Row height"))
{
- HelpMarker("This section allows you to interact and see the effect of StretchX vs FixedX sizing policies depending on whether Scroll is enabled and the contents of your columns.");
- enum ContentsType { CT_ShortText, CT_LongText, CT_Button, CT_FillButton, CT_InputText };
- static ImGuiTableFlags flags = ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg;
- static int contents_type = CT_Button;
- static int column_count = 3;
-
- PushStyleCompact();
- ImGui::SetNextItemWidth(TEXT_BASE_WIDTH * 22);
- ImGui::Combo("Contents", &contents_type, "Short Text\0Long Text\0Button\0Fill Button\0InputText\0");
- if (contents_type == CT_FillButton)
- {
- ImGui::SameLine();
- HelpMarker("Be mindful that using right-alignment (e.g. size.x = -FLT_MIN) creates a feedback loop where contents width can feed into auto-column width can feed into contents width.");
- }
- ImGui::SetNextItemWidth(TEXT_BASE_WIDTH * 22);
- ImGui::DragInt("Columns", &column_count, 0.1f, 1, 64, "%d", ImGuiSliderFlags_AlwaysClamp);
- ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerH", &flags, ImGuiTableFlags_BordersInnerH);
- ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterH", &flags, ImGuiTableFlags_BordersOuterH);
- ImGui::CheckboxFlags("ImGuiTableFlags_BordersInnerV", &flags, ImGuiTableFlags_BordersInnerV);
- ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuterV", &flags, ImGuiTableFlags_BordersOuterV);
- ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags, ImGuiTableFlags_ScrollX);
- ImGui::CheckboxFlags("ImGuiTableFlags_ScrollY", &flags, ImGuiTableFlags_ScrollY);
- if (ImGui::CheckboxFlags("ImGuiTableFlags_ColumnsWidthStretch", &flags, ImGuiTableFlags_ColumnsWidthStretch))
- flags &= ~ImGuiTableFlags_ColumnsWidthFixed; // Can't specify both sizing polices so we clear the other
- ImGui::SameLine(); HelpMarker("Default if _ScrollX if disabled. Makes columns use _WidthStretch policy by default.");
- if (ImGui::CheckboxFlags("ImGuiTableFlags_ColumnsWidthFixed", &flags, ImGuiTableFlags_ColumnsWidthFixed))
- flags &= ~ImGuiTableFlags_ColumnsWidthStretch; // Can't specify both sizing polices so we clear the other
- ImGui::SameLine(); HelpMarker("Default if _ScrollX if enabled. Makes columns use _WidthFixed by default, or _WidthFixedResize if _Resizable is not set.");
- ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths);
- ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.");
- ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
- ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip);
- PopStyleCompact();
-
- ImVec2 outer_size(0, TEXT_BASE_HEIGHT * 7);
- if (ImGui::BeginTable("##nways", column_count, flags, outer_size))
- {
- for (int cell = 0; cell < 10 * column_count; cell++)
- {
- ImGui::TableNextColumn();
- int column = ImGui::TableGetColumnIndex();
- int row = ImGui::TableGetRowIndex();
-
- ImGui::PushID(cell);
- char label[32];
- static char text_buf[32] = "";
- sprintf(label, "Hello %d,%d", column, row);
- switch (contents_type)
- {
- case CT_ShortText: ImGui::TextUnformatted(label); break;
- case CT_LongText: ImGui::Text("Some longer text %d,%d\nOver two lines..", column, row); break;
- case CT_Button: ImGui::Button(label); break;
- case CT_FillButton: ImGui::Button(label, ImVec2(-FLT_MIN, 0.0f)); break;
- case CT_InputText: ImGui::SetNextItemWidth(-FLT_MIN); ImGui::InputText("##", text_buf, IM_ARRAYSIZE(text_buf)); break;
- }
- ImGui::PopID();
- }
- ImGui::EndTable();
- }
-
- ImGui::TextUnformatted("Item Widths");
- ImGui::SameLine();
- HelpMarker("Showcase using PushItemWidth() and how it is preserved on a per-column basis");
- if (ImGui::BeginTable("##table2", 3, ImGuiTableFlags_Borders))
- {
- ImGui::TableSetupColumn("small");
- ImGui::TableSetupColumn("half");
- ImGui::TableSetupColumn("right-align");
- ImGui::TableHeadersRow();
-
- for (int row = 0; row < 3; row++)
- {
- ImGui::TableNextRow();
- if (row == 0)
- {
- // Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient)
- ImGui::TableSetColumnIndex(0);
- ImGui::PushItemWidth(TEXT_BASE_WIDTH * 3.0f); // Small
- ImGui::TableSetColumnIndex(1);
- ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f);
- ImGui::TableSetColumnIndex(2);
- ImGui::PushItemWidth(-FLT_MIN); // Right-aligned
- }
-
- // Draw our contents
- static float dummy_f = 0.0f;
- ImGui::PushID(row);
- ImGui::TableSetColumnIndex(0);
- ImGui::SliderFloat("float0", &dummy_f, 0.0f, 1.0f);
- ImGui::TableSetColumnIndex(1);
- ImGui::SliderFloat("float1", &dummy_f, 0.0f, 1.0f);
- ImGui::TableSetColumnIndex(2);
- ImGui::SliderFloat("float2", &dummy_f, 0.0f, 1.0f);
- ImGui::PopID();
- }
- ImGui::EndTable();
- }
-
- ImGui::TextUnformatted("Stretch + ScrollX");
- ImGui::SameLine();
- HelpMarker(
- "Showcase using Stretch columns + ScrollX together: "
- "this is rather unusual and only makes sense when specifying an 'inner_width' for the table!\n"
- "Without an explicit value, inner_width is == outer_size.x and therefore using Stretch columns + ScrollX together doesn't make sense.");
- static ImGuiTableFlags flags3 = ImGuiTableFlags_ColumnsWidthStretch | ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_RowBg;
- static float inner_width = 1000.0f;
- PushStyleCompact();
- ImGui::PushID("flags3");
- ImGui::CheckboxFlags("ImGuiTableFlags_ScrollX", &flags3, ImGuiTableFlags_ScrollX);
- if (ImGui::CheckboxFlags("ImGuiTableFlags_ColumnsWidthStretch", &flags3, ImGuiTableFlags_ColumnsWidthStretch))
- flags3 &= ~ImGuiTableFlags_ColumnsWidthFixed; // Can't specify both sizing polices so we clear the other
- if (ImGui::CheckboxFlags("ImGuiTableFlags_ColumnsWidthFixed", &flags3, ImGuiTableFlags_ColumnsWidthFixed))
- flags3 &= ~ImGuiTableFlags_ColumnsWidthStretch; // Can't specify both sizing polices so we clear the other
- ImGui::SetNextItemWidth(TEXT_BASE_WIDTH * 10.0f);
- ImGui::DragFloat("inner_width", &inner_width, 1.0f, 0.0f, FLT_MAX, "%.1f");
- ImGui::PopID();
- PopStyleCompact();
- if (ImGui::BeginTable("##table3", 7, flags3 | ImGuiTableFlags_ColumnsWidthStretch | ImGuiTableFlags_ContextMenuInBody, outer_size, inner_width))
+ HelpMarker("You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\nWe cannot honor a _maximum_ row height as that would requires a unique clipping rectangle per row.");
+ if (ImGui::BeginTable("##Table", 1, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerV))
{
- for (int cell = 0; cell < 20 * 7; cell++)
+ for (int row = 0; row < 10; row++)
{
+ float min_row_height = (float)(int)(TEXT_BASE_HEIGHT * 0.30f * row);
+ ImGui::TableNextRow(ImGuiTableRowFlags_None, min_row_height);
ImGui::TableNextColumn();
- ImGui::Text("Hello world %d,%d", ImGui::TableGetColumnIndex(), ImGui::TableGetRowIndex());
+ ImGui::Text("min_row_height = %.2f", min_row_height);
}
ImGui::EndTable();
}
-
ImGui::TreePop();
}
if (open_action != -1)
ImGui::SetNextItemOpen(open_action != 0);
- if (ImGui::TreeNode("Compact table"))
+ if (ImGui::TreeNode("Outer size"))
{
- // FIXME-TABLE: Vertical border not displayed the same way as horizontal one...
- HelpMarker("Setting style.CellPadding to (0,0).");
- static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg;
- static bool no_widget_frame = false;
-
+ // Showcasing use of outer_size.x == 0.0f and ImGuiTableFlags_NoHostExtendY
+ // The default value of outer_size.x is -FLT_MIN which right-align tables.
+ // Using outer_size.x == 0.0f on a table with no scrolling and no stretch column we can make them tighter.
+ ImGui::Text("Using auto/all width, using NoHostExtendY:");
PushStyleCompact();
- ImGui::CheckboxFlags("ImGuiTableFlags_BordersOuter", &flags, ImGuiTableFlags_BordersOuter);
- ImGui::CheckboxFlags("ImGuiTableFlags_BordersH", &flags, ImGuiTableFlags_BordersH);
- ImGui::CheckboxFlags("ImGuiTableFlags_BordersV", &flags, ImGuiTableFlags_BordersV);
- ImGui::CheckboxFlags("ImGuiTableFlags_RowBg", &flags, ImGuiTableFlags_RowBg);
- ImGui::CheckboxFlags("ImGuiTableFlags_Resizable", &flags, ImGuiTableFlags_Resizable);
- ImGui::Checkbox("no_widget_frame", &no_widget_frame);
+ static ImGuiTableFlags flags = ImGuiTableFlags_Borders | ImGuiTableFlags_Resizable | ImGuiTableFlags_ContextMenuInBody | ImGuiTableFlags_RowBg | ImGuiTableFlags_SizingFixedFit;
+ static bool fixed_fill = false;
+ ImGui::Checkbox("fill", &fixed_fill);
+ ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY);
PopStyleCompact();
- ImGui::PushStyleVar(ImGuiStyleVar_CellPadding, ImVec2(0, 0));
- if (ImGui::BeginTable("##3ways", 3, flags))
+ ImVec2 outer_size = ImVec2(fixed_fill ? -FLT_MIN : 0.0f, TEXT_BASE_HEIGHT * 5.5f);
+ if (ImGui::BeginTable("##table3", 3, flags, outer_size))
{
for (int row = 0; row < 10; row++)
{
- static char text_buf[32] = "";
ImGui::TableNextRow();
for (int column = 0; column < 3; column++)
{
- ImGui::TableSetColumnIndex(column);
- ImGui::SetNextItemWidth(-FLT_MIN);
- ImGui::PushID(row * 3 + column);
- if (no_widget_frame)
- ImGui::PushStyleColor(ImGuiCol_FrameBg, 0);
- ImGui::InputText("##cell", text_buf, IM_ARRAYSIZE(text_buf));
- if (no_widget_frame)
- ImGui::PopStyleColor();
- ImGui::PopID();
+ ImGui::TableNextColumn();
+ ImGui::Text("Cell %d,%d", column, row);
}
}
ImGui::EndTable();
}
- ImGui::PopStyleVar();
- ImGui::TreePop();
- }
-
- if (open_action != -1)
- ImGui::SetNextItemOpen(open_action != 0);
- if (ImGui::TreeNode("Row height"))
- {
- HelpMarker("You can pass a 'min_row_height' to TableNextRow().\n\nRows are padded with 'style.CellPadding.y' on top and bottom, so effectively the minimum row height will always be >= 'style.CellPadding.y * 2.0f'.\n\nWe cannot honor a _maximum_ row height as that would requires a unique clipping rectangle per row.");
- if (ImGui::BeginTable("##Table", 1, ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersInnerV))
- {
- for (int row = 0; row < 10; row++)
- {
- float min_row_height = (float)(int)(TEXT_BASE_HEIGHT * 0.30f * row);
- ImGui::TableNextRow(ImGuiTableRowFlags_None, min_row_height);
- ImGui::TableNextColumn();
- ImGui::Text("min_row_height = %.2f", min_row_height);
- }
- ImGui::EndTable();
- }
- ImGui::TreePop();
- }
+ ImGui::SameLine();
+ ImGui::Text("Hello!");
+ ImGui::Spacing();
- if (open_action != -1)
- ImGui::SetNextItemOpen(open_action != 0);
- if (ImGui::TreeNode("Outer size"))
- {
+ ImGui::Text("Using explicit size:");
if (ImGui::BeginTable("##table1", 3, ImGuiTableFlags_Borders | ImGuiTableFlags_RowBg, ImVec2(TEXT_BASE_WIDTH * 30, 0.0f)))
{
for (int row = 0; row < 5; row++)
@@ -4309,6 +4401,7 @@ static void ShowDemoWindowTables()
}
ImGui::EndTable();
}
+
ImGui::TreePop();
}
@@ -4440,6 +4533,50 @@ static void ShowDemoWindowTables()
ImGui::TreePop();
}
+ if (open_action != -1)
+ ImGui::SetNextItemOpen(open_action != 0);
+ if (ImGui::TreeNode("Item width"))
+ {
+ HelpMarker(
+ "Showcase using PushItemWidth() and how it is preserved on a per-column basis.\n\n"
+ "Note that on auto-resizing non-resizable fixed columns, querying the content width for e.g. right-alignment doesn't make sense.");
+ if (ImGui::BeginTable("##table2", 3, ImGuiTableFlags_Borders))
+ {
+ ImGui::TableSetupColumn("small");
+ ImGui::TableSetupColumn("half");
+ ImGui::TableSetupColumn("right-align");
+ ImGui::TableHeadersRow();
+
+ for (int row = 0; row < 3; row++)
+ {
+ ImGui::TableNextRow();
+ if (row == 0)
+ {
+ // Setup ItemWidth once (instead of setting up every time, which is also possible but less efficient)
+ ImGui::TableSetColumnIndex(0);
+ ImGui::PushItemWidth(TEXT_BASE_WIDTH * 3.0f); // Small
+ ImGui::TableSetColumnIndex(1);
+ ImGui::PushItemWidth(-ImGui::GetContentRegionAvail().x * 0.5f);
+ ImGui::TableSetColumnIndex(2);
+ ImGui::PushItemWidth(-FLT_MIN); // Right-aligned
+ }
+
+ // Draw our contents
+ static float dummy_f = 0.0f;
+ ImGui::PushID(row);
+ ImGui::TableSetColumnIndex(0);
+ ImGui::SliderFloat("float0", &dummy_f, 0.0f, 1.0f);
+ ImGui::TableSetColumnIndex(1);
+ ImGui::SliderFloat("float1", &dummy_f, 0.0f, 1.0f);
+ ImGui::TableSetColumnIndex(2);
+ ImGui::SliderFloat("float2", &dummy_f, 0.0f, 1.0f);
+ ImGui::PopID();
+ }
+ ImGui::EndTable();
+ }
+ ImGui::TreePop();
+ }
+
// Demonstrate using TableHeader() calls instead of TableHeadersRow()
if (open_action != -1)
ImGui::SetNextItemOpen(open_action != 0);
@@ -4519,7 +4656,7 @@ static void ShowDemoWindowTables()
for (int column = 0; column < COLUMNS_COUNT; column++)
{
ImGui::TableSetColumnIndex(column);
- ImGui::Text("Cell %d,%d", 0, row);
+ ImGui::Text("Cell %d,%d", column, row);
}
}
ImGui::EndTable();
@@ -4530,7 +4667,7 @@ static void ShowDemoWindowTables()
// [2.2] Right-click on the ".." to open a custom popup
// [2.3] Right-click in columns to open another custom popup
HelpMarker("Demonstrate mixing table context menu (over header), item context button (over button) and custom per-colum context menu (over column body).");
- ImGuiTableFlags flags2 = ImGuiTableFlags_Resizable | ImGuiTableFlags_ColumnsWidthFixed | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders;
+ ImGuiTableFlags flags2 = ImGuiTableFlags_Resizable | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders;
if (ImGui::BeginTable("##table2", COLUMNS_COUNT, flags2))
{
ImGui::TableSetupColumn("One");
@@ -4604,7 +4741,7 @@ static void ShowDemoWindowTables()
char buf[32];
sprintf(buf, "Synced Table %d", n);
bool open = ImGui::CollapsingHeader(buf, ImGuiTreeNodeFlags_DefaultOpen);
- if (open && ImGui::BeginTable("Table", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_ColumnsWidthFixed | ImGuiTableFlags_NoSavedSettings))
+ if (open && ImGui::BeginTable("Table", 3, ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Borders | ImGuiTableFlags_SizingFixedFit | ImGuiTableFlags_NoSavedSettings))
{
ImGui::TableSetupColumn("One");
ImGui::TableSetupColumn("Two");
@@ -4633,8 +4770,6 @@ static void ShowDemoWindowTables()
ImGui::SetNextItemOpen(open_action != 0);
if (ImGui::TreeNode("Sorting"))
{
- HelpMarker("Use Shift+Click to sort on multiple columns");
-
// Create item list
static ImVector<MyItem> items;
if (items.Size == 0)
@@ -4650,11 +4785,19 @@ static void ShowDemoWindowTables()
}
}
- ImGuiTableFlags flags =
- ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_MultiSortable
+ // Options
+ static ImGuiTableFlags flags =
+ ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
| ImGuiTableFlags_RowBg | ImGuiTableFlags_BordersOuter | ImGuiTableFlags_BordersV | ImGuiTableFlags_NoBordersInBody
| ImGuiTableFlags_ScrollY;
- if (ImGui::BeginTable("##table", 4, flags, ImVec2(0, TEXT_BASE_HEIGHT * 15), 0.0f))
+ PushStyleCompact();
+ ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti);
+ ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
+ ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate);
+ ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
+ PopStyleCompact();
+
+ if (ImGui::BeginTable("##table", 4, flags, ImVec2(-FLT_MIN, TEXT_BASE_HEIGHT * 15), 0.0f))
{
// Declare columns
// We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications.
@@ -4712,19 +4855,19 @@ static void ShowDemoWindowTables()
if (ImGui::TreeNode("Advanced"))
{
static ImGuiTableFlags flags =
- ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable | ImGuiTableFlags_MultiSortable
+ ImGuiTableFlags_Resizable | ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable
+ | ImGuiTableFlags_Sortable | ImGuiTableFlags_SortMulti
| ImGuiTableFlags_RowBg | ImGuiTableFlags_Borders | ImGuiTableFlags_NoBordersInBody
| ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY
- | ImGuiTableFlags_ColumnsWidthFixed
- ;
+ | ImGuiTableFlags_SizingFixedFit;
enum ContentsType { CT_Text, CT_Button, CT_SmallButton, CT_FillButton, CT_Selectable, CT_SelectableSpanRow };
- static int contents_type = CT_Button;
+ static int contents_type = CT_SelectableSpanRow;
const char* contents_type_names[] = { "Text", "Button", "SmallButton", "FillButton", "Selectable", "Selectable (span row)" };
static int freeze_cols = 1;
static int freeze_rows = 1;
- static int items_count = IM_ARRAYSIZE(template_items_names);
- static ImVec2 outer_size_value = ImVec2(0, TEXT_BASE_HEIGHT * 12);
+ static int items_count = IM_ARRAYSIZE(template_items_names) * 2;
+ static ImVec2 outer_size_value = ImVec2(-FLT_MIN, TEXT_BASE_HEIGHT * 12);
static float row_min_height = 0.0f; // Auto
static float inner_width_with_scroll = 0.0f; // Auto-extend
static bool outer_size_enabled = true;
@@ -4744,7 +4887,6 @@ static void ShowDemoWindowTables()
ImGui::CheckboxFlags("ImGuiTableFlags_Reorderable", &flags, ImGuiTableFlags_Reorderable);
ImGui::CheckboxFlags("ImGuiTableFlags_Hideable", &flags, ImGuiTableFlags_Hideable);
ImGui::CheckboxFlags("ImGuiTableFlags_Sortable", &flags, ImGuiTableFlags_Sortable);
- ImGui::CheckboxFlags("ImGuiTableFlags_MultiSortable", &flags, ImGuiTableFlags_MultiSortable);
ImGui::CheckboxFlags("ImGuiTableFlags_NoSavedSettings", &flags, ImGuiTableFlags_NoSavedSettings);
ImGui::CheckboxFlags("ImGuiTableFlags_ContextMenuInBody", &flags, ImGuiTableFlags_ContextMenuInBody);
ImGui::TreePop();
@@ -4766,19 +4908,13 @@ static void ShowDemoWindowTables()
if (ImGui::TreeNodeEx("Sizing:", ImGuiTreeNodeFlags_DefaultOpen))
{
- if (ImGui::CheckboxFlags("ImGuiTableFlags_ColumnsWidthStretch", &flags, ImGuiTableFlags_ColumnsWidthStretch))
- flags &= ~ImGuiTableFlags_ColumnsWidthFixed; // Can't specify both sizing polices so we clear the other
- ImGui::SameLine(); HelpMarker("[Default if ScrollX is off]\nFit all columns within available width (or specified inner_width). Fixed and Stretch columns allowed.");
- if (ImGui::CheckboxFlags("ImGuiTableFlags_ColumnsWidthFixed", &flags, ImGuiTableFlags_ColumnsWidthFixed))
- flags &= ~ImGuiTableFlags_ColumnsWidthStretch; // Can't specify both sizing polices so we clear the other
- ImGui::SameLine(); HelpMarker("[Default if ScrollX is on]\nEnlarge as needed: enable scrollbar if ScrollX is enabled, otherwise extend parent window's contents rectangle. Only Fixed columns allowed. Stretched columns will calculate their width assuming no scrolling.");
- ImGui::CheckboxFlags("ImGuiTableFlags_NoHeadersWidth", &flags, ImGuiTableFlags_NoHeadersWidth);
+ EditTableSizingFlags(&flags);
+ ImGui::SameLine(); HelpMarker("In the Advanced demo we override the policy of each column so those table-wide settings have less effect that typical.");
ImGui::CheckboxFlags("ImGuiTableFlags_NoHostExtendY", &flags, ImGuiTableFlags_NoHostExtendY);
ImGui::CheckboxFlags("ImGuiTableFlags_NoKeepColumnsVisible", &flags, ImGuiTableFlags_NoKeepColumnsVisible);
ImGui::SameLine(); HelpMarker("Only available if ScrollX is disabled.");
ImGui::CheckboxFlags("ImGuiTableFlags_PreciseWidths", &flags, ImGuiTableFlags_PreciseWidths);
ImGui::SameLine(); HelpMarker("Disable distributing remainder width to stretched columns (width allocation on a 100-wide table with 3 columns: Without this flag: 33,33,34. With this flag: 33,33,33). With larger number of columns, resizing will appear to be less smooth.");
- ImGui::CheckboxFlags("ImGuiTableFlags_SameWidths", &flags, ImGuiTableFlags_SameWidths);
ImGui::CheckboxFlags("ImGuiTableFlags_NoClip", &flags, ImGuiTableFlags_NoClip);
ImGui::SameLine(); HelpMarker("Disable clipping rectangle for every individual columns (reduce draw command count, items will be able to overflow into other columns). Generally incompatible with ScrollFreeze options.");
ImGui::TreePop();
@@ -4805,23 +4941,39 @@ static void ShowDemoWindowTables()
ImGui::TreePop();
}
+ if (ImGui::TreeNodeEx("Sorting:", ImGuiTreeNodeFlags_DefaultOpen))
+ {
+ ImGui::CheckboxFlags("ImGuiTableFlags_SortMulti", &flags, ImGuiTableFlags_SortMulti);
+ ImGui::SameLine(); HelpMarker("When sorting is enabled: hold shift when clicking headers to sort on multiple column. TableGetSortSpecs() may return specs where (SpecsCount > 1).");
+ ImGui::CheckboxFlags("ImGuiTableFlags_SortTristate", &flags, ImGuiTableFlags_SortTristate);
+ ImGui::SameLine(); HelpMarker("When sorting is enabled: allow no sorting, disable default sorting. TableGetSortSpecs() may return specs where (SpecsCount == 0).");
+ ImGui::TreePop();
+ }
+
if (ImGui::TreeNodeEx("Other:", ImGuiTreeNodeFlags_DefaultOpen))
{
ImGui::Checkbox("show_headers", &show_headers);
ImGui::Checkbox("show_wrapped_text", &show_wrapped_text);
+
ImGui::DragFloat2("##OuterSize", &outer_size_value.x);
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
ImGui::Checkbox("outer_size", &outer_size_enabled);
ImGui::SameLine();
- HelpMarker("If scrolling is disabled (ScrollX and ScrollY not set), the table is output directly in the parent window. OuterSize.y then becomes the minimum size for the table, which will extend vertically if there are more rows (unless NoHostExtendV is set).");
+ HelpMarker("If scrolling is disabled (ScrollX and ScrollY not set):\n"
+ "- The table is output directly in the parent window.\n"
+ "- OuterSize.x < 0.0f will right-align the table.\n"
+ "- OuterSize.x = 0.0f will narrow fit the table unless there are any Stretch column.\n"
+ "- OuterSize.y then becomes the minimum size for the table, which will extend vertically if there are more rows (unless NoHostExtendY is set).");
// From a user point of view we will tend to use 'inner_width' differently depending on whether our table is embedding scrolling.
- // To facilitate experimentation we expose two values and will select the right one depending on active flags.
+ // To facilitate toying with this demo we will actually pass 0.0f to the BeginTable() when ScrollX is disabled.
ImGui::DragFloat("inner_width (when ScrollX active)", &inner_width_with_scroll, 1.0f, 0.0f, FLT_MAX);
+
ImGui::DragFloat("row_min_height", &row_min_height, 1.0f, 0.0f, FLT_MAX);
ImGui::SameLine(); HelpMarker("Specify height of the Selectable item.");
+
ImGui::DragInt("items_count", &items_count, 0.1f, 0, 9999);
- ImGui::Combo("contents_type (first column)", &contents_type, contents_type_names, IM_ARRAYSIZE(contents_type_names));
+ ImGui::Combo("items_type (first column)", &contents_type, contents_type_names, IM_ARRAYSIZE(contents_type_names));
//filter.Draw("filter");
ImGui::TreePop();
}
@@ -4860,13 +5012,13 @@ static void ShowDemoWindowTables()
// Declare columns
// We use the "user_id" parameter of TableSetupColumn() to specify a user id that will be stored in the sort specifications.
// This is so our sort function can identify a column given our own identifier. We could also identify them based on their index!
+ ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, -1.0f, MyItemColumnID_ID);
+ ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, -1.0f, MyItemColumnID_Name);
+ ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, -1.0f, MyItemColumnID_Action);
+ ImGui::TableSetupColumn("Quantity", ImGuiTableColumnFlags_PreferSortDescending, -1.0f, MyItemColumnID_Quantity);
+ ImGui::TableSetupColumn("Description", ImGuiTableColumnFlags_WidthStretch, -1.0f, MyItemColumnID_Description);
+ ImGui::TableSetupColumn("Hidden", ImGuiTableColumnFlags_DefaultHide | ImGuiTableColumnFlags_NoSort);
ImGui::TableSetupScrollFreeze(freeze_cols, freeze_rows);
- ImGui::TableSetupColumn("ID", ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHide, -1.0f, MyItemColumnID_ID);
- ImGui::TableSetupColumn("Name", ImGuiTableColumnFlags_WidthFixed, -1.0f, MyItemColumnID_Name);
- ImGui::TableSetupColumn("Action", ImGuiTableColumnFlags_NoSort | ImGuiTableColumnFlags_WidthFixed, -1.0f, MyItemColumnID_Action);
- ImGui::TableSetupColumn("Quantity (Long Label)", ImGuiTableColumnFlags_PreferSortDescending | ImGuiTableColumnFlags_WidthStretch, 1.0f, MyItemColumnID_Quantity);// , ImGuiTableColumnFlags_WidthAutoResize);
- ImGui::TableSetupColumn("Description", ImGuiTableColumnFlags_WidthStretch, 1.0f, MyItemColumnID_Description);
- ImGui::TableSetupColumn("Hidden", ImGuiTableColumnFlags_DefaultHide | ImGuiTableColumnFlags_NoSort);
// Sort our data if sort specs have been changed!
ImGuiTableSortSpecs* sorts_specs = ImGui::TableGetSortSpecs();
@@ -5553,13 +5705,13 @@ void ImGui::ShowAboutWindow(bool* p_open)
bool ImGui::ShowStyleSelector(const char* label)
{
static int style_idx = -1;
- if (ImGui::Combo(label, &style_idx, "Classic\0Dark\0Light\0"))
+ if (ImGui::Combo(label, &style_idx, "Dark\0Light\0Classic\0"))
{
switch (style_idx)
{
- case 0: ImGui::StyleColorsClassic(); break;
- case 1: ImGui::StyleColorsDark(); break;
- case 2: ImGui::StyleColorsLight(); break;
+ case 0: ImGui::StyleColorsDark(); break;
+ case 1: ImGui::StyleColorsLight(); break;
+ case 2: ImGui::StyleColorsClassic(); break;
}
return true;
}
@@ -6073,7 +6225,7 @@ struct ExampleAppConsole
// Portable helpers
static int Stricmp(const char* s1, const char* s2) { int d; while ((d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; } return d; }
static int Strnicmp(const char* s1, const char* s2, int n) { int d = 0; while (n > 0 && (d = toupper(*s2) - toupper(*s1)) == 0 && *s1) { s1++; s2++; n--; } return d; }
- static char* Strdup(const char* s) { size_t len = strlen(s) + 1; void* buf = malloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)s, len); }
+ static char* Strdup(const char* s) { IM_ASSERT(s); size_t len = strlen(s) + 1; void* buf = malloc(len); IM_ASSERT(buf); return (char*)memcpy(buf, (const void*)s, len); }
static void Strtrim(char* s) { char* str_end = s + strlen(s); while (str_end > s && str_end[-1] == ' ') str_end--; *str_end = 0; }
void ClearLog()
@@ -6968,14 +7120,18 @@ static void ShowExampleAppCustomRendering(bool* p_open)
static int ngon_sides = 6;
static bool circle_segments_override = false;
static int circle_segments_override_v = 12;
+ static bool curve_segments_override = false;
+ static int curve_segments_override_v = 8;
static ImVec4 colf = ImVec4(1.0f, 1.0f, 0.4f, 1.0f);
ImGui::DragFloat("Size", &sz, 0.2f, 2.0f, 72.0f, "%.0f");
ImGui::DragFloat("Thickness", &thickness, 0.05f, 1.0f, 8.0f, "%.02f");
ImGui::SliderInt("N-gon sides", &ngon_sides, 3, 12);
ImGui::Checkbox("##circlesegmentoverride", &circle_segments_override);
ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
- if (ImGui::SliderInt("Circle segments", &circle_segments_override_v, 3, 40))
- circle_segments_override = true;
+ circle_segments_override |= ImGui::SliderInt("Circle segments override", &circle_segments_override_v, 3, 40);
+ ImGui::Checkbox("##curvessegmentoverride", &curve_segments_override);
+ ImGui::SameLine(0.0f, ImGui::GetStyle().ItemInnerSpacing.x);
+ curve_segments_override |= ImGui::SliderInt("Curves segments override", &curve_segments_override_v, 3, 40);
ImGui::ColorEdit4("Color", &colf.x);
const ImVec2 p = ImGui::GetCursorScreenPos();
@@ -6985,6 +7141,7 @@ static void ShowExampleAppCustomRendering(bool* p_open)
const ImDrawCornerFlags corners_all = ImDrawCornerFlags_All;
const ImDrawCornerFlags corners_tl_br = ImDrawCornerFlags_TopLeft | ImDrawCornerFlags_BotRight;
const int circle_segments = circle_segments_override ? circle_segments_override_v : 0;
+ const int curve_segments = curve_segments_override ? curve_segments_override_v : 0;
float x = p.x + 4.0f;
float y = p.y + 4.0f;
for (int n = 0; n < 2; n++)
@@ -7001,7 +7158,15 @@ static void ShowExampleAppCustomRendering(bool* p_open)
draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y), col, th); x += sz + spacing; // Horizontal line (note: drawing a filled rectangle will be faster!)
draw_list->AddLine(ImVec2(x, y), ImVec2(x, y + sz), col, th); x += spacing; // Vertical line (note: drawing a filled rectangle will be faster!)
draw_list->AddLine(ImVec2(x, y), ImVec2(x + sz, y + sz), col, th); x += sz + spacing; // Diagonal line
- draw_list->AddBezierCurve(ImVec2(x, y), ImVec2(x + sz*1.3f, y + sz*0.3f), ImVec2(x + sz - sz*1.3f, y + sz - sz*0.3f), ImVec2(x + sz, y + sz), col, th);
+
+ // Quadratic Bezier Curve (3 control points)
+ ImVec2 cp3[3] = { ImVec2(x, y + sz * 0.6f), ImVec2(x + sz * 0.5f, y - sz * 0.4f), ImVec2(x + sz, y + sz) };
+ draw_list->AddBezierQuadratic(cp3[0], cp3[1], cp3[2], col, th, curve_segments); x += sz + spacing;
+
+ // Cubic Bezier Curve (4 control points)
+ ImVec2 cp4[4] = { ImVec2(x, y), ImVec2(x + sz * 1.3f, y + sz * 0.3f), ImVec2(x + sz - sz * 1.3f, y + sz - sz * 0.3f), ImVec2(x + sz, y + sz) };
+ draw_list->AddBezierCubic(cp4[0], cp4[1], cp4[2], cp4[3], col, th, curve_segments);
+
x = p.x + 4;
y += sz + spacing;
}
diff --git a/imgui/imgui_draw.cpp b/imgui/imgui_draw.cpp
index 4eb9ca61..a076e03d 100644
--- a/imgui/imgui_draw.cpp
+++ b/imgui/imgui_draw.cpp
@@ -210,7 +210,7 @@ void ImGui::StyleColorsDark(ImGuiStyle* dst)
colors[ImGuiCol_Separator] = colors[ImGuiCol_Border];
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.10f, 0.40f, 0.75f, 0.78f);
colors[ImGuiCol_SeparatorActive] = ImVec4(0.10f, 0.40f, 0.75f, 1.00f);
- colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.25f);
+ colors[ImGuiCol_ResizeGrip] = ImVec4(0.26f, 0.59f, 0.98f, 0.20f);
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
@@ -244,7 +244,7 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst)
colors[ImGuiCol_Text] = ImVec4(0.90f, 0.90f, 0.90f, 1.00f);
colors[ImGuiCol_TextDisabled] = ImVec4(0.60f, 0.60f, 0.60f, 1.00f);
- colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.70f);
+ colors[ImGuiCol_WindowBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.85f);
colors[ImGuiCol_ChildBg] = ImVec4(0.00f, 0.00f, 0.00f, 0.00f);
colors[ImGuiCol_PopupBg] = ImVec4(0.11f, 0.11f, 0.14f, 0.92f);
colors[ImGuiCol_Border] = ImVec4(0.50f, 0.50f, 0.50f, 0.50f);
@@ -272,7 +272,7 @@ void ImGui::StyleColorsClassic(ImGuiStyle* dst)
colors[ImGuiCol_Separator] = ImVec4(0.50f, 0.50f, 0.50f, 0.60f);
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.60f, 0.60f, 0.70f, 1.00f);
colors[ImGuiCol_SeparatorActive] = ImVec4(0.70f, 0.70f, 0.90f, 1.00f);
- colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.16f);
+ colors[ImGuiCol_ResizeGrip] = ImVec4(1.00f, 1.00f, 1.00f, 0.10f);
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.78f, 0.82f, 1.00f, 0.60f);
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.78f, 0.82f, 1.00f, 0.90f);
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.80f);
@@ -335,7 +335,7 @@ void ImGui::StyleColorsLight(ImGuiStyle* dst)
colors[ImGuiCol_Separator] = ImVec4(0.39f, 0.39f, 0.39f, 0.62f);
colors[ImGuiCol_SeparatorHovered] = ImVec4(0.14f, 0.44f, 0.80f, 0.78f);
colors[ImGuiCol_SeparatorActive] = ImVec4(0.14f, 0.44f, 0.80f, 1.00f);
- colors[ImGuiCol_ResizeGrip] = ImVec4(0.80f, 0.80f, 0.80f, 0.56f);
+ colors[ImGuiCol_ResizeGrip] = ImVec4(0.35f, 0.35f, 0.35f, 0.17f);
colors[ImGuiCol_ResizeGripHovered] = ImVec4(0.26f, 0.59f, 0.98f, 0.67f);
colors[ImGuiCol_ResizeGripActive] = ImVec4(0.26f, 0.59f, 0.98f, 0.95f);
colors[ImGuiCol_Tab] = ImLerp(colors[ImGuiCol_Header], colors[ImGuiCol_TitleBgActive], 0.90f);
@@ -411,6 +411,7 @@ void ImDrawList::_ResetForNewFrame()
_Path.resize(0);
_Splitter.Clear();
CmdBuffer.push_back(ImDrawCmd());
+ _FringeScale = 1.0f;
}
void ImDrawList::_ClearFreeMemory()
@@ -686,12 +687,12 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
const ImVec2 opaque_uv = _Data->TexUvWhitePixel;
const int count = closed ? points_count : points_count - 1; // The number of line segments we need to draw
- const bool thick_line = (thickness > 1.0f);
+ const bool thick_line = (thickness > _FringeScale);
if (Flags & ImDrawListFlags_AntiAliasedLines)
{
// Anti-aliased stroke
- const float AA_SIZE = 1.0f;
+ const float AA_SIZE = _FringeScale;
const ImU32 col_trans = col & ~IM_COL32_A_MASK;
// Thicknesses <1.0 should behave like thickness 1.0
@@ -702,7 +703,7 @@ void ImDrawList::AddPolyline(const ImVec2* points, const int points_count, ImU32
// Do we want to draw this line using a texture?
// - For now, only draw integer-width lines using textures to avoid issues with the way scaling occurs, could be improved.
// - If AA_SIZE is not 1.0f we cannot use the texture path.
- const bool use_texture = (Flags & ImDrawListFlags_AntiAliasedLinesUseTex) && (integer_thickness < IM_DRAWLIST_TEX_LINES_WIDTH_MAX) && (fractional_thickness <= 0.00001f);
+ const bool use_texture = (Flags & ImDrawListFlags_AntiAliasedLinesUseTex) && (integer_thickness < IM_DRAWLIST_TEX_LINES_WIDTH_MAX) && (fractional_thickness <= 0.00001f) && (AA_SIZE == 1.0f);
// We should never hit this, because NewFrame() doesn't set ImDrawListFlags_AntiAliasedLinesUseTex unless ImFontAtlasFlags_NoBakedLines is off
IM_ASSERT_PARANOID(!use_texture || !(_Data->Font->ContainerAtlas->Flags & ImFontAtlasFlags_NoBakedLines));
@@ -944,7 +945,7 @@ void ImDrawList::AddConvexPolyFilled(const ImVec2* points, const int points_coun
if (Flags & ImDrawListFlags_AntiAliasedFill)
{
// Anti-aliased Fill
- const float AA_SIZE = 1.0f;
+ const float AA_SIZE = _FringeScale;
const ImU32 col_trans = col & ~IM_COL32_A_MASK;
const int idx_count = (points_count - 2)*3 + points_count * 6;
const int vtx_count = (points_count * 2);
@@ -1056,23 +1057,32 @@ void ImDrawList::PathArcTo(const ImVec2& center, float radius, float a_min, floa
}
}
-ImVec2 ImBezierCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t)
+ImVec2 ImBezierCubicCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t)
{
float u = 1.0f - t;
- float w1 = u*u*u;
- float w2 = 3*u*u*t;
- float w3 = 3*u*t*t;
- float w4 = t*t*t;
- return ImVec2(w1*p1.x + w2*p2.x + w3*p3.x + w4*p4.x, w1*p1.y + w2*p2.y + w3*p3.y + w4*p4.y);
+ float w1 = u * u * u;
+ float w2 = 3 * u * u * t;
+ float w3 = 3 * u * t * t;
+ float w4 = t * t * t;
+ return ImVec2(w1 * p1.x + w2 * p2.x + w3 * p3.x + w4 * p4.x, w1 * p1.y + w2 * p2.y + w3 * p3.y + w4 * p4.y);
}
-// Closely mimics BezierClosestPointCasteljauStep() in imgui.cpp
-static void PathBezierToCasteljau(ImVector<ImVec2>* path, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level)
+ImVec2 ImBezierQuadraticCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float t)
+{
+ float u = 1.0f - t;
+ float w1 = u * u;
+ float w2 = 2 * u * t;
+ float w3 = t * t;
+ return ImVec2(w1 * p1.x + w2 * p2.x + w3 * p3.x, w1 * p1.y + w2 * p2.y + w3 * p3.y);
+}
+
+// Closely mimics ImBezierCubicClosestPointCasteljau() in imgui.cpp
+static void PathBezierCubicCurveToCasteljau(ImVector<ImVec2>* path, float x1, float y1, float x2, float y2, float x3, float y3, float x4, float y4, float tess_tol, int level)
{
float dx = x4 - x1;
float dy = y4 - y1;
- float d2 = ((x2 - x4) * dy - (y2 - y4) * dx);
- float d3 = ((x3 - x4) * dy - (y3 - y4) * dx);
+ float d2 = (x2 - x4) * dy - (y2 - y4) * dx;
+ float d3 = (x3 - x4) * dy - (y3 - y4) * dx;
d2 = (d2 >= 0) ? d2 : -d2;
d3 = (d3 >= 0) ? d3 : -d3;
if ((d2 + d3) * (d2 + d3) < tess_tol * (dx * dx + dy * dy))
@@ -1081,29 +1091,62 @@ static void PathBezierToCasteljau(ImVector<ImVec2>* path, float x1, float y1, fl
}
else if (level < 10)
{
- float x12 = (x1 + x2)*0.5f, y12 = (y1 + y2)*0.5f;
- float x23 = (x2 + x3)*0.5f, y23 = (y2 + y3)*0.5f;
- float x34 = (x3 + x4)*0.5f, y34 = (y3 + y4)*0.5f;
- float x123 = (x12 + x23)*0.5f, y123 = (y12 + y23)*0.5f;
- float x234 = (x23 + x34)*0.5f, y234 = (y23 + y34)*0.5f;
- float x1234 = (x123 + x234)*0.5f, y1234 = (y123 + y234)*0.5f;
- PathBezierToCasteljau(path, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
- PathBezierToCasteljau(path, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
+ float x12 = (x1 + x2) * 0.5f, y12 = (y1 + y2) * 0.5f;
+ float x23 = (x2 + x3) * 0.5f, y23 = (y2 + y3) * 0.5f;
+ float x34 = (x3 + x4) * 0.5f, y34 = (y3 + y4) * 0.5f;
+ float x123 = (x12 + x23) * 0.5f, y123 = (y12 + y23) * 0.5f;
+ float x234 = (x23 + x34) * 0.5f, y234 = (y23 + y34) * 0.5f;
+ float x1234 = (x123 + x234) * 0.5f, y1234 = (y123 + y234) * 0.5f;
+ PathBezierCubicCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, x1234, y1234, tess_tol, level + 1);
+ PathBezierCubicCurveToCasteljau(path, x1234, y1234, x234, y234, x34, y34, x4, y4, tess_tol, level + 1);
+ }
+}
+
+static void PathBezierQuadraticCurveToCasteljau(ImVector<ImVec2>* path, float x1, float y1, float x2, float y2, float x3, float y3, float tess_tol, int level)
+{
+ float dx = x3 - x1, dy = y3 - y1;
+ float det = (x2 - x3) * dy - (y2 - y3) * dx;
+ if (det * det * 4.0f < tess_tol * (dx * dx + dy * dy))
+ {
+ path->push_back(ImVec2(x3, y3));
+ }
+ else if (level < 10)
+ {
+ float x12 = (x1 + x2) * 0.5f, y12 = (y1 + y2) * 0.5f;
+ float x23 = (x2 + x3) * 0.5f, y23 = (y2 + y3) * 0.5f;
+ float x123 = (x12 + x23) * 0.5f, y123 = (y12 + y23) * 0.5f;
+ PathBezierQuadraticCurveToCasteljau(path, x1, y1, x12, y12, x123, y123, tess_tol, level + 1);
+ PathBezierQuadraticCurveToCasteljau(path, x123, y123, x23, y23, x3, y3, tess_tol, level + 1);
}
}
-void ImDrawList::PathBezierCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments)
+void ImDrawList::PathBezierCubicCurveTo(const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, int num_segments)
{
ImVec2 p1 = _Path.back();
if (num_segments == 0)
{
- PathBezierToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, _Data->CurveTessellationTol, 0); // Auto-tessellated
+ PathBezierCubicCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, p4.x, p4.y, _Data->CurveTessellationTol, 0); // Auto-tessellated
}
else
{
float t_step = 1.0f / (float)num_segments;
for (int i_step = 1; i_step <= num_segments; i_step++)
- _Path.push_back(ImBezierCalc(p1, p2, p3, p4, t_step * i_step));
+ _Path.push_back(ImBezierCubicCalc(p1, p2, p3, p4, t_step * i_step));
+ }
+}
+
+void ImDrawList::PathBezierQuadraticCurveTo(const ImVec2& p2, const ImVec2& p3, int num_segments)
+{
+ ImVec2 p1 = _Path.back();
+ if (num_segments == 0)
+ {
+ PathBezierQuadraticCurveToCasteljau(&_Path, p1.x, p1.y, p2.x, p2.y, p3.x, p3.y, _Data->CurveTessellationTol, 0);// Auto-tessellated
+ }
+ else
+ {
+ float t_step = 1.0f / (float)num_segments;
+ for (int i_step = 1; i_step <= num_segments; i_step++)
+ _Path.push_back(ImBezierQuadraticCalc(p1, p2, p3, t_step * i_step));
}
}
@@ -1317,13 +1360,24 @@ void ImDrawList::AddNgonFilled(const ImVec2& center, float radius, ImU32 col, in
}
// Cubic Bezier takes 4 controls points
-void ImDrawList::AddBezierCurve(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments)
+void ImDrawList::AddBezierCubic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, ImU32 col, float thickness, int num_segments)
{
if ((col & IM_COL32_A_MASK) == 0)
return;
PathLineTo(p1);
- PathBezierCurveTo(p2, p3, p4, num_segments);
+ PathBezierCubicCurveTo(p2, p3, p4, num_segments);
+ PathStroke(col, false, thickness);
+}
+
+// Quadratic Bezier takes 3 controls points
+void ImDrawList::AddBezierQuadratic(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, ImU32 col, float thickness, int num_segments)
+{
+ if ((col & IM_COL32_A_MASK) == 0)
+ return;
+
+ PathLineTo(p1);
+ PathBezierQuadraticCurveTo(p2, p3, num_segments);
PathStroke(col, false, thickness);
}
@@ -2123,10 +2177,11 @@ bool ImFontAtlasBuildWithStbTruetype(ImFontAtlas* atlas)
for (int output_i = 0; output_i < atlas->Fonts.Size && src_tmp.DstIndex == -1; output_i++)
if (cfg.DstFont == atlas->Fonts[output_i])
src_tmp.DstIndex = output_i;
- IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array?
if (src_tmp.DstIndex == -1)
+ {
+ IM_ASSERT(src_tmp.DstIndex != -1); // cfg.DstFont not pointing within atlas->Fonts[] array?
return false;
-
+ }
// Initialize helper structure for font loading and verify that the TTF/OTF data is correct
const int font_offset = stbtt_GetFontOffsetForIndex((unsigned char*)cfg.FontData, cfg.FontNo);
IM_ASSERT(font_offset >= 0 && "FontData is incorrect, or FontNo cannot be found.");
diff --git a/imgui/imgui_internal.h b/imgui/imgui_internal.h
index bb8ea5c3..ea7b7899 100644
--- a/imgui/imgui_internal.h
+++ b/imgui/imgui_internal.h
@@ -408,9 +408,10 @@ static inline float ImLinearSweep(float current, float target, float speed)
static inline ImVec2 ImMul(const ImVec2& lhs, const ImVec2& rhs) { return ImVec2(lhs.x * rhs.x, lhs.y * rhs.y); }
// Helpers: Geometry
-IMGUI_API ImVec2 ImBezierCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t); // Cubic Bezier
-IMGUI_API ImVec2 ImBezierClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments); // For curves with explicit number of segments
-IMGUI_API ImVec2 ImBezierClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol);// For auto-tessellated curves you can use tess_tol = style.CurveTessellationTol
+IMGUI_API ImVec2 ImBezierCubicCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, float t);
+IMGUI_API ImVec2 ImBezierCubicClosestPoint(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, int num_segments); // For curves with explicit number of segments
+IMGUI_API ImVec2 ImBezierCubicClosestPointCasteljau(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, const ImVec2& p4, const ImVec2& p, float tess_tol);// For auto-tessellated curves you can use tess_tol = style.CurveTessellationTol
+IMGUI_API ImVec2 ImBezierQuadraticCalc(const ImVec2& p1, const ImVec2& p2, const ImVec2& p3, float t);
IMGUI_API ImVec2 ImLineClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& p);
IMGUI_API bool ImTriangleContainsPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p);
IMGUI_API ImVec2 ImTriangleClosestPoint(const ImVec2& a, const ImVec2& b, const ImVec2& c, const ImVec2& p);
@@ -1443,9 +1444,11 @@ struct ImGuiContext
float WheelingWindowTimer;
// Item/widgets state and tracking information
- ImGuiID HoveredId; // Hovered widget
+ ImGuiID HoveredId; // Hovered widget, filled during the frame
ImGuiID HoveredIdPreviousFrame;
bool HoveredIdAllowOverlap;
+ bool HoveredIdUsingMouseWheel; // Hovered widget will use mouse wheel. Blocks scrolling the underlying window.
+ bool HoveredIdPreviousFrameUsingMouseWheel;
bool HoveredIdDisabled; // At least one widget passed the rect test, but has been discarded by disabled flag or popup inhibit. May be true even if HoveredId == 0.
float HoveredIdTimer; // Measure contiguous hovering time
float HoveredIdNotActiveTimer; // Measure contiguous hovering time where the item has not been active
@@ -1458,6 +1461,7 @@ struct ImGuiContext
bool ActiveIdHasBeenPressedBefore; // Track whether the active id led to a press (this is to allow changing between PressOnClick and PressOnRelease without pressing twice). Used by range_select branch.
bool ActiveIdHasBeenEditedBefore; // Was the value associated to the widget Edited over the course of the Active state.
bool ActiveIdHasBeenEditedThisFrame;
+ bool ActiveIdUsingMouseWheel; // Active widget will want to read mouse wheel. Blocks scrolling the underlying window.
ImU32 ActiveIdUsingNavDirMask; // Active widget will want to read those nav move requests (e.g. can activate a button and move away from it)
ImU32 ActiveIdUsingNavInputMask; // Active widget will want to read those nav inputs.
ImU64 ActiveIdUsingKeyInputMask; // Active widget will want to read those key inputs. When we grow the ImGuiKey enum we'll need to either to order the enum to make useful keys come first, either redesign this into e.g. a small array.
@@ -1680,6 +1684,7 @@ struct ImGuiContext
HoveredId = HoveredIdPreviousFrame = 0;
HoveredIdAllowOverlap = false;
+ HoveredIdUsingMouseWheel = HoveredIdPreviousFrameUsingMouseWheel = false;
HoveredIdDisabled = false;
HoveredIdTimer = HoveredIdNotActiveTimer = 0.0f;
ActiveId = 0;
@@ -1691,6 +1696,7 @@ struct ImGuiContext
ActiveIdHasBeenPressedBefore = false;
ActiveIdHasBeenEditedBefore = false;
ActiveIdHasBeenEditedThisFrame = false;
+ ActiveIdUsingMouseWheel = false;
ActiveIdUsingNavDirMask = 0x00;
ActiveIdUsingNavInputMask = 0x00;
ActiveIdUsingKeyInputMask = 0x00;
@@ -1912,12 +1918,13 @@ struct IMGUI_API ImGuiWindow
ImS8 AutoFitChildAxises;
bool AutoFitOnlyGrows;
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
- ImGuiCond SetWindowPosAllowFlags; // store acceptable condition flags for SetNextWindowPos() use.
- ImGuiCond SetWindowSizeAllowFlags; // store acceptable condition flags for SetNextWindowSize() use.
- ImGuiCond SetWindowCollapsedAllowFlags; // store acceptable condition flags for SetNextWindowCollapsed() use.
- ImGuiCond SetWindowDockAllowFlags; // store acceptable condition flags for SetNextWindowDock() use.
+ ImS8 HiddenFramesCanSkipItems; // Hide the window for N frames
+ ImS8 HiddenFramesCannotSkipItems; // Hide the window for N frames while allowing items to be submitted so we can measure their size
+ ImS8 HiddenFramesForRenderOnly; // Hide the window until frame N at Render() time only
+ ImGuiCond SetWindowPosAllowFlags : 8; // store acceptable condition flags for SetNextWindowPos() use.
+ ImGuiCond SetWindowSizeAllowFlags : 8; // store acceptable condition flags for SetNextWindowSize() use.
+ ImGuiCond SetWindowCollapsedAllowFlags : 8; // store acceptable condition flags for SetNextWindowCollapsed() use.
+ ImGuiCond SetWindowDockAllowFlags : 8; // store acceptable condition flags for SetNextWindowDock() use.
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.
@@ -2109,24 +2116,23 @@ typedef ImU8 ImGuiTableDrawChannelIdx;
// [Internal] sizeof() ~ 104
// We use the terminology "Enabled" to refer to a column that is not Hidden by user/api.
-// We use the terminology "Clipped" to refer to a column that is out of sight because of scrolling/clipping.
+// We use the terminology "Clipped" to refer to a column that is out of sight because of scrolling/clipping.
// This is in contrast with some user-facing api such as IsItemVisible() / IsRectVisible() which use "Visible" to mean "not clipped".
struct ImGuiTableColumn
{
- ImRect ClipRect; // Clipping rectangle for the column
- ImGuiID UserID; // Optional, value passed to TableSetupColumn()
- ImGuiTableColumnFlags FlagsIn; // Flags as they were provided by user. See ImGuiTableColumnFlags_
- ImGuiTableColumnFlags Flags; // Effective flags. See ImGuiTableColumnFlags_
+ ImGuiTableColumnFlags Flags; // Flags after some patching (not directly same as provided by user). See ImGuiTableColumnFlags_
+ float WidthGiven; // Final/actual width visible == (MaxX - MinX), locked in TableUpdateLayout(). May be > WidthRequest to honor minimum width, may be < WidthRequest to honor shrinking columns down in tight space.
float MinX; // Absolute positions
float MaxX;
- float InitStretchWeightOrWidth; // Value passed to TableSetupColumn(). For Width it is a content width (_without padding_).
- float StretchWeight; // Master width weight when (Flags & _WidthStretch). Often around ~1.0f initially.
- float WidthAuto; // Automatic width
float WidthRequest; // Master width absolute value when !(Flags & _WidthStretch). When Stretch this is derived every frame from StretchWeight in TableUpdateLayout()
- float WidthGiven; // Final/actual width visible == (MaxX - MinX), locked in TableUpdateLayout(). May be > WidthRequest to honor minimum width, may be < WidthRequest to honor shrinking columns down in tight space.
- float WorkMinX; // Start position for the frame, currently ~(MinX + CellPaddingX)
- float WorkMaxX;
- float ItemWidth;
+ float WidthAuto; // Automatic width
+ float StretchWeight; // Master width weight when (Flags & _WidthStretch). Often around ~1.0f initially.
+ float InitStretchWeightOrWidth; // Value passed to TableSetupColumn(). For Width it is a content width (_without padding_).
+ ImRect ClipRect; // Clipping rectangle for the column
+ ImGuiID UserID; // Optional, value passed to TableSetupColumn()
+ float WorkMinX; // Contents region min ~(MinX + CellPaddingX + CellSpacingX1) == cursor start position when entering column
+ float WorkMaxX; // Contents region max ~(MaxX - CellPaddingX - CellSpacingX2)
+ float ItemWidth; // Current item width for the column, preserved across rows
float ContentMaxXFrozen; // Contents maximum position for frozen rows (apart from headers), from which we can infer content width.
float ContentMaxXUnfrozen;
float ContentMaxXHeadersUsed; // Contents maximum position for headers rows (regardless of freezing). TableHeader() automatically softclip itself + report ideal desired size, to avoid creating extraneous draw calls
@@ -2148,9 +2154,12 @@ struct ImGuiTableColumn
bool IsSkipItems; // Do we want item submissions to this column to be completely ignored (no layout will happen).
bool IsPreserveWidthAuto;
ImS8 NavLayerCurrent; // ImGuiNavLayer in 1 byte
- ImS8 SortDirection; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending
ImU8 AutoFitQueue; // Queue of 8 values for the next 8 frames to request auto-fit
ImU8 CannotSkipItemsQueue; // Queue of 8 values for the next 8 frames to disable Clipped/SkipItem
+ ImU8 SortDirection : 2; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending
+ ImU8 SortDirectionsAvailCount : 2; // Number of available sort directions (0 to 3)
+ ImU8 SortDirectionsAvailMask : 4; // Mask of available sort directions (1-bit each)
+ ImU8 SortDirectionsAvailList; // Ordered of available sort directions (2-bits each)
ImGuiTableColumn()
{
@@ -2173,7 +2182,7 @@ struct ImGuiTableCellData
ImGuiTableColumnIdx Column; // Column number
};
-// FIXME-TABLES: transient data could be stored in a per-stacked table structure: DrawSplitter, SortSpecs, incoming RowData
+// FIXME-TABLE: transient data could be stored in a per-stacked table structure: DrawSplitter, SortSpecs, incoming RowData
struct ImGuiTable
{
ImGuiID ID;
@@ -2208,6 +2217,7 @@ struct ImGuiTable
float BorderX1;
float BorderX2;
float HostIndentX;
+ float MinColumnWidth;
float OuterPaddingX;
float CellPaddingX; // Padding from each borders
float CellPaddingY;
@@ -2216,19 +2226,22 @@ struct ImGuiTable
float LastOuterHeight; // Outer height from last frame
float LastFirstRowHeight; // Height of first row from last frame
float InnerWidth; // User value passed to BeginTable(), see comments at the top of BeginTable() for details.
- float ColumnsTotalWidth; // Sum of current column width
+ float ColumnsGivenWidth; // Sum of current column width
float ColumnsAutoFitWidth; // Sum of ideal column width in order nothing to be clipped, used for auto-fitting and content width submission in outer window
float ResizedColumnNextWidth;
+ float ResizeLockMinContentsX2; // Lock minimum contents width while resizing down in order to not create feedback loops. But we allow growing the table.
float RefScale; // Reference scale to be able to rescale columns on font/dpi changes.
- ImRect OuterRect; // Note: OuterRect.Max.y is often FLT_MAX until EndTable(), unless a height has been specified in BeginTable().
+ ImRect OuterRect; // Note: for non-scrolling table, OuterRect.Max.y is often FLT_MAX until EndTable(), unless a height has been specified in BeginTable().
+ ImRect InnerRect; // InnerRect but without decoration. As with OuterRect, for non-scrolling tables, InnerRect.Max.y is
ImRect WorkRect;
ImRect InnerClipRect;
ImRect BgClipRect; // We use this to cpu-clip cell background color fill
- ImRect BgClipRectForDrawCmd;
+ ImRect Bg0ClipRectForDrawCmd; // Actual ImDrawCmd clip rect for BG0/1 channel. This tends to be == OuterWindow->ClipRect at BeginTable() because output in BG0/BG1 is cpu-clipped
+ ImRect Bg2ClipRectForDrawCmd; // Actual ImDrawCmd clip rect for BG2 channel. This tends to be a correct, tight-fit, because output to BG2 are done by widgets relying on regular ClipRect.
ImRect HostClipRect; // This is used to check if we can eventually merge our columns draw calls into the current draw call of the current window.
ImRect HostBackupWorkRect; // Backup of InnerWindow->WorkRect at the end of BeginTable()
ImRect HostBackupParentWorkRect; // Backup of InnerWindow->ParentWorkRect at the end of BeginTable()
- ImRect HostBackupClipRect; // Backup of InnerWindow->ClipRect during PushTableBackground()/PopTableBackground()
+ ImRect HostBackupInnerClipRect; // Backup of InnerWindow->ClipRect during PushTableBackground()/PopTableBackground()
ImVec2 HostBackupPrevLineSize; // Backup of InnerWindow->DC.PrevLineSize at the end of BeginTable()
ImVec2 HostBackupCurrLineSize; // Backup of InnerWindow->DC.CurrLineSize at the end of BeginTable()
ImVec2 HostBackupCursorMaxPos; // Backup of InnerWindow->DC.CursorMaxPos at the end of BeginTable()
@@ -2248,14 +2261,15 @@ struct ImGuiTable
ImGuiTableColumnIdx DeclColumnsCount; // Count calls to TableSetupColumn()
ImGuiTableColumnIdx HoveredColumnBody; // Index of column whose visible region is being hovered. Important: == ColumnsCount when hovering empty region after the right-most column!
ImGuiTableColumnIdx HoveredColumnBorder; // Index of column whose right-border is being hovered (for resizing).
- ImGuiTableColumnIdx AutoFitSingleStretchColumn; // Index of single stretch column requesting auto-fit.
+ ImGuiTableColumnIdx AutoFitSingleColumn; // Index of single column requesting auto-fit.
ImGuiTableColumnIdx ResizedColumn; // Index of column being resized. Reset when InstanceCurrent==0.
ImGuiTableColumnIdx LastResizedColumn; // Index of column being resized from previous frame.
ImGuiTableColumnIdx HeldHeaderColumn; // Index of column header being held.
ImGuiTableColumnIdx ReorderColumn; // Index of column being reordered. (not cleared)
ImGuiTableColumnIdx ReorderColumnDir; // -1 or +1
+ ImGuiTableColumnIdx LeftMostStretchedColumn; // Index of left-most stretched column.
+ ImGuiTableColumnIdx RightMostStretchedColumn; // Index of right-most stretched column.
ImGuiTableColumnIdx RightMostEnabledColumn; // Index of right-most non-hidden column.
- ImGuiTableColumnIdx LeftMostStretchedColumnDisplayOrder; // Display order of left-most stretched column.
ImGuiTableColumnIdx ContextPopupColumn; // Column right-clicked on, of -1 if opening context menu from a neutral/empty spot
ImGuiTableColumnIdx FreezeRowsRequest; // Requested frozen rows count
ImGuiTableColumnIdx FreezeRowsCount; // Actual frozen row count (== FreezeRowsRequest, or == 0 when no scrolling offset)
@@ -2263,8 +2277,8 @@ struct ImGuiTable
ImGuiTableColumnIdx FreezeColumnsCount; // Actual frozen columns count (== FreezeColumnsRequest, or == 0 when no scrolling offset)
ImGuiTableColumnIdx RowCellDataCurrent; // Index of current RowCellData[] entry in current row
ImGuiTableDrawChannelIdx DummyDrawChannel; // Redirect non-visible columns here.
- ImGuiTableDrawChannelIdx Bg1DrawChannelCurrent; // For Selectable() and other widgets drawing accross columns after the freezing line. Index within DrawSplitter.Channels[]
- ImGuiTableDrawChannelIdx Bg1DrawChannelUnfrozen;
+ ImGuiTableDrawChannelIdx Bg2DrawChannelCurrent; // For Selectable() and other widgets drawing accross columns after the freezing line. Index within DrawSplitter.Channels[]
+ ImGuiTableDrawChannelIdx Bg2DrawChannelUnfrozen;
bool IsLayoutLocked; // Set by TableUpdateLayout() which is called when beginning the first row.
bool IsInsideRow; // Set when inside TableBeginRow()/TableEndRow().
bool IsInitializing;
@@ -2276,12 +2290,13 @@ struct ImGuiTable
bool IsDefaultDisplayOrder; // Set when display order is unchanged from default (DisplayOrder contains 0...Count-1)
bool IsResetAllRequest;
bool IsResetDisplayOrderRequest;
- bool IsUnfrozen; // Set when we got past the frozen row.
+ bool IsUnfrozenRows; // Set when we got past the frozen row.
+ bool IsOuterRectAutoFitX; // Set when outer_size.x == 0.0f in BeginTable(), scrolling is disabled, and there are stretch columns.
bool MemoryCompacted;
bool HostSkipItems; // Backup of InnerWindow->SkipItem at the end of BeginTable(), because we will overwrite InnerWindow->SkipItem on a per-column basis
- IMGUI_API ImGuiTable();
- IMGUI_API ~ImGuiTable();
+ IMGUI_API ImGuiTable() { memset(this, 0, sizeof(*this)); LastFrameActive = -1; }
+ IMGUI_API ~ImGuiTable() { IM_FREE(RawData); }
};
// sizeof() ~ 12
@@ -2473,6 +2488,7 @@ namespace ImGui
// Inputs
// FIXME: Eventually we should aim to move e.g. IsActiveIdUsingKey() into IsKeyXXX functions.
+ IMGUI_API void SetItemUsingMouseWheel();
inline bool IsActiveIdUsingNavDir(ImGuiDir dir) { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavDirMask & (1 << dir)) != 0; }
inline bool IsActiveIdUsingNavInput(ImGuiNavInput input) { ImGuiContext& g = *GImGui; return (g.ActiveIdUsingNavInputMask & (1 << input)) != 0; }
inline bool IsActiveIdUsingKey(ImGuiKey key) { ImGuiContext& g = *GImGui; IM_ASSERT(key < 64); return (g.ActiveIdUsingKeyInputMask & ((ImU64)1 << key)) != 0; }
@@ -2550,7 +2566,6 @@ namespace ImGui
// Tables: Candidates for public API
IMGUI_API void TableOpenContextMenu(int column_n = -1);
IMGUI_API void TableSetColumnWidth(int column_n, float width);
- IMGUI_API void TableSetColumnIsEnabled(int column_n, bool enabled);
IMGUI_API void TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs);
IMGUI_API int TableGetHoveredColumn(); // May use (TableGetColumnFlags() & ImGuiTableColumnFlags_IsHovered) instead. Return hovered column. return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered.
IMGUI_API float TableGetHeaderRowHeight();
@@ -2565,12 +2580,15 @@ namespace ImGui
IMGUI_API void TableSetupDrawChannels(ImGuiTable* table);
IMGUI_API void TableUpdateLayout(ImGuiTable* table);
IMGUI_API void TableUpdateBorders(ImGuiTable* table);
+ IMGUI_API void TableUpdateColumnsWeightFromWidth(ImGuiTable* table);
IMGUI_API void TableDrawBorders(ImGuiTable* table);
IMGUI_API void TableDrawContextMenu(ImGuiTable* table);
IMGUI_API void TableMergeDrawChannels(ImGuiTable* table);
IMGUI_API void TableSortSpecsSanitize(ImGuiTable* table);
IMGUI_API void TableSortSpecsBuild(ImGuiTable* table);
- IMGUI_API void TableFixColumnSortDirection(ImGuiTableColumn* column);
+ IMGUI_API ImGuiSortDirection TableGetColumnNextSortDirection(ImGuiTableColumn* column);
+ IMGUI_API void TableFixColumnSortDirection(ImGuiTable* table, ImGuiTableColumn* column);
+ IMGUI_API float TableGetColumnWidthAuto(ImGuiTable* table, ImGuiTableColumn* column);
IMGUI_API void TableBeginRow(ImGuiTable* table);
IMGUI_API void TableEndRow(ImGuiTable* table);
IMGUI_API void TableBeginCell(ImGuiTable* table, int column_n);
@@ -2578,6 +2596,7 @@ namespace ImGui
IMGUI_API ImRect TableGetCellBgRect(const ImGuiTable* table, int column_n);
IMGUI_API const char* TableGetColumnName(const ImGuiTable* table, int column_n);
IMGUI_API ImGuiID TableGetColumnResizeID(const ImGuiTable* table, int column_n, int instance_no = 0);
+ IMGUI_API float TableGetMaxColumnWidth(const ImGuiTable* table, int column_n);
IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n);
IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table);
IMGUI_API void TableRemove(ImGuiTable* table);
@@ -2651,6 +2670,8 @@ namespace ImGui
IMGUI_API ImGuiID GetWindowScrollbarID(ImGuiWindow* window, ImGuiAxis axis);
IMGUI_API ImGuiID GetWindowResizeID(ImGuiWindow* window, int n); // 0..3: corners, 4..7: borders
IMGUI_API void SeparatorEx(ImGuiSeparatorFlags flags);
+ IMGUI_API bool CheckboxFlags(const char* label, ImS64* flags, ImS64 flags_value);
+ IMGUI_API bool CheckboxFlags(const char* label, ImU64* flags, ImU64 flags_value);
// Widgets low-level behaviors
IMGUI_API bool ButtonBehavior(const ImRect& bb, ImGuiID id, bool* out_hovered, bool* out_held, ImGuiButtonFlags flags = 0);
diff --git a/imgui/imgui_tables.cpp b/imgui/imgui_tables.cpp
index 24653cd8..a574e8c7 100644
--- a/imgui/imgui_tables.cpp
+++ b/imgui/imgui_tables.cpp
@@ -5,7 +5,12 @@
Index of this file:
+// [SECTION] Commentary
+// [SECTION] Header mess
// [SECTION] Tables: Main code
+// [SECTION] Tables: Row changes
+// [SECTION] Tables: Columns changes
+// [SECTION] Tables: Columns width management
// [SECTION] Tables: Drawing
// [SECTION] Tables: Sorting
// [SECTION] Tables: Headers
@@ -17,17 +22,29 @@ Index of this file:
*/
+// Navigating this file:
+// - In Visual Studio IDE: CTRL+comma ("Edit.NavigateTo") can follow symbols in comments, whereas CTRL+F12 ("Edit.GoToImplementation") cannot.
+// - With Visual Assist installed: ALT+G ("VAssistX.GoToImplementation") can also follow symbols in comments.
+
+//-----------------------------------------------------------------------------
+// [SECTION] Commentary
+//-----------------------------------------------------------------------------
+
//-----------------------------------------------------------------------------
// Typical tables call flow: (root level is generally public API):
//-----------------------------------------------------------------------------
// - BeginTable() user begin into a table
// | BeginChild() - (if ScrollX/ScrollY is set)
+// | TableBeginInitMemory() - first time table is used
+// | TableResetSettings() - on settings reset
+// | TableLoadSettings() - on settings load
// | TableBeginApplyRequests() - apply queued resizing/reordering/hiding requests
// | - TableSetColumnWidth() - apply resizing width (for mouse resize, often requested by previous frame)
// | - TableUpdateColumnsWeightFromWidth()- recompute columns weights (of stretch columns) from their respective width
// - TableSetupColumn() user submit columns details (optional)
// - TableSetupScrollFreeze() user submit scroll freeze information (optional)
-// - TableUpdateLayout() [Internal] automatically called by the FIRST call to TableNextRow() or TableHeadersRow(): lock all widths, columns positions, clipping rectangles
+//-----------------------------------------------------------------------------
+// - TableUpdateLayout() [Internal] followup to BeginTable(): setup everything: widths, columns positions, clipping rectangles. Automatically called by the FIRST call to TableNextRow() or TableHeadersRow().
// | TableSetupDrawChannels() - setup ImDrawList channels
// | TableUpdateBorders() - detect hovering columns for resize, ahead of contents submission
// | TableDrawContextMenu() - draw right-click context menu
@@ -54,26 +71,31 @@ Index of this file:
// TABLE SIZING
//-----------------------------------------------------------------------------
// (Read carefully because this is subtle but it does make sense!)
-// About 'outer_size', its meaning needs to differ slightly depending of if we are using ScrollX/ScrollY flags:
-// X:
-// - outer_size.x < 0.0f -> right align from window/work-rect maximum x edge.
-// - outer_size.x = 0.0f -> auto enlarge, use all available space.
-// - outer_size.x > 0.0f -> fixed width
-// Y with ScrollX/ScrollY: using a child window for scrolling:
-// - outer_size.y < 0.0f -> bottom align
-// - outer_size.y = 0.0f -> bottom align, consistent with BeginChild(). not recommended unless table is last item in parent window.
-// - outer_size.y > 0.0f -> fixed child height. recommended when using Scrolling on any axis.
-// Y without scrolling, we output table directly in parent window:
-// - outer_size.y < 0.0f -> bottom align (will auto extend, unless NoHostExtendV is set)
-// - outer_size.y = 0.0f -> zero minimum height (will auto extend, unless NoHostExtendV is set)
-// - outer_size.y > 0.0f -> minimum height (will auto extend, unless NoHostExtendV is set)
+//-----------------------------------------------------------------------------
+// About 'outer_size':
+// Its meaning needs to differ slightly depending of if we are using ScrollX/ScrollY flags.
+// Default value is ImVec2(-FLT_MIN, 0.0f). When binding this in a scripting language please follow this default value.
+// X
+// - outer_size.x < 0.0f -> Right-align from window/work-rect right-most edge. With -FLT_MIN will right-align exactly on right-most edge. With -1.0f will right-align one pixel away from right-most edge.
+// - outer_size.x = 0.0f -> Auto width. Generally use all available width. When NOT using scrolling and NOT using any Stretch column, use only necessary width, otherwise same as -FLT_MIN.
+// - outer_size.x > 0.0f -> Fixed width.
+// Y with ScrollX/ScrollY disabled: we output table directly in current window
+// - outer_size.y < 0.0f -> Bottom-align (but will auto extend, unless NoHostExtendV is set)
+// - outer_size.y = 0.0f -> No minimum height (but will auto extend, unless NoHostExtendV is set)
+// - outer_size.y > 0.0f -> Set Minimum height (but will auto extend, unless NoHostExtendV is set)
+// Y with ScrollX/ScrollY enabled: using a child window for scrolling
+// - outer_size.y < 0.0f -> Bottom-align
+// - outer_size.y = 0.0f -> Bottom-align, consistent with BeginChild(). Not recommended unless table is last item in parent window.
+// - outer_size.y > 0.0f -> Set Exact height. Recommended when using Scrolling on any axis.
+//-----------------------------------------------------------------------------
// About 'inner_width':
-// With ScrollX:
+// With ScrollX disabled:
+// - inner_width -> *ignored*
+// With ScrollX enable:
// - inner_width < 0.0f -> *illegal* fit in known width (right align from outer_size.x) <-- weird
// - inner_width = 0.0f -> fit in outer_width: Fixed size columns will take space they need (if avail, otherwise shrink down), Stretch columns becomes Fixed columns.
// - inner_width > 0.0f -> override scrolling width, generally to be larger than outer_size.x. Fixed column take space they need (if avail, otherwise shrink down), Stretch columns share remaining space!
-// Without ScrollX:
-// - inner_width -> *ignored*
+//-----------------------------------------------------------------------------
// Details:
// - If you want to use Stretch columns with ScrollX, you generally need to specify 'inner_width' otherwise the concept
// of "available space" doesn't make sense.
@@ -82,12 +104,43 @@ Index of this file:
//-----------------------------------------------------------------------------
//-----------------------------------------------------------------------------
-// TABLES CULLING
+// COLUMNS SIZING POLICIES
+//-----------------------------------------------------------------------------
+// About overriding column sizing policy and width/weight with TableSetupColumn():
+// We use a default parameter of 'init_width_or_weight == -1'.
+// - with ImGuiTableColumnFlags_WidthAuto, init_width (ignored) --> width is automatic
+// - with ImGuiTableColumnFlags_WidthFixed, init_width <= 0 (default) --> width is automatic
+// - with ImGuiTableColumnFlags_WidthFixed, init_width > 0 (explicit) --> width is custom
+// - with ImGuiTableColumnFlags_WidthStretch, init_weight <= 0 (default) --> weight is 1.0f
+// - with ImGuiTableColumnFlags_WidthStretch, init_weight > 0 (explicit) --> weight is custom
+// Widths are specified _without_ CellPadding. If you specify a width of 100.0f, the column will be cover (100.0f + Padding * 2.0f)
+// and you can fit a 100.0f wide item in it without clipping and with full padding.
+//-----------------------------------------------------------------------------
+// About default sizing policy (if you don't specify a ImGuiTableColumnFlags_WidthXXXX flag)
+// - with Table policy ImGuiTableFlags_SizingFixedFit && (Resizable == 1 || init_width > 0) --> default Column policy is ImGuiTableColumnFlags_WidthFixed, default Width is equal to contents width
+// - with Table policy ImGuiTableFlags_SizingFixedFit && (Resizable == 0 && init_width <= 0) --> default Column policy is ImGuiTableColumnFlags_WidthAuto, Width always equal to contents width
+// - with Table policy ImGuiTableFlags_SizingFixedSame --> default Column policy is ImGuiTableColumnFlags_WidthAuto, default Width is max of all contents width
+// - with Table policy ImGuiTableFlags_SizingStretchSame --> default Column policy is ImGuiTableColumnFlags_WidthStretch, default Weight is 1.0f
+// - with Table policy ImGuiTableFlags_SizingStretchWeight --> default Column policy is ImGuiTableColumnFlags_WidthStretch, default Weight is proportional to contents
+//-----------------------------------------------------------------------------
+// About mixing Fixed/Auto and Stretch columns together:
+// - the typical use of mixing sizing policies is: any number of LEADING Fixed columns, followed by one or two TRAILING Stretch columns.
+// - using mixed policies with ScrollX does not make much sense, as using Stretch columns with ScrollX does not make much sense in the first place!
+// that is, unless 'inner_width' is passed to BeginTable() to explicitely provide a total width to layout columns in.
+// - when using ImGuiTableFlags_SizingFixedSame with mixed columns, only the Fixed/Auto columns will match their widths to the maximum contents width.
+// - when using ImGuiTableFlags_SizingStretchSame with mixed columns, only the Stretch columns will match their weight/widths.
+//-----------------------------------------------------------------------------
+
+//-----------------------------------------------------------------------------
+// TABLES CLIPPING/CULLING
//-----------------------------------------------------------------------------
// About clipping/culling of Rows in Tables:
// - For large numbers of rows, it is recommended you use ImGuiListClipper to only submit visible rows.
// ImGuiListClipper is reliant on the fact that rows are of equal height.
// See 'Demo->Tables->Vertical Scrolling' or 'Demo->Tables->Advanced' for a demo of using the clipper.
+// - Note that columns with the ImGuiTableColumnFlags_WidthAuto policy generally don't play well with using the clipper,
+// and by default a table with _ScrollX but without _Resizable will have columns default to _WidthAuto.
+// So, if you want to use the clipper, make sure to either enable _Resizable, either setup columns explicitly with _WidthFixed.
//-----------------------------------------------------------------------------
// About clipping/culling of Columns in Tables:
// - Case A: column is not hidden by user, and at least partially in sight (most common case).
@@ -107,6 +160,10 @@ Index of this file:
// - Scrolling tables with a known outer size can be clipped earlier as BeginTable() will return false.
//-----------------------------------------------------------------------------
+//-----------------------------------------------------------------------------
+// [SECTION] Header mess
+//-----------------------------------------------------------------------------
+
#if defined(_MSC_VER) && !defined(_CRT_SECURE_NO_WARNINGS)
#define _CRT_SECURE_NO_WARNINGS
#endif
@@ -126,10 +183,6 @@ Index of this file:
#include <stdint.h> // intptr_t
#endif
-//-------------------------------------------------------------------------
-// Warnings
-//-------------------------------------------------------------------------
-
// Visual Studio warnings
#ifdef _MSC_VER
#pragma warning (disable: 4127) // condition expression is constant
@@ -166,8 +219,8 @@ Index of this file:
// Configuration
static const int TABLE_DRAW_CHANNEL_BG0 = 0;
-static const int TABLE_DRAW_CHANNEL_BG1_FROZEN = 1;
-static const int TABLE_DRAW_CHANNEL_UNCLIPPED = 2; // When using ImGuiTableFlags_NoClip
+static const int TABLE_DRAW_CHANNEL_BG2_FROZEN = 1;
+static const int TABLE_DRAW_CHANNEL_NOCLIP = 2; // When using ImGuiTableFlags_NoClip (this becomes the last visible channel)
static const float TABLE_BORDER_SIZE = 1.0f; // FIXME-TABLE: Currently hard-coded because of clipping assumptions with outer borders rendering.
static const float TABLE_RESIZE_SEPARATOR_HALF_THICKNESS = 4.0f; // Extend outside inner borders.
static const float TABLE_RESIZE_SEPARATOR_FEEDBACK_TIMER = 0.06f; // Delay/timer before making the hover feedback (color+cursor) visible because tables/columns tends to be more cramped.
@@ -176,16 +229,12 @@ static const float TABLE_RESIZE_SEPARATOR_FEEDBACK_TIMER = 0.06f; // Delay/tim
inline ImGuiTableFlags TableFixFlags(ImGuiTableFlags flags, ImGuiWindow* outer_window)
{
// Adjust flags: set default sizing policy
- if ((flags & (ImGuiTableFlags_ColumnsWidthStretch | ImGuiTableFlags_ColumnsWidthFixed)) == 0)
- flags |= (flags & ImGuiTableFlags_ScrollX) ? ImGuiTableFlags_ColumnsWidthFixed : ImGuiTableFlags_ColumnsWidthStretch;
-
- // Adjust flags: MultiSortable automatically enable Sortable
- if (flags & ImGuiTableFlags_MultiSortable)
- flags |= ImGuiTableFlags_Sortable;
+ if ((flags & ImGuiTableFlags_SizingMask_) == 0)
+ flags |= ((flags & ImGuiTableFlags_ScrollX) || (outer_window->Flags & ImGuiWindowFlags_AlwaysAutoResize)) ? ImGuiTableFlags_SizingFixedFit : ImGuiTableFlags_SizingStretchSame;
- // Adjust flags: disable Resizable when using SameWidths (done above enforcing BordersInnerV)
- if (flags & ImGuiTableFlags_SameWidths)
- flags = (flags & ~ImGuiTableFlags_Resizable) | ImGuiTableFlags_NoKeepColumnsVisible;
+ // Adjust flags: enable NoKeepColumnsVisible when using ImGuiTableFlags_SizingFixedSame
+ if ((flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedSame)
+ flags |= ImGuiTableFlags_NoKeepColumnsVisible;
// Adjust flags: enforce borders when resizable
if (flags & ImGuiTableFlags_Resizable)
@@ -215,25 +264,6 @@ inline ImGuiTableFlags TableFixFlags(ImGuiTableFlags flags, ImGuiWindow* outer_w
return flags;
}
-ImGuiTable::ImGuiTable()
-{
- memset(this, 0, sizeof(*this));
- SettingsOffset = -1;
- InstanceInteracted = -1;
- LastFrameActive = -1;
- LastResizedColumn = -1;
- ContextPopupColumn = -1;
- ReorderColumn = -1;
- ResizedColumn = -1;
- AutoFitSingleStretchColumn = -1;
- HoveredColumnBody = HoveredColumnBorder = -1;
-}
-
-ImGuiTable::~ImGuiTable()
-{
- IM_FREE(RawData);
-}
-
ImGuiTable* ImGui::TableFindByID(ImGuiID id)
{
ImGuiContext& g = *GImGui;
@@ -290,8 +320,7 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
table->ColumnsCount = columns_count;
table->IsLayoutLocked = false;
table->InnerWidth = inner_width;
- table->OuterRect = outer_rect;
- table->WorkRect = outer_rect;
+ table->IsOuterRectAutoFitX = (outer_size.x == 0.0f) && (use_child_window == false);
// When not using a child window, WorkRect.Max will grow as we append contents.
if (use_child_window)
@@ -314,12 +343,19 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
// Create scrolling region (without border and zero window padding)
ImGuiWindowFlags child_flags = (flags & ImGuiTableFlags_ScrollX) ? ImGuiWindowFlags_HorizontalScrollbar : ImGuiWindowFlags_None;
- BeginChildEx(name, instance_id, table->OuterRect.GetSize(), false, child_flags);
+ BeginChildEx(name, instance_id, outer_rect.GetSize(), false, child_flags);
table->InnerWindow = g.CurrentWindow;
table->WorkRect = table->InnerWindow->WorkRect;
table->OuterRect = table->InnerWindow->Rect();
+ table->InnerRect = table->InnerWindow->InnerRect;
IM_ASSERT(table->InnerWindow->WindowPadding.x == 0.0f && table->InnerWindow->WindowPadding.y == 0.0f && table->InnerWindow->WindowBorderSize == 0.0f);
}
+ else
+ {
+ // For non-scrolling tables, WorkRect == OuterRect == InnerRect.
+ // But at this point we do NOT have a correct value for .Max.y (unless a height has been explicitly passed in). It will only be updated in EndTable().
+ table->WorkRect = table->OuterRect = table->InnerRect = outer_rect;
+ }
// Push a standardized ID for both child-using and not-child-using tables
PushOverrideID(instance_id);
@@ -337,7 +373,6 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
table->HostBackupCursorMaxPos = inner_window->DC.CursorMaxPos;
table->HostBackupItemWidth = outer_window->DC.ItemWidth;
table->HostBackupItemWidthStackSize = outer_window->DC.ItemWidthStack.Size;
- inner_window->ParentWorkRect = table->WorkRect;
inner_window->DC.PrevLineSize = inner_window->DC.CurrLineSize = ImVec2(0.0f, 0.0f);
// Padding and Spacing
@@ -350,9 +385,8 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
const float inner_spacing_for_border = (flags & ImGuiTableFlags_BordersInnerV) ? TABLE_BORDER_SIZE : 0.0f;
const float inner_spacing_explicit = (pad_inner_x && (flags & ImGuiTableFlags_BordersInnerV) == 0) ? g.Style.CellPadding.x : 0.0f;
const float inner_padding_explicit = (pad_inner_x && (flags & ImGuiTableFlags_BordersInnerV) != 0) ? g.Style.CellPadding.x : 0.0f;
- const float inner_spacing = inner_spacing_for_border + inner_spacing_explicit;
- table->CellSpacingX1 = ImCeil(inner_spacing * 0.5f);
- table->CellSpacingX2 = inner_spacing - table->CellSpacingX1;
+ table->CellSpacingX1 = inner_spacing_explicit + inner_spacing_for_border;
+ table->CellSpacingX2 = inner_spacing_explicit;
table->CellPaddingX = inner_padding_explicit;
table->CellPaddingY = g.Style.CellPadding.y;
@@ -369,26 +403,16 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
table->InnerClipRect.ClipWithFull(table->HostClipRect);
table->InnerClipRect.Max.y = (flags & ImGuiTableFlags_NoHostExtendY) ? ImMin(table->InnerClipRect.Max.y, inner_window->WorkRect.Max.y) : inner_window->ClipRect.Max.y;
- // Initial draw cmd starts with a BgClipRect that matches the one of its host, to facilitate merge draw commands by default.
- // This is because all our cell highlight are manually clipped with BgClipRect
- // Larger at first, if/after unfreezing will become same as tight
- table->BgClipRect = table->InnerClipRect;
- table->BgClipRectForDrawCmd = table->HostClipRect;
- IM_ASSERT(table->BgClipRect.Min.y <= table->BgClipRect.Max.y);
-
table->RowPosY1 = table->RowPosY2 = table->WorkRect.Min.y; // This is needed somehow
table->RowTextBaseline = 0.0f; // This will be cleared again by TableBeginRow()
table->FreezeRowsRequest = table->FreezeRowsCount = 0; // This will be setup by TableSetupScrollFreeze(), if any
table->FreezeColumnsRequest = table->FreezeColumnsCount = 0;
- table->IsUnfrozen = true;
+ table->IsUnfrozenRows = true;
table->DeclColumnsCount = 0;
- table->RightMostEnabledColumn = -1;
// Using opaque colors facilitate overlapping elements of the grid
table->BorderColorStrong = GetColorU32(ImGuiCol_TableBorderStrong);
table->BorderColorLight = GetColorU32(ImGuiCol_TableBorderLight);
- table->BorderX1 = table->InnerClipRect.Min.x;// +((table->Flags & ImGuiTableFlags_BordersOuter) ? 0.0f : -1.0f);
- table->BorderX2 = table->InnerClipRect.Max.x;// +((table->Flags & ImGuiTableFlags_BordersOuter) ? 0.0f : +1.0f);
// Make table current
const int table_idx = g.Tables.GetIndex(table);
@@ -423,9 +447,14 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
TableResetSettings(table);
if (table->IsInitializing)
{
- // Initialize for new settings
+ // Initialize
table->SettingsOffset = -1;
table->IsSortSpecsDirty = true;
+ table->InstanceInteracted = -1;
+ table->ContextPopupColumn = -1;
+ table->ReorderColumn = table->ResizedColumn = table->LastResizedColumn = -1;
+ table->AutoFitSingleColumn = -1;
+ table->HoveredColumnBody = table->HoveredColumnBorder = -1;
for (int n = 0; n < columns_count; n++)
{
ImGuiTableColumn* column = &table->Columns[n];
@@ -463,16 +492,9 @@ bool ImGui::BeginTableEx(const char* name, ImGuiID id, int columns_count, ImG
inner_window->SkipItems = true;
// Clear names
- // FIXME-TABLES: probably could be done differently...
+ // At this point the ->NameOffset field of each column will be invalid until TableUpdateLayout() or the first call to TableSetupColumn()
if (table->ColumnsNames.Buf.Size > 0)
- {
table->ColumnsNames.Buf.resize(0);
- for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
- {
- ImGuiTableColumn* column = &table->Columns[column_n];
- column->NameOffset = -1;
- }
- }
// Apply queued resizing/reordering/hiding requests
TableBeginApplyRequests(table);
@@ -508,8 +530,7 @@ void ImGui::TableBeginApplyRequests(ImGuiTable* table)
{
// Handle resizing request
// (We process this at the first TableBegin of the frame)
- // FIXME-TABLE: Preserve contents width _while resizing down_ until releasing.
- // FIXME-TABLE: Contains columns if our work area doesn't allow for scrolling.
+ // FIXME-TABLE: Contains columns if our work area doesn't allow for scrolling?
if (table->InstanceCurrent == 0)
{
if (table->ResizedColumn != -1 && table->ResizedColumnNextWidth != FLT_MAX)
@@ -518,12 +539,12 @@ void ImGui::TableBeginApplyRequests(ImGuiTable* table)
table->ResizedColumnNextWidth = FLT_MAX;
table->ResizedColumn = -1;
- // Process auto-fit for single stretch column, which is a special case
+ // Process auto-fit for single column, which is a special case for stretch columns and fixed columns with FixedSame policy.
// FIXME-TABLE: Would be nice to redistribute available stretch space accordingly to other weights, instead of giving it all to siblings.
- if (table->AutoFitSingleStretchColumn != -1)
+ if (table->AutoFitSingleColumn != -1)
{
- TableSetColumnWidth(table->AutoFitSingleStretchColumn, table->Columns[table->AutoFitSingleStretchColumn].WidthAuto);
- table->AutoFitSingleStretchColumn = -1;
+ TableSetColumnWidth(table->AutoFitSingleColumn, table->Columns[table->AutoFitSingleColumn].WidthAuto);
+ table->AutoFitSingleColumn = -1;
}
}
@@ -573,65 +594,106 @@ void ImGui::TableBeginApplyRequests(ImGuiTable* table)
}
// Adjust flags: default width mode + stretch columns are not allowed when auto extending
-static ImGuiTableColumnFlags TableFixColumnFlags(ImGuiTable* table, ImGuiTableColumnFlags flags)
+static void TableSetupColumnFlags(ImGuiTable* table, ImGuiTableColumn* column, ImGuiTableColumnFlags flags_in)
{
+ ImGuiTableColumnFlags flags = flags_in;
+
// Sizing Policy
if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0)
{
- // FIXME-TABLE: Inconsistent to promote columns to WidthAutoResize
- if (table->Flags & ImGuiTableFlags_ColumnsWidthFixed)
- flags |= ((table->Flags & ImGuiTableFlags_Resizable) && !(flags & ImGuiTableColumnFlags_NoResize)) ? ImGuiTableColumnFlags_WidthFixed : ImGuiTableColumnFlags_WidthAutoResize;
+ // FIXME-TABLE: clarify promotion to WidthAuto?
+ const ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_);
+ if (table_sizing_policy == ImGuiTableFlags_SizingFixedFit || table_sizing_policy == ImGuiTableFlags_SizingFixedSame)
+ flags |= ((table->Flags & ImGuiTableFlags_Resizable) && !(flags & ImGuiTableColumnFlags_NoResize)) ? ImGuiTableColumnFlags_WidthFixed : ImGuiTableColumnFlags_WidthAuto;
else
flags |= ImGuiTableColumnFlags_WidthStretch;
}
- IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiTableColumnFlags_WidthMask_)); // Check that only 1 of each set is used.
- if (flags & ImGuiTableColumnFlags_WidthAutoResize)
+ else
+ {
+ IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiTableColumnFlags_WidthMask_)); // Check that only 1 of each set is used.
+ }
+
+ // Resize
+ if ((flags & ImGuiTableColumnFlags_WidthAuto) != 0 || (table->Flags & ImGuiTableFlags_Resizable) == 0)
flags |= ImGuiTableColumnFlags_NoResize;
// Sorting
if ((flags & ImGuiTableColumnFlags_NoSortAscending) && (flags & ImGuiTableColumnFlags_NoSortDescending))
flags |= ImGuiTableColumnFlags_NoSort;
+ // Indentation
+ if ((flags & ImGuiTableColumnFlags_IndentMask_) == 0)
+ flags |= (table->Columns.index_from_ptr(column) == 0) ? ImGuiTableColumnFlags_IndentEnable : ImGuiTableColumnFlags_IndentDisable;
+
// Alignment
//if ((flags & ImGuiTableColumnFlags_AlignMask_) == 0)
// flags |= ImGuiTableColumnFlags_AlignCenter;
//IM_ASSERT(ImIsPowerOfTwo(flags & ImGuiTableColumnFlags_AlignMask_)); // Check that only 1 of each set is used.
- return flags;
-}
+ // Preserve status flags
+ column->Flags = flags | (column->Flags & ImGuiTableColumnFlags_StatusMask_);
-// Minimum column content width (without padding)
-static float TableGetMinColumnWidth()
-{
- ImGuiContext& g = *GImGui;
- //return g.Style.ColumnsMinSpacing; // FIXME-TABLE
- return g.Style.FramePadding.x * 1.0f;
+ // Build an ordered list of available sort directions
+ column->SortDirectionsAvailCount = column->SortDirectionsAvailMask = column->SortDirectionsAvailList = 0;
+ if (table->Flags & ImGuiTableFlags_Sortable)
+ {
+ int count = 0, mask = 0, list = 0;
+ if ((flags & ImGuiTableColumnFlags_PreferSortAscending) != 0 && (flags & ImGuiTableColumnFlags_NoSortAscending) == 0) { mask |= 1 << ImGuiSortDirection_Ascending; list |= ImGuiSortDirection_Ascending << (count << 1); count++; }
+ if ((flags & ImGuiTableColumnFlags_PreferSortDescending) != 0 && (flags & ImGuiTableColumnFlags_NoSortDescending) == 0) { mask |= 1 << ImGuiSortDirection_Descending; list |= ImGuiSortDirection_Descending << (count << 1); count++; }
+ if ((flags & ImGuiTableColumnFlags_PreferSortAscending) == 0 && (flags & ImGuiTableColumnFlags_NoSortAscending) == 0) { mask |= 1 << ImGuiSortDirection_Ascending; list |= ImGuiSortDirection_Ascending << (count << 1); count++; }
+ if ((flags & ImGuiTableColumnFlags_PreferSortDescending) == 0 && (flags & ImGuiTableColumnFlags_NoSortDescending) == 0) { mask |= 1 << ImGuiSortDirection_Descending; list |= ImGuiSortDirection_Descending << (count << 1); count++; }
+ if ((table->Flags & ImGuiTableFlags_SortTristate) || count == 0) { mask |= 1 << ImGuiSortDirection_None; count++; }
+ column->SortDirectionsAvailList = (ImU8)list;
+ column->SortDirectionsAvailMask = (ImU8)mask;
+ column->SortDirectionsAvailCount = (ImU8)count;
+ ImGui::TableFixColumnSortDirection(table, column);
+ }
}
// Layout columns for the frame. This is in essence the followup to BeginTable().
// Runs on the first call to TableNextRow(), to give a chance for TableSetupColumn() to be called first.
-// FIXME-TABLE: Our width (and therefore our WorkRect) will be minimal in the first frame for WidthAutoResize
-// columns, increase feedback side-effect with widgets relying on WorkRect.Max.x. Maybe provide a default distribution
-// for WidthAutoResize columns?
+// FIXME-TABLE: Our width (and therefore our WorkRect) will be minimal in the first frame for _WidthAuto columns.
+// Increase feedback side-effect with widgets relying on WorkRect.Max.x... Maybe provide a default distribution for _WidthAuto columns?
void ImGui::TableUpdateLayout(ImGuiTable* table)
{
ImGuiContext& g = *GImGui;
IM_ASSERT(table->IsLayoutLocked == false);
- // [Part 1] Apply/lock Enabled and Order states.
- // Process columns in their visible orders as we are building the Prev/Next indices.
- int last_visible_column_idx = -1;
- bool want_column_auto_fit = false;
+ const ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_);
table->IsDefaultDisplayOrder = true;
table->ColumnsEnabledCount = 0;
table->EnabledMaskByIndex = 0x00;
table->EnabledMaskByDisplayOrder = 0x00;
+ table->MinColumnWidth = ImMax(1.0f, g.Style.FramePadding.x * 1.0f); // g.Style.ColumnsMinSpacing; // FIXME-TABLE
+
+ // [Part 1] Apply/lock Enabled and Order states. Calculate auto/ideal width for columns. Count fixed/stretch columns.
+ // Process columns in their visible orders as we are building the Prev/Next indices.
+ int count_fixed = 0; // Number of columns that have fixed sizing policies
+ int count_stretch = 0; // Number of columns that have stretch sizing policies
+ int last_visible_column_idx = -1;
+ bool has_auto_fit_request = false;
+ bool has_resizable = false;
+ float stretch_sum_width_auto = 0.0f;
+ float fixed_max_width_auto = 0.0f;
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
{
const int column_n = table->DisplayOrderToIndex[order_n];
if (column_n != order_n)
table->IsDefaultDisplayOrder = false;
ImGuiTableColumn* column = &table->Columns[column_n];
+
+ // Clear column setup if not submitted by user. Currently we make it mandatory to call TableSetupColumn() every frame.
+ // It would easily work without but we're not ready to guarantee it since e.g. names need resubmission anyway.
+ // We take a slight shortcut but in theory we could be calling TableSetupColumn() here with dummy values, it should yield the same effect.
+ if (table->DeclColumnsCount <= column_n)
+ {
+ TableSetupColumnFlags(table, column, ImGuiTableColumnFlags_None);
+ column->NameOffset = -1;
+ column->UserID = 0;
+ column->InitStretchWeightOrWidth = -1.0f;
+ }
+
+ // Update Enabled state, mark settings/sortspecs dirty
if (!(table->Flags & ImGuiTableFlags_Hideable) || (column->Flags & ImGuiTableColumnFlags_NoHide))
column->IsEnabledNextFrame = true;
if (column->IsEnabled != column->IsEnabledNextFrame)
@@ -641,203 +703,161 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
if (!column->IsEnabled && column->SortOrder != -1)
table->IsSortSpecsDirty = true;
}
- if (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_MultiSortable))
+ if (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_SortMulti))
table->IsSortSpecsDirty = true;
- bool start_auto_fit = false;
- if (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAutoResize))
- start_auto_fit = column->WidthRequest < 0.0f;
- else
- start_auto_fit = column->StretchWeight < 0.0f;
+ // Auto-fit unsized columns
+ const bool start_auto_fit = (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAuto)) ? (column->WidthRequest < 0.0f) : (column->StretchWeight < 0.0f);
if (start_auto_fit)
column->AutoFitQueue = column->CannotSkipItemsQueue = (1 << 3) - 1; // Fit for three frames
- if (column->AutoFitQueue != 0x00)
- want_column_auto_fit = true;
+ if (!column->IsEnabled)
+ {
+ column->IndexWithinEnabledSet = -1;
+ continue;
+ }
+
+ // Mark as enabled and link to previous/next enabled column
+ column->PrevEnabledColumn = (ImGuiTableColumnIdx)last_visible_column_idx;
+ column->NextEnabledColumn = -1;
+ if (last_visible_column_idx != -1)
+ table->Columns[last_visible_column_idx].NextEnabledColumn = (ImGuiTableColumnIdx)column_n;
+ column->IndexWithinEnabledSet = table->ColumnsEnabledCount++;
+ table->EnabledMaskByIndex |= (ImU64)1 << column_n;
+ table->EnabledMaskByDisplayOrder |= (ImU64)1 << column->DisplayOrder;
+ last_visible_column_idx = column_n;
+ IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder);
+
+ // Calculate ideal/auto column width (that's the width required for all contents to be visible without clipping)
+ // Combine width from regular rows + width from headers unless requested not to.
+ if (!column->IsPreserveWidthAuto)
+ column->WidthAuto = TableGetColumnWidthAuto(table, column);
+
+ // Non-resizable columns keep their requested width (apply user value regardless of IsPreserveWidthAuto)
+ const bool column_is_resizable = (column->Flags & ImGuiTableColumnFlags_NoResize) == 0;
+ if (column_is_resizable)
+ has_resizable = true;
+ if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && column->InitStretchWeightOrWidth > 0.0f && !column_is_resizable)
+ column->WidthAuto = column->InitStretchWeightOrWidth;
- ImU64 index_mask = (ImU64)1 << column_n;
- ImU64 display_order_mask = (ImU64)1 << column->DisplayOrder;
- if (column->IsEnabled)
+ if (column->AutoFitQueue != 0x00)
+ has_auto_fit_request = true;
+ if (column->Flags & ImGuiTableColumnFlags_WidthStretch)
{
- column->PrevEnabledColumn = (ImGuiTableColumnIdx)last_visible_column_idx;
- column->NextEnabledColumn = -1;
- if (last_visible_column_idx != -1)
- table->Columns[last_visible_column_idx].NextEnabledColumn = (ImGuiTableColumnIdx)column_n;
- column->IndexWithinEnabledSet = table->ColumnsEnabledCount;
- table->ColumnsEnabledCount++;
- table->EnabledMaskByIndex |= index_mask;
- table->EnabledMaskByDisplayOrder |= display_order_mask;
- last_visible_column_idx = column_n;
+ stretch_sum_width_auto += column->WidthAuto;
+ count_stretch++;
}
else
{
- column->IndexWithinEnabledSet = -1;
+ fixed_max_width_auto = ImMax(fixed_max_width_auto, column->WidthAuto);
+ count_fixed++;
}
- IM_ASSERT(column->IndexWithinEnabledSet <= column->DisplayOrder);
}
+ if ((table->Flags & ImGuiTableFlags_Sortable) && table->SortSpecsCount == 0 && !(table->Flags & ImGuiTableFlags_SortTristate))
+ table->IsSortSpecsDirty = true;
table->RightMostEnabledColumn = (ImGuiTableColumnIdx)last_visible_column_idx;
+ IM_ASSERT(table->RightMostEnabledColumn >= 0);
// [Part 2] Disable child window clipping while fitting columns. This is not strictly necessary but makes it possible
- // to avoid the column fitting to wait until the first visible frame of the child container (may or not be a good thing).
+ // to avoid the column fitting having to wait until the first visible frame of the child container (may or not be a good thing).
// FIXME-TABLE: for always auto-resizing columns may not want to do that all the time.
- if (want_column_auto_fit && table->OuterWindow != table->InnerWindow)
+ if (has_auto_fit_request && table->OuterWindow != table->InnerWindow)
table->InnerWindow->SkipItems = false;
- if (want_column_auto_fit)
+ if (has_auto_fit_request)
table->IsSettingsDirty = true;
- // [Part 3] Fix column flags. Calculate ideal width for columns. Count how many fixed/stretch columns we have and sum of weights.
- const float min_column_width = TableGetMinColumnWidth();
- const float min_column_distance = min_column_width + table->CellPaddingX * 2.0f + table->CellSpacingX1 + table->CellSpacingX2;
- int count_fixed = 0; // Number of columns that have fixed sizing policy (not stretched sizing policy) (this is NOT the opposite of count_resizable!)
- int count_resizable = 0; // Number of columns the user can resize (this is NOT the opposite of count_fixed!)
- float sum_weights_stretched = 0.0f; // Sum of all weights for weighted columns.
- float sum_width_fixed_requests = 0.0f; // Sum of all width for fixed and auto-resize columns, excluding width contributed by Stretch columns.
- float max_width_auto = 0.0f; // Largest auto-width (used for SameWidths feature)
- table->LeftMostStretchedColumnDisplayOrder = -1;
+ // [Part 3] Fix column flags and record a few extra information.
+ float sum_width_requests = 0.0f; // Sum of all width for fixed and auto-resize columns, excluding width contributed by Stretch columns but including spacing/padding.
+ float stretch_sum_weights = 0.0f; // Sum of all weights for stretch columns.
+ table->LeftMostStretchedColumn = table->RightMostStretchedColumn = -1;
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{
if (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n)))
continue;
ImGuiTableColumn* column = &table->Columns[column_n];
- // Adjust flags: default width mode + weighted columns are not allowed when auto extending
- // FIXME-TABLE: Clarify why we need to do this again here and not just in TableSetupColumn()
- column->Flags = TableFixColumnFlags(table, column->FlagsIn) | (column->Flags & ImGuiTableColumnFlags_StatusMask_);
- if ((column->Flags & ImGuiTableColumnFlags_IndentMask_) == 0)
- column->Flags |= (column_n == 0) ? ImGuiTableColumnFlags_IndentEnable : ImGuiTableColumnFlags_IndentDisable;
- if ((column->Flags & ImGuiTableColumnFlags_NoResize) == 0)
- count_resizable++;
-
- // We have a unusual edge case where if the user doesn't call TableGetSortSpecs() but has sorting enabled
- // or varying sorting flags, we still want the sorting arrows to honor those flags.
- if (table->Flags & ImGuiTableFlags_Sortable)
- TableFixColumnSortDirection(column);
-
- // Calculate ideal/auto column width (that's the width required for all contents to be visible without clipping)
- // Combine width from regular rows + width from headers unless requested not to.
- if (!column->IsPreserveWidthAuto)
+ const bool column_is_resizable = (column->Flags & ImGuiTableColumnFlags_NoResize) == 0;
+ if (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAuto))
{
- const float content_width_body = (float)ImMax(column->ContentMaxXFrozen, column->ContentMaxXUnfrozen) - column->WorkMinX;
- const float content_width_headers = (float)column->ContentMaxXHeadersIdeal - column->WorkMinX;
- float width_auto = content_width_body;
- if (!(table->Flags & ImGuiTableFlags_NoHeadersWidth) && !(column->Flags & ImGuiTableColumnFlags_NoHeaderWidth))
- width_auto = ImMax(width_auto, content_width_headers);
- width_auto = ImMax(width_auto, min_column_width);
-
- // Non-resizable columns also submit their requested width
- if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && column->InitStretchWeightOrWidth > 0.0f)
- if (!(table->Flags & ImGuiTableFlags_Resizable) || (column->Flags & ImGuiTableColumnFlags_NoResize))
- width_auto = ImMax(width_auto, column->InitStretchWeightOrWidth);
-
- column->WidthAuto = width_auto;
- }
- column->IsPreserveWidthAuto = false;
+ // Apply same widths policy
+ float width_auto = column->WidthAuto;
+ if (table_sizing_policy == ImGuiTableFlags_SizingFixedSame && (column->AutoFitQueue != 0x00 || !column_is_resizable))
+ width_auto = fixed_max_width_auto;
- if (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAutoResize))
- {
- // Process auto-fit for non-stretched columns
+ // Apply automatic width
// Latch initial size for fixed columns and update it constantly for auto-resizing column (unless clipped!)
- if ((column->AutoFitQueue != 0x00) || ((column->Flags & ImGuiTableColumnFlags_WidthAutoResize) && column->IsVisibleX))
- column->WidthRequest = column->WidthAuto;
+ if ((column->AutoFitQueue != 0x00) || ((column->Flags & ImGuiTableColumnFlags_WidthAuto) && column->IsVisibleX) || ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && !column_is_resizable))
+ column->WidthRequest = width_auto;
// FIXME-TABLE: Increase minimum size during init frame to avoid biasing auto-fitting widgets
// (e.g. TextWrapped) too much. Otherwise what tends to happen is that TextWrapped would output a very
// large height (= first frame scrollbar display very off + clipper would skip lots of items).
// This is merely making the side-effect less extreme, but doesn't properly fixes it.
// FIXME: Move this to ->WidthGiven to avoid temporary lossyless?
- if (column->AutoFitQueue > 0x01 && table->IsInitializing)
- column->WidthRequest = ImMax(column->WidthRequest, min_column_width * 4.0f); // FIXME-TABLE: Another constant/scale?
- count_fixed += 1;
- sum_width_fixed_requests += column->WidthRequest;
+ // FIXME: This break IsPreserveWidthAuto from not flickering if the stored WidthAuto was smaller.
+ if (column->AutoFitQueue > 0x01 && table->IsInitializing && !column->IsPreserveWidthAuto)
+ column->WidthRequest = ImMax(column->WidthRequest, table->MinColumnWidth * 4.0f); // FIXME-TABLE: Another constant/scale?
+ sum_width_requests += column->WidthRequest;
}
else
{
- IM_ASSERT(column->Flags & ImGuiTableColumnFlags_WidthStretch);
- if (column->StretchWeight < 0.0f)
- column->StretchWeight = 1.0f;
- sum_weights_stretched += column->StretchWeight;
- if (table->LeftMostStretchedColumnDisplayOrder == -1 || table->LeftMostStretchedColumnDisplayOrder > column->DisplayOrder)
- table->LeftMostStretchedColumnDisplayOrder = column->DisplayOrder;
- }
- max_width_auto = ImMax(max_width_auto, column->WidthAuto);
- sum_width_fixed_requests += table->CellPaddingX * 2.0f;
- }
- table->ColumnsEnabledFixedCount = (ImGuiTableColumnIdx)count_fixed;
-
- // [Part 4] Apply "same widths" feature.
- // - When all columns are fixed or columns are of mixed type: use the maximum auto width.
- // - When all columns are stretch: use same weight.
- const bool mixed_same_widths = (table->Flags & ImGuiTableFlags_SameWidths) && count_fixed > 0;
- if (table->Flags & ImGuiTableFlags_SameWidths)
- {
- for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
- {
- if (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n)))
- continue;
- ImGuiTableColumn* column = &table->Columns[column_n];
- if (column->Flags & (ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_WidthAutoResize))
+ // Initialize stretch weight
+ if (column->AutoFitQueue != 0x00 || column->StretchWeight < 0.0f || !column_is_resizable)
{
- sum_width_fixed_requests += max_width_auto - column->WidthRequest; // Update old sum
- column->WidthRequest = max_width_auto;
- }
- else
- {
- sum_weights_stretched += 1.0f - column->StretchWeight; // Update old sum
- column->StretchWeight = 1.0f;
- if (count_fixed > 0)
- column->WidthRequest = max_width_auto;
+ if (column->InitStretchWeightOrWidth > 0.0f)
+ column->StretchWeight = column->InitStretchWeightOrWidth;
+ else if (table_sizing_policy == ImGuiTableFlags_SizingStretchProp)
+ column->StretchWeight = (column->WidthAuto / stretch_sum_width_auto) * count_stretch;
+ else
+ column->StretchWeight = 1.0f;
}
+
+ stretch_sum_weights += column->StretchWeight;
+ if (table->LeftMostStretchedColumn == -1 || table->Columns[table->LeftMostStretchedColumn].DisplayOrder > column->DisplayOrder)
+ table->LeftMostStretchedColumn = (ImGuiTableColumnIdx)column_n;
+ if (table->RightMostStretchedColumn == -1 || table->Columns[table->RightMostStretchedColumn].DisplayOrder < column->DisplayOrder)
+ table->RightMostStretchedColumn = (ImGuiTableColumnIdx)column_n;
}
+ column->IsPreserveWidthAuto = false;
+ sum_width_requests += table->CellPaddingX * 2.0f;
}
+ table->ColumnsEnabledFixedCount = (ImGuiTableColumnIdx)count_fixed;
// [Part 5] Apply final widths based on requested widths
const ImRect work_rect = table->WorkRect;
const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1);
const float width_avail = ((table->Flags & ImGuiTableFlags_ScrollX) && table->InnerWidth == 0.0f) ? table->InnerClipRect.GetWidth() : work_rect.GetWidth();
- const float width_avail_for_stretched_columns = mixed_same_widths ? 0.0f : width_avail - width_spacings - sum_width_fixed_requests;
+ const float width_avail_for_stretched_columns = width_avail - width_spacings - sum_width_requests;
float width_remaining_for_stretched_columns = width_avail_for_stretched_columns;
- table->ColumnsTotalWidth = width_spacings;
- table->ColumnsAutoFitWidth = width_spacings;
+ table->ColumnsGivenWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount;
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{
if (!(table->EnabledMaskByIndex & ((ImU64)1 << column_n)))
continue;
ImGuiTableColumn* column = &table->Columns[column_n];
- // Allocate width for stretched/weighted columns
+ // Allocate width for stretched/weighted columns (StretchWeight gets converted into WidthRequest)
if (column->Flags & ImGuiTableColumnFlags_WidthStretch)
{
- // StretchWeight gets converted into WidthRequest
- if (!mixed_same_widths)
- {
- float weight_ratio = column->StretchWeight / sum_weights_stretched;
- column->WidthRequest = IM_FLOOR(ImMax(width_avail_for_stretched_columns * weight_ratio, min_column_width) + 0.01f);
- width_remaining_for_stretched_columns -= column->WidthRequest;
- }
-
- // [Resize Rule 2] Resizing from right-side of a stretch column preceding a fixed column
- // needs to forward resizing to left-side of fixed column. We also need to copy the NoResize flag..
- if (column->NextEnabledColumn != -1)
- if (ImGuiTableColumn* next_column = &table->Columns[column->NextEnabledColumn])
- if (next_column->Flags & ImGuiTableColumnFlags_WidthFixed)
- column->Flags |= (next_column->Flags & ImGuiTableColumnFlags_NoDirectResize_);
+ float weight_ratio = column->StretchWeight / stretch_sum_weights;
+ column->WidthRequest = IM_FLOOR(ImMax(width_avail_for_stretched_columns * weight_ratio, table->MinColumnWidth) + 0.01f);
+ width_remaining_for_stretched_columns -= column->WidthRequest;
}
// [Resize Rule 1] The right-most Visible column is not resizable if there is at least one Stretch column
- // (see comments in TableResizeColumn())
- if (column->NextEnabledColumn == -1 && table->LeftMostStretchedColumnDisplayOrder != -1)
+ // See additional comments in TableSetColumnWidth().
+ if (column->NextEnabledColumn == -1 && table->LeftMostStretchedColumn != -1)
column->Flags |= ImGuiTableColumnFlags_NoDirectResize_;
// Assign final width, record width in case we will need to shrink
- column->WidthGiven = ImFloor(ImMax(column->WidthRequest, min_column_width));
- table->ColumnsTotalWidth += column->WidthGiven + table->CellPaddingX * 2.0f;
- table->ColumnsAutoFitWidth += column->WidthAuto + table->CellPaddingX * 2.0f;
+ column->WidthGiven = ImFloor(ImMax(column->WidthRequest, table->MinColumnWidth));
+ table->ColumnsGivenWidth += column->WidthGiven;
}
// [Part 6] Redistribute stretch remainder width due to rounding (remainder width is < 1.0f * number of Stretch column).
// Using right-to-left distribution (more likely to match resizing cursor).
if (width_remaining_for_stretched_columns >= 1.0f && !(table->Flags & ImGuiTableFlags_PreciseWidths))
- for (int order_n = table->ColumnsCount - 1; sum_weights_stretched > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--)
+ for (int order_n = table->ColumnsCount - 1; stretch_sum_weights > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--)
{
if (!(table->EnabledMaskByDisplayOrder & ((ImU64)1 << order_n)))
continue;
@@ -857,6 +877,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// [Part 7] Setup final position, offset, skip/clip states and clipping rectangles, detect hovered column
// Process columns in their visible orders as we are comparing the visible order and adjusting host_clip_rect while looping.
int visible_n = 0;
+ bool offset_x_frozen = (table->FreezeColumnsCount > 0);
float offset_x = ((table->FreezeColumnsCount > 0) ? table->OuterRect.Min.x : work_rect.Min.x) + table->OuterPaddingX - table->CellSpacingX1;
ImRect host_clip_rect = table->InnerClipRect;
//host_clip_rect.Max.x += table->CellPaddingX + table->CellSpacingX2;
@@ -869,8 +890,11 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
column->NavLayerCurrent = (ImS8)((table->FreezeRowsCount > 0 || column_n < table->FreezeColumnsCount) ? ImGuiNavLayer_Menu : ImGuiNavLayer_Main);
- if (table->FreezeColumnsCount > 0 && table->FreezeColumnsCount == visible_n)
+ if (offset_x_frozen && table->FreezeColumnsCount == visible_n)
+ {
offset_x += work_rect.Min.x - table->OuterRect.Min.x;
+ offset_x_frozen = false;
+ }
// Clear status flags
column->Flags &= ~ImGuiTableColumnFlags_StatusMask_;
@@ -894,47 +918,26 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
if (is_hovering_table && g.IO.MousePos.x >= column->ClipRect.Min.x && g.IO.MousePos.x < column->ClipRect.Max.x)
table->HoveredColumnBody = (ImGuiTableColumnIdx)column_n;
- // Maximum width
- float max_width = FLT_MAX;
- if (table->Flags & ImGuiTableFlags_ScrollX)
- {
- // Frozen columns can't reach beyond visible width else scrolling will naturally break.
- if (order_n < table->FreezeColumnsRequest)
- {
- max_width = (table->InnerClipRect.Max.x - (table->FreezeColumnsRequest - order_n) * min_column_distance) - offset_x;
- max_width = max_width - table->OuterPaddingX - table->CellPaddingX - table->CellSpacingX2;
- }
- }
- else if ((table->Flags & ImGuiTableFlags_NoKeepColumnsVisible) == 0)
- {
- // If horizontal scrolling if disabled, we apply a final lossless shrinking of columns in order to make
- // sure they are all visible. Because of this we also know that all of the columns will always fit in
- // table->WorkRect and therefore in table->InnerRect (because ScrollX is off)
- // FIXME-TABLE: This is solved incorrectly but also quite a difficult problem to fix as we also want ClipRect width to match.
- // See "table_width_distrib" and "table_width_keep_visible" tests
- max_width = table->WorkRect.Max.x - (table->ColumnsEnabledCount - column->IndexWithinEnabledSet - 1) * min_column_distance - offset_x;
- //max_width -= table->CellSpacingX1;
- max_width -= table->CellSpacingX2;
- max_width -= table->CellPaddingX * 2.0f;
- max_width -= table->OuterPaddingX;
- }
- column->WidthGiven = ImMin(column->WidthGiven, max_width);
+ // Lock start position
+ column->MinX = offset_x;
- // Minimum width
- column->WidthGiven = ImMax(column->WidthGiven, ImMin(column->WidthRequest, min_column_width));
+ // Lock width based on start position and minimum/maximum width for this position
+ float max_width = TableGetMaxColumnWidth(table, column_n);
+ column->WidthGiven = ImMin(column->WidthGiven, max_width);
+ column->WidthGiven = ImMax(column->WidthGiven, ImMin(column->WidthRequest, table->MinColumnWidth));
+ column->MaxX = offset_x + column->WidthGiven + table->CellSpacingX1 + table->CellSpacingX2 + table->CellPaddingX * 2.0f;
- // Lock all our positions
+ // Lock other positions
// - ClipRect.Min.x: Because merging draw commands doesn't compare min boundaries, we make ClipRect.Min.x match left bounds to be consistent regardless of merging.
- // - ClipRect.Max.x: using WorkMaxX instead of MaxX (aka including padding) is detrimental to visibility in very-small column.
+ // - ClipRect.Max.x: using WorkMaxX instead of MaxX (aka including padding) makes things more consistent when resizing down, tho slightly detrimental to visibility in very-small column.
+ // - ClipRect.Max.x: using MaxX makes it easier for header to receive hover highlight with no discontinuity and display sorting arrow.
// - FIXME-TABLE: We want equal width columns to have equal (ClipRect.Max.x - WorkMinX) width, which means ClipRect.max.x cannot stray off host_clip_rect.Max.x else right-most column may appear shorter.
- column->MinX = offset_x;
- column->MaxX = offset_x + column->WidthGiven + table->CellSpacingX1 + table->CellSpacingX2 + table->CellPaddingX * 2.0f;
column->WorkMinX = column->MinX + table->CellPaddingX + table->CellSpacingX1;
column->WorkMaxX = column->MaxX - table->CellPaddingX - table->CellSpacingX2; // Expected max
column->ItemWidth = ImFloor(column->WidthGiven * 0.65f);
column->ClipRect.Min.x = column->MinX;
column->ClipRect.Min.y = work_rect.Min.y;
- column->ClipRect.Max.x = column->MaxX; // column->WorkMaxX;
+ column->ClipRect.Max.x = column->MaxX; //column->WorkMaxX;
column->ClipRect.Max.y = FLT_MAX;
column->ClipRect.ClipWithFull(host_clip_rect);
@@ -942,7 +945,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// Note that scrolling tables (where inner_window != outer_window) handle Y clipped earlier in BeginTable() so IsVisibleY really only applies to non-scrolling tables.
// FIXME-TABLE: Because InnerClipRect.Max.y is conservatively ==outer_window->ClipRect.Max.y, we never can mark columns _Above_ the scroll line as not IsVisibleY.
// Taking advantage of LastOuterHeight would yield good results there...
- // FIXME-TABLE: IsVisible == false is disabled because it effectively means not submitting will reduces contents width which is fed to outer_window->DC.CursorMaxPos.x,
+ // FIXME-TABLE: Y clipping is disabled because it effectively means not submitting will reduce contents width which is fed to outer_window->DC.CursorMaxPos.x,
// and this may be used (e.g. typically by outer_window using AlwaysAutoResize or outer_window's horizontal scrollbar, but could be something else).
// Possible solution to preserve last known content width for clipped column. Test 'table_reported_size' fails when enabling Y clipping and window is resized small.
column->IsVisibleX = (column->ClipRect.Max.x > column->ClipRect.Min.x);
@@ -958,9 +961,6 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// Mark column as SkipItems (ignoring all items/layout)
column->IsSkipItems = !column->IsEnabled || table->HostSkipItems;
- //if (!is_visible && (column->Flags & ImGuiTableColumnFlags_AutoCull))
- // if ((column->AutoFitQueue & 1) == 0 && (column->CannotSkipItemsQueue & 1) == 0)
- // column->IsSkipItems = true;
if (column->IsSkipItems)
IM_ASSERT(!is_visible);
@@ -1002,29 +1002,41 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// [Part 8] Detect/store when we are hovering the unused space after the right-most column (so e.g. context menus can react on it)
// Clear Resizable flag if none of our column are actually resizable (either via an explicit _NoResize flag, either
- // because of using _WidthAutoResize/_WidthStretch). This will hide the resizing option from the context menu.
+ // because of using _WidthAuto/_WidthStretch). This will hide the resizing option from the context menu.
+ const float unused_x1 = ImMax(table->WorkRect.Min.x, table->Columns[table->RightMostEnabledColumn].ClipRect.Max.x);
if (is_hovering_table && table->HoveredColumnBody == -1)
{
- float unused_x1 = table->WorkRect.Min.x;
- if (table->RightMostEnabledColumn != -1)
- unused_x1 = ImMax(unused_x1, table->Columns[table->RightMostEnabledColumn].ClipRect.Max.x);
if (g.IO.MousePos.x >= unused_x1)
table->HoveredColumnBody = (ImGuiTableColumnIdx)table->ColumnsCount;
}
- if (count_resizable == 0 && (table->Flags & ImGuiTableFlags_Resizable))
+ if (has_resizable == false && (table->Flags & ImGuiTableFlags_Resizable))
table->Flags &= ~ImGuiTableFlags_Resizable;
- // [Part 9] Allocate draw channels
+ // [Part 9] Lock actual OuterRect/WorkRect right-most position.
+ // This is done late to handle the case of fixed-columns tables not claiming more widths that they need.
+ // Because of this we are careful with uses of WorkRect and InnerClipRect before this point.
+ if (table->RightMostStretchedColumn != -1)
+ table->IsOuterRectAutoFitX = false;
+ if (table->IsOuterRectAutoFitX)
+ {
+ table->OuterRect.Max.x = table->WorkRect.Max.x = unused_x1;
+ table->InnerClipRect.Max.x = ImMin(table->InnerClipRect.Max.x, unused_x1);
+ }
+ table->InnerWindow->ParentWorkRect = table->WorkRect;
+ table->BorderX1 = table->InnerClipRect.Min.x;// +((table->Flags & ImGuiTableFlags_BordersOuter) ? 0.0f : -1.0f);
+ table->BorderX2 = table->InnerClipRect.Max.x;// +((table->Flags & ImGuiTableFlags_BordersOuter) ? 0.0f : +1.0f);
+
+ // [Part 10] Allocate draw channels and setup background cliprect
TableSetupDrawChannels(table);
- // [Part 10] Hit testing on borders
+ // [Part 11] Hit testing on borders
if (table->Flags & ImGuiTableFlags_Resizable)
TableUpdateBorders(table);
table->LastFirstRowHeight = 0.0f;
table->IsLayoutLocked = true;
table->IsUsingHeaders = false;
- // [Part 11] Context menu
+ // [Part 12] Context menu
if (table->IsContextPopupOpen && table->InstanceCurrent == table->InstanceInteracted)
{
const ImGuiID context_menu_id = ImHashStr("##ContextMenu", 0, table->ID);
@@ -1047,7 +1059,7 @@ void ImGui::TableUpdateLayout(ImGuiTable* table)
// Initial state
ImGuiWindow* inner_window = table->InnerWindow;
if (table->Flags & ImGuiTableFlags_NoClip)
- table->DrawSplitter.SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_UNCLIPPED);
+ table->DrawSplitter.SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP);
else
inner_window->DrawList->PushClipRect(inner_window->ClipRect.Min, inner_window->ClipRect.Max, false);
}
@@ -1085,6 +1097,10 @@ void ImGui::TableUpdateBorders(ImGuiTable* table)
if ((table->Flags & ImGuiTableFlags_NoBordersInBody) && table->IsUsingHeaders == false)
continue;
+ if (table->FreezeColumnsCount > 0)
+ if (column->MaxX < table->Columns[table->DisplayOrderToIndex[table->FreezeColumnsCount - 1]].MaxX)
+ continue;
+
ImGuiID column_id = TableGetColumnResizeID(table, column_n, table->InstanceCurrent);
ImRect hit_rect(column->MaxX - hit_half_width, hit_y1, column->MaxX + hit_half_width, border_y2_hit);
//GetForegroundDrawList()->AddRect(hit_rect.Min, hit_rect.Max, IM_COL32(255, 0, 0, 100));
@@ -1100,6 +1116,8 @@ void ImGui::TableUpdateBorders(ImGuiTable* table)
}
if (held)
{
+ if (table->LastResizedColumn == -1)
+ table->ResizeLockMinContentsX2 = table->RightMostEnabledColumn != -1 ? table->Columns[table->RightMostEnabledColumn].MaxX : -FLT_MAX;
table->ResizedColumn = (ImGuiTableColumnIdx)column_n;
table->InstanceInteracted = table->InstanceCurrent;
}
@@ -1146,12 +1164,13 @@ void ImGui::EndTable()
inner_window->DC.CursorMaxPos = table->HostBackupCursorMaxPos;
if (inner_window != outer_window)
{
- table->OuterRect.Max.y = ImMax(table->OuterRect.Max.y, inner_window->Pos.y + inner_window->Size.y);
+ // Both OuterRect/InnerRect are valid from BeginTable
inner_window->DC.CursorMaxPos.y = table->RowPosY2;
}
else if (!(flags & ImGuiTableFlags_NoHostExtendY))
{
- table->OuterRect.Max.y = ImMax(table->OuterRect.Max.y, inner_window->DC.CursorPos.y);
+ // Patch OuterRect/InnerRect height
+ table->OuterRect.Max.y = table->InnerRect.Max.y = ImMax(table->OuterRect.Max.y, inner_window->DC.CursorPos.y);
inner_window->DC.CursorMaxPos.y = table->RowPosY2;
}
table->WorkRect.Max.y = ImMax(table->WorkRect.Max.y, table->OuterRect.Max.y);
@@ -1164,20 +1183,12 @@ void ImGui::EndTable()
// Draw borders
if ((flags & ImGuiTableFlags_Borders) != 0)
TableDrawBorders(table);
- table->DrawSplitter.SetCurrentChannel(inner_window->DrawList, 0);
-
- // Store content width reference for each column (before attempting to merge draw calls)
- const float backup_outer_cursor_pos_x = outer_window->DC.CursorPos.x;
- const float backup_outer_max_pos_x = outer_window->DC.CursorMaxPos.x;
- const float backup_inner_max_pos_x = inner_window->DC.CursorMaxPos.x;
- float max_pos_x = backup_inner_max_pos_x;
- if (table->RightMostEnabledColumn != -1)
- max_pos_x = ImMax(max_pos_x, table->Columns[table->RightMostEnabledColumn].MaxX);
#if 0
// Strip out dummy channel draw calls
// We have no way to prevent user submitting direct ImDrawList calls into a hidden column (but ImGui:: calls will be clipped out)
- // (The problem with this approach is we are effectively making it harder for users watching metrics to spot wasted vertices)
+ // Pros: remove draw calls which will have no effect. since they'll have zero-size cliprect they may be early out anyway.
+ // Cons: making it harder for users watching metrics/debugger to spot the wasted vertices.
if (table->DummyDrawChannel != (ImGuiTableColumnIdx)-1)
{
ImDrawChannel* dummy_channel = &table->DrawSplitter._Channels[table->DummyDrawChannel];
@@ -1187,18 +1198,27 @@ void ImGui::EndTable()
#endif
// Flatten channels and merge draw calls
+ table->DrawSplitter.SetCurrentChannel(inner_window->DrawList, 0);
if ((table->Flags & ImGuiTableFlags_NoClip) == 0)
TableMergeDrawChannels(table);
table->DrawSplitter.Merge(inner_window->DrawList);
- if (!(table->Flags & ImGuiTableFlags_ScrollX) && inner_window != outer_window)
+ // Update ColumnsAutoFitWidth to get us ahead for host using our size to auto-resize without waiting for next BeginTable()
+ const float width_spacings = (table->OuterPaddingX * 2.0f) + (table->CellSpacingX1 + table->CellSpacingX2) * (table->ColumnsEnabledCount - 1);
+ table->ColumnsAutoFitWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount;
+ for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
+ if (table->EnabledMaskByIndex & ((ImU64)1 << column_n))
+ table->ColumnsAutoFitWidth += TableGetColumnWidthAuto(table, &table->Columns[column_n]);
+
+ // Update scroll
+ if ((table->Flags & ImGuiTableFlags_ScrollX) == 0 && inner_window != outer_window)
{
inner_window->Scroll.x = 0.0f;
}
else if (table->LastResizedColumn != -1 && table->ResizedColumn == -1 && inner_window->ScrollbarX && table->InstanceInteracted == table->InstanceCurrent)
{
// When releasing a column being resized, scroll to keep the resulting column in sight
- const float neighbor_width_to_keep_visible = TableGetMinColumnWidth() + table->CellPaddingX * 2.0f;
+ const float neighbor_width_to_keep_visible = table->MinColumnWidth + table->CellPaddingX * 2.0f;
ImGuiTableColumn* column = &table->Columns[table->LastResizedColumn];
if (column->MaxX < table->InnerClipRect.Min.x)
SetScrollFromPosX(inner_window, column->MaxX - inner_window->Pos.x - neighbor_width_to_keep_visible, 1.0f);
@@ -1215,10 +1235,20 @@ void ImGui::EndTable()
table->ResizedColumnNextWidth = new_width;
}
- // Layout in outer window
+ // Pop from id stack
IM_ASSERT_USER_ERROR(inner_window->IDStack.back() == table->ID + table->InstanceCurrent, "Mismatching PushID/PopID!");
IM_ASSERT_USER_ERROR(outer_window->DC.ItemWidthStack.Size >= table->HostBackupItemWidthStackSize, "Too many PopItemWidth!");
PopID();
+
+ // Layout in outer window
+ const float backup_outer_cursor_pos_x = outer_window->DC.CursorPos.x;
+ const float backup_outer_max_pos_x = outer_window->DC.CursorMaxPos.x;
+ const float backup_inner_max_pos_x = inner_window->DC.CursorMaxPos.x;
+ float max_pos_x = backup_inner_max_pos_x;
+ if (table->RightMostEnabledColumn != -1)
+ max_pos_x = ImMax(max_pos_x, table->Columns[table->RightMostEnabledColumn].MaxX);
+ if (table->ResizedColumn != -1)
+ max_pos_x = ImMax(max_pos_x, table->ResizeLockMinContentsX2);
inner_window->WorkRect = table->HostBackupWorkRect;
inner_window->ParentWorkRect = table->HostBackupParentWorkRect;
inner_window->SkipItems = table->HostSkipItems;
@@ -1226,14 +1256,14 @@ void ImGui::EndTable()
outer_window->DC.ItemWidth = table->HostBackupItemWidth;
outer_window->DC.ItemWidthStack.Size = table->HostBackupItemWidthStackSize;
outer_window->DC.ColumnsOffset = table->HostBackupColumnsOffset;
+ const float outer_width = table->IsOuterRectAutoFitX ? table->WorkRect.GetWidth() : table->ColumnsAutoFitWidth;
if (inner_window != outer_window)
{
EndChild();
}
else
{
- ImVec2 item_size = table->OuterRect.GetSize();
- item_size.x = table->ColumnsTotalWidth;
+ ImVec2 item_size(outer_width, table->OuterRect.GetHeight());
ItemSize(item_size);
}
@@ -1242,11 +1272,12 @@ void ImGui::EndTable()
if (table->Flags & ImGuiTableFlags_ScrollX)
{
inner_window->DC.CursorMaxPos.x = max_pos_x; // Set contents width for scrolling
- outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos_x, backup_outer_cursor_pos_x + table->ColumnsTotalWidth + inner_window->ScrollbarSizes.x); // For auto-fit
+ outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos_x, backup_outer_cursor_pos_x + table->ColumnsGivenWidth + inner_window->ScrollbarSizes.x); // For scrolling
}
else
{
- outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos_x, table->WorkRect.Min.x + table->ColumnsAutoFitWidth); // For auto-fit
+ outer_window->DC.CursorMaxPos.x = ImMax(backup_outer_max_pos_x, table->WorkRect.Min.x + outer_width); // For auto-fit
+ outer_window->DC.CursorPosPrevLine.x = table->WorkRect.Max.x; // For consistent reaction to SameLine() // FIXME: Should be a feature of layout/ItemAdd
}
// Save settings
@@ -1261,184 +1292,64 @@ void ImGui::EndTable()
outer_window->DC.CurrentTableIdx = g.CurrentTable ? g.Tables.GetIndex(g.CurrentTable) : -1;
}
-static void TableUpdateColumnsWeightFromWidth(ImGuiTable* table)
-{
- IM_ASSERT(table->LeftMostStretchedColumnDisplayOrder != -1);
-
- // Measure existing quantity
- float visible_weight = 0.0f;
- float visible_width = 0.0f;
- for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
- {
- ImGuiTableColumn* column = &table->Columns[column_n];
- if (!column->IsEnabled || !(column->Flags & ImGuiTableColumnFlags_WidthStretch))
- continue;
- IM_ASSERT(column->StretchWeight > 0.0f);
- visible_weight += column->StretchWeight;
- visible_width += column->WidthRequest;
- }
- IM_ASSERT(visible_weight > 0.0f && visible_width > 0.0f);
-
- // Apply new weights
- for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
- {
- ImGuiTableColumn* column = &table->Columns[column_n];
- if (!column->IsEnabled || !(column->Flags & ImGuiTableColumnFlags_WidthStretch))
- continue;
- column->StretchWeight = ((column->WidthRequest + 0.0f) / visible_width) * visible_weight;
- }
-}
-
-// 'width' = inner column width, without padding
-void ImGui::TableSetColumnWidth(int column_n, float width)
-{
- ImGuiContext& g = *GImGui;
- ImGuiTable* table = g.CurrentTable;
- IM_ASSERT(table != NULL && table->IsLayoutLocked == false);
- IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount);
- ImGuiTableColumn* column_0 = &table->Columns[column_n];
- float column_0_width = width;
-
- // Constraints
- const float min_width = TableGetMinColumnWidth();
- float max_width_0 = FLT_MAX;
- if (!(table->Flags & ImGuiTableFlags_ScrollX))
- max_width_0 = (table->WorkRect.Max.x - column_0->MinX) - (table->ColumnsEnabledCount - (column_0->IndexWithinEnabledSet + 1)) * min_width;
- column_0_width = ImClamp(column_0_width, min_width, max_width_0);
-
- // Compare both requested and actual given width to avoid overwriting requested width when column is stuck (minimum size, bounded)
- if (column_0->WidthGiven == column_0_width || column_0->WidthRequest == column_0_width)
- return;
-
- ImGuiTableColumn* column_1 = (column_0->NextEnabledColumn != -1) ? &table->Columns[column_0->NextEnabledColumn] : NULL;
-
- // In this surprisingly not simple because of how we support mixing Fixed and Stretch columns.
- // When forwarding resize from Wn| to Fn+1| we need to be considerate of the _NoResize flag on Fn+1.
- // FIXME-TABLE: Find a way to rewrite all of this so interactions feel more consistent for the user.
- // Scenarios:
- // - F1 F2 F3 resize from F1| or F2| --> ok: alter ->WidthRequested of Fixed column. Subsequent columns will be offset.
- // - F1 F2 F3 resize from F3| --> ok: alter ->WidthRequested of Fixed column. If active, ScrollX extent can be altered.
- // - F1 F2 W3 resize from F1| or F2| --> ok: alter ->WidthRequested of Fixed column. If active, ScrollX extent can be altered, but it doesn't make much sense as the Stretch column will always be minimal size.
- // - F1 F2 W3 resize from W3| --> ok: no-op (disabled by Resize Rule 1)
- // - W1 W2 W3 resize from W1| or W2| --> FIXME
- // - W1 W2 W3 resize from W3| --> ok: no-op (disabled by Resize Rule 1)
- // - W1 F2 F3 resize from F3| --> ok: no-op (disabled by Resize Rule 1)
- // - W1 F2 resize from F2| --> ok: no-op (disabled by Resize Rule 1)
- // - W1 W2 F3 resize from W1| or W2| --> ok
- // - W1 F2 W3 resize from W1| or F2| --> FIXME
- // - F1 W2 F3 resize from W2| --> ok
- // - W1 F2 F3 resize from W1| --> ok: equivalent to resizing |F2. F3 will not move. (forwarded by Resize Rule 2)
- // - W1 F2 F3 resize from F2| --> FIXME should resize F2, F3 and not have effect on W1 (Stretch columns are _before_ the Fixed column).
-
- // Rules:
- // - [Resize Rule 1] Can't resize from right of right-most visible column if there is any Stretch column. Implemented in TableUpdateLayout().
- // - [Resize Rule 2] Resizing from right-side of a Stretch column before a fixed column forward sizing to left-side of fixed column.
- // - [Resize Rule 3] If we are are followed by a fixed column and we have a Stretch column before, we need to ensure that our left border won't move.
- table->IsSettingsDirty = true;
- if (column_0->Flags & ImGuiTableColumnFlags_WidthFixed)
- {
- // [Resize Rule 3] If we are are followed by a fixed column and we have a Stretch column before, we need to ensure
- // that our left border won't move, which we can do by making sure column_a/column_b resizes cancels each others.
- if (column_1 && (column_1->Flags & ImGuiTableColumnFlags_WidthFixed))
- if (table->LeftMostStretchedColumnDisplayOrder != -1 && table->LeftMostStretchedColumnDisplayOrder < column_0->DisplayOrder)
- {
- // (old_a + old_b == new_a + new_b) --> (new_a == old_a + old_b - new_b)
- float column_1_width = ImMax(column_1->WidthRequest - (column_0_width - column_0->WidthRequest), min_width);
- column_0_width = column_0->WidthRequest + column_1->WidthRequest - column_1_width;
- column_1->WidthRequest = column_1_width;
- }
-
- // Apply
- //IMGUI_DEBUG_LOG("TableSetColumnWidth(%d, %.1f->%.1f)\n", column_0_idx, column_0->WidthRequested, column_0_width);
- column_0->WidthRequest = column_0_width;
- }
- else if (column_0->Flags & ImGuiTableColumnFlags_WidthStretch)
- {
- // We can also use previous column if there's no next one
- if (column_1 == NULL)
- column_1 = (column_0->PrevEnabledColumn != -1) ? &table->Columns[column_0->PrevEnabledColumn] : NULL;
- if (column_1 == NULL)
- return;
-
- if (column_1->Flags & ImGuiTableColumnFlags_WidthFixed)
- {
- // [Resize Rule 2]
- float off = (column_0->WidthGiven - column_0_width);
- float column_1_width = column_1->WidthGiven + off;
- column_1->WidthRequest = ImMax(min_width, column_1_width);
- }
- else
- {
- // (old_a + old_b == new_a + new_b) --> (new_a == old_a + old_b - new_b)
- float column_1_width = ImMax(column_1->WidthRequest - (column_0_width - column_0->WidthRequest), min_width);
- column_0_width = column_0->WidthRequest + column_1->WidthRequest - column_1_width;
- column_1->WidthRequest = column_1_width;
- column_0->WidthRequest = column_0_width;
- TableUpdateColumnsWeightFromWidth(table);
- }
- }
-}
-
-// We use a default parameter of 'init_width_or_weight == -1',
-// - with ImGuiTableColumnFlags_WidthFixed, width <= 0 --> init width == auto
-// - with ImGuiTableColumnFlags_WidthFixed, width > 0 --> init width == manual
-// - with ImGuiTableColumnFlags_WidthStretch, weight < 0 --> init weight == 1.0f
-// - with ImGuiTableColumnFlags_WidthStretch, weight >= 0 --> init weight == custom
-// Widths are specified _without_ CellPadding. So if you specify a width of 100.0f the column will be 100.0f+Padding*2.0f and you can fit a 100.0-wide item in it.
+// See "COLUMN SIZING POLICIES" comments at the top of this file
void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_id)
{
ImGuiContext& g = *GImGui;
ImGuiTable* table = g.CurrentTable;
IM_ASSERT(table != NULL && "Need to call TableSetupColumn() after BeginTable()!");
IM_ASSERT(table->IsLayoutLocked == false && "Need to call call TableSetupColumn() before first row!");
- IM_ASSERT(table->DeclColumnsCount >= 0 && table->DeclColumnsCount < table->ColumnsCount && "Called TableSetupColumn() too many times!");
IM_ASSERT((flags & ImGuiTableColumnFlags_StatusMask_) == 0 && "Illegal to pass StatusMask values to TableSetupColumn()");
+ if (table->DeclColumnsCount >= table->ColumnsCount)
+ {
+ IM_ASSERT_USER_ERROR(table->DeclColumnsCount < table->ColumnsCount, "Called TableSetupColumn() too many times!");
+ return;
+ }
ImGuiTableColumn* column = &table->Columns[table->DeclColumnsCount];
table->DeclColumnsCount++;
// When passing a width automatically enforce WidthFixed policy
- // (vs TableFixColumnFlags would default to WidthAutoResize)
- // (we write to FlagsIn which is a little misleading, another solution would be to pass init_width_or_weight to TableFixColumnFlags)
- if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0)
- if ((table->Flags & ImGuiTableFlags_ColumnsWidthFixed) && (init_width_or_weight > 0.0f))
+ // (whereas TableSetupColumnFlags would default to WidthAuto if table is not Resizable)
+ if ((flags & ImGuiTableColumnFlags_WidthMask_) == 0 && init_width_or_weight > 0.0f)
+ if ((table->Flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedFit || (table->Flags & ImGuiTableFlags_SizingMask_) == ImGuiTableFlags_SizingFixedSame)
flags |= ImGuiTableColumnFlags_WidthFixed;
+ TableSetupColumnFlags(table, column, flags);
column->UserID = user_id;
- column->FlagsIn = flags;
- column->Flags = TableFixColumnFlags(table, column->FlagsIn) | (column->Flags & ImGuiTableColumnFlags_StatusMask_);
flags = column->Flags;
// Initialize defaults
if (flags & ImGuiTableColumnFlags_WidthStretch)
IM_ASSERT(init_width_or_weight != 0.0f && "Need to provide a valid weight!");
column->InitStretchWeightOrWidth = init_width_or_weight;
- if (table->IsInitializing && column->WidthRequest < 0.0f && column->StretchWeight < 0.0f)
+ if (table->IsInitializing)
{
// Init width or weight
- if ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f)
- column->WidthRequest = init_width_or_weight;
- if (flags & ImGuiTableColumnFlags_WidthStretch)
- column->StretchWeight = (init_width_or_weight > 0.0f) ? init_width_or_weight : 1.0f;
+ if (column->WidthRequest < 0.0f && column->StretchWeight < 0.0f)
+ {
+ if ((flags & ImGuiTableColumnFlags_WidthFixed) && init_width_or_weight > 0.0f)
+ column->WidthRequest = init_width_or_weight;
+ if (flags & ImGuiTableColumnFlags_WidthStretch)
+ column->StretchWeight = (init_width_or_weight > 0.0f) ? init_width_or_weight : -1.0f;
+
+ // Disable auto-fit if an explicit width/weight has been specified
+ if (init_width_or_weight > 0.0f)
+ column->AutoFitQueue = 0x00;
+ }
- // Disable auto-fit if an explicit width/weight has been specified
- if (init_width_or_weight > 0.0f)
- column->AutoFitQueue = 0x00;
- }
- if (table->IsInitializing)
- {
// Init default visibility/sort state
if ((flags & ImGuiTableColumnFlags_DefaultHide) && (table->SettingsLoadedFlags & ImGuiTableFlags_Hideable) == 0)
column->IsEnabled = column->IsEnabledNextFrame = false;
if (flags & ImGuiTableColumnFlags_DefaultSort && (table->SettingsLoadedFlags & ImGuiTableFlags_Sortable) == 0)
{
- column->SortOrder = 0; // Multiple columns using _DefaultSort will be reordered when building the sort specs.
+ column->SortOrder = 0; // Multiple columns using _DefaultSort will be reassigned unique SortOrder values when building the sort specs.
column->SortDirection = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImU8)(ImGuiSortDirection_Ascending);
}
}
// Store name (append with zero-terminator in contiguous buffer)
- IM_ASSERT(column->NameOffset == -1);
+ column->NameOffset = -1;
if (label != NULL && label[0] != 0)
{
column->NameOffset = (ImS16)table->ColumnsNames.size();
@@ -1460,7 +1371,145 @@ void ImGui::TableSetupScrollFreeze(int columns, int rows)
table->FreezeColumnsCount = (table->InnerWindow->Scroll.x != 0.0f) ? table->FreezeColumnsRequest : 0;
table->FreezeRowsRequest = (table->Flags & ImGuiTableFlags_ScrollY) ? (ImGuiTableColumnIdx)rows : 0;
table->FreezeRowsCount = (table->InnerWindow->Scroll.y != 0.0f) ? table->FreezeRowsRequest : 0;
- table->IsUnfrozen = (table->FreezeRowsCount == 0); // Make sure this is set before TableUpdateLayout() so ImGuiListClipper can benefit from it.b
+ table->IsUnfrozenRows = (table->FreezeRowsCount == 0); // Make sure this is set before TableUpdateLayout() so ImGuiListClipper can benefit from it.b
+}
+
+int ImGui::TableGetColumnCount()
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiTable* table = g.CurrentTable;
+ return table ? table->ColumnsCount : 0;
+}
+
+const char* ImGui::TableGetColumnName(int column_n)
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiTable* table = g.CurrentTable;
+ if (!table)
+ return NULL;
+ if (column_n < 0)
+ column_n = table->CurrentColumn;
+ return TableGetColumnName(table, column_n);
+}
+
+const char* ImGui::TableGetColumnName(const ImGuiTable* table, int column_n)
+{
+ if (table->IsLayoutLocked == false && column_n >= table->DeclColumnsCount)
+ return ""; // NameOffset is invalid at this point
+ const ImGuiTableColumn* column = &table->Columns[column_n];
+ if (column->NameOffset == -1)
+ return "";
+ return &table->ColumnsNames.Buf[column->NameOffset];
+}
+
+// We allow querying for an extra column in order to poll the IsHovered state of the right-most section
+ImGuiTableColumnFlags ImGui::TableGetColumnFlags(int column_n)
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiTable* table = g.CurrentTable;
+ if (!table)
+ return ImGuiTableColumnFlags_None;
+ if (column_n < 0)
+ column_n = table->CurrentColumn;
+ if (column_n == table->ColumnsCount)
+ return (table->HoveredColumnBody == column_n) ? ImGuiTableColumnFlags_IsHovered : ImGuiTableColumnFlags_None;
+ return table->Columns[column_n].Flags;
+}
+
+// Return the cell rectangle based on currently known height.
+// - Important: we generally don't know our row height until the end of the row, so Max.y will be incorrect in many situations.
+// The only case where this is correct is if we provided a min_row_height to TableNextRow() and don't go below it.
+// - Important: if ImGuiTableFlags_PadOuterX is set but ImGuiTableFlags_PadInnerX is not set, the outer-most left and right
+// columns report a small offset so their CellBgRect can extend up to the outer border.
+ImRect ImGui::TableGetCellBgRect(const ImGuiTable* table, int column_n)
+{
+ const ImGuiTableColumn* column = &table->Columns[column_n];
+ float x1 = column->MinX;
+ float x2 = column->MaxX;
+ if (column->PrevEnabledColumn == -1)
+ x1 -= table->CellSpacingX1;
+ if (column->NextEnabledColumn == -1)
+ x2 += table->CellSpacingX2;
+ return ImRect(x1, table->RowPosY1, x2, table->RowPosY2);
+}
+
+// Return the resizing ID for the right-side of the given column.
+ImGuiID ImGui::TableGetColumnResizeID(const ImGuiTable* table, int column_n, int instance_no)
+{
+ IM_ASSERT(column_n < table->ColumnsCount);
+ ImGuiID id = table->ID + 1 + (instance_no * table->ColumnsCount) + column_n;
+ return id;
+}
+
+// Return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered.
+int ImGui::TableGetHoveredColumn()
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiTable* table = g.CurrentTable;
+ if (!table)
+ return -1;
+ return (int)table->HoveredColumnBody;
+}
+
+void ImGui::TableSetBgColor(ImGuiTableBgTarget bg_target, ImU32 color, int column_n)
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiTable* table = g.CurrentTable;
+ IM_ASSERT(bg_target != ImGuiTableBgTarget_None);
+
+ if (color == IM_COL32_DISABLE)
+ color = 0;
+
+ // We cannot draw neither the cell or row background immediately as we don't know the row height at this point in time.
+ switch (bg_target)
+ {
+ case ImGuiTableBgTarget_CellBg:
+ {
+ if (table->RowPosY1 > table->InnerClipRect.Max.y) // Discard
+ return;
+ if (column_n == -1)
+ column_n = table->CurrentColumn;
+ if ((table->VisibleMaskByIndex & ((ImU64)1 << column_n)) == 0)
+ return;
+ if (table->RowCellDataCurrent < 0 || table->RowCellData[table->RowCellDataCurrent].Column != column_n)
+ table->RowCellDataCurrent++;
+ ImGuiTableCellData* cell_data = &table->RowCellData[table->RowCellDataCurrent];
+ cell_data->BgColor = color;
+ cell_data->Column = (ImGuiTableColumnIdx)column_n;
+ break;
+ }
+ case ImGuiTableBgTarget_RowBg0:
+ case ImGuiTableBgTarget_RowBg1:
+ {
+ if (table->RowPosY1 > table->InnerClipRect.Max.y) // Discard
+ return;
+ IM_ASSERT(column_n == -1);
+ int bg_idx = (bg_target == ImGuiTableBgTarget_RowBg1) ? 1 : 0;
+ table->RowBgColor[bg_idx] = color;
+ break;
+ }
+ default:
+ IM_ASSERT(0);
+ }
+}
+
+//-------------------------------------------------------------------------
+// [SECTION] Tables: Row changes
+//-------------------------------------------------------------------------
+// - TableGetRowIndex()
+// - TableNextRow()
+// - TableBeginRow() [Internal]
+// - TableEndRow() [Internal]
+//-------------------------------------------------------------------------
+
+// [Public] Note: for row coloring we use ->RowBgColorCounter which is the same value without counting header rows
+int ImGui::TableGetRowIndex()
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiTable* table = g.CurrentTable;
+ if (!table)
+ return 0;
+ return table->CurrentRow;
}
// [Public] Starts into the first cell of a new row
@@ -1488,7 +1537,7 @@ void ImGui::TableNextRow(ImGuiTableRowFlags row_flags, float row_min_height)
table->InnerWindow->SkipItems = true;
}
-// [Internal] Called by TableNextRow()!
+// [Internal] Called by TableNextRow()
void ImGui::TableBeginRow(ImGuiTable* table)
{
ImGuiWindow* window = table->InnerWindow;
@@ -1521,7 +1570,7 @@ void ImGui::TableBeginRow(ImGuiTable* table)
}
}
-// [Internal] Called by TableNextRow()!
+// [Internal] Called by TableNextRow()
void ImGui::TableEndRow(ImGuiTable* table)
{
ImGuiContext& g = *GImGui;
@@ -1539,7 +1588,6 @@ void ImGui::TableEndRow(ImGuiTable* table)
// Row background fill
const float bg_y1 = table->RowPosY1;
const float bg_y2 = table->RowPosY2;
-
const bool unfreeze_rows_actual = (table->CurrentRow + 1 == table->FreezeRowsCount);
const bool unfreeze_rows_request = (table->CurrentRow + 1 == table->FreezeRowsRequest);
if (table->CurrentRow == 0)
@@ -1572,7 +1620,7 @@ void ImGui::TableEndRow(ImGuiTable* table)
// In theory we could call SetWindowClipRectBeforeSetChannel() but since we know TableEndRow() is
// always followed by a change of clipping rectangle we perform the smallest overwrite possible here.
if ((table->Flags & ImGuiTableFlags_NoClip) == 0)
- window->DrawList->_CmdHeader.ClipRect = table->BgClipRectForDrawCmd.ToVec4();
+ window->DrawList->_CmdHeader.ClipRect = table->Bg0ClipRectForDrawCmd.ToVec4();
table->DrawSplitter.SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_BG0);
}
@@ -1623,15 +1671,15 @@ void ImGui::TableEndRow(ImGuiTable* table)
}
if (unfreeze_rows_actual)
{
- IM_ASSERT(table->IsUnfrozen == false);
- table->IsUnfrozen = true;
+ IM_ASSERT(table->IsUnfrozenRows == false);
+ table->IsUnfrozenRows = true;
// BgClipRect starts as table->InnerClipRect, reduce it now and make BgClipRectForDrawCmd == BgClipRect
float y0 = ImMax(table->RowPosY2 + 1, window->InnerClipRect.Min.y);
- table->BgClipRect.Min.y = table->BgClipRectForDrawCmd.Min.y = ImMin(y0, window->InnerClipRect.Max.y);
- table->BgClipRect.Max.y = table->BgClipRectForDrawCmd.Max.y = window->InnerClipRect.Max.y;
- table->Bg1DrawChannelCurrent = table->Bg1DrawChannelUnfrozen;
- IM_ASSERT(table->BgClipRectForDrawCmd.Min.y <= table->BgClipRectForDrawCmd.Max.y);
+ table->BgClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y = ImMin(y0, window->InnerClipRect.Max.y);
+ table->BgClipRect.Max.y = table->Bg2ClipRectForDrawCmd.Max.y = window->InnerClipRect.Max.y;
+ table->Bg2DrawChannelCurrent = table->Bg2DrawChannelUnfrozen;
+ IM_ASSERT(table->Bg2ClipRectForDrawCmd.Min.y <= table->Bg2ClipRectForDrawCmd.Max.y);
float row_height = table->RowPosY2 - table->RowPosY1;
table->RowPosY2 = window->DC.CursorPos.y = table->WorkRect.Min.y + table->RowPosY2 - table->OuterRect.Min.y;
@@ -1640,7 +1688,7 @@ void ImGui::TableEndRow(ImGuiTable* table)
{
ImGuiTableColumn* column = &table->Columns[column_n];
column->DrawChannelCurrent = column->DrawChannelUnfrozen;
- column->ClipRect.Min.y = table->BgClipRectForDrawCmd.Min.y;
+ column->ClipRect.Min.y = table->Bg2ClipRectForDrawCmd.Min.y;
}
// Update cliprect ahead of TableBeginCell() so clipper can access to new ClipRect->Min.y
@@ -1653,7 +1701,74 @@ void ImGui::TableEndRow(ImGuiTable* table)
table->IsInsideRow = false;
}
-// [Internal] Called by TableNextColumn()!
+//-------------------------------------------------------------------------
+// [SECTION] Tables: Columns changes
+//-------------------------------------------------------------------------
+// - TableGetColumnIndex()
+// - TableSetColumnIndex()
+// - TableNextColumn()
+// - TableBeginCell() [Internal]
+// - TableEndCell() [Internal]
+//-------------------------------------------------------------------------
+
+int ImGui::TableGetColumnIndex()
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiTable* table = g.CurrentTable;
+ if (!table)
+ return 0;
+ return table->CurrentColumn;
+}
+
+// [Public] Append into a specific column
+bool ImGui::TableSetColumnIndex(int column_n)
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiTable* table = g.CurrentTable;
+ if (!table)
+ return false;
+
+ if (table->CurrentColumn != column_n)
+ {
+ if (table->CurrentColumn != -1)
+ TableEndCell(table);
+ IM_ASSERT(column_n >= 0 && table->ColumnsCount);
+ TableBeginCell(table, column_n);
+ }
+
+ // Return whether the column is visible. User may choose to skip submitting items based on this return value,
+ // however they shouldn't skip submitting for columns that may have the tallest contribution to row height.
+ return (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)) != 0;
+}
+
+// [Public] Append into the next column, wrap and create a new row when already on last column
+bool ImGui::TableNextColumn()
+{
+ ImGuiContext& g = *GImGui;
+ ImGuiTable* table = g.CurrentTable;
+ if (!table)
+ return false;
+
+ if (table->IsInsideRow && table->CurrentColumn + 1 < table->ColumnsCount)
+ {
+ if (table->CurrentColumn != -1)
+ TableEndCell(table);
+ TableBeginCell(table, table->CurrentColumn + 1);
+ }
+ else
+ {
+ TableNextRow();
+ TableBeginCell(table, 0);
+ }
+
+ // Return whether the column is visible. User may choose to skip submitting items based on this return value,
+ // however they shouldn't skip submitting for columns that may have the tallest contribution to row height.
+ int column_n = table->CurrentColumn;
+ return (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)) != 0;
+}
+
+
+// [Internal] Called by TableSetColumnIndex()/TableNextColumn()
// This is called very frequently, so we need to be mindful of unnecessary overhead.
// FIXME-TABLE FIXME-OPT: Could probably shortcut some things for non-active or clipped columns.
void ImGui::TableBeginCell(ImGuiTable* table, int column_n)
@@ -1672,7 +1787,6 @@ void ImGui::TableBeginCell(ImGuiTable* table, int column_n)
window->DC.CursorMaxPos.x = window->DC.CursorPos.x;
window->DC.ColumnsOffset.x = start_x - window->Pos.x - window->DC.Indent.x; // FIXME-WORKRECT
window->DC.CurrLineTextBaseOffset = table->RowTextBaseline;
- window->DC.LastItemId = 0;
window->DC.NavLayerCurrent = (ImGuiNavLayer)column->NavLayerCurrent;
window->WorkRect.Min.y = window->DC.CursorPos.y;
@@ -1685,11 +1799,17 @@ void ImGui::TableBeginCell(ImGuiTable* table, int column_n)
window->DC.CursorPos.y = ImMax(window->DC.CursorPos.y, table->RowPosY2);
window->SkipItems = column->IsSkipItems;
+ if (column->IsSkipItems)
+ {
+ window->DC.LastItemId = 0;
+ window->DC.LastItemStatusFlags = 0;
+ }
+
if (table->Flags & ImGuiTableFlags_NoClip)
{
// FIXME: if we end up drawing all borders/bg in EndTable, could remove this and just assert that channel hasn't changed.
- table->DrawSplitter.SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_UNCLIPPED);
- //IM_ASSERT(table->DrawSplitter._Current == TABLE_DRAW_CHANNEL_UNCLIPPED);
+ table->DrawSplitter.SetCurrentChannel(window->DrawList, TABLE_DRAW_CHANNEL_NOCLIP);
+ //IM_ASSERT(table->DrawSplitter._Current == TABLE_DRAW_CHANNEL_NOCLIP);
}
else
{
@@ -1699,7 +1819,7 @@ void ImGui::TableBeginCell(ImGuiTable* table, int column_n)
}
}
-// [Internal] Called by TableNextRow()/TableNextColumn()!
+// [Internal] Called by TableNextRow()/TableSetColumnIndex()/TableNextColumn()
void ImGui::TableEndCell(ImGuiTable* table)
{
ImGuiTableColumn* column = &table->Columns[table->CurrentColumn];
@@ -1710,7 +1830,7 @@ void ImGui::TableEndCell(ImGuiTable* table)
if (table->RowFlags & ImGuiTableRowFlags_Headers)
p_max_pos_x = &column->ContentMaxXHeadersUsed; // Useful in case user submit contents in header row that is not a TableHeader() call
else
- p_max_pos_x = table->IsUnfrozen ? &column->ContentMaxXUnfrozen : &column->ContentMaxXFrozen;
+ p_max_pos_x = table->IsUnfrozenRows ? &column->ContentMaxXUnfrozen : &column->ContentMaxXFrozen;
*p_max_pos_x = ImMax(*p_max_pos_x, window->DC.CursorMaxPos.x);
table->RowPosY2 = ImMax(table->RowPosY2, window->DC.CursorMaxPos.y + table->CellPaddingY);
column->ItemWidth = window->DC.ItemWidth;
@@ -1720,146 +1840,145 @@ void ImGui::TableEndCell(ImGuiTable* table)
table->RowTextBaseline = ImMax(table->RowTextBaseline, window->DC.PrevLineTextBaseOffset);
}
-// [Public] Append into the next column/cell
-bool ImGui::TableNextColumn()
-{
- ImGuiContext& g = *GImGui;
- ImGuiTable* table = g.CurrentTable;
- if (!table)
- return false;
+//-------------------------------------------------------------------------
+// [SECTION] Tables: Columns width management
+//-------------------------------------------------------------------------
+// - TableGetMaxColumnWidth() [Internal]
+// - TableGetColumnWidthAuto() [Internal]
+// - TableSetColumnWidth()
+// - TableSetColumnWidthAutoSingle() [Internal]
+// - TableSetColumnWidthAutoAll() [Internal]
+// - TableUpdateColumnsWeightFromWidth() [Internal]
+//-------------------------------------------------------------------------
- if (table->IsInsideRow && table->CurrentColumn + 1 < table->ColumnsCount)
+// Maximum column content width given current layout. Use column->MinX so this value on a per-column basis.
+float ImGui::TableGetMaxColumnWidth(const ImGuiTable* table, int column_n)
+{
+ const ImGuiTableColumn* column = &table->Columns[column_n];
+ float max_width = FLT_MAX;
+ const float min_column_distance = table->MinColumnWidth + table->CellPaddingX * 2.0f + table->CellSpacingX1 + table->CellSpacingX2;
+ if (table->Flags & ImGuiTableFlags_ScrollX)
{
- if (table->CurrentColumn != -1)
- TableEndCell(table);
- TableBeginCell(table, table->CurrentColumn + 1);
+ // Frozen columns can't reach beyond visible width else scrolling will naturally break.
+ if (column->DisplayOrder < table->FreezeColumnsRequest)
+ {
+ max_width = (table->InnerClipRect.Max.x - (table->FreezeColumnsRequest - column->DisplayOrder) * min_column_distance) - column->MinX;
+ max_width = max_width - table->OuterPaddingX - table->CellPaddingX - table->CellSpacingX2;
+ }
}
- else
+ else if ((table->Flags & ImGuiTableFlags_NoKeepColumnsVisible) == 0)
{
- TableNextRow();
- TableBeginCell(table, 0);
+ // If horizontal scrolling if disabled, we apply a final lossless shrinking of columns in order to make
+ // sure they are all visible. Because of this we also know that all of the columns will always fit in
+ // table->WorkRect and therefore in table->InnerRect (because ScrollX is off)
+ // FIXME-TABLE: This is solved incorrectly but also quite a difficult problem to fix as we also want ClipRect width to match.
+ // See "table_width_distrib" and "table_width_keep_visible" tests
+ max_width = table->WorkRect.Max.x - (table->ColumnsEnabledCount - column->IndexWithinEnabledSet - 1) * min_column_distance - column->MinX;
+ //max_width -= table->CellSpacingX1;
+ max_width -= table->CellSpacingX2;
+ max_width -= table->CellPaddingX * 2.0f;
+ max_width -= table->OuterPaddingX;
}
-
- // Return whether the column is visible. User may choose to skip submitting items based on this return value,
- // however they shouldn't skip submitting for columns that may have the tallest contribution to row height.
- int column_n = table->CurrentColumn;
- return (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)) != 0;
+ return max_width;
}
-// [Public] Append into a specific column
-bool ImGui::TableSetColumnIndex(int column_n)
+// Note this is meant to be stored in column->WidthAuto, please generally use the WidthAuto field
+float ImGui::TableGetColumnWidthAuto(ImGuiTable* table, ImGuiTableColumn* column)
{
- ImGuiContext& g = *GImGui;
- ImGuiTable* table = g.CurrentTable;
- if (!table)
- return false;
+ const float content_width_body = ImMax(column->ContentMaxXFrozen, column->ContentMaxXUnfrozen) - column->WorkMinX;
+ const float content_width_headers = column->ContentMaxXHeadersIdeal - column->WorkMinX;
+ float width_auto = content_width_body;
+ if (!(column->Flags & ImGuiTableColumnFlags_NoHeaderWidth))
+ width_auto = ImMax(width_auto, content_width_headers);
- if (table->CurrentColumn != column_n)
- {
- if (table->CurrentColumn != -1)
- TableEndCell(table);
- IM_ASSERT(column_n >= 0 && table->ColumnsCount);
- TableBeginCell(table, column_n);
- }
+ // Non-resizable fixed columns preserve their requested width
+ if ((column->Flags & ImGuiTableColumnFlags_WidthFixed) && column->InitStretchWeightOrWidth > 0.0f)
+ if (!(table->Flags & ImGuiTableFlags_Resizable) || (column->Flags & ImGuiTableColumnFlags_NoResize))
+ width_auto = column->InitStretchWeightOrWidth;
- // Return whether the column is visible. User may choose to skip submitting items based on this return value,
- // however they shouldn't skip submitting for columns that may have the tallest contribution to row height.
- return (table->RequestOutputMaskByIndex & ((ImU64)1 << column_n)) != 0;
+ return ImMax(width_auto, table->MinColumnWidth);
}
-int ImGui::TableGetColumnCount()
+// 'width' = inner column width, without padding
+void ImGui::TableSetColumnWidth(int column_n, float width)
{
ImGuiContext& g = *GImGui;
ImGuiTable* table = g.CurrentTable;
- return table ? table->ColumnsCount : 0;
-}
+ IM_ASSERT(table != NULL && table->IsLayoutLocked == false);
+ IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount);
+ ImGuiTableColumn* column_0 = &table->Columns[column_n];
+ float column_0_width = width;
-const char* ImGui::TableGetColumnName(int column_n)
-{
- ImGuiContext& g = *GImGui;
- ImGuiTable* table = g.CurrentTable;
- if (!table)
- return NULL;
- if (column_n < 0)
- column_n = table->CurrentColumn;
- return TableGetColumnName(table, column_n);
-}
+ // Apply constraints early
+ // Compare both requested and actual given width to avoid overwriting requested width when column is stuck (minimum size, bounded)
+ IM_ASSERT(table->MinColumnWidth > 0.0f);
+ const float min_width = table->MinColumnWidth;
+ const float max_width = ImMax(min_width, TableGetMaxColumnWidth(table, column_n));
+ column_0_width = ImClamp(column_0_width, min_width, max_width);
+ if (column_0->WidthGiven == column_0_width || column_0->WidthRequest == column_0_width)
+ return;
-// We allow querying for an extra column in order to poll the IsHovered state of the right-most section
-ImGuiTableColumnFlags ImGui::TableGetColumnFlags(int column_n)
-{
- ImGuiContext& g = *GImGui;
- ImGuiTable* table = g.CurrentTable;
- if (!table)
- return ImGuiTableColumnFlags_None;
- if (column_n < 0)
- column_n = table->CurrentColumn;
- if (column_n == table->ColumnsCount)
- return (table->HoveredColumnBody == column_n) ? ImGuiTableColumnFlags_IsHovered : ImGuiTableColumnFlags_None;
- return table->Columns[column_n].Flags;
-}
+ //IMGUI_DEBUG_LOG("TableSetColumnWidth(%d, %.1f->%.1f)\n", column_0_idx, column_0->WidthGiven, column_0_width);
+ ImGuiTableColumn* column_1 = (column_0->NextEnabledColumn != -1) ? &table->Columns[column_0->NextEnabledColumn] : NULL;
-void ImGui::TableSetColumnIsEnabled(int column_n, bool hidden)
-{
- ImGuiContext& g = *GImGui;
- ImGuiTable* table = g.CurrentTable;
- IM_ASSERT(table != NULL && table->IsLayoutLocked == false);
- if (column_n < 0)
- column_n = table->CurrentColumn;
- IM_ASSERT(column_n >= 0 && column_n < table->ColumnsCount);
- table->Columns[column_n].IsEnabledNextFrame = !hidden;
-}
+ // In this surprisingly not simple because of how we support mixing Fixed and multiple Stretch columns.
+ // - All fixed: easy.
+ // - All stretch: easy.
+ // - One or more fixed + one stretch: easy.
+ // - One or more fixed + more than one stretch: tricky.
+ // Qt when manual resize is enabled only support a single _trailing_ stretch column.
-int ImGui::TableGetColumnIndex()
-{
- ImGuiContext& g = *GImGui;
- ImGuiTable* table = g.CurrentTable;
- if (!table)
- return 0;
- return table->CurrentColumn;
-}
+ // When forwarding resize from Wn| to Fn+1| we need to be considerate of the _NoResize flag on Fn+1.
+ // FIXME-TABLE: Find a way to rewrite all of this so interactions feel more consistent for the user.
+ // Scenarios:
+ // - F1 F2 F3 resize from F1| or F2| --> ok: alter ->WidthRequested of Fixed column. Subsequent columns will be offset.
+ // - F1 F2 F3 resize from F3| --> ok: alter ->WidthRequested of Fixed column. If active, ScrollX extent can be altered.
+ // - F1 F2 W3 resize from F1| or F2| --> ok: alter ->WidthRequested of Fixed column. If active, ScrollX extent can be altered, but it doesn't make much sense as the Stretch column will always be minimal size.
+ // - F1 F2 W3 resize from W3| --> ok: no-op (disabled by Resize Rule 1)
+ // - W1 W2 W3 resize from W1| or W2| --> ok
+ // - W1 W2 W3 resize from W3| --> ok: no-op (disabled by Resize Rule 1)
+ // - W1 F2 F3 resize from F3| --> ok: no-op (disabled by Resize Rule 1)
+ // - W1 F2 resize from F2| --> ok: no-op (disabled by Resize Rule 1)
+ // - W1 W2 F3 resize from W1| or W2| --> ok
+ // - W1 F2 W3 resize from W1| or F2| --> ok
+ // - F1 W2 F3 resize from W2| --> ok
+ // - F1 W3 F2 resize from W3| --> ok
+ // - W1 F2 F3 resize from W1| --> ok: equivalent to resizing |F2. F3 will not move.
+ // - W1 F2 F3 resize from F2| --> ok
+ // All resizes from a Wx columns are locking other columns.
-// Note: for row coloring we use ->RowBgColorCounter which is the same value without counting header rows
-int ImGui::TableGetRowIndex()
-{
- ImGuiContext& g = *GImGui;
- ImGuiTable* table = g.CurrentTable;
- if (!table)
- return 0;
- return table->CurrentRow;
-}
+ // Possible improvements:
+ // - W1 W2 W3 resize W1| --> to not be stuck, both W2 and W3 would stretch down. Seems possible to fix. Would be most beneficial to simplify resize of all-weighted columns.
+ // - W3 F1 F2 resize W3| --> to not be stuck past F1|, both F1 and F2 would need to stretch down, which would be lossy or ambiguous. Seems hard to fix.
-// Return the cell rectangle based on currently known height.
-// - Important: we generally don't know our row height until the end of the row, so Max.y will be incorrect in many situations.
-// The only case where this is correct is if we provided a min_row_height to TableNextRow() and don't go below it.
-// - Important: if ImGuiTableFlags_PadOuterX is set but ImGuiTableFlags_PadInnerX is not set, the outer-most left and right
-// columns report a small offset so their CellBgRect can extend up to the outer border.
-ImRect ImGui::TableGetCellBgRect(const ImGuiTable* table, int column_n)
-{
- const ImGuiTableColumn* column = &table->Columns[column_n];
- float x1 = column->MinX;
- float x2 = column->MaxX;
- if (column->PrevEnabledColumn == -1)
- x1 -= table->CellSpacingX1;
- if (column->NextEnabledColumn == -1)
- x2 += table->CellSpacingX2;
- return ImRect(x1, table->RowPosY1, x2, table->RowPosY2);
-}
+ // [Resize Rule 1] Can't resize from right of right-most visible column if there is any Stretch column. Implemented in TableUpdateLayout().
-const char* ImGui::TableGetColumnName(const ImGuiTable* table, int column_n)
-{
- const ImGuiTableColumn* column = &table->Columns[column_n];
- if (column->NameOffset == -1)
- return "";
- return &table->ColumnsNames.Buf[column->NameOffset];
-}
+ // If we have all Fixed columns OR resizing a Fixed column that doesn't come after a Stretch one, we can do an offsetting resize.
+ // This is the preferred resize path
+ if (column_0->Flags & ImGuiTableColumnFlags_WidthFixed)
+ if (!column_1 || table->LeftMostStretchedColumn == -1 || table->Columns[table->LeftMostStretchedColumn].DisplayOrder >= column_0->DisplayOrder)
+ {
+ column_0->WidthRequest = column_0_width;
+ table->IsSettingsDirty = true;
+ return;
+ }
-// Return the resizing ID for the right-side of the given column.
-ImGuiID ImGui::TableGetColumnResizeID(const ImGuiTable* table, int column_n, int instance_no)
-{
- IM_ASSERT(column_n < table->ColumnsCount);
- ImGuiID id = table->ID + 1 + (instance_no * table->ColumnsCount) + column_n;
- return id;
+ // We can also use previous column if there's no next one (this is used when doing an auto-fit on the right-most stretch column)
+ if (column_1 == NULL)
+ column_1 = (column_0->PrevEnabledColumn != -1) ? &table->Columns[column_0->PrevEnabledColumn] : NULL;
+ if (column_1 == NULL)
+ return;
+
+ // Resizing from right-side of a Stretch column before a Fixed column forward sizing to left-side of fixed column.
+ // (old_a + old_b == new_a + new_b) --> (new_a == old_a + old_b - new_b)
+ float column_1_width = ImMax(column_1->WidthRequest - (column_0_width - column_0->WidthRequest), min_width);
+ column_0_width = column_0->WidthRequest + column_1->WidthRequest - column_1_width;
+ IM_ASSERT(column_0_width > 0.0f && column_1_width > 0.0f);
+ column_0->WidthRequest = column_0_width;
+ column_1->WidthRequest = column_1_width;
+ if ((column_0->Flags | column_1->Flags) & ImGuiTableColumnFlags_WidthStretch)
+ TableUpdateColumnsWeightFromWidth(table);
+ table->IsSettingsDirty = true;
}
// Disable clipping then auto-fit, will take 2 frames
@@ -1871,9 +1990,7 @@ void ImGui::TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n)
if (!column->IsEnabled)
return;
column->CannotSkipItemsQueue = (1 << 0);
- column->AutoFitQueue = (1 << 1);
- if (column->Flags & ImGuiTableColumnFlags_WidthStretch)
- table->AutoFitSingleStretchColumn = (ImGuiTableColumnIdx)column_n;
+ table->AutoFitSingleColumn = (ImGuiTableColumnIdx)column_n;
}
void ImGui::TableSetColumnWidthAutoAll(ImGuiTable* table)
@@ -1881,62 +1998,39 @@ void ImGui::TableSetColumnWidthAutoAll(ImGuiTable* table)
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{
ImGuiTableColumn* column = &table->Columns[column_n];
- if (!column->IsEnabled)
+ if (!column->IsEnabled && !(column->Flags & ImGuiTableColumnFlags_WidthStretch)) // Cannot reset weight of hidden stretch column
continue;
column->CannotSkipItemsQueue = (1 << 0);
column->AutoFitQueue = (1 << 1);
}
}
-// Return -1 when table is not hovered. return columns_count if the unused space at the right of visible columns is hovered.
-int ImGui::TableGetHoveredColumn()
-{
- ImGuiContext& g = *GImGui;
- ImGuiTable* table = g.CurrentTable;
- if (!table)
- return -1;
- return (int)table->HoveredColumnBody;
-}
-
-void ImGui::TableSetBgColor(ImGuiTableBgTarget bg_target, ImU32 color, int column_n)
+void ImGui::TableUpdateColumnsWeightFromWidth(ImGuiTable* table)
{
- ImGuiContext& g = *GImGui;
- ImGuiTable* table = g.CurrentTable;
- IM_ASSERT(bg_target != ImGuiTableBgTarget_None);
+ IM_ASSERT(table->LeftMostStretchedColumn != -1 && table->RightMostStretchedColumn != -1);
- if (color == IM_COL32_DISABLE)
- color = 0;
-
- // We cannot draw neither the cell or row background immediately as we don't know the row height at this point in time.
- switch (bg_target)
- {
- case ImGuiTableBgTarget_CellBg:
+ // Measure existing quantity
+ float visible_weight = 0.0f;
+ float visible_width = 0.0f;
+ for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{
- if (table->RowPosY1 > table->InnerClipRect.Max.y) // Discard
- return;
- if (column_n == -1)
- column_n = table->CurrentColumn;
- if ((table->VisibleMaskByIndex & ((ImU64)1 << column_n)) == 0)
- return;
- if (table->RowCellDataCurrent < 0 || table->RowCellData[table->RowCellDataCurrent].Column != column_n)
- table->RowCellDataCurrent++;
- ImGuiTableCellData* cell_data = &table->RowCellData[table->RowCellDataCurrent];
- cell_data->BgColor = color;
- cell_data->Column = (ImGuiTableColumnIdx)column_n;
- break;
+ ImGuiTableColumn* column = &table->Columns[column_n];
+ if (!column->IsEnabled || !(column->Flags & ImGuiTableColumnFlags_WidthStretch))
+ continue;
+ IM_ASSERT(column->StretchWeight > 0.0f);
+ visible_weight += column->StretchWeight;
+ visible_width += column->WidthRequest;
}
- case ImGuiTableBgTarget_RowBg0:
- case ImGuiTableBgTarget_RowBg1:
+ IM_ASSERT(visible_weight > 0.0f && visible_width > 0.0f);
+
+ // Apply new weights
+ for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{
- if (table->RowPosY1 > table->InnerClipRect.Max.y) // Discard
- return;
- IM_ASSERT(column_n == -1);
- int bg_idx = (bg_target == ImGuiTableBgTarget_RowBg1) ? 1 : 0;
- table->RowBgColor[bg_idx] = color;
- break;
- }
- default:
- IM_ASSERT(0);
+ ImGuiTableColumn* column = &table->Columns[column_n];
+ if (!column->IsEnabled || !(column->Flags & ImGuiTableColumnFlags_WidthStretch))
+ continue;
+ column->StretchWeight = (column->WidthRequest / visible_width) * visible_weight;
+ IM_ASSERT(column->StretchWeight > 0.0f);
}
}
@@ -1950,6 +2044,8 @@ void ImGui::TableSetBgColor(ImGuiTableBgTarget bg_target, ImU32 color, int colum
// - TableDrawBorders() [Internal]
//-------------------------------------------------------------------------
+// Bg2 is used by Selectable (and possibly other widgets) to render to the background.
+// Unlike our Bg0/1 channel which we uses for RowBg/CellBg/Borders and where we guarantee all shapes to be CPU-clipped, the Bg2 channel being widgets-facing will rely on regular ClipRect.
void ImGui::TablePushBackgroundChannel()
{
ImGuiContext& g = *GImGui;
@@ -1957,9 +2053,9 @@ void ImGui::TablePushBackgroundChannel()
ImGuiTable* table = g.CurrentTable;
// Optimization: avoid SetCurrentChannel() + PushClipRect()
- table->HostBackupClipRect = window->ClipRect;
- SetWindowClipRectBeforeSetChannel(window, table->BgClipRectForDrawCmd);
- table->DrawSplitter.SetCurrentChannel(window->DrawList, table->Bg1DrawChannelCurrent);
+ table->HostBackupInnerClipRect = window->ClipRect;
+ SetWindowClipRectBeforeSetChannel(window, table->Bg2ClipRectForDrawCmd);
+ table->DrawSplitter.SetCurrentChannel(window->DrawList, table->Bg2DrawChannelCurrent);
}
void ImGui::TablePopBackgroundChannel()
@@ -1970,7 +2066,7 @@ void ImGui::TablePopBackgroundChannel()
ImGuiTableColumn* column = &table->Columns[table->CurrentColumn];
// Optimization: avoid PopClipRect() + SetCurrentChannel()
- SetWindowClipRectBeforeSetChannel(window, table->HostBackupClipRect);
+ SetWindowClipRectBeforeSetChannel(window, table->HostBackupInnerClipRect);
table->DrawSplitter.SetCurrentChannel(window->DrawList, column->DrawChannelCurrent);
}
@@ -1982,10 +2078,10 @@ void ImGui::TablePopBackgroundChannel()
// - After crossing FreezeRowsCount, all columns see their current draw channel changed to a second set of channels.
// - We only use the dummy draw channel so we can push a null clipping rectangle into it without affecting other
// channels, while simplifying per-row/per-cell overhead. It will be empty and discarded when merged.
-// - We allocate 1 or 2 background draw channels. This is because we know PushTableBackground() is only used for
+// - We allocate 1 or 2 background draw channels. This is because we know TablePushBackgroundChannel() is only used for
// horizontal spanning. If we allowed vertical spanning we'd need one background draw channel per merge group (1-4).
// Draw channel allocation (before merging):
-// - NoClip --> 2+D+1 channels: bg0 + bg1 + foreground (same clip rect == 1 draw call) (FIXME-TABLE: could merge bg1 and foreground?)
+// - NoClip --> 2+D+1 channels: bg0/1 + bg2 + foreground (same clip rect == always 1 draw call)
// - Clip --> 2+D+N channels
// - FreezeRows --> 2+D+N*2 (unless scrolling value is zero)
// - FreezeRows || FreezeColunns --> 3+D+N*2 (unless scrolling value is zero)
@@ -1999,8 +2095,8 @@ void ImGui::TableSetupDrawChannels(ImGuiTable* table)
const int channels_total = channels_for_bg + (channels_for_row * freeze_row_multiplier) + channels_for_dummy;
table->DrawSplitter.Split(table->InnerWindow->DrawList, channels_total);
table->DummyDrawChannel = (ImGuiTableDrawChannelIdx)((channels_for_dummy > 0) ? channels_total - 1 : -1);
- table->Bg1DrawChannelCurrent = TABLE_DRAW_CHANNEL_BG1_FROZEN;
- table->Bg1DrawChannelUnfrozen = (ImGuiTableDrawChannelIdx)((table->FreezeRowsCount > 0) ? 2 + channels_for_row : TABLE_DRAW_CHANNEL_BG1_FROZEN);
+ table->Bg2DrawChannelCurrent = TABLE_DRAW_CHANNEL_BG2_FROZEN;
+ table->Bg2DrawChannelUnfrozen = (ImGuiTableDrawChannelIdx)((table->FreezeRowsCount > 0) ? 2 + channels_for_row : TABLE_DRAW_CHANNEL_BG2_FROZEN);
int draw_channel_current = 2;
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
@@ -2019,6 +2115,14 @@ void ImGui::TableSetupDrawChannels(ImGuiTable* table)
}
column->DrawChannelCurrent = column->DrawChannelFrozen;
}
+
+ // Initial draw cmd starts with a BgClipRect that matches the one of its host, to facilitate merge draw commands by default.
+ // All our cell highlight are manually clipped with BgClipRect. When unfreezing it will be made smaller to fit scrolling rect.
+ // (This technically isn't part of setting up draw channels, but is reasonably related to be done here)
+ table->BgClipRect = table->InnerClipRect;
+ table->Bg0ClipRectForDrawCmd = table->OuterWindow->ClipRect;
+ table->Bg2ClipRectForDrawCmd = table->HostClipRect;
+ IM_ASSERT(table->BgClipRect.Min.y <= table->BgClipRect.Max.y);
}
// This function reorder draw channels based on matching clip rectangle, to facilitate merging them. Called by EndTable().
@@ -2056,6 +2160,7 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
ImDrawListSplitter* splitter = &table->DrawSplitter;
const bool has_freeze_v = (table->FreezeRowsCount > 0);
const bool has_freeze_h = (table->FreezeColumnsCount > 0);
+ IM_ASSERT(splitter->_Current == 0);
// Track which groups we are going to attempt to merge, and which channels goes into each group.
struct MergeGroup
@@ -2139,15 +2244,15 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
// 2. Rewrite channel list in our preferred order
if (merge_group_mask != 0)
{
- // We skip channel 0 (Bg0) and 1 (Bg1 frozen) from the shuffling since they won't move - see channels allocation in TableSetupDrawChannels().
+ // We skip channel 0 (Bg0/Bg1) and 1 (Bg2 frozen) from the shuffling since they won't move - see channels allocation in TableSetupDrawChannels().
const int LEADING_DRAW_CHANNELS = 2;
g.DrawChannelsTempMergeBuffer.resize(splitter->_Count - LEADING_DRAW_CHANNELS); // Use shared temporary storage so the allocation gets amortized
ImDrawChannel* dst_tmp = g.DrawChannelsTempMergeBuffer.Data;
ImBitArray<IMGUI_TABLE_MAX_DRAW_CHANNELS> remaining_mask; // We need 132-bit of storage
remaining_mask.ClearBits();
remaining_mask.SetBitRange(LEADING_DRAW_CHANNELS, splitter->_Count - 1);
- remaining_mask.ClearBit(table->Bg1DrawChannelUnfrozen);
- IM_ASSERT(has_freeze_v == false || table->Bg1DrawChannelUnfrozen != TABLE_DRAW_CHANNEL_BG1_FROZEN);
+ remaining_mask.ClearBit(table->Bg2DrawChannelUnfrozen);
+ IM_ASSERT(has_freeze_v == false || table->Bg2DrawChannelUnfrozen != TABLE_DRAW_CHANNEL_BG2_FROZEN);
int remaining_count = splitter->_Count - (has_freeze_v ? LEADING_DRAW_CHANNELS + 1 : LEADING_DRAW_CHANNELS);
//ImRect host_rect = (table->InnerWindow == table->OuterWindow) ? table->InnerClipRect : table->HostClipRect;
ImRect host_rect = table->HostClipRect;
@@ -2196,9 +2301,9 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
}
}
- // Make sure Bg1DrawChannelUnfrozen appears in the middle of our groups (whereas Bg0 and Bg1 frozen are fixed to 0 and 1)
+ // Make sure Bg2DrawChannelUnfrozen appears in the middle of our groups (whereas Bg0/Bg1 and Bg2 frozen are fixed to 0 and 1)
if (merge_group_n == 1 && has_freeze_v)
- memcpy(dst_tmp++, &splitter->_Channels[table->Bg1DrawChannelUnfrozen], sizeof(ImDrawChannel));
+ memcpy(dst_tmp++, &splitter->_Channels[table->Bg2DrawChannelUnfrozen], sizeof(ImDrawChannel));
}
// Append unmergeable channels that we didn't reorder at the end of the list
@@ -2219,19 +2324,18 @@ void ImGui::TableMergeDrawChannels(ImGuiTable* table)
void ImGui::TableDrawBorders(ImGuiTable* table)
{
ImGuiWindow* inner_window = table->InnerWindow;
- ImGuiWindow* outer_window = table->OuterWindow;
- table->DrawSplitter.SetCurrentChannel(inner_window->DrawList, TABLE_DRAW_CHANNEL_BG0);
if (inner_window->Hidden || !table->HostClipRect.Overlaps(table->InnerClipRect))
return;
+
ImDrawList* inner_drawlist = inner_window->DrawList;
- ImDrawList* outer_drawlist = outer_window->DrawList;
+ table->DrawSplitter.SetCurrentChannel(inner_drawlist, TABLE_DRAW_CHANNEL_BG0);
+ inner_drawlist->PushClipRect(table->Bg0ClipRectForDrawCmd.Min, table->Bg0ClipRectForDrawCmd.Max, false);
// Draw inner border and resizing feedback
const float border_size = TABLE_BORDER_SIZE;
- const float draw_y1 = table->OuterRect.Min.y;
- const float draw_y2_body = table->OuterRect.Max.y;
+ const float draw_y1 = table->InnerRect.Min.y;
+ const float draw_y2_body = table->InnerRect.Max.y;
const float draw_y2_head = table->IsUsingHeaders ? ((table->FreezeRowsCount >= 1 ? table->OuterRect.Min.y : table->WorkRect.Min.y) + table->LastFirstRowHeight) : draw_y1;
-
if (table->Flags & ImGuiTableFlags_BordersInnerV)
{
for (int order_n = 0; order_n < table->ColumnsCount; order_n++)
@@ -2244,11 +2348,13 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
const bool is_hovered = (table->HoveredColumnBorder == column_n);
const bool is_resized = (table->ResizedColumn == column_n) && (table->InstanceInteracted == table->InstanceCurrent);
const bool is_resizable = (column->Flags & (ImGuiTableColumnFlags_NoResize | ImGuiTableColumnFlags_NoDirectResize_)) == 0;
+ const bool is_frozen_separator = (table->FreezeColumnsCount != -1 && table->FreezeColumnsCount == order_n + 1);
- if (column->MaxX > table->InnerClipRect.Max.x && !is_resized)// && is_hovered)
+ if (column->MaxX > table->InnerClipRect.Max.x && !is_resized)
continue;
if (column->NextEnabledColumn == -1 && !is_resizable)
- continue;
+ if ((table->Flags & ImGuiTableFlags_SizingMask_) != ImGuiTableFlags_SizingFixedSame || table->IsOuterRectAutoFitX)
+ continue;
if (column->MaxX <= column->ClipRect.Min.x) // FIXME-TABLE FIXME-STYLE: Assume BorderSize==1, this is problematic if we want to increase the border size..
continue;
@@ -2256,7 +2362,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
// Always draw full height border when being resized/hovered, or on the delimitation of frozen column scrolling.
ImU32 col;
float draw_y2;
- if (is_hovered || is_resized || (table->FreezeColumnsCount != -1 && table->FreezeColumnsCount == order_n + 1))
+ if (is_hovered || is_resized || is_frozen_separator)
{
draw_y2 = draw_y2_body;
col = is_resized ? GetColorU32(ImGuiCol_SeparatorActive) : is_hovered ? GetColorU32(ImGuiCol_SeparatorHovered) : table->BorderColorStrong;
@@ -2273,7 +2379,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
}
// Draw outer border
- // FIXME-TABLE: could use AddRect or explicit VLine/HLine helper?
+ // FIXME: could use AddRect or explicit VLine/HLine helper?
if (table->Flags & ImGuiTableFlags_BordersOuter)
{
// Display outer border offset by 1 which is a simple way to display it without adding an extra draw call
@@ -2281,23 +2387,21 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
// parent. In inner_window, it won't reach out over scrollbars. Another weird solution would be to display part
// of it in inner window, and the part that's over scrollbars in the outer window..)
// Either solution currently won't allow us to use a larger border size: the border would clipped.
- ImRect outer_border = table->OuterRect;
+ const ImRect outer_border = table->OuterRect;
const ImU32 outer_col = table->BorderColorStrong;
- if (inner_window != outer_window) // FIXME-TABLE
- outer_border.Expand(1.0f);
if ((table->Flags & ImGuiTableFlags_BordersOuter) == ImGuiTableFlags_BordersOuter)
{
- outer_drawlist->AddRect(outer_border.Min, outer_border.Max, outer_col, 0.0f, ~0, border_size);
+ inner_drawlist->AddRect(outer_border.Min, outer_border.Max, outer_col, 0.0f, ~0, border_size);
}
else if (table->Flags & ImGuiTableFlags_BordersOuterV)
{
- outer_drawlist->AddLine(outer_border.Min, ImVec2(outer_border.Min.x, outer_border.Max.y), outer_col, border_size);
- outer_drawlist->AddLine(ImVec2(outer_border.Max.x, outer_border.Min.y), outer_border.Max, outer_col, border_size);
+ inner_drawlist->AddLine(outer_border.Min, ImVec2(outer_border.Min.x, outer_border.Max.y), outer_col, border_size);
+ inner_drawlist->AddLine(ImVec2(outer_border.Max.x, outer_border.Min.y), outer_border.Max, outer_col, border_size);
}
else if (table->Flags & ImGuiTableFlags_BordersOuterH)
{
- outer_drawlist->AddLine(outer_border.Min, ImVec2(outer_border.Max.x, outer_border.Min.y), outer_col, border_size);
- outer_drawlist->AddLine(ImVec2(outer_border.Min.x, outer_border.Max.y), outer_border.Max, outer_col, border_size);
+ inner_drawlist->AddLine(outer_border.Min, ImVec2(outer_border.Max.x, outer_border.Min.y), outer_col, border_size);
+ inner_drawlist->AddLine(ImVec2(outer_border.Min.x, outer_border.Max.y), outer_border.Max, outer_col, border_size);
}
}
if ((table->Flags & ImGuiTableFlags_BordersInnerH) && table->RowPosY2 < table->OuterRect.Max.y)
@@ -2307,6 +2411,8 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
if (border_y >= table->BgClipRect.Min.y && border_y < table->BgClipRect.Max.y)
inner_drawlist->AddLine(ImVec2(table->BorderX1, border_y), ImVec2(table->BorderX2, border_y), table->BorderColorLight, border_size);
}
+
+ inner_drawlist->PopClipRect();
}
//-------------------------------------------------------------------------
@@ -2314,6 +2420,7 @@ void ImGui::TableDrawBorders(ImGuiTable* table)
//-------------------------------------------------------------------------
// - TableGetSortSpecs()
// - TableFixColumnSortDirection() [Internal]
+// - TableGetColumnNextSortDirection() [Internal]
// - TableSetColumnSortDirection() [Internal]
// - TableSortSpecsSanitize() [Internal]
// - TableSortSpecsBuild() [Internal]
@@ -2339,22 +2446,39 @@ ImGuiTableSortSpecs* ImGui::TableGetSortSpecs()
if (table->IsSortSpecsDirty)
TableSortSpecsBuild(table);
- return table->SortSpecs.SpecsCount ? &table->SortSpecs : NULL;
+ return &table->SortSpecs;
}
-void ImGui::TableFixColumnSortDirection(ImGuiTableColumn* column)
+static inline ImGuiSortDirection TableGetColumnAvailSortDirection(ImGuiTableColumn* column, int n)
{
- // Initial sort state
- if (column->SortDirection == ImGuiSortDirection_None)
- column->SortDirection = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? (ImS8)ImGuiSortDirection_Descending : (ImS8)(ImGuiSortDirection_Ascending);
+ IM_ASSERT(n < column->SortDirectionsAvailCount);
+ return (column->SortDirectionsAvailList >> (n << 1)) & 0x03;
+}
- // Handle NoSortAscending/NoSortDescending
- if (column->SortDirection == ImGuiSortDirection_Ascending && (column->Flags & ImGuiTableColumnFlags_NoSortAscending))
- column->SortDirection = ImGuiSortDirection_Descending;
- else if (column->SortDirection == ImGuiSortDirection_Descending && (column->Flags & ImGuiTableColumnFlags_NoSortDescending))
- column->SortDirection = ImGuiSortDirection_Ascending;
+// Fix sort direction if currently set on a value which is unavailable (e.g. activating NoSortAscending/NoSortDescending)
+void ImGui::TableFixColumnSortDirection(ImGuiTable* table, ImGuiTableColumn* column)
+{
+ if (column->SortOrder == -1 || (column->SortDirectionsAvailMask & (1 << column->SortDirection)) != 0)
+ return;
+ column->SortDirection = (ImU8)TableGetColumnAvailSortDirection(column, 0);
+ table->IsSortSpecsDirty = true;
}
+// Calculate next sort direction that would be set after clicking the column
+// - If the PreferSortDescending flag is set, we will default to a Descending direction on the first click.
+// - Note that the PreferSortAscending flag is never checked, it is essentially the default and therefore a no-op.
+IM_STATIC_ASSERT(ImGuiSortDirection_None == 0 && ImGuiSortDirection_Ascending == 1 && ImGuiSortDirection_Descending == 2);
+ImGuiSortDirection ImGui::TableGetColumnNextSortDirection(ImGuiTableColumn* column)
+{
+ IM_ASSERT(column->SortDirectionsAvailCount > 0);
+ if (column->SortOrder == -1)
+ return TableGetColumnAvailSortDirection(column, 0);
+ for (int n = 0; n < 3; n++)
+ if (column->SortDirection == TableGetColumnAvailSortDirection(column, n))
+ return TableGetColumnAvailSortDirection(column, (n + 1) % column->SortDirectionsAvailCount);
+ IM_ASSERT(0);
+ return ImGuiSortDirection_None;
+}
// Note that the NoSortAscending/NoSortDescending flags are processed in TableSortSpecsSanitize(), and they may change/revert
// the value of SortDirection. We could technically also do it here but it would be unnecessary and duplicate code.
@@ -2363,8 +2487,10 @@ void ImGui::TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_di
ImGuiContext& g = *GImGui;
ImGuiTable* table = g.CurrentTable;
- if (!(table->Flags & ImGuiTableFlags_MultiSortable))
+ if (!(table->Flags & ImGuiTableFlags_SortMulti))
append_to_sort_specs = false;
+ if (!(table->Flags & ImGuiTableFlags_SortTristate))
+ IM_ASSERT(sort_direction != ImGuiSortDirection_None);
ImGuiTableColumnIdx sort_order_max = 0;
if (append_to_sort_specs)
@@ -2372,8 +2498,10 @@ void ImGui::TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_di
sort_order_max = ImMax(sort_order_max, table->Columns[other_column_n].SortOrder);
ImGuiTableColumn* column = &table->Columns[column_n];
- column->SortDirection = (ImS8)sort_direction;
- if (column->SortOrder == -1 || !append_to_sort_specs)
+ column->SortDirection = (ImU8)sort_direction;
+ if (column->SortDirection == ImGuiSortDirection_None)
+ column->SortOrder = -1;
+ else if (column->SortOrder == -1 || !append_to_sort_specs)
column->SortOrder = append_to_sort_specs ? sort_order_max + 1 : 0;
for (int other_column_n = 0; other_column_n < table->ColumnsCount; other_column_n++)
@@ -2381,7 +2509,7 @@ void ImGui::TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_di
ImGuiTableColumn* other_column = &table->Columns[other_column_n];
if (other_column != column && !append_to_sort_specs)
other_column->SortOrder = -1;
- TableFixColumnSortDirection(other_column);
+ TableFixColumnSortDirection(table, other_column);
}
table->IsSettingsDirty = true;
table->IsSortSpecsDirty = true;
@@ -2407,7 +2535,7 @@ void ImGui::TableSortSpecsSanitize(ImGuiTable* table)
}
const bool need_fix_linearize = ((ImU64)1 << sort_order_count) != (sort_order_mask + 1);
- const bool need_fix_single_sort_order = (sort_order_count > 1) && !(table->Flags & ImGuiTableFlags_MultiSortable);
+ const bool need_fix_single_sort_order = (sort_order_count > 1) && !(table->Flags & ImGuiTableFlags_SortMulti);
if (need_fix_linearize || need_fix_single_sort_order)
{
ImU64 fixed_mask = 0x00;
@@ -2437,7 +2565,7 @@ void ImGui::TableSortSpecsSanitize(ImGuiTable* table)
}
// Fallback default sort order (if no column had the ImGuiTableColumnFlags_DefaultSort flag)
- if (sort_order_count == 0)
+ if (sort_order_count == 0 && !(table->Flags & ImGuiTableFlags_SortTristate))
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{
ImGuiTableColumn* column = &table->Columns[column_n];
@@ -2445,7 +2573,7 @@ void ImGui::TableSortSpecsSanitize(ImGuiTable* table)
{
sort_order_count = 1;
column->SortOrder = 0;
- TableFixColumnSortDirection(column);
+ column->SortDirection = (ImU8)TableGetColumnAvailSortDirection(column, 0);
break;
}
}
@@ -2459,9 +2587,8 @@ void ImGui::TableSortSpecsBuild(ImGuiTable* table)
TableSortSpecsSanitize(table);
// Write output
- const bool single_sort_specs = (table->SortSpecsCount <= 1);
- table->SortSpecsMulti.resize(single_sort_specs ? 0 : table->SortSpecsCount);
- ImGuiTableColumnSortSpecs* sort_specs = single_sort_specs ? &table->SortSpecsSingle : table->SortSpecsMulti.Data;
+ table->SortSpecsMulti.resize(table->SortSpecsCount <= 1 ? 0 : table->SortSpecsCount);
+ ImGuiTableColumnSortSpecs* sort_specs = (table->SortSpecsCount == 0) ? NULL : (table->SortSpecsCount == 1) ? &table->SortSpecsSingle : table->SortSpecsMulti.Data;
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
{
ImGuiTableColumn* column = &table->Columns[column_n];
@@ -2515,6 +2642,10 @@ void ImGui::TableHeadersRow()
ImGuiTable* table = g.CurrentTable;
IM_ASSERT(table != NULL && "Need to call TableHeadersRow() after BeginTable()!");
+ // Layout if not already done (this is automatically done by TableNextRow, we do it here solely to facilitate stepping in debugger as it is frequent to step in TableUpdateLayout)
+ if (!table->IsLayoutLocked)
+ TableUpdateLayout(table);
+
// Open row
const float row_y1 = GetCursorScreenPos().y;
const float row_height = TableGetHeaderRowHeight();
@@ -2547,7 +2678,6 @@ void ImGui::TableHeadersRow()
// Emit a column header (text + optional sort order)
// We cpu-clip text here so that all columns headers can be merged into a same draw call.
// Note that because of how we cpu-clip and display sorting indicators, you _cannot_ use SameLine() after a TableHeader()
-// FIXME-TABLE: Style confusion between CellPadding.y and FramePadding.y
void ImGui::TableHeader(const char* label)
{
ImGuiContext& g = *GImGui;
@@ -2569,10 +2699,30 @@ void ImGui::TableHeader(const char* label)
ImVec2 label_pos = window->DC.CursorPos;
// If we already got a row height, there's use that.
- // FIXME-TABLE-PADDING: Problem if the correct outer-padding CellBgRect strays off our ClipRect
+ // FIXME-TABLE: Padding problem if the correct outer-padding CellBgRect strays off our ClipRect?
ImRect cell_r = TableGetCellBgRect(table, column_n);
float label_height = ImMax(label_size.y, table->RowMinHeight - table->CellPaddingY * 2.0f);
+ // Calculate ideal size for sort order arrow
+ float w_arrow = 0.0f;
+ float w_sort_text = 0.0f;
+ char sort_order_suf[4] = "";
+ const float ARROW_SCALE = 0.65f;
+ if ((table->Flags & ImGuiTableFlags_Sortable) && !(column->Flags & ImGuiTableColumnFlags_NoSort))
+ {
+ w_arrow = ImFloor(g.FontSize * ARROW_SCALE + g.Style.FramePadding.x);
+ if (column->SortOrder > 0)
+ {
+ ImFormatString(sort_order_suf, IM_ARRAYSIZE(sort_order_suf), "%d", column->SortOrder + 1);
+ w_sort_text = g.Style.ItemInnerSpacing.x + CalcTextSize(sort_order_suf).x;
+ }
+ }
+
+ // We feed our unclipped width to the column without writing on CursorMaxPos, so that column is still considering for merging.
+ float max_pos_x = label_pos.x + label_size.x + w_sort_text + w_arrow;
+ column->ContentMaxXHeadersUsed = ImMax(column->ContentMaxXHeadersUsed, column->WorkMaxX);
+ column->ContentMaxXHeadersIdeal = ImMax(column->ContentMaxXHeadersIdeal, max_pos_x);
+
// Keep header highlighted when context menu is open.
const bool selected = (table->IsContextPopupOpen && table->ContextPopupColumn == column_n && table->InstanceInteracted == table->InstanceCurrent);
ImGuiID id = window->GetID(label);
@@ -2584,15 +2734,24 @@ void ImGui::TableHeader(const char* label)
//GetForegroundDrawList()->AddRect(cell_r.Min, cell_r.Max, IM_COL32(255, 0, 0, 255)); // [DEBUG]
//GetForegroundDrawList()->AddRect(bb.Min, bb.Max, IM_COL32(255, 0, 0, 255)); // [DEBUG]
+ // Using AllowItemOverlap mode because we cover the whole cell, and we want user to be able to submit subsequent items.
bool hovered, held;
- bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_None);
- if (hovered || selected)
+ bool pressed = ButtonBehavior(bb, id, &hovered, &held, ImGuiButtonFlags_AllowItemOverlap);
+ if (g.ActiveId != id)
+ SetItemAllowOverlap();
+ if (held || hovered || selected)
{
const ImU32 col = GetColorU32(held ? ImGuiCol_HeaderActive : hovered ? ImGuiCol_HeaderHovered : ImGuiCol_Header);
//RenderFrame(bb.Min, bb.Max, col, false, 0.0f);
TableSetBgColor(ImGuiTableBgTarget_CellBg, col, table->CurrentColumn);
RenderNavHighlight(bb, id, ImGuiNavHighlightFlags_TypeThin | ImGuiNavHighlightFlags_NoRounding);
}
+ else
+ {
+ // Submit single cell bg color in the case we didn't submit a full header row
+ if ((table->RowFlags & ImGuiTableRowFlags_Headers) == 0)
+ TableSetBgColor(ImGuiTableBgTarget_CellBg, GetColorU32(ImGuiCol_TableHeaderBg), table->CurrentColumn);
+ }
if (held)
table->HeldHeaderColumn = (ImGuiTableColumnIdx)column_n;
window->DC.CursorPos.y -= g.Style.ItemSpacing.y * 0.5f;
@@ -2619,28 +2778,13 @@ void ImGui::TableHeader(const char* label)
}
// Sort order arrow
- float w_arrow = 0.0f;
- float w_sort_text = 0.0f;
- float ellipsis_max = cell_r.Max.x;
+ const float ellipsis_max = cell_r.Max.x - w_arrow - w_sort_text;
if ((table->Flags & ImGuiTableFlags_Sortable) && !(column->Flags & ImGuiTableColumnFlags_NoSort))
{
- const float ARROW_SCALE = 0.65f;
- w_arrow = ImFloor(g.FontSize * ARROW_SCALE + g.Style.FramePadding.x);// table->CellPadding.x);
if (column->SortOrder != -1)
{
- char sort_order_suf[8];
- w_sort_text = 0.0f;
- if (column->SortOrder > 0)
- {
- ImFormatString(sort_order_suf, IM_ARRAYSIZE(sort_order_suf), "%d", column->SortOrder + 1);
- w_sort_text = g.Style.ItemInnerSpacing.x + CalcTextSize(sort_order_suf).x;
- }
-
float x = ImMax(cell_r.Min.x, cell_r.Max.x - w_arrow - w_sort_text);
- ellipsis_max -= w_arrow + w_sort_text;
-
float y = label_pos.y;
- ImU32 col = GetColorU32(ImGuiCol_Text);
if (column->SortOrder > 0)
{
PushStyleColor(ImGuiCol_Text, GetColorU32(ImGuiCol_Text, 0.70f));
@@ -2648,20 +2792,13 @@ void ImGui::TableHeader(const char* label)
PopStyleColor();
x += w_sort_text;
}
- RenderArrow(window->DrawList, ImVec2(x, y), col, column->SortDirection == ImGuiSortDirection_Ascending ? ImGuiDir_Up : ImGuiDir_Down, ARROW_SCALE);
+ RenderArrow(window->DrawList, ImVec2(x, y), GetColorU32(ImGuiCol_Text), column->SortDirection == ImGuiSortDirection_Ascending ? ImGuiDir_Up : ImGuiDir_Down, ARROW_SCALE);
}
// Handle clicking on column header to adjust Sort Order
if (pressed && table->ReorderColumn != column_n)
{
- // Set new sort direction
- // - If the PreferSortDescending flag is set, we will default to a Descending direction on the first click.
- // - Note that the PreferSortAscending flag is never checked, it is essentially the default and therefore a no-op.
- ImGuiSortDirection sort_direction;
- if (column->SortOrder == -1)
- sort_direction = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending) ? ImGuiSortDirection_Descending : ImGuiSortDirection_Ascending;
- else
- sort_direction = (column->SortDirection == ImGuiSortDirection_Ascending) ? ImGuiSortDirection_Descending : ImGuiSortDirection_Ascending;
+ ImGuiSortDirection sort_direction = TableGetColumnNextSortDirection(column);
TableSetColumnSortDirection(column_n, sort_direction, g.IO.KeyShift);
}
}
@@ -2675,11 +2812,6 @@ void ImGui::TableHeader(const char* label)
if (text_clipped && hovered && g.HoveredIdNotActiveTimer > g.TooltipSlowDelay)
SetTooltip("%.*s", (int)(label_end - label), label);
- // We feed our unclipped width to the column without writing on CursorMaxPos, so that column is still considering for merging.
- float max_pos_x = label_pos.x + label_size.x + w_sort_text + w_arrow;
- column->ContentMaxXHeadersUsed = ImMax(column->ContentMaxXHeadersUsed, column->WorkMaxX);
- column->ContentMaxXHeadersIdeal = ImMax(column->ContentMaxXHeadersIdeal, max_pos_x);
-
// We don't use BeginPopupContextItem() because we want the popup to stay up even after the column is hidden
if (IsMouseReleased(1) && IsItemHovered())
TableOpenContextMenu(column_n);
@@ -2731,17 +2863,15 @@ void ImGui::TableDrawContextMenu(ImGuiTable* table)
if (column != NULL)
{
const bool can_resize = !(column->Flags & ImGuiTableColumnFlags_NoResize) && column->IsEnabled;
- if (MenuItem("Size column to fit", NULL, false, can_resize))
+ if (MenuItem("Size column to fit###SizeOne", NULL, false, can_resize))
TableSetColumnWidthAutoSingle(table, column_n);
}
const char* size_all_desc;
- if (table->ColumnsEnabledFixedCount == table->ColumnsEnabledCount)
+ if (table->ColumnsEnabledFixedCount == table->ColumnsEnabledCount && (table->Flags & ImGuiTableFlags_SizingMask_) != ImGuiTableFlags_SizingFixedSame)
size_all_desc = "Size all columns to fit###SizeAll"; // All fixed
- else if (table->ColumnsEnabledFixedCount == 0)
- size_all_desc = "Size all columns to default###SizeAll"; // All stretch
else
- size_all_desc = "Size all columns to fit/default###SizeAll";// Mixed
+ size_all_desc = "Size all columns to default###SizeAll"; // All stretch or mixed
if (MenuItem(size_all_desc, NULL))
TableSetColumnWidthAutoAll(table);
want_separator = true;
@@ -2972,6 +3102,7 @@ void ImGui::TableLoadSettings(ImGuiTable* table)
// Serialize ImGuiTableSettings/ImGuiTableColumnSettings into ImGuiTable/ImGuiTableColumn
ImGuiTableColumnSettings* column_settings = settings->GetColumnSettings();
+ ImU64 display_order_mask = 0;
for (int data_n = 0; data_n < settings->ColumnsCount; data_n++, column_settings++)
{
int column_n = column_settings->Index;
@@ -2991,12 +3122,19 @@ void ImGui::TableLoadSettings(ImGuiTable* table)
column->DisplayOrder = column_settings->DisplayOrder;
else
column->DisplayOrder = (ImGuiTableColumnIdx)column_n;
+ display_order_mask |= (ImU64)1 << column->DisplayOrder;
column->IsEnabled = column->IsEnabledNextFrame = column_settings->IsEnabled;
column->SortOrder = column_settings->SortOrder;
column->SortDirection = column_settings->SortDirection;
}
- // FIXME-TABLE: Need to validate .ini data
+ // Validate and fix invalid display order data
+ const ImU64 expected_display_order_mask = (settings->ColumnsCount == 64) ? ~0 : ((ImU64)1 << settings->ColumnsCount) - 1;
+ if (display_order_mask != expected_display_order_mask)
+ for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
+ table->Columns[column_n].DisplayOrder = (ImGuiTableColumnIdx)column_n;
+
+ // Rebuild index
for (int column_n = 0; column_n < table->ColumnsCount; column_n++)
table->DisplayOrderToIndex[table->Columns[column_n].DisplayOrder] = (ImGuiTableColumnIdx)column_n;
}
@@ -3182,6 +3320,16 @@ void ImGui::TableGcCompactSettings()
#ifndef IMGUI_DISABLE_METRICS_WINDOW
+static const char* DebugNodeTableGetSizingPolicyDesc(ImGuiTableFlags sizing_policy)
+{
+ sizing_policy &= ImGuiTableFlags_SizingMask_;
+ if (sizing_policy == ImGuiTableFlags_SizingFixedFit) { return "FixedFit"; }
+ if (sizing_policy == ImGuiTableFlags_SizingFixedSame) { return "FixedSame"; }
+ if (sizing_policy == ImGuiTableFlags_SizingStretchProp) { return "StretchProp"; }
+ if (sizing_policy == ImGuiTableFlags_SizingStretchSame) { return "StretchSame"; }
+ return "N/A";
+}
+
void ImGui::DebugNodeTable(ImGuiTable* table)
{
char buf[512];
@@ -3194,35 +3342,41 @@ void ImGui::DebugNodeTable(ImGuiTable* table)
if (!is_active) { PopStyleColor(); }
if (IsItemHovered())
GetForegroundDrawList()->AddRect(table->OuterRect.Min, table->OuterRect.Max, IM_COL32(255, 255, 0, 255));
+ if (IsItemVisible() && table->HoveredColumnBody != -1)
+ GetForegroundDrawList()->AddRect(GetItemRectMin(), GetItemRectMax(), IM_COL32(255, 255, 0, 255));
if (!open)
return;
bool clear_settings = SmallButton("Clear settings");
- BulletText("OuterRect: Pos: (%.1f,%.1f) Size: (%.1f,%.1f)", table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.GetWidth(), table->OuterRect.GetHeight());
- BulletText("ColumnsWidth: %.1f, AutoFitWidth: %.1f, InnerWidth: %.1f%s", table->ColumnsTotalWidth, table->ColumnsAutoFitWidth, table->InnerWidth, table->InnerWidth == 0.0f ? " (auto)" : "");
+ BulletText("OuterRect: Pos: (%.1f,%.1f) Size: (%.1f,%.1f) Sizing: '%s'", table->OuterRect.Min.x, table->OuterRect.Min.y, table->OuterRect.GetWidth(), table->OuterRect.GetHeight(), DebugNodeTableGetSizingPolicyDesc(table->Flags));
+ BulletText("ColumnsGivenWidth: %.1f, ColumnsAutoFitWidth: %.1f, InnerWidth: %.1f%s", table->ColumnsGivenWidth, table->ColumnsAutoFitWidth, table->InnerWidth, table->InnerWidth == 0.0f ? " (auto)" : "");
BulletText("CellPaddingX: %.1f, CellSpacingX: %.1f/%.1f, OuterPaddingX: %.1f", table->CellPaddingX, table->CellSpacingX1, table->CellSpacingX2, table->OuterPaddingX);
BulletText("HoveredColumnBody: %d, HoveredColumnBorder: %d", table->HoveredColumnBody, table->HoveredColumnBorder);
BulletText("ResizedColumn: %d, ReorderColumn: %d, HeldHeaderColumn: %d", table->ResizedColumn, table->ReorderColumn, table->HeldHeaderColumn);
//BulletText("BgDrawChannels: %d/%d", 0, table->BgDrawChannelUnfrozen);
+ float sum_weights = 0.0f;
+ for (int n = 0; n < table->ColumnsCount; n++)
+ if (table->Columns[n].Flags & ImGuiTableColumnFlags_WidthStretch)
+ sum_weights += table->Columns[n].StretchWeight;
for (int n = 0; n < table->ColumnsCount; n++)
{
ImGuiTableColumn* column = &table->Columns[n];
const char* name = TableGetColumnName(table, n);
ImFormatString(buf, IM_ARRAYSIZE(buf),
- "Column %d order %d name '%s': offset %+.2f to %+.2f\n"
+ "Column %d order %d '%s': offset %+.2f to %+.2f%s\n"
"Enabled: %d, VisibleX/Y: %d/%d, RequestOutput: %d, SkipItems: %d, DrawChannels: %d,%d\n"
- "WidthGiven: %.1f, Request/Auto: %.1f/%.1f, StretchWeight: %.3f\n"
+ "WidthGiven: %.1f, Request/Auto: %.1f/%.1f, StretchWeight: %.3f (%.1f%%)\n"
"MinX: %.1f, MaxX: %.1f (%+.1f), ClipRect: %.1f to %.1f (+%.1f)\n"
"ContentWidth: %.1f,%.1f, HeadersUsed/Ideal %.1f/%.1f\n"
"Sort: %d%s, UserID: 0x%08X, Flags: 0x%04X: %s%s%s%s..",
- n, column->DisplayOrder, name, column->MinX - table->WorkRect.Min.x, column->MaxX - table->WorkRect.Min.x,
+ n, column->DisplayOrder, name, column->MinX - table->WorkRect.Min.x, column->MaxX - table->WorkRect.Min.x, (n < table->FreezeColumnsRequest) ? " (Frozen)" : "",
column->IsEnabled, column->IsVisibleX, column->IsVisibleY, column->IsRequestOutput, column->IsSkipItems, column->DrawChannelFrozen, column->DrawChannelUnfrozen,
- column->WidthGiven, column->WidthRequest, column->WidthAuto, column->StretchWeight,
+ column->WidthGiven, column->WidthRequest, column->WidthAuto, column->StretchWeight, column->StretchWeight > 0.0f ? (column->StretchWeight / sum_weights) * 100.0f : 0.0f,
column->MinX, column->MaxX, column->MaxX - column->MinX, column->ClipRect.Min.x, column->ClipRect.Max.x, column->ClipRect.Max.x - column->ClipRect.Min.x,
column->ContentMaxXFrozen - column->WorkMinX, column->ContentMaxXUnfrozen - column->WorkMinX, column->ContentMaxXHeadersUsed - column->WorkMinX, column->ContentMaxXHeadersIdeal - column->WorkMinX,
column->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? " (Asc)" : (column->SortDirection == ImGuiSortDirection_Descending) ? " (Des)" : "", column->UserID, column->Flags,
(column->Flags & ImGuiTableColumnFlags_WidthStretch) ? "WidthStretch " : "",
(column->Flags & ImGuiTableColumnFlags_WidthFixed) ? "WidthFixed " : "",
- (column->Flags & ImGuiTableColumnFlags_WidthAutoResize) ? "WidthAutoResize " : "",
+ (column->Flags & ImGuiTableColumnFlags_WidthAuto) ? "WidthAuto " : "",
(column->Flags & ImGuiTableColumnFlags_NoResize) ? "NoResize " : "");
Bullet();
Selectable(buf);
@@ -3269,6 +3423,8 @@ void ImGui::DebugNodeTableSettings(ImGuiTableSettings*) {}
// [SECTION] Columns, BeginColumns, EndColumns, etc.
// (This is a legacy API, prefer using BeginTable/EndTable!)
//-------------------------------------------------------------------------
+// FIXME: sizing is lossy when columns width is very small (default width may turn negative etc.)
+//-------------------------------------------------------------------------
// - SetWindowClipRectBeforeSetChannel() [Internal]
// - GetColumnIndex()
// - GetColumnsCount()
diff --git a/imgui/imgui_widgets.cpp b/imgui/imgui_widgets.cpp
index 4d232fbc..3bf7254f 100644
--- a/imgui/imgui_widgets.cpp
+++ b/imgui/imgui_widgets.cpp
@@ -1070,7 +1070,10 @@ bool ImGui::Checkbox(const char* label, bool* v)
const ImRect total_bb(pos, pos + ImVec2(square_sz + (label_size.x > 0.0f ? style.ItemInnerSpacing.x + label_size.x : 0.0f), label_size.y + style.FramePadding.y * 2.0f));
ItemSize(total_bb, style.FramePadding.y);
if (!ItemAdd(total_bb, id))
+ {
+ IMGUI_TEST_ENGINE_ITEM_INFO(id, label, window->DC.ItemFlags | ImGuiItemStatusFlags_Checkable | (*v ? ImGuiItemStatusFlags_Checked : 0));
return false;
+ }
bool hovered, held;
bool pressed = ButtonBehavior(total_bb, id, &hovered, &held);
@@ -1146,6 +1149,16 @@ bool ImGui::CheckboxFlags(const char* label, unsigned int* flags, unsigned int f
return CheckboxFlagsT(label, flags, flags_value);
}
+bool ImGui::CheckboxFlags(const char* label, ImS64* flags, ImS64 flags_value)
+{
+ return CheckboxFlagsT(label, flags, flags_value);
+}
+
+bool ImGui::CheckboxFlags(const char* label, ImU64* flags, ImU64 flags_value)
+{
+ return CheckboxFlagsT(label, flags, flags_value);
+}
+
bool ImGui::RadioButton(const char* label, bool active)
{
ImGuiWindow* window = GetCurrentWindow();
@@ -1707,6 +1720,9 @@ bool ImGui::Combo(const char* label, int* current_item, bool (*items_getter)(voi
}
EndCombo();
+ if (value_changed)
+ MarkItemEdited(g.CurrentWindow->DC.LastItemId);
+
return value_changed;
}
@@ -6159,7 +6175,9 @@ bool ImGui::ListBoxHeader(const char* label, int items_count, int height_in_item
// FIXME: In principle this function should be called EndListBox(). We should rename it after re-evaluating if we want to keep the same signature.
void ImGui::ListBoxFooter()
{
- ImGuiWindow* parent_window = GetCurrentWindow()->ParentWindow;
+ ImGuiWindow * window = GetCurrentWindow();
+ IM_ASSERT((window->Flags & ImGuiWindowFlags_ChildWindow) && "Mismatched ListBoxHeader/ListBoxFooter calls. Did you test the return value of ListBoxHeader()?");
+ ImGuiWindow* parent_window = window->ParentWindow;
const ImRect bb = parent_window->DC.LastItemRect;
const ImGuiStyle& style = GetStyle();
@@ -7756,7 +7774,7 @@ bool ImGui::TabItemEx(ImGuiTabBar* tab_bar, const char* label, bool* p_open,
g.ActiveIdWindow = docked_window;
// Allow the close button to overlap unless we are dragging (in which case we don't want any overlapping tabs to be hovered)
- if (!held)
+ if (g.ActiveId != id)
SetItemAllowOverlap();
// Drag and drop a single floating window node moves it