Skip to content
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

Table Persistence optimization is breaking reloads. #7934

Open
lailoken opened this issue Aug 29, 2024 · 11 comments
Open

Table Persistence optimization is breaking reloads. #7934

lailoken opened this issue Aug 29, 2024 · 11 comments
Labels
bug settings .ini persistance tables/columns test wanted Should add corresponding test to ImGuiTestSuite

Comments

@lailoken
Copy link

Version/Branch of Dear ImGui:

1.91-docking

Back-ends:

SDL

Compiler, OS:

Linux + GCC

Full config/build information:

No response

Details:

I'm using multiple save / restore config calls including both ImGui window layout and table layout in order to store and retrieve "workspaces".

This works beautifully, window positions, etc. are restored and table information as well.

I can switch back and forth between config by loading the ini no problem and windows update responsively.

However, I've noticed that some tables sometimes seem to lose their column information, and I've traced it down to an optimization in imgui_tables.cpp (line 3634 onwards), If I change the code as indicated, my INI is slightly larger, but it all works.

how to reproduce
The issue is when a table is created with a default visibility (let's say hidden),
Then that visibility is not stored in the config when the user persists the state.
If the config is loaded into a new environment it works, but if the user made those columns visible, then loaded the config that had it hidden, then the columns are not hidden since those INI items were not written.

I expected it to work the same way with window positions that are persisted even though they have not been moved from their default initial location.

The window example is sensible, and I can understand why the optimization for table column state was initially added, but I think removing it may be more robust.

I'm assuming very few other people use config to switch workspaces on the fly like this.

Screenshots/Video:

No response

Minimal, Complete and Verifiable Example code:

        // We skip saving some data in the .ini file when they are unnecessary to restore our state.
        // Note that fixed width where initial width was derived from auto-fit will always be saved as InitStretchWeightOrWidth will be 0.0f.
        // FIXME-TABLE: We don't have logic to easily compare SortOrder to DefaultSortOrder yet so it's always saved when present.
        if (width_or_weight != column->InitStretchWeightOrWidth)
            settings->SaveFlags |= ImGuiTableFlags_Resizable;
        if (column->DisplayOrder != n)
            settings->SaveFlags |= ImGuiTableFlags_Reorderable;
        if (column->SortOrder != -1)
            settings->SaveFlags |= ImGuiTableFlags_Sortable;
        if (column->IsUserEnabled != ((column->Flags & ImGuiTableColumnFlags_DefaultHide) == 0))
            settings->SaveFlags |= ImGuiTableFlags_Hideable;

should perhaps just be:

        settings->SaveFlags |= ImGuiTableFlags_Resizable;
        settings->SaveFlags |= ImGuiTableFlags_Reorderable;
        settings->SaveFlags |= ImGuiTableFlags_Sortable;
        settings->SaveFlags |= ImGuiTableFlags_Hideable;
@ocornut ocornut added tables/columns settings .ini persistance labels Sep 3, 2024
@ocornut
Copy link
Owner

ocornut commented Feb 10, 2025

I think perhaps the issue could be tackled at the loading stage rather than the saving stage.

I tried to build a repro and noticed it only seems to happens for the Hidden state:

Image

Do you get it for other states?

if (ImGui::Shortcut(ImGuiKey_F1, ImGuiInputFlags_RouteGlobal))
    ImGui::LoadIniSettingsFromDisk("imgui_1.ini");
if (ImGui::Shortcut(ImGuiKey_F2, ImGuiInputFlags_RouteGlobal))
    ImGui::LoadIniSettingsFromDisk("imgui_2.ini");

imgui_1.ini

[Table][0x951FCC8A,6]
RefScale=13
Column 0  Width=28 Sort=0v
Column 1  Width=70
Column 2  Width=73
Column 3  Width=68
Column 4  Weight=1.0000
Column 5  Width=-1

imgui_2.ini

[Table][0x951FCC8A,6]
RefScale=13
Column 0  Width=28 Visible=1 Order=0
Column 1  Width=159 Visible=1 Order=2 Sort=0^
Column 2  Width=73 Visible=1 Order=3
Column 3  Width=68 Visible=1 Order=4
Column 4  Weight=1.0000 Visible=1 Order=5
Column 5  Width=42 Visible=1 Order=1

@ocornut ocornut added the test wanted Should add corresponding test to ImGuiTestSuite label Feb 10, 2025
ocornut added a commit that referenced this issue Feb 10, 2025
… correctly overridden when hot-reloading .ini state. (#7934)
@ocornut
Copy link
Owner

ocornut commented Feb 10, 2025

I've pushed a fix 4dc9df6 for what I could notice with not reloading Visible/Hidden state correctly, but would like to now if you have other issues.

Keeping this open because I'd like to allow write some more tests for this.

@lailoken
Copy link
Author

The code between master and docking looks too dissimilar for me to apply this patch easily.

But as of docking v1.91.9 WIP, when saving a config containing unmodified settings that match the default, then modifying setting, then restoring the original saved setting, does not restore:

  • column order
  • column visibility
  • column width
  • current sort

@ocornut
Copy link
Owner

ocornut commented Feb 11, 2025

I’ll experiment further with this tomorrow. My test above as shown in the recording seems to work (apart from Hidden state as that’s before my first fix), so there must be something else at play.

@lailoken
Copy link
Author

lailoken commented Feb 11, 2025

I'm not sure if this may be a docking vs. master difference; but reading the code I don't see how to make this work except for writing out all values (including when default).

At the time the config is loaded, the code may have changed the defaults - thus loading config where those values are missing it would be impossible to restore the visual state at the time of the originally save.

This would be consistent behavior with operations like window position (first use ever) : window positions are persisted even if they don't deviate from the initial set values. This allows for reloading to show it at the last position even if the code has since changed the value if the first use ever position.

@ocornut
Copy link
Owner

ocornut commented Feb 12, 2025

The code between master and docking looks too dissimilar for me to apply this patch easily.

I believe it may be only because you are not on most recent version. The branches are fairly tightly synchronized, whenever they are the imgui_tables.cpp file is identical, and cherry-picking the commit on latest docking works (apart from a conflict in changelog.txt). Anyhow I'll do a merge as soon as this is solved if it is solved soon.

At the time the config is loaded, the code may have changed the defaults

I didn't expect/intend to handle this specific case: I believe it is rather unlikely that app code would actually change default, and the "minified" .ini output is practical and advantageous in the typical use case.
But it would make sense for people storing .ini files for this purpose to have a more verbose/explicit-value saving mode, I can add one.

So there are two issues IMHO:

  • (1) If anything doesn't get restored properly with app code not changing default: there's a clear bug to fix. For this, I presently don't have a repro as my test case above works. Would you mind posting your ini files and maybe a gif/shot of result after loading + BeginTable/TableSetupColumns() flags?
  • (2) I will separately see how I can expose a more verbose saving mode.

I'd appreciate if we can also solve 1 separately, although I understand that always-enabling (2) would naturally solve (1).

And for avoidance of doubt:

If the config is loaded into a new environment it works, but if the user made those columns visible, then loaded the config that had it hidden, then the columns are not hidden since those INI items were not written.

This specific issue was solved on Monday.

@ocornut
Copy link
Owner

ocornut commented Feb 12, 2025

Another reason I'd like to dig for (1) is there I think there's something smelly that may be deeper (even if not that harmful).

The change in fae362f (Oct 2020) which exists today as if (has_auto_fit_request) { table->IsSettingsDirty = true; } seem subtly faulty as it is prematurely marking certain tables for saving even thought they shouldn't.

Could you clarify if for the table where you are having an issue there is a corresponding [Table] entry in your .ini file? (even an empty one). I can confirm that if width/weight are provided explicitly in TableSetupColumns() it can lead to a [Table] entry missing in which case .ini restoring would overwrite back to default, which itself is a bug.

ocornut added a commit to ocornut/imgui_test_engine that referenced this issue Feb 12, 2025
…sible/Hidden state with ImGuiTableColumnFlags_DefaultHide.

ocornut/imgui#7934
ocornut added a commit that referenced this issue Feb 12, 2025
ocornut added a commit to ocornut/imgui_test_engine that referenced this issue Feb 12, 2025
@ocornut
Copy link
Owner

ocornut commented Feb 12, 2025

I have pushed another series of fixes which may I have affected you (and merged it all into docking).

This doesn't cater for the possibility that defaults (e.g. ImGuiTableColumnFlags_DefaultHide) may be altered between the time the .ini were stored, but I imagine this would be less likely a problem. If the first wave of issues are confirmed fixed we can advise on the rest.

@lailoken
Copy link
Author

lailoken commented Feb 18, 2025

I've tried your commits in our codebase, and it looks like the column visibility persistence is working, but the column size of columns that were not modified breaks on restore.

I did a simple save of settings with a column that had a default fixed width, and immediately restored it. What it seems to do is change the column to best fit or something.

If I modify a column width then that still works (as it had before).

My column (at index 3 as an example) is created with the following lines:

    ImGuiTableColumnFlags const colFlag = ImGuiTableColumnFlags_WidthFixed | ImGuiTableColumnFlags_NoHeaderWidth | ImGuiTableColumnFlags_NoSort;
    ImGui::TableSetupColumn("Ask", colFlag, w4 * 6);

And the ini when saved without any changes contains only:

[Table][0x2A80B1C9,12]
RefScale=19.5

If I quit and restart the app, then it works, just if I reload the saved config all my unmodified columns seems to revert to "best fit".

Also, when I resize only column 0 and resave, it changes to:

[Table][0x2A80B1C9,12]
RefScale=19.5
Column 0  Width=154
Column 1  Width=54
Column 2  Width=81
Column 3  Width=54
Column 4  Width=54
Column 5  Width=54
Column 6  Width=27
Column 7  Width=36
Column 8  Width=54
Column 9  Width=36
Column 10 Width=36
Column 11 Width=4096

This (obviously) then works subsequently whatever I do since all the values are explicit.

@ocornut ocornut added the bug label Feb 19, 2025
ocornut added a commit that referenced this issue Feb 19, 2025
…y restored when hot-reloading .ini state. (#7934)

Amend 7cd31c3
column->SortDirection initialized setting was wrong in first block but without side-effect, since sorting always stored explicitly in .ini data.
@ocornut
Copy link
Owner

ocornut commented Feb 19, 2025

Sorry I confirm there was another issue there.
I have pushed a fix 8b7b3ce + a subsequent refactor 05742f9 to reduce almost-same-same-but-different code duplication and the likehood of that sorts of issue.

@lailoken
Copy link
Author

This is working for me now, I've tried to test all the permutations I could think of.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
bug settings .ini persistance tables/columns test wanted Should add corresponding test to ImGuiTestSuite
Projects
None yet
Development

No branches or pull requests

2 participants