Settings - UI Layout Redesign - #1828
Open
LinkIsGrim wants to merge 17 commits into
Open
Conversation
The settings menu rescanned and sorted every setting in the game every time a category was opened, and kept its own category map for the search bar that was shaped exactly like the one the menu needed. Build both from one pass and cache them: - GVAR(categorySettings) maps a lower case category to its display name and its settings, already in the order the menu shows them. - GVAR(subCategories) marks the index each sub-category header goes at. - GVAR(searchCategories) is gone, GVAR(categorySettings) replaces it. Renames fnc_gui_searchIndex.sqf to fnc_gui_index.sqf, it no longer only serves the search bar. Nothing consumes the new indices for drawing yet, so the menu is unchanged.
Opening a category walked and sorted every setting in the game to find the ones belonging to it. Read them from GVAR(categorySettings) instead, and take the sub-category header positions from GVAR(subCategories), so the work is proportional to the category rather than to the whole modset. Turns gui_createCategory.inc.sqf into a real function while it is being rewritten anyway. It only needed the display and the category from its caller's scope, and as an include its errors were reported against gui_addonChanged. Also adds the missing default branch to the "can this be edited" switch, which left _enabled undefined for an unexpected source.
Positioning a row read its x/y/w/h from config, and greying one out enumerated its child control classes to find their IDCs. Both are the same for every row of a given class, and a category creates hundreds of them, so opening one did thousands of config reads to look up a handful of distinct answers. Cache them per class in uiNamespace, where they outlive the mission because config can't change at runtime.
Settings were positioned as they were created and then positioned again by the search filter, with the two passes duplicating the layout rules between them. Create them without a position and lay the table out once afterwards, in FUNC(gui_reflow), which is now the only thing that positions a setting. Every list setting also carried its own invisible padding control, sized to its open dropdown and parked on top of the settings below it, purely to keep the scroll area tall enough. One pad per category does the same job: the reflow stretches it to reach past the lowest dropdown of the settings that are shown.
Every control of a row carried its own copy of the setting name and the source it was showing, so changing either meant rewriting up to nine of them. Keep both on the row itself and read them back through ROW_SETTING and ROW_SOURCE where they are needed, leaving the per-control variables to hold only what is specific to that control. The row level QGVAR(params) is now QGVAR(settingData), it held something else entirely and the name collided. Colour settings kept a copy of the value alongside the sliders and mutated it in place, which aliased the stored value. Read it back off the sliders instead. Fixes two bugs on the way: - A password was replaced with asterisks only when its row was created, so importing settings put the real one on screen. It is replaced whenever the value is displayed now. This is only ever done when the box is disabled, so the mask can't be written back over the value. - Tabbing out of a colour channel updated the sliders but never stored the value or refreshed the rest of the row.
Whether a setting can be edited from the source being shown was worked out once while the row was built and applied by switching every one of its controls off. Nothing recorded the answer, so anything that later switched a control back on - the "reset to default" button, the overwrite checkboxes - could hand the player a control they aren't allowed to use. Work it out in FUNC(gui_setRowEnabled), keep it on the row, and have those places ask before they enable anything. The overwrite checkboxes are hidden by moving them off screen, which threw away where they belong. Remember that when the row is built so they can be put back.
An edited setting is stored as a value and a priority together, but only one of them is edited at a time and writing either one stored a nil in place of the other. Everything that works out which source wins then read that nil instead of falling back to the setting's real value or priority: - Editing a value in the server tab stored no priority, so the server was treated as having none and the clients appeared to overwrite it. The lock column turned into a red "overwritten by clients" as soon as anything was edited, and only corrected itself if a priority was written afterwards. - Ticking an overwrite checkbox stored no value, so the check for whether the overwriting source holds the same value compared against nothing. The lock column kept the icon it had and never picked up the "overwritten" colour or tooltip. Fill in whichever half isn't being written with what is in effect right now, which is what FUNC(gui_saveTempData) already did when the settings were saved. Also restores "overwrite clients" to ticked when "overwrite mission" is unticked on a setting that was saved overwriting the mission. Nothing recorded what it had been, and overwriting the mission includes overwriting the clients, so it drops back to that rather than to nothing.
Every setting was built three times over, once for each of the server, mission and client tabs, and switching tab swapped which of the three sets of controls was shown. Two thirds of what a category created was never looked at. Build one row per setting and point it at the source being shown. Nothing about a row depended on the source any more except which overwrite checkboxes it has and whether it can be edited at all, and neither of those is expensive to redo, so switching tab is now FUNC(gui_refresh) putting the values back rather than hundreds of controls being hidden and shown. Which settings are shown doesn't depend on the source either, so a search no longer has to be re-applied and the table no longer has to be laid out again every time the tab changes. The controls groups were kept in a display variable per category and source with the two joined into its name. There is one per category now, so they are kept in a hashmap and the "was this category built" flag is gone with them.
The table gave up a lot of room to things that didn't need it and had no way to get past a long category other than scrolling. Folding: - Clicking a sub-category header folds its settings away and back, and the fold holds for as long as the menu is open. Searching opens a folded group if the search found something in it, so a match is never hidden behind one. - Settings registered without a sub-category come first and had no header, which made them the one block that couldn't be folded. They get a "General" one, but only in categories that have other groups to fold them against. Room: - Rows and sub-category headers are shorter, the strip above the table is smaller, and the buttons below it move down into space that was empty. 13 settings fit where 10 did. - The two overwrite checkboxes sat far apart to keep their labels from touching. The labels are "Clients" and "Mission" under a shared "Overwrites:" now, so the columns can close up and give the width to the setting name instead. Reading: - Setting names are aligned left. Right aligned, a short name sat far from the control it belongs to and the left edge never lined up. - Whether a setting applies reads down the left edge of the table instead of from the middle of a cluster of four icons. - Rows are banded, so a name can be followed across to its control. Every row class has to name its own background control for this: an inherited one that is never redeclared doesn't get created, and setting a colour on the nothing it returns does nothing. - Overwritten by a source that holds the same value has its own icon rather than the same one in a different colour, which is not a difference everyone can see. The value is in effect either way, which is what the new one says.
Contributor
Author
Contributor
|
For me nothing is clickable, drop down menus don't expand and I can't click checkboxes 2026-07-30.21-36-38.mp4 |
Contributor
Author
|
background's ctrlEnabled |
Contributor
Author
PabstMirror
reviewed
Jul 31, 2026
PabstMirror
approved these changes
Jul 31, 2026
Co-authored-by: PabstMirror <pabstmirror@gmail.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


The table gave up a lot of room to things that didn't need it and had no way to get past a long category other than scrolling.
Folding:
Room:
Reading:
Requires #1825, #1827
Fixes: