Skip to content

Settings - UI Layout Redesign - #1828

Open
LinkIsGrim wants to merge 17 commits into
CBATeam:masterfrom
LinkIsGrim:settings-layout
Open

Settings - UI Layout Redesign#1828
LinkIsGrim wants to merge 17 commits into
CBATeam:masterfrom
LinkIsGrim:settings-layout

Conversation

@LinkIsGrim

@LinkIsGrim LinkIsGrim commented Jul 29, 2026

Copy link
Copy Markdown
Contributor

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.
image

Requires #1825, #1827

Fixes:

  • Settings would show as yellow (edited) if they were touched at all even if the end value would be the same.
  • ctrlShow the overwrite checkboxes instead of moving them off-screen

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.
@LinkIsGrim

Copy link
Copy Markdown
Contributor Author

This is what the color banding actually looks like now. I don't want to boot the game to grab an ACE Medical screenshot again.

image

@PabstMirror

Copy link
Copy Markdown
Contributor

For me nothing is clickable, drop down menus don't expand and I can't click checkboxes
The setting itself turns grey
and I can manually hit tab to get to and hit space to check or type so the ctrls aren't locked

2026-07-30.21-36-38.mp4

@LinkIsGrim

Copy link
Copy Markdown
Contributor Author

background's ctrlEnabled

@LinkIsGrim

Copy link
Copy Markdown
Contributor Author

Added confirmation pop-up on cancelling/hitting escape with live changes:

image

Comment thread addons/settings/fnc_gui_confirmDiscard.sqf Outdated
Co-authored-by: PabstMirror <pabstmirror@gmail.com>
@PabstMirror PabstMirror added this to the 3.18.7 milestone Aug 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants