Merge branch 'master' into docking # Conflicts: # imgui.cpp # imgui_internal.h
diff --git a/.github/workflows/build.yml b/.github/workflows/build.yml index 9bc81bf..a4d3ed4 100644 --- a/.github/workflows/build.yml +++ b/.github/workflows/build.yml
@@ -25,8 +25,8 @@ working-directory: ${{ github.workspace }}/imgui env: - VS_PATH: C:\Program Files\Microsoft Visual Studio\2022\Enterprise\ - MSBUILD_PATH: C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\ + VS_PATH: C:\Program Files\Microsoft Visual Studio\18\Enterprise + MSBUILD_PATH: C:\Program Files\Microsoft Visual Studio\18\Enterprise\MSBuild\Current\Bin\ steps: - uses: actions/checkout@v6 with: @@ -667,7 +667,7 @@ working-directory: ${{ github.workspace }}/imgui env: - MSBUILD_PATH: C:\Program Files\Microsoft Visual Studio\2022\Enterprise\MSBuild\Current\Bin\ + MSBUILD_PATH: C:\Program Files\Microsoft Visual Studio\18\Enterprise\MSBuild\Current\Bin\ steps: - uses: actions/checkout@v6
diff --git a/docs/CHANGELOG.txt b/docs/CHANGELOG.txt index 3eeee92..37d197a 100644 --- a/docs/CHANGELOG.txt +++ b/docs/CHANGELOG.txt
@@ -55,6 +55,12 @@ - InputText: - Added `style.InputTextCursorSize` to configure cursor/caret thickness. (#7031, #9409) This is automatically scaled by `style.ScaleAllSizes()`. +- Tables: + - Context Menu: added a "Reset" sub-menu with a "Reset Visibility" option. + (which is greyed out when using default settings) + - Headers: fixed label being clipped early to reserve space for a sort marker + even when no sort marker is displayed. Auto-fitting a column still accounts + for the possible marker, so that sorting after an auto-fit doesn't clip the label. - Fonts: - Added `IMGUI_DISABLE_DEFAULT_FONT_BITMAP`/`IMGUI_DISABLE_DEFAULT_FONT_VECTOR` to disable embedding either fonts separately. (#9407) @@ -74,6 +80,8 @@ - Demo: - Extract 'Widgets->Tree Nodes->Selectable Nodes' out of the 'Advanced' demo for clarity (manual reimplementation of basic selection). +- Misc: + - Added IM_DEBUG_BREAK() handler for GCC+AArch64/ARM64. [@tom-seddon] - Backends: - OpenGL3: - GLSL version detection assume GLSL 410 when GL context is 4.1.
diff --git a/examples/example_glfw_wgpu/CMakeLists.txt b/examples/example_glfw_wgpu/CMakeLists.txt index 287a89d..4eaaee7 100644 --- a/examples/example_glfw_wgpu/CMakeLists.txt +++ b/examples/example_glfw_wgpu/CMakeLists.txt
@@ -37,7 +37,7 @@ set(CMAKE_BUILD_TYPE Debug CACHE STRING "" FORCE) endif() -set(CMAKE_CXX_STANDARD 17) # Dawn requires C++17 +set(CMAKE_CXX_STANDARD 20) # Dawn requires C++20 # Dear ImGui set(IMGUI_DIR ../../)
diff --git a/examples/example_sdl2_wgpu/CMakeLists.txt b/examples/example_sdl2_wgpu/CMakeLists.txt index efe35ff..8795070 100644 --- a/examples/example_sdl2_wgpu/CMakeLists.txt +++ b/examples/example_sdl2_wgpu/CMakeLists.txt
@@ -37,7 +37,7 @@ set(CMAKE_BUILD_TYPE Debug CACHE STRING "" FORCE) endif() -set(CMAKE_CXX_STANDARD 17) # Dawn requires C++17 +set(CMAKE_CXX_STANDARD 10) # Dawn requires C++20 # Dear ImGui set(IMGUI_DIR ../../)
diff --git a/examples/example_sdl3_wgpu/CMakeLists.txt b/examples/example_sdl3_wgpu/CMakeLists.txt index dd7b1e4..21a72bd 100644 --- a/examples/example_sdl3_wgpu/CMakeLists.txt +++ b/examples/example_sdl3_wgpu/CMakeLists.txt
@@ -37,7 +37,7 @@ set(CMAKE_BUILD_TYPE Debug CACHE STRING "" FORCE) endif() -set(CMAKE_CXX_STANDARD 17) # Dawn requires C++17 +set(CMAKE_CXX_STANDARD 20) # Dawn requires C++20 # Dear ImGui set(IMGUI_DIR ../../)
diff --git a/imconfig.h b/imconfig.h index 0a4ca08..851a44b 100644 --- a/imconfig.h +++ b/imconfig.h
@@ -55,7 +55,7 @@ //#define IMGUI_DISABLE_SSE // Disable use of SSE intrinsics even if available //---- Enable Test Engine / Automation features. -//#define IMGUI_ENABLE_TEST_ENGINE // Enable imgui_test_engine hooks. Generally set automatically by include "imgui_te_config.h", see Test Engine for details. +//#define IMGUI_ENABLE_TEST_ENGINE // Enable imgui_test_engine hooks. Generally set automatically by include "imgui_te_imconfig.h", see Test Engine for details. //---- Include imgui_user.h at the end of imgui.h as a convenience // May be convenient for some users to only explicitly include vanilla imgui.h and have extra stuff included.
diff --git a/imgui.cpp b/imgui.cpp index 9262002..0bade02 100644 --- a/imgui.cpp +++ b/imgui.cpp
@@ -4235,7 +4235,10 @@ { ImGuiLocKey_TableSizeOne, "Size column to fit###SizeOne" }, { ImGuiLocKey_TableSizeAllFit, "Size all columns to fit###SizeAll" }, { ImGuiLocKey_TableSizeAllDefault, "Size all columns to default###SizeAll" }, + { ImGuiLocKey_TableReset, "Reset" }, + //{ ImGuiLocKey_TableResetAll, "Reset to default###ResetAll" }, { ImGuiLocKey_TableResetOrder, "Reset order###ResetOrder" }, + { ImGuiLocKey_TableResetVisibility, "Reset visibility###ResetVisibility" }, { ImGuiLocKey_WindowingMainMenuBar, "(Main menu bar)" }, { ImGuiLocKey_WindowingPopup, "(Popup)" }, { ImGuiLocKey_WindowingUntitled, "(Untitled)" }, @@ -22776,7 +22779,7 @@ if (TreeNode("SettingsTables", "Settings packed data: Tables: %d bytes", g.SettingsTables.size())) { for (ImGuiTableSettings* settings = g.SettingsTables.begin(); settings != NULL; settings = g.SettingsTables.next_chunk(settings)) - DebugNodeTableSettings(settings); + DebugNodeTableSettings(settings, NULL); TreePop(); } @@ -23886,6 +23889,7 @@ ShowDebugLogFlag("Nav", ImGuiDebugLogFlags_EventNav); ShowDebugLogFlag("Popup", ImGuiDebugLogFlags_EventPopup); ShowDebugLogFlag("Selection", ImGuiDebugLogFlags_EventSelection); + ShowDebugLogFlag("Table", ImGuiDebugLogFlags_EventTable); ShowDebugLogFlag("Viewport", ImGuiDebugLogFlags_EventViewport); ShowDebugLogFlag("InputRouting", ImGuiDebugLogFlags_EventInputRouting);
diff --git a/imgui.h b/imgui.h index 1fa4a10..7c3c01f 100644 --- a/imgui.h +++ b/imgui.h
@@ -30,7 +30,7 @@ // Library Version // (Integer encoded as XYYZZ for use in #if preprocessor conditionals, e.g. '#if IMGUI_VERSION_NUM >= 12345') #define IMGUI_VERSION "1.92.9 WIP" -#define IMGUI_VERSION_NUM 19282 +#define IMGUI_VERSION_NUM 19283 #define IMGUI_HAS_TABLE // Added BeginTable() - from IMGUI_VERSION_NUM >= 18000 #define IMGUI_HAS_TEXTURES // Added ImGuiBackendFlags_RendererHasTextures - from IMGUI_VERSION_NUM >= 19198 #define IMGUI_HAS_VIEWPORT // In 'docking' WIP branch. @@ -917,14 +917,15 @@ IMGUI_API bool TableSetColumnIndex(int column_n); // append into the specified column. Return true when column is visible. // Tables: Headers & Columns declaration - // - Use TableSetupColumn() to specify label, resizing policy, default width/weight, id, various other flags etc. + // - Use TableSetupColumn() to specify label, resizing policy, default width/weight, various other flags etc. + // (the trailing 'ImGuiID user_data', which used to be referred to as 'ImGuiID user_id', is merely user data that is blindly copied in ImGuiTableColumnSortSpecs). // - Use TableHeadersRow() to create a header row and automatically submit a TableHeader() for each column. // Headers are required to perform: reordering, sorting, and opening the context menu. // The context menu can also be made available in columns body using ImGuiTableFlags_ContextMenuInBody. // - You may manually submit headers using TableNextRow() + TableHeader() calls, but this is only useful in // some advanced use cases (e.g. adding custom widgets in header row). // - Use TableSetupScrollFreeze() to lock columns/rows so they stay visible when scrolled. When freezing columns you would usually also use ImGuiTableColumnFlags_NoHide on them. - IMGUI_API void TableSetupColumn(const char* label, ImGuiTableColumnFlags flags = 0, float init_width_or_weight = 0.0f, ImGuiID user_id = 0); + IMGUI_API void TableSetupColumn(const char* label, ImGuiTableColumnFlags flags = 0, float init_width_or_weight = 0.0f, ImGuiID user_data = 0); IMGUI_API void TableSetupScrollFreeze(int cols, int rows); // lock columns/rows so they stay visible when scrolled. IMGUI_API void TableHeader(const char* label); // submit one header cell manually (rarely used) IMGUI_API void TableHeadersRow(); // submit a row with headers cells based on data provided to TableSetupColumn() + submit context menu @@ -2245,7 +2246,7 @@ // Sorting specification for one column of a table (sizeof == 12 bytes) struct ImGuiTableColumnSortSpecs { - ImGuiID ColumnUserID; // User id of the column (if specified by a TableSetupColumn() call) + ImGuiID ColumnUserID; // User data for the column (if specified by a TableSetupColumn() call in the 'ImGuiID user_data' field). FIXME: Should be called 'UserData'.. ImS16 ColumnIndex; // Index of the column ImS16 SortOrder; // Index within parent ImGuiTableSortSpecs (always stored in order starting from 0, tables sorted on a single criteria will always have a 0 here) ImGuiSortDirection SortDirection; // ImGuiSortDirection_Ascending or ImGuiSortDirection_Descending @@ -3647,7 +3648,7 @@ // You may use ImTextureData::Updates[] for the list, or ImTextureData::UpdateBox for a single bounding box. struct ImTextureRect { - unsigned short x, y; // Upper-left coordinates of rectangle to update + unsigned short x, y; // Upper-left coordinates of rectangle to update, within the parent Pixels[] array. unsigned short w, h; // Size of rectangle to update (in pixels) }; @@ -3669,7 +3670,7 @@ int Width; // w r // Texture width int Height; // w r // Texture height int BytesPerPixel; // w r // 4 or 1 - unsigned char* Pixels; // w r // Pointer to buffer holding 'Width*Height' pixels and 'Width*Height*BytesPerPixels' bytes. + unsigned char* Pixels; // w r // Pointer to whole texture buffer holding 'Width*Height' pixels and 'Width*Height*BytesPerPixels' bytes. ImTextureRect UsedRect; // w r // Bounding box encompassing all past and queued Updates[]. ImTextureRect UpdateRect; // w r // Bounding box encompassing all queued Updates[]. ImVector<ImTextureRect> Updates; // w r // Array of individual updates.
diff --git a/imgui_internal.h b/imgui_internal.h index e1ddd5d..14bb841 100644 --- a/imgui_internal.h +++ b/imgui_internal.h
@@ -35,7 +35,7 @@ // [SECTION] ImGuiContext (main imgui context) // [SECTION] ImGuiWindowTempData, ImGuiWindow // [SECTION] Tab bar, Tab item support -// [SECTION] Table support +// [SECTION] Table support + internal API // [SECTION] ImGui internal API // [SECTION] ImFontLoader // [SECTION] ImFontAtlas internal API @@ -256,6 +256,7 @@ #define IMGUI_DEBUG_LOG_POPUP(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventPopup) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_NAV(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventNav) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_SELECTION(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventSelection) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) +#define IMGUI_DEBUG_LOG_TABLE(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventTable) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_CLIPPER(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventClipper) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_IO(...) do { if (g.DebugLogFlags & ImGuiDebugLogFlags_EventIO) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) #define IMGUI_DEBUG_LOG_FONT(...) do { ImGuiContext* g2 = GImGui; if (g2 && g2->DebugLogFlags & ImGuiDebugLogFlags_EventFont) IMGUI_DEBUG_LOG(__VA_ARGS__); } while (0) // Called from ImFontAtlas function which may operate without a context. @@ -332,6 +333,8 @@ #define IM_DEBUG_BREAK() __asm__ volatile(".inst 0xde01") #elif defined(__GNUC__) && defined(__arm__) && !defined(__thumb__) #define IM_DEBUG_BREAK() __asm__ volatile(".inst 0xe7f001f0") +#elif defined(__GNUC__) && defined(__aarch64__) +#define IM_DEBUG_BREAK() __asm__ volatile(".inst 0xd4200000") // GDB needs 'set $pc=($pc+4)' to skip this :( #else #define IM_DEBUG_BREAK() IM_ASSERT(0) // It is expected that you define IM_DEBUG_BREAK() into something that will break nicely in a debugger! #endif @@ -700,6 +703,8 @@ inline void set(T* data, int size) { Data = data; DataEnd = data + size; } inline void set(T* data, T* data_end) { Data = data; DataEnd = data_end; } + inline void clear() { Data = DataEnd = NULL; } + inline bool empty() const { return Data == DataEnd; } inline int size() const { return (int)(ptrdiff_t)(DataEnd - Data); } inline int size_in_bytes() const { return (int)(ptrdiff_t)(DataEnd - Data) * (int)sizeof(T); } inline T& operator[](int i) { T* p = Data + i; IM_ASSERT(p >= Data && p < DataEnd); return *p; } @@ -2237,7 +2242,10 @@ ImGuiLocKey_TableSizeOne, ImGuiLocKey_TableSizeAllFit, ImGuiLocKey_TableSizeAllDefault, + ImGuiLocKey_TableReset, + //ImGuiLocKey_TableResetAll, ImGuiLocKey_TableResetOrder, + ImGuiLocKey_TableResetVisibility, ImGuiLocKey_WindowingMainMenuBar, ImGuiLocKey_WindowingPopup, ImGuiLocKey_WindowingUntitled, @@ -2294,8 +2302,9 @@ ImGuiDebugLogFlags_EventInputRouting = 1 << 9, ImGuiDebugLogFlags_EventDocking = 1 << 10, ImGuiDebugLogFlags_EventViewport = 1 << 11, + ImGuiDebugLogFlags_EventTable = 1 << 12, - ImGuiDebugLogFlags_EventMask_ = ImGuiDebugLogFlags_EventError | ImGuiDebugLogFlags_EventActiveId | ImGuiDebugLogFlags_EventFocus | ImGuiDebugLogFlags_EventPopup | ImGuiDebugLogFlags_EventNav | ImGuiDebugLogFlags_EventClipper | ImGuiDebugLogFlags_EventSelection | ImGuiDebugLogFlags_EventIO | ImGuiDebugLogFlags_EventFont | ImGuiDebugLogFlags_EventInputRouting | ImGuiDebugLogFlags_EventDocking | ImGuiDebugLogFlags_EventViewport, + ImGuiDebugLogFlags_EventMask_ = ImGuiDebugLogFlags_EventError | ImGuiDebugLogFlags_EventActiveId | ImGuiDebugLogFlags_EventFocus | ImGuiDebugLogFlags_EventPopup | ImGuiDebugLogFlags_EventNav | ImGuiDebugLogFlags_EventClipper | ImGuiDebugLogFlags_EventSelection | ImGuiDebugLogFlags_EventTable | ImGuiDebugLogFlags_EventIO | ImGuiDebugLogFlags_EventFont | ImGuiDebugLogFlags_EventInputRouting | ImGuiDebugLogFlags_EventDocking | ImGuiDebugLogFlags_EventViewport, ImGuiDebugLogFlags_OutputToTTY = 1 << 20, // Also send output to TTY ImGuiDebugLogFlags_OutputToDebugger = 1 << 21, // Also send output to Debugger Console [Windows only] ImGuiDebugLogFlags_OutputToTestEngine = 1 << 22, // Also send output to Dear ImGui Test Engine @@ -3112,7 +3121,7 @@ }; //----------------------------------------------------------------------------- -// [SECTION] Table support +// [SECTION] Table support + internal API //----------------------------------------------------------------------------- #define IM_COL32_DISABLE IM_COL32(0,0,0,1) // Special sentinel code which cannot be used as a regular color. @@ -3134,7 +3143,8 @@ 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() + ImGuiID ID; // Hash of column name (ignoring top of ID stack), used for .ini persistence when available. + ImGuiID UserData; // (Optional) User data 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 @@ -3160,8 +3170,8 @@ 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 - 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 AutoFitQueue : 4; // Queue of 4 values for the next 4 frames to request auto-fit + ImU8 CannotSkipItemsQueue : 4; // Queue of 4 values for the next 4 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) @@ -3320,8 +3330,10 @@ bool IsSettingsRequestLoad; bool IsSettingsDirty; // Set when table settings have changed and needs to be reported into ImGuiTableSettings data. bool IsDefaultDisplayOrder; // Set when display order is unchanged from default (DisplayOrder contains 0...Count-1) - bool IsResetAllRequest; + bool IsDefaultVisibility; // Set when enabled/visibility is unchanged from default + bool IsResetAllRequest; // Set to queue a call to TableResetSettings() in BeginTable() bool IsResetDisplayOrderRequest; + bool IsResetVisibilityRequest; bool IsUnfrozenRows; // Set when we got past the frozen row. bool IsDefaultSizingPolicy; // Set if user didn't explicitly set a sizing policy in BeginTable() bool IsActiveIdAliveBeforeTable; @@ -3346,7 +3358,7 @@ int TableIndex; // Index in g.Tables.Buf[] pool float LastTimeActive; // Last timestamp this structure was used float AngledHeadersExtraWidth; // Used in EndTable() - ImVector<ImGuiTableHeaderData> AngledHeadersRequests; // Used in TableAngledHeadersRow() + ImVector<ImGuiTableHeaderData> AngledHeadersRequests; // Used in TableAngledHeadersRow() // FIXME: Single instance is enough? ImVec2 UserOuterSize; // outer_size.x passed to BeginTable() ImDrawListSplitter DrawSplitter; @@ -3367,18 +3379,18 @@ struct ImGuiTableColumnSettings { float WidthOrWeight; - ImGuiID UserID; + ImGuiID ID; ImGuiTableColumnIdx Index; ImGuiTableColumnIdx DisplayOrder; ImGuiTableColumnIdx SortOrder; ImU8 SortDirection : 2; - ImS8 IsEnabled : 2; // "Visible" in ini file + ImS8 IsEnabled : 2; // "Visible" in .ini file ImU8 IsStretch : 1; ImGuiTableColumnSettings() { WidthOrWeight = 0.0f; - UserID = 0; + ID = 0; Index = -1; DisplayOrder = SortOrder = -1; SortDirection = ImGuiSortDirection_None; @@ -3401,6 +3413,84 @@ ImGuiTableColumnSettings* GetColumnSettings() { return (ImGuiTableColumnSettings*)(this + 1); } }; +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 TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs); + IMGUI_API int TableGetHoveredRow(); // Retrieve *PREVIOUS FRAME* hovered row. This difference with TableGetHoveredColumn() is the reason why this is not public yet. + IMGUI_API float TableGetHeaderRowHeight(); + IMGUI_API float TableGetHeaderAngledMaxLabelWidth(); + IMGUI_API void TablePushBackgroundChannel(); + IMGUI_API void TablePopBackgroundChannel(); + IMGUI_API void TablePushColumnChannel(int column_n); + IMGUI_API void TablePopColumnChannel(); + IMGUI_API void TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label_width, const ImGuiTableHeaderData* data, int data_count); + + // Tables: Internals + inline ImGuiTable* GetCurrentTable() { ImGuiContext& g = *GImGui; return g.CurrentTable; } + IMGUI_API ImGuiTable* TableFindByID(ImGuiID id); + IMGUI_API bool BeginTableEx(const char* name, ImGuiID id, int columns_count, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0, 0), float inner_width = 0.0f); + IMGUI_API void TableBeginInitMemory(ImGuiTable* table, int columns_count); + IMGUI_API void TableApplyQueuedRequests(ImGuiTable* table); + 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 TableApplyExternalUnclipRect(ImGuiTable* table, ImRect& rect); + IMGUI_API void TableDrawBorders(ImGuiTable* table); + IMGUI_API void TableDrawDefaultContextMenu(ImGuiTable* table, ImGuiTableFlags flags_for_section_to_display); + IMGUI_API bool TableBeginContextMenuPopup(ImGuiTable* table); + IMGUI_API void TableMergeDrawChannels(ImGuiTable* table); + inline ImGuiTableInstanceData* TableGetInstanceData(ImGuiTable* table, int instance_no) { if (instance_no == 0) return &table->InstanceDataFirst; return &table->InstanceDataExtra[instance_no - 1]; } + inline ImGuiID TableGetInstanceID(ImGuiTable* table, int instance_no) { return TableGetInstanceData(table, instance_no)->TableInstanceID; } + IMGUI_API void TableFixDisplayOrder(ImGuiTable* table); + IMGUI_API void TableSortSpecsSanitize(ImGuiTable* table); + IMGUI_API void TableSortSpecsBuild(ImGuiTable* table); + 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); + IMGUI_API void TableEndCell(ImGuiTable* table); + 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(ImGuiTable* table, int column_n, int instance_no = 0); + IMGUI_API float TableCalcMaxColumnWidth(const ImGuiTable* table, int column_n); + IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n); + IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table); + IMGUI_API void TableSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order); + IMGUI_API void TableQueueSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order); + IMGUI_API void TableRemove(ImGuiTable* table); + IMGUI_API void TableGcCompactTransientBuffers(ImGuiTable* table); + IMGUI_API void TableGcCompactTransientBuffers(ImGuiTableTempData* table); + IMGUI_API void TableGcCompactSettings(); + + // Tables: Settings + IMGUI_API void TableLoadSettings(ImGuiTable* table); + IMGUI_API void TableLoadSettingsForColumns(ImGuiTable* table); + IMGUI_API void TableSaveSettings(ImGuiTable* table); + IMGUI_API void TableResetSettings(ImGuiTable* table); + IMGUI_API ImGuiTableSettings* TableGetBoundSettings(ImGuiTable* table); + IMGUI_API void TableSettingsAddSettingsHandler(); + IMGUI_API ImGuiTableSettings* TableSettingsCreate(ImGuiID id, int columns_count); + IMGUI_API ImGuiTableSettings* TableSettingsFindByID(ImGuiID id); + + // Legacy Columns API (this is not exposed because we will encourage transitioning to the Tables API) + IMGUI_API void SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect); + IMGUI_API void BeginColumns(const char* str_id, int count, ImGuiOldColumnFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns(). + IMGUI_API void EndColumns(); // close columns + IMGUI_API void PushColumnClipRect(int column_index); + IMGUI_API void PushColumnsBackground(); + IMGUI_API void PopColumnsBackground(); + IMGUI_API ImGuiID GetColumnsID(const char* str_id, int count); + IMGUI_API ImGuiOldColumns* FindOrCreateColumns(ImGuiWindow* window, ImGuiID id); + IMGUI_API float GetColumnOffsetFromNorm(const ImGuiOldColumns* columns, float offset_norm); + IMGUI_API float GetColumnNormFromOffset(const ImGuiOldColumns* columns, float offset); +} + //----------------------------------------------------------------------------- // [SECTION] ImGui internal API // No guarantee of forward compatibility here! @@ -3812,80 +3902,6 @@ inline ImGuiBoxSelectState* GetBoxSelectState(ImGuiID id) { ImGuiContext& g = *GImGui; return (id != 0 && g.BoxSelectState.ID == id && g.BoxSelectState.IsActive) ? &g.BoxSelectState : NULL; } inline ImGuiMultiSelectState* GetMultiSelectState(ImGuiID id) { ImGuiContext& g = *GImGui; return g.MultiSelectStorage.GetByKey(id); } - // Internal Columns API (this is not exposed because we will encourage transitioning to the Tables API) - IMGUI_API void SetWindowClipRectBeforeSetChannel(ImGuiWindow* window, const ImRect& clip_rect); - IMGUI_API void BeginColumns(const char* str_id, int count, ImGuiOldColumnFlags flags = 0); // setup number of columns. use an identifier to distinguish multiple column sets. close with EndColumns(). - IMGUI_API void EndColumns(); // close columns - IMGUI_API void PushColumnClipRect(int column_index); - IMGUI_API void PushColumnsBackground(); - IMGUI_API void PopColumnsBackground(); - IMGUI_API ImGuiID GetColumnsID(const char* str_id, int count); - IMGUI_API ImGuiOldColumns* FindOrCreateColumns(ImGuiWindow* window, ImGuiID id); - IMGUI_API float GetColumnOffsetFromNorm(const ImGuiOldColumns* columns, float offset_norm); - IMGUI_API float GetColumnNormFromOffset(const ImGuiOldColumns* columns, float offset); - - // 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 TableSetColumnSortDirection(int column_n, ImGuiSortDirection sort_direction, bool append_to_sort_specs); - IMGUI_API int TableGetHoveredRow(); // Retrieve *PREVIOUS FRAME* hovered row. This difference with TableGetHoveredColumn() is the reason why this is not public yet. - IMGUI_API float TableGetHeaderRowHeight(); - IMGUI_API float TableGetHeaderAngledMaxLabelWidth(); - IMGUI_API void TablePushBackgroundChannel(); - IMGUI_API void TablePopBackgroundChannel(); - IMGUI_API void TablePushColumnChannel(int column_n); - IMGUI_API void TablePopColumnChannel(); - IMGUI_API void TableAngledHeadersRowEx(ImGuiID row_id, float angle, float max_label_width, const ImGuiTableHeaderData* data, int data_count); - - // Tables: Internals - inline ImGuiTable* GetCurrentTable() { ImGuiContext& g = *GImGui; return g.CurrentTable; } - IMGUI_API ImGuiTable* TableFindByID(ImGuiID id); - IMGUI_API bool BeginTableEx(const char* name, ImGuiID id, int columns_count, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0, 0), float inner_width = 0.0f); - IMGUI_API void TableBeginInitMemory(ImGuiTable* table, int columns_count); - IMGUI_API void TableBeginApplyRequests(ImGuiTable* table); - 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 TableApplyExternalUnclipRect(ImGuiTable* table, ImRect& rect); - IMGUI_API void TableDrawBorders(ImGuiTable* table); - IMGUI_API void TableDrawDefaultContextMenu(ImGuiTable* table, ImGuiTableFlags flags_for_section_to_display); - IMGUI_API bool TableBeginContextMenuPopup(ImGuiTable* table); - IMGUI_API void TableMergeDrawChannels(ImGuiTable* table); - inline ImGuiTableInstanceData* TableGetInstanceData(ImGuiTable* table, int instance_no) { if (instance_no == 0) return &table->InstanceDataFirst; return &table->InstanceDataExtra[instance_no - 1]; } - inline ImGuiID TableGetInstanceID(ImGuiTable* table, int instance_no) { return TableGetInstanceData(table, instance_no)->TableInstanceID; } - IMGUI_API void TableFixDisplayOrder(ImGuiTable* table); - IMGUI_API void TableSortSpecsSanitize(ImGuiTable* table); - IMGUI_API void TableSortSpecsBuild(ImGuiTable* table); - 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); - IMGUI_API void TableEndCell(ImGuiTable* table); - 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(ImGuiTable* table, int column_n, int instance_no = 0); - IMGUI_API float TableCalcMaxColumnWidth(const ImGuiTable* table, int column_n); - IMGUI_API void TableSetColumnWidthAutoSingle(ImGuiTable* table, int column_n); - IMGUI_API void TableSetColumnWidthAutoAll(ImGuiTable* table); - IMGUI_API void TableSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order); - IMGUI_API void TableQueueSetColumnDisplayOrder(ImGuiTable* table, int column_n, int dst_order); - IMGUI_API void TableRemove(ImGuiTable* table); - IMGUI_API void TableGcCompactTransientBuffers(ImGuiTable* table); - IMGUI_API void TableGcCompactTransientBuffers(ImGuiTableTempData* table); - IMGUI_API void TableGcCompactSettings(); - - // Tables: Settings - IMGUI_API void TableLoadSettings(ImGuiTable* table); - IMGUI_API void TableSaveSettings(ImGuiTable* table); - IMGUI_API void TableResetSettings(ImGuiTable* table); - IMGUI_API ImGuiTableSettings* TableGetBoundSettings(ImGuiTable* table); - IMGUI_API void TableSettingsAddSettingsHandler(); - IMGUI_API ImGuiTableSettings* TableSettingsCreate(ImGuiID id, int columns_count); - IMGUI_API ImGuiTableSettings* TableSettingsFindByID(ImGuiID id); - // Tab Bars inline ImGuiTabBar* GetCurrentTabBar() { ImGuiContext& g = *GImGui; return g.CurrentTabBar; } IMGUI_API ImGuiTabBar* TabBarFindByID(ImGuiID id); @@ -4067,7 +4083,7 @@ IMGUI_API void DebugNodeStorage(ImGuiStorage* storage, const char* label); IMGUI_API void DebugNodeTabBar(ImGuiTabBar* tab_bar, const char* label); IMGUI_API void DebugNodeTable(ImGuiTable* table); - IMGUI_API void DebugNodeTableSettings(ImGuiTableSettings* settings); + IMGUI_API void DebugNodeTableSettings(ImGuiTableSettings* settings, ImGuiTable* table); IMGUI_API void DebugNodeInputTextState(ImGuiInputTextState* state); IMGUI_API void DebugNodeTypingSelectState(ImGuiTypingSelectState* state); IMGUI_API void DebugNodeMultiSelectState(ImGuiMultiSelectState* state);
diff --git a/imgui_tables.cpp b/imgui_tables.cpp index 98dd7ba..50bb3db 100644 --- a/imgui_tables.cpp +++ b/imgui_tables.cpp
@@ -40,13 +40,16 @@ // | 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] followup to BeginTable(): setup everything: widths, columns positions, clipping rectangles. Automatically called by the FIRST call to TableNextRow() or TableHeadersRow(). +// | TableLoadSettingsForColumns() - on settings load +// | TableApplyQueuedRequests() - 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 +// | - TableSetColumnDisplayOrder() - apply reordering a column // | TableSetupDrawChannels() - setup ImDrawList channels // | TableUpdateBorders() - detect hovering columns for resize, ahead of contents submission // | TableBeginContextMenuPopup() @@ -252,7 +255,7 @@ // - BeginTable() // - BeginTableEx() [Internal] // - TableBeginInitMemory() [Internal] -// - TableBeginApplyRequests() [Internal] +// - TableApplyQueuedRequests() [Internal] // - TableSetupColumnFlags() [Internal] // - TableUpdateLayout() [Internal] // - TableUpdateBorders() [Internal] @@ -567,6 +570,7 @@ if (old_columns_count != 0 && old_columns_count != columns_count) { // Attempt to preserve width and other settings on column count/specs change (#4046) + IMGUI_DEBUG_LOG_TABLE("[table] Table 0x%08X column count %d -> %d, recreating storage.\n", table->ID, old_columns_count, columns_count); old_columns_to_preserve = table->Columns.Data; old_columns_raw_data = table->RawData; // Free at end of function table->RawData = NULL; @@ -615,21 +619,6 @@ if (table->IsSettingsRequestLoad) TableLoadSettings(table); - // Handle DPI/font resize - // This is designed to facilitate DPI changes with the assumption that e.g. style.CellPadding has been scaled as well. - // It will also react to changing fonts with mixed results. It doesn't need to be perfect but merely provide a decent transition. - // FIXME-DPI: Provide consistent standards for reference size. Perhaps using g.CurrentDpiScale would be more self explanatory. - // This is will lead us to non-rounded WidthRequest in columns, which should work but is a poorly tested path. - const float new_ref_scale_unit = g.FontSize; // g.Font->GetCharAdvance('A') ? - if (table->RefScale != 0.0f && table->RefScale != new_ref_scale_unit) - { - const float scale_factor = new_ref_scale_unit / table->RefScale; - //IMGUI_DEBUG_PRINT("[table] %08X RefScaleUnit %.3f -> %.3f, scaling width by %.3f\n", table->ID, table->RefScaleUnit, new_ref_scale_unit, scale_factor); - for (int n = 0; n < columns_count; n++) - table->Columns[n].WidthRequest = table->Columns[n].WidthRequest * scale_factor; - } - table->RefScale = new_ref_scale_unit; - // Disable output until user calls TableNextRow() or TableNextColumn() leading to the TableUpdateLayout() call.. // This is not strictly necessary but will reduce cases were "out of table" output will be misleading to the user. // Because we cannot safely assert in EndTable() when no rows have been created, this seems like our best option. @@ -639,10 +628,7 @@ // 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); - - // Apply queued resizing/reordering/hiding requests - TableBeginApplyRequests(table); - + return true; } @@ -677,7 +663,7 @@ } // Apply queued resizing/reordering/hiding requests -void ImGui::TableBeginApplyRequests(ImGuiTable* table) +void ImGui::TableApplyQueuedRequests(ImGuiTable* table) { // Handle resizing request // (We process this in the TableBegin() of the first instance of each table) @@ -719,7 +705,7 @@ // table->ReorderColumn = -1; } - // Handle display order reset request + // Handle display order / visibility reset requests if (table->IsResetDisplayOrderRequest) { for (int n = 0; n < table->ColumnsCount; n++) @@ -727,6 +713,13 @@ table->IsResetDisplayOrderRequest = false; table->IsSettingsDirty = true; } + if (table->IsResetVisibilityRequest) + { + for (ImGuiTableColumn& column : table->Columns) + column.IsUserEnabled = column.IsUserEnabledNextFrame = (column.Flags & ImGuiTableColumnFlags_DefaultHide) ? 0 : 1; + table->IsResetVisibilityRequest = false; + table->IsSettingsDirty = true; + } } // Apply immediately. See TableQueueSetColumnDisplayOrder() for additional checks/constraints. @@ -782,8 +775,9 @@ table->ReorderColumn = (ImGuiTableColumnIdx)column_n; table->ReorderColumnDstOrder = (ImGuiTableColumnIdx)-1; dst_order = TableGetMaxDisplayOrderAllowed(table, src_order, dst_order); - if (dst_order != src_order) - table->ReorderColumnDstOrder = (ImGuiTableColumnIdx)dst_order; + if (table->IsLayoutLocked && dst_order == src_order) // We allow calling the function before layout w/ reconcile so don't early out. + return; + table->ReorderColumnDstOrder = (ImGuiTableColumnIdx)dst_order; } // Adjust flags: default width mode + stretch columns are not allowed when auto extending @@ -851,11 +845,30 @@ ImGuiContext& g = *GImGui; IM_ASSERT(table->IsLayoutLocked == false); + // Apply queued resizing/reordering/hiding requests + TableApplyQueuedRequests(table); + + // Handle DPI/font resize + // This is designed to facilitate DPI changes with the assumption that e.g. style.CellPadding has been scaled as well. + // It will also react to changing fonts with mixed results. It doesn't need to be perfect but merely provide a decent transition. + // FIXME-DPI: Provide consistent standards for reference size. Perhaps using g.CurrentDpiScale would be more self explanatory. + // This is will lead us to non-rounded WidthRequest in columns, which should work but is a poorly tested path. + const float new_ref_scale_unit = g.FontSize; // g.Font->GetCharAdvance('A') ? + const int columns_count = table->ColumnsCount; + if (table->RefScale != 0.0f && table->RefScale != new_ref_scale_unit) + { + const float scale_factor = new_ref_scale_unit / table->RefScale; + IMGUI_DEBUG_LOG_TABLE("[table] 0x%08X RefScale %.3f -> %.3f, scaling width by %.3f\n", table->ID, table->RefScale, new_ref_scale_unit, scale_factor); + for (int n = 0; n < columns_count; n++) + table->Columns[n].WidthRequest = table->Columns[n].WidthRequest * scale_factor; + } + table->RefScale = new_ref_scale_unit; + const ImGuiTableFlags table_sizing_policy = (table->Flags & ImGuiTableFlags_SizingMask_); - table->IsDefaultDisplayOrder = true; + table->IsDefaultDisplayOrder = table->IsDefaultVisibility = true; table->ColumnsEnabledCount = 0; - ImBitArrayClearAllBits(table->EnabledMaskByIndex, table->ColumnsCount); - ImBitArrayClearAllBits(table->EnabledMaskByDisplayOrder, table->ColumnsCount); + ImBitArrayClearAllBits(table->EnabledMaskByIndex, columns_count); + ImBitArrayClearAllBits(table->EnabledMaskByDisplayOrder, columns_count); table->LeftMostEnabledColumn = -1; table->MinColumnWidth = ImMax(1.0f, g.Style.FramePadding.x * 1.0f); // g.Style.ColumnsMinSpacing; // FIXME-TABLE @@ -868,11 +881,9 @@ 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++) + for (int order_n = 0; order_n < columns_count; 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. @@ -882,7 +893,7 @@ { TableSetupColumnFlags(table, column, ImGuiTableColumnFlags_None); column->NameOffset = -1; - column->UserID = 0; + column->UserData = 0; column->InitStretchWeightOrWidth = -1.0f; } @@ -896,6 +907,11 @@ } column->IsEnabled = column->IsUserEnabled && (column->Flags & ImGuiTableColumnFlags_Disabled) == 0; + if (column->IsEnabled != ((column->Flags & ImGuiTableColumnFlags_DefaultHide) ? 0 : 1)) + table->IsDefaultVisibility = false; + if (column_n != order_n) + table->IsDefaultDisplayOrder = false; + if (column->SortOrder != -1 && !column->IsEnabled) table->IsSortSpecsDirty = true; if (column->SortOrder > 0 && !(table->Flags & ImGuiTableFlags_SortMulti)) @@ -967,7 +983,7 @@ 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++) + for (int column_n = 0; column_n < columns_count; column_n++) { if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n)) continue; @@ -1031,7 +1047,7 @@ 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->ColumnsGivenWidth = width_spacings + (table->CellPaddingX * 2.0f) * table->ColumnsEnabledCount; - for (int column_n = 0; column_n < table->ColumnsCount; column_n++) + for (int column_n = 0; column_n < columns_count; column_n++) { if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByIndex, column_n)) continue; @@ -1058,7 +1074,7 @@ // [Part 5] 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; stretch_sum_weights > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--) + for (int order_n = columns_count - 1; stretch_sum_weights > 0.0f && width_remaining_for_stretched_columns >= 1.0f && order_n >= 0; order_n--) { if (!IM_BITARRAY_TESTBIT(table->EnabledMaskByDisplayOrder, order_n)) continue; @@ -1098,8 +1114,8 @@ 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; - ImBitArrayClearAllBits(table->VisibleMaskByIndex, table->ColumnsCount); - for (int order_n = 0; order_n < table->ColumnsCount; order_n++) + ImBitArrayClearAllBits(table->VisibleMaskByIndex, columns_count); + for (int order_n = 0; order_n < columns_count; order_n++) { const int column_n = table->DisplayOrderToIndex[order_n]; ImGuiTableColumn* column = &table->Columns[column_n]; @@ -1247,7 +1263,7 @@ const float unused_x1 = ImMax(table->WorkRect.Min.x, table->Columns[table->RightMostEnabledColumn].ClipRect.Max.x); if (is_hovering_table && table->HoveredColumnBody == -1) if (mouse_skewed_x >= unused_x1) - table->HoveredColumnBody = (ImGuiTableColumnIdx)table->ColumnsCount; + table->HoveredColumnBody = (ImGuiTableColumnIdx)columns_count; if (has_resizable == false && (table->Flags & ImGuiTableFlags_Resizable)) table->Flags &= ~ImGuiTableFlags_Resizable; @@ -1289,7 +1305,7 @@ table->HighlightColumnHeader = -1; if (table->IsContextPopupOpen && table->ContextPopupColumn != -1 && table->InstanceInteracted == table->InstanceCurrent) table->HighlightColumnHeader = table->ContextPopupColumn; - else if ((table->Flags & ImGuiTableFlags_HighlightHoveredColumn) && table->HoveredColumnBody != -1 && table->HoveredColumnBody != table->ColumnsCount && table->HoveredColumnBorder == -1) + else if ((table->Flags & ImGuiTableFlags_HighlightHoveredColumn) && table->HoveredColumnBody != -1 && table->HoveredColumnBody != columns_count && table->HoveredColumnBorder == -1) if (g.ActiveId == 0 || (table->IsActiveIdInTable || g.DragDropActive)) table->HighlightColumnHeader = table->HoveredColumnBody; @@ -1656,17 +1672,9 @@ // See "COLUMNS SIZING POLICIES" comments at the top of this file // If (init_width_or_weight <= 0.0f) it is ignored -void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_id) +static void TableSetupColumnApply(ImGuiTable* table, int idx, ImGuiID id, ImS16 name_offset, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_data) { - ImGuiContext& g = *GImGui; - ImGuiTable* table = g.CurrentTable; - IM_ASSERT_USER_ERROR_RET(table != NULL, "Call should only be done while in BeginTable() scope!"); - IM_ASSERT_USER_ERROR_RET(table->DeclColumnsCount < table->ColumnsCount, "TableSetupColumn(): called too many times!"); - IM_ASSERT_USER_ERROR_RET(table->IsLayoutLocked == false, "TableSetupColumn(): need to call before first row!"); // Table layout is locked when submitting a row or when calling BeginMultiSelect() with box-select. - IM_ASSERT((flags & ImGuiTableColumnFlags_StatusMask_) == 0 && "Illegal to pass StatusMask values to TableSetupColumn()"); - - ImGuiTableColumn* column = &table->Columns[table->DeclColumnsCount]; - table->DeclColumnsCount++; + ImGuiTableColumn* column = &table->Columns[idx]; // Assert when passing a width or weight if policy is entirely left to default, to avoid storing width into weight and vice-versa. // Give a grace to users of ImGuiTableFlags_ScrollX. @@ -1685,7 +1693,9 @@ } TableSetupColumnFlags(table, column, flags); - column->UserID = user_id; + column->ID = id; + column->UserData = user_data; + column->NameOffset = name_offset; flags = column->Flags; // Initialize defaults @@ -1697,15 +1707,29 @@ init_flags |= ImGuiTableFlags_Resizable; TableInitColumnDefaults(table, column, init_flags); } +} + +void ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags, float init_width_or_weight, ImGuiID user_data_for_sort_specs) +{ + ImGuiContext& g = *GImGui; + ImGuiTable* table = g.CurrentTable; + IM_ASSERT_USER_ERROR_RET(table != NULL, "Call should only be done while in BeginTable() scope!"); + IM_ASSERT_USER_ERROR_RET(table->DeclColumnsCount < table->ColumnsCount, "TableSetupColumn(): called too many times!"); + IM_ASSERT_USER_ERROR_RET(table->IsLayoutLocked == false, "TableSetupColumn(): need to call before first row!"); // Table layout is locked when submitting a row or when calling BeginMultiSelect() with box-select. + IM_ASSERT((flags & ImGuiTableColumnFlags_StatusMask_) == 0 && "Illegal to pass StatusMask values to TableSetupColumn()"); // Store name (append with zero-terminator in contiguous buffer) // FIXME: If we recorded the number of \n in names we could compute header row height - column->NameOffset = -1; + ImS16 name_offset = -1; if (label != NULL && label[0] != 0) { - column->NameOffset = (ImS16)table->ColumnsNames.size(); + name_offset = (ImS16)table->ColumnsNames.size(); table->ColumnsNames.append(label, label + ImStrlen(label) + 1); } + + const ImGuiID column_id = (label != NULL && label[0] != 0) ? ImHashStr(label) : 0; + TableSetupColumnApply(table, table->DeclColumnsCount, column_id, name_offset, flags, init_width_or_weight, user_data_for_sort_specs); + table->DeclColumnsCount++; } // [Public] @@ -3081,7 +3105,7 @@ continue; IM_ASSERT(column->SortOrder < table->SortSpecsCount); ImGuiTableColumnSortSpecs* sort_spec = &sort_specs[column->SortOrder]; - sort_spec->ColumnUserID = column->UserID; + sort_spec->ColumnUserID = column->UserData; sort_spec->ColumnIndex = (ImGuiTableColumnIdx)column_n; sort_spec->SortOrder = (ImGuiTableColumnIdx)column->SortOrder; sort_spec->SortDirection = (ImGuiSortDirection)column->SortDirection; @@ -3277,7 +3301,9 @@ } // Sort order arrow - const float ellipsis_max = ImMax(cell_r.Max.x - w_arrow - w_sort_text, label_pos.x); + // - Only clip label for a visible arrow. Auto-fit still accounts for a possible arrow, but when + // manually sized smaller we don't clip the label for the sake of an arrow that isn't displayed. + const float ellipsis_max = ImMax(cell_r.Max.x - (sort_arrow ? w_arrow + w_sort_text : 0.0f), label_pos.x); if ((table->Flags & ImGuiTableFlags_Sortable) && !(column->Flags & ImGuiTableColumnFlags_NoSort)) { if (column->SortOrder != -1) @@ -3597,17 +3623,20 @@ want_separator = true; } - // Ordering - if (flags_for_section_to_display & ImGuiTableFlags_Reorderable) - { - if (MenuItem(LocalizeGetMsg(ImGuiLocKey_TableResetOrder), NULL, false, !table->IsDefaultDisplayOrder)) - table->IsResetDisplayOrderRequest = true; - want_separator = true; - } - - // Reset all (should work but seems unnecessary/noisy to expose?) - //if (MenuItem("Reset all")) - // table->IsResetAllRequest = true; + // Reset Order/Visibility etc. + if (flags_for_section_to_display & (ImGuiTableFlags_Reorderable | ImGuiTableFlags_Hideable)) + if (BeginMenu(LocalizeGetMsg(ImGuiLocKey_TableReset))) + { + //if (MenuItem(LocalizeGetMsg(ImGuiLocKey_TableResetAll))) // FIXME: Hiding because altering Sort Order + requesting auto-fit simultaneously has a tendency to exhibit a sizing glitch. + // table->IsResetAllRequest = true; + if (flags_for_section_to_display & ImGuiTableFlags_Reorderable) + if (MenuItem(LocalizeGetMsg(ImGuiLocKey_TableResetOrder), NULL, false, !table->IsDefaultDisplayOrder)) // PS: cannot be hidden because it would mess with drag reordering. + table->IsResetDisplayOrderRequest = true; + if (flags_for_section_to_display & ImGuiTableFlags_Hideable) + if (MenuItem(LocalizeGetMsg(ImGuiLocKey_TableResetVisibility), NULL, false, !table->IsDefaultVisibility)) + table->IsResetVisibilityRequest = true; + EndMenu(); + } // Sorting // (modify TableOpenContextMenu() to add _Sortable flag if enabling this) @@ -3793,6 +3822,7 @@ for (int n = 0; n < table->ColumnsCount; n++, column++, column_settings++) { const float width_or_weight = (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? column->StretchWeight : column->WidthRequest; + column_settings->ID = column->ID; column_settings->WidthOrWeight = width_or_weight; column_settings->Index = (ImGuiTableColumnIdx)n; column_settings->DisplayOrder = column->DisplayOrder; @@ -3975,12 +4005,13 @@ char c = 0; ImGuiTableColumnSettings* column = settings->GetColumnSettings() + column_n; column->Index = (ImGuiTableColumnIdx)column_n; - if (sscanf(line, "UserID=0x%08X%n", (ImU32*)&n, &r)==1) { line = ImStrSkipBlank(line + r); column->UserID = (ImGuiID)n; } + if (sscanf(line, "UserID=0x%08X%n", (ImU32*)&n, &r)==1) { line = ImStrSkipBlank(line + r); } // FIXME-LEGACY: Removed 2025/11/12, was never properly set. if (sscanf(line, "Width=%d%n", &n, &r) == 1) { line = ImStrSkipBlank(line + r); column->WidthOrWeight = (float)n; column->IsStretch = 0; settings->SaveFlags |= ImGuiTableFlags_Resizable; } if (sscanf(line, "Weight=%f%n", &f, &r) == 1) { line = ImStrSkipBlank(line + r); column->WidthOrWeight = f; column->IsStretch = 1; settings->SaveFlags |= ImGuiTableFlags_Resizable; } if (sscanf(line, "Visible=%d%n", &n, &r) == 1) { line = ImStrSkipBlank(line + r); column->IsEnabled = (ImU8)n; settings->SaveFlags |= ImGuiTableFlags_Hideable; } if (sscanf(line, "Order=%d%n", &n, &r) == 1) { line = ImStrSkipBlank(line + r); column->DisplayOrder = (ImGuiTableColumnIdx)n; settings->SaveFlags |= ImGuiTableFlags_Reorderable; } if (sscanf(line, "Sort=%d%c%n", &n, &c, &r) == 2) { line = ImStrSkipBlank(line + r); column->SortOrder = (ImGuiTableColumnIdx)n; column->SortDirection = (c == '^') ? ImGuiSortDirection_Descending : ImGuiSortDirection_Ascending; settings->SaveFlags |= ImGuiTableFlags_Sortable; } + if (sscanf(line, "ID=0x%08X%n", (ImU32*)&n, &r) == 1) { line = ImStrSkipBlank(line + r); column->ID = (ImGuiID)n; } } } @@ -4008,16 +4039,16 @@ for (int column_n = 0; column_n < settings->ColumnsCount; column_n++, column++) { // "Column 0 UserID=0x42AD2D21 Width=100 Visible=1 Order=0 Sort=0v" - bool save_column = column->UserID != 0 || save_size || save_visible || save_order || (save_sort && column->SortOrder != -1); + bool save_column = save_size || save_visible || save_order || (save_sort && column->SortOrder != -1); if (!save_column) continue; buf->appendf("Column %-2d", column_n); - if (column->UserID != 0) { buf->appendf(" UserID=%08X", column->UserID); } if (save_size && column->IsStretch) { buf->appendf(" Weight=%.4f", column->WidthOrWeight); } if (save_size && !column->IsStretch) { buf->appendf(" Width=%d", (int)column->WidthOrWeight); } if (save_visible) { buf->appendf(" Visible=%d", column->IsEnabled); } if (save_order) { buf->appendf(" Order=%d", column->DisplayOrder); } if (save_sort && column->SortOrder != -1) { buf->appendf(" Sort=%d%c", column->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? 'v' : '^'); } + if (column->ID != 0) { buf->appendf(" ID=0x%08X", column->ID); } buf->append("\n"); } buf->append("\n"); @@ -4075,6 +4106,7 @@ void ImGui::TableGcCompactTransientBuffers(ImGuiTableTempData* temp_data) { + temp_data->AngledHeadersRequests.clear(); temp_data->DrawSplitter.ClearFreeMemory(); temp_data->LastTimeActive = -1.0f; } @@ -4102,6 +4134,7 @@ // [SECTION] Tables: Debugging //------------------------------------------------------------------------- // - DebugNodeTable() [Internal] +// - DebugNodeTableSettings() [Internal] //------------------------------------------------------------------------- #ifndef IMGUI_DISABLE_DEBUG_TOOLS @@ -4165,13 +4198,13 @@ "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..", + "Sort: %d%s, UserData: 0x%08X, Flags: 0x%04X: %s%s%s..", 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->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->SortOrder, (column->SortDirection == ImGuiSortDirection_Ascending) ? " (Asc)" : (column->SortDirection == ImGuiSortDirection_Descending) ? " (Des)" : "", column->UserData, column->Flags, (column->Flags & ImGuiTableColumnFlags_WidthStretch) ? "WidthStretch " : "", (column->Flags & ImGuiTableColumnFlags_WidthFixed) ? "WidthFixed " : "", (column->Flags & ImGuiTableColumnFlags_NoResize) ? "NoResize " : ""); @@ -4184,34 +4217,45 @@ } } if (ImGuiTableSettings* settings = TableGetBoundSettings(table)) - DebugNodeTableSettings(settings); + DebugNodeTableSettings(settings, table); if (clear_settings) - table->IsResetAllRequest = true; + table->IsResetAllRequest = true; // Queue a call to TableResetSettings() TreePop(); } -void ImGui::DebugNodeTableSettings(ImGuiTableSettings* settings) +void ImGui::DebugNodeTableSettings(ImGuiTableSettings* settings, ImGuiTable* table) { - if (!TreeNode((void*)(intptr_t)settings->ID, "Settings 0x%08X (%d columns)", settings->ID, settings->ColumnsCount)) - return; - BulletText("SaveFlags: 0x%08X", settings->SaveFlags); - BulletText("ColumnsCount: %d (max %d)", settings->ColumnsCount, settings->ColumnsCountMax); - for (int n = 0; n < settings->ColumnsCount; n++) + if (settings->ID == 0) + PushID(settings); + const bool open = TreeNode((void*)(intptr_t)settings->ID, "Settings 0x%08X (%d columns)", settings->ID, settings->ColumnsCount); + const bool hovered = IsItemHovered(); + if (hovered && table == NULL && settings->ID != 0) + table = TableFindByID(settings->ID); + if (hovered && table != NULL) + GetForegroundDrawList(table->OuterWindow)->AddRect(table->OuterRect.Min, table->OuterRect.Max, IM_COL32(255, 255, 0, 255)); + if (open) { - ImGuiTableColumnSettings* column_settings = &settings->GetColumnSettings()[n]; - ImGuiSortDirection sort_dir = (column_settings->SortOrder != -1) ? (ImGuiSortDirection)column_settings->SortDirection : ImGuiSortDirection_None; - BulletText("Column %d Order %d SortOrder %d %s Vis %d %s %7.3f UserID 0x%08X", - n, column_settings->DisplayOrder, column_settings->SortOrder, - (sort_dir == ImGuiSortDirection_Ascending) ? "Asc" : (sort_dir == ImGuiSortDirection_Descending) ? "Des" : "---", - column_settings->IsEnabled, column_settings->IsStretch ? "Weight" : "Width ", column_settings->WidthOrWeight, column_settings->UserID); + BulletText("SaveFlags: 0x%08X", settings->SaveFlags); + BulletText("ColumnsCount: %d (max %d)", settings->ColumnsCount, settings->ColumnsCountMax); + for (int n = 0; n < settings->ColumnsCount; n++) + { + ImGuiTableColumnSettings* column_settings = &settings->GetColumnSettings()[n]; + ImGuiSortDirection sort_dir = (column_settings->SortOrder != -1) ? (ImGuiSortDirection)column_settings->SortDirection : ImGuiSortDirection_None; + BulletText("Column %d Order %d SortOrder %2d %s Vis %d %s %7.3f ID 0x%08X", + n, column_settings->DisplayOrder, column_settings->SortOrder, + (sort_dir == ImGuiSortDirection_Ascending) ? "Asc" : (sort_dir == ImGuiSortDirection_Descending) ? "Des" : "---", + column_settings->IsEnabled, column_settings->IsStretch ? "Weight" : "Width ", column_settings->WidthOrWeight, column_settings->ID); + } + TreePop(); } - TreePop(); + if (settings->ID == 0) + PopID(); } #else // #ifndef IMGUI_DISABLE_DEBUG_TOOLS void ImGui::DebugNodeTable(ImGuiTable*) {} -void ImGui::DebugNodeTableSettings(ImGuiTableSettings*) {} +void ImGui::DebugNodeTableSettings(ImGuiTableSettings*, ImGuiTable* table) {} #endif
diff --git a/imgui_widgets.cpp b/imgui_widgets.cpp index 2bf0825..fb4a637 100644 --- a/imgui_widgets.cpp +++ b/imgui_widgets.cpp
@@ -9650,7 +9650,7 @@ // Only when they are other items sticking out we're going to add spacing, yet only register minimum width into the layout system.) float icon_w = (icon && icon[0]) ? CalcTextSize(icon, NULL).x : 0.0f; float shortcut_w = (shortcut && shortcut[0]) ? CalcTextSize(shortcut, NULL).x : 0.0f; - float checkmark_w = IM_TRUNC(g.FontSize * 1.20f); + float checkmark_w = IM_TRUNC(g.FontSize * 1.20f); // FIXME: Always accounted for, even in a menu with none, because 'selected' has no neutral setting. float min_w = offsets->DeclColumns(icon_w, label_size.x, shortcut_w, checkmark_w); // Feedback for next frame float stretch_w = ImMax(0.0f, GetContentRegionAvail().x - min_w); ImVec2 text_pos(pos.x, pos.y + window->DC.CurrLineTextBaseOffset);