-
-
Notifications
You must be signed in to change notification settings - Fork 10.3k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Tables: content covering the entire row or spanning multiple columns #3565
Comments
Hello, The way More general cell-spanning is currently unimplemented and it is in the TODO list (visible in the main Tables thread), but "full row spanning" should be easier to implement as we already have a suitable clip rect. Some complication coming to mind:
I'll have to think about if there are quick paths to get that done, but in the meanwhile if you push a clip rect while in any column you should be able to render that stuff. |
Hello again Andrew, In my initial answer I overlooked one important feature of tables, which is that same-id table share their settings and storage. What it means is that in some usage contexts, you might be able to solve your problem by just closing the table, outputting your stuff and then reopening. Now, arguably this is a bit of a workaround and it is likely to incur noticeable overhead if you use it a lot (e.g. for every line). But it may be a good workaround for more occasional use. |
Thanks Omar. |
Hello Omar.
Thank you for this suggestion, it helped me a lot! I would like to point out a small pitfall that I encountered. The struct ImGuiTable {
ImS16 InstanceCurrent; // Count of BeginTable() calls with same ID in the same frame (generally 0). This is a little bit similar to BeginCount for a window, but multiple table with same ID look are multiple tables, they are just synched. This means that the ID stack of widgets inside the table(s) can change upon user interaction. In my case this messed with the internal state and behavior of #include "imgui_internal.h"
void f() {
if (ImGui::BeginTable(outer_table_id, column_count, flags)) {
bool outer_table_closed = false;
for (auto const &row : rows) {
if (outer_table_closed && ImGui::BeginTable(outer_table_id, column_count, flags)) {
outer_table_closed = false;
}
ImGui::TableNextRow();
ImGui::TableNextColumn();
bool tree_node_open;
{
auto &id_stack = ImGui::GetCurrentWindow()->IDStack;
auto const outer_table_instance_id = id_stack.back();
id_stack.pop_back();
tree_node_open = ImGui::TreeNodeEx("unique tree node", ImGuiTreeNodeFlags_NoTreePushOnOpen);
id_stack.push_back(outer_table_instance_id);
}
if (tree_node_open) {
ImGui::EndTable();
outer_table_closed = true;
ImGui::Indent();
if (ImGui::BeginTable( /* ... */ )) {
ImGui::EndTable();
}
ImGui::Unindent();
}
}
if (outer_table_closed == false) {
ImGui::EndTable();
}
}
} In my opinion this also happens to look better than having the nested table inside a row of the outer table. Win-win : ) Thanks again for the great library, Omar! |
Thanks for your great idea!
The reason is because the hit test button is built based on LastOuterHeight, so if the last ended table has less height than the current, the button will not cover the entire current height. |
Correct, there is a big bug there with synchronized tables. |
…e of several synchronized instance of a same table ID, when instances have a different height. (ocornut#3955, ocornut#3565)
This would be a great feature and I'd like to upvote. I'm currently writing some code that displays HTML tables in ImGui and was hoping to find the eqivalent of |
I found this issue again searching for a solution to basically the same problem! 😂 I went back to the code I used to solve this initially (which was specialized to that use-case), and after playing around with it for a bit I've ended up with something more general purpose. It pushes/pops a new There may well be edge cases where this breaks, but so far it seems to work. /// Make contents in a table cover the entire row rather than just a single column.
///
/// Always covers the entire row (not just the remaining columns);
/// can sort of coexist with per-column data, but may not be as intended.
/// Accounts for:
/// - scrollbar
/// - header row
/// - column reordering
/// - hidden columns
static inline float
igTableFullRowBegin()
{
ImGuiTable *table = igGetCurrentTable();
// Set to the first visible column, so that all contents starts from the leftmost point
for (ImGuiTableColumnIdx *clmn_idx = table->DisplayOrderToIndex.Data,
*end = table->DisplayOrderToIndex.DataEnd;
clmn_idx < end; ++clmn_idx)
{ if (igTableSetColumnIndex(*clmn_idx)) break; }
ImRect *work_rect = &igGetCurrentWindow()->WorkRect;
float restore_x = work_rect->Max.x;
ImRect bg_clip_rect = table->BgClipRect; // NOTE: this accounts for header column & scrollbar
igPushClipRect(bg_clip_rect.Min, bg_clip_rect.Max, 0); // ensure that both our own drawing...
work_rect->Max.x = bg_clip_rect.Max.x; // ...and Dear ImGui drawing will be visible across the entire row
return restore_x;
}
static inline void
igTableFullRowEnd(float restore_x)
{
igGetCurrentWindow()->WorkRect.Max.x = restore_x;
igPopClipRect();
} Usage: float restore_x = igTableFullRowBegin();
igSeparatorText("Look - the whole row!"); // whatever content you want here
igTableFullRowEnd(restore_x); |
@howprice I haven't tried it but I believe the same technique could be used to create arbitrary-length
You could make this work with columns that can be reordered, but I'm not sure if it makes any sense to do so. |
@azmr thanks for that code snippet! I've noticed that in a table with auto-fit enabled ( To prevent that, one needs to save/restore @ocornut can you please take a look at that code snippet above and give some comments on whether it "feels right", taking into account how the table is rendered? All those channels, merging, layout, etc. - I haven't reached the zen of it yet. I'm curious to know whether such manipulations can degrade performance or lead to other unexpected side effects P.S. One expected side effect is that vertical inner borders cross through that full-width row (as you mentioned before); I circumvent it by using another nested table with opaque background -- nasty but it works. |
I don't have bandwidth/energy to investigate this presently, sorry I have to juggle with things to take care of. For full row it is a much simpler problem, and you can do what One problem with "spanning multiple columns" is that the amount of possible columns pairs is large, so for efficiency we ought to maybe dynamically allocate draw channels for each unique pair that's been being. For the bordering and other decorations, my expected approach will be to introduce a PS: The code is generally not easy to work with because of performance concerns. It's easy to get things done, but not as easy optimally. |
Note that for widgets which may lend themselves to be drawn over full row (and probably SeparatorText is one of those case) we can also add a specialized flag. |
One more thing I noticed is that the loop after the "Set to the first visible column" comment might lead to weird results when the table is being scrolled and leftmost columns get out of the visible area. In this example, the rows at the top and at the bottom are regular rows, whereas the two rows in the middle contain full-width cells: It would be better to use ImGui::TableSetColumnIndex(table->LeftMostEnabledColumn >= 0? table->LeftMostEnabledColumn : 0); |
Branch: tables (using cimgui-generated code)
My Issue/Question:
I'm liking the tables API so far but I've hit the edge of what I can easily see how to do.
I'm trying to have some content (a graph currently) span all columns in a new row of the table.
Some approaches I've tried/considered:
NoClipX
- I don't seem to be able to set this midway through the tableNoClipX
- I don't seem to be able to actually have it at 0-width, even withNoKeepColumnsVisible
on the tableEndTable
, do the graph, thenBeginTable
again - this is currently slightly awkward given that there are other IDs pushed fromTreeNode
s on the table. I'd also like to be able to have them all in the same scroll section when I continue the table (although I suppose I could wrap it again in a child window - but then the headers would get lost).This would be harder to do if I wanted to nest a table inside the row of another table and have both scrollable and using the same ID (so that their columns move in tandem).
BeginCell
/EndCell
code to make the draw rect cover the whole row. This seems like it's likely to break with future versions...If you were to expand the API, some options might include:
PopID
to return theImGuiID
that it takes off theIDStack
, to make it easier to collate them on the user-side before pushing them again.ImGuiTableRowFlags
to specify full-row contentScreenshots/Video
The text was updated successfully, but these errors were encountered: