Skip to content

Commit

Permalink
Merge pull request #1733 from CitiesSkylinesMods/improvement/customiz…
Browse files Browse the repository at this point in the history
…able-scroll-behavior-closed-dropdown

Custom Dropdown - prevent unwanted option change on mouse wheel scrool
  • Loading branch information
krzychu124 committed Mar 22, 2023
2 parents d22b8d0 + e9653fe commit be0f6e3
Show file tree
Hide file tree
Showing 6 changed files with 139 additions and 5 deletions.
5 changes: 3 additions & 2 deletions TLM/TLM/State/OptionsTabs/GeneralTab_LocalisationGroup.cs
Original file line number Diff line number Diff line change
Expand Up @@ -10,6 +10,7 @@ namespace TrafficManager.State {
using TrafficManager.UI;
using TrafficManager.UI.Helpers;
using TrafficManager.UI.Textures;
using TrafficManager.Util.Extensions;

/// <summary>
/// Adds localisation options to General options tab.
Expand Down Expand Up @@ -64,7 +65,7 @@ public static class GeneralTab_LocalisationGroup {
}
}

group.AddDropdown(
group.AddCustomDropDown(
text: T("General.Dropdown:Select language") + ":",
options: languageLabels,
defaultSelection: languageIndex,
Expand All @@ -84,7 +85,7 @@ public static class GeneralTab_LocalisationGroup {
int selectedThemeIndex = themeNames.FindIndex(x => x == mainConfig.RoadSignTheme);
int defaultSignsThemeIndex = RoadSignThemeManager.Instance.FindDefaultThemeIndex(mainConfig.DisplaySpeedLimitsMph);

_roadSignsThemeDropdown = group.AddDropdown(
_roadSignsThemeDropdown = group.AddCustomDropDown(
text: TSpeedLimits("General.Dropdown:Road signs theme") + ":",
options: themeOptions,
defaultSelection: selectedThemeIndex >= 0 ? selectedThemeIndex : defaultSignsThemeIndex,
Expand Down
1 change: 1 addition & 0 deletions TLM/TLM/TLM.csproj
Original file line number Diff line number Diff line change
Expand Up @@ -184,6 +184,7 @@
<Compile Include="TrafficLight\Impl\ITrafficLightContainer.cs" />
<Compile Include="TrafficLight\Impl\TrafficLightSimulation.cs" />
<Compile Include="UI\AllowDespawn\AllowDespawnPanel.cs" />
<Compile Include="UI\Helpers\CustomDownDown.cs" />
<Compile Include="UI\Helpers\DebugOverlay.cs" />
<Compile Include="UI\DebugSwitches\DebugSwitchPanel.cs" />
<Compile Include="UI\DebugSwitches\DebugSwitchCheckboxOption.cs" />
Expand Down
36 changes: 36 additions & 0 deletions TLM/TLM/UI/Helpers/CustomDownDown.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,36 @@
namespace TrafficManager.UI.Helpers;

using ColossalFramework.UI;
using UnityEngine;

/// <summary>
/// Custom version of vanilla dropdown with customizable mouse wheel behavior on hover closed dropdown control
/// </summary>
public class CustomDownDown : UIDropDown {
public static GameObject ScrollTemplate;

/// <summary>
/// Use mouse wheel when dropdown is closed to change selection
/// Unlike in vanilla, default is False
/// </summary>
public bool MouseWheelSelectItem { get; set; } = false;

public override void OnDestroy() {
if (ScrollTemplate) {
Destroy(ScrollTemplate);
ScrollTemplate = null;
}

base.OnDestroy();
}

protected override void OnMouseWheel(UIMouseEventParameter p) {
if (MouseWheelSelectItem) {
// do default action
base.OnMouseWheel(p);
} else {
// mark as used to prevent scrolling page or selecting different items in the dropdown!
p.Use();
}
}
}
4 changes: 2 additions & 2 deletions TLM/TLM/UI/Helpers/DropDownOption.cs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
namespace TrafficManager.UI.Helpers {
using ICities;
using ColossalFramework.UI;
using TrafficManager.State;
using CSUtil.Commons;
using System;
using System.Linq;
using TrafficManager.API.Traffic.Enums;
using TrafficManager.Util;
using TrafficManager.Util.Extensions;

public class DropDownOption<TEnum> : SerializableUIOptionBase<TEnum, UIDropDown, DropDownOption<TEnum>>
where TEnum : struct, Enum, IConvertible {
Expand Down Expand Up @@ -71,7 +71,7 @@ public DropDownOption(string fieldName, Scope scope = Scope.Savegame)
}

public override DropDownOption<TEnum> AddUI(UIHelperBase container) {
_ui = container.AddDropdown(
_ui = container.AddCustomDropDown(
text: Translate(Label) + ":",
options: GetTranslatedItems(),
defaultSelection: IndexOf(Value),
Expand Down
96 changes: 96 additions & 0 deletions TLM/TLM/Util/Extensions/UIHelperExtensions.cs
Original file line number Diff line number Diff line change
@@ -1,6 +1,8 @@
namespace TrafficManager.Util.Extensions {
using ColossalFramework.UI;
using ICities;
using TrafficManager.Lifecycle;
using TrafficManager.UI.Helpers;
using UnityEngine;

internal static class UIHelperExtensions {
Expand All @@ -11,5 +13,99 @@ public static T AddComponent<T>(this UIHelperBase container)

public static T AddUIComponent<T>(this UIHelperBase container)
where T : UIComponent => container.GetSelf().AddUIComponent<T>();

public static CustomDownDown AddCustomDropDown(this UIHelperBase container,
string text,
string[] options,
int defaultSelection,
OnDropdownSelectionChanged eventCallback
) {
if (eventCallback != null && !string.IsNullOrEmpty(text)) {
UIComponent root = container.GetSelf();
UIPanel uipanel = root.AddUIComponent<UIPanel>();
uipanel.area = new Vector4(14, 0, 232, 72);
uipanel.autoLayoutDirection = LayoutDirection.Vertical;
uipanel.autoLayoutPadding = new RectOffset(1, 0, 2, 0);
uipanel.autoLayout = true;

var label = uipanel.AddUIComponent<UILabel>();
label.text = text;
label.name = "Label";

var dropdown = uipanel.AddUIComponent<CustomDownDown>();
dropdown.name = "Dropdown";
dropdown.area = new Vector4(0, 24, 225, 38);
dropdown.items = options;
dropdown.selectedIndex = defaultSelection;
dropdown.triggerButton = dropdown;
dropdown.relativePosition = new Vector3(0, 24, 0);
dropdown.itemPadding = new RectOffset(14, 14, 0, 0);
dropdown.listPadding = new RectOffset(4, 4, 4, 4);
dropdown.textFieldPadding = new RectOffset(14, 40, 7, 4);
dropdown.itemHeight = 24;
dropdown.listHeight = 200;
dropdown.textScale = 1.25f;
dropdown.itemHover = "ListItemHover";
dropdown.itemHighlight = "ListItemHighlight";
dropdown.focusedFgSprite = "OptionsDropboxFocused";
dropdown.focusedBgSprite = "OptionsDropboxHovered";
dropdown.hoveredBgSprite = "OptionsDropboxHovered";
dropdown.normalBgSprite = "OptionsDropbox";
dropdown.listBackground = "OptionsDropboxListbox";
dropdown.popupColor = Color.white;
dropdown.popupTextColor = new Color32(170, 170, 170, 255);
dropdown.eventSelectedIndexChanged += delegate(UIComponent c, int sel) {
eventCallback(sel);
};

if (CustomDownDown.ScrollTemplate) {
// reuse gameObject template
dropdown.listScrollbar = CustomDownDown.ScrollTemplate.GetComponent<UIScrollbar>();
} else {
UIScrollbar scrollbar = CreateScrollbar();
// cache gameObject for later reuse
CustomDownDown.ScrollTemplate = scrollbar.gameObject;
dropdown.listScrollbar = scrollbar;
}

return dropdown;
}
return null;
}

private static UIScrollbar CreateScrollbar() {
UIScrollbar verticalScrollbar = new GameObject("TMPE_ScrollbarV").AddComponent<UIScrollbar>();
// attach to lifecycle gameObject for easier search in gameObject tree
verticalScrollbar.gameObject.transform.SetParent(TMPELifecycle.Instance.gameObject.transform);

verticalScrollbar.name = "TMPE_ScrollbarV";
verticalScrollbar.width = 25;
verticalScrollbar.height = 200;
verticalScrollbar.orientation = UIOrientation.Vertical;
verticalScrollbar.pivot = UIPivotPoint.TopLeft;
verticalScrollbar.minValue = 0;
verticalScrollbar.maxValue = 87;
verticalScrollbar.value = 0;
verticalScrollbar.incrementAmount = 50;
verticalScrollbar.autoHide = true;

UISlicedSprite trackSprite = verticalScrollbar.AddUIComponent<UISlicedSprite>();
trackSprite.relativePosition = Vector2.zero;
trackSprite.autoSize = true;
trackSprite.size = trackSprite.parent.size;
trackSprite.fillDirection = UIFillDirection.Vertical;
trackSprite.spriteName = "ScrollbarTrack";
verticalScrollbar.trackObject = trackSprite;

UISlicedSprite thumbSprite = trackSprite.AddUIComponent<UISlicedSprite>();
thumbSprite.relativePosition = Vector2.zero;
thumbSprite.fillDirection = UIFillDirection.Vertical;
thumbSprite.autoSize = true;
thumbSprite.width = thumbSprite.parent.width - 6;
thumbSprite.spriteName = "ScrollbarThumb";
verticalScrollbar.thumbObject = thumbSprite;

return verticalScrollbar;
}
}
}
2 changes: 1 addition & 1 deletion TLM/TLM/Util/Shortcuts.cs
Original file line number Diff line number Diff line change
Expand Up @@ -146,7 +146,7 @@ internal static class Shortcuts {
/// <exception cref="ArgumentException">
/// Thrown if <typeparamref name="T"/> is not some kind of <see cref="Enum"/>.
/// </exception>
internal static void AssertNotNone<T>(T value, string m = "") where T: IEquatable<T> {
internal static void AssertNotNone<T>(T value, string m = "") where T: Enum {
if (!typeof(T).IsEnum)
throw new ArgumentException($"Type '{typeof(T).FullName}' is not an enum");

Expand Down

0 comments on commit be0f6e3

Please sign in to comment.