ocornut / imgui

Dear ImGui: Bloat-free Graphical User interface for C++ with minimal dependencies
MIT License
60.63k stars 10.24k forks source link

New Tables API (alpha available for testing) #2957

Closed ocornut closed 3 years ago

ocornut commented 4 years ago

TABLES ARE NOW MERGED, MOVING THIS TO #3740

I have pushed an experimental tables branch: https://github.com/ocornut/imgui/tree/tables Providing a long awaited full-featured replacement to the old "Columns" API (#125).

I have been working on this for an embarassingly looong time.. What seemingly started as "let's refactor columns" became a multi-month thing with many rewrites/iterations. A large portion of this work been sponsored by Blizzard Entertainment. Several internal changes pushed to 1.71-1.74 were in preparation for this as I often try to have changes trickle down to master whenever possible to reduce complication of branching.

Please read <3 (this post will be occasionally updated)

Basic Usage: https://github.com/ocornut/imgui/issues/2957#issuecomment-569725733

TODO List: https://github.com/ocornut/imgui/issues/2957#issuecomment-569726095

WIP API breaking changes Sept 2020 https://github.com/ocornut/imgui/issues/2957#issuecomment-698317698

Question? Feedback? Bug report? Feature request? Please create a NEW ISSUE!

Status

Looking for early testers

Git Flow

Features

Some screenshots

image

image

image

image

image

ocornut commented 4 years ago

Basic Usage (Edited Jan 8, 2021)

Main API

// Tables
// [BETA API] API may evolve!
// - Full-featured replacement for old Columns API.
// - See Demo->Tables for details.
// - See ImGuiTableFlags_ and ImGuiTableColumnFlags_ enums for a description of available flags.
// The typical call flow is:
// - 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)
// - 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,
//      you may prefer using TableNextColumn() instead of TableNextRow() + TableSetColumnIndex().
//      TableNextColumn() will automatically wrap-around into the next row if needed.
//    - IMPORTANT: Comparatively to the old Columns() API, we need to call TableNextColumn() for the first column!
//    - Both TableSetColumnIndex() and TableNextColumn() return true when the column is visible or performing
//      width measurements. Otherwise, you may skip submitting the contents of a cell/column, BUT ONLY if you know
//      it is not going to contribute to row height.
//      In many situations, you may skip submitting contents for every columns but one (e.g. the first one).
//    - Summary of possible call flow:
//      ----------------------------------------------------------------------------------------------------------
//       TableNextRow() -> TableSetColumnIndex(0) -> Text("Hello 0") -> TableSetColumnIndex(1) -> Text("Hello 1")  // OK
//       TableNextRow() -> TableNextColumn()      -> Text("Hello 0") -> TableNextColumn()      -> Text("Hello 1")  // OK
//                         TableNextColumn()      -> Text("Hello 0") -> TableNextColumn()      -> Text("Hello 1")  // OK: TableNextColumn() automatically gets to next row!
//       TableNextRow()                           -> Text("Hello 0")                                               // Not OK! Missing TableSetColumnIndex() or TableNextColumn()! Text will not appear!
//      ----------------------------------------------------------------------------------------------------------
// - 5. Call EndTable()

bool  BeginTable(const char* str_id, int columns_count, ImGuiTableFlags flags = 0, const ImVec2& outer_size = ImVec2(0, 0), float inner_width = 0.0f);
void  EndTable();                                 // only call EndTable() if BeginTable() returns true!
void  TableNextRow(ImGuiTableRowFlags row_flags = 0, float min_row_height = 0.0f); // append into the first cell of a new row.
bool  TableNextColumn();                          // append into the next column (or first column of next row if currently in last column). Return true when column is visible.
bool  TableSetColumnIndex(int column_n);          // append into the specified column. Return true when column is visible.
int   TableGetColumnIndex();                      // return current column index.
int   TableGetRowIndex();                         // return current row index.

// Tables: Headers & Columns declaration
// - Use TableSetupColumn() to specify label, resizing policy, default width/weight, id, various other flags etc.
//   Important: this will not display anything! The name passed to TableSetupColumn() is used by TableHeadersRow() and context-menus.
// - Use TableHeadersRow() to create a row and automatically submit a TableHeader() for each column.
//   Headers are required to perform: reordering, sorting, and opening the context menu (but context menu can also be available in columns body using ImGuiTableFlags_ContextMenuInBody).
// - You may manually submit headers using TableNextRow() + TableHeader() calls, but this is only useful in some advanced cases (e.g. adding custom widgets in header row).
// - Use TableSetupScrollFreeze() to lock columns (from the right) or rows (from the top) so they stay visible when scrolled.
void  TableSetupColumn(const char* label, ImGuiTableColumnFlags flags = 0, float init_width_or_weight = -1.0f, ImU32 user_id = 0);
void  TableSetupScrollFreeze(int cols, int rows); // lock columns/rows so they stay visible when scrolled.
void  TableHeadersRow();                          // submit all headers cells based on data provided to TableSetupColumn() + submit context menu
void  TableHeader(const char* label);             // submit one header cell manually (rarely used)

// Tables: Miscellaneous functions
// - Most functions taking 'int column_n' treat the default value of -1 as the same as passing the current column index
// - Sorting: call TableGetSortSpecs() to retrieve latest sort specs for the table. Return value will be NULL if no sorting.
//   When 'SpecsDirty == true' you should sort your data. It will be true when sorting specs have changed since last call, or the first time.
//   Make sure to set 'SpecsDirty = false' after sorting, else you may wastefully sort your data every frame!
//   Lifetime: don't hold on this pointer over multiple frames or past any subsequent call to BeginTable().
int                   TableGetColumnCount();                      // return number of columns (value passed to BeginTable)
const char*           TableGetColumnName(int column_n = -1);      // return "" if column didn't have a name declared by TableSetupColumn(). Pass -1 to use current column.
ImGuiTableColumnFlags TableGetColumnFlags(int column_n = -1);     // return column flags so you can query their Enabled/Visible/Sorted/Hovered status flags.
ImGuiTableSortSpecs*  TableGetSortSpecs();                        // get latest sort specs for the table (NULL if not sorting).
void                  TableSetBgColor(ImGuiTableBgTarget bg_target, ImU32 color, int column_n = -1);  // change the color of a cell, row, or column. See ImGuiTableBgTarget_ flags for details.
// Basic use of tables using TableNextRow() to create a new row, and TableSetColumnIndex() to select the column.
// In many situations, this is the most flexible and easy to use pattern.
HelpMarker("Using TableNextRow() + calling TableSetColumnIndex() _before_ each cell, in a loop.");
if (ImGui::BeginTable("##table1", 3))
{
    for (int row = 0; row < 4; row++)
    {
        ImGui::TableNextRow();
        for (int column = 0; column < 3; column++)
        {
            ImGui::TableSetColumnIndex(column);
            ImGui::Text("Row %d Column %d", row, column);
        }
    }
    ImGui::EndTable();
}

// This essentially the same as above, except instead of using a for loop we call TableSetColumnIndex() manually.
// Sometimes this makes more sense.
HelpMarker("Using TableNextRow() + calling TableNextColumn() _before_ each cell, manually.");
if (ImGui::BeginTable("##table2", 3))
{
    for (int row = 0; row < 4; row++)
    {
        ImGui::TableNextRow();
        ImGui::TableNextColumn();
        ImGui::Text("Row %d", row);
        ImGui::TableNextColumn();
        ImGui::Text("Some contents");
        ImGui::TableNextColumn();
        ImGui::Text("123.456");
    }
    ImGui::EndTable();
}

// Another subtle variant, we call TableNextColumn() _before_ each cell. At the end of a row, TableNextColumn() will create a new row.
// Note that we never TableNextRow() here!
HelpMarker(
    "Only using TableNextColumn(), which tends to be convenient for tables where every cells contains the same type of contents.\n"
    "This is also more similar to the old NextColumn() function of the Columns API, and provided to facilitate the Columns->Tables API transition.");
if (ImGui::BeginTable("##table4", 3))
{
    for (int item = 0; item < 14; item++)
    {
        ImGui::TableNextColumn();
        ImGui::Text("Item %d", item);
    }
    ImGui::EndTable();
}

TODO: add details here

In particular, Demo > Tables & Columns > Advanced is exposing a lots of options for you to play with:

image

API as of October 2020

Provided a rough references here,

// Flags for ImGui::BeginTable()
// - Important! Sizing policies have particularly 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! 
//    - Fixed Columns can be enlarged as needed. Table will show an horizontal scrollbar if needed.
//    - 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.
enum ImGuiTableFlags_
{
    // Features
    ImGuiTableFlags_None                            = 0,
    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 << 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 << 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 << 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 << 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).
};

// Flags for ImGui::TableSetupColumn()
enum ImGuiTableColumnFlags_
{
    // Input configuration flags
    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 _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.
    ImGuiTableColumnFlags_NoClip                    = 1 << 8,   // Disable clipping for this column (all NoClip columns will render in a same draw command).
    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,  // 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).
    ImGuiTableColumnFlags_IndentDisable             = 1 << 16,  // Ignore current Indent value when entering cell (default for columns > 0). Indentation changes _within_ the cell will still be honored.

    // Output status flags, read-only via TableGetColumnFlags()
    ImGuiTableColumnFlags_IsEnabled                 = 1 << 20,  // Status: is enabled == not hidden by user/api (referred to as "Hide" in _DefaultHide and _NoHide) flags.
    ImGuiTableColumnFlags_IsVisible                 = 1 << 21,  // Status: is visible == is enabled AND not clipped by scrolling.
    ImGuiTableColumnFlags_IsSorted                  = 1 << 22,  // Status: is currently part of the sort specs
    ImGuiTableColumnFlags_IsHovered                 = 1 << 23,  // Status: is hovered by mouse
};

// Flags for ImGui::TableNextRow()
enum ImGuiTableRowFlags_
{
    ImGuiTableRowFlags_None                         = 0,
    ImGuiTableRowFlags_Headers                      = 1 << 0    // Identify header row (set default background color + width of its contents accounted different for auto column width)
};

// Enum for ImGui::TableSetBgColor()
// Background colors are rendering in 3 layers:
//  - Layer 0: draw with RowBg0 color if set, otherwise draw with ColumnBg0 if set.
//  - Layer 1: draw with RowBg1 color if set, otherwise draw with ColumnBg1 if set.
//  - Layer 2: draw with CellBg color if set.
// The purpose of the two row/columns layers is to let you decide if a background color changes should override or blend with the existing color.
// When using ImGuiTableFlags_RowBg on the table, each row has the RowBg0 color automatically set for odd/even rows.
// If you set the color of RowBg0 target, your color will override the existing RowBg0 color.
// If you set the color of RowBg1 or ColumnBg1 target, your color will blend over the RowBg0 color.
enum ImGuiTableBgTarget_
{
    ImGuiTableBgTarget_None                         = 0,
    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)
};
ocornut commented 4 years ago

Issues / Todo list

Some of the stuff remaining in my current todo list

Sizing behaviors

Render, clipping, borders, background color

Keyboard/Gamepad Navigation

Headers, context menu

Sorting

Documentation

Demo

soulthreads commented 4 years ago

What do you think would be the best way to implement a table tree view with this API? Something like, say, QTreeView. Or is this out of scope for now?

Folling commented 4 years ago

It's entirely possible to use TreeNode with the table API, which should be enough to recreate a widget akin to QTreeView

hofstee commented 4 years ago

General Questions

Notes

Feedback

ocornut commented 4 years ago

@soulthreads I am working on a Tree view demo right now. I think there may be currently some problems with how indentation is handled accross multiple columns. Will post when I have a demo.

@hofstee

If you're in the first/last row of a table, and you scroll upwards/downwards, should that scroll the parent window?

That's a good idea, thought not inherently a table feature. I'll add something in my todo list about the possibility for child windows to forward scroll requests to their parent when already at a limit. (EDIT: there's a ImGuiWindowFlags_NavFlattened flag that attempts to do that but it's not fully functional)

Are cells selectable? Copy/Paste/Context Menus on individual cells?

Will be working on selection patterns in the upcoming months. You can already use Selectable() and the ImGuiSelectableFlags_SpanAllColumns flag but there's lots to do to provide variety of solid selection scheme (expose ways to alter per-cell bg/borders, expose index>display map, interface with range-selection branch). I don't have very specific answers or ETA.

Should the column list in the context menu for hiding be in the same order as the columns visibly appear?

I personally don't think it does as I modelled it after Windows Explorer which shows this list in default order. I think it has the advantage of highlighting important columns. I'd be curious to know if other OS/toolkits uses a different scheme.

Echoing the todo about per-column horizontal alignment. I have a column with names that are hundreds of characters long but the most important part of the name is on the right side

I don't it as a table-specific feature but we should generally aim to provide ellipsis/clipping settings to e.g. Text functions. When we have this features we could imagine that table columns should store and forward this setting as a convenience. I think when we start refactoring text functions we will work on low-level features to enable this.

I like the way that resizing is handled. At first, it bugged me that extending a column in the middle would shrink the columns to its right, but when you shrink the middle column the other columns expand in the ratio they had prior so I'm ok with it.

It's a lot more complicated than you'd imagine as they are lots of rules depending on the order and number of columns of each sizing policy. So you'll probably stumble on cases where it behave differently than this too. There are generally good reasons for it but they are very unobvious to the user :/

Reordering columns feels a bit weird. I think I might personally prefer if it didn't reorder until you pass more than halfway through the next column.

I will experiment with this. I also had code to smoothly move the columns but it was incredibly complicated and eventually decided to ditch/stash it (was requiring z-ordering of elements, with side-effects on inputs, alpha blending, draw channels etc.). Surprisingly, alpha blending was the trickiest issue to solve. Comment in my stashed code says:

// To handle smooth reordering of columns, initially we tried to offset the entire column (headers + row).
// This is possible but we ran into a problem where it is difficult to draw the correct background color for the front-most column,
// because 1) we don't know what the actual background color was, 2) we don't want to be overlaying the same transparent color twice.
// Instead we decided to only offset the header row, for which we control what the background is, and can make it non-transparent.
// The complications involved with offsetting only the header rows are simpler to handle.

Hidden columns behave strangely with reordering.

Thanks, will look at this! EDIT: Fixed

With many columns, I think the context menu has the potential to get very long and crowded. Maybe a Hide option when right-clicking a column would be helpful? Should this be left to the user to implement?

Will see when it happens, we might want to add dedicated context menu hints.

joeslay commented 4 years ago

I haven't used the new tables API yet, but hopefully I have some useful feedback as I implemented tables with a bunch of similar features to this a while back using the old columns API.

While a lot of table features look great with a trivial/nice/small examples data and you can do a lot of cool stuff, once I connected it to some real data into it and tried to interact / understand the table/data a lot of features became useless almost immediately when the number of table rows was 50+, nevermind 500+.

Put simply, features like sorting were only useful in tables where the sorting by a column happens to put the thing your looking for at the top of the list in the first ~10 item.

Anyway. long story short, I'm not sure if it's in your plans to build in directly, but the feature that made the tables usable for me was putting basic per column filtering based on data type directly in the table.

So in your example, my IDs columns (number data type) could filter for all items > 12 (comparison operator could changable) The Name column (string data type) could filter for strings containing "Apr" This would give me just the Apricot item.

There's a few more filter types you can implement like for enums, but you get the idea. Only in a trivial example does it seems a bit pointless, but the goal when I was implementing this pretty much went from implementing the table features you've made to be able to find / filter for as many subsets of data in a dataset into a trivial/nice/small sizes so that "last mile" features like sorting by column were much more usable.

ocornut commented 4 years ago

the feature that made the tables usable for me was putting basic per column filtering based on data type directly in the table.

That makes sense of course, if you have tables with 100+ you want some sort of search going on. That's perfectly implementable already with what you have available. I'm not sure what you expect Dear ImGui to provide here, there are an infinite ways of filtering things (math ops, all kind of regexps). There's no concept of "data type in the table", tables are layout helper where you output your own data and that can be anything.

I agree we could provide more elaborate demo/examples code of doing things like that, adding that to my list.

joeslay commented 4 years ago

Yeah it was pretty easy to implement simple/generic filters, the issues (besides columns api constraints/bugs) were pretty minor but mostly being space constrained to fit a filter in the column space and getting the look/interaction mechanics somewhat acceptable.

I wouldn't expect imgui to do much, if you've implemented native support for regexes things have probably gone very wrong. It would be as if Valve had implemented regexes to help find the games you own in your steam library for those 0.01% of users.

However I think there is compromise, I've not had much time to think about what the interface/implementation inside imgui would look like, but maybe you could optionally define some filtering flag for a given column for basic operations, trying to get you 95% there with little effort and not trying to hunt the last 5%. But like you say, it might also be better done in just a demo/example.

ocornut commented 4 years ago

@joeslay You are right and will definitively work on this at some point. The optimal way to handle coarse clipping along with filtering requires sorting e.g. a filtered list of index anyway, so it would be good to provide a demo. This is very similar to the data structure ideally required for large range-multi-selection patterns (see features/rangeselect branch #1861). I will likely work on both filtering demos and range-select demos hand in hands.

Speaking of which I have fixed the indentation issue and added a simple Tree View demo now (cc: @soulthreads @folling)

image

The ultimate target is to get large tree view with clipping, multi-select, range-select. This should currently be possible if merging both tables and rangeselect features but requires some work on a demo. I have a feeling those branches may converge soon.

randallrvr commented 4 years ago

Could a ImGuiTableFlags_ScrollFreezeBottomRow be added? Sometimes it is nice to have a row of totals at the bottom of a table. Also, is there any intended functionality for cells to span columns or rows?

ocornut commented 4 years ago

@raegnar

Sometimes it is nice to have a row of totals at the bottom of a table.

Ouch, I didn't think of that. Adding to todo list but it may not be easy right now (though you should be able to create second table with same id right below the first one)

Also, is there any intended functionality for cells to span columns or rows?

Spanning multiple columns I will consider looking into but not too easy (will look after reworking all the border drawing code). Spanning multiple rows is much weirder/trickier but also less useful maybe? Because we don't know row height ahead it'd be difficult to implement.

randallrvr commented 4 years ago

Is there a way to query the column widths from the first table? I've tried the second table with the same id, but it seems to override the column width sizing.

ocornut commented 4 years ago

Is there a way to query the column widths from the first table? I've tried the second table with the same id, but it seems to override the column width sizing.

The sizes should be synchronized so you shouldn't not have query any width. If you do two successives BeginTable()/EndTable() with same id they are normally synchronized. If you can't get it to work please open a separate issue for it, thanks!

j-zeppenfeld commented 4 years ago

This is looking very nice - so much more flexible than the columns API!

I'm still missing the ability to select table rows, specifically when the table is paired with interactive widgets such as buttons or tree nodes. Adding the following to the demo:

                 static void DisplayNode(const MyTreeNode* node, const MyTreeNode* all_nodes)
                 {
                     ImGui::TableNextRow();
+                    ImGui::Selectable("##select", false,
+                                      ImGuiSelectableFlags_SpanAllColumns |
+                                      ImGuiSelectableFlags_AllowItemOverlap);
+                    ImGui::SameLine();
                     const bool is_folder = (node->ChildCount > 0);
                     if (is_folder)
                     {

basically works, but is not at all pretty, since the Selectable "disappears" when the TreeNode is hovered. This is generally a problem with Selectables over interactive widgets, and it would be very nice to see this addressed by the table selection mechanics you are working on.

xpenatan commented 4 years ago

Hi, I deleted my posts earlier to attempt a new way to find the row height. In my earlier post I tried to edit internal table code but now I added the code to my ImGuiEx Library. If you can add the code or use the idea to find the row height it would be great.

What I would like to have is a method that will tell the height of a row. If any cell content change its height it will update the row height value.

This example shows it in action along with my Layout lib solution that align the "A0 Cell 1" text.

gif2

To try it out you can download the c++ files from

The tableEx methods used are GetTableContentHeight() CalculateTableRowHeight() GetTableRowHeight()

Thanks

eRabbit0 commented 4 years ago

Fantastic job with new tables!

On the subject of alignment - why not add header alignment? As a solution it could be implemented with flags, something like: imgui.h

` 
enum ImGuiTableColumnFlags_ 
{
    ImGuiTableColumnFlags_AlignLeft     = 1 << 29,    // left align cell content
    ImGuiTableColumnFlags_AlignCenter       = 1 << 30,    // center align cell content
    ImGuiTableColumnFlags_AlignRight        = 1 << 31     // right align cell content
};
` 

imgui_widgets.cpp

`
void    ImGui::TableHeader(const char* label) 
{
     if ((table->Flags & ImGuiTableFlags_Sortable) && !(column->Flags & ImGuiTableColumnFlags_NoSort)) {
        if (column->SortOrder != -1) {
              w_arrow = ImFloor(g.FontSize * ARROW_SCALE + g.Style.FramePadding.x);  // w_arrow is calculated only for sorting column
        }
    }
...
    if      (column->Flags & ImGuiTableColumnFlags_AlignCenter)     label_pos.x += (column->WidthGiven - label_size.x - g.Style.CellPadding.x) / 2;
    else if (column->Flags & ImGuiTableColumnFlags_AlignRight)      label_pos.x +=  column->WidthGiven - label_size.x - g.Style.CellPadding.x - w_arrow;

    RenderTextEllipsis(...)
}
`

Screenshot from 2020-01-16 07-18-10 Screenshot from 2020-01-16 07-18-20

It does seem to behave nicely and is very easy to implement. Please correct me if i am missing something.

eRabbit0 commented 4 years ago

I also noticed some misalignment of highlighted part of the header (on the right side): Screenshot from 2020-01-16 07-24-28 Tried different flags, but behaviour is persistent and happens for every column. Could be a bug stemming from behaviour of ImGui::Selectable() in this line of imgui_widgets.cpp:

const bool pressed = Selectable("", selected, ImGuiSelectableFlags_DrawHoveredWhenHeld, ImVec2(0.0f, label_height));

But i'm not sure.

eRabbit0 commented 4 years ago

What would be the best way to implement tooltips for the header? For now i can use TableSetupColumn (NULL, flags, width); and then in a helper so something like:

TableHeader (actual_label);
If (IsItemHovered ()) {
   show_something();
}
TableNextCell ();
 

Am i doing it right or is there better solution to tackle the problem?

ocornut commented 4 years ago

About row selection, TreeNode, Selectable

@j-zeppenfeld Please open a dedicated issue for it. This is at the cross-over of several features. On one hand, I'm going to add internal api to make it easy to colorize row/lines/cells so that will be used for selection visuals. The wider issue is that the reach and features scope of Selectable vs TreeNode have been overlapping and confusing because none of them provide all the features we want. I think there's more general table-agnostic rework to do on them, maybe a new, better widget that covers the desirable feature set of both. Note in the meanwhile that TreeNode has a ImGuiTreeNodeFlags_Selected.

Since the canonical use case of Tables will be to provide e.g. large selectable trees we will aim to provide such demo and implement whatever is needed. I think the features/rangeselect branch will probably also converge into Tables.

About row height

@xpenatan: You can't calculcate a guaranted row height for the current frame before the full row (all cells) have been submitted. It's just not possible since any cell can extend the row height.

Possible workaround are:

-> If you want to discuss the topic of Tables Row Height please open a dedicated issue for it.

About horizontal alignment of headers

On the subject of alignment - why not add header alignment?

@eRabbit0 I had those exact flags during earlier work but removed them. We can only align 1 item over 1 line, anything else won't work and proper multi-item multi-line alignment wouldn't be a table feature per se. If we offer the option only for Headers, we make it harder for people to use the option with custom headers (multi-item or multi-lines, say the user wants to have a checkbox before the TableHeader call). That said, if we restrict it to single-line header and rely on temporal coherency I could re-enable the feature.

Selectable() are a bit tricky here they were initially designed to cover half of the spacing between each others to avoid leaving any visual and mouse-hover gaps, but we can solve this.

TableHeader()+IsItemHovered() should work I am not sure what you are asking. -> If you to discuss the topic of Tables Column Horizontal Alignment please open a dedicated issue for it.

eRabbit0 commented 4 years ago

I played a bit more with Tables and would like to expand on my issue with Selectable in a header.

Overflow is happening with ImGuiTableColumnFlags_BordersVInner. But, as you can see below, behaviour is predictable with both ImGuiTableColumnFlags_BordersV and ImGuiTableColumnFlags_Borders. Screenshot from 2020-01-16 07-24-28 Screenshot from 2020-01-21 11-36-20

Additionally, when FreezeRow is set, clipping of Selectable could be used for cases like below, when top visible row is selected and/or hovered): Screenshot from 2020-01-21 11-27-11

lunarflint commented 4 years ago

Thanks for the new tables!

I just want to report that clicking on the table headers will close the whole modal dialog.

In case anyone is facing the same issue, the work-around for now is to add these internal function calls

ImGui::PushItemFlag(ImGuiItemFlags_SelectableDontClosePopup, true);
ImGui::TableAutoHeaders();
ImGui::PopItemFlag();

as suggested in a similar issue here.

ocornut commented 4 years ago

@lunarflint Thank you for the report. This now has been fixed by 250f96149e2a70a635b34b30c13ef1df835f4e21.

parbo commented 4 years ago

Is it possible to set the font for each column header? I want some headers to use my icon font and some to use a regular font.

ocornut commented 4 years ago

Is it possible to set the font for each column header? I want some headers to use my icon font and some to use a regular font.

Just push your desired font before submitting the headers?

codz01 commented 4 years ago

hi seems like a bug GIF 05-02-2020 13-41-20

parbo commented 4 years ago

Is it possible to set the font for each column header? I want some headers to use my icon font and some to use a regular font.

Just push your desired font before submitting the headers?

Ah, I had to use ImGui::TableHeader manually, not ImGui::TableAutoHeaders

Now it works fine!

parbo commented 4 years ago

Is it possible to make the sorted column default to descending? I set the table as sortable, and one column to ImGuiTableColumnFlags_DefaultSort | ImGuiTableColumnFlags_PreferSortDescending, but it will still sort it ascending.

parbo commented 4 years ago

This seems to make it do what I want:

--- a/imgui_widgets.cpp
+++ b/imgui_widgets.cpp
@@ -9152,8 +9152,12 @@ void    ImGui::TableSetupColumn(const char* label, ImGuiTableColumnFlags flags,
         // Init default visibility/sort state
         if (flags & ImGuiTableColumnFlags_DefaultHide)
             column->IsActive = column->NextIsActive = false;
-        if (flags & ImGuiTableColumnFlags_DefaultSort)
+        if (flags & ImGuiTableColumnFlags_DefaultSort) {
             column->SortOrder = 0; // Multiple columns using _DefaultSort will be reordered when building the sort specs.
+            column->SortDirection = (column->Flags & ImGuiTableColumnFlags_PreferSortDescending)
+                                        ? (ImS8)ImGuiSortDirection_Descending
+                                        : (ImU8)(ImGuiSortDirection_Ascending);
+        }
     }
ocornut commented 4 years ago

@codz01 Fixed this bug in 978a3e700 It's a little tricky because Table-wide ImGuiTableFlags_SizingPolicyFixedX without ImGuiTableFlags_Resizable promote columns to ImGuiTableColumnFlags_WidthAlwaysAutoResize which can be misleading and confusing especially with that particular mode of the demo outputting a right-aligned Button(). I think I will rework some of the sizing policy wording and naming at some point.

@parbo:

Just push your desired font before submitting the headers? Ah, I had to use ImGui::TableHeader manually, not ImGui::TableAutoHeaders Now it works fine!

It should work in both cases and I just tested and confirmed it here. TableAutoHeaders() mostly just submit TableHeaders() so there should not be any difference between both, as long as they are surrounded with the PushFont/PopFon calls.

Is it possible to make the sorted column default to descending? I set the table as sortable,

Applied your fix now, thank you!

ocornut commented 4 years ago

Note, I have fixed a bug with the arrow direction displayed for sort direction, and also removed SortSign from ImGuiTableSortSpecsColumn.

See d456e19 and #3023

I removed SortSign from ImGuiTableSortSpecsColumn because it was both duplicate from SortDirection (therefore misleading/confusing) and because different sort functions work differently this integer value/sign was also more misleading. Better removed!

sab24 commented 4 years ago

Scrolling in a table with horizontal scrollbar seems to get stuck on MacOs. I tried both Glfw with OpenGL3 and Vulkan. When moving the scrollbar while click dragging the mouse is fine, by using the touchpad it does not move left and right.

Code is like this:

ImGui::BeginChild("##AthletesTable");

    int ncolumns = 9 + raceobj.readpoints.size() * 4;
    ImVec2 size = ImVec2(0, ImGui::GetTextLineHeightWithSpacing() * 7);

    static ImGuiTableFlags flags = ImGuiTableFlags_ScrollX | ImGuiTableFlags_ScrollY; 
    std::string tstring = "cell content";
    if (ImGui::BeginTable("##AthletesTable", ncolumns, flags, size)){
        ImGuiListClipper clipper(10);
        while (clipper.Step()){
            for (int i = 0; i < 10; i++){
                ImGui::TableNextRow();
                for (int j = 0; j < 5; j++){ 
                    if (i >= clipper.DisplayStart && i < clipper.DisplayEnd){
                        ImGui::TableSetColumnIndex(j);
                        char label[10];
                        std::sprintf(label, "##%d%d", i, j);
                        ImGui::InputText(label, tstring.data(), (size_t)tstring.size() + 1, ImGuiInputTextFlags_CallbackResize, MainWindow::inputTextCallback, (void*)&tstring);
                    }
                }
            }
        }
        ImGui::EndTable();
    }
    ImGui::EndChild()

1

sab24 commented 4 years ago

The problem was with the clipper.

ImGuiListClipper clipper;
clipper.Begin(100);

solved the problem.

johanwendin commented 4 years ago

Great work on this API so far - intuitive to use and works great, for the most part. :)

Some issues that might be related to stuff you've already mentioned:

ImGui::ScrollToBringRectIntoView seems to ignore frozen columns/rows

(the rect is "in another cell" below the frozen column and thus not visible - not sure how to handle this - maybe have frozen cells/rows as "not visible" regions?), possibly related to this:

B. Clipper: should keep going without advancing step while table row is within frozen count > probably need to just rewrite clipper nicely.

Edit: A ImGui::ScrollToBringTableCellIntoView function would be even better!

I've locally needed to display which row was "selected" or "current". I did this by adding:

ImGuiTableRowFlags_Selected
ImGuiCol_TableRowBgSelected

// and at the bottom of ImGui::TableBeginRow
if (table->RowFlags & ImGuiTableRowFlags_Selected)
{
        table->RowBgColor = GetColorU32(ImGuiCol_TableRowBgSelected);
}

Could possibly be solved much more nicely with this related item:

B. Per-cell background color override. Also easy to do per-row, per-column?

All in all, very good job on this!

eRabbit0 commented 4 years ago

As an expansion for the tables API, would be nice to be able to set row colour directly. There are many use cases, e.g. when you want to group entries as in the image below. Currently it is doable with ImGuiTableFlags_RowBg, but clunky.

Screenshot from 2020-06-18 23-49-34

MunWolf commented 4 years ago

Would it be possible to initialize the table with multi column sorting? (Note would also like to have that multi sort available without enabling user sorting).

Aborres commented 4 years ago

I was testing the tables API with the latest docking branch (so not sure if you will care about "bugs" out of the tables branch).

I have noticed something that I am not sure if it is intended bhv so I wanted to mention it just in case. if you have two tables in the same window (with different IDs) and you are using the ImGuiTableFlags_ScrollY flag in both. The second table gets collapsed and disappears.

The flag mentions "Require 'outer_size' parameter of BeginTable() to specify the container size."

And yes, adding a vertical fixed size to the outer_size, fixes the problem from the images. It wasn't obvious to me at first that if I didn't have an outer size, the table would disappear, I can't think of any other imgui "widget" that does that. Would it be possible to maintain the default size of the table and autoscroll the header if the outer size is 0?

Without the flag: image

With the flag: image

  const ImGuiTableFlags flags = ImGuiTableFlags_ScrollY;

  ImGui::Begin("CC");
  if (ImGui::BeginTable("TestTable", 2, flags)) {
    ImGui::TableSetupColumn("A", ImGuiTableColumnFlags_None);
    ImGui::TableSetupColumn("B", ImGuiTableColumnFlags_None);
    ImGui::TableAutoHeaders();

    ImGui::TableNextRow();
    ImGui::TableSetColumnIndex(0);
    ImGui::Text("%d", 0);
    ImGui::TableSetColumnIndex(1);
    ImGui::Text("%d", 1);

    ImGui::EndTable();
  }

  if (ImGui::BeginTable("TestTable1", 2, flags)) {
    ImGui::TableSetupColumn("A", ImGuiTableColumnFlags_None);
    ImGui::TableSetupColumn("B", ImGuiTableColumnFlags_None);
    ImGui::TableAutoHeaders();

    ImGui::TableNextRow();
    ImGui::TableSetColumnIndex(0);
    ImGui::Text("%d", 0);
    ImGui::TableSetColumnIndex(1);
    ImGui::Text("%d", 1);

    ImGui::EndTable();
  }

  ImGui::End();

I could attach the debug report if you want more info to repro. Thanks

parbo commented 4 years ago

In my project, I want to support doubleclick on rows. To do this I've been using ImGui::Selectable with ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowDoubleClick in a zero-width column. This works fine. But when I updated to the latest ImGui today it seems like it messes up the header height calculations.

This example:

    const int ROWS_COUNT = 3;
    const int COLUMNS_COUNT = 3;
    static int double_clicked[ROWS_COUNT] = {0};
    if (ImGui::BeginTable("##table1", COLUMNS_COUNT)) {
      ImGui::TableSetupColumn("Apricot");
      ImGui::TableSetupColumn("Banana");
      ImGui::TableSetupColumn("Cherry");

      ImGui::TableNextRow(ImGuiTableRowFlags_Headers /*, ImGui::GetTextLineHeightWithSpacing()*/);
      for (int column = 0; column < COLUMNS_COUNT; column++) {
        ImGui::TableSetColumnIndex(column);
        ImGui::PushID(column);
        ImGui::TableHeader(ImGui::TableGetColumnName(column));
        ImGui::PopID();
      }

      for (int row = 0; row < ROWS_COUNT; row++) {
        for (int column = 0; column < COLUMNS_COUNT; column++) {
          char buf[32];
          sprintf(buf, "Cell %d,%d", row, column);
          ImGui::TableNextCell();
          if (column == 0) {
            if (ImGui::Selectable(
                    buf,
                    false,
                    ImGuiSelectableFlags_SpanAllColumns | ImGuiSelectableFlags_AllowDoubleClick)) {
              if (ImGui::IsMouseDoubleClicked(0)) {
                double_clicked[row]++;
              }
            }
          } else {
            ImGui::Text(buf);
          }
        }
      }
      ImGui::EndTable();
    }
    for (int row = 0; row < ROWS_COUNT; row++) {
      ImGui::Text("Double-clicked %d times on row %d.", double_clicked[row], row);
    }

Turns out like:

image

The fix for now is the commented out part to set min row height for the header row.

ocornut commented 4 years ago

@parbo

This works fine. But when I updated to the latest ImGui today it seems like it messes up the header height calculations.

This is a bug introduced in 2c676770, it's unrelated to the contents of your rows, it's just that TableHeader() doesn't properly extend the content height so the header row ends up being minimum size (~cellpadding.y * 2). Now fixed by 56b0485daa0a10087033021281a30245fd3539d5.

There's some smelly code left-over in there caused by the fact I want to support customs widgets in the header lines.

ocornut commented 4 years ago

@johanwendin

ImGui::ScrollToBringRectIntoView seems to ignore frozen columns/rows A ImGui::ScrollToBringTableCellIntoView function would be even better!

Right, will look into that.

@eRabbit0

As an expansion for the tables API, would be nice to be able to set row colour directly.

Yes this planned and in the todo list above.

@MunWolf

Would it be possible to initialize the table with multi column sorting? (Note would also like to have that multi sort available without enabling user sorting).

Everything is in the demo. Since sorting the data to submit is on your end, if you don't want to expose the sorting button to the user there's nothing for dear imgui to provide, feel free to sort your data however you want.

@Aborres

I have noticed something that I am not sure if it is intended bhv so I wanted to mention it just in case. if you have two tables in the same window (with different IDs) and you are using the ImGuiTableFlags_ScrollY flag in both. The second table gets collapsed and disappears. [...] And yes, adding a vertical fixed size to the outer_size, fixes the problem from the images. It wasn't obvious to me at first that if I didn't have an outer size, the table would disappear, I can't think of any other imgui "widget" that does that. Would it be possible to maintain the default size of the table and autoscroll the header if the outer size is 0?

It's not that it disappears, it is that the first table fills the height available in the window. We can't by definition decide of sensible default height if the container is meant to scroll, so we default to "fill available space". The only change I can think of would be to require the user to specify a size, aka assert if size is (0,0). The same thing would happen if you create two child windows without specifying their height.

ocornut commented 4 years ago

Added a WIP api for altering Row or Cell background color. I iterated quite a lot on this to find a flexible and suitable solution that would also be fast. It's currently missing support for changing the color of a whole Column (hopefully coming soon).

In my earlier draft I wanted to make it possible for CellBg color to completely overlap (no blending) ColumnBg or RowBg, which required storing a mask of drawn cell bg colors for each visible row and render a masked out selection. I have some unfinished code for that but I don't think it is worth the complexity, you can always set CellBg to be opaque anyway so the only remaining bonus would be to save on fill-rate and I think that's absurdly negligible at this point. However I'm going to use some of that uncommitted code for tracking visible rows so I can simplify and improve the Borders rendering code down the line.

Here's the current API:

void TableSetBgColor(ImGuiTableBgTarget bg_target, ImU32 color, int column_n = -1);
// Enum for ImGui::TableSetBgColor()
// Background colors are rendering in 3 layers:
//  - Layer 0: draw with RowBg0 color if set, otherwise draw with ColumnBg0 if set.
//  - Layer 1: draw with RowBg1 color if set, otherwise draw with ColumnBg1 if set.
//  - Layer 2: draw with CellBg color if set.
// The purpose of the two row/columns layers is to let you decide if a background color changes should override or blend with the existing color.
// When using ImGuiTableFlags_RowBg on the table, each row has the RowBg0 color automatically set for odd/even rows.
// If you set the color of RowBg0 target, your color will override the existing RowBg0 color.
// If you set the color of RowBg1 or ColumnBg1 target, your color will blend over the RowBg0 color.
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)
};

image

image

eRabbit0 commented 4 years ago

Really like the blending!

One thing which i stumbled upon while testing new TableSetBgColor is when i apply ImGuiTableBgTarget_RowBg1 to any row but the header, i cannot select those rows, hover doesn't work either. Though it is perfectly fine when used on the header row. No problems at all with RowBg0 and CellBg.

Some additional thoughs: 1) Priority of the colors. If RowBg1 is envisioned to be used for selection, then it should override CellBg, and probably future ColumnBg0. 2) Selectable on hover and for selected rows should behave the same as above, otherwise it could look like this (applied extreme color to make the point): Screenshot from 2020-07-29 23-26-48

Here we have (for the first 3 rows):

sdhawk commented 4 years ago

This may already be covered with the clipper items on the todo, but I'm not sure. Popups that use a clipper within a table throw an error when creating the clipper within the popup.

Assertion failed: window == table->InnerWindow, file imgui_widgets.cpp, line 9480

void Sample()
{
    ImGui::Begin("Window");
    ImGui::BeginTable("Table", 2);

    ImGui::TableNextRow();
    ImGui::TableSetColumnIndex(0);
    ImGui::Text("Column 0");

    ImGui::TableSetColumnIndex(1);
    if (ImGui::Button("Open"))
        ImGui::OpenPopup("Popup");

    if (ImGui::BeginPopupModal("Popup"))
    {
        ImGuiListClipper clipper = ImGuiListClipper(100);
        while (clipper.Step())
        {
            for (int x = clipper.DisplayStart; x < clipper.DisplayEnd; x++)
                ImGui::Text("%d", x);
        }

        ImGui::EndPopup();
    }

    ImGui::EndTable();
    ImGui::End();
}
ocornut commented 4 years ago

@sdhawk Fixed this issue now, thanks for reporting!

epezent commented 4 years ago

@ocornut, just wanted to drop in and say that Tables play really nicely with ImPlot. Still learning the API but I love it!

tables

hoffstadt commented 4 years ago

@ocornut I apologize in that I have not yet played with the new table API. As always, great work on everything you do. For DearPyGui, I made a simple table widget using the columns API and selectables. It was really just a Band-aid while waiting for this branch to merge with master. However with the recent explosion of popularity, we receive requests everyday for more features.

You mention that the API is evolving (understandably), however are there any parts of the API that we can expect to remain? Initially we would just wrap the minimum number of features and gradually add more. I imagine this would help find issues with the API as we have several thousand users who would be using it immediately once we added it in.

Are certain parts of the API not expected to change?

ocornut commented 4 years ago

I'm genuinely confused as to why are apologizing here (?), nor why you find the need to unnecessarily state "we have several thousand users who would be using it immediately" which is one lie followed by one idealistic assumption. Let's move forward by being accurate and genuine else we're not building on solid ground.

Unfortunately I can't predict what is expected to be stable or evolve but I'm hoping we'll know more by 1.80. There are such so many daily queries here and there which are eating time out from working on Tables so I am not able to provide much guarantees or ETA there.

hoffstadt commented 4 years ago

Wow. I don't understand the reason to be rude to me.

  1. I apologized because I haven't had time to test or follow the progress of the tables API and assumed I may be asking a question that's been asked before.

  2. We do have a few thousand users using DearPyGui, 2300 downloads in that last month, and ~1000 the previous month.

  3. I claimed they would be using it "immediately" because we've been pushing out updates almost daily, which most users seem to be upgrading as soon after doing so.

Again sorry for asking...

ocornut commented 4 years ago

I am just saying there’s no need for hyperboles, you know that N downloads doesn’t equate N users, let alone users of a specific unfinished api. I support your effort, but consider that on many topics even dear imgui is lacking feedback when asked. So let’s be realistic with the numbers.

If you are curious/interested about finding how the Tables API could be expressed nicely in your RM system I am sure that most of the work won’t be waster either way, but let your users know to be cautious as its hard to provide api guarantees.

hoffstadt commented 4 years ago

We did decide to go ahead start bringing in the new table API (along with docking and multiple viewports), but will require users to explicitly import these features from an "experimental" module. Hopefully, we can provide some good feedback.