From 16c7e8fc72ff3876ed508f3c0a304b139f9ee029 Mon Sep 17 00:00:00 2001 From: dmytro lytovchenko Date: Sun, 7 Jul 2019 11:46:59 +0200 Subject: [PATCH] Hovering a lane in incoming select mode, will show allowed turns as circles --- TLM/TLM/TLM.csproj | 2 +- TLM/TLM/Traffic/Data/SpeedLimit.cs | 349 ++++++++------- TLM/TLM/UI/SubTool.cs | 46 +- .../UI/SubTools/LaneArrows/LaneArrowTool.cs | 411 +----------------- .../LaneArrows/LaneArrowTool_Render.cs | 160 +++++-- ...ArrowTool_Click.cs => LaneArrowTool_UI.cs} | 34 +- TLM/TLM/UI/TrafficManagerTool.cs | 74 +++- 7 files changed, 425 insertions(+), 651 deletions(-) rename TLM/TLM/UI/SubTools/LaneArrows/{LaneArrowTool_Click.cs => LaneArrowTool_UI.cs} (82%) diff --git a/TLM/TLM/TLM.csproj b/TLM/TLM/TLM.csproj index eaefe93cd..63cd668a3 100644 --- a/TLM/TLM/TLM.csproj +++ b/TLM/TLM/TLM.csproj @@ -255,7 +255,7 @@ - + diff --git a/TLM/TLM/Traffic/Data/SpeedLimit.cs b/TLM/TLM/Traffic/Data/SpeedLimit.cs index 7f72d4c6a..d3e839d05 100644 --- a/TLM/TLM/Traffic/Data/SpeedLimit.cs +++ b/TLM/TLM/Traffic/Data/SpeedLimit.cs @@ -1,176 +1,175 @@ -using System; -using System.Collections.Generic; -using TrafficManager.State; -using TrafficManager.UI; -using UnityEngine; - -namespace TrafficManager.Traffic.Data { - public enum SpeedUnit { - CurrentlyConfigured, // Currently selected in the options menu - Kmph, - Mph - } - - public enum MphSignStyle { - SquareUS = 0, - RoundUK = 1, - RoundGerman = 2, - } - - /// - /// Defines a speed limit value with default Kmph and display value of Mph - /// for when the option is set to display Mph. The engine still uses kmph. - /// - public struct SpeedLimit { - public const float SPEED_TO_KMPH = 50.0f; // 1.0f equals 50 km/h - private const ushort LOWER_KMPH = 10; - public const ushort UPPER_KMPH = 140; - private const ushort KMPH_STEP = 10; - public const int BREAK_PALETTE_COLUMN_KMPH = 8; // palette shows N in a row, then break and another row - - private const float SPEED_TO_MPH = 32.06f; // 50 km/h converted to mph - private const ushort LOWER_MPH = 5; - public const ushort UPPER_MPH = 90; - private const ushort MPH_STEP = 5; - public const int BREAK_PALETTE_COLUMN_MPH = 10; // palette shows M in a row, then break and another row - - private const float LOWER_SPEED = 0.1f; - private const float UPPER_SPEED = 2 * 10.0f; // 1000 km/h - - /// - /// Produces list of speed limits to offer user in the palette - /// - /// What kind of speed limit list is required - /// List from smallest to largest speed with the given unit. Zero (no limit) is not added to the list. - /// The values are in-game speeds as float. - public static List EnumerateSpeedLimits(SpeedUnit unit) { - var result = new List(); - switch (unit) { - case SpeedUnit.Kmph: - for (var km = LOWER_KMPH; km <= UPPER_KMPH; km += KMPH_STEP) { - result.Add(km / SPEED_TO_KMPH); - } - break; - case SpeedUnit.Mph: - for (var mi = LOWER_MPH; mi <= UPPER_MPH; mi += MPH_STEP) { - result.Add(mi / SPEED_TO_MPH); - } - break; - case SpeedUnit.CurrentlyConfigured: - // Automatically choose from the config - return GlobalConfig.Instance.Main.DisplaySpeedLimitsMph - ? EnumerateSpeedLimits(SpeedUnit.Mph) - : EnumerateSpeedLimits(SpeedUnit.Kmph); - } - - return result; - } - - public static string ToMphPreciseString(float speed) { - if (IsZero(speed)) { - return Translation.GetString("Speed_limit_unlimited"); - } - - return ToMphPrecise(speed) + " MPH"; - } - - public static string ToKmphPreciseString(float speed) { - if (IsZero(speed)) { - return Translation.GetString("Speed_limit_unlimited"); - } - - return ToKmphPrecise(speed) + " km/h"; - } - - public static bool NearlyEqual(float a, float b) { - return Mathf.Abs(a - b) < 0.001f; - } - - public static bool IsZero(float speed) { - return speed < 0.001f; - } - - public static bool IsValidRange(float speed) { - return IsZero(speed) || (speed >= LOWER_SPEED && speed <= UPPER_SPEED); - } - - /// - /// Convert float game speed to mph and round to nearest STEP - /// - /// - /// - public static ushort ToMphRounded(float speed) { - var mph = speed * SPEED_TO_MPH; - return (ushort)(Mathf.Round(mph / MPH_STEP) * MPH_STEP); - } - - public static ushort ToMphPrecise(float speed) { - return (ushort)Mathf.Round(speed * SPEED_TO_MPH); - } - - /// - /// Convert float game speed to km/h and round to nearest STEP - /// - /// - /// - public static ushort ToKmphRounded(float speed) { - var kmph = speed * SPEED_TO_KMPH; - return (ushort)(Mathf.Round(kmph / KMPH_STEP) * KMPH_STEP); - } - - public static ushort ToKmphPrecise(float speed) { - return (ushort)Mathf.Round(speed * SPEED_TO_KMPH); - } - - /// - /// Based on the MPH/KMPH settings round the current speed to the nearest STEP and - /// then decrease by STEP. - /// - /// Ingame speed - /// Ingame speed decreased by the increment for MPH or KMPH - public static float GetPrevious(float speed) { - if (speed < 0f) { - return -1f; - } - if (GlobalConfig.Instance.Main.DisplaySpeedLimitsMph) { - var rounded = ToMphRounded(speed); - return (rounded > LOWER_MPH ? rounded - MPH_STEP : LOWER_MPH) / SPEED_TO_MPH; - } else { - var rounded = ToKmphRounded(speed); - return (rounded > LOWER_KMPH ? rounded - KMPH_STEP : LOWER_KMPH) / SPEED_TO_KMPH; - } - } - - /// - /// Based on the MPH/KMPH settings round the current speed to the nearest STEP and - /// then increase by STEP. - /// - /// Ingame speed - /// Ingame speed increased by the increment for MPH or KMPH - public static float GetNext(float speed) { - if (speed < 0f) { - return -1f; - } - if (GlobalConfig.Instance.Main.DisplaySpeedLimitsMph) { - var rounded = ToMphRounded(speed); - return (rounded < UPPER_MPH ? rounded + MPH_STEP : UPPER_MPH) / SPEED_TO_MPH; - } - else { - var rounded = ToKmphRounded(speed); - return (rounded < UPPER_KMPH ? rounded + KMPH_STEP : UPPER_KMPH) / SPEED_TO_KMPH; - } - } - - /// - /// For US signs and MPH enabled, scale textures vertically by 1.25f. - /// Other signs are round. - /// - /// Multiplier for horizontal sign size - public static float GetVerticalTextureScale() { - return (GlobalConfig.Instance.Main.DisplaySpeedLimitsMph && - GlobalConfig.Instance.Main.MphRoadSignStyle == MphSignStyle.SquareUS) - ? 1.25f - : 1.0f; - } - } +namespace TrafficManager.Traffic.Data { + using System.Collections.Generic; + using State; + using UI; + using UnityEngine; + + public enum SpeedUnit { + CurrentlyConfigured, // Currently selected in the options menu + Kmph, + Mph + } + + public enum MphSignStyle { + SquareUS = 0, + RoundUK = 1, + RoundGerman = 2, + } + + /// + /// Defines a speed limit value with default Kmph and display value of Mph + /// for when the option is set to display Mph. The engine still uses kmph. + /// + public struct SpeedLimit { + public const float SPEED_TO_KMPH = 50.0f; // 1.0f equals 50 km/h + private const ushort LOWER_KMPH = 10; + public const ushort UPPER_KMPH = 140; + private const ushort KMPH_STEP = 10; + public const int BREAK_PALETTE_COLUMN_KMPH = 8; // palette shows N in a row, then break and another row + + private const float SPEED_TO_MPH = 32.06f; // 50 km/h converted to mph + private const ushort LOWER_MPH = 5; + public const ushort UPPER_MPH = 90; + private const ushort MPH_STEP = 5; + public const int BREAK_PALETTE_COLUMN_MPH = 10; // palette shows M in a row, then break and another row + + private const float LOWER_SPEED = 0.1f; + private const float UPPER_SPEED = 2 * 10.0f; // 1000 km/h + + /// + /// Produces list of speed limits to offer user in the palette + /// + /// What kind of speed limit list is required + /// List from smallest to largest speed with the given unit. Zero (no limit) is not added to the list. + /// The values are in-game speeds as float. + public static List EnumerateSpeedLimits(SpeedUnit unit) { + var result = new List(); + switch (unit) { + case SpeedUnit.Kmph: + for (var km = LOWER_KMPH; km <= UPPER_KMPH; km += KMPH_STEP) { + result.Add(km / SPEED_TO_KMPH); + } + break; + case SpeedUnit.Mph: + for (var mi = LOWER_MPH; mi <= UPPER_MPH; mi += MPH_STEP) { + result.Add(mi / SPEED_TO_MPH); + } + break; + case SpeedUnit.CurrentlyConfigured: + // Automatically choose from the config + return GlobalConfig.Instance.Main.DisplaySpeedLimitsMph + ? EnumerateSpeedLimits(SpeedUnit.Mph) + : EnumerateSpeedLimits(SpeedUnit.Kmph); + } + + return result; + } + + public static string ToMphPreciseString(float speed) { + if (IsZero(speed)) { + return Translation.GetString("Speed_limit_unlimited"); + } + + return ToMphPrecise(speed) + " MPH"; + } + + public static string ToKmphPreciseString(float speed) { + if (IsZero(speed)) { + return Translation.GetString("Speed_limit_unlimited"); + } + + return ToKmphPrecise(speed) + " km/h"; + } + + public static bool NearlyEqual(float a, float b) { + return Mathf.Abs(a - b) < 0.001f; + } + + public static bool IsZero(float speed) { + return speed < 0.001f; + } + + public static bool IsValidRange(float speed) { + return IsZero(speed) || (speed >= LOWER_SPEED && speed <= UPPER_SPEED); + } + + /// + /// Convert float game speed to mph and round to nearest STEP + /// + /// + /// + public static ushort ToMphRounded(float speed) { + var mph = speed * SPEED_TO_MPH; + return (ushort)(Mathf.Round(mph / MPH_STEP) * MPH_STEP); + } + + public static ushort ToMphPrecise(float speed) { + return (ushort)Mathf.Round(speed * SPEED_TO_MPH); + } + + /// + /// Convert float game speed to km/h and round to nearest STEP + /// + /// + /// + public static ushort ToKmphRounded(float speed) { + var kmph = speed * SPEED_TO_KMPH; + return (ushort)(Mathf.Round(kmph / KMPH_STEP) * KMPH_STEP); + } + + public static ushort ToKmphPrecise(float speed) { + return (ushort)Mathf.Round(speed * SPEED_TO_KMPH); + } + + /// + /// Based on the MPH/KMPH settings round the current speed to the nearest STEP and + /// then decrease by STEP. + /// + /// Ingame speed + /// Ingame speed decreased by the increment for MPH or KMPH + public static float GetPrevious(float speed) { + if (speed < 0f) { + return -1f; + } + if (GlobalConfig.Instance.Main.DisplaySpeedLimitsMph) { + var rounded = ToMphRounded(speed); + return (rounded > LOWER_MPH ? rounded - MPH_STEP : LOWER_MPH) / SPEED_TO_MPH; + } else { + var rounded = ToKmphRounded(speed); + return (rounded > LOWER_KMPH ? rounded - KMPH_STEP : LOWER_KMPH) / SPEED_TO_KMPH; + } + } + + /// + /// Based on the MPH/KMPH settings round the current speed to the nearest STEP and + /// then increase by STEP. + /// + /// Ingame speed + /// Ingame speed increased by the increment for MPH or KMPH + public static float GetNext(float speed) { + if (speed < 0f) { + return -1f; + } + if (GlobalConfig.Instance.Main.DisplaySpeedLimitsMph) { + var rounded = ToMphRounded(speed); + return (rounded < UPPER_MPH ? rounded + MPH_STEP : UPPER_MPH) / SPEED_TO_MPH; + } + else { + var rounded = ToKmphRounded(speed); + return (rounded < UPPER_KMPH ? rounded + KMPH_STEP : UPPER_KMPH) / SPEED_TO_KMPH; + } + } + + /// + /// For US signs and MPH enabled, scale textures vertically by 1.25f. + /// Other signs are round. + /// + /// Multiplier for horizontal sign size + public static float GetVerticalTextureScale() { + return (GlobalConfig.Instance.Main.DisplaySpeedLimitsMph && + GlobalConfig.Instance.Main.MphRoadSignStyle == MphSignStyle.SquareUS) + ? 1.25f + : 1.0f; + } + } } \ No newline at end of file diff --git a/TLM/TLM/UI/SubTool.cs b/TLM/TLM/UI/SubTool.cs index a9ab6afa0..256e5f970 100644 --- a/TLM/TLM/UI/SubTool.cs +++ b/TLM/TLM/UI/SubTool.cs @@ -4,7 +4,10 @@ using UnityEngine; public abstract class SubTool { - public TrafficManagerTool MainTool { get; } + /// + /// Parent Main Tool, one for all subtools + /// + internal TrafficManagerTool MainTool { get; } protected Texture2D WindowTexture { get { @@ -94,25 +97,25 @@ public abstract class SubTool { private GUIStyle borderlessStyle; - protected ushort HoveredNodeId => TrafficManagerTool.HoveredNodeId; + protected ushort HoveredNodeId => MainTool.HoveredNodeId; - protected ushort HoveredSegmentId => TrafficManagerTool.HoveredSegmentId; + protected ushort HoveredSegmentId => MainTool.HoveredSegmentId; - protected uint HoveredLaneId => TrafficManagerTool.HoveredLaneId; + protected uint HoveredLaneId => MainTool.HoveredLaneId; protected ushort SelectedNodeId { - get => TrafficManagerTool.SelectedNodeId; - set => TrafficManagerTool.SelectedNodeId = value; + get => MainTool.SelectedNodeId; + set => MainTool.SelectedNodeId = value; } protected ushort SelectedSegmentId { - get => TrafficManagerTool.SelectedSegmentId; - set => TrafficManagerTool.SelectedSegmentId = value; + get => MainTool.SelectedSegmentId; + set => MainTool.SelectedSegmentId = value; } protected uint SelectedLaneId { - get => TrafficManagerTool.SelectedLaneId; - set => TrafficManagerTool.SelectedLaneId = value; + get => MainTool.SelectedLaneId; + set => MainTool.SelectedLaneId = value; } public SubTool(TrafficManagerTool mainTool) { @@ -127,12 +130,33 @@ public abstract class SubTool { const float NATIVE_HEIGHT = 1200; /// - /// Called whenever the + /// Called whenever left mouse is clicked on the screen, over the GUI or the world /// public abstract void OnPrimaryClickOverlay(); public virtual void OnSecondaryClickOverlay() { } + /// + /// Hovered node is changed to a different value than before (also 0) + /// + /// The previously hovered node + /// New hovered node + internal virtual void OnChangeHoveredNode(ushort oldNodeId, ushort newNodeId) { } + + /// + /// Hovered segment is changed to a different value than before (also 0) + /// + /// The previously hovered segment + /// New hovered segment + internal virtual void OnChangeHoveredSegment(ushort oldSegmentId, ushort newSegmentId) { } + + /// + /// Hovered lane is changed a different value than before (also 0) + /// + /// The previously hovered lane + /// New hovered lane + internal virtual void OnChangeHoveredLane(uint oldLaneId, uint newLaneId) { } + public virtual void OnToolGUI(Event e) { // set up scaling /*Vector2 resolution = UIView.GetAView().GetScreenResolution(); diff --git a/TLM/TLM/UI/SubTools/LaneArrows/LaneArrowTool.cs b/TLM/TLM/UI/SubTools/LaneArrows/LaneArrowTool.cs index eaa5d880f..ae1b595fd 100644 --- a/TLM/TLM/UI/SubTools/LaneArrows/LaneArrowTool.cs +++ b/TLM/TLM/UI/SubTools/LaneArrows/LaneArrowTool.cs @@ -1,5 +1,4 @@ namespace TrafficManager.UI.SubTools.LaneArrows { - using System; using System.Collections.Generic; using ColossalFramework; using CSUtil.Commons; @@ -45,12 +44,7 @@ private enum Trigger { /// /// Allowed outgoing turns grouped by the direction /// - private OutgoingTurnsCollection outgoingTurns_; - -// /// -// /// Allowed outgoing lanes -// /// -// private HashSet outgoingLanes_; + private OutgoingTurnsCollection? outgoingTurns_; public LaneArrowTool(TrafficManagerTool mainTool) : base(mainTool) { @@ -186,33 +180,6 @@ public LaneArrowTool(TrafficManagerTool mainTool) // No GUI interaction in this mode } - // Cancel selection immediately if there are no vehicle lanes - // var numLanes = TrafficManagerTool.GetSegmentNumVehicleLanes( - // SelectedSegmentId, SelectedNodeId, out _, LaneArrowManager.VEHICLE_TYPES); - // if (numLanes <= 0) { - // Deselect(); - // return; - // } - -// var nodePos = Singleton.instance.m_nodes.m_buffer[SelectedNodeId].m_position; -// var visible = MainTool.WorldToScreenPoint(nodePos, out _); -// if (!visible) { -// return; -// } - -// var camPos = Singleton.instance.m_simulationView.m_position; -// var diff = nodePos - camPos; -// if (diff.magnitude > TrafficManagerTool.MAX_OVERLAY_DISTANCE) { -// return; // do not draw if too distant -// } - -// // Try click something on Canvas -// foreach (var laneEditor in laneEditors_.Values) { -// if (laneEditor.Gui.HandleInput()) { -// break; // handle until first true is returned (consumed) -// } -// } - /// /// Handle events for OutgoingDirections state /// @@ -230,245 +197,6 @@ public LaneArrowTool(TrafficManagerTool mainTool) SelectedLaneId = 0; } -// /// -// /// Create canvas one per incoming segment to the selected node. -// /// Fill each canvas with lane buttons. -// /// The initial GUI state is one lane control button per each incoming lane. -// /// Clicking that lane button will produce 0..3 arrow buttons controlling that lane. -// /// Clicking another lane button will destroy these and create another 0..3 buttons. -// /// Right-clicking, or clicking another node will destroy the GUI. -// /// -// private void CreateEditorsForAllSegments() { -// var nodeBuffer = Singleton.instance.m_nodes.m_buffer; -// var segmentBuffer = Singleton.instance.m_segments.m_buffer; -// var selectedNode = nodeBuffer[SelectedNodeId]; -// var nodeId = SelectedNodeId; -// -// // For all incoming segments -// for (var i = 0; i < MAX_NODE_SEGMENTS; ++i) { -// var incomingSegmentId = selectedNode.GetSegment(i); -// if (incomingSegmentId == 0) { -// continue; -// } -// -// var incomingSegment = segmentBuffer[incomingSegmentId]; -// -// // Create the GUI form and center it according to the node position -// Quaternion rotInverse; -// Vector3 guiOriginWorldPos; -// var editor = new LaneArrowsEditor(); -// editor.CreateWorldSpaceCanvas( -// incomingSegment, nodeId, incomingSegmentId, out guiOriginWorldPos, out rotInverse); -// laneEditors_[incomingSegmentId] = editor; -// -// if (LaneConnectionManager.Instance.HasNodeConnections(nodeId)) { -// // Do not allow editing lanes, because custom connections exist -// // Create a forbidden icon button which does not click -// CreateForbiddenButton_LaneConnections(); -// return; // do not create any more buttons -// } -// -// var laneList = GetIncomingLaneList(incomingSegmentId, nodeId); -// CreateLaneControlButtons(editor, nodeId, incomingSegmentId, laneList, -// rotInverse, guiOriginWorldPos); -// } -// } - -// /// -// /// As now we know that lane arrows cannot be edited, we do not create lane control GUI, -// /// instead create a single button with a warning icon. Clicking this button -// /// will pop up an explanation message. -// /// -// private void CreateForbiddenButton_LaneConnections() { -// var gui = laneEditors_.First().Value.Gui; // exact 1 element in laneEditors -// var button = gui.AddButton( -// new Vector3(0f, 0f, 0f), -// new Vector2(LANE_BUTTON_SIZE, LANE_BUTTON_SIZE), -// string.Empty); -// WorldSpaceGUI.SetButtonSprite(button, LaneArrowsTextures.GetSprite(3, 2)); -// -// UnityAction clickLaneConnections = () => { -// const string MESSAGE = "Lane arrows disabled for this node, because you have custom " + -// "lane connections set up."; -// UIView.library -// .ShowModal("ExceptionPanel") -// .SetMessage("No Lane Arrows for this node", MESSAGE, false); -// }; -// button.GetComponent