-
Notifications
You must be signed in to change notification settings - Fork 88
Tristate toggle #1675
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
Merged
Merged
Tristate toggle #1675
Changes from 13 commits
Commits
Show all changes
19 commits
Select commit
Hold shift + click to select a range
d5cd614
UIHelper extensions
kianzarrin 16cd07b
Interface for propagating value.
kianzarrin d36c4ec
tristate checkbox option
kianzarrin 1996dd9
changed sprites
kianzarrin 1d1b951
bug fix: type safety
kianzarrin 63a7d54
bc3ece0
merge
kianzarrin 706576e
polish sprites
kianzarrin b2399ac
use `bool?`
kianzarrin cadda4c
resize buttons
kianzarrin 43a119a
NotImplementedException
kianzarrin 66f958f
apply value propagator doc
kianzarrin 2c9ab66
Merge branch 'master' into tri-toggle
kianzarrin 23531cc
Merge branch 'master' into tri-toggle
kianzarrin f34bb6c
fixed: Convert.ChangeType can only handle IConvirtable
kianzarrin 3f01445
Merge branch 'tri-toggle' of https://github.com/CitiesSkylinesMods/TM…
kianzarrin c53853a
type safety for Convert.ChangeType()
kianzarrin 11f46e4
fixed disabled color
kianzarrin 51a7288
Merge branch 'master' into tri-toggle
kianzarrin File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
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
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
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
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,11 @@ | ||
| namespace TrafficManager.UI.Helpers { | ||
| /// <summary> | ||
| /// we propagate <c>true</c> when depender* has been enabled. | ||
| /// we propagate <c>false</c> when dependee* has been disabled. | ||
| /// (depender depends on dependee) | ||
| /// </summary> | ||
| public interface IValuePropagator { | ||
| void Propagate(bool value); | ||
| void AddPropagate(IValuePropagator item, bool value); | ||
| } | ||
| } |
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,158 @@ | ||
| namespace TrafficManager.UI.Helpers { | ||
| using ICities; | ||
| using ColossalFramework.UI; | ||
| using TrafficManager.State; | ||
| using CSUtil.Commons; | ||
| using UnityEngine; | ||
| using TrafficManager.Util.Extensions; | ||
| using JetBrains.Annotations; | ||
| using System.Collections.Generic; | ||
| using TrafficManager.Util; | ||
| using System; | ||
|
|
||
| public class TriStateCheckboxOption : | ||
| SerializableUIOptionBase<bool?, UITriStateCheckbox, TriStateCheckboxOption>, IValuePropagator { | ||
| private const int LABEL_MAX_WIDTH = 615; | ||
| private const int LABEL_MAX_WIDTH_INDENTED = 600; | ||
|
|
||
| public TriStateCheckboxOption(string fieldName, Options.PersistTo scope = Options.PersistTo.Savegame) | ||
| : base(fieldName, scope) { } | ||
|
|
||
| private HashSet<IValuePropagator> _propagatesTrueTo = new(); | ||
| private HashSet<IValuePropagator> _propagatesFalseTo = new(); | ||
|
|
||
| public TriStateCheckboxOption PropagateTrueTo([NotNull] IValuePropagator target) { | ||
| Log.Info($"TriStateCheckboxOption.PropagateTrueTo: `{FieldName}` will propagate to `{target}`"); | ||
| this.AddPropagate(target, true); | ||
| target.AddPropagate(this, false); | ||
| return this; | ||
| } | ||
|
|
||
| private HashSet<IValuePropagator> GetTargetPropagates(bool value) => | ||
| value ? _propagatesTrueTo : _propagatesFalseTo; | ||
|
|
||
| public void AddPropagate(IValuePropagator target, bool value) => | ||
| GetTargetPropagates(value).Add(target); | ||
|
|
||
| public void Propagate(bool value) { | ||
| if (!value) { | ||
| // this tristate button depends on another option that has been disabled. | ||
| Value = null; | ||
| } else { | ||
| // Don't know to set to true or false because both are none-null. | ||
| // I don't think it makes sense for other options to depend on tristate checkbox anyway. | ||
| throw new NotImplementedException("other options cannot depend on tristate checkbox"); | ||
| } | ||
| } | ||
|
|
||
| private void PropagateAll(bool value) { | ||
| foreach (var target in GetTargetPropagates(value)) | ||
| target.Propagate(value); | ||
| } | ||
|
|
||
| public override string ToString() => FieldName; | ||
|
|
||
| public override void Load(byte data) => | ||
| Value = TernaryBoolUtil.ToOptBool((TernaryBool)data); | ||
|
|
||
| public override byte Save() => | ||
| (byte)TernaryBoolUtil.ToTernaryBool(Value); | ||
|
|
||
| public override bool? Value { | ||
| get => base.Value; | ||
| set { | ||
| if (value != base.Value) { | ||
| base.Value = value; | ||
| Log.Info($"TriStateCheckboxOption.Value: `{FieldName}` changed to {value}"); | ||
| PropagateAll(value.HasValue); | ||
|
|
||
| if (Shortcuts.IsMainThread()) { | ||
| if (HasUI) { | ||
| _ui.Value = value; | ||
| } | ||
| } else { | ||
| SimulationManager.instance.m_ThreadingWrapper.QueueMainThread(() => { | ||
| if (HasUI) { | ||
| _ui.Value = value; | ||
| } | ||
| }); | ||
| } | ||
| } | ||
| } | ||
| } | ||
|
|
||
| public override TriStateCheckboxOption AddUI(UIHelperBase container) { | ||
| _ui = container.AddUIComponent<UITriStateCheckbox>(); | ||
| _ui.EventValueChanged += (_,val) => InvokeOnValueChanged(val); | ||
| if (Indent) ApplyIndent(_ui); | ||
| UpdateLabel(); | ||
| ApplyTextWrap(_ui, Indent); | ||
|
|
||
| UpdateTooltip(); | ||
| UpdateReadOnly(); | ||
|
|
||
| return this; | ||
| } | ||
|
|
||
| protected override void UpdateLabel() { | ||
| if (!HasUI) return; | ||
|
|
||
| _ui.label.text = Translate(Label); | ||
| } | ||
|
|
||
| protected override void UpdateTooltip() { | ||
| if (!HasUI) return; | ||
|
|
||
| _ui.tooltip = IsInScope | ||
| ? string.IsNullOrEmpty(_tooltip) | ||
| ? string.Empty // avoid invalidating UI if already no tooltip | ||
| : Translate(_tooltip) | ||
| : Translate(INGAME_ONLY_SETTING); | ||
| } | ||
|
|
||
| protected override void UpdateReadOnly() { | ||
| if (!HasUI) return; | ||
|
|
||
| var readOnly = !IsInScope || _readOnly; | ||
|
|
||
| Log._Debug($"TriStateCheckboxOption.UpdateReadOnly() - `{FieldName}` is {(readOnly ? "read-only" : "writeable")}"); | ||
|
|
||
| _ui.readOnly = readOnly; | ||
| _ui.opacity = readOnly ? 0.3f : 1f; | ||
| } | ||
|
|
||
| /* UI helper methods */ | ||
|
|
||
| internal static void ApplyIndent(UIComponent component) { | ||
| UILabel label = component.Find<UILabel>("Label"); | ||
|
|
||
| if (label != null) { | ||
| label.padding = new RectOffset(22, 0, 0, 0); | ||
| } | ||
|
|
||
| UISprite check = component.Find<UISprite>("Unchecked"); | ||
|
|
||
| if (check != null) { | ||
| check.relativePosition += new Vector3(22.0f, 0); | ||
| } | ||
| } | ||
|
|
||
| internal static void ApplyTextWrap(UICheckBox checkBox, bool indented = false) { | ||
| UILabel label = checkBox.label; | ||
| bool requireTextWrap; | ||
| int maxWidth = indented ? LABEL_MAX_WIDTH_INDENTED : LABEL_MAX_WIDTH; | ||
| using (UIFontRenderer renderer = label.ObtainRenderer()) { | ||
| Vector2 size = renderer.MeasureString(label.text); | ||
| requireTextWrap = size.x > maxWidth; | ||
| } | ||
| label.autoSize = false; | ||
| label.wordWrap = true; | ||
| label.verticalAlignment = UIVerticalAlignment.Middle; | ||
| label.textAlignment = UIHorizontalAlignment.Left; | ||
| label.size = new Vector2(maxWidth, requireTextWrap ? 40 : 20); | ||
| if (requireTextWrap) { | ||
| checkBox.height = 42; // set new height + top/bottom 1px padding | ||
| } | ||
| } | ||
| } | ||
| } |
Oops, something went wrong.
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.
Uh oh!
There was an error while loading. Please reload this page.