From ba4cff35cc06ce41b0df11f43277531efb9014f3 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Mon, 19 Aug 2024 18:14:38 +0100 Subject: [PATCH 01/41] Fix: Copy+paste typo in makefile [skip ci] --- makefile | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/makefile b/makefile index be08e3549..f205ccbcb 100644 --- a/makefile +++ b/makefile @@ -208,6 +208,6 @@ ifeq (, $(PROGRAM_VERSION)) @mv installers/debian.deb OpenBVE-$$(date '+%F').deb else @echo This is a $(COLOR_YELLOW)Tagged Release build$(COLOR_END) - @echo Final filename: $(COLOR_RED)OpenBVE-$$(date '+%F').deb$(COLOR_END) + @echo Final filename: $(COLOR_RED)OpenBVE-$(PROGRAM_VERSION).deb(COLOR_END) @mv installers/debian.deb OpenBVE-$(PROGRAM_VERSION).deb endif \ No newline at end of file From baa10dd79916b6b44503e942f2f4d28a2dfe72ab Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Mon, 19 Aug 2024 19:16:29 +0100 Subject: [PATCH 02/41] Fix: Incorrect cant interpolation --- source/Plugins/Route.Bve5/MapParser/ConvertComponents.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Plugins/Route.Bve5/MapParser/ConvertComponents.cs b/source/Plugins/Route.Bve5/MapParser/ConvertComponents.cs index de3b352ab..11e1c8eaa 100644 --- a/source/Plugins/Route.Bve5/MapParser/ConvertComponents.cs +++ b/source/Plugins/Route.Bve5/MapParser/ConvertComponents.cs @@ -815,7 +815,7 @@ private static void ConvertTrack(MapData ParseData, RouteData RouteData) } } - i = RouteData.sortedBlocks.IndexOfKey(i); + i = RouteData.sortedBlocks.IndexOfKey(dist); } } } From 30656bcc92c5d36035fac310af1bb8b6487397af Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Wed, 21 Aug 2024 10:24:54 +0100 Subject: [PATCH 03/41] Change: Move some menu components to LibRender2 https://github.com/leezer3/OpenBVE/issues/1023#issuecomment-2301326069 Closes https://github.com/leezer3/OpenBVE/pull/921 --- source/LibRender2/BaseRenderer.cs | 7 ++ source/LibRender2/LibRender2.csproj | 7 ++ source/LibRender2/Menu/Menu.OptionType.cs | 19 ++++++ source/LibRender2/Menu/Menu.RouteState.cs | 14 ++++ .../Menu/MenuEntries/MenuEntry.Caption.cs | 11 ++++ .../Menu/MenuEntries/MenuEntry.Command.cs | 29 ++++++++ .../LibRender2/Menu/MenuEntries/MenuEntry.cs | 66 +++++++++++++++++++ .../Game => LibRender2}/Menu/MenuTag.cs | 2 +- .../Game => LibRender2}/Menu/MenuType.cs | 4 +- source/OpenBVE/Game/Menu/Menu.MenuCaption.cs | 14 ---- source/OpenBVE/Game/Menu/Menu.MenuCommand.cs | 32 --------- source/OpenBVE/Game/Menu/Menu.MenuEntry.cs | 66 ------------------- source/OpenBVE/Game/Menu/Menu.MenuOption.cs | 41 ++++++------ source/OpenBVE/Game/Menu/Menu.OptionType.cs | 13 ---- source/OpenBVE/Game/Menu/Menu.Route.cs | 1 + source/OpenBVE/Game/Menu/Menu.RouteState.cs | 19 ------ source/OpenBVE/Game/Menu/Menu.SingleMenu.cs | 13 ++-- source/OpenBVE/Game/Menu/Menu.cs | 1 + source/OpenBVE/Graphics/NewRenderer.cs | 12 ++++ source/OpenBVE/Graphics/Screen.cs | 8 +-- source/OpenBVE/OpenBve.csproj | 7 -- source/OpenBVE/System/GameWindow.cs | 1 + source/OpenBVE/System/Input/Keyboard.cs | 1 + .../System/Input/ProcessControls.Digital.cs | 1 + .../OpenBVE/System/Input/ProcessControls.cs | 1 + 25 files changed, 204 insertions(+), 186 deletions(-) create mode 100644 source/LibRender2/Menu/Menu.OptionType.cs create mode 100644 source/LibRender2/Menu/Menu.RouteState.cs create mode 100644 source/LibRender2/Menu/MenuEntries/MenuEntry.Caption.cs create mode 100644 source/LibRender2/Menu/MenuEntries/MenuEntry.Command.cs create mode 100644 source/LibRender2/Menu/MenuEntries/MenuEntry.cs rename source/{OpenBVE/Game => LibRender2}/Menu/MenuTag.cs (98%) rename source/{OpenBVE/Game => LibRender2}/Menu/MenuType.cs (98%) delete mode 100644 source/OpenBVE/Game/Menu/Menu.MenuCaption.cs delete mode 100644 source/OpenBVE/Game/Menu/Menu.MenuCommand.cs delete mode 100644 source/OpenBVE/Game/Menu/Menu.MenuEntry.cs delete mode 100644 source/OpenBVE/Game/Menu/Menu.OptionType.cs delete mode 100644 source/OpenBVE/Game/Menu/Menu.RouteState.cs diff --git a/source/LibRender2/BaseRenderer.cs b/source/LibRender2/BaseRenderer.cs index b91ff65fb..7481908b5 100644 --- a/source/LibRender2/BaseRenderer.cs +++ b/source/LibRender2/BaseRenderer.cs @@ -1695,5 +1695,12 @@ public virtual void SetCursor(OpenTK.MouseCursor newCursor) { } + + /// Sets the window state + /// The new window state + public virtual void SetWindowState(OpenTK.WindowState windowState) + { + + } } } diff --git a/source/LibRender2/LibRender2.csproj b/source/LibRender2/LibRender2.csproj index 2cb556c2d..2a374444e 100644 --- a/source/LibRender2/LibRender2.csproj +++ b/source/LibRender2/LibRender2.csproj @@ -57,6 +57,13 @@ + + + + + + + diff --git a/source/LibRender2/Menu/Menu.OptionType.cs b/source/LibRender2/Menu/Menu.OptionType.cs new file mode 100644 index 000000000..8bf38aaad --- /dev/null +++ b/source/LibRender2/Menu/Menu.OptionType.cs @@ -0,0 +1,19 @@ +namespace LibRender2.Menu +{ + /// The type of menu option + public enum OptionType + { + /// Sets the screen resolution + ScreenResolution, + /// Sets the viewing distance + ViewingDistance, + /// Toggles full-screen mode + FullScreen, + /// Sets the interpolation level + Interpolation, + /// Sets the anisotropic filtering level + AnisotropicLevel, + /// Sets the antialiasing level + AntialiasingLevel + } +} diff --git a/source/LibRender2/Menu/Menu.RouteState.cs b/source/LibRender2/Menu/Menu.RouteState.cs new file mode 100644 index 000000000..090e7d521 --- /dev/null +++ b/source/LibRender2/Menu/Menu.RouteState.cs @@ -0,0 +1,14 @@ +namespace LibRender2.Menu +{ + public enum RouteState + { + /// No routefile is currently selected + NoneSelected, + /// The background thread is currently loading the routefile data + Loading, + /// The background thread has processed the route data + Processed, + /// An error was encountered loading the route data + Error + } +} diff --git a/source/LibRender2/Menu/MenuEntries/MenuEntry.Caption.cs b/source/LibRender2/Menu/MenuEntries/MenuEntry.Caption.cs new file mode 100644 index 000000000..46b7a6ef1 --- /dev/null +++ b/source/LibRender2/Menu/MenuEntries/MenuEntry.Caption.cs @@ -0,0 +1,11 @@ +namespace LibRender2.Menu +{ + /// A caption to be rendered at the top of the menu + public class MenuCaption : MenuEntry + { + public MenuCaption(string Text) + { + this.Text = Text; + } + } +} diff --git a/source/LibRender2/Menu/MenuEntries/MenuEntry.Command.cs b/source/LibRender2/Menu/MenuEntries/MenuEntry.Command.cs new file mode 100644 index 000000000..294f436fc --- /dev/null +++ b/source/LibRender2/Menu/MenuEntries/MenuEntry.Command.cs @@ -0,0 +1,29 @@ +using OpenBveApi.Textures; + +namespace LibRender2.Menu +{ + /// A menu entry which performs a command when selected + public class MenuCommand : MenuEntry + { + /// The command tag describing the function of the menu entry + public readonly MenuTag Tag; + /// The optional data to be passed with the command + public readonly object Data; + + public MenuCommand(string Text, MenuTag Tag, object Data) + { + this.Text = Text; + this.Tag = Tag; + this.Data = Data; + this.Icon = null; + } + + public MenuCommand(string Text, MenuTag Tag, object Data, Texture Icon) + { + this.Text = Text; + this.Tag = Tag; + this.Data = Data; + this.Icon = Icon; + } + } +} diff --git a/source/LibRender2/Menu/MenuEntries/MenuEntry.cs b/source/LibRender2/Menu/MenuEntries/MenuEntry.cs new file mode 100644 index 000000000..24822829a --- /dev/null +++ b/source/LibRender2/Menu/MenuEntries/MenuEntry.cs @@ -0,0 +1,66 @@ +using OpenBveApi.Textures; + +namespace LibRender2.Menu +{ + /// The base abstract Menu Entry class + public abstract class MenuEntry + { + /// The base text of the menu entry + public string Text; + /// The display text of the menu entry + public string DisplayText(double TimeElapsed) + { + if (DisplayLength == 0) + { + return Text; + } + timer += TimeElapsed; + if (timer > 0.5) + { + if (pause) + { + pause = false; + return _displayText; + } + timer = 0; + scroll++; + if (scroll == Text.Length) + { + scroll = 0; + pause = true; + } + _displayText = Text.Substring(scroll); + if (_displayText.Length > _displayLength) + { + _displayText = _displayText.Substring(0, _displayLength); + } + } + return _displayText; + } + /// Backing property for display text + private string _displayText; + /// Backing property for display length + private int _displayLength; + /// The length to display + public int DisplayLength + { + get + { + return _displayLength; + } + set + { + _displayLength = value; + _displayText = Text.Substring(0, value); + timer = 0; + } + } + /// The icon to draw for this menu entry + public Texture Icon; + //Properties used for controlling the scrolling text if overlong + private double timer; + private int scroll; + private bool pause; + + } +} diff --git a/source/OpenBVE/Game/Menu/MenuTag.cs b/source/LibRender2/Menu/MenuTag.cs similarity index 98% rename from source/OpenBVE/Game/Menu/MenuTag.cs rename to source/LibRender2/Menu/MenuTag.cs index ab2f4b8ea..8516b8b49 100644 --- a/source/OpenBVE/Game/Menu/MenuTag.cs +++ b/source/LibRender2/Menu/MenuTag.cs @@ -1,5 +1,5 @@ // ReSharper disable UnusedMember.Global -namespace OpenBve +namespace LibRender2.Menu { /// The list of possible tags for a menu entry- These define the functionality of a given menu entry public enum MenuTag diff --git a/source/OpenBVE/Game/Menu/MenuType.cs b/source/LibRender2/Menu/MenuType.cs similarity index 98% rename from source/OpenBVE/Game/Menu/MenuType.cs rename to source/LibRender2/Menu/MenuType.cs index 1a2c3f952..452b54c98 100644 --- a/source/OpenBVE/Game/Menu/MenuType.cs +++ b/source/LibRender2/Menu/MenuType.cs @@ -1,4 +1,4 @@ -namespace OpenBve +namespace LibRender2.Menu { /// The list of possible sub-menu types public enum MenuType @@ -43,6 +43,6 @@ public enum MenuType Options, /// A menu allowing switch settings to be changed ChangeSwitch - + } } diff --git a/source/OpenBVE/Game/Menu/Menu.MenuCaption.cs b/source/OpenBVE/Game/Menu/Menu.MenuCaption.cs deleted file mode 100644 index ed513eec6..000000000 --- a/source/OpenBVE/Game/Menu/Menu.MenuCaption.cs +++ /dev/null @@ -1,14 +0,0 @@ -namespace OpenBve -{ - public sealed partial class Menu - { - /// A caption to be rendered at the top of the menu - private class MenuCaption : MenuEntry - { - internal MenuCaption(string Text) - { - this.Text = Text; - } - } - } -} diff --git a/source/OpenBVE/Game/Menu/Menu.MenuCommand.cs b/source/OpenBVE/Game/Menu/Menu.MenuCommand.cs deleted file mode 100644 index 9df485088..000000000 --- a/source/OpenBVE/Game/Menu/Menu.MenuCommand.cs +++ /dev/null @@ -1,32 +0,0 @@ -using OpenBveApi.Textures; - -namespace OpenBve -{ - public sealed partial class Menu - { - /// A menu entry which performs a command when selected - private class MenuCommand : MenuEntry - { - /// The command tag describing the function of the menu entry - internal readonly MenuTag Tag; - /// The optional data to be passed with the command - internal readonly object Data; - - internal MenuCommand(string Text, MenuTag Tag, object Data) - { - this.Text = Text; - this.Tag = Tag; - this.Data = Data; - this.Icon = null; - } - - internal MenuCommand(string Text, MenuTag Tag, object Data, Texture Icon) - { - this.Text = Text; - this.Tag = Tag; - this.Data = Data; - this.Icon = Icon; - } - } - } -} diff --git a/source/OpenBVE/Game/Menu/Menu.MenuEntry.cs b/source/OpenBVE/Game/Menu/Menu.MenuEntry.cs deleted file mode 100644 index ed7701dd5..000000000 --- a/source/OpenBVE/Game/Menu/Menu.MenuEntry.cs +++ /dev/null @@ -1,66 +0,0 @@ -using OpenBveApi.Textures; - -namespace OpenBve -{ - public sealed partial class Menu - { - /// The base abstract Menu Entry class - private abstract class MenuEntry - { - /// The base text of the menu entry - internal string Text; - /// The display text of the menu entry - internal string DisplayText(double TimeElapsed) - { - if (DisplayLength == 0) - { - return Text; - } - timer += TimeElapsed; - if (timer > 0.5) - { - if (pause) - { - pause = false; - return _displayText; - } - timer = 0; - scroll++; - if (scroll == Text.Length) - { - scroll = 0; - pause = true; - } - _displayText = Text.Substring(scroll); - if (_displayText.Length > _displayLength) - { - _displayText = _displayText.Substring(0, _displayLength); - } - } - return _displayText; - } - /// Backing property for display text - private string _displayText; - /// Backing property for display length - private int _displayLength; - /// The length to display - internal int DisplayLength - { - get => _displayLength; - set - { - _displayLength = value; - _displayText = Text.Substring(0, value); - timer = 0; - } - } - /// The icon to draw for this menu entry - internal Texture Icon; - //Properties used for controlling the scrolling text if overlong - private double timer; - private int scroll; - private bool pause; - - } - } -} diff --git a/source/OpenBVE/Game/Menu/Menu.MenuOption.cs b/source/OpenBVE/Game/Menu/Menu.MenuOption.cs index 6780d8cb7..6ffd93041 100644 --- a/source/OpenBVE/Game/Menu/Menu.MenuOption.cs +++ b/source/OpenBVE/Game/Menu/Menu.MenuOption.cs @@ -1,6 +1,7 @@ using System.Collections.Generic; using System.Globalization; using System.IO; +using LibRender2.Menu; using LibRender2.Screens; using OpenBveApi.Graphics; using OpenTK; @@ -11,7 +12,7 @@ public sealed partial class Menu { private class MenuOption : MenuEntry { - private readonly MenuOptionType Type; + private readonly OptionType Type; /// Holds the entries for all options private readonly object[] Entries; @@ -21,14 +22,14 @@ private class MenuOption : MenuEntry private int CurrentlySelectedOption; - internal MenuOption(MenuOptionType type, string text, object[] entries) + internal MenuOption(OptionType type, string text, object[] entries) { Type = type; Text = text; Entries = entries; switch (type) { - case MenuOptionType.ScreenResolution: + case OptionType.ScreenResolution: if (entries is ScreenResolution[] castEntries) { for (int i = 0; i < castEntries.Length; i++) @@ -46,13 +47,13 @@ internal MenuOption(MenuOptionType type, string text, object[] entries) } break; - case MenuOptionType.FullScreen: + case OptionType.FullScreen: CurrentlySelectedOption = Interface.CurrentOptions.FullscreenMode ? 0 : 1; return; - case MenuOptionType.Interpolation: + case OptionType.Interpolation: CurrentlySelectedOption = (int)Interface.CurrentOptions.Interpolation; return; - case MenuOptionType.AnisotropicLevel: + case OptionType.AnisotropicLevel: for (int i = 0; i < Entries.Length; i++) { int level = int.Parse(entries[i] as string ?? string.Empty, NumberStyles.Integer); @@ -63,7 +64,7 @@ internal MenuOption(MenuOptionType type, string text, object[] entries) } } break; - case MenuOptionType.AntialiasingLevel: + case OptionType.AntialiasingLevel: for (int i = 0; i < Entries.Length; i++) { int level = int.Parse(entries[i] as string ?? string.Empty, NumberStyles.Integer); @@ -74,7 +75,7 @@ internal MenuOption(MenuOptionType type, string text, object[] entries) } } break; - case MenuOptionType.ViewingDistance: + case OptionType.ViewingDistance: switch (Interface.CurrentOptions.ViewingDistance) { case 400: @@ -116,7 +117,7 @@ internal void Flip() //Apply switch (Type) { - case MenuOptionType.ScreenResolution: + case OptionType.ScreenResolution: if (!(CurrentOption is ScreenResolution res)) { return; @@ -139,9 +140,7 @@ internal void Flip() //HACK: some resolutions will result in openBVE not appearing on screen in full screen, so restore resolution then change resolution DisplayDevice.Default.RestoreResolution(); DisplayDevice.Default.ChangeResolution(currentResolution); - Program.currentGameWindow.WindowState = WindowState.Fullscreen; - Program.currentGameWindow.X = 0; - Program.currentGameWindow.Y = 0; + Program.Renderer.SetWindowState(WindowState.Fullscreen); Program.currentGameWindow.Width = (int)(currentResolution.Width * DisplayDevice.Default.ScaleFactor.X); Program.currentGameWindow.Height = (int)(currentResolution.Height * DisplayDevice.Default.ScaleFactor.Y); Program.Renderer.Screen.Width = Program.currentGameWindow.Width; @@ -156,11 +155,11 @@ internal void Flip() } } break; - case MenuOptionType.FullScreen: + case OptionType.FullScreen: Interface.CurrentOptions.FullscreenMode = !Interface.CurrentOptions.FullscreenMode; - if (Program.currentGameWindow.WindowState == WindowState.Fullscreen) + if (Interface.CurrentOptions.FullscreenMode) { - Program.currentGameWindow.WindowState = WindowState.Normal; + Program.Renderer.SetWindowState(WindowState.Fullscreen); DisplayDevice.Default.RestoreResolution(); } else @@ -177,9 +176,7 @@ internal void Flip() //HACK: some resolutions will result in openBVE not appearing on screen in full screen, so restore resolution then change resolution DisplayDevice.Default.RestoreResolution(); DisplayDevice.Default.ChangeResolution(currentResolution); - Program.currentGameWindow.WindowState = WindowState.Fullscreen; - Program.currentGameWindow.X = 0; - Program.currentGameWindow.Y = 0; + Program.Renderer.SetWindowState(WindowState.Fullscreen); Program.currentGameWindow.Width = (int)(currentResolution.Width * DisplayDevice.Default.ScaleFactor.X); Program.currentGameWindow.Height = (int)(currentResolution.Height * DisplayDevice.Default.ScaleFactor.Y); Program.Renderer.Screen.Width = Program.currentGameWindow.Width; @@ -194,17 +191,17 @@ internal void Flip() } } break; - case MenuOptionType.Interpolation: + case OptionType.Interpolation: Interface.CurrentOptions.Interpolation = (InterpolationMode)CurrentlySelectedOption; break; //HACK: We can't store plain ints due to to boxing, so store strings and parse instead - case MenuOptionType.AnisotropicLevel: + case OptionType.AnisotropicLevel: Interface.CurrentOptions.AnisotropicFilteringLevel = int.Parse((string)CurrentOption, NumberStyles.Integer); break; - case MenuOptionType.AntialiasingLevel: + case OptionType.AntialiasingLevel: Interface.CurrentOptions.AntiAliasingLevel = int.Parse((string)CurrentOption, NumberStyles.Integer); break; - case MenuOptionType.ViewingDistance: + case OptionType.ViewingDistance: Interface.CurrentOptions.ViewingDistance = int.Parse((string)CurrentOption, NumberStyles.Integer); break; diff --git a/source/OpenBVE/Game/Menu/Menu.OptionType.cs b/source/OpenBVE/Game/Menu/Menu.OptionType.cs deleted file mode 100644 index 725651054..000000000 --- a/source/OpenBVE/Game/Menu/Menu.OptionType.cs +++ /dev/null @@ -1,13 +0,0 @@ -namespace OpenBve -{ - /// The type of menu option - internal enum MenuOptionType - { - ScreenResolution, - ViewingDistance, - FullScreen, - Interpolation, - AnisotropicLevel, - AntialiasingLevel - } -} diff --git a/source/OpenBVE/Game/Menu/Menu.Route.cs b/source/OpenBVE/Game/Menu/Menu.Route.cs index e0cd4ae2a..8489cc683 100644 --- a/source/OpenBVE/Game/Menu/Menu.Route.cs +++ b/source/OpenBVE/Game/Menu/Menu.Route.cs @@ -4,6 +4,7 @@ using System.Drawing; using System.IO; using System.Text; +using LibRender2.Menu; using LibRender2.Primitives; using OpenBveApi; using OpenBveApi.Colors; diff --git a/source/OpenBVE/Game/Menu/Menu.RouteState.cs b/source/OpenBVE/Game/Menu/Menu.RouteState.cs deleted file mode 100644 index f52dc92c9..000000000 --- a/source/OpenBVE/Game/Menu/Menu.RouteState.cs +++ /dev/null @@ -1,19 +0,0 @@ -namespace OpenBve -{ - public partial class Menu - { - private enum RouteState - { - /// No routefile is currently selected - NoneSelected, - /// The background thread is currently loading the routefile data - Loading, - /// The background thread has processed the route data - Processed, - /// An error was encountered loading the route data - Error - - } - } - -} diff --git a/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs b/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs index c14363605..7e93b8ee5 100644 --- a/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs +++ b/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs @@ -3,6 +3,7 @@ using System.Drawing; using System.IO; using DavyKager; +using LibRender2.Menu; using OpenBveApi.Graphics; using OpenBveApi.Hosts; using OpenBveApi.Interface; @@ -242,9 +243,9 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) case MenuType.Options: Items = new MenuEntry[8]; Items[0] = new MenuCaption(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"panel","options"})); - Items[1] = new MenuOption(MenuOptionType.ScreenResolution, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","resolution"}), Program.Renderer.Screen.AvailableResolutions.ToArray()); - Items[2] = new MenuOption(MenuOptionType.FullScreen, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","display_mode_fullscreen"}), new[] { "true", "false" }); - Items[3] = new MenuOption(MenuOptionType.Interpolation, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation"}), new[] + Items[1] = new MenuOption(OptionType.ScreenResolution, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","resolution"}), Program.Renderer.Screen.AvailableResolutions.ToArray()); + Items[2] = new MenuOption(OptionType.FullScreen, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","display_mode_fullscreen"}), new[] { "true", "false" }); + Items[3] = new MenuOption(OptionType.Interpolation, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation"}), new[] { Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_mode_nearest"}), Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_mode_bilinear"}), @@ -253,9 +254,9 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_mode_trilinearmipmap"}), Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_mode_anisotropic"}) }); - Items[4] = new MenuOption(MenuOptionType.AnisotropicLevel, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_anisotropic_level"}), new[] { "0", "2", "4", "8", "16" }); - Items[5] = new MenuOption(MenuOptionType.AntialiasingLevel, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_antialiasing_level"}), new[] { "0", "2", "4", "8", "16" }); - Items[6] = new MenuOption(MenuOptionType.ViewingDistance, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_distance_viewingdistance"}), new[] { "400", "600", "800", "1000", "1500", "2000" }); + Items[4] = new MenuOption(OptionType.AnisotropicLevel, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_anisotropic_level"}), new[] { "0", "2", "4", "8", "16" }); + Items[5] = new MenuOption(OptionType.AntialiasingLevel, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_antialiasing_level"}), new[] { "0", "2", "4", "8", "16" }); + Items[6] = new MenuOption(OptionType.ViewingDistance, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_distance_viewingdistance"}), new[] { "400", "600", "800", "1000", "1500", "2000" }); Items[7] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","back"}), MenuTag.MenuBack, 0); Align = TextAlignment.TopLeft; break; diff --git a/source/OpenBVE/Game/Menu/Menu.cs b/source/OpenBVE/Game/Menu/Menu.cs index 16ace96c8..88110c0b4 100644 --- a/source/OpenBVE/Game/Menu/Menu.cs +++ b/source/OpenBVE/Game/Menu/Menu.cs @@ -7,6 +7,7 @@ using System.IO; using System.Text; using System.Windows.Forms; +using LibRender2.Menu; using LibRender2.Primitives; using LibRender2.Screens; using LibRender2.Text; diff --git a/source/OpenBVE/Graphics/NewRenderer.cs b/source/OpenBVE/Graphics/NewRenderer.cs index 80c72fb1e..ae94bfe71 100644 --- a/source/OpenBVE/Graphics/NewRenderer.cs +++ b/source/OpenBVE/Graphics/NewRenderer.cs @@ -18,6 +18,7 @@ using OpenBveApi.Objects; using OpenBveApi.Routes; using OpenBveApi.World; +using OpenTK; using OpenTK.Graphics.OpenGL; using Vector3 = OpenBveApi.Math.Vector3; @@ -489,6 +490,17 @@ public override void SetCursor(OpenTK.MouseCursor newCursor) Program.currentGameWindow.Cursor = newCursor; } + public override void SetWindowState(OpenTK.WindowState windowState) + { + Program.currentGameWindow.WindowState = windowState; + if (windowState == WindowState.Fullscreen) + { + // move origin appropriately + Program.currentGameWindow.X = 0; + Program.currentGameWindow.Y = 0; + } + } + public NewRenderer(HostInterface CurrentHost, BaseOptions CurrentOptions, FileSystem FileSystem) : base(CurrentHost, CurrentOptions, FileSystem) { } diff --git a/source/OpenBVE/Graphics/Screen.cs b/source/OpenBVE/Graphics/Screen.cs index 44fe70a69..8bc13375b 100644 --- a/source/OpenBVE/Graphics/Screen.cs +++ b/source/OpenBVE/Graphics/Screen.cs @@ -202,14 +202,14 @@ internal static void ToggleFullscreen() { MessageBox.Show(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"errors","fullscreen_switch1"}) + Environment.NewLine + Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"errors","fullscreen_switch2"}), Application.ProductName, MessageBoxButtons.OK, MessageBoxIcon.Hand); - Program.Renderer.Screen.Fullscreen = false; - } + Program.Renderer.SetWindowState(WindowState.Fullscreen); + } } else { DisplayDevice.Default.RestoreResolution(); - Program.currentGameWindow.WindowState = WindowState.Normal; - Program.currentGameWindow.Width = Interface.CurrentOptions.WindowWidth; + Program.Renderer.SetWindowState(WindowState.Normal); + Program.currentGameWindow.Width = Interface.CurrentOptions.WindowWidth; Program.currentGameWindow.Height = Interface.CurrentOptions.WindowHeight; Program.Renderer.Screen.Width = Interface.CurrentOptions.WindowWidth; diff --git a/source/OpenBVE/OpenBve.csproj b/source/OpenBVE/OpenBve.csproj index 3d3451247..d465d544f 100644 --- a/source/OpenBVE/OpenBve.csproj +++ b/source/OpenBVE/OpenBve.csproj @@ -144,16 +144,9 @@ AI.cs - - - - - - - MessageManager.cs diff --git a/source/OpenBVE/System/GameWindow.cs b/source/OpenBVE/System/GameWindow.cs index 6e8d54e3e..553d5e818 100644 --- a/source/OpenBVE/System/GameWindow.cs +++ b/source/OpenBVE/System/GameWindow.cs @@ -11,6 +11,7 @@ using System.Windows.Forms; using LibRender2; using LibRender2.Cameras; +using LibRender2.Menu; using LibRender2.Overlays; using LibRender2.Screens; using LibRender2.Trains; diff --git a/source/OpenBVE/System/Input/Keyboard.cs b/source/OpenBVE/System/Input/Keyboard.cs index 7e0ede11b..4deabf8d4 100644 --- a/source/OpenBVE/System/Input/Keyboard.cs +++ b/source/OpenBVE/System/Input/Keyboard.cs @@ -1,4 +1,5 @@ using System; +using LibRender2.Menu; using LibRender2.Screens; using OpenTK.Input; using OpenBveApi.Interface; diff --git a/source/OpenBVE/System/Input/ProcessControls.Digital.cs b/source/OpenBVE/System/Input/ProcessControls.Digital.cs index a98bdff3c..148fe87dd 100644 --- a/source/OpenBVE/System/Input/ProcessControls.Digital.cs +++ b/source/OpenBVE/System/Input/ProcessControls.Digital.cs @@ -1,5 +1,6 @@ using System; using LibRender2.Cameras; +using LibRender2.Menu; using LibRender2.Overlays; using LibRender2.Screens; using LibRender2.Trains; diff --git a/source/OpenBVE/System/Input/ProcessControls.cs b/source/OpenBVE/System/Input/ProcessControls.cs index c2c6fa654..01c7c965e 100644 --- a/source/OpenBVE/System/Input/ProcessControls.cs +++ b/source/OpenBVE/System/Input/ProcessControls.cs @@ -1,6 +1,7 @@ using System; using System.Linq; using LibRender2.Cameras; +using LibRender2.Menu; using LibRender2.Screens; using LibRender2.Trains; using LibRender2.Viewports; From 02d1c14f7c239eccd9507eeaa355e02d9d17de07 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Wed, 21 Aug 2024 17:33:27 +0100 Subject: [PATCH 04/41] Change: Remove unused constructors from DirectXParser, minor improvement --- .../Plugins/Object.DirectX/Helpers/Block.cs | 70 +++---------------- .../Object.DirectX/Parsers/NewXParser.cs | 1 - 2 files changed, 10 insertions(+), 61 deletions(-) diff --git a/source/Plugins/Object.DirectX/Helpers/Block.cs b/source/Plugins/Object.DirectX/Helpers/Block.cs index 76bcb466a..2398d9ccc 100644 --- a/source/Plugins/Object.DirectX/Helpers/Block.cs +++ b/source/Plugins/Object.DirectX/Helpers/Block.cs @@ -41,7 +41,7 @@ public abstract class Block /// Normally blank public string Label; - public int FloatingPointSize; + public readonly int FloatingPointSize; /// Reads an integer from the block public abstract int ReadUInt(); @@ -65,16 +65,6 @@ public abstract class Block /// Returns the position of the reader within the block public abstract long Position(); - /// Creates a new block from the supplied byte array - /// The block of data - /// The token for the new block - /// The new block - /// Always creates a BinaryBlock - public static Block ReadBlock(byte[] bytes, TemplateID token) - { - return new BinaryBlock(bytes, token); - } - /// Creates a new block from the supplied string /// The string /// The token for the new block @@ -101,6 +91,11 @@ public static Block ReadBlock(string text, TemplateID token) /// The new block /// The type of the new block will always match that of the base block public abstract Block ReadSubBlock(); + + public Block(int floatingPointSize = -1) + { + FloatingPointSize = floatingPointSize; + } } /// @@ -110,13 +105,13 @@ public class TextualBlock : Block private int currentPosition; - public TextualBlock(string text) + public TextualBlock(string text) : base(-1) { myText = text; currentPosition = 0; } - public TextualBlock(string text, TemplateID token) + public TextualBlock(string text, TemplateID token) : base(-1) { StringBuilder sb = new StringBuilder(); for (int i = 0; i < text.Length; i++) @@ -597,52 +592,8 @@ public class BinaryBlock : Block, IDisposable private readonly List cachedFloats = new List(); private readonly List cachedStrings = new List(); - public BinaryBlock(byte[] bytes, TemplateID token) + public BinaryBlock(byte[] bytes, int floatingPointSize) : base(floatingPointSize) { - myStream = new MemoryStream(bytes); - myReader = new BinaryReader(myStream); - while (myStream.Position < myStream.Length) - { - string currentToken = getNextToken(); - switch (currentToken) - { - case "int_list": - int integerCount = (int) myReader.ReadInt32(); - for (int i = 0; i < integerCount; i++) - { - cachedIntegers.Add(myReader.ReadInt16()); - } - myStream.Position += integerCount * 4; - break; - case "float_list": - int floatCount = (int) myReader.ReadInt32(); - switch (FloatingPointSize) - { - case 32: - for (int i = 0; i < floatCount; i++) - { - cachedFloats.Add(myReader.ReadSingle()); - } - - break; - case 64: - for (int i = 0; i < floatCount; i++) - { - cachedFloats.Add(myReader.ReadDouble()); - } - break; - default: - throw new Exception("Unsupported Floating Point Size"); - } - break; - - } - } - } - - public BinaryBlock(byte[] bytes, int floatingPointSize) - { - FloatingPointSize = floatingPointSize; myStream = new MemoryStream(bytes); myReader = new BinaryReader(myStream); long startPosition; @@ -694,9 +645,8 @@ public BinaryBlock(byte[] bytes, int floatingPointSize) } } - private BinaryBlock(byte[] bytes, TemplateID token, int floatingPointSize) + private BinaryBlock(byte[] bytes, TemplateID token, int floatingPointSize) : base(floatingPointSize) { - FloatingPointSize = floatingPointSize; myStream = new MemoryStream(bytes); myReader = new BinaryReader(myStream); Token = token; diff --git a/source/Plugins/Object.DirectX/Parsers/NewXParser.cs b/source/Plugins/Object.DirectX/Parsers/NewXParser.cs index 0b93232ad..078d36069 100644 --- a/source/Plugins/Object.DirectX/Parsers/NewXParser.cs +++ b/source/Plugins/Object.DirectX/Parsers/NewXParser.cs @@ -581,7 +581,6 @@ private static void ParseSubBlock(Block block, ref StaticObject obj, ref MeshBui private static StaticObject LoadBinaryX(byte[] Data, int FloatingPointSize) { Block block = new BinaryBlock(Data, FloatingPointSize); - block.FloatingPointSize = FloatingPointSize; StaticObject obj = new StaticObject(Plugin.currentHost); MeshBuilder builder = new MeshBuilder(Plugin.currentHost); Material material = new Material(); From eebf86e124546d1536ce190cf788ad232585e831 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Wed, 21 Aug 2024 17:46:14 +0100 Subject: [PATCH 05/41] Change: Stop VS from nagging about PascalCase constantly --- .editorconfig | 1 + 1 file changed, 1 insertion(+) diff --git a/.editorconfig b/.editorconfig index ce284e575..3257056ea 100644 --- a/.editorconfig +++ b/.editorconfig @@ -11,6 +11,7 @@ tab_width = 4 [*.cs] csharp_preserve_single_line_blocks = false +dotnet_diagnostic.IDE1006.severity = none [*.yml] indent_style = space From 522bd42b0c05704102ea5d17c119684e7b540553 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Wed, 21 Aug 2024 17:49:36 +0100 Subject: [PATCH 06/41] Change: Minor improvement in Assimp DirectX parser --- source/AssimpParser/AssimpParser.csproj | 4 ++-- source/AssimpParser/X/XFileHelper.cs | 5 +++-- source/AssimpParser/X/XFileParser.cs | 10 +++------- 3 files changed, 8 insertions(+), 11 deletions(-) diff --git a/source/AssimpParser/AssimpParser.csproj b/source/AssimpParser/AssimpParser.csproj index 4ecf864a8..092795690 100644 --- a/source/AssimpParser/AssimpParser.csproj +++ b/source/AssimpParser/AssimpParser.csproj @@ -23,7 +23,7 @@ 4 AnyCPU false - 6 + 7.0 pdbonly @@ -34,7 +34,7 @@ 4 AnyCPU false - 6 + 7.0 diff --git a/source/AssimpParser/X/XFileHelper.cs b/source/AssimpParser/X/XFileHelper.cs index 95fd40d52..9981a127a 100644 --- a/source/AssimpParser/X/XFileHelper.cs +++ b/source/AssimpParser/X/XFileHelper.cs @@ -108,7 +108,7 @@ public TexEntry(string name, bool isNormalMap = false) /** Helper structure representing a XFile material */ public class Material { - public string Name; + public readonly string Name; public readonly bool IsReference; // if true, mName holds a name by which the actual material can be found in the material list public Color128 Diffuse; public float SpecularExponent; @@ -118,9 +118,10 @@ public class Material public uint SceneIndex; // the index under which it was stored in the scene's material list - public Material(bool isReference) + public Material(bool isReference, string name) { IsReference = isReference; + Name = name; } } diff --git a/source/AssimpParser/X/XFileParser.cs b/source/AssimpParser/X/XFileParser.cs index 3780e08ca..d06fa4865 100644 --- a/source/AssimpParser/X/XFileParser.cs +++ b/source/AssimpParser/X/XFileParser.cs @@ -847,10 +847,9 @@ protected void ParseDataObjectMeshMaterialList(ref Mesh mesh) { // template materials string matName = GetNextToken(); - Material material = new Material(true); + Material material = new Material(true, matName); //Use default BVE white color so this is visible if the global material is missing, otherwise will be overwritten material.Diffuse = Color128.White; - material.Name = matName; mesh.Materials.Add(material); CheckForClosingBrace(); // skip } @@ -875,15 +874,12 @@ protected void ParseDataObjectMeshMaterialList(ref Mesh mesh) protected void ParseDataObjectMaterial(out Material material) { - material = new Material(false); - - string matName; - ReadHeadOfDataObject(out matName); + ReadHeadOfDataObject(out string matName); if (matName.Length == 0) { matName = "material" + LineNumber; } - material.Name = matName; + material = new Material(false, matName); // read material values material.Diffuse = ReadRGBA(); From afa7a86c9efd9702b4a97890e6f3941b4fb5234d Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Wed, 21 Aug 2024 17:53:30 +0100 Subject: [PATCH 07/41] Change: Suppress a couple of useless warnings --- source/OpenBveApi/Math/Vectors/Vector2.cs | 1 + source/OpenBveApi/Math/Vectors/Vector2f.cs | 3 ++- 2 files changed, 3 insertions(+), 1 deletion(-) diff --git a/source/OpenBveApi/Math/Vectors/Vector2.cs b/source/OpenBveApi/Math/Vectors/Vector2.cs index 786dffc20..e8ea7b5b4 100644 --- a/source/OpenBveApi/Math/Vectors/Vector2.cs +++ b/source/OpenBveApi/Math/Vectors/Vector2.cs @@ -1,4 +1,5 @@ using System; +#pragma warning disable IDE0064 using System.Runtime.InteropServices; namespace OpenBveApi.Math { diff --git a/source/OpenBveApi/Math/Vectors/Vector2f.cs b/source/OpenBveApi/Math/Vectors/Vector2f.cs index dd3f51f33..06fa76554 100644 --- a/source/OpenBveApi/Math/Vectors/Vector2f.cs +++ b/source/OpenBveApi/Math/Vectors/Vector2f.cs @@ -1,4 +1,5 @@ -using System; +#pragma warning disable IDE0064 +using System; namespace OpenBveApi.Math { /// Represents a two-dimensional vector. From 6e4775a1fa546734286356908fd3d36a0103f994 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Wed, 21 Aug 2024 17:55:37 +0100 Subject: [PATCH 08/41] Change: Inline variables in Assimp DirectX parser --- source/AssimpParser/X/XFileParser.cs | 33 ++++++++++------------------ 1 file changed, 11 insertions(+), 22 deletions(-) diff --git a/source/AssimpParser/X/XFileParser.cs b/source/AssimpParser/X/XFileParser.cs index d06fa4865..8505fc35a 100644 --- a/source/AssimpParser/X/XFileParser.cs +++ b/source/AssimpParser/X/XFileParser.cs @@ -346,8 +346,7 @@ protected void ParseFile() case "mesh": { // some meshes have no frames at all - Mesh mesh; - ParseDataObjectMesh(out mesh); + ParseDataObjectMesh(out Mesh mesh); Scene.GlobalMeshes.Add(mesh); break; } @@ -360,8 +359,7 @@ protected void ParseFile() case "material": { // Material outside of a mesh or node - Material material; - ParseDataObjectMaterial(out material); + ParseDataObjectMaterial(out Material material); Scene.GlobalMaterials.Add(material); break; } @@ -382,8 +380,7 @@ protected void ParseDataObjectTemplate() { // parse a template data object. Currently not stored. // ReSharper disable once NotAccessedVariable - string name; - ReadHeadOfDataObject(out name); + ReadHeadOfDataObject(out string name); // read GUID string guid = GetNextToken(); @@ -412,8 +409,7 @@ protected void ParseDataObjectFrame(Node parent) // mesh-loading functions recognize Mesh, FrameTransformMatrix, and // Frame template instances as child objects when loading a Frame // instance. - string name; - ReadHeadOfDataObject(out name); + ReadHeadOfDataObject(out string name); // create a named node and place it at its parent, if given Node node = new Node(name, parent); @@ -470,8 +466,7 @@ protected void ParseDataObjectFrame(Node parent) break; case "mesh": { - Mesh mesh; - ParseDataObjectMesh(out mesh); + ParseDataObjectMesh(out Mesh mesh); node.Meshes.Add(mesh); break; } @@ -521,8 +516,7 @@ protected void ParseDataObjectMesh(out Mesh mesh) mesh = new Mesh(); // ReSharper disable once NotAccessedVariable - string name; - ReadHeadOfDataObject(out name); + ReadHeadOfDataObject(out string name); // read vertex count uint numVertices = ReadInt(); @@ -614,8 +608,7 @@ protected void ParseDataObjectSkinWeights(ref Mesh mesh) { ReadHeadOfDataObject(); - string transformNodeName; - GetNextTokenAsString(out transformNodeName); + GetNextTokenAsString(out string transformNodeName); Bone bone = new Bone(transformNodeName); @@ -856,8 +849,7 @@ protected void ParseDataObjectMeshMaterialList(ref Mesh mesh) } else if (objectName == "Material") { - Material material; - ParseDataObjectMaterial(out material); + ParseDataObjectMaterial(out Material material); mesh.Materials.Add(material); } else if (objectName == ";") @@ -902,15 +894,13 @@ protected void ParseDataObjectMaterial(out Material material) else if (objectName == "TextureFilename" || objectName == "TextureFileName") { // some exporters write "TextureFileName" instead. - string texname; - ParseDataObjectTextureFilename(out texname); + ParseDataObjectTextureFilename(out string texname); material.Textures.Add(new TexEntry(texname)); } else if (objectName == "NormalmapFilename" || objectName == "NormalmapFileName") { // one exporter writes out the normal map in a separate filename tag - string texname; - ParseDataObjectTextureFilename(out texname); + ParseDataObjectTextureFilename(out string texname); material.Textures.Add(new TexEntry(texname, true)); } else @@ -930,8 +920,7 @@ protected void ParseDataObjectAnimTicksPerSecond() protected void ParseDataObjectAnimationSet() { - string animName; - ReadHeadOfDataObject(out animName); + ReadHeadOfDataObject(out string animName); Animation anim = new Animation(animName); From cc49e20d22f15d12931ebea32fbb4d9abbdaf3a0 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Wed, 21 Aug 2024 17:57:19 +0100 Subject: [PATCH 09/41] Change: Minor cleaning --- .../DenshaDeGoInput/DenshaDeGoInput.csproj | 2 +- .../InputDevicePlugins/SanYingInput/SanYingInput.csproj | 2 +- source/ObjectViewer/ObjectViewer.csproj | 2 +- source/OpenBveApi/Routes/BackgroundObject.cs | 1 - source/Plugins/Object.Animated/Object.Animated.csproj | 2 +- source/Plugins/Object.Animated/Plugin.Parser.cs | 9 ++++----- source/RouteViewer/RouteViewer.csproj | 2 +- source/TrainManager/Train/Doors.cs | 4 ++-- 8 files changed, 11 insertions(+), 13 deletions(-) diff --git a/source/InputDevicePlugins/DenshaDeGoInput/DenshaDeGoInput.csproj b/source/InputDevicePlugins/DenshaDeGoInput/DenshaDeGoInput.csproj index a78fd6b93..c449bb613 100644 --- a/source/InputDevicePlugins/DenshaDeGoInput/DenshaDeGoInput.csproj +++ b/source/InputDevicePlugins/DenshaDeGoInput/DenshaDeGoInput.csproj @@ -119,4 +119,4 @@ - + \ No newline at end of file diff --git a/source/InputDevicePlugins/SanYingInput/SanYingInput.csproj b/source/InputDevicePlugins/SanYingInput/SanYingInput.csproj index 9b990f56d..6ce6f5267 100644 --- a/source/InputDevicePlugins/SanYingInput/SanYingInput.csproj +++ b/source/InputDevicePlugins/SanYingInput/SanYingInput.csproj @@ -1,4 +1,4 @@ - + diff --git a/source/ObjectViewer/ObjectViewer.csproj b/source/ObjectViewer/ObjectViewer.csproj index 7c7f190d8..cf5328327 100644 --- a/source/ObjectViewer/ObjectViewer.csproj +++ b/source/ObjectViewer/ObjectViewer.csproj @@ -1,7 +1,7 @@  - $(NoWarn),IDE1006 + $(NoWarn),IDE1006 Debug diff --git a/source/OpenBveApi/Routes/BackgroundObject.cs b/source/OpenBveApi/Routes/BackgroundObject.cs index cc5e229c1..16195a05c 100644 --- a/source/OpenBveApi/Routes/BackgroundObject.cs +++ b/source/OpenBveApi/Routes/BackgroundObject.cs @@ -47,7 +47,6 @@ public BackgroundObject(StaticObject Object, bool CreateCylinderCaps = false) } newObject.Mesh.Faces[f] = new MeshFace(vertexIndicies.ToArray(), FaceFlags.Face2Mask); - newObject.Mesh.Faces[f].Material = 0; this.Object = newObject; } else diff --git a/source/Plugins/Object.Animated/Object.Animated.csproj b/source/Plugins/Object.Animated/Object.Animated.csproj index d372544d9..8c5519221 100644 --- a/source/Plugins/Object.Animated/Object.Animated.csproj +++ b/source/Plugins/Object.Animated/Object.Animated.csproj @@ -1,4 +1,4 @@ - + diff --git a/source/Plugins/Object.Animated/Plugin.Parser.cs b/source/Plugins/Object.Animated/Plugin.Parser.cs index 2cb1c12e6..64134635d 100644 --- a/source/Plugins/Object.Animated/Plugin.Parser.cs +++ b/source/Plugins/Object.Animated/Plugin.Parser.cs @@ -115,9 +115,8 @@ private static AnimatedObjectCollection ReadObject(string FileName, System.Text. { if (obj[j] != null) { - if (obj[j] is StaticObject) + if (obj[j] is StaticObject s) { - StaticObject s = (StaticObject)obj[j]; s.Dynamic = true; if (ObjectCount >= Result.Objects.Length) { @@ -760,17 +759,17 @@ private static AnimatedObjectCollection ReadObject(string FileName, System.Text. if (StateFiles[k] != null) { currentHost.LoadObject(StateFiles[k], Encoding, out UnifiedObject currentObject); - if (currentObject is StaticObject) + if (currentObject is StaticObject staticObject) { if (Scale != Vector3.One) { - StaticObject obj = (StaticObject)currentObject.Clone(); + StaticObject obj = (StaticObject)staticObject.Clone(); obj.ApplyScale(Scale); Result.Objects[ObjectCount].States[k].Prototype = obj; } else { - Result.Objects[ObjectCount].States[k].Prototype = (StaticObject) currentObject; + Result.Objects[ObjectCount].States[k].Prototype = staticObject; } } diff --git a/source/RouteViewer/RouteViewer.csproj b/source/RouteViewer/RouteViewer.csproj index f37b14ce2..a686709b1 100644 --- a/source/RouteViewer/RouteViewer.csproj +++ b/source/RouteViewer/RouteViewer.csproj @@ -1,7 +1,7 @@  - $(NoWarn),IDE1006 + $(NoWarn),IDE1006 Debug diff --git a/source/TrainManager/Train/Doors.cs b/source/TrainManager/Train/Doors.cs index f8db59fbc..d7803961e 100644 --- a/source/TrainManager/Train/Doors.cs +++ b/source/TrainManager/Train/Doors.cs @@ -266,9 +266,9 @@ public void UpdateDoors(double TimeElapsed) { for (int j = 0; j < InputDevicePlugin.AvailablePluginInfos.Count; j++) { - if (InputDevicePlugin.AvailablePluginInfos[j].Status == InputDevicePlugin.PluginInfo.PluginStatus.Enable && InputDevicePlugin.AvailablePlugins[j] is ITrainInputDevice) + if (InputDevicePlugin.AvailablePluginInfos[j].Status == InputDevicePlugin.PluginInfo.PluginStatus.Enable + && InputDevicePlugin.AvailablePlugins[j] is ITrainInputDevice trainInputDevice) { - ITrainInputDevice trainInputDevice = (ITrainInputDevice)InputDevicePlugin.AvailablePlugins[j]; trainInputDevice.DoorChange(oldState, newState); } } From b8d440cd3ce1ae28501baef13df87f7807ae1bf0 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Thu, 22 Aug 2024 10:52:26 +0100 Subject: [PATCH 10/41] Change: Move more of the GL menu to LibRender2, add BSD headers --- source/LibRender2/LibRender2.csproj | 2 + source/LibRender2/Menu/AbstractMenu.cs | 76 ++++++++++++ source/LibRender2/Menu/Menu.OptionType.cs | 26 ++++- source/LibRender2/Menu/Menu.RouteState.cs | 26 ++++- source/LibRender2/Menu/MenuBase.cs | 74 ++++++++++++ .../Menu/MenuEntries/MenuEntry.Caption.cs | 26 ++++- .../Menu/MenuEntries/MenuEntry.Command.cs | 26 ++++- .../LibRender2/Menu/MenuEntries/MenuEntry.cs | 26 ++++- source/LibRender2/Menu/MenuTag.cs | 26 ++++- source/LibRender2/Menu/MenuType.cs | 26 ++++- source/OpenBVE/Game/Information.cs | 2 +- source/OpenBVE/Game/Menu/Menu.Controls.cs | 2 +- source/OpenBVE/Game/Menu/Menu.MenuOption.cs | 2 +- source/OpenBVE/Game/Menu/Menu.Route.cs | 2 +- source/OpenBVE/Game/Menu/Menu.SingleMenu.cs | 32 ++---- source/OpenBVE/Game/Menu/Menu.cs | 108 +++++++----------- source/OpenBVE/OpenBve.csproj | 4 +- source/OpenBVE/System/GameWindow.cs | 2 +- 18 files changed, 385 insertions(+), 103 deletions(-) create mode 100644 source/LibRender2/Menu/AbstractMenu.cs create mode 100644 source/LibRender2/Menu/MenuBase.cs diff --git a/source/LibRender2/LibRender2.csproj b/source/LibRender2/LibRender2.csproj index 2a374444e..77c55b744 100644 --- a/source/LibRender2/LibRender2.csproj +++ b/source/LibRender2/LibRender2.csproj @@ -59,6 +59,8 @@ + + diff --git a/source/LibRender2/Menu/AbstractMenu.cs b/source/LibRender2/Menu/AbstractMenu.cs new file mode 100644 index 000000000..724edd781 --- /dev/null +++ b/source/LibRender2/Menu/AbstractMenu.cs @@ -0,0 +1,76 @@ +//Simplified BSD License (BSD-2-Clause) +// +//Copyright (c) 2024, Maurizo M. Gavioli, The OpenBVE Project +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions are met: +// +//1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +//2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +using LibRender2.Text; +using OpenBveApi.Colors; +using OpenBveApi.Math; + +namespace LibRender2.Menu +{ + /// Provides the abstract class for creating OpenGL based menus + public abstract class AbstractMenu + { + /// The color used for the overlay + public readonly Color128 overlayColor = new Color128(0.0f, 0.0f, 0.0f, 0.2f); + + /// The color used for the menu background + public readonly Color128 backgroundColor = Color128.Black; + + /// The color used to draw the highlight over a selected item + public readonly Color128 highlightColor = Color128.Orange; + + /// The color used to draw the highlight over a selected folder + public readonly Color128 folderHighlightColor = new Color128(0.0f, 0.69f, 1.0f, 1.0f); + + /// The color used to draw the highlight over a selected routefile + public readonly Color128 routeHighlightColor = new Color128(0.0f, 1.0f, 0.69f, 1.0f); + + /// The color used for caption text + public static readonly Color128 ColourCaption = new Color128(0.750f, 0.750f, 0.875f, 1.0f); + + /// The color used to draw dimmed text + public static readonly Color128 ColourDimmed = new Color128(1.000f, 1.000f, 1.000f, 0.5f); + + /// The color used to draw highlighted text + public static readonly Color128 ColourHighlight = Color128.Black; + + /// The color used to draw normal text + public static readonly Color128 ColourNormal = Color128.White; + + /// Holds the stack of menus + public MenuBase[] Menus = { }; + + /// The font currently used for drawing menu items + public OpenGlFont menuFont = null; + + /// The number of visible items in the menu + public int visibleItems; + + /// The screen co-ordinates of the top-left of the menu + public Vector2 menuMin; + + /// The screen co-ordinates of the bottom-right of the menu + public Vector2 menuMax; + } +} diff --git a/source/LibRender2/Menu/Menu.OptionType.cs b/source/LibRender2/Menu/Menu.OptionType.cs index 8bf38aaad..e7f1cbfcd 100644 --- a/source/LibRender2/Menu/Menu.OptionType.cs +++ b/source/LibRender2/Menu/Menu.OptionType.cs @@ -1,4 +1,28 @@ -namespace LibRender2.Menu +//Simplified BSD License (BSD-2-Clause) +// +//Copyright (c) 2024, Maurizo M. Gavioli, The OpenBVE Project +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions are met: +// +//1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +//2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +namespace LibRender2.Menu { /// The type of menu option public enum OptionType diff --git a/source/LibRender2/Menu/Menu.RouteState.cs b/source/LibRender2/Menu/Menu.RouteState.cs index 090e7d521..fd871b998 100644 --- a/source/LibRender2/Menu/Menu.RouteState.cs +++ b/source/LibRender2/Menu/Menu.RouteState.cs @@ -1,4 +1,28 @@ -namespace LibRender2.Menu +//Simplified BSD License (BSD-2-Clause) +// +//Copyright (c) 2024, Maurizo M. Gavioli, The OpenBVE Project +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions are met: +// +//1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +//2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +namespace LibRender2.Menu { public enum RouteState { diff --git a/source/LibRender2/Menu/MenuBase.cs b/source/LibRender2/Menu/MenuBase.cs new file mode 100644 index 000000000..41d4db2a2 --- /dev/null +++ b/source/LibRender2/Menu/MenuBase.cs @@ -0,0 +1,74 @@ +//Simplified BSD License (BSD-2-Clause) +// +//Copyright (c) 2024, Maurizo M. Gavioli, The OpenBVE Project +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions are met: +// +//1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +//2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +using OpenBveApi.Graphics; + +namespace LibRender2.Menu +{ + /// The base class for a single menu within the menu stack + public class MenuBase + { + /// The text alignment for the menu + public TextAlignment Align; + + /// The list of items to be shown + public MenuEntry[] Items = { }; + + /// The smaller of the width of the largest item, and the absolute width + public double ItemWidth = 0; + + /// The absolute width + public double Width = 0; + + /// The absolute height + public double Height = 0; + + /// The previous menu selection + public int LastSelection = int.MaxValue; + + private int currentSelection; + + /// The currently displayed top item + public int TopItem; + + /// The type of menu + public readonly MenuType Type; + + /// Gets the currently selected menu item + public virtual int Selection + { + get => currentSelection; + set + { + LastSelection = currentSelection; + currentSelection = value; + } + } + + public MenuBase(MenuType type) + { + Type = type; + } + } +} diff --git a/source/LibRender2/Menu/MenuEntries/MenuEntry.Caption.cs b/source/LibRender2/Menu/MenuEntries/MenuEntry.Caption.cs index 46b7a6ef1..71327102a 100644 --- a/source/LibRender2/Menu/MenuEntries/MenuEntry.Caption.cs +++ b/source/LibRender2/Menu/MenuEntries/MenuEntry.Caption.cs @@ -1,4 +1,28 @@ -namespace LibRender2.Menu +//Simplified BSD License (BSD-2-Clause) +// +//Copyright (c) 2024, Maurizo M. Gavioli, The OpenBVE Project +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions are met: +// +//1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +//2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +namespace LibRender2.Menu { /// A caption to be rendered at the top of the menu public class MenuCaption : MenuEntry diff --git a/source/LibRender2/Menu/MenuEntries/MenuEntry.Command.cs b/source/LibRender2/Menu/MenuEntries/MenuEntry.Command.cs index 294f436fc..f21c483f1 100644 --- a/source/LibRender2/Menu/MenuEntries/MenuEntry.Command.cs +++ b/source/LibRender2/Menu/MenuEntries/MenuEntry.Command.cs @@ -1,4 +1,28 @@ -using OpenBveApi.Textures; +//Simplified BSD License (BSD-2-Clause) +// +//Copyright (c) 2024, Maurizo M. Gavioli, The OpenBVE Project +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions are met: +// +//1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +//2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +using OpenBveApi.Textures; namespace LibRender2.Menu { diff --git a/source/LibRender2/Menu/MenuEntries/MenuEntry.cs b/source/LibRender2/Menu/MenuEntries/MenuEntry.cs index 24822829a..48fa1c322 100644 --- a/source/LibRender2/Menu/MenuEntries/MenuEntry.cs +++ b/source/LibRender2/Menu/MenuEntries/MenuEntry.cs @@ -1,4 +1,28 @@ -using OpenBveApi.Textures; +//Simplified BSD License (BSD-2-Clause) +// +//Copyright (c) 2024, Maurizo M. Gavioli, The OpenBVE Project +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions are met: +// +//1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +//2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +using OpenBveApi.Textures; namespace LibRender2.Menu { diff --git a/source/LibRender2/Menu/MenuTag.cs b/source/LibRender2/Menu/MenuTag.cs index 8516b8b49..a76d739b7 100644 --- a/source/LibRender2/Menu/MenuTag.cs +++ b/source/LibRender2/Menu/MenuTag.cs @@ -1,4 +1,28 @@ -// ReSharper disable UnusedMember.Global +//Simplified BSD License (BSD-2-Clause) +// +//Copyright (c) 2024, Maurizo M. Gavioli, The OpenBVE Project +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions are met: +// +//1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +//2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +// ReSharper disable UnusedMember.Global namespace LibRender2.Menu { /// The list of possible tags for a menu entry- These define the functionality of a given menu entry diff --git a/source/LibRender2/Menu/MenuType.cs b/source/LibRender2/Menu/MenuType.cs index 452b54c98..4bb05d70d 100644 --- a/source/LibRender2/Menu/MenuType.cs +++ b/source/LibRender2/Menu/MenuType.cs @@ -1,4 +1,28 @@ -namespace LibRender2.Menu +//Simplified BSD License (BSD-2-Clause) +// +//Copyright (c) 2024, Maurizo M. Gavioli, The OpenBVE Project +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions are met: +// +//1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +//2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +namespace LibRender2.Menu { /// The list of possible sub-menu types public enum MenuType diff --git a/source/OpenBVE/Game/Information.cs b/source/OpenBVE/Game/Information.cs index 2b0f2e918..b383dedfd 100644 --- a/source/OpenBVE/Game/Information.cs +++ b/source/OpenBVE/Game/Information.cs @@ -5,7 +5,7 @@ internal static partial class Game /// The current plugin debug message to be displayed internal static string InfoDebugString = ""; /// The in-game menu system - internal static readonly Menu Menu = Menu.Instance; + internal static readonly GameMenu Menu = GameMenu.Instance; /// The in-game overlay with route info drawings internal static readonly RouteInfoOverlay routeInfoOverlay = new RouteInfoOverlay(); diff --git a/source/OpenBVE/Game/Menu/Menu.Controls.cs b/source/OpenBVE/Game/Menu/Menu.Controls.cs index 1b4bdccb6..f0467d37a 100644 --- a/source/OpenBVE/Game/Menu/Menu.Controls.cs +++ b/source/OpenBVE/Game/Menu/Menu.Controls.cs @@ -5,7 +5,7 @@ namespace OpenBve { - public sealed partial class Menu + public sealed partial class GameMenu { private static readonly Picturebox controlPictureBox = new Picturebox(Program.Renderer); private static readonly Textbox controlTextBox = new Textbox(Program.Renderer, Program.Renderer.Fonts.NormalFont, Color128.White, Color128.Black); diff --git a/source/OpenBVE/Game/Menu/Menu.MenuOption.cs b/source/OpenBVE/Game/Menu/Menu.MenuOption.cs index 6ffd93041..bdf85ce7a 100644 --- a/source/OpenBVE/Game/Menu/Menu.MenuOption.cs +++ b/source/OpenBVE/Game/Menu/Menu.MenuOption.cs @@ -8,7 +8,7 @@ namespace OpenBve { - public sealed partial class Menu + public sealed partial class GameMenu { private class MenuOption : MenuEntry { diff --git a/source/OpenBVE/Game/Menu/Menu.Route.cs b/source/OpenBVE/Game/Menu/Menu.Route.cs index 8489cc683..7a06a671d 100644 --- a/source/OpenBVE/Game/Menu/Menu.Route.cs +++ b/source/OpenBVE/Game/Menu/Menu.Route.cs @@ -17,7 +17,7 @@ namespace OpenBve { - public partial class Menu + public partial class GameMenu { private static BackgroundWorker routeWorkerThread; private static BackgroundWorker packageWorkerThread; diff --git a/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs b/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs index 7e93b8ee5..6fb4c9fe8 100644 --- a/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs +++ b/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs @@ -15,29 +15,19 @@ namespace OpenBve { - public sealed partial class Menu + public sealed partial class GameMenu { - /// Describes a single menu of the menu stack. - /// The class is private to Menu, but all its fields are public to allow 'quick-and-dirty' - /// access from Menu itself. - private class SingleMenu + /// Provides implementation for a single menu of the menu stack. + /// The class is private to Menu, but all its fields are public to allow 'quick-and-dirty' + /// access from Menu itself. + private class SingleMenu : MenuBase { - /// The text alignment for the menu - public readonly TextAlignment Align; - /// The list of items to be shown - public readonly MenuEntry[] Items = { }; - /// The smaller of the width of the largest item, and the absolute width - public readonly double ItemWidth = 0; - /// The absolute width - public readonly double Width = 0; - /// The absolute height - public readonly double Height = 0; /// The previous menu selection internal int LastSelection = int.MaxValue; private int currentSelection; - public int Selection + public sealed override int Selection { get => currentSelection; set @@ -54,16 +44,9 @@ public int Selection } } } - public int TopItem; // the top displayed menu item - internal readonly MenuType Type; - - /******************** - MENU C'TOR - *********************/ - public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) + public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(menuType) { - Type = menuType; int i; int jump = 0; //Vector2 size; @@ -582,7 +565,6 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) Height = Items.Length * Game.Menu.LineHeight; TopItem = 0; } - } internal class FoundSwitch diff --git a/source/OpenBVE/Game/Menu/Menu.cs b/source/OpenBVE/Game/Menu/Menu.cs index 88110c0b4..efcb7d13a 100644 --- a/source/OpenBVE/Game/Menu/Menu.cs +++ b/source/OpenBVE/Game/Menu/Menu.cs @@ -6,7 +6,6 @@ using System.Drawing; using System.IO; using System.Text; -using System.Windows.Forms; using LibRender2.Menu; using LibRender2.Primitives; using LibRender2.Screens; @@ -32,27 +31,13 @@ Implemented as a singleton. Keeps a stack of menus, allowing navigating forward and back */ /// Implements the in-game menu system; manages addition and removal of individual menus. - public sealed partial class Menu + public sealed partial class GameMenu : AbstractMenu { - // components of the semi-transparent screen overlay - private readonly Color128 overlayColor = new Color128(0.0f, 0.0f, 0.0f, 0.2f); - private readonly Color128 backgroundColor = Color128.Black; - private readonly Color128 highlightColor = Color128.Orange; - private readonly Color128 folderHighlightColor = new Color128(0.0f, 0.69f, 1.0f, 1.0f); - private readonly Color128 routeHighlightColor = new Color128(0.0f, 1.0f, 0.69f, 1.0f); - // text colours - private static readonly Color128 ColourCaption = new Color128(0.750f, 0.750f, 0.875f, 1.0f); - private static readonly Color128 ColourDimmed = new Color128(1.000f, 1.000f, 1.000f, 0.5f); - private static readonly Color128 ColourHighlight = Color128.Black; - private static readonly Color128 ColourNormal = Color128.White; private static readonly Picturebox LogoPictureBox = new Picturebox(Program.Renderer); internal static List nextSwitches = new List(); internal static List previousSwitches = new List(); internal static bool switchesFound = false; - - // some sizes and constants - // TODO: make borders Menu fields dependent on font size private const int MenuBorderX = 16; private const int MenuBorderY = 16; private const int MenuItemBorderX = 8; @@ -73,13 +58,9 @@ MENU SYSTEM FIELDS private bool isInitialized = false; // the total line height from the top of an item to the top of the item below (in pixels) private int lineHeight; - private SingleMenu[] Menus = { }; - private OpenGlFont menuFont = null; - // area occupied by the items of the current menu in screen coordinates - private double menuXmin, menuXmax, menuYmin, menuYmax; + private double topItemY; // the top edge of top item - private int visibleItems; // the number of visible items - // properties (to allow read-only access to some fields) + internal int LineHeight => lineHeight; internal OpenGlFont MenuFont => menuFont; @@ -89,17 +70,17 @@ MENU SYSTEM FIELDS /******************** MENU SYSTEM SINGLETON C'TOR *********************/ - private static readonly Menu instance = new Menu(); + private static readonly GameMenu instance = new GameMenu(); // Explicit static constructor to tell C# compiler not to mark type as beforefieldinit - static Menu() + static GameMenu() { } - private Menu() + private GameMenu() { } /// Returns the current menu instance (If applicable) - public static Menu Instance => instance; + public static GameMenu Instance => instance; /******************** MENU SYSTEM METHODS @@ -295,7 +276,7 @@ internal void ProcessMouseScroll(int Scroll) return; } // Load the current menu - SingleMenu menu = Menus[CurrMenu]; + MenuBase menu = Menus[CurrMenu]; if (menu.Type == MenuType.RouteList || menu.Type == MenuType.TrainList || menu.Type == MenuType.PackageInstall || menu.Type == MenuType.Packages || (int)menu.Type >= 107) { if (routeDescriptionBox.CurrentlySelected) @@ -358,8 +339,8 @@ internal bool ProcessMouseMove(int x, int y) return false; // Load the current menu - SingleMenu menu = Menus[CurrMenu]; - if (menu.TopItem > 1 && y < topItemY && y > menuYmin) + MenuBase menu = Menus[CurrMenu]; + if (menu.TopItem > 1 && y < topItemY && y > menuMin.Y) { //Item is the scroll up ellipsis menu.Selection = menu.TopItem - 1; @@ -375,7 +356,7 @@ internal bool ProcessMouseMove(int x, int y) return true; } } - if (x < menuXmin || x > menuXmax || y < menuYmin || y > menuYmax) + if (x < menuMin.X || x > menuMax.X || y < menuMin.Y || y > menuMax.Y) { return false; } @@ -391,7 +372,6 @@ internal bool ProcessMouseMove(int x, int y) return true; } } - return false; } @@ -432,7 +412,7 @@ internal void ProcessCommand(Translations.Command cmd, double timeElapsed) { return; } - SingleMenu menu = Menus[CurrMenu]; + MenuBase menu = Menus[CurrMenu]; // MenuBack is managed independently from single menu data if (cmd == Translations.Command.MenuBack) { @@ -550,19 +530,19 @@ internal void ProcessCommand(Translations.Command cmd, double timeElapsed) { // menu management commands case MenuTag.MenuBack: // BACK TO PREVIOUS MENU - Menu.instance.PopMenu(); + GameMenu.instance.PopMenu(); break; case MenuTag.MenuJumpToStation: // TO STATIONS MENU - Menu.instance.PushMenu(MenuType.JumpToStation); + GameMenu.instance.PushMenu(MenuType.JumpToStation); break; case MenuTag.MenuExitToMainMenu: // TO EXIT MENU - Menu.instance.PushMenu(MenuType.ExitToMainMenu); + GameMenu.instance.PushMenu(MenuType.ExitToMainMenu); break; case MenuTag.MenuQuit: // TO QUIT MENU - Menu.instance.PushMenu(MenuType.Quit); + GameMenu.instance.PushMenu(MenuType.Quit); break; case MenuTag.MenuControls: // TO CONTROLS MENU - Menu.instance.PushMenu(MenuType.Controls); + GameMenu.instance.PushMenu(MenuType.Controls); break; case MenuTag.BackToSim: // OUT OF MENU BACK TO SIMULATION Reset(); @@ -571,7 +551,7 @@ internal void ProcessCommand(Translations.Command cmd, double timeElapsed) case MenuTag.Packages: if (Database.LoadDatabase(Program.FileSystem.PackageDatabaseFolder, currentDatabaseFile, out _)) { - Menu.instance.PushMenu(MenuType.Packages); + GameMenu.instance.PushMenu(MenuType.Packages); } break; @@ -649,16 +629,16 @@ internal void ProcessCommand(Translations.Command cmd, double timeElapsed) } break; case MenuTag.Options: - Menu.instance.PushMenu(MenuType.Options); + GameMenu.instance.PushMenu(MenuType.Options); break; case MenuTag.RouteList: // TO ROUTE LIST MENU - Menu.instance.PushMenu(MenuType.RouteList); + GameMenu.instance.PushMenu(MenuType.RouteList); routeDescriptionBox.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"errors","route_please_select"}); Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\please_select.png"), new TextureParameters(null, null), out routePictureBox.Texture); break; case MenuTag.Directory: // SHOWS THE LIST OF FILES IN THE SELECTED DIR SearchDirectory = SearchDirectory == string.Empty ? menu.Items[menu.Selection].Text : Path.CombineDirectory(SearchDirectory, menu.Items[menu.Selection].Text); - Menu.instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + GameMenu.instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); break; case MenuTag.ParentDirectory: // SHOWS THE LIST OF FILES IN THE PARENT DIR if (string.IsNullOrEmpty(SearchDirectory)) @@ -677,7 +657,7 @@ internal void ProcessCommand(Translations.Command cmd, double timeElapsed) SearchDirectory = oldSearchDirectory; return; } - Menu.instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + GameMenu.instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); break; case MenuTag.RouteFile: RoutefileState = RouteState.Loading; @@ -697,7 +677,7 @@ internal void ProcessCommand(Translations.Command cmd, double timeElapsed) { //enter folder SearchDirectory = SearchDirectory == string.Empty ? menu.Items[menu.Selection].Text : Path.CombineDirectory(SearchDirectory, menu.Items[menu.Selection].Text); - Menu.instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + GameMenu.instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); } else { @@ -795,19 +775,19 @@ internal void ProcessCommand(Translations.Command cmd, double timeElapsed) menu.Items[2].Text = "Current Setting: " + Program.CurrentRoute.Switches[switchToToggle].CurrentlySetTrack; switchesFound = false; // as switch has been toggled, need to recalculate switches along route - Menu.instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + GameMenu.instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); break; case MenuTag.PreviousSwitch: FoundSwitch fs = previousSwitches[0]; previousSwitches.RemoveAt(0); nextSwitches.Insert(0, fs); - Menu.instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + GameMenu.instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); break; case MenuTag.NextSwitch: FoundSwitch ns = nextSwitches[0]; nextSwitches.RemoveAt(0); previousSwitches.Insert(0, ns); - Menu.instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + GameMenu.instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); break; } } @@ -851,7 +831,7 @@ internal void Draw(double RealTimeElapsed) if (CurrMenu < 0 || CurrMenu >= Menus.Length) return; - SingleMenu menu = Menus[CurrMenu]; + MenuBase menu = Menus[CurrMenu]; // overlay background Program.Renderer.Rectangle.Draw(null, Vector2.Null, new Vector2(Program.Renderer.Screen.Width, Program.Renderer.Screen.Height), overlayColor); @@ -861,14 +841,14 @@ internal void Draw(double RealTimeElapsed) { itemLeft = 0; itemX = 16; - Program.Renderer.Rectangle.Draw(null, new Vector2(0, menuYmin - MenuBorderY), new Vector2(menuXmax - menuXmin + 2.0f * MenuBorderX, menuYmax - menuYmin + 2.0f * MenuBorderY), backgroundColor); + Program.Renderer.Rectangle.Draw(null, new Vector2(0, menuMin.Y - MenuBorderY), new Vector2(menuMax.X - menuMin.X + 2.0f * MenuBorderX, menuMax.Y - menuMin.Y + 2.0f * MenuBorderY), backgroundColor); } else { itemLeft = (Program.Renderer.Screen.Width - menu.ItemWidth) / 2; // item left edge // if menu alignment is left, left-align items, otherwise centre them in the screen itemX = (menu.Align & TextAlignment.Left) != 0 ? itemLeft : Program.Renderer.Screen.Width / 2.0; - Program.Renderer.Rectangle.Draw(null, new Vector2(menuXmin - MenuBorderX, menuYmin - MenuBorderY), new Vector2(menuXmax - menuXmin + 2.0f * MenuBorderX, menuYmax - menuYmin + 2.0f * MenuBorderY), backgroundColor); + Program.Renderer.Rectangle.Draw(null, new Vector2(menuMin.X - MenuBorderX, menuMin.Y - MenuBorderY), new Vector2(menuMax.X - menuMin.X + 2.0f * MenuBorderX, menuMax.Y - menuMin.Y + 2.0f * MenuBorderY), backgroundColor); } // draw the menu background @@ -881,10 +861,10 @@ internal void Draw(double RealTimeElapsed) // if not starting from the top of the menu, draw a dimmed ellipsis item if (menu.Selection == menu.TopItem - 1 && !isCustomisingControl) { - Program.Renderer.Rectangle.Draw(null, new Vector2(itemLeft - MenuItemBorderX, menuYmin /*-MenuItemBorderY*/), new Vector2(menu.ItemWidth + MenuItemBorderX, em + MenuItemBorderY * 2), highlightColor); + Program.Renderer.Rectangle.Draw(null, new Vector2(itemLeft - MenuItemBorderX, menuMin.Y /*-MenuItemBorderY*/), new Vector2(menu.ItemWidth + MenuItemBorderX, em + MenuItemBorderY * 2), highlightColor); } if (menu.TopItem > 0) - Program.Renderer.OpenGlString.Draw(MenuFont, @"...", new Vector2(itemX, menuYmin), + Program.Renderer.OpenGlString.Draw(MenuFont, @"...", new Vector2(itemX, menuMin.Y), menu.Align, ColourDimmed, false); // draw the items double itemY = topItemY; @@ -945,7 +925,7 @@ internal void Draw(double RealTimeElapsed) menu.Align, ColourNormal, false); if (menu.Items[i] is MenuOption) { - Program.Renderer.OpenGlString.Draw(MenuFont, (menu.Items[i] as MenuOption).CurrentOption.ToString(), new Vector2((menuXmax - menuXmin + 2.0f * MenuBorderX) + 4.0f, itemY), + Program.Renderer.OpenGlString.Draw(MenuFont, (menu.Items[i] as MenuOption).CurrentOption.ToString(), new Vector2((menuMax.X - menuMin.X + 2.0f * MenuBorderX) + 4.0f, itemY), menu.Align, backgroundColor, false); } itemY += lineHeight; @@ -971,7 +951,7 @@ internal void Draw(double RealTimeElapsed) case MenuType.GameStart: case MenuType.Packages: LogoPictureBox.Draw(); - string currentVersion = @"v" + Application.ProductVersion + Program.VersionSuffix; + string currentVersion = @"v" + System.Windows.Forms.Application.ProductVersion + Program.VersionSuffix; if (IntPtr.Size != 4) { currentVersion += @" 64-bit"; @@ -1133,7 +1113,7 @@ private void PositionMenu() if (CurrMenu < 0 || CurrMenu >= Menus.Length) return; - SingleMenu menu = Menus[CurrMenu]; + MenuBase menu = Menus[CurrMenu]; for (int i = 0; i < menu.Items.Length; i++) { /* @@ -1151,25 +1131,25 @@ private void PositionMenu() { case TextAlignment.TopLeft: // Left aligned - menuXmin = 0; + menuMin.X = 0; break; default: // Centered in window - menuXmin = (Program.Renderer.Screen.Width - menu.Width) / 2; // menu left edge (border excluded) + menuMin.X = (Program.Renderer.Screen.Width - menu.Width) / 2; // menu left edge (border excluded) break; } - menuXmax = menuXmin + menu.Width; // menu right edge (border excluded) + menuMax.X = menuMin.X + menu.Width; // menu right edge (border excluded) // VERTICAL PLACEMENT: centre the menu in the main window - menuYmin = (Program.Renderer.Screen.Height - menu.Height) / 2; // menu top edge (border excluded) - menuYmax = menuYmin + menu.Height; // menu bottom edge (border excluded) - topItemY = menuYmin; // top edge of top item + menuMin.Y = (Program.Renderer.Screen.Height - menu.Height) / 2; // menu top edge (border excluded) + menuMax.Y = menuMin.Y + menu.Height; // menu bottom edge (border excluded) + topItemY = menuMin.Y; // top edge of top item // assume all items fit in the screen visibleItems = menu.Items.Length; // if there are more items than can fit in the screen height, // (there should be at least room for the menu top border) - if (menuYmin < MenuBorderY) + if (menuMin.Y < MenuBorderY) { // the number of lines which fit in the screen int numOfLines = (Program.Renderer.Screen.Height - MenuBorderY * 2) / lineHeight; @@ -1179,11 +1159,11 @@ private void PositionMenu() menu.TopItem = menu.Selection - (menu.Selection % visibleItems); visibleItems = menu.Items.Length - menu.TopItem < visibleItems ? // in the last chunk, menu.Items.Length - menu.TopItem : visibleItems; // display remaining items only - menuYmin = (Program.Renderer.Screen.Height - numOfLines * lineHeight) / 2.0; - menuYmax = menuYmin + numOfLines * lineHeight; + menuMin.Y = (Program.Renderer.Screen.Height - numOfLines * lineHeight) / 2.0; + menuMax.Y = menuMin.Y + numOfLines * lineHeight; // first menu item is drawn on second line (first line is empty // on first screen and contains an ellipsis on following screens - topItemY = menuYmin + lineHeight; + topItemY = menuMin.Y + lineHeight; } } diff --git a/source/OpenBVE/OpenBve.csproj b/source/OpenBVE/OpenBve.csproj index d465d544f..2403fea84 100644 --- a/source/OpenBVE/OpenBve.csproj +++ b/source/OpenBVE/OpenBve.csproj @@ -51,7 +51,7 @@ TRACE;DEBUG prompt 4 - 7.0 + 7.3 false @@ -66,7 +66,7 @@ true ..\..\bin_release\OpenBve.XML true - 7.0 + 7.3 false diff --git a/source/OpenBVE/System/GameWindow.cs b/source/OpenBVE/System/GameWindow.cs index 553d5e818..e6ec2c131 100644 --- a/source/OpenBVE/System/GameWindow.cs +++ b/source/OpenBVE/System/GameWindow.cs @@ -424,7 +424,7 @@ protected override void OnLoad(EventArgs e) MouseUp += MainLoop.mouseUpEvent; MouseMove += MainLoop.mouseMoveEvent; MouseWheel += MainLoop.mouseWheelEvent; - FileDrop += Menu.Instance.DragFile; + FileDrop += GameMenu.Instance.DragFile; for (int i = 0; i < InputDevicePlugin.AvailablePluginInfos.Count; i++) { From 093835167396af16d3eb9f5f9c041d31a69754c4 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Thu, 22 Aug 2024 15:48:07 +0100 Subject: [PATCH 11/41] Change: Move more bits of menu system to LibRender2, reworking --- source/LibRender2/Menu/AbstractMenu.cs | 123 ++++++++++++++++ source/LibRender2/Primitives/GLControl.cs | 2 + source/OpenBVE/Game/Menu/Menu.SingleMenu.cs | 2 +- source/OpenBVE/Game/Menu/Menu.cs | 149 ++++---------------- 4 files changed, 155 insertions(+), 121 deletions(-) diff --git a/source/LibRender2/Menu/AbstractMenu.cs b/source/LibRender2/Menu/AbstractMenu.cs index 724edd781..a4081306e 100644 --- a/source/LibRender2/Menu/AbstractMenu.cs +++ b/source/LibRender2/Menu/AbstractMenu.cs @@ -22,9 +22,13 @@ //(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS //SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +using LibRender2.Screens; using LibRender2.Text; using OpenBveApi.Colors; +using OpenBveApi.Graphics; using OpenBveApi.Math; +using System.Collections.Generic; +using LibRender2.Primitives; namespace LibRender2.Menu { @@ -72,5 +76,124 @@ public abstract class AbstractMenu /// The screen co-ordinates of the bottom-right of the menu public Vector2 menuMax; + + /// Holds a reference to the base renderer + private readonly BaseRenderer Renderer; + + /// The index of the current menu within the stack + public int CurrMenu = -1; + + /// The border for the menu in pixels + public static readonly Vector2 Border = new Vector2(16, 16); + + /// The border for each menu item in pixels + public static readonly Vector2 ItemBorder = new Vector2(8, 2); + + /// The height of the top item in the current menu in pixels + public double topItemY; + + /// The total height of one rendered menu item in pixels + public int lineHeight; + + /// The controls within the menu + public List menuControls = new List(); + + /// Creates a new menu instance + protected AbstractMenu(BaseRenderer renderer) + { + Renderer = renderer; + } + + /// Resets the menu system to it's initial condition + public virtual void Reset() + { + CurrMenu = -1; + Menus = new MenuBase[] { }; + } + + /// Pushes a menu into the menu stack + /// The type of menu to push + /// The index of the menu in the menu stack (If pushing an existing higher level menu) + /// Whether we are replacing the selected menu item + public abstract void PushMenu(MenuType type, int data = 0, bool replace = false); + + /// Pops the previous menu in the menu stack + public void PopMenu() + { + if (CurrMenu > 0) // if more than one menu remaining... + { + CurrMenu--; // ...back to previous menu + ComputePosition(); + } + else + { // if only one menu remaining... + Reset(); + Renderer.CurrentInterface = InterfaceType.Normal; // return to simulation + } + } + + + + /// Computes the position in the screen of the current menu. + /// Also sets the menu size + public void ComputePosition() + { + if (CurrMenu < 0 || CurrMenu >= Menus.Length) + return; + + MenuBase menu = Menus[CurrMenu]; + for (int i = 0; i < menu.Items.Length; i++) + { + /* + * HACK: This is a property method, and is also used to + * reset the timer and display string back to the starting values + */ + if (menu.Items[i] != null) + { + menu.Items[i].DisplayLength = menu.Items[i].DisplayLength; + } + } + + // HORIZONTAL PLACEMENT + switch (menu.Align) + { + case TextAlignment.TopLeft: + // Left aligned + menuMin.X = 0; + break; + default: + // Centered in window + menuMin.X = (Renderer.Screen.Width - menu.Width) / 2; // menu left edge (border excluded) + break; + } + + menuMax.X = menuMin.X + menu.Width; // menu right edge (border excluded) + // VERTICAL PLACEMENT: centre the menu in the main window + menuMin.Y = (Renderer.Screen.Height - menu.Height) / 2; // menu top edge (border excluded) + menuMax.Y = menuMin.Y + menu.Height; // menu bottom edge (border excluded) + topItemY = menuMin.Y; // top edge of top item + // assume all items fit in the screen + visibleItems = menu.Items.Length; + + // if there are more items than can fit in the screen height, + // (there should be at least room for the menu top border) + if (menuMin.Y < Border.Y) + { + // the number of lines which fit in the screen + int numOfLines = (int)(Renderer.Screen.Height - Border.Y * 2) / lineHeight; + visibleItems = numOfLines - 2; // at least an empty line at the top and at the bottom + // split the menu in chunks of 'visibleItems' items + // and display the chunk which contains the currently selected item + menu.TopItem = menu.Selection - (menu.Selection % visibleItems); + visibleItems = menu.Items.Length - menu.TopItem < visibleItems ? // in the last chunk, + menu.Items.Length - menu.TopItem : visibleItems; // display remaining items only + menuMin.Y = (Renderer.Screen.Height - numOfLines * lineHeight) / 2.0; + menuMax.Y = menuMin.Y + numOfLines * lineHeight; + // first menu item is drawn on second line (first line is empty + // on first screen and contains an ellipsis on following screens + topItemY = menuMin.Y + lineHeight; + } + } + } } diff --git a/source/LibRender2/Primitives/GLControl.cs b/source/LibRender2/Primitives/GLControl.cs index a9add2b25..43ff49f02 100644 --- a/source/LibRender2/Primitives/GLControl.cs +++ b/source/LibRender2/Primitives/GLControl.cs @@ -46,6 +46,8 @@ public abstract class GLControl public bool CurrentlySelected; /// The event handler for the OnClick event public EventHandler OnClick; + /// Whether the control is currently visible + public bool IsVisible; protected GLControl(BaseRenderer renderer) { diff --git a/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs b/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs index 6fb4c9fe8..5a68ca8bf 100644 --- a/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs +++ b/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs @@ -562,7 +562,7 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m if (!(Items[i] is MenuCaption && menuType!= MenuType.RouteList && menuType != MenuType.GameStart && menuType != MenuType.Packages) && size.X > ItemWidth) ItemWidth = size.X; } - Height = Items.Length * Game.Menu.LineHeight; + Height = Items.Length * Game.Menu.lineHeight; TopItem = 0; } } diff --git a/source/OpenBVE/Game/Menu/Menu.cs b/source/OpenBVE/Game/Menu/Menu.cs index efcb7d13a..c64119d5c 100644 --- a/source/OpenBVE/Game/Menu/Menu.cs +++ b/source/OpenBVE/Game/Menu/Menu.cs @@ -38,10 +38,6 @@ public sealed partial class GameMenu : AbstractMenu internal static List previousSwitches = new List(); internal static bool switchesFound = false; - private const int MenuBorderX = 16; - private const int MenuBorderY = 16; - private const int MenuItemBorderX = 8; - private const int MenuItemBorderY = 2; private const float LineSpacing = 1.75f; // the ratio between the font size and line distance private const int SelectionNone = -1; @@ -51,17 +47,11 @@ public sealed partial class GameMenu : AbstractMenu /******************** MENU SYSTEM FIELDS *********************/ - private int CurrMenu = -1; + private int CustomControlIdx; // the index of the control being customized private int em; // the size of menu font (in pixels) private bool isCustomisingControl = false; private bool isInitialized = false; - // the total line height from the top of an item to the top of the item below (in pixels) - private int lineHeight; - - private double topItemY; // the top edge of top item - - internal int LineHeight => lineHeight; internal OpenGlFont MenuFont => menuFont; @@ -75,7 +65,7 @@ MENU SYSTEM SINGLETON C'TOR static GameMenu() { } - private GameMenu() + private GameMenu() : base(Program.Renderer) { } @@ -150,28 +140,32 @@ private void Init() controlTextBox.Size = new Vector2(quarterWidth, quarterWidth); controlTextBox.BackgroundColor = Color128.Black; isInitialized = true; + + // add controls to list so we can itinerate them on mouse calls etc. + menuControls.Add(routePictureBox); + menuControls.Add(controlPictureBox); + menuControls.Add(switchMainPictureBox); + menuControls.Add(switchSettingPictureBox); + menuControls.Add(switchMapPictureBox); + menuControls.Add(LogoPictureBox); + menuControls.Add(controlTextBox); + menuControls.Add(routeDescriptionBox); } - // - // RESET MENU SYSTEM TO INITIAL CONDITIONS - // - private void Reset() + public override void Reset() { CurrMenu = -1; - Menus = new SingleMenu[] { }; + Menus = new MenuBase[] { }; isCustomisingControl = false; routeDescriptionBox.CurrentlySelected = false; } - // - // PUSH ANOTHER MENU - // /// Pushes a menu into the menu stack /// The type of menu to push /// The index of the menu in the menu stack (If pushing an existing higher level menu) /// Whether we are replacing the selected menu item - public void PushMenu(MenuType type, int data = 0, bool replace = false) + public override void PushMenu(MenuType type, int data = 0, bool replace = false) { if (Program.Renderer.CurrentInterface < InterfaceType.Menu) { @@ -197,32 +191,12 @@ public void PushMenu(MenuType type, int data = 0, bool replace = false) { Menus[CurrMenu].Selection = 1; } - PositionMenu(); + ComputePosition(); Program.Renderer.CurrentInterface = TrainManager.PlayerTrain == null ? InterfaceType.GLMainMenu : InterfaceType.Menu; } - - // - // POP LAST MENU - // - /// Pops the previous menu in the menu stack - public void PopMenu() - { - if (CurrMenu > 0) // if more than one menu remaining... - { - CurrMenu--; // ...back to previous menu - PositionMenu(); - } - else - { // if only one menu remaining... - Reset(); - Program.Renderer.CurrentInterface = InterfaceType.Normal; // return to simulation - } - } - - // - // IS CUSTOMIZING CONTROL? - // + + /// Whether we are currently customising a control (Used for key/ joystick capture) /// True if currently capturing a control, false otherwise public bool IsCustomizingControl() @@ -511,14 +485,14 @@ internal void ProcessCommand(Translations.Command cmd, double timeElapsed) !(menu.Items[menu.Selection - 1] is MenuCaption)) { menu.Selection--; - PositionMenu(); + ComputePosition(); } break; case Translations.Command.MenuDown: // DOWN if (menu.Selection < menu.Items.Length - 1) { menu.Selection++; - PositionMenu(); + ComputePosition(); } break; // case Translations.Command.MenuBack: // ESC: managed above @@ -841,14 +815,14 @@ internal void Draw(double RealTimeElapsed) { itemLeft = 0; itemX = 16; - Program.Renderer.Rectangle.Draw(null, new Vector2(0, menuMin.Y - MenuBorderY), new Vector2(menuMax.X - menuMin.X + 2.0f * MenuBorderX, menuMax.Y - menuMin.Y + 2.0f * MenuBorderY), backgroundColor); + Program.Renderer.Rectangle.Draw(null, new Vector2(0, menuMin.Y - Border.Y), new Vector2(menuMax.X - menuMin.X + 2.0f * Border.X, menuMax.Y - menuMin.Y + 2.0f * Border.Y), backgroundColor); } else { itemLeft = (Program.Renderer.Screen.Width - menu.ItemWidth) / 2; // item left edge // if menu alignment is left, left-align items, otherwise centre them in the screen itemX = (menu.Align & TextAlignment.Left) != 0 ? itemLeft : Program.Renderer.Screen.Width / 2.0; - Program.Renderer.Rectangle.Draw(null, new Vector2(menuMin.X - MenuBorderX, menuMin.Y - MenuBorderY), new Vector2(menuMax.X - menuMin.X + 2.0f * MenuBorderX, menuMax.Y - menuMin.Y + 2.0f * MenuBorderY), backgroundColor); + Program.Renderer.Rectangle.Draw(null, new Vector2(menuMin.X - Border.X, menuMin.Y - Border.Y), new Vector2(menuMax.X - menuMin.X + 2.0f * Border.X, menuMax.Y - menuMin.Y + 2.0f * Border.Y), backgroundColor); } // draw the menu background @@ -861,7 +835,7 @@ internal void Draw(double RealTimeElapsed) // if not starting from the top of the menu, draw a dimmed ellipsis item if (menu.Selection == menu.TopItem - 1 && !isCustomisingControl) { - Program.Renderer.Rectangle.Draw(null, new Vector2(itemLeft - MenuItemBorderX, menuMin.Y /*-MenuItemBorderY*/), new Vector2(menu.ItemWidth + MenuItemBorderX, em + MenuItemBorderY * 2), highlightColor); + Program.Renderer.Rectangle.Draw(null, new Vector2(itemLeft - ItemBorder.X, menuMin.Y /*-ItemBorder.Y*/), new Vector2(menu.ItemWidth + ItemBorder.X, em + ItemBorder.Y * 2), highlightColor); } if (menu.TopItem > 0) Program.Renderer.OpenGlString.Draw(MenuFont, @"...", new Vector2(itemX, menuMin.Y), @@ -906,11 +880,11 @@ internal void Draw(double RealTimeElapsed) if (itemLeft == 0) { - Program.Renderer.Rectangle.Draw(null, new Vector2(MenuItemBorderX, itemY /*-MenuItemBorderY*/), new Vector2(menu.Width + 2.0f * MenuItemBorderX, em + MenuItemBorderY * 2), color); + Program.Renderer.Rectangle.Draw(null, new Vector2(ItemBorder.X, itemY /*-ItemBorder.Y*/), new Vector2(menu.Width + 2.0f * ItemBorder.X, em + ItemBorder.Y * 2), color); } else { - Program.Renderer.Rectangle.Draw(null, new Vector2(itemLeft - MenuItemBorderX, itemY /*-MenuItemBorderY*/), new Vector2(menu.ItemWidth + 2.0f * MenuItemBorderX, em + MenuItemBorderY * 2), color); + Program.Renderer.Rectangle.Draw(null, new Vector2(itemLeft - ItemBorder.X, itemY /*-ItemBorder.Y*/), new Vector2(menu.ItemWidth + 2.0f * ItemBorder.X, em + ItemBorder.Y * 2), color); } // draw the text @@ -925,7 +899,7 @@ internal void Draw(double RealTimeElapsed) menu.Align, ColourNormal, false); if (menu.Items[i] is MenuOption) { - Program.Renderer.OpenGlString.Draw(MenuFont, (menu.Items[i] as MenuOption).CurrentOption.ToString(), new Vector2((menuMax.X - menuMin.X + 2.0f * MenuBorderX) + 4.0f, itemY), + Program.Renderer.OpenGlString.Draw(MenuFont, (menu.Items[i] as MenuOption).CurrentOption.ToString(), new Vector2((menuMax.X - menuMin.X + 2.0f * Border.X) + 4.0f, itemY), menu.Align, backgroundColor, false); } itemY += lineHeight; @@ -940,7 +914,7 @@ internal void Draw(double RealTimeElapsed) if (menu.Selection == menu.TopItem + visibleItems) { - Program.Renderer.Rectangle.Draw(null, new Vector2(itemLeft - MenuItemBorderX, itemY /*-MenuItemBorderY*/), new Vector2(menu.ItemWidth + 2.0f * MenuItemBorderX, em + MenuItemBorderY * 2), highlightColor); + Program.Renderer.Rectangle.Draw(null, new Vector2(itemLeft - ItemBorder.X, itemY /*-ItemBorder.Y*/), new Vector2(menu.ItemWidth + 2.0f * ItemBorder.X, em + ItemBorder.Y * 2), highlightColor); } // if not at the end of the menu, draw a dimmed ellipsis item at the bottom if (i < menu.Items.Length - 1) @@ -1093,8 +1067,8 @@ internal void Draw(double RealTimeElapsed) /* * Set final image locs, which we don't know till the menu extent has been measured in the render sequence */ - switchMainPictureBox.Location = new Vector2(menu.Width + (MenuItemBorderX * 4), switchMainPictureBox.Location.Y); - switchSettingPictureBox.Location = new Vector2(menu.Width + (MenuItemBorderX * 4) + 80, switchSettingPictureBox.Location.Y); + switchMainPictureBox.Location = new Vector2(menu.Width + (ItemBorder.X * 4), switchMainPictureBox.Location.Y); + switchSettingPictureBox.Location = new Vector2(menu.Width + (ItemBorder.X * 4) + 80, switchSettingPictureBox.Location.Y); switchMainPictureBox.Draw(); switchSettingPictureBox.Draw(); switchMapPictureBox.Draw(); @@ -1102,71 +1076,6 @@ internal void Draw(double RealTimeElapsed) } } - - // - // POSITION MENU - // - /// Computes the position in the screen of the current menu. - /// Also sets the menu size - private void PositionMenu() - { - if (CurrMenu < 0 || CurrMenu >= Menus.Length) - return; - - MenuBase menu = Menus[CurrMenu]; - for (int i = 0; i < menu.Items.Length; i++) - { - /* - * HACK: This is a property method, and is also used to - * reset the timer and display string back to the starting values - */ - if (menu.Items[i] != null) - { - menu.Items[i].DisplayLength = menu.Items[i].DisplayLength; - } - } - - // HORIZONTAL PLACEMENT - switch (menu.Align) - { - case TextAlignment.TopLeft: - // Left aligned - menuMin.X = 0; - break; - default: - // Centered in window - menuMin.X = (Program.Renderer.Screen.Width - menu.Width) / 2; // menu left edge (border excluded) - break; - } - - menuMax.X = menuMin.X + menu.Width; // menu right edge (border excluded) - // VERTICAL PLACEMENT: centre the menu in the main window - menuMin.Y = (Program.Renderer.Screen.Height - menu.Height) / 2; // menu top edge (border excluded) - menuMax.Y = menuMin.Y + menu.Height; // menu bottom edge (border excluded) - topItemY = menuMin.Y; // top edge of top item - // assume all items fit in the screen - visibleItems = menu.Items.Length; - - // if there are more items than can fit in the screen height, - // (there should be at least room for the menu top border) - if (menuMin.Y < MenuBorderY) - { - // the number of lines which fit in the screen - int numOfLines = (Program.Renderer.Screen.Height - MenuBorderY * 2) / lineHeight; - visibleItems = numOfLines - 2; // at least an empty line at the top and at the bottom - // split the menu in chunks of 'visibleItems' items - // and display the chunk which contains the currently selected item - menu.TopItem = menu.Selection - (menu.Selection % visibleItems); - visibleItems = menu.Items.Length - menu.TopItem < visibleItems ? // in the last chunk, - menu.Items.Length - menu.TopItem : visibleItems; // display remaining items only - menuMin.Y = (Program.Renderer.Screen.Height - numOfLines * lineHeight) / 2.0; - menuMax.Y = menuMin.Y + numOfLines * lineHeight; - // first menu item is drawn on second line (first line is empty - // on first screen and contains an ellipsis on following screens - topItemY = menuMin.Y + lineHeight; - } - } - } } From 08c3d5b0d97cde51165a5951ad53a810fe81a0a4 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Fri, 23 Aug 2024 12:08:34 +0100 Subject: [PATCH 12/41] Change: Move more bits to shared menu --- source/LibRender2/Menu/AbstractMenu.cs | 56 +++++++++++++++++++++ source/LibRender2/Menu/MenuBase.cs | 21 ++++++++ source/OpenBVE/Game/Menu/Menu.cs | 67 +++----------------------- 3 files changed, 85 insertions(+), 59 deletions(-) diff --git a/source/LibRender2/Menu/AbstractMenu.cs b/source/LibRender2/Menu/AbstractMenu.cs index a4081306e..3e268a715 100644 --- a/source/LibRender2/Menu/AbstractMenu.cs +++ b/source/LibRender2/Menu/AbstractMenu.cs @@ -29,6 +29,8 @@ using OpenBveApi.Math; using System.Collections.Generic; using LibRender2.Primitives; +using System; +using OpenBveApi.Interface; namespace LibRender2.Menu { @@ -132,6 +134,60 @@ public void PopMenu() } } + /// Processes a scroll wheel event + /// The delta + public virtual void ProcessMouseScroll(int Scroll) + { + if (Menus.Length == 0) + { + return; + } + // Load the current menu + Menus[CurrMenu].ProcessScroll(Scroll, visibleItems); + } + + /// Processes a mouse move event + /// The screen-relative x coordinate of the move event + /// The screen-relative y coordinate of the move event + public virtual bool ProcessMouseMove(int x, int y) + { + return true; + } + + /// Processes a mouse down event + /// The screen-relative x coordinate of the down event + /// The screen-relative y coordinate of the down event + public void ProcessMouseDown(int x, int y) + { + if (ProcessMouseMove(x, y)) + { + if (Menus[CurrMenu].Selection == Menus[CurrMenu].TopItem + visibleItems) + { + ProcessCommand(Translations.Command.MenuDown, 0); + return; + } + if (Menus[CurrMenu].Selection == Menus[CurrMenu].TopItem - 1) + { + ProcessCommand(Translations.Command.MenuUp, 0); + return; + } + ProcessCommand(Translations.Command.MenuEnter, 0); + } + } + + /// Processes a user command for the current menu + /// The command to apply to the current menu + /// The time elapsed since previous frame + public virtual void ProcessCommand(Translations.Command cmd, double timeElapsed) + { + + } + + /// Processes a file drop event + public virtual void DragFile(object sender, OpenTK.Input.FileDropEventArgs e) + { + + } /// Computes the position in the screen of the current menu. diff --git a/source/LibRender2/Menu/MenuBase.cs b/source/LibRender2/Menu/MenuBase.cs index 41d4db2a2..f7dbe4607 100644 --- a/source/LibRender2/Menu/MenuBase.cs +++ b/source/LibRender2/Menu/MenuBase.cs @@ -23,6 +23,7 @@ //SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. using OpenBveApi.Graphics; +using System; namespace LibRender2.Menu { @@ -66,6 +67,26 @@ public virtual int Selection } } + public void ProcessScroll(int Scroll, int VisibleItems) + { + if (Math.Abs(Scroll) == Scroll) + { + //Negative + if (TopItem > 0) + { + TopItem--; + } + } + else + { + //Positive + if (Items.Length - TopItem > VisibleItems) + { + TopItem++; + } + } + } + public MenuBase(MenuType type) { Type = type; diff --git a/source/OpenBVE/Game/Menu/Menu.cs b/source/OpenBVE/Game/Menu/Menu.cs index c64119d5c..1cc6df9e4 100644 --- a/source/OpenBVE/Game/Menu/Menu.cs +++ b/source/OpenBVE/Game/Menu/Menu.cs @@ -236,14 +236,9 @@ internal void SetControlJoyCustomData(Guid device, JoystickComponent component, } } - - // - // PROCESS MOUSE EVENTS - // - /// Processes a scroll wheel event /// The delta - internal void ProcessMouseScroll(int Scroll) + public override void ProcessMouseScroll(int Scroll) { if (Menus.Length == 0) { @@ -266,26 +261,10 @@ internal void ProcessMouseScroll(int Scroll) return; } } - if (Math.Abs(Scroll) == Scroll) - { - //Negative - if (menu.TopItem > 0) - { - menu.TopItem--; - } - } - else - { - //Positive - if (menu.Items.Length - menu.TopItem > visibleItems) - { - menu.TopItem++; - } - } + base.ProcessMouseScroll(Scroll); } - - internal void DragFile(object sender, OpenTK.Input.FileDropEventArgs e) + public override void DragFile(object sender, OpenTK.Input.FileDropEventArgs e) { if (Menus[CurrMenu].Type == MenuType.PackageInstall) { @@ -297,10 +276,7 @@ internal void DragFile(object sender, OpenTK.Input.FileDropEventArgs e) } } - /// Processes a mouse move event - /// The screen-relative x coordinate of the move event - /// The screen-relative y coordinate of the move event - internal bool ProcessMouseMove(int x, int y) + public override bool ProcessMouseMove(int x, int y) { Program.currentGameWindow.CursorVisible = true; if (CurrMenu < 0) @@ -348,38 +324,11 @@ internal bool ProcessMouseMove(int x, int y) } return false; } - - // - // PROCESS MOUSE DOWN EVENTS - // - /// Processes a mouse down event - /// The screen-relative x coordinate of the down event - /// The screen-relative y coordinate of the down event - internal void ProcessMouseDown(int x, int y) - { - if (ProcessMouseMove(x, y)) - { - if (Menus[CurrMenu].Selection == Menus[CurrMenu].TopItem + visibleItems) - { - ProcessCommand(Translations.Command.MenuDown, 0); - return; - } - if (Menus[CurrMenu].Selection == Menus[CurrMenu].TopItem - 1) - { - ProcessCommand(Translations.Command.MenuUp, 0); - return; - } - ProcessCommand(Translations.Command.MenuEnter, 0); - } - } - - // - // PROCESS MENU COMMAND - // + /// Processes a user command for the current menu /// The command to apply to the current menu /// The time elapsed since previous frame - internal void ProcessCommand(Translations.Command cmd, double timeElapsed) + public override void ProcessCommand(Translations.Command cmd, double timeElapsed) { if (CurrMenu < 0) @@ -897,9 +846,9 @@ internal void Draw(double RealTimeElapsed) else Program.Renderer.OpenGlString.Draw(MenuFont, menu.Items[i].DisplayText(TimeElapsed), new Vector2(itemX, itemY), menu.Align, ColourNormal, false); - if (menu.Items[i] is MenuOption) + if (menu.Items[i] is MenuOption opt) { - Program.Renderer.OpenGlString.Draw(MenuFont, (menu.Items[i] as MenuOption).CurrentOption.ToString(), new Vector2((menuMax.X - menuMin.X + 2.0f * Border.X) + 4.0f, itemY), + Program.Renderer.OpenGlString.Draw(MenuFont, opt.CurrentOption.ToString(), new Vector2((menuMax.X - menuMin.X + 2.0f * Border.X) + 4.0f, itemY), menu.Align, backgroundColor, false); } itemY += lineHeight; From bb105b129b551ef9b6610156082615d1056bdace Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Sun, 25 Aug 2024 18:37:57 +0100 Subject: [PATCH 13/41] Remove pointless accessor fields --- source/LibRender2/Menu/AbstractMenu.cs | 5 +- source/OpenBVE/Game/Menu/Menu.cs | 69 ++++++++++++-------------- 2 files changed, 36 insertions(+), 38 deletions(-) diff --git a/source/LibRender2/Menu/AbstractMenu.cs b/source/LibRender2/Menu/AbstractMenu.cs index 3e268a715..86d9636b9 100644 --- a/source/LibRender2/Menu/AbstractMenu.cs +++ b/source/LibRender2/Menu/AbstractMenu.cs @@ -68,7 +68,10 @@ public abstract class AbstractMenu public MenuBase[] Menus = { }; /// The font currently used for drawing menu items - public OpenGlFont menuFont = null; + public OpenGlFont MenuFont = null; + + /// The ratio between the menu font size and the line spacing + public const float LineSpacing = 1.75f; /// The number of visible items in the menu public int visibleItems; diff --git a/source/OpenBVE/Game/Menu/Menu.cs b/source/OpenBVE/Game/Menu/Menu.cs index 1cc6df9e4..0e57da409 100644 --- a/source/OpenBVE/Game/Menu/Menu.cs +++ b/source/OpenBVE/Game/Menu/Menu.cs @@ -38,7 +38,6 @@ public sealed partial class GameMenu : AbstractMenu internal static List previousSwitches = new List(); internal static bool switchesFound = false; - private const float LineSpacing = 1.75f; // the ratio between the font size and line distance private const int SelectionNone = -1; private double lastTimeElapsed; @@ -49,18 +48,15 @@ MENU SYSTEM FIELDS *********************/ private int CustomControlIdx; // the index of the control being customized - private int em; // the size of menu font (in pixels) private bool isCustomisingControl = false; private bool isInitialized = false; - internal OpenGlFont MenuFont => menuFont; - internal Key MenuBackKey; /******************** MENU SYSTEM SINGLETON C'TOR *********************/ - private static readonly GameMenu instance = new GameMenu(); + // Explicit static constructor to tell C# compiler not to mark type as beforefieldinit static GameMenu() { @@ -70,7 +66,7 @@ private GameMenu() : base(Program.Renderer) } /// Returns the current menu instance (If applicable) - public static GameMenu Instance => instance; + public static readonly GameMenu Instance = new GameMenu(); /******************** MENU SYSTEM METHODS @@ -84,20 +80,19 @@ private void Init() // choose the text font size according to screen height // the boundaries follow approximately the progression // of font sizes defined in Graphics/Fonts.cs - if (Program.Renderer.Screen.Height <= 512) menuFont = Program.Renderer.Fonts.SmallFont; - else if (Program.Renderer.Screen.Height <= 680) menuFont = Program.Renderer.Fonts.NormalFont; - else if (Program.Renderer.Screen.Height <= 890) menuFont = Program.Renderer.Fonts.LargeFont; - else if (Program.Renderer.Screen.Height <= 1150) menuFont = Program.Renderer.Fonts.VeryLargeFont; - else menuFont = Program.Renderer.Fonts.EvenLargerFont; + if (Program.Renderer.Screen.Height <= 512) MenuFont = Program.Renderer.Fonts.SmallFont; + else if (Program.Renderer.Screen.Height <= 680) MenuFont = Program.Renderer.Fonts.NormalFont; + else if (Program.Renderer.Screen.Height <= 890) MenuFont = Program.Renderer.Fonts.LargeFont; + else if (Program.Renderer.Screen.Height <= 1150) MenuFont = Program.Renderer.Fonts.VeryLargeFont; + else MenuFont = Program.Renderer.Fonts.EvenLargerFont; if (Interface.CurrentOptions.UserInterfaceFolder == "Large") { // If using the large HUD option, increase the text size in the menu too - menuFont = Program.Renderer.Fonts.NextLargestFont(menuFont); + MenuFont = Program.Renderer.Fonts.NextLargestFont(MenuFont); } - em = (int)menuFont.FontSize; - lineHeight = (int)(em * LineSpacing); + lineHeight = (int)(MenuFont.FontSize * LineSpacing); for (int i = 0; i < Interface.CurrentControls.Length; i++) { //Find the current menu back key- It's unlikely that we want to set a new key to this @@ -453,19 +448,19 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed { // menu management commands case MenuTag.MenuBack: // BACK TO PREVIOUS MENU - GameMenu.instance.PopMenu(); + GameMenu.Instance.PopMenu(); break; case MenuTag.MenuJumpToStation: // TO STATIONS MENU - GameMenu.instance.PushMenu(MenuType.JumpToStation); + GameMenu.Instance.PushMenu(MenuType.JumpToStation); break; case MenuTag.MenuExitToMainMenu: // TO EXIT MENU - GameMenu.instance.PushMenu(MenuType.ExitToMainMenu); + GameMenu.Instance.PushMenu(MenuType.ExitToMainMenu); break; case MenuTag.MenuQuit: // TO QUIT MENU - GameMenu.instance.PushMenu(MenuType.Quit); + GameMenu.Instance.PushMenu(MenuType.Quit); break; case MenuTag.MenuControls: // TO CONTROLS MENU - GameMenu.instance.PushMenu(MenuType.Controls); + GameMenu.Instance.PushMenu(MenuType.Controls); break; case MenuTag.BackToSim: // OUT OF MENU BACK TO SIMULATION Reset(); @@ -474,7 +469,7 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed case MenuTag.Packages: if (Database.LoadDatabase(Program.FileSystem.PackageDatabaseFolder, currentDatabaseFile, out _)) { - GameMenu.instance.PushMenu(MenuType.Packages); + GameMenu.Instance.PushMenu(MenuType.Packages); } break; @@ -482,20 +477,20 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed case MenuTag.PackageInstall: currentOperation = PackageOperation.Installing; packagePreview = true; - instance.PushMenu(MenuType.PackageInstall); + Instance.PushMenu(MenuType.PackageInstall); routeDescriptionBox.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","selection_none"}); Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\package.png"), new TextureParameters(null, null), out routePictureBox.Texture); break; case MenuTag.PackageUninstall: currentOperation = PackageOperation.Uninstalling; - instance.PushMenu(MenuType.PackageUninstall); + Instance.PushMenu(MenuType.PackageUninstall); break; case MenuTag.UninstallRoute: if (Database.currentDatabase.InstalledRoutes.Count == 0) { return; } - instance.PushMenu(MenuType.UninstallRoute); + Instance.PushMenu(MenuType.UninstallRoute); routeDescriptionBox.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","selection_none"}); Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\please_select.png"), new TextureParameters(null, null), out routePictureBox.Texture); break; @@ -504,7 +499,7 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed { return; } - instance.PushMenu(MenuType.UninstallTrain); + Instance.PushMenu(MenuType.UninstallTrain); routeDescriptionBox.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","selection_none"}); Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\please_select.png"), new TextureParameters(null, null), out routePictureBox.Texture); break; @@ -513,7 +508,7 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed { return; } - instance.PushMenu(MenuType.UninstallOther); + Instance.PushMenu(MenuType.UninstallOther); routeDescriptionBox.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","selection_none"}); Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\please_select.png"), new TextureParameters(null, null), out routePictureBox.Texture); break; @@ -552,16 +547,16 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed } break; case MenuTag.Options: - GameMenu.instance.PushMenu(MenuType.Options); + GameMenu.Instance.PushMenu(MenuType.Options); break; case MenuTag.RouteList: // TO ROUTE LIST MENU - GameMenu.instance.PushMenu(MenuType.RouteList); + GameMenu.Instance.PushMenu(MenuType.RouteList); routeDescriptionBox.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"errors","route_please_select"}); Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\please_select.png"), new TextureParameters(null, null), out routePictureBox.Texture); break; case MenuTag.Directory: // SHOWS THE LIST OF FILES IN THE SELECTED DIR SearchDirectory = SearchDirectory == string.Empty ? menu.Items[menu.Selection].Text : Path.CombineDirectory(SearchDirectory, menu.Items[menu.Selection].Text); - GameMenu.instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + GameMenu.Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); break; case MenuTag.ParentDirectory: // SHOWS THE LIST OF FILES IN THE PARENT DIR if (string.IsNullOrEmpty(SearchDirectory)) @@ -580,7 +575,7 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed SearchDirectory = oldSearchDirectory; return; } - GameMenu.instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + GameMenu.Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); break; case MenuTag.RouteFile: RoutefileState = RouteState.Loading; @@ -600,7 +595,7 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed { //enter folder SearchDirectory = SearchDirectory == string.Empty ? menu.Items[menu.Selection].Text : Path.CombineDirectory(SearchDirectory, menu.Items[menu.Selection].Text); - GameMenu.instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + GameMenu.Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); } else { @@ -698,19 +693,19 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed menu.Items[2].Text = "Current Setting: " + Program.CurrentRoute.Switches[switchToToggle].CurrentlySetTrack; switchesFound = false; // as switch has been toggled, need to recalculate switches along route - GameMenu.instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + GameMenu.Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); break; case MenuTag.PreviousSwitch: FoundSwitch fs = previousSwitches[0]; previousSwitches.RemoveAt(0); nextSwitches.Insert(0, fs); - GameMenu.instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + GameMenu.Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); break; case MenuTag.NextSwitch: FoundSwitch ns = nextSwitches[0]; nextSwitches.RemoveAt(0); previousSwitches.Insert(0, ns); - GameMenu.instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + GameMenu.Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); break; } } @@ -784,7 +779,7 @@ internal void Draw(double RealTimeElapsed) // if not starting from the top of the menu, draw a dimmed ellipsis item if (menu.Selection == menu.TopItem - 1 && !isCustomisingControl) { - Program.Renderer.Rectangle.Draw(null, new Vector2(itemLeft - ItemBorder.X, menuMin.Y /*-ItemBorder.Y*/), new Vector2(menu.ItemWidth + ItemBorder.X, em + ItemBorder.Y * 2), highlightColor); + Program.Renderer.Rectangle.Draw(null, new Vector2(itemLeft - ItemBorder.X, menuMin.Y /*-ItemBorder.Y*/), new Vector2(menu.ItemWidth + ItemBorder.X, MenuFont.FontSize + ItemBorder.Y * 2), highlightColor); } if (menu.TopItem > 0) Program.Renderer.OpenGlString.Draw(MenuFont, @"...", new Vector2(itemX, menuMin.Y), @@ -829,11 +824,11 @@ internal void Draw(double RealTimeElapsed) if (itemLeft == 0) { - Program.Renderer.Rectangle.Draw(null, new Vector2(ItemBorder.X, itemY /*-ItemBorder.Y*/), new Vector2(menu.Width + 2.0f * ItemBorder.X, em + ItemBorder.Y * 2), color); + Program.Renderer.Rectangle.Draw(null, new Vector2(ItemBorder.X, itemY /*-ItemBorder.Y*/), new Vector2(menu.Width + 2.0f * ItemBorder.X, MenuFont.FontSize + ItemBorder.Y * 2), color); } else { - Program.Renderer.Rectangle.Draw(null, new Vector2(itemLeft - ItemBorder.X, itemY /*-ItemBorder.Y*/), new Vector2(menu.ItemWidth + 2.0f * ItemBorder.X, em + ItemBorder.Y * 2), color); + Program.Renderer.Rectangle.Draw(null, new Vector2(itemLeft - ItemBorder.X, itemY /*-ItemBorder.Y*/), new Vector2(menu.ItemWidth + 2.0f * ItemBorder.X, MenuFont.FontSize + ItemBorder.Y * 2), color); } // draw the text @@ -863,7 +858,7 @@ internal void Draw(double RealTimeElapsed) if (menu.Selection == menu.TopItem + visibleItems) { - Program.Renderer.Rectangle.Draw(null, new Vector2(itemLeft - ItemBorder.X, itemY /*-ItemBorder.Y*/), new Vector2(menu.ItemWidth + 2.0f * ItemBorder.X, em + ItemBorder.Y * 2), highlightColor); + Program.Renderer.Rectangle.Draw(null, new Vector2(itemLeft - ItemBorder.X, itemY /*-ItemBorder.Y*/), new Vector2(menu.ItemWidth + 2.0f * ItemBorder.X, MenuFont.FontSize + ItemBorder.Y * 2), highlightColor); } // if not at the end of the menu, draw a dimmed ellipsis item at the bottom if (i < menu.Items.Length - 1) From 14c4a91fa8246ec7d25cbb67589548ccab7e21d6 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Sun, 25 Aug 2024 19:02:22 +0100 Subject: [PATCH 14/41] Initial implementation work --- source/LibRender2/Menu/AbstractMenu.cs | 15 ++ source/ObjectViewer/Game/Menu.cs | 211 ++++++++++++++++++++++++ source/ObjectViewer/ObjectViewer.csproj | 1 + source/OpenBVE/Game/Menu/Menu.cs | 26 +-- 4 files changed, 234 insertions(+), 19 deletions(-) create mode 100644 source/ObjectViewer/Game/Menu.cs diff --git a/source/LibRender2/Menu/AbstractMenu.cs b/source/LibRender2/Menu/AbstractMenu.cs index 86d9636b9..2e608f25f 100644 --- a/source/LibRender2/Menu/AbstractMenu.cs +++ b/source/LibRender2/Menu/AbstractMenu.cs @@ -30,6 +30,7 @@ using System.Collections.Generic; using LibRender2.Primitives; using System; +using OpenBveApi.Input; using OpenBveApi.Interface; namespace LibRender2.Menu @@ -103,12 +104,21 @@ public abstract class AbstractMenu /// The controls within the menu public List menuControls = new List(); + /// Whether the menu system is initialized + public bool IsInitialized = false; + + /// The key used to go back within the menu stack + public Key MenuBackKey; + /// Creates a new menu instance protected AbstractMenu(BaseRenderer renderer) { Renderer = renderer; } + /// Initializes the menu system upon first use + public abstract void Initialize(); + /// Resets the menu system to it's initial condition public virtual void Reset() { @@ -254,5 +264,10 @@ public void ComputePosition() } } + /// Draws the current menu + /// The real time elapsed since the last draw call + /// Note that the real time elapsed may be different to the game time elapsed + public abstract void Draw(double RealTimeElapsed); + } } diff --git a/source/ObjectViewer/Game/Menu.cs b/source/ObjectViewer/Game/Menu.cs new file mode 100644 index 000000000..c05597764 --- /dev/null +++ b/source/ObjectViewer/Game/Menu.cs @@ -0,0 +1,211 @@ +using System; +using LibRender2; +using LibRender2.Menu; +using LibRender2.Primitives; +using LibRender2.Screens; +using OpenBveApi.Colors; +using OpenBveApi.Graphics; +using OpenBveApi.Input; +using OpenBveApi.Math; + +namespace ObjectViewer +{ + public sealed class GameMenu: AbstractMenu + { + + internal Picturebox filePictureBox; + internal Textbox fileTextBox; + private double lastTimeElapsed; + + public GameMenu(BaseRenderer renderer) : base(renderer) + { + } + + public override void Initialize() + { + Reset(); + // choose the text font size according to screen height + // the boundaries follow approximately the progression + // of font sizes defined in Graphics/Fonts.cs + if (Program.Renderer.Screen.Height <= 512) MenuFont = Program.Renderer.Fonts.SmallFont; + else if (Program.Renderer.Screen.Height <= 680) MenuFont = Program.Renderer.Fonts.NormalFont; + else if (Program.Renderer.Screen.Height <= 890) MenuFont = Program.Renderer.Fonts.LargeFont; + else if (Program.Renderer.Screen.Height <= 1150) MenuFont = Program.Renderer.Fonts.VeryLargeFont; + else MenuFont = Program.Renderer.Fonts.EvenLargerFont; + + lineHeight = (int)(MenuFont.FontSize * LineSpacing); + MenuBackKey = Key.Escape; // fixed in viewers + int quarterWidth = (int)(Program.Renderer.Screen.Width / 4.0); + int quarterHeight = (int)(Program.Renderer.Screen.Height / 4.0); + int descriptionLoc = Program.Renderer.Screen.Width - quarterWidth - quarterWidth / 2; + int descriptionWidth = quarterWidth + quarterWidth / 2; + int descriptionHeight = descriptionWidth; + if (descriptionHeight + quarterWidth > Program.Renderer.Screen.Height - 50) + { + descriptionHeight = Program.Renderer.Screen.Height - quarterWidth - 50; + } + fileTextBox.Location = new Vector2(descriptionLoc, quarterWidth); + fileTextBox.Size = new Vector2(descriptionWidth, descriptionHeight); + int imageLoc = Program.Renderer.Screen.Width - quarterWidth - quarterWidth / 4; + filePictureBox.Location = new Vector2(imageLoc, 0); + filePictureBox.Size = new Vector2(quarterWidth, quarterWidth); + filePictureBox.BackgroundColor = Color128.White; + } + + public override void PushMenu(MenuType type, int data = 0, bool replace = false) + { + if (Program.Renderer.CurrentInterface < InterfaceType.Menu) + { + // Deliberately set to the standard cursor, as touch controls may have set to something else + Program.Renderer.SetCursor(OpenTK.MouseCursor.Default); + } + if (!IsInitialized) + Initialize(); + if (!replace) + { + CurrMenu++; + } + + if (Menus.Length <= CurrMenu) + Array.Resize(ref Menus, CurrMenu + 1); + int MaxWidth = 0; + if ((int)type >= 100) + { + MaxWidth = Program.Renderer.Screen.Width / 2; + } +// Menus[CurrMenu] = new SingleMenu(type, data, MaxWidth); + if (replace) + { + Menus[CurrMenu].Selection = 1; + } + ComputePosition(); + Program.Renderer.CurrentInterface = InterfaceType.Menu; + } + + public override void Draw(double RealTimeElapsed) + { + double TimeElapsed = RealTimeElapsed - lastTimeElapsed; + lastTimeElapsed = RealTimeElapsed; + int i; + + if (CurrMenu < 0 || CurrMenu >= Menus.Length) + return; + + MenuBase menu = Menus[CurrMenu]; + // overlay background + Program.Renderer.Rectangle.Draw(null, Vector2.Null, new Vector2(Program.Renderer.Screen.Width, Program.Renderer.Screen.Height), overlayColor); + + + double itemLeft, itemX; + if (menu.Align == TextAlignment.TopLeft) + { + itemLeft = 0; + itemX = 16; + Program.Renderer.Rectangle.Draw(null, new Vector2(0, menuMin.Y - Border.Y), new Vector2(menuMax.X - menuMin.X + 2.0f * Border.X, menuMax.Y - menuMin.Y + 2.0f * Border.Y), backgroundColor); + } + else + { + itemLeft = (Program.Renderer.Screen.Width - menu.ItemWidth) / 2; // item left edge + // if menu alignment is left, left-align items, otherwise centre them in the screen + itemX = (menu.Align & TextAlignment.Left) != 0 ? itemLeft : Program.Renderer.Screen.Width / 2.0; + Program.Renderer.Rectangle.Draw(null, new Vector2(menuMin.X - Border.X, menuMin.Y - Border.Y), new Vector2(menuMax.X - menuMin.X + 2.0f * Border.X, menuMax.Y - menuMin.Y + 2.0f * Border.Y), backgroundColor); + } + + // draw the menu background + + + int menuBottomItem = menu.TopItem + visibleItems - 1; + + + + // if not starting from the top of the menu, draw a dimmed ellipsis item + if (menu.Selection == menu.TopItem - 1) + { + Program.Renderer.Rectangle.Draw(null, new Vector2(itemLeft - ItemBorder.X, menuMin.Y /*-ItemBorder.Y*/), new Vector2(menu.ItemWidth + ItemBorder.X, MenuFont.FontSize + ItemBorder.Y * 2), highlightColor); + } + if (menu.TopItem > 0) + Program.Renderer.OpenGlString.Draw(MenuFont, @"...", new Vector2(itemX, menuMin.Y), + menu.Align, ColourDimmed, false); + // draw the items + double itemY = topItemY; + for (i = menu.TopItem; i <= menuBottomItem && i < menu.Items.Length; i++) + { + if (menu.Items[i] == null) + { + continue; + } + + double itemHeight = MenuFont.MeasureString(menu.Items[i].Text).Y; + double iconX = itemX; + if (menu.Items[i].Icon != null) + { + itemX += itemHeight * 1.25; + } + if (i == menu.Selection) + { + // draw a solid highlight rectangle under the text + // HACK! the highlight rectangle has to be shifted a little down to match + // the text body. OpenGL 'feature'? + Color128 color = highlightColor; + if (menu.Items[i] is MenuCommand command) + { + switch (command.Tag) + { + case MenuTag.Directory: + case MenuTag.ParentDirectory: + color = folderHighlightColor; + break; + case MenuTag.RouteFile: + color = routeHighlightColor; + break; + default: + color = highlightColor; + break; + } + } + + if (itemLeft == 0) + { + Program.Renderer.Rectangle.Draw(null, new Vector2(ItemBorder.X, itemY /*-ItemBorder.Y*/), new Vector2(menu.Width + 2.0f * ItemBorder.X, MenuFont.FontSize + ItemBorder.Y * 2), color); + } + else + { + Program.Renderer.Rectangle.Draw(null, new Vector2(itemLeft - ItemBorder.X, itemY /*-ItemBorder.Y*/), new Vector2(menu.ItemWidth + 2.0f * ItemBorder.X, MenuFont.FontSize + ItemBorder.Y * 2), color); + } + + // draw the text + Program.Renderer.OpenGlString.Draw(MenuFont, menu.Items[i].DisplayText(TimeElapsed), new Vector2(itemX, itemY), + menu.Align, ColourHighlight, false); + } + else if (menu.Items[i] is MenuCaption) + Program.Renderer.OpenGlString.Draw(MenuFont, menu.Items[i].DisplayText(TimeElapsed), new Vector2(itemX, itemY), + menu.Align, ColourCaption, false); + else + Program.Renderer.OpenGlString.Draw(MenuFont, menu.Items[i].DisplayText(TimeElapsed), new Vector2(itemX, itemY), + menu.Align, ColourNormal, false); +// if (menu.Items[i] is MenuOption opt) +// { +// Program.Renderer.OpenGlString.Draw(MenuFont, opt.CurrentOption.ToString(), new Vector2((menuMax.X - menuMin.X + 2.0f * Border.X) + 4.0f, itemY), +// menu.Align, backgroundColor, false); +// } + itemY += lineHeight; + if (menu.Items[i].Icon != null) + { + Program.Renderer.Rectangle.DrawAlpha(menu.Items[i].Icon, new Vector2(iconX, itemY - itemHeight * 1.5), new Vector2(itemHeight, itemHeight), Color128.White); + itemX = iconX; + } + + } + + + if (menu.Selection == menu.TopItem + visibleItems) + { + Program.Renderer.Rectangle.Draw(null, new Vector2(itemLeft - ItemBorder.X, itemY /*-ItemBorder.Y*/), new Vector2(menu.ItemWidth + 2.0f * ItemBorder.X, MenuFont.FontSize + ItemBorder.Y * 2), highlightColor); + } + // if not at the end of the menu, draw a dimmed ellipsis item at the bottom + if (i < menu.Items.Length - 1) + Program.Renderer.OpenGlString.Draw(MenuFont, @"...", new Vector2(itemX, itemY), + menu.Align, ColourDimmed, false); + } + } +} diff --git a/source/ObjectViewer/ObjectViewer.csproj b/source/ObjectViewer/ObjectViewer.csproj index cf5328327..9871da510 100644 --- a/source/ObjectViewer/ObjectViewer.csproj +++ b/source/ObjectViewer/ObjectViewer.csproj @@ -88,6 +88,7 @@ formTrain.cs + diff --git a/source/OpenBVE/Game/Menu/Menu.cs b/source/OpenBVE/Game/Menu/Menu.cs index 0e57da409..7ac2c67cf 100644 --- a/source/OpenBVE/Game/Menu/Menu.cs +++ b/source/OpenBVE/Game/Menu/Menu.cs @@ -49,18 +49,14 @@ MENU SYSTEM FIELDS private int CustomControlIdx; // the index of the control being customized private bool isCustomisingControl = false; - private bool isInitialized = false; + - internal Key MenuBackKey; + /******************** MENU SYSTEM SINGLETON C'TOR *********************/ - // Explicit static constructor to tell C# compiler not to mark type as beforefieldinit - static GameMenu() - { - } private GameMenu() : base(Program.Renderer) { } @@ -71,10 +67,7 @@ private GameMenu() : base(Program.Renderer) /******************** MENU SYSTEM METHODS *********************/ - // - // INITIALIZE THE MENU SYSTEM - // - private void Init() + public override void Initialize() { Reset(); // choose the text font size according to screen height @@ -134,7 +127,7 @@ private void Init() controlTextBox.Location = new Vector2(Program.Renderer.Screen.Width / 2.0, Program.Renderer.Screen.Height / 8.0 + quarterWidth); controlTextBox.Size = new Vector2(quarterWidth, quarterWidth); controlTextBox.BackgroundColor = Color128.Black; - isInitialized = true; + IsInitialized = true; // add controls to list so we can itinerate them on mouse calls etc. menuControls.Add(routePictureBox); @@ -167,8 +160,8 @@ public override void PushMenu(MenuType type, int data = 0, bool replace = false // Deliberately set to the standard cursor, as touch controls may have set to something else Program.Renderer.SetCursor(MouseCursor.Default); } - if (!isInitialized) - Init(); + if (!IsInitialized) + Initialize(); if (!replace) { CurrMenu++; @@ -325,7 +318,6 @@ public override bool ProcessMouseMove(int x, int y) /// The time elapsed since previous frame public override void ProcessCommand(Translations.Command cmd, double timeElapsed) { - if (CurrMenu < 0) { return; @@ -730,11 +722,7 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed private ControlMethod lastControlMethod; - // - // DRAW MENU - // - /// Draws the current menu as a screen overlay - internal void Draw(double RealTimeElapsed) + public override void Draw(double RealTimeElapsed) { pluginKeepAliveTimer += RealTimeElapsed; if (pluginKeepAliveTimer > 100000 && TrainManager.PlayerTrain != null && TrainManager.PlayerTrain.Plugin != null) From a43f495773fcaf24ffbda4ed28ad44a32735c514 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Sun, 25 Aug 2024 20:23:32 +0100 Subject: [PATCH 15/41] Fix: Incorrect decoding of some interlaced PNG files https://bveworldwide.forumotion.com/t2422-indonesian-kcic-400af-panel2-cfg-problem#21866 --- source/Plugins/Texture.BmpGifJpegPngTiff/PNG/PngDecoder.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/source/Plugins/Texture.BmpGifJpegPngTiff/PNG/PngDecoder.cs b/source/Plugins/Texture.BmpGifJpegPngTiff/PNG/PngDecoder.cs index 6a831082f..4e2c88c6e 100644 --- a/source/Plugins/Texture.BmpGifJpegPngTiff/PNG/PngDecoder.cs +++ b/source/Plugins/Texture.BmpGifJpegPngTiff/PNG/PngDecoder.cs @@ -462,7 +462,7 @@ internal bool Read(string fileName) data[rowStartByte + j] = (byte)((data[rowStartByte + j] + leftByte) % 256); break; case ScanlineFilterAlgorithm.Up: - upByte = data[previousRowStartByte + j]; + upByte = currentScanline == 0 ? (byte)0 : data[previousRowStartByte + j]; data[rowStartByte + j] = (byte)((data[rowStartByte + j] + upByte) % 256); break; case ScanlineFilterAlgorithm.Average: From 28decf689dd9e2d461764c59040d6ab8b58fc60d Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Sun, 25 Aug 2024 20:32:43 +0100 Subject: [PATCH 16/41] Hacks: Use more appropriate values for cab position on KIC400 --- .../Train.OpenBve/Panel/Panel2CfgParser.cs | 16 ++++++++++++++++ 1 file changed, 16 insertions(+) diff --git a/source/Plugins/Train.OpenBve/Panel/Panel2CfgParser.cs b/source/Plugins/Train.OpenBve/Panel/Panel2CfgParser.cs index ce18a7829..62e8ead2b 100644 --- a/source/Plugins/Train.OpenBve/Panel/Panel2CfgParser.cs +++ b/source/Plugins/Train.OpenBve/Panel/Panel2CfgParser.cs @@ -217,6 +217,15 @@ internal void ParsePanel2Config(string PanelFile, string TrainPath, CarBase Car) } } break; + case 483: + switch (trainName.ToUpperInvariant()) + { + case "[HOSHIRAIL] KCIC CR400-AF": + PanelCenter.X = 517; + PanelCenter.Y = 300; + break; + } + break; } } @@ -248,6 +257,13 @@ internal void ParsePanel2Config(string PanelFile, string TrainPath, CarBase Car) PanelOrigin.Y = 0; } break; + case "[HOSHIRAIL] KCIC CR400-AF": + if (PanelResolution == 826 && PanelOrigin.X == 350) + { + PanelOrigin.X = 517; + PanelOrigin.Y = 300; + } + break; } } } else { From 00d37a66460fcf086cb6a0c062c5042342b933c7 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Tue, 27 Aug 2024 19:29:50 +0100 Subject: [PATCH 17/41] More bits, AI generated object icon --- assets/Menu/icon_object.png | Bin 0 -> 5898 bytes source/LibRender2/Menu/MenuTag.cs | 8 +- source/LibRender2/Menu/MenuType.cs | 5 +- source/ObjectViewer/Game/Menu.SingleMenu.cs | 109 +++++++++++++++++++ source/ObjectViewer/Game/Menu.cs | 12 +- source/ObjectViewer/Graphics/NewRendererS.cs | 6 + source/ObjectViewer/ObjectViewer.csproj | 5 +- source/ObjectViewer/ProgramS.cs | 17 ++- 8 files changed, 153 insertions(+), 9 deletions(-) create mode 100644 assets/Menu/icon_object.png create mode 100644 source/ObjectViewer/Game/Menu.SingleMenu.cs diff --git a/assets/Menu/icon_object.png b/assets/Menu/icon_object.png new file mode 100644 index 0000000000000000000000000000000000000000..dfcc3b2ef7aec4d823f96e5879a0dd90a800a1ef GIT binary patch literal 5898 zcmV+l7xn0gP)EX>4Tx04R}tkv&MmKpe$iTct%RMeHEzkfA!+MMVUcQpF-zC~bvS9ZW9$f+h_~ zii@M*T5#}VvFhOBtgC~oAP9bdI6F8gx=4xtOA0MwJUH&hyL*qjcYwE9Ws1=g0~FQN z(}}o{%dZOlR|GJE0n8yJGDAyd7PD|2U-$6v^)AY@+|T_v`sISb0FOW%W14OfZxGLH zni}VQ;xH?VGVwX_giaSEe&o93@Ehln&0d}v*0bq(;xMsL>SC#jSy@+zr->u7qEfy$ z=djFqi?dR#v-Umt3xfr9CBt=^qex&0Nu(e^LLC)UVIoSaN{WFr?Z;jG!?r&~E{R+f zFmf!Q1_h$+2mgcL-5SNINhc{72YO#D>thV??*grcWqlu8R_g@tJp)&2$6sp#v!A3l zI$Goi2yFuw*BwpT11@)fp(jn$MO*UG^cIW2`x$*x9vHj@`qrG@+WRy{D4^000SaNLh0L z04^f{04^f|c%?sf00007bV*G`2j~bJ5(hJGm?+->000?uMObu0Z*6U5Zgc=ca%Ew3 zWn>_CX>@2HM@dakSAh-}000!>Nkl@G2IMcoN-QnFg>WzAOk{%!i zLl6dG;ux@r6G$q?2FFQPoH&&Z?byb#LmYRPGtjOs$DMYk+%XQeF(k%;#@H=03j<;h z1_?9^jZXp%Ptu!*JDqd(-u=gY46amn*+eE(qOa=yx9_=kf9G3keQWIvr*RsmaT=#_ z8mDm@|4t!(UJu^%^kZiV=SoWJslH_^D&>yuSN=^B;GFe-_!pnMe&M;Nd@mD_X>CWp z>piRHk)N_jLjT|pL&GB&Ye}(x*tc}~EpI0R^uP208}GUErm6K${1y8TkSfQ#_Hi;o zoO=Oj9MfqmQ9eg~ex7~zKk%^^?!5K4>hp8EgK{|yg&GUOOa;%ImYHa#k<^ddFtgCo z*0s>FWZ-0!&CS296|m!pb?@5q?Qi_3{-ejdd^StN#LQ#xuX;b7S6+j_v7~>HkyYn# zc*D~?`+;A_c>?WuG@PKOH8RQ(6k1UE9IntpP$-~t8G>wvsI?8HI z+8E8}im{60!?s*7`DJH(xzM+){+26X|E{g2J$Kx8$HIdTd&|lN5(!!cv_xP$jSvp$ z1j_S3Df0Oi&gd&q6A-5fGmQoT4dPmrc$}V z>S^jCA=Hk27o{-`lB4( zI-r1{EeOdtjg}rJn<2>t$gIRf0vBikPZM~8AP{I@;4}oDAnz*%J3^WZ!R1j4c`(4?0opXRlC1^`~L_gkCH89sU-I`2edek+SH((Qt-&6EkNT%++J+ah*7h zNz5Oqndp{U1@I72OsSuk}LY7OSAF>#|ooTdzQ zl<|Gd=Cf9j?;qg79WS$cYzpm9zWFki-BuShwm&U}x5-5cc0-IQTElH3_Ze_} z{`On1edVsZzN9C{D1{O$1VUL>yRjvRQPCCl}n_Tyo>N-pCFE7s?{2J zn!Ve0Qt&j(t8;BN<(a?v;X~_BDFNFbeQ0psKiz#F`*uVf`H;GE)U72EiX;^n3)ToK zNz9Ik3Q5C~$8z1p!}N^rLp-$>`P>gtC5bCYD0!%y#`83})S;3(vod}sEV$4hz75IccEqWl0YJu+4iCIXuZ4$K=4I>GSuAEs&}CaZNa%%LjB zk&P-COWH7)*&69=jby$~HEl4KG?PKSPVi*bm$>70SeId2J^L; znOaI+3+mAH21+1}LkYpk?q1}`DxyF7G%D}`iPVZP2#BjSs?rns50pn$@ed1 z!{!~ll*G)`9h;}>$fbE?PX^rM&UzFvBlFQcokkHIw;F)bC39UdohV5gVe`oitCxf$ zoN#1>aP@g?*?$;O4$wt~-y+c&i}o8B8#7&vF)>6+5ei2(RD>Cc_BFl59CBco>_>hR zB?XOo11}1ZPEu?s;2h{|#FF752A2)dJ-mYQrSIhN?V}u;S|I<-qvtlBc<|4DW&*zd zU;pxkBmZ>!Ro$&wkRAwuXCP9bl)wprvksFOCR4{NwS=Lw&!N=bMy^=o{9kwnzj4j4 zkVr|}FI~>QZTs1|f0ksrPC8ztFF>V}V_ za|NVOm^3Am&0v6RHq&&9DDtgkdWTogJ21e&*{e{)L)`J=e$q+>f6McqAK&)lvwkK5 zmR@q{_j*74JOArsxFk8TP-QYrsfy-uBL!aIp?uA(^4LCC!yjHjTi*aJEiGg-5iQw> z?ygR9nG9Z62Zbx&&*rB#krwml&N5L?fuJ*k$@nBj5e6PI2nmA-Uj;-))0+)Ruls#6 z=l;Ut;KgB`!vY3{A7(%_yLllcMC%{?YCFfKKJ|spSbyp-}Sru`X{UyIXOAac%|AbgHmF&X0)Dg#A(ia_hqzqFQHf} zlZhgL5~He(o8@$EO%7<|&$mK6;l- z-F(ZpfBdEfBKO~UtDBpcr8+*z{IM|_V@FsxImW)xL*y^Gkmai{rlYfiLa~JJ`$#De zLLjBXi4>POYFjoje(NnW^Gn)FYBRn~Jk`$0uV1)w<-T4A53K8b!FH!i#_u+&? z(hR#=rHb!qoRUZj%2PNTVv#RkFjrhf%cbu|NP$3L(iGWfkO>q{Nt_c1XNc!& z=v)@51kO2>_UT?agsD~bMi*T8&7auBP5=4LH$&Rf(@`cWr52nsSQ|o;!xRPJP})Ol zjZz9J-#`H199U%#K?`ladKCx1{3UkR1YF{=n`}=vqS%I>og+FhN+A={__NOv{_-^lCBcFAG@b}gZ8s={n9|xS3F~l9 z;he%Mhi5?u@y|Z5N0(Y8!eEp`w)N6^#rt^a@dxQ`?Lt^X>RTL+0+Mo&;y!y5s&5eC z9EnXidjA6)`ohiRJ%<@PhL#Rr35vxmp{Qd2+kc@kHGzNqZ=?JW=bFEFN(u12fJWS$ zaaF1flvZffY+0pjGB1R{iRQKia`BHioNczW!V0VcwfbVF4<6+4{dXSDiT3h{7tAH?~9;Y}2&RGr|I>5GVFLKUVXX1Gt9bIjlv2q1U zNR(`np_IZ{aMm`;`IwKTYtZFAkmBiI8I!2M&SfX~Mu~0nkCn zp3y@r)N8C99s;2_J~ob&f(_+Ag}_Ib1cb+JI>O9e&V=}F$N(8p&z1^!qXnvYzqetzD%Wdh_lZ=r&%UnE0V7!O-O1LrY9$u zs?3u}A6nbV5B5{&DiioVOB!|7|Ie>uM9L8ivpBR?qzJ6`nLoLJl>TD0I!I430Yd49 zOJW29-}9-b38mIDJ>5OjYBi1?K1!ulBMdVHo`b@>QeMtO&0^ zi%uy4C#R-QI_vOtv!j&OfdeH4QfNHSLn%cn96>h2`KwpcKR(X%_#{h8B_`+R7VYut zCegjYs|eRTJJed^2f(1) zBWcQh(J(n{-(a;RLaD``!pB^7u-{GhY3(U4 zgYE6@&oAljet!E)dse@+cOSi7-3$!$Q!W%xQlb{)S~ZVD@s-3`1J2RW-a$uCFB8Wn zFvcLA!wCV_y)FkK5lSPZLZv8*SFgTiJ8;qW?z#JdojZ2iI66A|fxY|ph2_>(mJJQj+u21F1Xw3gQXz#zAW)*2 z{HVvY7qVDu7yq#M3AZj~bA7WiIGkJTF&5XVw1EfIY05jmLumEdJI5I&CnngvV;4Jj z?c$8Cu=aB~8~nhvA9?}!tqmKV`Qslwy6*SJj*Z>$+{R5kTf%@dR;;AIx0g&NLm>5H zTindbN`R2MS@W$09LCu<7|o`ul_<277_~U4T2z)v8d%qSyT%x_1nmbnYuLYc7dy6Y zV{Gg=*<5~qTetFlY)njAFZrr|W$EDkM?qb=p zVTStqDHV$NO5iClPN1a3iRN67#ZK|n?K@|2)?rPGwFZIZ4a!D15Q)Jh24}(HA*JHz z_RVZqx0ax_`>Ey2m;TNBuD@1+zZ@$_g#0L_reRCK0bE*#7Fk++Y>Gw z7-X=&pU$>60^h?4@R}C}789p?UBcF35=$J{h#NJW0B6&mP>2^Ng!P!-IHsITlic(f z%Dc93O)-a9vwB6nB^anroCw3V&iY$Mz#H+Q>#o}Zd~Cxr&wTFDb&vec_~gVV*FE`o zPe-|(mCJ_c@9QNSMkpx}vN=0=Rr=038gYX-PMDjUNBfE-jsc5x0^)>ddI4n;&M^k# zLA2?|c%eqk&EuZ_ai`k4^D9%c6Ym4w|F1&8YvHkG%{cJaNs@f!@4tS_)vp{ma^nlz zcV4<>$1X;eFJpM=5cyoTSp=L#xRm*Y1$OS=$8*m=&*S&s&shU~wB_=w9(oZTeSqM; z2MDB~E+n4Rpfy_AW-7H1Ps~tp0XAjsZF5ufjkxE3-@R(%#*H`3Oig}tVP-ZQ?Ca-U z@A)NGj;vts?w5FW!?PTCWt1a_UZ$^qXjfx)wtN1mAC*3^q>T$(3v@S9GRMbp#$uI3 zmU9HzEJ-Y>opWxzHoWXMaml5B*YlqD?|54h@G72M|9EM`lj}b^b8_+%p(h8Hj;vsE zdKw|cmPS3kXL#iqcU}9T>-TTlvL$@z`}cli=HS7P&ph(Tc|G+7&i6eo?kW&zN31-i z-+k4~3&X>ITUvebZQbv9=k(j|uJHf=dad*B``&kdWqx*|cX;HyhgPq-Z2$jj?VVr! z>gtJIyFT66wCUG=t-m#7`S3b@_PKvI_~GBXUkaJSelects the previous switch PreviousSwitch, /// Selects the next switch - NextSwitch + NextSwitch, + + // OBJECT VIEWER + /// Displays a list of objects + ObjectList, + /// Selects an object file to load + ObjectFile } } diff --git a/source/LibRender2/Menu/MenuType.cs b/source/LibRender2/Menu/MenuType.cs index 4bb05d70d..98561b02d 100644 --- a/source/LibRender2/Menu/MenuType.cs +++ b/source/LibRender2/Menu/MenuType.cs @@ -66,7 +66,8 @@ public enum MenuType /// The options menu Options, /// A menu allowing switch settings to be changed - ChangeSwitch - + ChangeSwitch, + /// Displays a list of object files + ObjectList } } diff --git a/source/ObjectViewer/Game/Menu.SingleMenu.cs b/source/ObjectViewer/Game/Menu.SingleMenu.cs new file mode 100644 index 000000000..931f3e1bc --- /dev/null +++ b/source/ObjectViewer/Game/Menu.SingleMenu.cs @@ -0,0 +1,109 @@ +using LibRender2.Menu; +using OpenBveApi.Graphics; +using OpenBveApi.Hosts; +using OpenBveApi.Interface; +using OpenBveApi.Textures; +using System; +using System.IO; +using Path = OpenBveApi.Path; + +namespace ObjectViewer +{ + public sealed partial class GameMenu + { + /// Provides implementation for a single menu of the menu stack. + /// The class is private to Menu, but all its fields are public to allow 'quick-and-dirty' + /// access from Menu itself. + private class SingleMenu : MenuBase + { + public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(menuType) + { + int i; + int jump = 0; + //Vector2 size; + Align = TextAlignment.TopMiddle; + Height = Width = 0; + Selection = 0; // defaults to first menu item + switch (menuType) + { + case MenuType.GameStart: // top level menu + Items = new MenuEntry[3]; + Items[0] = new MenuCommand("Open Object File", MenuTag.ObjectList, 0); + Items[1] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "title" }), MenuTag.Options, 0); + Items[2] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "menu", "quit" }), MenuTag.MenuQuit, 0); + SearchDirectory = Program.FileSystem.InitialRouteFolder; + Align = TextAlignment.TopLeft; + break; + case MenuType.ObjectList: + string[] potentialFiles = { }; + string[] directoryList = { }; + bool drives = false; + if (SearchDirectory != string.Empty) + { + try + { + potentialFiles = Directory.GetFiles(SearchDirectory); + directoryList = Directory.GetDirectories(SearchDirectory); + } + catch + { + // Ignored + } + } + else + { + DriveInfo[] systemDrives = DriveInfo.GetDrives(); + directoryList = new string[systemDrives.Length]; + for (int k = 0; k < systemDrives.Length; k++) + { + directoryList[k] = systemDrives[k].Name; + } + drives = true; + } + + Items = new MenuEntry[potentialFiles.Length + directoryList.Length + 2]; + Items[0] = new MenuCaption(SearchDirectory); + Items[1] = new MenuCommand("...", MenuTag.ParentDirectory, 0); + int totalEntries = 2; + for (int j = 0; j < directoryList.Length; j++) + { + DirectoryInfo directoryInfo = new DirectoryInfo(directoryList[j]); + if (Program.CurrentHost.Platform != HostPlatform.MicrosoftWindows && directoryInfo.Name[0] == '.') + { + continue; + } + Items[totalEntries] = new MenuCommand(directoryInfo.Name, MenuTag.Directory, 0); + if (drives) + { + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_disk.png"), new TextureParameters(null, null), out Items[totalEntries].Icon); + } + else + { + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_folder.png"), new TextureParameters(null, null), out Items[totalEntries].Icon); + } + + totalEntries++; + } + + for (int j = 0; j < potentialFiles.Length; j++) + { + string fileName = System.IO.Path.GetFileName(potentialFiles[j]); + if (Program.CurrentHost.Platform != HostPlatform.MicrosoftWindows && fileName[0] == '.') + { + continue; + } + if (fileName.ToLowerInvariant().EndsWith(".csv") || fileName.ToLowerInvariant().EndsWith(".b3d") || fileName.ToLowerInvariant().EndsWith(".x") || fileName.ToLowerInvariant().EndsWith(".animated")) + { + Items[totalEntries] = new MenuCommand(fileName, MenuTag.ObjectFile, 0); + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_object.png"), new TextureParameters(null, null), out Items[totalEntries].Icon); + totalEntries++; + } + } + Array.Resize(ref Items, totalEntries); + Align = TextAlignment.TopLeft; + break; + } + } + } + } +} diff --git a/source/ObjectViewer/Game/Menu.cs b/source/ObjectViewer/Game/Menu.cs index c05597764..44225feda 100644 --- a/source/ObjectViewer/Game/Menu.cs +++ b/source/ObjectViewer/Game/Menu.cs @@ -10,19 +10,25 @@ namespace ObjectViewer { - public sealed class GameMenu: AbstractMenu + public sealed partial class GameMenu: AbstractMenu { internal Picturebox filePictureBox; internal Textbox fileTextBox; private double lastTimeElapsed; + private static string SearchDirectory; - public GameMenu(BaseRenderer renderer) : base(renderer) + /// Returns the current menu instance (If applicable) + public static readonly GameMenu Instance = new GameMenu(); + + public GameMenu() : base(Program.Renderer) { } public override void Initialize() { + filePictureBox = new Picturebox(Program.Renderer); + fileTextBox = new Textbox(Program.Renderer, Program.Renderer.Fonts.NormalFont, Color128.White, Color128.Black); Reset(); // choose the text font size according to screen height // the boundaries follow approximately the progression @@ -73,7 +79,7 @@ public override void PushMenu(MenuType type, int data = 0, bool replace = false) { MaxWidth = Program.Renderer.Screen.Width / 2; } -// Menus[CurrMenu] = new SingleMenu(type, data, MaxWidth); + Menus[CurrMenu] = new SingleMenu(type, data, MaxWidth); if (replace) { Menus[CurrMenu].Selection = 1; diff --git a/source/ObjectViewer/Graphics/NewRendererS.cs b/source/ObjectViewer/Graphics/NewRendererS.cs index 29eb1049f..ee11dbe4a 100644 --- a/source/ObjectViewer/Graphics/NewRendererS.cs +++ b/source/ObjectViewer/Graphics/NewRendererS.cs @@ -5,6 +5,7 @@ using LibRender2; using LibRender2.Objects; using LibRender2.Primitives; +using LibRender2.Screens; using LibRender2.Viewports; using OpenBveApi; using OpenBveApi.Colors; @@ -384,6 +385,11 @@ private void RenderOverlays() // finalize PopMatrix(MatrixMode.Projection); PopMatrix(MatrixMode.Modelview); + + if (CurrentInterface == InterfaceType.Menu) + { + Program.Menu.Draw(0); + } } public NewRenderer(HostInterface CurrentHost, BaseOptions CurrentOptions, FileSystem FileSystem) : base(CurrentHost, CurrentOptions, FileSystem) diff --git a/source/ObjectViewer/ObjectViewer.csproj b/source/ObjectViewer/ObjectViewer.csproj index 9871da510..b6d7695f7 100644 --- a/source/ObjectViewer/ObjectViewer.csproj +++ b/source/ObjectViewer/ObjectViewer.csproj @@ -27,7 +27,7 @@ full false ..\..\bin_debug\ - x86 + AnyCPU TRACE;DEBUG prompt 4 @@ -39,7 +39,7 @@ None true ..\..\bin_release\ - x86 + AnyCPU TRACE prompt 4 @@ -89,6 +89,7 @@ + diff --git a/source/ObjectViewer/ProgramS.cs b/source/ObjectViewer/ProgramS.cs index 3d3ec8efd..2e97c3d76 100644 --- a/source/ObjectViewer/ProgramS.cs +++ b/source/ObjectViewer/ProgramS.cs @@ -9,11 +9,14 @@ using System.Collections.Generic; using System.Text; using System.Windows.Forms; +using LibRender2.Menu; +using LibRender2.Screens; using LibRender2.Trains; using ObjectViewer.Graphics; using ObjectViewer.Trains; using OpenBveApi; using OpenBveApi.FileSystem; +using OpenBveApi.Hosts; using OpenBveApi.Interface; using OpenBveApi.Objects; using OpenBveApi.Routes; @@ -62,8 +65,11 @@ internal static class Program { internal static TrainManager TrainManager; + /// The in-game menu system + internal static readonly GameMenu Menu = GameMenu.Instance; + // main - [STAThread] + [STAThread] internal static void Main(string[] args) { CurrentHost = new Host(); @@ -357,6 +363,15 @@ internal static void KeyDown(object sender, KeyboardKeyEventArgs e) break; case Key.F7: { + if (/* Program.CurrentHost.Platform == HostPlatform.AppleOSX && **TEMP** */IntPtr.Size != 4) + { + if (Program.Renderer.CurrentInterface != InterfaceType.Menu) + { + Program.Renderer.CurrentInterface = InterfaceType.Menu; + Program.Menu.PushMenu(MenuType.GameStart); + } + return; + } OpenFileDialog Dialog = new OpenFileDialog { CheckFileExists = true, From d6ff8345c3b3f1b621174d231d56e1eab53a57db Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Thu, 29 Aug 2024 18:17:49 +0100 Subject: [PATCH 18/41] Make initial menu draw in ObjectViewer Needs to have keys etc. hooked in --- source/LibRender2/Menu/AbstractMenu.cs | 1 - source/ObjectViewer/Game/Menu.SingleMenu.cs | 44 +++++++++++++++++++ source/ObjectViewer/Game/Menu.cs | 6 +-- source/ObjectViewer/Graphics/NewRendererS.cs | 10 ++--- source/ObjectViewer/InterfaceS.cs | 10 ++--- source/ObjectViewer/ProgramS.cs | 16 +++---- .../Translations/InterfaceStrings.cs | 8 ---- 7 files changed, 63 insertions(+), 32 deletions(-) diff --git a/source/LibRender2/Menu/AbstractMenu.cs b/source/LibRender2/Menu/AbstractMenu.cs index 2e608f25f..14efe6780 100644 --- a/source/LibRender2/Menu/AbstractMenu.cs +++ b/source/LibRender2/Menu/AbstractMenu.cs @@ -29,7 +29,6 @@ using OpenBveApi.Math; using System.Collections.Generic; using LibRender2.Primitives; -using System; using OpenBveApi.Input; using OpenBveApi.Interface; diff --git a/source/ObjectViewer/Game/Menu.SingleMenu.cs b/source/ObjectViewer/Game/Menu.SingleMenu.cs index 931f3e1bc..731832289 100644 --- a/source/ObjectViewer/Game/Menu.SingleMenu.cs +++ b/source/ObjectViewer/Game/Menu.SingleMenu.cs @@ -5,6 +5,7 @@ using OpenBveApi.Textures; using System; using System.IO; +using OpenBveApi.Math; using Path = OpenBveApi.Path; namespace ObjectViewer @@ -103,6 +104,49 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m Align = TextAlignment.TopLeft; break; } + + // compute menu extent + for (i = 0; i < Items.Length; i++) + { + if (Items[i] == null) + { + continue; + } + Vector2 size = Game.Menu.MenuFont.MeasureString(Items[i].Text); + if (Items[i].Icon != null) + { + size.X += size.Y * 1.25; + } + if (size.X > Width) + { + Width = size.X; + } + + if (MaxWidth != 0 && size.X > MaxWidth) + { + for (int j = Items[i].Text.Length - 1; j > 0; j--) + { + string trimmedText = Items[i].Text.Substring(0, j); + size = Game.Menu.MenuFont.MeasureString(trimmedText); + double mwi = MaxWidth; + if (Items[i].Icon != null) + { + mwi -= size.Y * 1.25; + } + if (size.X < mwi) + { + Items[i].DisplayLength = trimmedText.Length; + break; + } + } + Width = MaxWidth; + } + if (!(Items[i] is MenuCaption && menuType != MenuType.RouteList && menuType != MenuType.GameStart && menuType != MenuType.Packages) && size.X > ItemWidth) + ItemWidth = size.X; + } + Height = Items.Length * Game.Menu.lineHeight; + TopItem = 0; + } } } diff --git a/source/ObjectViewer/Game/Menu.cs b/source/ObjectViewer/Game/Menu.cs index 44225feda..0b532edb1 100644 --- a/source/ObjectViewer/Game/Menu.cs +++ b/source/ObjectViewer/Game/Menu.cs @@ -1,5 +1,4 @@ using System; -using LibRender2; using LibRender2.Menu; using LibRender2.Primitives; using LibRender2.Screens; @@ -19,14 +18,15 @@ public sealed partial class GameMenu: AbstractMenu private static string SearchDirectory; /// Returns the current menu instance (If applicable) - public static readonly GameMenu Instance = new GameMenu(); + public static GameMenu Instance; - public GameMenu() : base(Program.Renderer) + internal GameMenu() : base(Program.Renderer) { } public override void Initialize() { + Instance = new GameMenu(); filePictureBox = new Picturebox(Program.Renderer); fileTextBox = new Textbox(Program.Renderer, Program.Renderer.Fonts.NormalFont, Color128.White, Color128.Black); Reset(); diff --git a/source/ObjectViewer/Graphics/NewRendererS.cs b/source/ObjectViewer/Graphics/NewRendererS.cs index ee11dbe4a..953213b97 100644 --- a/source/ObjectViewer/Graphics/NewRendererS.cs +++ b/source/ObjectViewer/Graphics/NewRendererS.cs @@ -381,15 +381,15 @@ private void RenderOverlays() } } } - + if (CurrentInterface == InterfaceType.Menu) + { + Game.Menu.Draw(0); + } // finalize PopMatrix(MatrixMode.Projection); PopMatrix(MatrixMode.Modelview); - if (CurrentInterface == InterfaceType.Menu) - { - Program.Menu.Draw(0); - } + } public NewRenderer(HostInterface CurrentHost, BaseOptions CurrentOptions, FileSystem FileSystem) : base(CurrentHost, CurrentOptions, FileSystem) diff --git a/source/ObjectViewer/InterfaceS.cs b/source/ObjectViewer/InterfaceS.cs index 6a48a52c7..01f94c261 100644 --- a/source/ObjectViewer/InterfaceS.cs +++ b/source/ObjectViewer/InterfaceS.cs @@ -1,10 +1,3 @@ -// ╔══════════════════════════════════════════════════════════════╗ -// ║ Interface.cs and TrainManager.cs for the Structure Viewer ║ -// ╠══════════════════════════════════════════════════════════════╣ -// ║ This file cannot be used in the openBVE main program. ║ -// ║ The files from the openBVE main program cannot be used here. ║ -// ╚══════════════════════════════════════════════════════════════╝ - using System.Collections.Generic; using ObjectViewer.Graphics; using OpenBveApi; @@ -35,6 +28,9 @@ internal static void Reset() ObjectManager.AnimatedWorldObjects = new WorldObject[4]; ObjectManager.AnimatedWorldObjectsUsed = 0; } + + /// The in-game menu system + internal static readonly GameMenu Menu = GameMenu.Instance; } // --- Interface.cs --- diff --git a/source/ObjectViewer/ProgramS.cs b/source/ObjectViewer/ProgramS.cs index 2e97c3d76..ef1282f13 100644 --- a/source/ObjectViewer/ProgramS.cs +++ b/source/ObjectViewer/ProgramS.cs @@ -64,10 +64,7 @@ internal static class Program { internal static CurrentRoute CurrentRoute; internal static TrainManager TrainManager; - - /// The in-game menu system - internal static readonly GameMenu Menu = GameMenu.Instance; - + // main [STAThread] internal static void Main(string[] args) @@ -154,9 +151,12 @@ internal static void Main(string[] args) Backend = PlatformBackend.PreferX11 }; Toolkit.Init(options); - // initialize camera - - currentGraphicsMode = new GraphicsMode(new ColorFormat(8, 8, 8, 8), 24, 8,Interface.CurrentOptions.AntiAliasingLevel); + // --- load language --- + string folder = Program.FileSystem.GetDataFolder("Languages"); + Translations.LoadLanguageFiles(folder); + GameMenu.Instance = new GameMenu(); + // initialize camera + currentGraphicsMode = new GraphicsMode(new ColorFormat(8, 8, 8, 8), 24, 8,Interface.CurrentOptions.AntiAliasingLevel); currentGameWindow = new ObjectViewer(Renderer.Screen.Width, Renderer.Screen.Height, currentGraphicsMode, "Object Viewer", GameWindowFlags.Default) { Visible = true, @@ -368,7 +368,7 @@ internal static void KeyDown(object sender, KeyboardKeyEventArgs e) if (Program.Renderer.CurrentInterface != InterfaceType.Menu) { Program.Renderer.CurrentInterface = InterfaceType.Menu; - Program.Menu.PushMenu(MenuType.GameStart); + Game.Menu.PushMenu(MenuType.GameStart); } return; } diff --git a/source/OpenBveApi/Interface/Translations/InterfaceStrings.cs b/source/OpenBveApi/Interface/Translations/InterfaceStrings.cs index e563a0b75..a478ebea4 100644 --- a/source/OpenBveApi/Interface/Translations/InterfaceStrings.cs +++ b/source/OpenBveApi/Interface/Translations/InterfaceStrings.cs @@ -6,14 +6,6 @@ public static partial class Translations { /// Stores the current language-code public static string CurrentLanguageCode = "en-GB"; - - internal struct InterfaceString - { - /// The name of the string - internal string Name; - /// The translated string text - internal string Text; - } /// Sets the in-game language /// The language string to set From 93c2abed17c8ff2ea3bd4f855f1cb414d08f8af1 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Thu, 29 Aug 2024 18:28:13 +0100 Subject: [PATCH 19/41] Hook in mouse movement events --- source/ObjectViewer/Game/Menu.cs | 48 +++++++++++++++++++ source/ObjectViewer/ProgramS.cs | 59 ++++++++++++++++-------- source/ObjectViewer/System/GameWindow.cs | 1 + source/OpenBVE/System/MainLoop.cs | 4 +- 4 files changed, 91 insertions(+), 21 deletions(-) diff --git a/source/ObjectViewer/Game/Menu.cs b/source/ObjectViewer/Game/Menu.cs index 0b532edb1..7066112ee 100644 --- a/source/ObjectViewer/Game/Menu.cs +++ b/source/ObjectViewer/Game/Menu.cs @@ -88,6 +88,54 @@ public override void PushMenu(MenuType type, int data = 0, bool replace = false) Program.Renderer.CurrentInterface = InterfaceType.Menu; } + public override bool ProcessMouseMove(int x, int y) + { + Program.currentGameWindow.CursorVisible = true; + if (CurrMenu < 0) + { + return false; + } + // if not in menu or during control customisation or down outside menu area, do nothing + if (Program.Renderer.CurrentInterface < InterfaceType.Menu) + return false; + + // Load the current menu + MenuBase menu = Menus[CurrMenu]; + if (menu.TopItem > 1 && y < topItemY && y > menuMin.Y) + { + //Item is the scroll up ellipsis + menu.Selection = menu.TopItem - 1; + return true; + } + if (menu.Type == MenuType.RouteList || menu.Type == MenuType.TrainList || menu.Type == MenuType.PackageInstall || menu.Type == MenuType.Packages || (int)menu.Type >= 107) + { + fileTextBox.MouseMove(x, y); + //HACK: Use this to trigger our menu start button! + if (x > Program.Renderer.Screen.Width - 200 && x < Program.Renderer.Screen.Width - 10 && y > Program.Renderer.Screen.Height - 40 && y < Program.Renderer.Screen.Height - 10) + { + menu.Selection = int.MaxValue; + return true; + } + } + if (x < menuMin.X || x > menuMax.X || y < menuMin.Y || y > menuMax.Y) + { + return false; + } + + int item = (int)((y - topItemY) / lineHeight + menu.TopItem); + // if the mouse is above a command item, select it + if (item >= 0 && item < menu.Items.Length && menu.Items[item] is MenuCommand /* || menu.Items[item] is MenuOption) */) + { + if (item < visibleItems + menu.TopItem + 1) + { + //Item is a standard menu entry or the scroll down elipsis + menu.Selection = item; + return true; + } + } + return false; + } + public override void Draw(double RealTimeElapsed) { double TimeElapsed = RealTimeElapsed - lastTimeElapsed; diff --git a/source/ObjectViewer/ProgramS.cs b/source/ObjectViewer/ProgramS.cs index ef1282f13..b1ca669b5 100644 --- a/source/ObjectViewer/ProgramS.cs +++ b/source/ObjectViewer/ProgramS.cs @@ -183,25 +183,46 @@ internal static void MouseWheelEvent(object sender, MouseWheelEventArgs e) } } - internal static void MouseEvent(object sender, MouseButtonEventArgs e) + internal static void MouseMoveEvent(object sender, MouseMoveEventArgs e) + { + switch (Program.Renderer.CurrentInterface) + { + case InterfaceType.Menu: + case InterfaceType.GLMainMenu: + Game.Menu.ProcessMouseMove(e.X, e.Y); + break; + } + } + + internal static void MouseEvent(object sender, MouseButtonEventArgs e) { - MouseCameraPosition = Renderer.Camera.AbsolutePosition; - MouseCameraDirection = Renderer.Camera.AbsoluteDirection; - MouseCameraUp = Renderer.Camera.AbsoluteUp; - MouseCameraSide = Renderer.Camera.AbsoluteSide; - if (e.Button == OpenTK.Input.MouseButton.Left) - { - MouseButton = e.Mouse.LeftButton == ButtonState.Pressed ? 1 : 0; - } - if (e.Button == OpenTK.Input.MouseButton.Right) - { - MouseButton = e.Mouse.RightButton == ButtonState.Pressed ? 2 : 0; - } - if (e.Button == OpenTK.Input.MouseButton.Middle) - { - MouseButton = e.Mouse.RightButton == ButtonState.Pressed ? 3 : 0; - } - previousMouseState = Mouse.GetState(); + switch (Program.Renderer.CurrentInterface) + { + case InterfaceType.Menu: + case InterfaceType.GLMainMenu: + Game.Menu.ProcessMouseDown(e.X, e.Y); + break; + default: + MouseCameraPosition = Renderer.Camera.AbsolutePosition; + MouseCameraDirection = Renderer.Camera.AbsoluteDirection; + MouseCameraUp = Renderer.Camera.AbsoluteUp; + MouseCameraSide = Renderer.Camera.AbsoluteSide; + if (e.Button == OpenTK.Input.MouseButton.Left) + { + MouseButton = e.Mouse.LeftButton == ButtonState.Pressed ? 1 : 0; + } + if (e.Button == OpenTK.Input.MouseButton.Right) + { + MouseButton = e.Mouse.RightButton == ButtonState.Pressed ? 2 : 0; + } + if (e.Button == OpenTK.Input.MouseButton.Middle) + { + MouseButton = e.Mouse.RightButton == ButtonState.Pressed ? 3 : 0; + } + previousMouseState = Mouse.GetState(); + break; + } + } internal static void DragFile(object sender, FileDropEventArgs e) @@ -222,7 +243,7 @@ internal static void DragFile(object sender, FileDropEventArgs e) internal static void MouseMovement() { - if (MouseButton == 0) return; + if (MouseButton == 0 || Program.Renderer.CurrentInterface != InterfaceType.Normal) return; currentMouseState = Mouse.GetState(); if (currentMouseState != previousMouseState) { diff --git a/source/ObjectViewer/System/GameWindow.cs b/source/ObjectViewer/System/GameWindow.cs index 5bb3f9d98..5ce851d29 100644 --- a/source/ObjectViewer/System/GameWindow.cs +++ b/source/ObjectViewer/System/GameWindow.cs @@ -288,6 +288,7 @@ protected override void OnLoad(EventArgs e) MouseDown += Program.MouseEvent; MouseUp += Program.MouseEvent; MouseWheel += Program.MouseWheelEvent; + MouseMove += Program.MouseMoveEvent; FileDrop += Program.DragFile; Program.Renderer.Camera.Reset(new Vector3(-5.0, 2.5, -25.0)); Program.Renderer.Initialize(); diff --git a/source/OpenBVE/System/MainLoop.cs b/source/OpenBVE/System/MainLoop.cs index 29aae9fdd..a56a4e754 100644 --- a/source/OpenBVE/System/MainLoop.cs +++ b/source/OpenBVE/System/MainLoop.cs @@ -197,9 +197,9 @@ internal static void mouseUpEvent(object sender, MouseButtonEventArgs e) } } - /// Called when a mouse button is released + /// Called when the mouse is moved /// The sender - /// The button arguments + /// The move arguments internal static void mouseMoveEvent(object sender, MouseMoveEventArgs e) { timeSinceLastMouseEvent = 0; From 33480a9de64f436c8a5a0354a4daf563e1242757 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Sat, 31 Aug 2024 19:08:31 +0100 Subject: [PATCH 20/41] Hooking in some of the commands Use fixed keys for the viewers --- source/ObjectViewer/Game/Menu.cs | 115 ++++++++++++++++++++++++++++++- source/ObjectViewer/ProgramS.cs | 30 +++++++- 2 files changed, 142 insertions(+), 3 deletions(-) diff --git a/source/ObjectViewer/Game/Menu.cs b/source/ObjectViewer/Game/Menu.cs index 7066112ee..f1618ee4a 100644 --- a/source/ObjectViewer/Game/Menu.cs +++ b/source/ObjectViewer/Game/Menu.cs @@ -1,11 +1,16 @@ using System; +using System.IO; using LibRender2.Menu; using LibRender2.Primitives; using LibRender2.Screens; using OpenBveApi.Colors; using OpenBveApi.Graphics; +using OpenBveApi.Hosts; using OpenBveApi.Input; +using OpenBveApi.Interface; using OpenBveApi.Math; +using OpenBveApi.Textures; +using Path = OpenBveApi.Path; namespace ObjectViewer { @@ -16,6 +21,7 @@ public sealed partial class GameMenu: AbstractMenu internal Textbox fileTextBox; private double lastTimeElapsed; private static string SearchDirectory; + private static string currentFile; /// Returns the current menu instance (If applicable) public static GameMenu Instance; @@ -26,7 +32,6 @@ internal GameMenu() : base(Program.Renderer) public override void Initialize() { - Instance = new GameMenu(); filePictureBox = new Picturebox(Program.Renderer); fileTextBox = new Textbox(Program.Renderer, Program.Renderer.Fonts.NormalFont, Color128.White, Color128.Black); Reset(); @@ -56,6 +61,7 @@ public override void Initialize() filePictureBox.Location = new Vector2(imageLoc, 0); filePictureBox.Size = new Vector2(quarterWidth, quarterWidth); filePictureBox.BackgroundColor = Color128.White; + IsInitialized = true; } public override void PushMenu(MenuType type, int data = 0, bool replace = false) @@ -88,6 +94,113 @@ public override void PushMenu(MenuType type, int data = 0, bool replace = false) Program.Renderer.CurrentInterface = InterfaceType.Menu; } + public override void ProcessCommand(Translations.Command cmd, double timeElapsed) + { + if (CurrMenu < 0) + { + return; + } + MenuBase menu = Menus[CurrMenu]; + // MenuBack is managed independently from single menu data + if (cmd == Translations.Command.MenuBack) + { + if (menu.Type == MenuType.GameStart) + { + Reset(); + Program.Renderer.CurrentInterface = InterfaceType.Normal; + } + else + { + PopMenu(); + } + return; + } + if (menu.Selection == -1) // if menu has no selection, do nothing + return; + switch (cmd) + { + case Translations.Command.MenuUp: // UP + if (menu.Selection > 0 && + !(menu.Items[menu.Selection - 1] is MenuCaption)) + { + menu.Selection--; + ComputePosition(); + } + + break; + case Translations.Command.MenuDown: // DOWN + if (menu.Selection < menu.Items.Length - 1) + { + menu.Selection++; + ComputePosition(); + } + + break; + // case Translations.Command.MenuBack: // ESC: managed above + // break; + case Translations.Command.MenuEnter: // ENTER + if (menu.Items[menu.Selection] is MenuCommand menuItem) + { + switch (menuItem.Tag) + { + // menu management commands + case MenuTag.MenuBack: // BACK TO PREVIOUS MENU + GameMenu.Instance.PopMenu(); + break; + case MenuTag.MenuJumpToStation: // TO STATIONS MENU + GameMenu.Instance.PushMenu(MenuType.JumpToStation); + break; + case MenuTag.MenuExitToMainMenu: // TO EXIT MENU + GameMenu.Instance.PushMenu(MenuType.ExitToMainMenu); + break; + case MenuTag.MenuQuit: // TO QUIT MENU + GameMenu.Instance.PushMenu(MenuType.Quit); + break; + case MenuTag.MenuControls: // TO CONTROLS MENU + GameMenu.Instance.PushMenu(MenuType.Controls); + break; + case MenuTag.BackToSim: // OUT OF MENU BACK TO SIMULATION + Reset(); + Program.Renderer.CurrentInterface = InterfaceType.Normal; + break; + case MenuTag.ObjectList: // TO OBJECT LIST MENU + GameMenu.Instance.PushMenu(MenuType.ObjectList); + fileTextBox.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "errors", "route_please_select" }); + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\please_select.png"), new TextureParameters(null, null), out filePictureBox.Texture); + break; + case MenuTag.Directory: // SHOWS THE LIST OF FILES IN THE SELECTED DIR + SearchDirectory = SearchDirectory == string.Empty ? menu.Items[menu.Selection].Text : Path.CombineDirectory(SearchDirectory, menu.Items[menu.Selection].Text); + GameMenu.Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + break; + case MenuTag.ParentDirectory: // SHOWS THE LIST OF FILES IN THE PARENT DIR + if (string.IsNullOrEmpty(SearchDirectory)) + { + return; + } + + string oldSearchDirectory = SearchDirectory; + try + { + DirectoryInfo newDirectory = Directory.GetParent(SearchDirectory); + SearchDirectory = newDirectory == null ? string.Empty : Directory.GetParent(SearchDirectory)?.ToString(); + } + catch + { + SearchDirectory = oldSearchDirectory; + return; + } + GameMenu.Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + break; + case MenuTag.ObjectFile: + currentFile = Path.CombineFile(SearchDirectory, menu.Items[menu.Selection].Text); + break; + } + } + break; + } + + } + public override bool ProcessMouseMove(int x, int y) { Program.currentGameWindow.CursorVisible = true; diff --git a/source/ObjectViewer/ProgramS.cs b/source/ObjectViewer/ProgramS.cs index b1ca669b5..e98fc14b0 100644 --- a/source/ObjectViewer/ProgramS.cs +++ b/source/ObjectViewer/ProgramS.cs @@ -470,10 +470,24 @@ internal static void KeyDown(object sender, KeyboardKeyEventArgs e) RotateX = 1; break; case Key.Up: - RotateY = -1; + if (Renderer.CurrentInterface == InterfaceType.Normal) + { + RotateY = -1; + } + else + { + Game.Menu.ProcessCommand(Translations.Command.MenuUp, 0); + } break; case Key.Down: - RotateY = 1; + if (Renderer.CurrentInterface == InterfaceType.Normal) + { + RotateY = 1; + } + else + { + Game.Menu.ProcessCommand(Translations.Command.MenuDown, 0); + } break; case Key.A: case Key.Keypad4: @@ -555,6 +569,18 @@ internal static void KeyDown(object sender, KeyboardKeyEventArgs e) case Key.F11: Renderer.RenderStatsOverlay = !Renderer.RenderStatsOverlay; break; + case Key.Enter: + if (Renderer.CurrentInterface != InterfaceType.Normal) + { + Game.Menu.ProcessCommand(Translations.Command.MenuEnter, 0); + } + break; + case Key.Escape: + if (Renderer.CurrentInterface != InterfaceType.Normal) + { + Game.Menu.ProcessCommand(Translations.Command.MenuBack, 0); + } + break; } } From 926f961148c5bee20a8654e2c79af291732d3953 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Mon, 2 Sep 2024 12:01:43 +0100 Subject: [PATCH 21/41] Change: Purge texture caches when interpolation changed https://github.com/leezer3/OpenBVE/issues/1061 --- source/ObjectViewer/formOptions.cs | 7 +++++++ source/RouteViewer/formOptions.cs | 19 ++++++++++++------- 2 files changed, 19 insertions(+), 7 deletions(-) diff --git a/source/ObjectViewer/formOptions.cs b/source/ObjectViewer/formOptions.cs index 49378e4c8..11494cc12 100644 --- a/source/ObjectViewer/formOptions.cs +++ b/source/ObjectViewer/formOptions.cs @@ -35,6 +35,7 @@ private void CloseButton_Click(object sender, EventArgs e) int previousAntialasingLevel = Interface.CurrentOptions.AntiAliasingLevel; //Interpolation mode + InterpolationMode previousInterpolationMode = Interface.CurrentOptions.Interpolation; switch (InterpolationMode.SelectedIndex) { case 0: @@ -57,6 +58,12 @@ private void CloseButton_Click(object sender, EventArgs e) break; } + if (previousInterpolationMode != Interface.CurrentOptions.Interpolation) + { + // We have changed interpolation level, so the texture cache needs totally clearing (as opposed to changed files) + Program.Renderer.TextureManager.UnloadAllTextures(false); + } + //Ansiotropic filtering level Interface.CurrentOptions.AnisotropicFilteringLevel = (int) AnsiotropicLevel.Value; //Antialiasing level diff --git a/source/RouteViewer/formOptions.cs b/source/RouteViewer/formOptions.cs index b200c4e61..5c48dedc2 100644 --- a/source/RouteViewer/formOptions.cs +++ b/source/RouteViewer/formOptions.cs @@ -46,11 +46,9 @@ private void formOptions_Shown(object sender, EventArgs e) private void button1_Click(object sender, EventArgs e) { - - - - //Interpolation mode - switch (InterpolationMode.SelectedIndex) + //Interpolation mode + InterpolationMode prevInterpolationMode = Interface.CurrentOptions.Interpolation; + switch (InterpolationMode.SelectedIndex) { case 0: Interface.CurrentOptions.Interpolation = OpenBveApi.Graphics.InterpolationMode.NearestNeighbor; @@ -71,8 +69,15 @@ private void button1_Click(object sender, EventArgs e) Interface.CurrentOptions.Interpolation = OpenBveApi.Graphics.InterpolationMode.AnisotropicFiltering; break; } - //Ansiotropic filtering level - Interface.CurrentOptions.AnisotropicFilteringLevel = (int) AnsiotropicLevel.Value; + + if (previousInterpolationMode != Interface.CurrentOptions.Interpolation) + { + // We have changed interpolation level, so the texture cache needs totally clearing (as opposed to changed files) + Program.Renderer.TextureManager.UnloadAllTextures(false); + } + + //Ansiotropic filtering level + Interface.CurrentOptions.AnisotropicFilteringLevel = (int) AnsiotropicLevel.Value; //Antialiasing level Interface.CurrentOptions.AntiAliasingLevel = (int)AntialiasingLevel.Value; if (Interface.CurrentOptions.AntiAliasingLevel != previousAntialasingLevel) From ea7e5274d2ebde82041fbdf00cedb8b13e845f88 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Tue, 3 Sep 2024 18:55:59 +0100 Subject: [PATCH 22/41] Handle scroll, fix duplicate mouse event triggering --- source/ObjectViewer/ProgramS.cs | 24 +++++++++++++++++++----- 1 file changed, 19 insertions(+), 5 deletions(-) diff --git a/source/ObjectViewer/ProgramS.cs b/source/ObjectViewer/ProgramS.cs index e98fc14b0..c2950ec68 100644 --- a/source/ObjectViewer/ProgramS.cs +++ b/source/ObjectViewer/ProgramS.cs @@ -175,12 +175,22 @@ internal static void Main(string[] args) internal static void MouseWheelEvent(object sender, MouseWheelEventArgs e) - { - if(e.Delta != 0) + { + switch (Program.Renderer.CurrentInterface) { - double dx = -0.025 * e.Delta; - Renderer.Camera.AbsolutePosition += dx * Renderer.Camera.AbsoluteDirection; + case InterfaceType.Menu: + case InterfaceType.GLMainMenu: + Game.Menu.ProcessMouseScroll(e.Delta); + break; + default: + if (e.Delta != 0) + { + double dx = -0.025 * e.Delta; + Renderer.Camera.AbsolutePosition += dx * Renderer.Camera.AbsoluteDirection; + } + break; } + } internal static void MouseMoveEvent(object sender, MouseMoveEventArgs e) @@ -200,7 +210,11 @@ internal static void MouseEvent(object sender, MouseButtonEventArgs e) { case InterfaceType.Menu: case InterfaceType.GLMainMenu: - Game.Menu.ProcessMouseDown(e.X, e.Y); + if (e.IsPressed) + { + // viewer hooks up and down to same event + Game.Menu.ProcessMouseDown(e.X, e.Y); + } break; default: MouseCameraPosition = Renderer.Camera.AbsolutePosition; From b9c72cba7b778eb9480ab71af74b19363283bd02 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Tue, 3 Sep 2024 18:59:39 +0100 Subject: [PATCH 23/41] Actually load the object --- source/ObjectViewer/Game/Menu.cs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/source/ObjectViewer/Game/Menu.cs b/source/ObjectViewer/Game/Menu.cs index f1618ee4a..241382a06 100644 --- a/source/ObjectViewer/Game/Menu.cs +++ b/source/ObjectViewer/Game/Menu.cs @@ -193,6 +193,11 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed break; case MenuTag.ObjectFile: currentFile = Path.CombineFile(SearchDirectory, menu.Items[menu.Selection].Text); + Program.Files.Add(currentFile); + Game.Reset(); + Program.RefreshObjects(); + Reset(); + Program.Renderer.CurrentInterface = InterfaceType.Normal; break; } } From 2c2f48b052b33a6f9bcc3c9f4a4370f248f1292b Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Tue, 3 Sep 2024 19:09:23 +0100 Subject: [PATCH 24/41] Save the previous search folder, including between runs --- source/ObjectViewer/Game/Menu.SingleMenu.cs | 5 ++++- source/ObjectViewer/Game/Menu.cs | 2 ++ source/ObjectViewer/InterfaceS.cs | 3 +++ source/ObjectViewer/Options.cs | 19 +++++++++++++++++-- source/ObjectViewer/System/GameWindow.cs | 3 ++- 5 files changed, 28 insertions(+), 4 deletions(-) diff --git a/source/ObjectViewer/Game/Menu.SingleMenu.cs b/source/ObjectViewer/Game/Menu.SingleMenu.cs index 731832289..0d01b4a41 100644 --- a/source/ObjectViewer/Game/Menu.SingleMenu.cs +++ b/source/ObjectViewer/Game/Menu.SingleMenu.cs @@ -32,7 +32,10 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m Items[0] = new MenuCommand("Open Object File", MenuTag.ObjectList, 0); Items[1] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "title" }), MenuTag.Options, 0); Items[2] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "menu", "quit" }), MenuTag.MenuQuit, 0); - SearchDirectory = Program.FileSystem.InitialRouteFolder; + if (string.IsNullOrEmpty(SearchDirectory)) + { + SearchDirectory = Program.FileSystem.InitialRouteFolder; + } Align = TextAlignment.TopLeft; break; case MenuType.ObjectList: diff --git a/source/ObjectViewer/Game/Menu.cs b/source/ObjectViewer/Game/Menu.cs index 241382a06..0addd6336 100644 --- a/source/ObjectViewer/Game/Menu.cs +++ b/source/ObjectViewer/Game/Menu.cs @@ -61,6 +61,7 @@ public override void Initialize() filePictureBox.Location = new Vector2(imageLoc, 0); filePictureBox.Size = new Vector2(quarterWidth, quarterWidth); filePictureBox.BackgroundColor = Color128.White; + SearchDirectory = Interface.CurrentOptions.ObjectSearchDirectory; IsInitialized = true; } @@ -198,6 +199,7 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed Program.RefreshObjects(); Reset(); Program.Renderer.CurrentInterface = InterfaceType.Normal; + Interface.CurrentOptions.ObjectSearchDirectory = SearchDirectory; break; } } diff --git a/source/ObjectViewer/InterfaceS.cs b/source/ObjectViewer/InterfaceS.cs index 01f94c261..c88bc14f2 100644 --- a/source/ObjectViewer/InterfaceS.cs +++ b/source/ObjectViewer/InterfaceS.cs @@ -37,6 +37,7 @@ internal static void Reset() internal static class Interface { internal static readonly List LogMessages = new List(); + internal static void AddMessage(MessageType Type, bool FileNotFound, string Text) { LogMessages.Add(new LogMessage(Type, FileNotFound, Text)); } @@ -45,6 +46,8 @@ internal class Options : BaseOptions { private ObjectOptimizationMode objectOptimizationMode; + internal string ObjectSearchDirectory; + /// /// The mode of optimization to be performed on an object /// diff --git a/source/ObjectViewer/Options.cs b/source/ObjectViewer/Options.cs index 690e58a74..3411a2537 100644 --- a/source/ObjectViewer/Options.cs +++ b/source/ObjectViewer/Options.cs @@ -1,11 +1,12 @@ using System; using System.Globalization; +using System.IO; using System.Reflection; using System.Windows.Forms; using ObjectViewer.Graphics; -using OpenBveApi; using OpenBveApi.Graphics; using OpenBveApi.Objects; +using Path = OpenBveApi.Path; namespace ObjectViewer { @@ -172,6 +173,17 @@ internal static void LoadOptions() break; } break; + case "folders": + switch (Key) + { + case "objectsearch": + if (Directory.Exists(Value)) + { + Interface.CurrentOptions.ObjectSearchDirectory = Value; + } + break; + } + break; } } } @@ -219,7 +231,10 @@ internal static void SaveOptions() Builder.AppendLine(); Builder.AppendLine("[objectOptimization]"); Builder.AppendLine($"mode = {Interface.CurrentOptions.ObjectOptimizationMode}"); - string configFile = Path.CombineFile(Program.FileSystem.SettingsFolder, "1.5.0/options_ov.cfg"); + Builder.AppendLine(); + Builder.AppendLine("[Folders]"); + Builder.AppendLine($"objectsearch = {Interface.CurrentOptions.ObjectSearchDirectory}"); + string configFile = Path.CombineFile(Program.FileSystem.SettingsFolder, "1.5.0/options_ov.cfg"); System.IO.File.WriteAllText(configFile, Builder.ToString(), new System.Text.UTF8Encoding(true)); } catch diff --git a/source/ObjectViewer/System/GameWindow.cs b/source/ObjectViewer/System/GameWindow.cs index 5ce851d29..396650efa 100644 --- a/source/ObjectViewer/System/GameWindow.cs +++ b/source/ObjectViewer/System/GameWindow.cs @@ -302,7 +302,8 @@ protected override void OnLoad(EventArgs e) protected override void OnClosing(CancelEventArgs e) { - Program.Renderer.visibilityThread = false; + Options.SaveOptions(); + Program.Renderer.visibilityThread = false; } protected override void OnUnload(EventArgs e) From ecaca9ec83a4d0b435c11571dae47baee5137329 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Wed, 4 Sep 2024 09:28:14 +0100 Subject: [PATCH 25/41] Move MenuOption to LibRender2, required refactoring --- source/LibRender2/BaseRenderer.cs | 8 + source/LibRender2/LibRender2.csproj | 1 + source/LibRender2/Menu/AbstractMenu.cs | 9 +- .../Menu/MenuEntries/MenuEntry.Caption.cs | 2 +- .../Menu/MenuEntries/MenuEntry.Command.cs | 4 +- .../LibRender2/Menu/MenuEntries/MenuEntry.cs | 7 + .../LibRender2/Menu/MenuEntries/MenuOption.cs | 200 ++++++++++++++++ source/ObjectViewer/Game/Menu.SingleMenu.cs | 16 +- source/ObjectViewer/Game/Menu.cs | 80 +++---- source/OpenBVE/Game/Menu/Menu.MenuOption.cs | 214 ------------------ source/OpenBVE/Game/Menu/Menu.SingleMenu.cs | 136 +++++------ source/OpenBVE/Game/Menu/Menu.cs | 4 +- source/OpenBVE/Graphics/NewRenderer.cs | 8 + source/OpenBVE/OpenBve.csproj | 1 - 14 files changed, 352 insertions(+), 338 deletions(-) create mode 100644 source/LibRender2/Menu/MenuEntries/MenuOption.cs delete mode 100644 source/OpenBVE/Game/Menu/Menu.MenuOption.cs diff --git a/source/LibRender2/BaseRenderer.cs b/source/LibRender2/BaseRenderer.cs index 7481908b5..e24d0d493 100644 --- a/source/LibRender2/BaseRenderer.cs +++ b/source/LibRender2/BaseRenderer.cs @@ -1702,5 +1702,13 @@ public virtual void SetWindowState(OpenTK.WindowState windowState) { } + + /// Sets the size of the window + /// The new width + /// The new height + public virtual void SetWindowSize(int width, int height) + { + + } } } diff --git a/source/LibRender2/LibRender2.csproj b/source/LibRender2/LibRender2.csproj index 77c55b744..cb9bb0ed3 100644 --- a/source/LibRender2/LibRender2.csproj +++ b/source/LibRender2/LibRender2.csproj @@ -64,6 +64,7 @@ + diff --git a/source/LibRender2/Menu/AbstractMenu.cs b/source/LibRender2/Menu/AbstractMenu.cs index 14efe6780..24f789366 100644 --- a/source/LibRender2/Menu/AbstractMenu.cs +++ b/source/LibRender2/Menu/AbstractMenu.cs @@ -29,6 +29,7 @@ using OpenBveApi.Math; using System.Collections.Generic; using LibRender2.Primitives; +using OpenBveApi; using OpenBveApi.Input; using OpenBveApi.Interface; @@ -83,8 +84,11 @@ public abstract class AbstractMenu public Vector2 menuMax; /// Holds a reference to the base renderer - private readonly BaseRenderer Renderer; + public readonly BaseRenderer Renderer; + /// Holds a reference to the options + public readonly BaseOptions CurrentOptions; + /// The index of the current menu within the stack public int CurrMenu = -1; @@ -110,9 +114,10 @@ public abstract class AbstractMenu public Key MenuBackKey; /// Creates a new menu instance - protected AbstractMenu(BaseRenderer renderer) + protected AbstractMenu(BaseRenderer renderer, BaseOptions currentOptions) { Renderer = renderer; + CurrentOptions = currentOptions; } /// Initializes the menu system upon first use diff --git a/source/LibRender2/Menu/MenuEntries/MenuEntry.Caption.cs b/source/LibRender2/Menu/MenuEntries/MenuEntry.Caption.cs index 71327102a..650207d71 100644 --- a/source/LibRender2/Menu/MenuEntries/MenuEntry.Caption.cs +++ b/source/LibRender2/Menu/MenuEntries/MenuEntry.Caption.cs @@ -27,7 +27,7 @@ namespace LibRender2.Menu /// A caption to be rendered at the top of the menu public class MenuCaption : MenuEntry { - public MenuCaption(string Text) + public MenuCaption(AbstractMenu menu, string Text) : base(menu) { this.Text = Text; } diff --git a/source/LibRender2/Menu/MenuEntries/MenuEntry.Command.cs b/source/LibRender2/Menu/MenuEntries/MenuEntry.Command.cs index f21c483f1..6f5b0f750 100644 --- a/source/LibRender2/Menu/MenuEntries/MenuEntry.Command.cs +++ b/source/LibRender2/Menu/MenuEntries/MenuEntry.Command.cs @@ -34,7 +34,7 @@ public class MenuCommand : MenuEntry /// The optional data to be passed with the command public readonly object Data; - public MenuCommand(string Text, MenuTag Tag, object Data) + public MenuCommand(AbstractMenu menu, string Text, MenuTag Tag, object Data) : base(menu) { this.Text = Text; this.Tag = Tag; @@ -42,7 +42,7 @@ public MenuCommand(string Text, MenuTag Tag, object Data) this.Icon = null; } - public MenuCommand(string Text, MenuTag Tag, object Data, Texture Icon) + public MenuCommand(AbstractMenu menu, string Text, MenuTag Tag, object Data, Texture Icon) : base(menu) { this.Text = Text; this.Tag = Tag; diff --git a/source/LibRender2/Menu/MenuEntries/MenuEntry.cs b/source/LibRender2/Menu/MenuEntries/MenuEntry.cs index 48fa1c322..dde63643d 100644 --- a/source/LibRender2/Menu/MenuEntries/MenuEntry.cs +++ b/source/LibRender2/Menu/MenuEntries/MenuEntry.cs @@ -29,6 +29,8 @@ namespace LibRender2.Menu /// The base abstract Menu Entry class public abstract class MenuEntry { + /// Holds a reference to the containing base menu + public readonly AbstractMenu BaseMenu; /// The base text of the menu entry public string Text; /// The display text of the menu entry @@ -86,5 +88,10 @@ public int DisplayLength private int scroll; private bool pause; + public MenuEntry(AbstractMenu menu) + { + BaseMenu = menu; + } + } } diff --git a/source/LibRender2/Menu/MenuEntries/MenuOption.cs b/source/LibRender2/Menu/MenuEntries/MenuOption.cs new file mode 100644 index 000000000..d40c85dea --- /dev/null +++ b/source/LibRender2/Menu/MenuEntries/MenuOption.cs @@ -0,0 +1,200 @@ +using LibRender2.Screens; +using OpenTK; +using System.Collections.Generic; +using System.Globalization; +using System.IO; +using OpenBveApi.Graphics; + +namespace LibRender2.Menu +{ + public class MenuOption : MenuEntry + { + private readonly OptionType Type; + + /// Holds the entries for all options + private readonly object[] Entries; + + /// Gets the current option + public object CurrentOption => Entries[CurrentlySelectedOption]; + + private int CurrentlySelectedOption; + + public MenuOption(AbstractMenu menu, OptionType type, string text, object[] entries) : base(menu) + { + Type = type; + Text = text; + Entries = entries; + switch (type) + { + case OptionType.ScreenResolution: + if (entries is ScreenResolution[] castEntries) + { + for (int i = 0; i < castEntries.Length; i++) + { + if (castEntries[i].Width == BaseMenu.Renderer.Screen.Width && castEntries[i].Height == BaseMenu.Renderer.Screen.Height) + { + CurrentlySelectedOption = i; + return; + } + } + } + else + { + throw new InvalidDataException("Entries must be a list of screen resolutions"); + } + + break; + case OptionType.FullScreen: + CurrentlySelectedOption = BaseMenu.CurrentOptions.FullscreenMode ? 0 : 1; + return; + case OptionType.Interpolation: + CurrentlySelectedOption = (int)BaseMenu.CurrentOptions.Interpolation; + return; + case OptionType.AnisotropicLevel: + for (int i = 0; i < Entries.Length; i++) + { + int level = int.Parse(entries[i] as string ?? string.Empty, NumberStyles.Integer); + if (level == BaseMenu.CurrentOptions.AnisotropicFilteringLevel) + { + CurrentlySelectedOption = i; + return; + } + } + break; + case OptionType.AntialiasingLevel: + for (int i = 0; i < Entries.Length; i++) + { + int level = int.Parse(entries[i] as string ?? string.Empty, NumberStyles.Integer); + if (level == BaseMenu.CurrentOptions.AntiAliasingLevel) + { + CurrentlySelectedOption = i; + return; + } + } + break; + case OptionType.ViewingDistance: + switch (BaseMenu.CurrentOptions.ViewingDistance) + { + case 400: + CurrentlySelectedOption = 0; + break; + case 600: + CurrentlySelectedOption = 1; + break; + case 800: + CurrentlySelectedOption = 2; + break; + case 1000: + CurrentlySelectedOption = 3; + break; + case 1500: + CurrentlySelectedOption = 4; + break; + case 2000: + CurrentlySelectedOption = 5; + break; + } + return; + } + CurrentlySelectedOption = 0; + } + + /// Flips to the next option + public void Flip() + { + if (CurrentlySelectedOption < Entries.Length - 1) + { + CurrentlySelectedOption++; + } + else + { + CurrentlySelectedOption = 0; + } + + //Apply + switch (Type) + { + case OptionType.ScreenResolution: + if (!(CurrentOption is ScreenResolution res)) + { + return; + } + BaseMenu.Renderer.SetWindowSize((int)(res.Width * DisplayDevice.Default.ScaleFactor.X), (int)(res.Height * DisplayDevice.Default.ScaleFactor.Y)); + if (BaseMenu.CurrentOptions.FullscreenMode) + { + IList resolutions = DisplayDevice.Default.AvailableResolutions; + foreach (DisplayResolution currentResolution in resolutions) + { + //Test resolution + if (currentResolution.Width == BaseMenu.Renderer.Screen.Width / DisplayDevice.Default.ScaleFactor.X && + currentResolution.Height == BaseMenu.Renderer.Screen.Height / DisplayDevice.Default.ScaleFactor.Y) + { + try + { + //HACK: some resolutions will result in openBVE not appearing on screen in full screen, so restore resolution then change resolution + DisplayDevice.Default.RestoreResolution(); + DisplayDevice.Default.ChangeResolution(currentResolution); + BaseMenu.Renderer.SetWindowState(WindowState.Fullscreen); + BaseMenu.Renderer.SetWindowSize((int)(currentResolution.Width * DisplayDevice.Default.ScaleFactor.X), (int)(currentResolution.Height * DisplayDevice.Default.ScaleFactor.Y)); + return; + } + catch + { + //refresh rate wrong? - Keep trying in case a different refresh rate works OK + } + } + } + } + break; + case OptionType.FullScreen: + BaseMenu.CurrentOptions.FullscreenMode = !BaseMenu.CurrentOptions.FullscreenMode; + if (BaseMenu.CurrentOptions.FullscreenMode) + { + BaseMenu.Renderer.SetWindowState(WindowState.Fullscreen); + DisplayDevice.Default.RestoreResolution(); + } + else + { + IList resolutions = DisplayDevice.Default.AvailableResolutions; + foreach (DisplayResolution currentResolution in resolutions) + { + //Test resolution + if (currentResolution.Width == BaseMenu.Renderer.Screen.Width / DisplayDevice.Default.ScaleFactor.X && + currentResolution.Height == BaseMenu.Renderer.Screen.Height / DisplayDevice.Default.ScaleFactor.Y) + { + try + { + //HACK: some resolutions will result in openBVE not appearing on screen in full screen, so restore resolution then change resolution + DisplayDevice.Default.RestoreResolution(); + DisplayDevice.Default.ChangeResolution(currentResolution); + BaseMenu.Renderer.SetWindowState(WindowState.Fullscreen); + BaseMenu.Renderer.SetWindowSize((int)(currentResolution.Width * DisplayDevice.Default.ScaleFactor.X), (int)(currentResolution.Height * DisplayDevice.Default.ScaleFactor.Y)); + return; + } + catch + { + //refresh rate wrong? - Keep trying in case a different refresh rate works OK + } + } + } + } + break; + case OptionType.Interpolation: + BaseMenu.CurrentOptions.Interpolation = (InterpolationMode)CurrentlySelectedOption; + break; + //HACK: We can't store plain ints due to to boxing, so store strings and parse instead + case OptionType.AnisotropicLevel: + BaseMenu.CurrentOptions.AnisotropicFilteringLevel = int.Parse((string)CurrentOption, NumberStyles.Integer); + break; + case OptionType.AntialiasingLevel: + BaseMenu.CurrentOptions.AntiAliasingLevel = int.Parse((string)CurrentOption, NumberStyles.Integer); + break; + case OptionType.ViewingDistance: + BaseMenu.CurrentOptions.ViewingDistance = int.Parse((string)CurrentOption, NumberStyles.Integer); + break; + + } + + } + } +} diff --git a/source/ObjectViewer/Game/Menu.SingleMenu.cs b/source/ObjectViewer/Game/Menu.SingleMenu.cs index 0d01b4a41..64189188e 100644 --- a/source/ObjectViewer/Game/Menu.SingleMenu.cs +++ b/source/ObjectViewer/Game/Menu.SingleMenu.cs @@ -17,7 +17,7 @@ public sealed partial class GameMenu /// access from Menu itself. private class SingleMenu : MenuBase { - public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(menuType) + public SingleMenu(AbstractMenu menu, MenuType menuType, int data = 0, double MaxWidth = 0) : base(menuType) { int i; int jump = 0; @@ -29,9 +29,9 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m { case MenuType.GameStart: // top level menu Items = new MenuEntry[3]; - Items[0] = new MenuCommand("Open Object File", MenuTag.ObjectList, 0); - Items[1] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "title" }), MenuTag.Options, 0); - Items[2] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "menu", "quit" }), MenuTag.MenuQuit, 0); + Items[0] = new MenuCommand(menu, "Open Object File", MenuTag.ObjectList, 0); + Items[1] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "title" }), MenuTag.Options, 0); + Items[2] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "menu", "quit" }), MenuTag.MenuQuit, 0); if (string.IsNullOrEmpty(SearchDirectory)) { SearchDirectory = Program.FileSystem.InitialRouteFolder; @@ -66,8 +66,8 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m } Items = new MenuEntry[potentialFiles.Length + directoryList.Length + 2]; - Items[0] = new MenuCaption(SearchDirectory); - Items[1] = new MenuCommand("...", MenuTag.ParentDirectory, 0); + Items[0] = new MenuCaption(menu, SearchDirectory); + Items[1] = new MenuCommand(menu, "...", MenuTag.ParentDirectory, 0); int totalEntries = 2; for (int j = 0; j < directoryList.Length; j++) { @@ -76,7 +76,7 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m { continue; } - Items[totalEntries] = new MenuCommand(directoryInfo.Name, MenuTag.Directory, 0); + Items[totalEntries] = new MenuCommand(menu, directoryInfo.Name, MenuTag.Directory, 0); if (drives) { Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_disk.png"), new TextureParameters(null, null), out Items[totalEntries].Icon); @@ -98,7 +98,7 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m } if (fileName.ToLowerInvariant().EndsWith(".csv") || fileName.ToLowerInvariant().EndsWith(".b3d") || fileName.ToLowerInvariant().EndsWith(".x") || fileName.ToLowerInvariant().EndsWith(".animated")) { - Items[totalEntries] = new MenuCommand(fileName, MenuTag.ObjectFile, 0); + Items[totalEntries] = new MenuCommand(menu, fileName, MenuTag.ObjectFile, 0); Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_object.png"), new TextureParameters(null, null), out Items[totalEntries].Icon); totalEntries++; } diff --git a/source/ObjectViewer/Game/Menu.cs b/source/ObjectViewer/Game/Menu.cs index 0addd6336..aface173f 100644 --- a/source/ObjectViewer/Game/Menu.cs +++ b/source/ObjectViewer/Game/Menu.cs @@ -26,38 +26,38 @@ public sealed partial class GameMenu: AbstractMenu /// Returns the current menu instance (If applicable) public static GameMenu Instance; - internal GameMenu() : base(Program.Renderer) + internal GameMenu() : base(Program.Renderer, Interface.CurrentOptions) { } public override void Initialize() { - filePictureBox = new Picturebox(Program.Renderer); - fileTextBox = new Textbox(Program.Renderer, Program.Renderer.Fonts.NormalFont, Color128.White, Color128.Black); + filePictureBox = new Picturebox(Renderer); + fileTextBox = new Textbox(Renderer, Renderer.Fonts.NormalFont, Color128.White, Color128.Black); Reset(); // choose the text font size according to screen height // the boundaries follow approximately the progression // of font sizes defined in Graphics/Fonts.cs - if (Program.Renderer.Screen.Height <= 512) MenuFont = Program.Renderer.Fonts.SmallFont; - else if (Program.Renderer.Screen.Height <= 680) MenuFont = Program.Renderer.Fonts.NormalFont; - else if (Program.Renderer.Screen.Height <= 890) MenuFont = Program.Renderer.Fonts.LargeFont; - else if (Program.Renderer.Screen.Height <= 1150) MenuFont = Program.Renderer.Fonts.VeryLargeFont; - else MenuFont = Program.Renderer.Fonts.EvenLargerFont; + if (Renderer.Screen.Height <= 512) MenuFont = Renderer.Fonts.SmallFont; + else if (Renderer.Screen.Height <= 680) MenuFont = Renderer.Fonts.NormalFont; + else if (Renderer.Screen.Height <= 890) MenuFont = Renderer.Fonts.LargeFont; + else if (Renderer.Screen.Height <= 1150) MenuFont = Renderer.Fonts.VeryLargeFont; + else MenuFont = Renderer.Fonts.EvenLargerFont; lineHeight = (int)(MenuFont.FontSize * LineSpacing); MenuBackKey = Key.Escape; // fixed in viewers - int quarterWidth = (int)(Program.Renderer.Screen.Width / 4.0); - int quarterHeight = (int)(Program.Renderer.Screen.Height / 4.0); - int descriptionLoc = Program.Renderer.Screen.Width - quarterWidth - quarterWidth / 2; + int quarterWidth = (int)(Renderer.Screen.Width / 4.0); + int quarterHeight = (int)(Renderer.Screen.Height / 4.0); + int descriptionLoc = Renderer.Screen.Width - quarterWidth - quarterWidth / 2; int descriptionWidth = quarterWidth + quarterWidth / 2; int descriptionHeight = descriptionWidth; - if (descriptionHeight + quarterWidth > Program.Renderer.Screen.Height - 50) + if (descriptionHeight + quarterWidth > Renderer.Screen.Height - 50) { - descriptionHeight = Program.Renderer.Screen.Height - quarterWidth - 50; + descriptionHeight = Renderer.Screen.Height - quarterWidth - 50; } fileTextBox.Location = new Vector2(descriptionLoc, quarterWidth); fileTextBox.Size = new Vector2(descriptionWidth, descriptionHeight); - int imageLoc = Program.Renderer.Screen.Width - quarterWidth - quarterWidth / 4; + int imageLoc = Renderer.Screen.Width - quarterWidth - quarterWidth / 4; filePictureBox.Location = new Vector2(imageLoc, 0); filePictureBox.Size = new Vector2(quarterWidth, quarterWidth); filePictureBox.BackgroundColor = Color128.White; @@ -67,10 +67,10 @@ public override void Initialize() public override void PushMenu(MenuType type, int data = 0, bool replace = false) { - if (Program.Renderer.CurrentInterface < InterfaceType.Menu) + if (Renderer.CurrentInterface < InterfaceType.Menu) { // Deliberately set to the standard cursor, as touch controls may have set to something else - Program.Renderer.SetCursor(OpenTK.MouseCursor.Default); + Renderer.SetCursor(OpenTK.MouseCursor.Default); } if (!IsInitialized) Initialize(); @@ -84,15 +84,15 @@ public override void PushMenu(MenuType type, int data = 0, bool replace = false) int MaxWidth = 0; if ((int)type >= 100) { - MaxWidth = Program.Renderer.Screen.Width / 2; + MaxWidth = Renderer.Screen.Width / 2; } - Menus[CurrMenu] = new SingleMenu(type, data, MaxWidth); + Menus[CurrMenu] = new SingleMenu(this, type, data, MaxWidth); if (replace) { Menus[CurrMenu].Selection = 1; } ComputePosition(); - Program.Renderer.CurrentInterface = InterfaceType.Menu; + Renderer.CurrentInterface = InterfaceType.Menu; } public override void ProcessCommand(Translations.Command cmd, double timeElapsed) @@ -108,7 +108,7 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed if (menu.Type == MenuType.GameStart) { Reset(); - Program.Renderer.CurrentInterface = InterfaceType.Normal; + Renderer.CurrentInterface = InterfaceType.Normal; } else { @@ -162,7 +162,7 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed break; case MenuTag.BackToSim: // OUT OF MENU BACK TO SIMULATION Reset(); - Program.Renderer.CurrentInterface = InterfaceType.Normal; + Renderer.CurrentInterface = InterfaceType.Normal; break; case MenuTag.ObjectList: // TO OBJECT LIST MENU GameMenu.Instance.PushMenu(MenuType.ObjectList); @@ -198,7 +198,7 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed Game.Reset(); Program.RefreshObjects(); Reset(); - Program.Renderer.CurrentInterface = InterfaceType.Normal; + Renderer.CurrentInterface = InterfaceType.Normal; Interface.CurrentOptions.ObjectSearchDirectory = SearchDirectory; break; } @@ -216,7 +216,7 @@ public override bool ProcessMouseMove(int x, int y) return false; } // if not in menu or during control customisation or down outside menu area, do nothing - if (Program.Renderer.CurrentInterface < InterfaceType.Menu) + if (Renderer.CurrentInterface < InterfaceType.Menu) return false; // Load the current menu @@ -231,7 +231,7 @@ public override bool ProcessMouseMove(int x, int y) { fileTextBox.MouseMove(x, y); //HACK: Use this to trigger our menu start button! - if (x > Program.Renderer.Screen.Width - 200 && x < Program.Renderer.Screen.Width - 10 && y > Program.Renderer.Screen.Height - 40 && y < Program.Renderer.Screen.Height - 10) + if (x > Renderer.Screen.Width - 200 && x < Renderer.Screen.Width - 10 && y > Renderer.Screen.Height - 40 && y < Renderer.Screen.Height - 10) { menu.Selection = int.MaxValue; return true; @@ -267,7 +267,7 @@ public override void Draw(double RealTimeElapsed) MenuBase menu = Menus[CurrMenu]; // overlay background - Program.Renderer.Rectangle.Draw(null, Vector2.Null, new Vector2(Program.Renderer.Screen.Width, Program.Renderer.Screen.Height), overlayColor); + Renderer.Rectangle.Draw(null, Vector2.Null, new Vector2(Renderer.Screen.Width, Renderer.Screen.Height), overlayColor); double itemLeft, itemX; @@ -275,14 +275,14 @@ public override void Draw(double RealTimeElapsed) { itemLeft = 0; itemX = 16; - Program.Renderer.Rectangle.Draw(null, new Vector2(0, menuMin.Y - Border.Y), new Vector2(menuMax.X - menuMin.X + 2.0f * Border.X, menuMax.Y - menuMin.Y + 2.0f * Border.Y), backgroundColor); + Renderer.Rectangle.Draw(null, new Vector2(0, menuMin.Y - Border.Y), new Vector2(menuMax.X - menuMin.X + 2.0f * Border.X, menuMax.Y - menuMin.Y + 2.0f * Border.Y), backgroundColor); } else { - itemLeft = (Program.Renderer.Screen.Width - menu.ItemWidth) / 2; // item left edge + itemLeft = (Renderer.Screen.Width - menu.ItemWidth) / 2; // item left edge // if menu alignment is left, left-align items, otherwise centre them in the screen - itemX = (menu.Align & TextAlignment.Left) != 0 ? itemLeft : Program.Renderer.Screen.Width / 2.0; - Program.Renderer.Rectangle.Draw(null, new Vector2(menuMin.X - Border.X, menuMin.Y - Border.Y), new Vector2(menuMax.X - menuMin.X + 2.0f * Border.X, menuMax.Y - menuMin.Y + 2.0f * Border.Y), backgroundColor); + itemX = (menu.Align & TextAlignment.Left) != 0 ? itemLeft : Renderer.Screen.Width / 2.0; + Renderer.Rectangle.Draw(null, new Vector2(menuMin.X - Border.X, menuMin.Y - Border.Y), new Vector2(menuMax.X - menuMin.X + 2.0f * Border.X, menuMax.Y - menuMin.Y + 2.0f * Border.Y), backgroundColor); } // draw the menu background @@ -295,10 +295,10 @@ public override void Draw(double RealTimeElapsed) // if not starting from the top of the menu, draw a dimmed ellipsis item if (menu.Selection == menu.TopItem - 1) { - Program.Renderer.Rectangle.Draw(null, new Vector2(itemLeft - ItemBorder.X, menuMin.Y /*-ItemBorder.Y*/), new Vector2(menu.ItemWidth + ItemBorder.X, MenuFont.FontSize + ItemBorder.Y * 2), highlightColor); + Renderer.Rectangle.Draw(null, new Vector2(itemLeft - ItemBorder.X, menuMin.Y /*-ItemBorder.Y*/), new Vector2(menu.ItemWidth + ItemBorder.X, MenuFont.FontSize + ItemBorder.Y * 2), highlightColor); } if (menu.TopItem > 0) - Program.Renderer.OpenGlString.Draw(MenuFont, @"...", new Vector2(itemX, menuMin.Y), + Renderer.OpenGlString.Draw(MenuFont, @"...", new Vector2(itemX, menuMin.Y), menu.Align, ColourDimmed, false); // draw the items double itemY = topItemY; @@ -340,32 +340,32 @@ public override void Draw(double RealTimeElapsed) if (itemLeft == 0) { - Program.Renderer.Rectangle.Draw(null, new Vector2(ItemBorder.X, itemY /*-ItemBorder.Y*/), new Vector2(menu.Width + 2.0f * ItemBorder.X, MenuFont.FontSize + ItemBorder.Y * 2), color); + Renderer.Rectangle.Draw(null, new Vector2(ItemBorder.X, itemY /*-ItemBorder.Y*/), new Vector2(menu.Width + 2.0f * ItemBorder.X, MenuFont.FontSize + ItemBorder.Y * 2), color); } else { - Program.Renderer.Rectangle.Draw(null, new Vector2(itemLeft - ItemBorder.X, itemY /*-ItemBorder.Y*/), new Vector2(menu.ItemWidth + 2.0f * ItemBorder.X, MenuFont.FontSize + ItemBorder.Y * 2), color); + Renderer.Rectangle.Draw(null, new Vector2(itemLeft - ItemBorder.X, itemY /*-ItemBorder.Y*/), new Vector2(menu.ItemWidth + 2.0f * ItemBorder.X, MenuFont.FontSize + ItemBorder.Y * 2), color); } // draw the text - Program.Renderer.OpenGlString.Draw(MenuFont, menu.Items[i].DisplayText(TimeElapsed), new Vector2(itemX, itemY), + Renderer.OpenGlString.Draw(MenuFont, menu.Items[i].DisplayText(TimeElapsed), new Vector2(itemX, itemY), menu.Align, ColourHighlight, false); } else if (menu.Items[i] is MenuCaption) - Program.Renderer.OpenGlString.Draw(MenuFont, menu.Items[i].DisplayText(TimeElapsed), new Vector2(itemX, itemY), + Renderer.OpenGlString.Draw(MenuFont, menu.Items[i].DisplayText(TimeElapsed), new Vector2(itemX, itemY), menu.Align, ColourCaption, false); else - Program.Renderer.OpenGlString.Draw(MenuFont, menu.Items[i].DisplayText(TimeElapsed), new Vector2(itemX, itemY), + Renderer.OpenGlString.Draw(MenuFont, menu.Items[i].DisplayText(TimeElapsed), new Vector2(itemX, itemY), menu.Align, ColourNormal, false); // if (menu.Items[i] is MenuOption opt) // { -// Program.Renderer.OpenGlString.Draw(MenuFont, opt.CurrentOption.ToString(), new Vector2((menuMax.X - menuMin.X + 2.0f * Border.X) + 4.0f, itemY), +// Renderer.OpenGlString.Draw(MenuFont, opt.CurrentOption.ToString(), new Vector2((menuMax.X - menuMin.X + 2.0f * Border.X) + 4.0f, itemY), // menu.Align, backgroundColor, false); // } itemY += lineHeight; if (menu.Items[i].Icon != null) { - Program.Renderer.Rectangle.DrawAlpha(menu.Items[i].Icon, new Vector2(iconX, itemY - itemHeight * 1.5), new Vector2(itemHeight, itemHeight), Color128.White); + Renderer.Rectangle.DrawAlpha(menu.Items[i].Icon, new Vector2(iconX, itemY - itemHeight * 1.5), new Vector2(itemHeight, itemHeight), Color128.White); itemX = iconX; } @@ -374,11 +374,11 @@ public override void Draw(double RealTimeElapsed) if (menu.Selection == menu.TopItem + visibleItems) { - Program.Renderer.Rectangle.Draw(null, new Vector2(itemLeft - ItemBorder.X, itemY /*-ItemBorder.Y*/), new Vector2(menu.ItemWidth + 2.0f * ItemBorder.X, MenuFont.FontSize + ItemBorder.Y * 2), highlightColor); + Renderer.Rectangle.Draw(null, new Vector2(itemLeft - ItemBorder.X, itemY /*-ItemBorder.Y*/), new Vector2(menu.ItemWidth + 2.0f * ItemBorder.X, MenuFont.FontSize + ItemBorder.Y * 2), highlightColor); } // if not at the end of the menu, draw a dimmed ellipsis item at the bottom if (i < menu.Items.Length - 1) - Program.Renderer.OpenGlString.Draw(MenuFont, @"...", new Vector2(itemX, itemY), + Renderer.OpenGlString.Draw(MenuFont, @"...", new Vector2(itemX, itemY), menu.Align, ColourDimmed, false); } } diff --git a/source/OpenBVE/Game/Menu/Menu.MenuOption.cs b/source/OpenBVE/Game/Menu/Menu.MenuOption.cs deleted file mode 100644 index bdf85ce7a..000000000 --- a/source/OpenBVE/Game/Menu/Menu.MenuOption.cs +++ /dev/null @@ -1,214 +0,0 @@ -using System.Collections.Generic; -using System.Globalization; -using System.IO; -using LibRender2.Menu; -using LibRender2.Screens; -using OpenBveApi.Graphics; -using OpenTK; - -namespace OpenBve -{ - public sealed partial class GameMenu - { - private class MenuOption : MenuEntry - { - private readonly OptionType Type; - - /// Holds the entries for all options - private readonly object[] Entries; - - /// Gets the current option - internal object CurrentOption => Entries[CurrentlySelectedOption]; - - private int CurrentlySelectedOption; - - internal MenuOption(OptionType type, string text, object[] entries) - { - Type = type; - Text = text; - Entries = entries; - switch (type) - { - case OptionType.ScreenResolution: - if (entries is ScreenResolution[] castEntries) - { - for (int i = 0; i < castEntries.Length; i++) - { - if (castEntries[i].Width == Program.Renderer.Screen.Width && castEntries[i].Height == Program.Renderer.Screen.Height) - { - CurrentlySelectedOption = i; - return; - } - } - } - else - { - throw new InvalidDataException("Entries must be a list of screen resolutions"); - } - - break; - case OptionType.FullScreen: - CurrentlySelectedOption = Interface.CurrentOptions.FullscreenMode ? 0 : 1; - return; - case OptionType.Interpolation: - CurrentlySelectedOption = (int)Interface.CurrentOptions.Interpolation; - return; - case OptionType.AnisotropicLevel: - for (int i = 0; i < Entries.Length; i++) - { - int level = int.Parse(entries[i] as string ?? string.Empty, NumberStyles.Integer); - if (level == Interface.CurrentOptions.AnisotropicFilteringLevel) - { - CurrentlySelectedOption = i; - return; - } - } - break; - case OptionType.AntialiasingLevel: - for (int i = 0; i < Entries.Length; i++) - { - int level = int.Parse(entries[i] as string ?? string.Empty, NumberStyles.Integer); - if (level == Interface.CurrentOptions.AntiAliasingLevel) - { - CurrentlySelectedOption = i; - return; - } - } - break; - case OptionType.ViewingDistance: - switch (Interface.CurrentOptions.ViewingDistance) - { - case 400: - CurrentlySelectedOption = 0; - break; - case 600: - CurrentlySelectedOption = 1; - break; - case 800: - CurrentlySelectedOption = 2; - break; - case 1000: - CurrentlySelectedOption = 3; - break; - case 1500: - CurrentlySelectedOption = 4; - break; - case 2000: - CurrentlySelectedOption = 5; - break; - } - return; - } - CurrentlySelectedOption = 0; - } - - /// Flips to the next option - internal void Flip() - { - if (CurrentlySelectedOption < Entries.Length - 1) - { - CurrentlySelectedOption++; - } - else - { - CurrentlySelectedOption = 0; - } - - //Apply - switch (Type) - { - case OptionType.ScreenResolution: - if (!(CurrentOption is ScreenResolution res)) - { - return; - } - Program.Renderer.Screen.Width = (int)(res.Width * DisplayDevice.Default.ScaleFactor.X); - Program.Renderer.Screen.Height = (int)(res.Height * DisplayDevice.Default.ScaleFactor.Y); - Program.currentGameWindow.Width = (int)(res.Width * DisplayDevice.Default.ScaleFactor.X); - Program.currentGameWindow.Height = (int)(res.Height * DisplayDevice.Default.ScaleFactor.Y); - if (Interface.CurrentOptions.FullscreenMode) - { - IList resolutions = DisplayDevice.Default.AvailableResolutions; - foreach (DisplayResolution currentResolution in resolutions) - { - //Test resolution - if (currentResolution.Width == Program.Renderer.Screen.Width / DisplayDevice.Default.ScaleFactor.X && - currentResolution.Height == Program.Renderer.Screen.Height / DisplayDevice.Default.ScaleFactor.Y) - { - try - { - //HACK: some resolutions will result in openBVE not appearing on screen in full screen, so restore resolution then change resolution - DisplayDevice.Default.RestoreResolution(); - DisplayDevice.Default.ChangeResolution(currentResolution); - Program.Renderer.SetWindowState(WindowState.Fullscreen); - Program.currentGameWindow.Width = (int)(currentResolution.Width * DisplayDevice.Default.ScaleFactor.X); - Program.currentGameWindow.Height = (int)(currentResolution.Height * DisplayDevice.Default.ScaleFactor.Y); - Program.Renderer.Screen.Width = Program.currentGameWindow.Width; - Program.Renderer.Screen.Height = Program.currentGameWindow.Height; - return; - } - catch - { - //refresh rate wrong? - Keep trying in case a different refresh rate works OK - } - } - } - } - break; - case OptionType.FullScreen: - Interface.CurrentOptions.FullscreenMode = !Interface.CurrentOptions.FullscreenMode; - if (Interface.CurrentOptions.FullscreenMode) - { - Program.Renderer.SetWindowState(WindowState.Fullscreen); - DisplayDevice.Default.RestoreResolution(); - } - else - { - IList resolutions = DisplayDevice.Default.AvailableResolutions; - foreach (DisplayResolution currentResolution in resolutions) - { - //Test resolution - if (currentResolution.Width == Program.Renderer.Screen.Width / DisplayDevice.Default.ScaleFactor.X && - currentResolution.Height == Program.Renderer.Screen.Height / DisplayDevice.Default.ScaleFactor.Y) - { - try - { - //HACK: some resolutions will result in openBVE not appearing on screen in full screen, so restore resolution then change resolution - DisplayDevice.Default.RestoreResolution(); - DisplayDevice.Default.ChangeResolution(currentResolution); - Program.Renderer.SetWindowState(WindowState.Fullscreen); - Program.currentGameWindow.Width = (int)(currentResolution.Width * DisplayDevice.Default.ScaleFactor.X); - Program.currentGameWindow.Height = (int)(currentResolution.Height * DisplayDevice.Default.ScaleFactor.Y); - Program.Renderer.Screen.Width = Program.currentGameWindow.Width; - Program.Renderer.Screen.Height = Program.currentGameWindow.Height; - return; - } - catch - { - //refresh rate wrong? - Keep trying in case a different refresh rate works OK - } - } - } - } - break; - case OptionType.Interpolation: - Interface.CurrentOptions.Interpolation = (InterpolationMode)CurrentlySelectedOption; - break; - //HACK: We can't store plain ints due to to boxing, so store strings and parse instead - case OptionType.AnisotropicLevel: - Interface.CurrentOptions.AnisotropicFilteringLevel = int.Parse((string)CurrentOption, NumberStyles.Integer); - break; - case OptionType.AntialiasingLevel: - Interface.CurrentOptions.AntiAliasingLevel = int.Parse((string)CurrentOption, NumberStyles.Integer); - break; - case OptionType.ViewingDistance: - Interface.CurrentOptions.ViewingDistance = int.Parse((string)CurrentOption, NumberStyles.Integer); - break; - - } - - } - } - - } -} diff --git a/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs b/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs index 5a68ca8bf..5c730e304 100644 --- a/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs +++ b/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs @@ -45,7 +45,7 @@ public sealed override int Selection } } - public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(menuType) + public SingleMenu(AbstractMenu menu, MenuType menuType, int data = 0, double MaxWidth = 0) : base(menuType) { int i; int jump = 0; @@ -72,15 +72,15 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\loading.png"), new TextureParameters(null, null), out routePictureBox.Texture); } Items = new MenuEntry[5]; - Items[0] = new MenuCommand("Open Route File", MenuTag.RouteList, 0); + Items[0] = new MenuCommand(menu, "Open Route File", MenuTag.RouteList, 0); if (!Interface.CurrentOptions.KioskMode) { //Don't allow quitting or customisation of the controls in kiosk mode - Items[1] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","title"}), MenuTag.Options, 0); - Items[2] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","customize_controls"}), MenuTag.MenuControls, 0); - Items[3] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","title"}), MenuTag.Packages, 0); - Items[4] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","quit"}), MenuTag.MenuQuit, 0); + Items[1] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","title"}), MenuTag.Options, 0); + Items[2] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","customize_controls"}), MenuTag.MenuControls, 0); + Items[3] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","title"}), MenuTag.Packages, 0); + Items[4] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","quit"}), MenuTag.MenuQuit, 0); } else { @@ -91,46 +91,46 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m break; case MenuType.Packages: Items = new MenuEntry[4]; - Items[0] = new MenuCaption(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","title"})); - Items[1] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","install_header"}), MenuTag.PackageInstall, 0); - Items[2] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","uninstall_button"}), MenuTag.PackageUninstall, 0); - Items[3] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","button_cancel"}), MenuTag.MenuBack, 0); + Items[0] = new MenuCaption(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","title"})); + Items[1] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","install_header"}), MenuTag.PackageInstall, 0); + Items[2] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","uninstall_button"}), MenuTag.PackageUninstall, 0); + Items[3] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","button_cancel"}), MenuTag.MenuBack, 0); Align = TextAlignment.TopLeft; break; case MenuType.PackageUninstall: routeDescriptionBox.Text = string.Empty; Items = new MenuEntry[5]; - Items[0] = new MenuCaption(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","list_type"})); - Items[1] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","type_route"}), MenuTag.UninstallRoute, 0); - Items[2] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","type_train"}), MenuTag.UninstallTrain, 0); - Items[3] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","type_other"}), MenuTag.UninstallOther, 0); - Items[4] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","button_cancel"}), MenuTag.MenuBack, 0); + Items[0] = new MenuCaption(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","list_type"})); + Items[1] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","type_route"}), MenuTag.UninstallRoute, 0); + Items[2] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","type_train"}), MenuTag.UninstallTrain, 0); + Items[3] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","type_other"}), MenuTag.UninstallOther, 0); + Items[4] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","button_cancel"}), MenuTag.MenuBack, 0); Align = TextAlignment.TopLeft; break; case MenuType.UninstallRoute: Items = new MenuEntry[Database.currentDatabase.InstalledRoutes.Count + 1]; - Items[0] = new MenuCaption(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","list"})); + Items[0] = new MenuCaption(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","list"})); for (int j = 0; j < Database.currentDatabase.InstalledRoutes.Count; j++) { - Items[j + 1] = new MenuCommand(Database.currentDatabase.InstalledRoutes[j].Name, MenuTag.Package, Database.currentDatabase.InstalledRoutes[j]); + Items[j + 1] = new MenuCommand(menu, Database.currentDatabase.InstalledRoutes[j].Name, MenuTag.Package, Database.currentDatabase.InstalledRoutes[j]); } Align = TextAlignment.TopLeft; break; case MenuType.UninstallTrain: Items = new MenuEntry[Database.currentDatabase.InstalledTrains.Count + 1]; - Items[0] = new MenuCaption(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","list"})); + Items[0] = new MenuCaption(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","list"})); for (int j = 0; j < Database.currentDatabase.InstalledTrains.Count; j++) { - Items[j + 1] = new MenuCommand(Database.currentDatabase.InstalledTrains[j].Name, MenuTag.Package, Database.currentDatabase.InstalledTrains[j]); + Items[j + 1] = new MenuCommand(menu, Database.currentDatabase.InstalledTrains[j].Name, MenuTag.Package, Database.currentDatabase.InstalledTrains[j]); } Align = TextAlignment.TopLeft; break; case MenuType.UninstallOther: Items = new MenuEntry[Database.currentDatabase.InstalledOther.Count + 1]; - Items[0] = new MenuCaption(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","list"})); + Items[0] = new MenuCaption(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"packages","list"})); for (int j = 0; j < Database.currentDatabase.InstalledOther.Count; j++) { - Items[j + 1] = new MenuCommand(Database.currentDatabase.InstalledOther[j].Name, MenuTag.Package, Database.currentDatabase.InstalledOther[j]); + Items[j + 1] = new MenuCommand(menu, Database.currentDatabase.InstalledOther[j].Name, MenuTag.Package, Database.currentDatabase.InstalledOther[j]); } Align = TextAlignment.TopLeft; break; @@ -162,8 +162,8 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m } Items = new MenuEntry[potentialFiles.Length + directoryList.Length + 2]; - Items[0] = new MenuCaption(SearchDirectory); - Items[1] = new MenuCommand("...", MenuTag.ParentDirectory, 0); + Items[0] = new MenuCaption(menu, SearchDirectory); + Items[1] = new MenuCommand(menu, "...", MenuTag.ParentDirectory, 0); int totalEntries = 2; for (int j = 0; j < directoryList.Length; j++) { @@ -172,7 +172,7 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m { continue; } - Items[totalEntries] = new MenuCommand(directoryInfo.Name, MenuTag.Directory, 0); + Items[totalEntries] = new MenuCommand(menu, directoryInfo.Name, MenuTag.Directory, 0); if (drives) { Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_disk.png"), new TextureParameters(null, null), out Items[totalEntries].Icon); @@ -192,7 +192,7 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m { continue; } - Items[totalEntries] = new MenuCommand(fileName, MenuTag.File, 0); + Items[totalEntries] = new MenuCommand(menu, fileName, MenuTag.File, 0); string ext = System.IO.Path.GetExtension(fileName); if (!iconCache.ContainsKey(ext)) { @@ -225,10 +225,10 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m break; case MenuType.Options: Items = new MenuEntry[8]; - Items[0] = new MenuCaption(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"panel","options"})); - Items[1] = new MenuOption(OptionType.ScreenResolution, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","resolution"}), Program.Renderer.Screen.AvailableResolutions.ToArray()); - Items[2] = new MenuOption(OptionType.FullScreen, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","display_mode_fullscreen"}), new[] { "true", "false" }); - Items[3] = new MenuOption(OptionType.Interpolation, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation"}), new[] + Items[0] = new MenuCaption(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"panel","options"})); + Items[1] = new MenuOption(menu, OptionType.ScreenResolution, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","resolution"}), Program.Renderer.Screen.AvailableResolutions.ToArray()); + Items[2] = new MenuOption(menu, OptionType.FullScreen, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","display_mode_fullscreen"}), new[] { "true", "false" }); + Items[3] = new MenuOption(menu, OptionType.Interpolation, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation"}), new[] { Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_mode_nearest"}), Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_mode_bilinear"}), @@ -237,10 +237,10 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_mode_trilinearmipmap"}), Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_mode_anisotropic"}) }); - Items[4] = new MenuOption(OptionType.AnisotropicLevel, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_anisotropic_level"}), new[] { "0", "2", "4", "8", "16" }); - Items[5] = new MenuOption(OptionType.AntialiasingLevel, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_antialiasing_level"}), new[] { "0", "2", "4", "8", "16" }); - Items[6] = new MenuOption(OptionType.ViewingDistance, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_distance_viewingdistance"}), new[] { "400", "600", "800", "1000", "1500", "2000" }); - Items[7] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","back"}), MenuTag.MenuBack, 0); + Items[4] = new MenuOption(menu, OptionType.AnisotropicLevel, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_anisotropic_level"}), new[] { "0", "2", "4", "8", "16" }); + Items[5] = new MenuOption(menu, OptionType.AntialiasingLevel, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_antialiasing_level"}), new[] { "0", "2", "4", "8", "16" }); + Items[6] = new MenuOption(menu, OptionType.ViewingDistance, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_distance_viewingdistance"}), new[] { "400", "600", "800", "1000", "1500", "2000" }); + Items[7] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","back"}), MenuTag.MenuBack, 0); Align = TextAlignment.TopLeft; break; case MenuType.RouteList: @@ -271,8 +271,8 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m } Items = new MenuEntry[potentialFiles.Length + directoryList.Length + 2]; - Items[0] = new MenuCaption(SearchDirectory); - Items[1] = new MenuCommand("...", MenuTag.ParentDirectory, 0); + Items[0] = new MenuCaption(menu, SearchDirectory); + Items[1] = new MenuCommand(menu, "...", MenuTag.ParentDirectory, 0); totalEntries = 2; for (int j = 0; j < directoryList.Length; j++) { @@ -281,7 +281,7 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m { continue; } - Items[totalEntries] = new MenuCommand(directoryInfo.Name, MenuTag.Directory, 0); + Items[totalEntries] = new MenuCommand(menu, directoryInfo.Name, MenuTag.Directory, 0); if (drives) { Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_disk.png"), new TextureParameters(null, null), out Items[totalEntries].Icon); @@ -303,7 +303,7 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m } if (fileName.ToLowerInvariant().EndsWith(".csv") || fileName.ToLowerInvariant().EndsWith(".rw")) { - Items[totalEntries] = new MenuCommand(fileName, MenuTag.RouteFile, 0); + Items[totalEntries] = new MenuCommand(menu, fileName, MenuTag.RouteFile, 0); Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_route.png"), new TextureParameters(null, null), out Items[totalEntries].Icon); totalEntries++; } @@ -339,8 +339,8 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m } Items = new MenuEntry[potentialFiles.Length + directoryList.Length + 2]; - Items[0] = new MenuCaption(SearchDirectory); - Items[1] = new MenuCommand("...", MenuTag.ParentDirectory, 0); + Items[0] = new MenuCaption(menu, SearchDirectory); + Items[1] = new MenuCommand(menu, "...", MenuTag.ParentDirectory, 0); totalEntries = 2; for (int j = 0; j < directoryList.Length; j++) { @@ -360,7 +360,7 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m } if (!isTrain) { - Items[totalEntries] = new MenuCommand(directoryInfo.Name, MenuTag.Directory, 0); + Items[totalEntries] = new MenuCommand(menu, directoryInfo.Name, MenuTag.Directory, 0); if (drives) { Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_disk.png"), new TextureParameters(null, null), out Items[totalEntries].Icon); @@ -372,7 +372,7 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m } else { - Items[totalEntries] = new MenuCommand(directoryInfo.Name, MenuTag.TrainDirectory, 0); + Items[totalEntries] = new MenuCommand(menu, directoryInfo.Name, MenuTag.TrainDirectory, 0); Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_train.png"), new TextureParameters(null, null), out Items[totalEntries].Icon); } totalEntries++; @@ -396,15 +396,15 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m break; } Items = new MenuEntry[4 + jump]; - Items[0] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","resume"}), MenuTag.BackToSim, 0); + Items[0] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","resume"}), MenuTag.BackToSim, 0); if (jump > 0) - Items[1] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","jump"}), MenuTag.MenuJumpToStation, 0); + Items[1] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","jump"}), MenuTag.MenuJumpToStation, 0); if (!Interface.CurrentOptions.KioskMode) { //Don't allow quitting or customisation of the controls in kiosk mode - Items[1 + jump] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","exit"}), MenuTag.MenuExitToMainMenu, 0); - Items[2 + jump] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","customize_controls"}), MenuTag.MenuControls, 0); - Items[3 + jump] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","quit"}), MenuTag.MenuQuit, 0); + Items[1 + jump] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","exit"}), MenuTag.MenuExitToMainMenu, 0); + Items[2 + jump] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","customize_controls"}), MenuTag.MenuControls, 0); + Items[3 + jump] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","quit"}), MenuTag.MenuQuit, 0); } else { @@ -420,12 +420,12 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m // list available stations, selecting the next station as predefined choice jump = 0; // no jump found yet Items = new MenuEntry[menuItem + 1]; - Items[0] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","back"}), MenuTag.MenuBack, 0); + Items[0] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","back"}), MenuTag.MenuBack, 0); menuItem = 1; for (i = 0; i < Program.CurrentRoute.Stations.Length; i++) if (Program.CurrentRoute.Stations[i].PlayerStops() & Program.CurrentRoute.Stations[i].Stops.Length > 0) { - Items[menuItem] = new MenuCommand(Program.CurrentRoute.Stations[i].Name, MenuTag.JumpToStation, i); + Items[menuItem] = new MenuCommand(menu, Program.CurrentRoute.Stations[i].Name, MenuTag.JumpToStation, i); // if no preferred jump-to-station found yet and this station is // after the last station the user stopped at, select this item if (jump == 0 && i > TrainManagerBase.PlayerTrain.LastStation) @@ -439,17 +439,17 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m case MenuType.ExitToMainMenu: Items = new MenuEntry[3]; - Items[0] = new MenuCaption(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","exit_question"})); - Items[1] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","exit_no"}), MenuTag.MenuBack, 0); - Items[2] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","exit_yes"}), MenuTag.ExitToMainMenu, 0); + Items[0] = new MenuCaption(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","exit_question"})); + Items[1] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","exit_no"}), MenuTag.MenuBack, 0); + Items[2] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","exit_yes"}), MenuTag.ExitToMainMenu, 0); Selection = 1; break; case MenuType.Quit: // ask for quit confirmation Items = new MenuEntry[3]; - Items[0] = new MenuCaption(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","quit_question"})); - Items[1] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","quit_no"}), MenuTag.MenuBack, 0); - Items[2] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","quit_yes"}), MenuTag.Quit, 0); + Items[0] = new MenuCaption(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","quit_question"})); + Items[1] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","quit_no"}), MenuTag.MenuBack, 0); + Items[2] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","quit_yes"}), MenuTag.Quit, 0); Selection = 1; break; @@ -457,14 +457,14 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m //Refresh the joystick list Program.Joysticks.RefreshJoysticks(); Items = new MenuEntry[Interface.CurrentControls.Length + 2]; - Items[0] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","back"}), MenuTag.MenuBack, 0); - Items[1] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","reset"}), MenuTag.ControlReset, 0); + Items[0] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","back"}), MenuTag.MenuBack, 0); + Items[1] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","reset"}), MenuTag.ControlReset, 0); int ci = 2; for (i = 0; i < Interface.CurrentControls.Length; i++) { if (Interface.CurrentControls[i].Command != Translations.Command.None) { - Items[ci] = new MenuCommand(Interface.CurrentControls[i].Command.ToString(), MenuTag.Control, i); + Items[ci] = new MenuCommand(menu, Interface.CurrentControls[i].Command.ToString(), MenuTag.Control, i); ci++; } } @@ -480,19 +480,19 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m Items = new MenuEntry[4]; // get code name and description Control loadedControl = Interface.CurrentControls[data]; - Items[0] = new MenuCommand(loadedControl.Command + " - " + - Translations.CommandInfos[loadedControl.Command].Description, MenuTag.None, 0); + Items[0] = new MenuCommand(menu, loadedControl.Command + " - " + + Translations.CommandInfos[loadedControl.Command].Description, MenuTag.None, 0); // get assignment string str = GetControlDescription(data); - Items[1] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","assignment_current"}) + " " + str, MenuTag.None, 0); - Items[2] = new MenuCommand(" ", MenuTag.None, 0); - Items[3] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","assign"}), MenuTag.None, 0); + Items[1] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","assignment_current"}) + " " + str, MenuTag.None, 0); + Items[2] = new MenuCommand(menu, " ", MenuTag.None, 0); + Items[3] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","assign"}), MenuTag.None, 0); break; case MenuType.ControlReset: Items = new MenuEntry[3]; - Items[0] = new MenuCaption(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","reset_question"})); - Items[1] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","train_default_yes"}), MenuTag.Yes, 0); - Items[2] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","train_default_no"}), MenuTag.No, 0); + Items[0] = new MenuCaption(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","reset_question"})); + Items[1] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","train_default_yes"}), MenuTag.Yes, 0); + Items[2] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","train_default_no"}), MenuTag.No, 0); Selection = 1; break; case MenuType.TrainDefault: @@ -510,9 +510,9 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m if (canLoad) { Items = new MenuEntry[3]; - Items[0] = new MenuCaption(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","train_default"})); - Items[1] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","train_default_yes"}), MenuTag.Yes, 0); - Items[2] = new MenuCommand(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","train_default_no"}), MenuTag.No, 0); + Items[0] = new MenuCaption(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","train_default"})); + Items[1] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","train_default_yes"}), MenuTag.Yes, 0); + Items[2] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"menu","train_default_no"}), MenuTag.No, 0); Selection = 1; } else diff --git a/source/OpenBVE/Game/Menu/Menu.cs b/source/OpenBVE/Game/Menu/Menu.cs index 7ac2c67cf..de38bcf5d 100644 --- a/source/OpenBVE/Game/Menu/Menu.cs +++ b/source/OpenBVE/Game/Menu/Menu.cs @@ -57,7 +57,7 @@ MENU SYSTEM FIELDS MENU SYSTEM SINGLETON C'TOR *********************/ - private GameMenu() : base(Program.Renderer) + private GameMenu() : base(Program.Renderer, Interface.CurrentOptions) { } @@ -174,7 +174,7 @@ public override void PushMenu(MenuType type, int data = 0, bool replace = false { MaxWidth = Program.Renderer.Screen.Width / 2; } - Menus[CurrMenu] = new SingleMenu(type, data, MaxWidth); + Menus[CurrMenu] = new SingleMenu(this, type, data, MaxWidth); if (replace) { Menus[CurrMenu].Selection = 1; diff --git a/source/OpenBVE/Graphics/NewRenderer.cs b/source/OpenBVE/Graphics/NewRenderer.cs index ae94bfe71..f640019b8 100644 --- a/source/OpenBVE/Graphics/NewRenderer.cs +++ b/source/OpenBVE/Graphics/NewRenderer.cs @@ -501,6 +501,14 @@ public override void SetWindowState(OpenTK.WindowState windowState) } } + public override void SetWindowSize(int width, int height) + { + Program.currentGameWindow.Width = width; + Program.currentGameWindow.Height = height; + Screen.Width = width; + Screen.Height = height; + } + public NewRenderer(HostInterface CurrentHost, BaseOptions CurrentOptions, FileSystem FileSystem) : base(CurrentHost, CurrentOptions, FileSystem) { } diff --git a/source/OpenBVE/OpenBve.csproj b/source/OpenBVE/OpenBve.csproj index 2403fea84..11608ea02 100644 --- a/source/OpenBVE/OpenBve.csproj +++ b/source/OpenBVE/OpenBve.csproj @@ -144,7 +144,6 @@ AI.cs - From 74bbca218e97e0afe6d84114c8c169ffba67dbf6 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Wed, 4 Sep 2024 14:52:06 +0100 Subject: [PATCH 26/41] Implement options to Object Viewer Still requires viewer specific options (?) --- .../LibRender2/Menu/MenuEntries/MenuOption.cs | 6 ++-- source/ObjectViewer/Game/Menu.SingleMenu.cs | 20 +++++++++++ source/ObjectViewer/Game/Menu.cs | 17 +++++++--- source/ObjectViewer/Graphics/NewRendererS.cs | 22 +++++++++++- source/OpenBVE/Game/Menu/Menu.cs | 34 +++++++++---------- 5 files changed, 74 insertions(+), 25 deletions(-) diff --git a/source/LibRender2/Menu/MenuEntries/MenuOption.cs b/source/LibRender2/Menu/MenuEntries/MenuOption.cs index d40c85dea..73d5d8a27 100644 --- a/source/LibRender2/Menu/MenuEntries/MenuOption.cs +++ b/source/LibRender2/Menu/MenuEntries/MenuOption.cs @@ -145,12 +145,13 @@ public void Flip() } } } + BaseMenu.ComputePosition(); break; case OptionType.FullScreen: BaseMenu.CurrentOptions.FullscreenMode = !BaseMenu.CurrentOptions.FullscreenMode; - if (BaseMenu.CurrentOptions.FullscreenMode) + if (!BaseMenu.CurrentOptions.FullscreenMode) { - BaseMenu.Renderer.SetWindowState(WindowState.Fullscreen); + BaseMenu.Renderer.SetWindowState(WindowState.Normal); DisplayDevice.Default.RestoreResolution(); } else @@ -178,6 +179,7 @@ public void Flip() } } } + BaseMenu.ComputePosition(); break; case OptionType.Interpolation: BaseMenu.CurrentOptions.Interpolation = (InterpolationMode)CurrentlySelectedOption; diff --git a/source/ObjectViewer/Game/Menu.SingleMenu.cs b/source/ObjectViewer/Game/Menu.SingleMenu.cs index 64189188e..3a08e6abd 100644 --- a/source/ObjectViewer/Game/Menu.SingleMenu.cs +++ b/source/ObjectViewer/Game/Menu.SingleMenu.cs @@ -106,6 +106,26 @@ public SingleMenu(AbstractMenu menu, MenuType menuType, int data = 0, double Max Array.Resize(ref Items, totalEntries); Align = TextAlignment.TopLeft; break; + case MenuType.Options: + Items = new MenuEntry[8]; + Items[0] = new MenuCaption(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "panel", "options" })); + Items[1] = new MenuOption(menu, OptionType.ScreenResolution, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "resolution" }), Program.Renderer.Screen.AvailableResolutions.ToArray()); + Items[2] = new MenuOption(menu, OptionType.FullScreen, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "display_mode_fullscreen" }), new[] { "true", "false" }); + Items[3] = new MenuOption(menu, OptionType.Interpolation, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "quality_interpolation" }), new[] + { + Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_mode_nearest"}), + Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_mode_bilinear"}), + Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_mode_nearestmipmap"}), + Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_mode_bilinearmipmap"}), + Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_mode_trilinearmipmap"}), + Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_mode_anisotropic"}) + }); + Items[4] = new MenuOption(menu, OptionType.AnisotropicLevel, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "quality_interpolation_anisotropic_level" }), new[] { "0", "2", "4", "8", "16" }); + Items[5] = new MenuOption(menu, OptionType.AntialiasingLevel, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "quality_interpolation_antialiasing_level" }), new[] { "0", "2", "4", "8", "16" }); + Items[6] = new MenuOption(menu, OptionType.ViewingDistance, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "quality_distance_viewingdistance" }), new[] { "400", "600", "800", "1000", "1500", "2000" }); + Items[7] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "menu", "back" }), MenuTag.MenuBack, 0); + Align = TextAlignment.TopLeft; + break; } // compute menu extent diff --git a/source/ObjectViewer/Game/Menu.cs b/source/ObjectViewer/Game/Menu.cs index aface173f..242f1f081 100644 --- a/source/ObjectViewer/Game/Menu.cs +++ b/source/ObjectViewer/Game/Menu.cs @@ -192,6 +192,9 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed } GameMenu.Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); break; + case MenuTag.Options: + Instance.PushMenu(MenuType.Options); + break; case MenuTag.ObjectFile: currentFile = Path.CombineFile(SearchDirectory, menu.Items[menu.Selection].Text); Program.Files.Add(currentFile); @@ -203,6 +206,10 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed break; } } + else if (menu.Items[menu.Selection] is MenuOption opt) + { + opt.Flip(); + } break; } @@ -357,11 +364,11 @@ public override void Draw(double RealTimeElapsed) else Renderer.OpenGlString.Draw(MenuFont, menu.Items[i].DisplayText(TimeElapsed), new Vector2(itemX, itemY), menu.Align, ColourNormal, false); -// if (menu.Items[i] is MenuOption opt) -// { -// Renderer.OpenGlString.Draw(MenuFont, opt.CurrentOption.ToString(), new Vector2((menuMax.X - menuMin.X + 2.0f * Border.X) + 4.0f, itemY), -// menu.Align, backgroundColor, false); -// } + if (menu.Items[i] is MenuOption opt) + { + Renderer.OpenGlString.Draw(MenuFont, opt.CurrentOption.ToString(), new Vector2((menuMax.X - menuMin.X + 2.0f * Border.X) + 4.0f, itemY), + menu.Align, backgroundColor, false); + } itemY += lineHeight; if (menu.Items[i].Icon != null) { diff --git a/source/ObjectViewer/Graphics/NewRendererS.cs b/source/ObjectViewer/Graphics/NewRendererS.cs index 953213b97..318120598 100644 --- a/source/ObjectViewer/Graphics/NewRendererS.cs +++ b/source/ObjectViewer/Graphics/NewRendererS.cs @@ -16,7 +16,10 @@ using OpenBveApi.Math; using OpenBveApi.Objects; using OpenBveApi.Routes; +using OpenTK; using OpenTK.Graphics.OpenGL; +using Vector2 = OpenBveApi.Math.Vector2; +using Vector3 = OpenBveApi.Math.Vector3; namespace ObjectViewer.Graphics { @@ -388,8 +391,25 @@ private void RenderOverlays() // finalize PopMatrix(MatrixMode.Projection); PopMatrix(MatrixMode.Modelview); + } - + public override void SetWindowState(OpenTK.WindowState windowState) + { + Program.currentGameWindow.WindowState = windowState; + if (windowState == WindowState.Fullscreen) + { + // move origin appropriately + Program.currentGameWindow.X = 0; + Program.currentGameWindow.Y = 0; + } + } + + public override void SetWindowSize(int width, int height) + { + Program.currentGameWindow.Width = width; + Program.currentGameWindow.Height = height; + Screen.Width = width; + Screen.Height = height; } public NewRenderer(HostInterface CurrentHost, BaseOptions CurrentOptions, FileSystem FileSystem) : base(CurrentHost, CurrentOptions, FileSystem) diff --git a/source/OpenBVE/Game/Menu/Menu.cs b/source/OpenBVE/Game/Menu/Menu.cs index de38bcf5d..db37f0700 100644 --- a/source/OpenBVE/Game/Menu/Menu.cs +++ b/source/OpenBVE/Game/Menu/Menu.cs @@ -180,7 +180,7 @@ public override void PushMenu(MenuType type, int data = 0, bool replace = false Menus[CurrMenu].Selection = 1; } ComputePosition(); - Program.Renderer.CurrentInterface = TrainManager.PlayerTrain == null ? InterfaceType.GLMainMenu : InterfaceType.Menu; + Program.Renderer.CurrentInterface = TrainManagerBase.PlayerTrain == null ? InterfaceType.GLMainMenu : InterfaceType.Menu; } @@ -440,19 +440,19 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed { // menu management commands case MenuTag.MenuBack: // BACK TO PREVIOUS MENU - GameMenu.Instance.PopMenu(); + Instance.PopMenu(); break; case MenuTag.MenuJumpToStation: // TO STATIONS MENU - GameMenu.Instance.PushMenu(MenuType.JumpToStation); + Instance.PushMenu(MenuType.JumpToStation); break; case MenuTag.MenuExitToMainMenu: // TO EXIT MENU - GameMenu.Instance.PushMenu(MenuType.ExitToMainMenu); + Instance.PushMenu(MenuType.ExitToMainMenu); break; case MenuTag.MenuQuit: // TO QUIT MENU - GameMenu.Instance.PushMenu(MenuType.Quit); + Instance.PushMenu(MenuType.Quit); break; case MenuTag.MenuControls: // TO CONTROLS MENU - GameMenu.Instance.PushMenu(MenuType.Controls); + Instance.PushMenu(MenuType.Controls); break; case MenuTag.BackToSim: // OUT OF MENU BACK TO SIMULATION Reset(); @@ -461,7 +461,7 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed case MenuTag.Packages: if (Database.LoadDatabase(Program.FileSystem.PackageDatabaseFolder, currentDatabaseFile, out _)) { - GameMenu.Instance.PushMenu(MenuType.Packages); + Instance.PushMenu(MenuType.Packages); } break; @@ -539,16 +539,16 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed } break; case MenuTag.Options: - GameMenu.Instance.PushMenu(MenuType.Options); + Instance.PushMenu(MenuType.Options); break; case MenuTag.RouteList: // TO ROUTE LIST MENU - GameMenu.Instance.PushMenu(MenuType.RouteList); + Instance.PushMenu(MenuType.RouteList); routeDescriptionBox.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"errors","route_please_select"}); Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\please_select.png"), new TextureParameters(null, null), out routePictureBox.Texture); break; case MenuTag.Directory: // SHOWS THE LIST OF FILES IN THE SELECTED DIR SearchDirectory = SearchDirectory == string.Empty ? menu.Items[menu.Selection].Text : Path.CombineDirectory(SearchDirectory, menu.Items[menu.Selection].Text); - GameMenu.Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); break; case MenuTag.ParentDirectory: // SHOWS THE LIST OF FILES IN THE PARENT DIR if (string.IsNullOrEmpty(SearchDirectory)) @@ -567,7 +567,7 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed SearchDirectory = oldSearchDirectory; return; } - GameMenu.Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); break; case MenuTag.RouteFile: RoutefileState = RouteState.Loading; @@ -587,7 +587,7 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed { //enter folder SearchDirectory = SearchDirectory == string.Empty ? menu.Items[menu.Selection].Text : Path.CombineDirectory(SearchDirectory, menu.Items[menu.Selection].Text); - GameMenu.Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); } else { @@ -685,19 +685,19 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed menu.Items[2].Text = "Current Setting: " + Program.CurrentRoute.Switches[switchToToggle].CurrentlySetTrack; switchesFound = false; // as switch has been toggled, need to recalculate switches along route - GameMenu.Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); break; case MenuTag.PreviousSwitch: FoundSwitch fs = previousSwitches[0]; previousSwitches.RemoveAt(0); nextSwitches.Insert(0, fs); - GameMenu.Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); break; case MenuTag.NextSwitch: FoundSwitch ns = nextSwitches[0]; nextSwitches.RemoveAt(0); previousSwitches.Insert(0, ns); - GameMenu.Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); break; } } @@ -725,9 +725,9 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed public override void Draw(double RealTimeElapsed) { pluginKeepAliveTimer += RealTimeElapsed; - if (pluginKeepAliveTimer > 100000 && TrainManager.PlayerTrain != null && TrainManager.PlayerTrain.Plugin != null) + if (pluginKeepAliveTimer > 100000 && TrainManagerBase.PlayerTrain != null && TrainManagerBase.PlayerTrain.Plugin != null) { - TrainManager.PlayerTrain.Plugin.KeepAlive(); + TrainManagerBase.PlayerTrain.Plugin.KeepAlive(); pluginKeepAliveTimer = 0; } double TimeElapsed = RealTimeElapsed - lastTimeElapsed; From a031f1d77757cdadf4424dfba76cf7bce156dc8f Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Thu, 5 Sep 2024 09:47:54 +0100 Subject: [PATCH 27/41] More work, distinct object type icons --- assets/Menu/icon_object.png | Bin 5898 -> 5341 bytes assets/Menu/icon_wavefront.png | Bin 0 -> 1523 bytes assets/Menu/icon_xobject.png | Bin 0 -> 3827 bytes .../LibRender2/Menu/MenuEntries/MenuOption.cs | 26 +++++++++++++++++- source/ObjectViewer/Game/Menu.SingleMenu.cs | 22 ++++++++++++--- source/ObjectViewer/Game/Menu.cs | 2 +- 6 files changed, 44 insertions(+), 6 deletions(-) create mode 100644 assets/Menu/icon_wavefront.png create mode 100644 assets/Menu/icon_xobject.png diff --git a/assets/Menu/icon_object.png b/assets/Menu/icon_object.png index dfcc3b2ef7aec4d823f96e5879a0dd90a800a1ef..83530e6538b6f21a42ce84b89b51e8774ecca7df 100644 GIT binary patch literal 5341 zcmV<36e8=1P)G;8bE#I0SMH-eNmm!H#1b z<51)p8!(G~Wt&Sdg;@;3fLO#LwC}snHbS#c_jLEaopa4!Q>t>^s#_&IrhMz_={eQY z)qnMLz2Ezt^M2FK40D|09OpR4InHs8bDXzcdH$qTFaKuA+Sit!IC5mLn?F(nzbD3M z`&VE8!bdA_yzJO%mvloj)_Ld8FC#yt!;tRYKKcgc5o=9^{`;=kC)~{+5f;BED<4_< z`O)Ps-pbBhM9NUM9E?mMPFqA21hmGQR6a|+TxQ3UPhGca={Q7HVq8bk z+S!G`(9+UQHdkV7!zKp5^3_Gg7Ff2u#5aPPWg$~p+(HhO&teKW+(H2>o5szgdFhVZ zP)ZJ2c4|`CYSbwd11s`(=d;B?1;KvZScvoeCw{lk)n9+#1=zWHU1{4x_dis5`Wd^w zu|O!nk}kOv#I}VH25AJ!wm~WK`5Y&9m8b~_qL6Xl$Hgb8RS8Cq5X1(9p{@ZVP#UBF z1I-|sl~Vm$DsZhO!uCjITt0aAJoGu|=Yh|??*bfr?u8#8`q`tsZN&^Rg4lp#E40v9 zVT2U}22890P(tEKg9TJ=i@FH$EJLUb(gQ+C6iX~42;zvUR2VIZ;}~L%HXzY3Rfo9F zsZGt~#}8rFzV@l{Wsg5ryy%J*yay!jfz=N`^vUh_-g9MpR*-XDDq%=0B0^oITCL*i z7%e~|Ac_HSEk$=KOS|P#K+xoRq>Y6oZQ@LtFykUKk~k$Wu7zvAy9BN)upEK0NFL`M zMQ@8oPcFskLsiBP9kksyUc9fef4BF(IAGH=Pt4!?z=LvB5Qh$QY1ylu-x)p_ItP`vxH-!Zt|H!We-vU>P{2 zqr{};@wGSCaP?Fh*E({Z|ICx$06zBz72wF*yEAL=`uCsJUVO&uET+(wCZ!E^+u$2b zE!Jo>vL28L>Ih*IMIivjvLTZpHBqA^G;yq{hl+G488<$4OHv~d1VKy`#b^T})Ci$) zBq*tv)82~XNZvSkKKTQqJiT!{XEqe+Tead-!_PncSkw8J9#bnQj)6;iXWe=5?z=DR zO53!hj*P(q_kj4x75d1)$@af(eXboBLOrYfi>e~E)2jZCU<;+VRQ&`O|% zgh*p62?C@5*D+WYq!d^fN?wK&N;%5cT+49BY^GwL!Tkpq93EjwDXpA9FS+Tydw=wA z|9+RAaR)4a@SdypKJdUNEfZiVhu8=lp)qL-AB72H!cbAJMZB|mHTkhI!q#@`^G*Vz zF@70sOH?rhI7mMvQw@km%S4qb<-n(|48)4ifB`HTOy1SgxqwQXd53>gJU)d563g7FXzO)@$>!j7uXq%jzy zh=q-o5J@lw(1KIi^K=zb=nqr{b~WpkJ%?Gpo-cjq3<`7ShLe~4 z*_pkUUA1mTTA(&LVXwIBKYlg3?1?$e8HqumwZXD&q)>QTAY%wLY@PJk9>$z?%}1Hs zb&#%}60MmKS)W9P0T_t<7&GOgrvl<~fM2b$zg*^>dWg^wcsET_!{a6A}w&VK*a*1VK@xgP@W{Ua4`c*&Ia3N@Xc)ubmow;!1x+Xj8GEG zvyo{R1z2^TaxGxI7E!kZbs)(GN+4r{5`wwyoyd9fN!@e{%5?yVv=pA}5>#tcYd(>Q z*tKds-K7GZQ)6vIwiVy`=o8C-uN?6F-9NZ+=hB~krm4ZfwZSNfvLucJQbGmIhz=PF z0=8DFj5tN|-LqM-W+Pj|fbqIv&1fAtJCB@|#%fAo6&1!2#9>GnM3n0><3WU05=RJ9 zQjoS3X<=|MbT&4TPP?d^K8`J)&pi9nc-^b*Ed@8Ru&<+J^9v)xWROH%EFq{$i;dMOqFJ4^ z4)oDjYGi!8!jV0D@IG`N-s00)yK_GmFBw2pHAFEcju5_2qyxsP0dW8+r4SgTr!bbp zXhml+i|iR7{g)p@Nr7MYu~Qz>NQ$`v#(M z?zDPWPjV_8lLLPF&2QXr;O7rs(%z5(X@d~hF{BhIB``u@v>^^-Mk2$$T1ek1r&4Ne zB3mr7@Qelg`4#^)Np(#hx_}+)cd}{c1mRenXsC)mRL4J5B|2PY+t?&k1)-41^q z+Bd&6wEp#zk0}U!;mcp%H)VOL@uA5DmGL7g01RLQ0U)J9A($|V)suB}e?R@FFQmD( zm256Y%5%u&vUrY-%%m_V4!`^gCoYtHLCbnq+(B`myHF{ddD zANd5CE3QIF3BcQX-=0dB^74_itKvWqI3XOl5+!Qg}*YBiS)oXR9wb<%-Mb z=o_H5eHPhl1}OzX2$Te4BBF^=2Jg6&`Exs1)Zc+Qa+vtw5!UY;=D-vvX;4z4q{0=F zzQ#Na9bKgE{RyI}C22K)S6_GuFvJ=f3Pt9haT-T4hOxl|Y$CLyw{rF$+1pe&FrT3W0;R~q_jZi)`NPX}C!$$@g9NA0P znP<}6)k~?NfmF&vDRoo;DGf$Q>_Q{WS6d+w&MbS{ng6yX8IXedZd6fM!hB%^O3 zpQX{Ui9dA-*XaN{=_3@Y;2M!(#dcWM?R51g7X@HY zmW^du)76(p1(7-D%xXszo3JJ(N$uKAA?@LR@w0fBUV%vZEqSll!kgJ~SO_s{S$0Y2 zB&#P&D}$|*=l+kCfB+O=fS6brWK$=t7k-#6FFZ|WLmNWJM2^N_C?IKcBg|(%kLv10 z7(=Kd4nFx5d%t=cdD{>V9>S6aM+u6>44$Z>zx`$W(P5mAUW;?eVXa0$d6o4W|Acdruu_&e`!e|sR?tTA;KQV#xx7Q=nSqx@o{~z#o zAOF}jkv836*tO>%Yd3DCR;`iAq)^IA1QAk#5Xrq1iUbTGj&4$5(6)DJr6^~;%afR~~kL>L6dXm;)0#rpNDIrZd|ux*=`wkA%TI|n5sN?M5< zlv2c+!~sG8Mxca)kQP!YGCf6l2j<~kcoEG_&9u**hnp*+BcJhoyLsu>uVdD&LrIae z12IX&o>fX=OE8*gyGcNzkyx*-ptk=O-0ys=Z$?`H!vqEl0^7FmT!#u^xgOhg@1;_& zF?XO3gyQhv5K;;Xg#xbUVjvL&p};7FG+5H2wWXQHh63qqkzA<(mCmArDkD3#vEs+~ zQ+f6o99sbbEkGGVN8TgrC=ePWK?^~s(oA?cMiwk&;QD_c-Q0|}H8Uze;MWHY00PTW zi3mXyA|!-?&&0$87|)=Kh)0w?tMQYw|mBM7v7qiVW-H8Jd=&SCOL+A8m#KLrS{jR- z)YSvRAgaSND}bKP=-Pm#1i5!@U&y257@{~id!LwUS{lnwv}1JMi%Ae7}#CoLS?0R*Ln zM$TBYh(GzQ4NsaokEvRXD2{P$8>3@PY)}F)291DNPv-;)0;XRt5!J8NsMUQikjkdX ztk}VGYY+XlMwj1ONts(55i6LCCU#*wm3i zpaDxrw1j%Sj@B_Pt<4Cj&=`U+pj0YQsZLR^SAirwf)vvN07d|Y1Y?N85TiAgWhHxs z6oNvbNOw;kjm@oykx@!Q5@Sf|2no3FUTb@)vlcAk;tMXOrL6-oZ7HoyYDNV(GCFp| zXoF+f07z}XfRX|!tfU%BDI#HTGieqsUQGAU5Mx6lbd*YrlqZo=a+JgY97PyVLM8$@ zt_wgmpQm%q98%dL$>c#RDW^!N4A+1f_Rbp<5Ysm> z7&AR%Okb-a9~-DcBBG0puoM6Wz{HFU53_aSW;Si!%!zGY?GN(d=v7x=vkLgD6)Rr- z^lzS9_KCqmgEzdf@~v5GJ(m;b%%!`tlXN6>Hxa;+U^#B$vYp#EvvJ*e1_uw5$>w)9HJ0vbnK%FbKj;@E&N*kv zJHWTf<;mNB_=6u@J~(*j<_()Sp1WbwX8QXF=3p7If?j|Y181wGZV6c%=ad5*LRxEoQx1s&z6Hb`@y$@f0^<(ercZ71e zds<&<&Jp9gI?%1)-o88k(Z+ADXO-;CtjS*lQ0a}ANdJJFyv>^^P zK~N*`YZw7WN5A6`I|%XW0i8iWV>m|m`Ona}c`a8Ivxp^&=hSm+(o?ZST+jsAxQmYa~Q4*G79b?2%>nE+@ z2R=a%GC5gJHnA`W0F5>pf{@f$g+gVDQ{$L3L`dqb*Ku`3X0lA`mDgJ{|M~FuM<2ca z(PMYO40FzsB}2gNVHke@M?bv#@_h#m+`MYTrgPVB+|0Za`WcwrM?RZD8^CCUi6~bp zY}&blH{N`c7oL2QlY6>o%H~IclG>@K)oTO&_ltAR{U5W=zicCa z%)GSxh0?cg{n{=6bkj|Hzjn)iHxK^kKg{?3^)_?I?cZGU?OVV4rAHqA`2fKBwQIfa zeDy1z_~OT}U2{WQtNCUzW1em)n(*dpG~^j#~!Tyk6q}HH5!qU6$T72gXH~jqe#fxj(ufD`=|H6&W?p}J&mD*^V|DV|O v{By0lpLuL9GsAI?bDZNG=QzhX&T;-X3nEfP@f1~K00000NkvXXu0mjftZw)k literal 5898 zcmV+l7xn0gP)EX>4Tx04R}tkv&MmKpe$iTct%RMeHEzkfA!+MMVUcQpF-zC~bvS9ZW9$f+h_~ zii@M*T5#}VvFhOBtgC~oAP9bdI6F8gx=4xtOA0MwJUH&hyL*qjcYwE9Ws1=g0~FQN z(}}o{%dZOlR|GJE0n8yJGDAyd7PD|2U-$6v^)AY@+|T_v`sISb0FOW%W14OfZxGLH zni}VQ;xH?VGVwX_giaSEe&o93@Ehln&0d}v*0bq(;xMsL>SC#jSy@+zr->u7qEfy$ z=djFqi?dR#v-Umt3xfr9CBt=^qex&0Nu(e^LLC)UVIoSaN{WFr?Z;jG!?r&~E{R+f zFmf!Q1_h$+2mgcL-5SNINhc{72YO#D>thV??*grcWqlu8R_g@tJp)&2$6sp#v!A3l zI$Goi2yFuw*BwpT11@)fp(jn$MO*UG^cIW2`x$*x9vHj@`qrG@+WRy{D4^000SaNLh0L z04^f{04^f|c%?sf00007bV*G`2j~bJ5(hJGm?+->000?uMObu0Z*6U5Zgc=ca%Ew3 zWn>_CX>@2HM@dakSAh-}000!>Nkl@G2IMcoN-QnFg>WzAOk{%!i zLl6dG;ux@r6G$q?2FFQPoH&&Z?byb#LmYRPGtjOs$DMYk+%XQeF(k%;#@H=03j<;h z1_?9^jZXp%Ptu!*JDqd(-u=gY46amn*+eE(qOa=yx9_=kf9G3keQWIvr*RsmaT=#_ z8mDm@|4t!(UJu^%^kZiV=SoWJslH_^D&>yuSN=^B;GFe-_!pnMe&M;Nd@mD_X>CWp z>piRHk)N_jLjT|pL&GB&Ye}(x*tc}~EpI0R^uP208}GUErm6K${1y8TkSfQ#_Hi;o zoO=Oj9MfqmQ9eg~ex7~zKk%^^?!5K4>hp8EgK{|yg&GUOOa;%ImYHa#k<^ddFtgCo z*0s>FWZ-0!&CS296|m!pb?@5q?Qi_3{-ejdd^StN#LQ#xuX;b7S6+j_v7~>HkyYn# zc*D~?`+;A_c>?WuG@PKOH8RQ(6k1UE9IntpP$-~t8G>wvsI?8HI z+8E8}im{60!?s*7`DJH(xzM+){+26X|E{g2J$Kx8$HIdTd&|lN5(!!cv_xP$jSvp$ z1j_S3Df0Oi&gd&q6A-5fGmQoT4dPmrc$}V z>S^jCA=Hk27o{-`lB4( zI-r1{EeOdtjg}rJn<2>t$gIRf0vBikPZM~8AP{I@;4}oDAnz*%J3^WZ!R1j4c`(4?0opXRlC1^`~L_gkCH89sU-I`2edek+SH((Qt-&6EkNT%++J+ah*7h zNz5Oqndp{U1@I72OsSuk}LY7OSAF>#|ooTdzQ zl<|Gd=Cf9j?;qg79WS$cYzpm9zWFki-BuShwm&U}x5-5cc0-IQTElH3_Ze_} z{`On1edVsZzN9C{D1{O$1VUL>yRjvRQPCCl}n_Tyo>N-pCFE7s?{2J zn!Ve0Qt&j(t8;BN<(a?v;X~_BDFNFbeQ0psKiz#F`*uVf`H;GE)U72EiX;^n3)ToK zNz9Ik3Q5C~$8z1p!}N^rLp-$>`P>gtC5bCYD0!%y#`83})S;3(vod}sEV$4hz75IccEqWl0YJu+4iCIXuZ4$K=4I>GSuAEs&}CaZNa%%LjB zk&P-COWH7)*&69=jby$~HEl4KG?PKSPVi*bm$>70SeId2J^L; znOaI+3+mAH21+1}LkYpk?q1}`DxyF7G%D}`iPVZP2#BjSs?rns50pn$@ed1 z!{!~ll*G)`9h;}>$fbE?PX^rM&UzFvBlFQcokkHIw;F)bC39UdohV5gVe`oitCxf$ zoN#1>aP@g?*?$;O4$wt~-y+c&i}o8B8#7&vF)>6+5ei2(RD>Cc_BFl59CBco>_>hR zB?XOo11}1ZPEu?s;2h{|#FF752A2)dJ-mYQrSIhN?V}u;S|I<-qvtlBc<|4DW&*zd zU;pxkBmZ>!Ro$&wkRAwuXCP9bl)wprvksFOCR4{NwS=Lw&!N=bMy^=o{9kwnzj4j4 zkVr|}FI~>QZTs1|f0ksrPC8ztFF>V}V_ za|NVOm^3Am&0v6RHq&&9DDtgkdWTogJ21e&*{e{)L)`J=e$q+>f6McqAK&)lvwkK5 zmR@q{_j*74JOArsxFk8TP-QYrsfy-uBL!aIp?uA(^4LCC!yjHjTi*aJEiGg-5iQw> z?ygR9nG9Z62Zbx&&*rB#krwml&N5L?fuJ*k$@nBj5e6PI2nmA-Uj;-))0+)Ruls#6 z=l;Ut;KgB`!vY3{A7(%_yLllcMC%{?YCFfKKJ|spSbyp-}Sru`X{UyIXOAac%|AbgHmF&X0)Dg#A(ia_hqzqFQHf} zlZhgL5~He(o8@$EO%7<|&$mK6;l- z-F(ZpfBdEfBKO~UtDBpcr8+*z{IM|_V@FsxImW)xL*y^Gkmai{rlYfiLa~JJ`$#De zLLjBXi4>POYFjoje(NnW^Gn)FYBRn~Jk`$0uV1)w<-T4A53K8b!FH!i#_u+&? z(hR#=rHb!qoRUZj%2PNTVv#RkFjrhf%cbu|NP$3L(iGWfkO>q{Nt_c1XNc!& z=v)@51kO2>_UT?agsD~bMi*T8&7auBP5=4LH$&Rf(@`cWr52nsSQ|o;!xRPJP})Ol zjZz9J-#`H199U%#K?`ladKCx1{3UkR1YF{=n`}=vqS%I>og+FhN+A={__NOv{_-^lCBcFAG@b}gZ8s={n9|xS3F~l9 z;he%Mhi5?u@y|Z5N0(Y8!eEp`w)N6^#rt^a@dxQ`?Lt^X>RTL+0+Mo&;y!y5s&5eC z9EnXidjA6)`ohiRJ%<@PhL#Rr35vxmp{Qd2+kc@kHGzNqZ=?JW=bFEFN(u12fJWS$ zaaF1flvZffY+0pjGB1R{iRQKia`BHioNczW!V0VcwfbVF4<6+4{dXSDiT3h{7tAH?~9;Y}2&RGr|I>5GVFLKUVXX1Gt9bIjlv2q1U zNR(`np_IZ{aMm`;`IwKTYtZFAkmBiI8I!2M&SfX~Mu~0nkCn zp3y@r)N8C99s;2_J~ob&f(_+Ag}_Ib1cb+JI>O9e&V=}F$N(8p&z1^!qXnvYzqetzD%Wdh_lZ=r&%UnE0V7!O-O1LrY9$u zs?3u}A6nbV5B5{&DiioVOB!|7|Ie>uM9L8ivpBR?qzJ6`nLoLJl>TD0I!I430Yd49 zOJW29-}9-b38mIDJ>5OjYBi1?K1!ulBMdVHo`b@>QeMtO&0^ zi%uy4C#R-QI_vOtv!j&OfdeH4QfNHSLn%cn96>h2`KwpcKR(X%_#{h8B_`+R7VYut zCegjYs|eRTJJed^2f(1) zBWcQh(J(n{-(a;RLaD``!pB^7u-{GhY3(U4 zgYE6@&oAljet!E)dse@+cOSi7-3$!$Q!W%xQlb{)S~ZVD@s-3`1J2RW-a$uCFB8Wn zFvcLA!wCV_y)FkK5lSPZLZv8*SFgTiJ8;qW?z#JdojZ2iI66A|fxY|ph2_>(mJJQj+u21F1Xw3gQXz#zAW)*2 z{HVvY7qVDu7yq#M3AZj~bA7WiIGkJTF&5XVw1EfIY05jmLumEdJI5I&CnngvV;4Jj z?c$8Cu=aB~8~nhvA9?}!tqmKV`Qslwy6*SJj*Z>$+{R5kTf%@dR;;AIx0g&NLm>5H zTindbN`R2MS@W$09LCu<7|o`ul_<277_~U4T2z)v8d%qSyT%x_1nmbnYuLYc7dy6Y zV{Gg=*<5~qTetFlY)njAFZrr|W$EDkM?qb=p zVTStqDHV$NO5iClPN1a3iRN67#ZK|n?K@|2)?rPGwFZIZ4a!D15Q)Jh24}(HA*JHz z_RVZqx0ax_`>Ey2m;TNBuD@1+zZ@$_g#0L_reRCK0bE*#7Fk++Y>Gw z7-X=&pU$>60^h?4@R}C}789p?UBcF35=$J{h#NJW0B6&mP>2^Ng!P!-IHsITlic(f z%Dc93O)-a9vwB6nB^anroCw3V&iY$Mz#H+Q>#o}Zd~Cxr&wTFDb&vec_~gVV*FE`o zPe-|(mCJ_c@9QNSMkpx}vN=0=Rr=038gYX-PMDjUNBfE-jsc5x0^)>ddI4n;&M^k# zLA2?|c%eqk&EuZ_ai`k4^D9%c6Ym4w|F1&8YvHkG%{cJaNs@f!@4tS_)vp{ma^nlz zcV4<>$1X;eFJpM=5cyoTSp=L#xRm*Y1$OS=$8*m=&*S&s&shU~wB_=w9(oZTeSqM; z2MDB~E+n4Rpfy_AW-7H1Ps~tp0XAjsZF5ufjkxE3-@R(%#*H`3Oig}tVP-ZQ?Ca-U z@A)NGj;vts?w5FW!?PTCWt1a_UZ$^qXjfx)wtN1mAC*3^q>T$(3v@S9GRMbp#$uI3 zmU9HzEJ-Y>opWxzHoWXMaml5B*YlqD?|54h@G72M|9EM`lj}b^b8_+%p(h8Hj;vsE zdKw|cmPS3kXL#iqcU}9T>-TTlvL$@z`}cli=HS7P&ph(Tc|G+7&i6eo?kW&zN31-i z-+k4~3&X>ITUvebZQbv9=k(j|uJHf=dad*B``&kdWqx*|cX;HyhgPq-Z2$jj?VVr! z>gtJIyFT66wCUG=t-m#7`S3b@_PKvI_~GBXUkaJfi=TY_KBa!U(e#x+Hi5cvFEeBW+1=E^ls4Qh&a?w7rGOL_;- z^CIc_FEZ}e?Atl>yQYAv$kXoow^&@J{T3)_2wZX}KcIQxHm$E;KTbGtO`GS9h=Ssq zfM>HGB`3KxOq?+zM|k-ZhDDO+#Q$_MnK939bXt^b_d>J%ZNuN>E+^X^wn7F{jjO&T zu}R+%VnsE&BWyh7|9q#ov}@J$O5@&nk z0f(E3=by4!#MUl7efV;DB+E9pmpdGGGMcqKb7$Ci+;`25Y3wdJ>Ftkv8wBlCn96^B zS7CUxk5jEeI^q7G9tI^2_V24KSQ*>?ozhfzE3`X$Dyzg|m-ZVAEEL|ltOo`~N>lT9 znFqTaPQHHO*cjz-Is2o?hA&wRxeJb8J@I_ioYMx325AhhF8O_TP`@2=!q~w>qh8%NYe7bxdH&_ROXkO=+$$@S4+*{utv`_1+cvt%rpDpj+&YpP7=9~&#SaHh))q5RB(KTprjc_?SR&&`^d zUoNY`{j|63(?S`8KP?R}Q}^5O@^m;qyu;-`Kb4_azo>&N{v6}_xZQJN-%1AxT{<itt?J^1ob+WXiYe?_YedH|?x%uE=xVaMJ#)@#l`~_b-78a|TaWKbLh*2~7YCP~blR literal 0 HcmV?d00001 diff --git a/assets/Menu/icon_xobject.png b/assets/Menu/icon_xobject.png new file mode 100644 index 0000000000000000000000000000000000000000..6506e0c6ce038a2e1848e28e35495c099c4c029b GIT binary patch literal 3827 zcmV$P){yF;z4zEaDGxh&}mvid$44<_B=P-T7LZAvnfY*C&fxZRWKyobsiZ8zS;&0x4_uYS* zW!Z@Lo?E4bVVG=eZ2aR>Pd)WQyWQUEE5M_VK6>Q&=b!(?{&N;OL@4edIz5tLheXh%wFO!omJoeaQhXMKu zV5AxH5Mg0qfti^ZDwRq%D3{BETm(TFh9ZD5M#&3-oS4j`$c62N{;Z!UGKYw=yC4b` zN6Bkno=JshHk$zC&N90RpwJupK?rw4qX6iRgzkHF4i%~!-D3dSXTa7y$2I4R_ApUj z^per0`Vs4{#=Yn* zQoYq%`~3vnO^|-rt029ie&iY;M0*IT)xxHeclW!Oz~1WJE97qE`=K8}wf*|N7)Ssm zBBXNiT8xx%_cACD0TjE7(GN7&#zfW1}Drw zDbPz^tP<@as}Uj4F-?Oc?Yq5ucUJ9P(;4F z?8VFH`RlL#U9b1APXP6nlGn*h0ELM~s+AED07QAQ@^Gj}E!JmjEndp4(Jd}%l9HvF zz-Bv9V4Yflcb@V{%(<;snL9Ma@Yod2XLv+h0os?Iqn&J%#ESqoCIU2Ul{_kd@oY6V zC>BaoiX&jq2ms^pKEUr-<3mPA$GEz9g+q7M=yW2^oLs_pQb;pQjv%#!nI%dcX>KQm zBIb`wGku_nE5;m{{uIU_WF1aL7OP))!}98TY;81^{NNFw`44oj*_Fer0j z@m-pot2l2FZ{sw*Gy>?PZERZL_)MAhR86)iTAXiugeu61=8? zlLwXY+E|53VI;>mpL^m0=P#aO>FNqe;>j#n3z&d?`}gzk{lCK8=p?C)NvE~|D-i`A z)Z%yEHzGWirL_yxM+%gpQQ&fKAsna%^a>#O(f6)OZ75YwQYw`x1XY4CARq*zsymGY zJZr3PpQl!u;?R*P<`2&C##^s(`sAY2gklvI?mWnYM;~UWT<7%4_eryDKx>M6-)kKp z$=Vo-`MhUXy42*y-`&EdTfN>Nd==;>uS?g36B)%)glC-Q_Bs<|B}S?<7z`dT1X`rU z0y|+0V}DavO$_dTCmg zt3p^N$`KIh5-DG`(j?AhV2s#WX@bw*{s%NVOCr{2Z7v@hm7=PoHRP>J=wuDb(J)Y8 zb^8RRY@F9$ejl59oCWXtdS9;x5VUtSP>Bbzq;anRgKve^`(lG2K&%bO5+l37q-c2moihwi8XkV=5o{JP zQrj;Coky0l&_sZd@6ePfg~K_92uw&~TjJFmNYu!^J82h)ka*Xm9vzUMZ#CD+nx1dJ z`V*S#o}}e)nRs8&LwH~Tl(bmw=foufqC###kSi~;3qIzsZ zwrp{molV;5Him#7ocspge)H?BFSl8}(qZYmW#tkymmRJH_+7n!eFAio@3qqR89^mu zXfk7THph%%cp_vd$IRHB92mP#-wnj`scTCg*jeKAgABbV)MB}_-_HmGSs}m}9ys_E z`w#ACYOc)Ge1X~93{wX^wMkD{0dIW2!_~o$#DXBuPg%4WO5a+f4zybk=SY(bk43h% z4?a#i-N5;jdTEj$GQ&ITQ=iM)XO6ro%;g+ z^{qc)@qCBn3!aT-hmFBIaJFyZ8(07(uaIjD1O+2xYr}@&@f?#8GY9J|9Qk>MDpM>q z|3`L)#y~xsk=%A(A_wp|CzjN9D2CM?0StHpKwwH(9L@Gsw)~=Of~F^DxZ|Ef1i>QC zt`ZhudjsO8!?nSuDEWZ}(BrCI1#s426X>*zL_n5VzW9YNF*7quwK$6RvI(LTj>!5g z+{7~y{x~|h1?$^*QxtI`ssw=)K>{M8pePZO+AXXfrBO(8GWX8?x)j2#_6n_JSp+CXH4IW1#CoJ|NCZ@iEo^BSUv5yULzX}%_F(*O>3n?= zpvtKL68#1OV+caSGhaDM6h+MKpQTvz1 z{2KVaZMsSzs;GYH+lWd zm$-2D0!d=|;JvSM+mYM(^wGzum#2x72F>=mY@3x7c=^&3XD|%crkLF~&4=5kz#!O)oGPgzQuVNyN7}SDBkSS4##$+FG=He-ujV33LpCwHk z0G+tQ@zw`SjE%E@;y%i?F{u|@oeP?RAm1KBkTD<&uQD+ zdFMa>jbD2FDo_5_r!hoqHr5%bPvCJnXE$iOgv_PXN{1MkC=e2Kzsn513aAijjR}OD z2|b4o&tnT$h$4^oiFzET5#V>u>o?AG{?rot_Z=cKb$pNzmA&3Wh&BJw9d!vi>} z1X_#mVqxF(9LtMKSbJWbHn;%YeT6Xv%7t-OHx_%|=fr~c<;pWQHp9^D9HTQQa6wyN zhx)J09-Q}h=NKKD0ifc>TD#~8|g5x92 zuPsfX)l7DqU!iZQeeM}N1+@BKlbD_xTyN_>b^iF;;QN5SHc1k$vkBq;p1b)1Tvs^n zF_i`&eG>&39CZJM=^mos<_pkw1<-aYMM1RJ3a#iBrGJs^-&Y~SFk}zyMv0}TTLY(n z66qzj*A%!JD}$b9-_#l~IPt;B-$ViS9_E4@HD{Wp1Ai`{M_@Oauwrme_kV8j{Gi9; zI?-= 0 && item < menu.Items.Length && menu.Items[item] is MenuCommand /* || menu.Items[item] is MenuOption) */) + if (item >= 0 && item < menu.Items.Length && menu.Items[item] is MenuCommand || menu.Items[item] is MenuOption) { if (item < visibleItems + menu.TopItem + 1) { From 8c00ce108511db4fd87d723b6bcb95e899b088c7 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Thu, 5 Sep 2024 10:23:05 +0100 Subject: [PATCH 28/41] Implement error list --- source/LibRender2/LibRender2.csproj | 1 + .../Menu/MenuEntries/MenuEntry.Error.cs | 35 +++++++++++++++++++ source/LibRender2/Menu/MenuTag.cs | 4 ++- source/LibRender2/Menu/MenuType.cs | 4 ++- source/ObjectViewer/Game/Menu.SingleMenu.cs | 28 +++++++++++++-- source/ObjectViewer/Game/Menu.cs | 21 ++++++----- 6 files changed, 80 insertions(+), 13 deletions(-) create mode 100644 source/LibRender2/Menu/MenuEntries/MenuEntry.Error.cs diff --git a/source/LibRender2/LibRender2.csproj b/source/LibRender2/LibRender2.csproj index cb9bb0ed3..c3500a061 100644 --- a/source/LibRender2/LibRender2.csproj +++ b/source/LibRender2/LibRender2.csproj @@ -64,6 +64,7 @@ + diff --git a/source/LibRender2/Menu/MenuEntries/MenuEntry.Error.cs b/source/LibRender2/Menu/MenuEntries/MenuEntry.Error.cs new file mode 100644 index 000000000..2ef39fa87 --- /dev/null +++ b/source/LibRender2/Menu/MenuEntries/MenuEntry.Error.cs @@ -0,0 +1,35 @@ +//Simplified BSD License (BSD-2-Clause) +// +//Copyright (c) 2024, Maurizo M. Gavioli, The OpenBVE Project +// +//Redistribution and use in source and binary forms, with or without +//modification, are permitted provided that the following conditions are met: +// +//1. Redistributions of source code must retain the above copyright notice, this +// list of conditions and the following disclaimer. +//2. Redistributions in binary form must reproduce the above copyright notice, +// this list of conditions and the following disclaimer in the documentation +// and/or other materials provided with the distribution. +// +//THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND +//ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED +//WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE +//DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE LIABLE FOR +//ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES +//(INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; +//LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND +//ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT +//(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS +//SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. + +namespace LibRender2.Menu +{ + /// A caption to be rendered at the top of the menu + public class MenuErrorDisplay : MenuEntry + { + public MenuErrorDisplay(AbstractMenu menu, string Text) : base(menu) + { + this.Text = Text; + } + } +} diff --git a/source/LibRender2/Menu/MenuTag.cs b/source/LibRender2/Menu/MenuTag.cs index d0feda31b..26dd1cff8 100644 --- a/source/LibRender2/Menu/MenuTag.cs +++ b/source/LibRender2/Menu/MenuTag.cs @@ -99,6 +99,8 @@ public enum MenuTag /// Displays a list of objects ObjectList, /// Selects an object file to load - ObjectFile + ObjectFile, + /// Shows the list of current errors + ErrorList } } diff --git a/source/LibRender2/Menu/MenuType.cs b/source/LibRender2/Menu/MenuType.cs index 98561b02d..4a2f42aac 100644 --- a/source/LibRender2/Menu/MenuType.cs +++ b/source/LibRender2/Menu/MenuType.cs @@ -68,6 +68,8 @@ public enum MenuType /// A menu allowing switch settings to be changed ChangeSwitch, /// Displays a list of object files - ObjectList + ObjectList, + /// Displays the current list of errors + ErrorList } } diff --git a/source/ObjectViewer/Game/Menu.SingleMenu.cs b/source/ObjectViewer/Game/Menu.SingleMenu.cs index 28b338d50..71c3f89a1 100644 --- a/source/ObjectViewer/Game/Menu.SingleMenu.cs +++ b/source/ObjectViewer/Game/Menu.SingleMenu.cs @@ -28,10 +28,11 @@ public SingleMenu(AbstractMenu menu, MenuType menuType, int data = 0, double Max switch (menuType) { case MenuType.GameStart: // top level menu - Items = new MenuEntry[3]; + Items = new MenuEntry[4]; Items[0] = new MenuCommand(menu, "Open Object File", MenuTag.ObjectList, 0); Items[1] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "title" }), MenuTag.Options, 0); - Items[2] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "menu", "quit" }), MenuTag.MenuQuit, 0); + Items[2] = new MenuCommand(menu, "Show Errors", MenuTag.ErrorList, 0); + Items[3] = new MenuCommand(menu, "Close", MenuTag.BackToSim, 0); if (string.IsNullOrEmpty(SearchDirectory)) { SearchDirectory = Program.FileSystem.InitialRouteFolder; @@ -140,6 +141,29 @@ public SingleMenu(AbstractMenu menu, MenuType menuType, int data = 0, double Max Items[7] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "menu", "back" }), MenuTag.MenuBack, 0); Align = TextAlignment.TopLeft; break; + case MenuType.ErrorList: + Items = new MenuEntry[Interface.LogMessages.Count + 2]; + Items[0] = Interface.LogMessages.Count == 0 ? new MenuCaption(menu, "No current errors / warnings.") : new MenuCaption(menu, Interface.LogMessages.Count + " total errors / warnings."); + + for (int j = 0; j < Interface.LogMessages.Count; j++) + { + Items[j + 1] = new MenuErrorDisplay(menu, Interface.LogMessages[j].Text); + switch (Interface.LogMessages[j].Type) + { + case MessageType.Information: + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_information.png"), new TextureParameters(null, null), out Items[j + 1].Icon); + break; + case MessageType.Warning: + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_warning.png"), new TextureParameters(null, null), out Items[j + 1].Icon); + break; + case MessageType.Error: + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_error.png"), new TextureParameters(null, null), out Items[j + 1].Icon); + break; + } + } + Items[Items.Length -1] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "menu", "back" }), MenuTag.MenuBack, 0); + Align = TextAlignment.TopLeft; + break; } // compute menu extent diff --git a/source/ObjectViewer/Game/Menu.cs b/source/ObjectViewer/Game/Menu.cs index eb56633bc..4c9ddc67d 100644 --- a/source/ObjectViewer/Game/Menu.cs +++ b/source/ObjectViewer/Game/Menu.cs @@ -146,32 +146,35 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed { // menu management commands case MenuTag.MenuBack: // BACK TO PREVIOUS MENU - GameMenu.Instance.PopMenu(); + Instance.PopMenu(); break; case MenuTag.MenuJumpToStation: // TO STATIONS MENU - GameMenu.Instance.PushMenu(MenuType.JumpToStation); + Instance.PushMenu(MenuType.JumpToStation); break; case MenuTag.MenuExitToMainMenu: // TO EXIT MENU - GameMenu.Instance.PushMenu(MenuType.ExitToMainMenu); + Instance.PushMenu(MenuType.ExitToMainMenu); break; case MenuTag.MenuQuit: // TO QUIT MENU - GameMenu.Instance.PushMenu(MenuType.Quit); + Instance.PushMenu(MenuType.Quit); break; case MenuTag.MenuControls: // TO CONTROLS MENU - GameMenu.Instance.PushMenu(MenuType.Controls); + Instance.PushMenu(MenuType.Controls); break; case MenuTag.BackToSim: // OUT OF MENU BACK TO SIMULATION Reset(); Renderer.CurrentInterface = InterfaceType.Normal; break; case MenuTag.ObjectList: // TO OBJECT LIST MENU - GameMenu.Instance.PushMenu(MenuType.ObjectList); + Instance.PushMenu(MenuType.ObjectList); fileTextBox.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "errors", "route_please_select" }); Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\please_select.png"), new TextureParameters(null, null), out filePictureBox.Texture); break; + case MenuTag.ErrorList: + Instance.PushMenu(MenuType.ErrorList); + break; case MenuTag.Directory: // SHOWS THE LIST OF FILES IN THE SELECTED DIR SearchDirectory = SearchDirectory == string.Empty ? menu.Items[menu.Selection].Text : Path.CombineDirectory(SearchDirectory, menu.Items[menu.Selection].Text); - GameMenu.Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); break; case MenuTag.ParentDirectory: // SHOWS THE LIST OF FILES IN THE PARENT DIR if (string.IsNullOrEmpty(SearchDirectory)) @@ -190,7 +193,7 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed SearchDirectory = oldSearchDirectory; return; } - GameMenu.Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); break; case MenuTag.Options: Instance.PushMenu(MenuType.Options); @@ -251,7 +254,7 @@ public override bool ProcessMouseMove(int x, int y) int item = (int)((y - topItemY) / lineHeight + menu.TopItem); // if the mouse is above a command item, select it - if (item >= 0 && item < menu.Items.Length && menu.Items[item] is MenuCommand || menu.Items[item] is MenuOption) + if (item >= 0 && item < menu.Items.Length && (menu.Items[item] is MenuCommand || menu.Items[item] is MenuOption)) { if (item < visibleItems + menu.TopItem + 1) { From 7f9f253924de513f58e1a58a33b3eba0830ff9fd Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Fri, 6 Sep 2024 10:42:47 +0100 Subject: [PATCH 29/41] Finish implementing overlays, remove testing hacks from Object Viewer --- source/ObjectViewer/Game/Menu.SingleMenu.cs | 1 + source/ObjectViewer/Graphics/NewRendererS.cs | 85 ++++++++++++++------ source/ObjectViewer/ProgramS.cs | 41 +++++++--- 3 files changed, 89 insertions(+), 38 deletions(-) diff --git a/source/ObjectViewer/Game/Menu.SingleMenu.cs b/source/ObjectViewer/Game/Menu.SingleMenu.cs index 71c3f89a1..4495b8c4d 100644 --- a/source/ObjectViewer/Game/Menu.SingleMenu.cs +++ b/source/ObjectViewer/Game/Menu.SingleMenu.cs @@ -102,6 +102,7 @@ public SingleMenu(AbstractMenu menu, MenuType menuType, int data = 0, double Max { case ".csv": case ".b3d": + case ".animated": Items[totalEntries] = new MenuCommand(menu, fileName, MenuTag.ObjectFile, 0); Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_object.png"), new TextureParameters(null, null), out Items[totalEntries].Icon); totalEntries++; diff --git a/source/ObjectViewer/Graphics/NewRendererS.cs b/source/ObjectViewer/Graphics/NewRendererS.cs index 318120598..b6b1524e9 100644 --- a/source/ObjectViewer/Graphics/NewRendererS.cs +++ b/source/ObjectViewer/Graphics/NewRendererS.cs @@ -1,4 +1,5 @@ -using System.Collections.Generic; +using System; +using System.Collections.Generic; using System.Globalization; using System.Linq; using System.Windows.Forms; @@ -269,38 +270,52 @@ private void RenderOverlays() if (VisibleObjects.Objects.Count == 0 && ObjectManager.AnimatedWorldObjectsUsed == 0) { - keys = new[] { new[] { "F7" }, new[] { "F8" }, new[] { "F10" } }; - Keys.Render(4, 4, 20, Fonts.SmallFont, keys); - OpenGlString.Draw(Fonts.SmallFont, "Open one or more objects", new Vector2(32, 4), TextAlignment.TopLeft, TextColor); - OpenGlString.Draw(Fonts.SmallFont, "Display the options window", new Vector2(32, 24), TextAlignment.TopLeft, TextColor); - OpenGlString.Draw(Fonts.SmallFont, "Display the train settings window", new Vector2(32, 44), TextAlignment.TopLeft, TextColor); - OpenGlString.Draw(Fonts.SmallFont, $"v{Application.ProductVersion}", new Vector2(Screen.Width - 8, Screen.Height - 20), TextAlignment.TopLeft, TextColor); + int errorPos; + if (Program.CurrentHost.Platform == HostPlatform.AppleOSX && IntPtr.Size != 4) + { + keys = new[] { new[] { "esc" }}; + Keys.Render(4, 4, 20, Fonts.SmallFont, keys); + OpenGlString.Draw(Fonts.SmallFont, "Display the menu", new Vector2(32, 4), TextAlignment.TopLeft, TextColor); + OpenGlString.Draw(Fonts.SmallFont, $"v{Application.ProductVersion}", new Vector2(Screen.Width - 8, Screen.Height - 20), TextAlignment.TopLeft, TextColor); + errorPos = 24; + } + else + { + keys = new[] { new[] { "F7" }, new[] { "F8" }, new[] { "F10" } }; + Keys.Render(4, 4, 20, Fonts.SmallFont, keys); + OpenGlString.Draw(Fonts.SmallFont, "Open one or more objects", new Vector2(32, 4), TextAlignment.TopLeft, TextColor); + OpenGlString.Draw(Fonts.SmallFont, "Display the options window", new Vector2(32, 24), TextAlignment.TopLeft, TextColor); + OpenGlString.Draw(Fonts.SmallFont, "Display the train settings window", new Vector2(32, 44), TextAlignment.TopLeft, TextColor); + OpenGlString.Draw(Fonts.SmallFont, $"v{Application.ProductVersion}", new Vector2(Screen.Width - 8, Screen.Height - 20), TextAlignment.TopLeft, TextColor); + errorPos = 64; + } + if (Interface.LogMessages.Count == 1) { - Keys.Render(4, 64, 20, Fonts.SmallFont, new[] { new[] { "F9" } }); + Keys.Render(4, errorPos, 20, Fonts.SmallFont, new[] { new[] { "F9" } }); if (Interface.LogMessages[0].Type != MessageType.Information) { - OpenGlString.Draw(Fonts.SmallFont, "Display the 1 error message recently generated.", new Vector2(32, 64), TextAlignment.TopLeft, new Color128(1.0f, 0.5f, 0.5f)); + OpenGlString.Draw(Fonts.SmallFont, "Display the 1 error message recently generated.", new Vector2(32, errorPos), TextAlignment.TopLeft, new Color128(1.0f, 0.5f, 0.5f)); } else { //If all of our messages are information, then print the message text in grey - OpenGlString.Draw(Fonts.SmallFont, "Display the 1 message recently generated.", new Vector2(32, 64), TextAlignment.TopLeft, TextColor); + OpenGlString.Draw(Fonts.SmallFont, "Display the 1 message recently generated.", new Vector2(32, errorPos), TextAlignment.TopLeft, TextColor); } } else if (Interface.LogMessages.Count > 1) { - Keys.Render(4, 64, 20, Fonts.SmallFont, new[] { new[] { "F9" } }); + Keys.Render(4, errorPos, 20, Fonts.SmallFont, new[] { new[] { "F9" } }); bool error = Interface.LogMessages.Any(x => x.Type != MessageType.Information); if (error) { - OpenGlString.Draw(Fonts.SmallFont, $"Display the {Interface.LogMessages.Count.ToString(culture)} error messages recently generated.", new Vector2(32, 64), TextAlignment.TopLeft, new Color128(1.0f, 0.5f, 0.5f)); + OpenGlString.Draw(Fonts.SmallFont, $"Display the {Interface.LogMessages.Count.ToString(culture)} error messages recently generated.", new Vector2(32, errorPos), TextAlignment.TopLeft, new Color128(1.0f, 0.5f, 0.5f)); } else { - OpenGlString.Draw(Fonts.SmallFont, $"Display the {Interface.LogMessages.Count.ToString(culture)} messages recently generated.", new Vector2(32, 64), TextAlignment.TopLeft, TextColor); + OpenGlString.Draw(Fonts.SmallFont, $"Display the {Interface.LogMessages.Count.ToString(culture)} messages recently generated.", new Vector2(32, errorPos), TextAlignment.TopLeft, TextColor); } } } @@ -308,13 +323,31 @@ private void RenderOverlays() { OpenGlString.Draw(Fonts.SmallFont, $"Position: {Camera.AbsolutePosition.X.ToString("0.00", culture)}, {Camera.AbsolutePosition.Y.ToString("0.00", culture)}, {Camera.AbsolutePosition.Z.ToString("0.00", culture)}", new Vector2((int)(0.5 * Screen.Width - 88), 4), TextAlignment.TopLeft, TextColor); OpenGlString.Draw(Fonts.SmallFont, ForceLegacyOpenGL ? $"Renderer: Old (GL 1.2)- GL 3.0 not available" : $"Renderer: {(AvailableNewRenderer ? "New (GL 3.0)" : "Old (GL 1.2)")}", new Vector2((int)(0.5 * Screen.Width - 88), 24), TextAlignment.TopLeft, Color128.White); - keys = new[] { new[] { "F5" }, new[] { "F7" }, new[] { "del" }, new[] { "F8" }, new[] { "F10" } }; - Keys.Render(4, 4, 24, Fonts.SmallFont, keys); - OpenGlString.Draw(Fonts.SmallFont, "Reload the currently open objects", new Vector2(32, 4), TextAlignment.TopLeft, TextColor); - OpenGlString.Draw(Fonts.SmallFont, "Open additional objects", new Vector2(32, 24), TextAlignment.TopLeft, TextColor); - OpenGlString.Draw(Fonts.SmallFont, "Clear currently open objects", new Vector2(32, 44), TextAlignment.TopLeft, TextColor); - OpenGlString.Draw(Fonts.SmallFont, "Display the options window", new Vector2(32, 64), TextAlignment.TopLeft, TextColor); - OpenGlString.Draw(Fonts.SmallFont, "Display the train settings window", new Vector2(32, 84), TextAlignment.TopLeft, TextColor); + + int errorPos; + if (Program.CurrentHost.Platform == HostPlatform.AppleOSX && IntPtr.Size != 4) + { + keys = new[] { new[] { "F5" }, new[] { "esc" }, new[] { "del" }}; + Keys.Render(4, 4, 24, Fonts.SmallFont, keys); + OpenGlString.Draw(Fonts.SmallFont, "Reload the currently open objects", new Vector2(32, 4), TextAlignment.TopLeft, TextColor); + OpenGlString.Draw(Fonts.SmallFont, "Show the menu", new Vector2(32, 24), TextAlignment.TopLeft, TextColor); + OpenGlString.Draw(Fonts.SmallFont, "Clear currently open objects", new Vector2(32, 44), TextAlignment.TopLeft, TextColor); + errorPos = 72; + } + else + { + OpenGlString.Draw(Fonts.SmallFont, $"Position: {Camera.AbsolutePosition.X.ToString("0.00", culture)}, {Camera.AbsolutePosition.Y.ToString("0.00", culture)}, {Camera.AbsolutePosition.Z.ToString("0.00", culture)}", new Vector2((int)(0.5 * Screen.Width - 88), 4), TextAlignment.TopLeft, TextColor); + OpenGlString.Draw(Fonts.SmallFont, ForceLegacyOpenGL ? $"Renderer: Old (GL 1.2)- GL 3.0 not available" : $"Renderer: {(AvailableNewRenderer ? "New (GL 3.0)" : "Old (GL 1.2)")}", new Vector2((int)(0.5 * Screen.Width - 88), 24), TextAlignment.TopLeft, Color128.White); + keys = new[] { new[] { "F5" }, new[] { "F7" }, new[] { "del" }, new[] { "F8" }, new[] { "F10" } }; + Keys.Render(4, 4, 24, Fonts.SmallFont, keys); + OpenGlString.Draw(Fonts.SmallFont, "Reload the currently open objects", new Vector2(32, 4), TextAlignment.TopLeft, TextColor); + OpenGlString.Draw(Fonts.SmallFont, "Open additional objects", new Vector2(32, 24), TextAlignment.TopLeft, TextColor); + OpenGlString.Draw(Fonts.SmallFont, "Clear currently open objects", new Vector2(32, 44), TextAlignment.TopLeft, TextColor); + OpenGlString.Draw(Fonts.SmallFont, "Display the options window", new Vector2(32, 64), TextAlignment.TopLeft, TextColor); + OpenGlString.Draw(Fonts.SmallFont, "Display the train settings window", new Vector2(32, 84), TextAlignment.TopLeft, TextColor); + errorPos = 112; + } + keys = new[] { new[] { "F" }, new[] { "N" }, new[] { "L" }, new[] { "G" }, new[] { "B" }, new[] { "I" }, new[] { "R" } }; Keys.Render(Screen.Width - 20, 4, 16, Fonts.SmallFont, keys); @@ -346,30 +379,30 @@ private void RenderOverlays() if (Interface.LogMessages.Count == 1) { - Keys.Render(4, 112, 20, Fonts.SmallFont, new[] { new[] { "F9" } }); + Keys.Render(4, errorPos, 20, Fonts.SmallFont, new[] { new[] { "F9" } }); if (Interface.LogMessages[0].Type != MessageType.Information) { - OpenGlString.Draw(Fonts.SmallFont, "Display the 1 error message recently generated.", new Vector2(32, 112), TextAlignment.TopLeft, new Color128(1.0f, 0.5f, 0.5f)); + OpenGlString.Draw(Fonts.SmallFont, "Display the 1 error message recently generated.", new Vector2(32, errorPos), TextAlignment.TopLeft, new Color128(1.0f, 0.5f, 0.5f)); } else { //If all of our messages are information, then print the message text in grey - OpenGlString.Draw(Fonts.SmallFont, "Display the 1 message recently generated.", new Vector2(32, 112), TextAlignment.TopLeft, TextColor); + OpenGlString.Draw(Fonts.SmallFont, "Display the 1 message recently generated.", new Vector2(32, errorPos), TextAlignment.TopLeft, TextColor); } } else if (Interface.LogMessages.Count > 1) { - Keys.Render(4, 112, 20, Fonts.SmallFont, new[] { new[] { "F9" } }); + Keys.Render(4, errorPos, 20, Fonts.SmallFont, new[] { new[] { "F9" } }); bool error = Interface.LogMessages.Any(x => x.Type != MessageType.Information); if (error) { - OpenGlString.Draw(Fonts.SmallFont, $"Display the {Interface.LogMessages.Count.ToString(culture)} error messages recently generated.", new Vector2(32, 112), TextAlignment.TopLeft, new Color128(1.0f, 0.5f, 0.5f)); + OpenGlString.Draw(Fonts.SmallFont, $"Display the {Interface.LogMessages.Count.ToString(culture)} error messages recently generated.", new Vector2(32, errorPos), TextAlignment.TopLeft, new Color128(1.0f, 0.5f, 0.5f)); } else { - OpenGlString.Draw(Fonts.SmallFont, $"Display the {Interface.LogMessages.Count.ToString(culture)} messages recently generated.", new Vector2(32, 112), TextAlignment.TopLeft, TextColor); + OpenGlString.Draw(Fonts.SmallFont, $"Display the {Interface.LogMessages.Count.ToString(culture)} messages recently generated.", new Vector2(32, errorPos), TextAlignment.TopLeft, TextColor); } } diff --git a/source/ObjectViewer/ProgramS.cs b/source/ObjectViewer/ProgramS.cs index c2950ec68..f08204bad 100644 --- a/source/ObjectViewer/ProgramS.cs +++ b/source/ObjectViewer/ProgramS.cs @@ -387,7 +387,6 @@ internal static void KeyDown(object sender, KeyboardKeyEventArgs e) { switch (e.Key) { - case Key.LShift: case Key.RShift: ShiftPressed = true; @@ -398,13 +397,8 @@ internal static void KeyDown(object sender, KeyboardKeyEventArgs e) break; case Key.F7: { - if (/* Program.CurrentHost.Platform == HostPlatform.AppleOSX && **TEMP** */IntPtr.Size != 4) + if (Program.CurrentHost.Platform == HostPlatform.AppleOSX && IntPtr.Size != 4) { - if (Program.Renderer.CurrentInterface != InterfaceType.Menu) - { - Program.Renderer.CurrentInterface = InterfaceType.Menu; - Game.Menu.PushMenu(MenuType.GameStart); - } return; } OpenFileDialog Dialog = new OpenFileDialog @@ -464,7 +458,13 @@ internal static void KeyDown(object sender, KeyboardKeyEventArgs e) } break; case Key.F9: - if (Interface.LogMessages.Count != 0) + if (Program.CurrentHost.Platform == HostPlatform.AppleOSX && IntPtr.Size != 4) + { + Program.Renderer.CurrentInterface = InterfaceType.Menu; + Game.Menu.PushMenu(MenuType.ErrorList); + return; + } + if (Interface.LogMessages.Count != 0) { formMessages.ShowMessages(); Application.DoEvents(); @@ -545,11 +545,19 @@ internal static void KeyDown(object sender, KeyboardKeyEventArgs e) Renderer.OptionInterface = !Renderer.OptionInterface; break; case Key.F8: - formOptions.ShowOptions(); + if (Program.CurrentHost.Platform == HostPlatform.AppleOSX && IntPtr.Size != 4) + { + return; + } + formOptions.ShowOptions(); Application.DoEvents(); break; case Key.F10: - formTrain.ShowTrainSettings(); + if (Program.CurrentHost.Platform == HostPlatform.AppleOSX && IntPtr.Size != 4) + { + return; + } + formTrain.ShowTrainSettings(); break; case Key.G: case Key.C: @@ -590,10 +598,19 @@ internal static void KeyDown(object sender, KeyboardKeyEventArgs e) } break; case Key.Escape: - if (Renderer.CurrentInterface != InterfaceType.Normal) + if (Program.CurrentHost.Platform == HostPlatform.AppleOSX && IntPtr.Size != 4) { - Game.Menu.ProcessCommand(Translations.Command.MenuBack, 0); + if (Renderer.CurrentInterface != InterfaceType.Normal) + { + Game.Menu.ProcessCommand(Translations.Command.MenuBack, 0); + } + else + { + Program.Renderer.CurrentInterface = InterfaceType.Menu; + Game.Menu.PushMenu(MenuType.GameStart); + } } + break; } } From 12ea89f5bcb9f43b9ced84874c8ae0a1c7254b82 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Mon, 9 Sep 2024 12:54:37 +0100 Subject: [PATCH 30/41] Supply elapsed time so messages etc. scroll properly --- source/ObjectViewer/Graphics/NewRendererS.cs | 8 ++++---- source/ObjectViewer/System/GameWindow.cs | 2 +- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/source/ObjectViewer/Graphics/NewRendererS.cs b/source/ObjectViewer/Graphics/NewRendererS.cs index b6b1524e9..306e67184 100644 --- a/source/ObjectViewer/Graphics/NewRendererS.cs +++ b/source/ObjectViewer/Graphics/NewRendererS.cs @@ -95,7 +95,7 @@ internal void ApplyBackgroundColor(byte red, byte green, byte blue) } // render scene - internal void RenderScene() + internal void RenderScene(double timeElapsed) { lastObjectState = null; if (AvailableNewRenderer) @@ -249,11 +249,11 @@ internal void RenderScene() UnsetAlphaFunc(); GL.Disable(EnableCap.DepthTest); SetBlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); //FIXME: Remove when text switches between two renderer types - RenderOverlays(); + RenderOverlays(timeElapsed); OptionLighting = true; } - private void RenderOverlays() + private void RenderOverlays(double timeElapsed) { //Initialize openGL SetBlendFunc(); @@ -419,7 +419,7 @@ private void RenderOverlays() } if (CurrentInterface == InterfaceType.Menu) { - Game.Menu.Draw(0); + Game.Menu.Draw(timeElapsed); } // finalize PopMatrix(MatrixMode.Projection); diff --git a/source/ObjectViewer/System/GameWindow.cs b/source/ObjectViewer/System/GameWindow.cs index 396650efa..5216bd84b 100644 --- a/source/ObjectViewer/System/GameWindow.cs +++ b/source/ObjectViewer/System/GameWindow.cs @@ -251,7 +251,7 @@ protected override void OnRenderFrame(FrameEventArgs e) } Program.Renderer.Lighting.Initialize(); - Program.Renderer.RenderScene(); + Program.Renderer.RenderScene(timeElapsed); SwapBuffers(); RenderRealTimeElapsed = 0.0; From 996dcb6676b33748df1060aa884b517957aff101 Mon Sep 17 00:00:00 2001 From: LX86 Date: Mon, 9 Sep 2024 19:54:54 +0800 Subject: [PATCH 31/41] Update zh-HK Translation (#1063) --- assets/Languages/zh-HK.xlf | 716 +++++++++++++++++++++++++++++-------- 1 file changed, 560 insertions(+), 156 deletions(-) diff --git a/assets/Languages/zh-HK.xlf b/assets/Languages/zh-HK.xlf index 6dbb55144..2186eefac 100644 --- a/assets/Languages/zh-HK.xlf +++ b/assets/Languages/zh-HK.xlf @@ -30,6 +30,7 @@ About + 關於OpenBVE OpenBVE is a free and open-source multi-platform train simulator, featuring support for 2D and 3D cabs and scenery.\r\n\r\nThis program was initially developed by Michelle, and is released into the public domain where legally possible. @@ -51,9 +52,11 @@ Report Problem + 回報問題 This function will create a zip archive on your Desktop, containing the previous Simulation log and Crash log (If any), along with a text file containing the brief description of the problem entered below.\r\n\r\nPlease post this on the discussion board, or create a new issue on Github. + 此功能將在你的桌面上建立一個 zip 檔案,當中包含上次的模擬日誌和崩潰日誌(如有),以及下面輸入的簡要描述。儲存後請將此檔案發佈到討論區,或在 Github 上建立新Issue。 View... @@ -115,7 +118,7 @@ Visit official homepage - 官方網站 + 前往官方網站 Check for updates @@ -139,6 +142,7 @@ Close + 關閉 Package Management @@ -282,11 +286,13 @@ The .Turn command and the .Switch command may not be used in the same route. + .Turn 和 .Switch 指令不能在同一路線中使用。 Start new game + 開始新遊戲 Route @@ -366,6 +372,7 @@ Route default + 路線預設設定 Use the train suggested by the route @@ -405,6 +412,7 @@ Start + 開始遊戲 Mode of driving: @@ -416,11 +424,13 @@ The default train is not currently installed:\r\n\r\n [train]\r\n\r\n It may be downloaded at:\r\n\r\n + 未能找到此路線的預設列車: [train]\r\n\r\n你可在以下連結下載:\r\n\r\n Review last game + 回顧上次遊戲 Conditions @@ -472,7 +482,7 @@ Maximum: - 最高: + 最高得分: Ratio: @@ -534,6 +544,7 @@ Package Management + 擴展包管理 Proceed... @@ -753,6 +764,7 @@ Enter Package Details + 輸入擴展包的資料 Please enter a package name. @@ -1002,6 +1014,7 @@ Customize controls + 控制設定 Command @@ -1009,6 +1022,7 @@ Type + 類型 Digital @@ -1052,6 +1066,7 @@ Reset the current control configuration to the defaults? + 要重設控制設定嗎? Reset to defaults @@ -1323,6 +1338,7 @@ Options + 選項 Language @@ -1586,7 +1602,7 @@ Timetable mode: - 時間表模式: + 時間表模式: None @@ -1806,9 +1822,11 @@ Route: + 路線: Train: + 列車: Date: @@ -1820,6 +1838,7 @@ Score: + 分數: Rating: @@ -1873,6 +1892,7 @@ Save report... + 儲存報告 Ignore @@ -2000,6 +2020,7 @@ Loading. Please wait... + 載入中,請稍候…… @@ -2069,18 +2090,23 @@ Please switch to exterior view to uncouple. + 請切換至車外視覺以脱鈎車廂。 Unable to uncouple this car. + 未能脱鈎此車廂。 Uncoupling the rear of car number + 已脱離後方車鈎,在車卡 Uncoupling the front of car number + 已脱鈎前方車鈎,在車卡 This coupler is fixed, and cannot uncouple. + 此車鈎是固定的,不能脱鈎。 @@ -2138,6 +2164,7 @@ Your rating: + 你的評分: @@ -2183,11 +2210,13 @@ Unknown + 未知 In-Game Menu + 遊戲菜單 PAUSE @@ -2255,7 +2284,7 @@ Joystick (Not currently connected) - N/A + 控制桿 (未連接) Positive @@ -2267,7 +2296,7 @@ Current assignment: - 目前分配: + 目前分配: Do you wish to use the default train? @@ -2355,6 +2384,7 @@ P + P N @@ -2362,6 +2392,7 @@ B + B L @@ -2405,6 +2436,7 @@ Score:\x20 + 分數:\x20 @@ -2434,9 +2466,11 @@ Decreases the locomotive brake by one notch + 把機動列車的制動減少一級 Increases the locomotive brake by one notch + 把機動列車的制動增加一級 Controls brake for trains with two handles on half of a joystick axis @@ -2484,7 +2518,7 @@ Hold Brake - Hold Brake + 抑速制動 Moves reverser forward by one notch @@ -2896,53 +2930,69 @@ Accessibility: Audibly announces the current speed. + 無障礙: 廣播現時速度 Accessibility: Audibly announces the next signal distance and aspect. + 無障礙: 廣播下一盞訊號燈的燈號和距離 Accessibility: Audibly announces the the next station name and distance. + 無障礙: 廣播下一站名稱和距離 Uncouples the front coupler for the selected car. + 脱離目前車卡的前車鈎 Uncouples the rear coupler for the selected car. + 脱離目前車卡的後車鈎 Shows the change switch menu + 顯示道岔切換菜單 0 + 0 1 + 1 2 + 2 3 + 3 4 + 4 5 + 5 6 + 6 7 + 7 8 + 8 9 + 9 Ampersand @@ -2958,11 +3008,11 @@ Backquote - Backquote (`) + ` Backslash - Backslash (\\) + \\ Backspace @@ -2974,7 +3024,7 @@ Capslock - Capslock + Caps Lock Caret @@ -3002,6 +3052,7 @@ Down + Down End @@ -3177,38 +3228,39 @@ Left Alt - Left Alt + 左 Alt Left Ctrl - Left Ctrl + 左 Ctrl Left + Left Left bracket - Left bracket ([) + [ Left parenthesis - Left parantheses (() + ( Less - Less (<) + < Left Meta - Left Meta (◇) + 左 Meta (◇) Left Shift - Left Shift + 左 Shift Left Application - Left Application + 左 Application Menu @@ -3216,22 +3268,23 @@ Minus - Minus (-) + - Alt Gr + Alt Gr Numlock - Numlock + Num Lock Page down - 下頁 + Page down Page up - 上頁 + Page up Pause @@ -3239,14 +3292,15 @@ Period - Period (.) + . Plus - Plus (+) + + Power + Power Print @@ -3254,23 +3308,23 @@ Question - Question (?) + ? Quote - Quote (') + ' Quote double - Quote double ('') + " Right Alt - Right Alt + 右 Alt Right Ctrl - Right Ctrl + 右 Ctrl Return @@ -3278,38 +3332,39 @@ Right + Right Right bracket - Right bracket (]) + ] Right parenthesis - Right parentheses ()) + ) Right Meta - Right Meta (◇) + 右 Meta (◇) Right Shift - Right Shift + 右 Shift Right Application - Right Application + 右 Application Scrolllock - Scrolllock + Scroll Lock Semicolon - Semicolon + ; Slash - Slash (/) + / Space @@ -3325,10 +3380,11 @@ Underscore - Underscore (_) + _ Up + Up A @@ -3609,32 +3665,41 @@ Reverser: [notch] + 方向控制桿: [notch] A2 + A2 ATS + ATS Select a Switch To Change: + 請選擇道岔: Selected Switch: + 已選擇道岔: Current Setting: + 開通方向: Distance from Player: + 與玩家的距離: Zoom In + 放大 Zoom Out + 縮小 @@ -3646,10 +3711,11 @@ Open... - 打開... + 開啓... Save + 儲存 Save as... @@ -3657,6 +3723,7 @@ Close + 關閉 Do you want to save data before creating a new train? @@ -3690,98 +3757,101 @@ CoefficientOfStaticFriction: - CoefficientOfStaticFriction: + 靜摩擦係數: CoefficientOfRollingResistance: - CoefficientOfRollingResistance: + 滾動摩擦係數: AerodynamicDragCoefficient: - AerodynamicDragCoefficient: + 空氣阻力係數: Delay - Delay + 延遲 DelayPowerUp - DelayPowerUp + 動力增加 DelayPowerDown - DelayPowerDown + 動力减少 DelayBrakeUp - DelayBrakeUp + 煞車增加 DelayBrakeDown - DelayBrakeDown + 煞車減少 Set - Set + 設定 Notch - Notch + 級位 Save + 儲存 Cancel + 取消 Move - Move + 速率 JerkPowerUp: - JerkPowerUp: + 動力增加: JerkPowerDown: - JerkPowerDown: + 動力減少: JerkBrakeUp: - JerkBrakeUp: + 煞車增加: JerkBrakeDown: - JerkBrakeDown: + 煞車減少: BrakeCylinderUp: - BrakeCylinderUp: + 煞車風缸充氣: BrakeCylinderDown: - BrakeCylinderDown: + 煞車風缸充氣: Brake + 制動 BrakeType: - BrakeType: + 煞車類型: BrakeControlSystem: - BrakeControlSystem: + 煞車控制系统: BrakeControlSpeed: - BrakeControlSpeed: + 煞車控制速度: Electromagnetic straight air brake @@ -3815,23 +3885,23 @@ BrakeCylinderServiceMaximumPressure: - BrakeCylinderServiceMaximumPressure: + 煞車風缸常用最大壓力: BrakeCylinderEmergencyMaximumPressure: - BrakeCylinderEmergencyMaximumPressure: + 煞車風缸緊急煞車最大壓力: MainReservoirMinimumPressure: - MainReservoirMinimumPressure: + 主風缸最小壓力: MainReservoirMaximumPressure: - MainReservoirMaximumPressure: + 主風缸最大壓力: BrakePipeNormalPressure: - BrakePipeNormalPressure: + 煞車管正常壓力: @@ -3841,26 +3911,27 @@ HandleType: + 控制桿類型: PowerNotches: - PowerNotches: + 動力控制級數: BrakeNotches: - BrakeNotches: + 煞車控制級數: DriverPowerNotches: - DriverPowerNotches: + 司機可用的動力級數: DriverBrakeNotches: - DriverBrakeNotches: + 司機可用的煞車級數: PowerNotchReduceSteps: - PowerNotchReduceSteps: + 動力控制桿動作分段: Separated @@ -3876,127 +3947,129 @@ Separated (Reverser Interlocked) - 分隔 (反向器連鎖) + 分隔 (方向控制桿連鎖) BrakeNotches must be at least 1 if HoldBrake is set. - 如果HoldBrake沒有設置, BrakeNotches 一定至少為1 + 如有安裝抑速煞車, 就必須至少有1個煞車級位。 DriverPowerNotches must be less than or equal to PowerNotches. - DriverPowerNotches 一定要少過或等於 PowerNotches。 + "司機可用的動力級數" 一定要少過或等於 "動力控制級數"。 DriverBrakeNotches must be less than or equal to BrakeNotches. - DriverBrakeNotches 一定要少過或等於 BrakeNotches。 + "司機可用的煞車級數" 一定要少過或等於 "煞車控制級數"。 Cab - Cab + 駕駛室 DriverCar: - DriverCar: + 駕駛室所在車卡: DriverCar must be less than NumberOfMotorCars + NumberOfTrailerCars. - DriverCar 一定要少過 NumberOfMotorCars + NumberOfTrailerCars. + DriverCar 數值要少過 NumberOfMotorCars + NumberOfTrailerCars. Car - Car + 車輛 MotorCarMass: - MotorCarMass: + 動力車卡重量: NumberOfMotorCars: - NumberOfMotorCars: + 動力車卡數量: TrailerCarMass: - TrailerCarMass: + 無動力車卡重量: NumberOfTrailerCars: - NumberOfTrailerCars: + 無動力車卡數量: LengthOfACar: - LengthOfACar: + 車卡長度: FrontCarIsMotorCar: - FrontCarIsMotorCar: + 第一卡是動力車卡: WidthOfACar: - WidthOfACar: + 車廂寬度: HeightOfACar: - HeightOfACar: + 車廂高度: CenterOfGravityHeight: - CenterOfGravityHeight: + 重心高度: ExposedFrontalArea: - ExposedFrontalArea: + 暴露的前端面積: UnexposedFrontalArea: - UnexposedFrontalArea: + 未暴露的前端面積 NumberOfTrailerCars must be at least 1 if FrontCarIsAMotorCar is not set. - 如果FrontCarIsAMotorCar沒有設置, NumberOfTrailerCars 一定至少為1 + 如果沒有設定FrontCarIsAMotorCar, NumberOfTrailerCars 一定至少為1 。 Device + 裝置: ConstSpeed: - ConstSpeed: + 定速設備: HoldBrake: + 抑速煞車: ReAdhesionDevice: - ReAdhesionDevice: + 防滑設備: PassAlarm: - PassAlarm: + 停車鈴: DoorOpenMode: - DoorOpenMode: + 車門開啟模式: DoorCloseMode: - DoorCloseMode: + 車門關閉模式: DoorWidth: - DoorWidth: + 車門闊度: DoorMaxTolerance: - DoorMaxTolerance: + 車門最大偏差: None - None + 沒有 Manual switching @@ -4046,9 +4119,11 @@ Acceleration + 加速 Notch: + 級位: Data @@ -4082,30 +4157,31 @@ SoundIndex: - SoundIndex: + 聲音索引: Pitch - Pitch + 音調 Volume - Volume + 音量 None - None + 沒有 Preview + 預覽 Ypitch - Ypitch + Y 音調 Yvolume - Yvolume + Y 音量 Xmin: @@ -4113,28 +4189,31 @@ Xmax: + Xmax: Left + Right + In - In + 放大 Out - Out + 縮小 YmaxPitch: - YmaxPitch: + Ymax 音調: YmaxVolume: - YmaxVolume: + Ymax 聲量: @@ -4144,93 +4223,95 @@ Please note: Features found on this page may require the following minimum version of OpenBVE: - 注意: 本頁看到的功能至少需要以下的OpenBVE版本: + 請注意: 本頁顯示的功能需要至少以下的OpenBVE版本: Locomotive Brake - Locomotive Brake + 機車制動 BrakeType: - BrakeType: + 煞車類型: Notches: - Notches: + 動力控制級數: DelayUp: - DelayUp: + 增加延遲: DelayDown: - DelayDown: + 減少延遲: Type: - Type: + 類型: Set - Set + 設置 Not fitted - Not fitted + 沒有安裝 Notched air brake - Notched air brake + 等级空氣製動器 Air brake with partial release - Air brake with partial release + 三壓力機構自動空氣製動 Combined - Combined + 聯控 Independent - Independent + 獨立 Blocking - Blocking + 阻塞 DelayLocoBrakeUp - DelayLocoBrakeUp + 機車煞車增加延遲 DelayLocoBrakeDown - DelayLocoBrakeDown + 機車煞車減少延遲 Miscellaneous Features + 雜項 Handle behaviour on EB: - Handle behaviour on EB: + 緊急制動時控制桿的動作: No Action - No Action + 無動作 Return Power to neutral - Return Power to neutral + 將電源和反向器恢復至中性 Return Reverser to neutral - Return Reverser to neutral + 將電源和反向器恢復至中性 Return Power and Reverser to neutral - Return Power and Reverser to neutral + 將電源和反向器恢復至中性 Language + 語言 @@ -4239,60 +4320,76 @@ File + 檔案 New + Open... + 開啓... Save + 儲存 Save as... + 另存為... Import... + 匯入... Export... + 匯出... Exit + 關閉 You have attempted to open a train.\r\nThese cannot be opened directly-\r\nPlease use the import function to import this train into TrainEditor2. - 您嘗試打開列車數據。 \n\n 但TrainEditor2不能直接讀取列車資料。 \n\n 請使用導入(Import)功能將列車資料導入到TrainEditor2格式。 + TrainEditor2不能直接讀取列車資料。 \n\n 請使用導入(Import)功能將列車資料導入到TrainEditor2格式。 Do you want to save the current file before creating a new one? + 您要在創建新列車前儲存目前的檔案嗎? Do you want to save the current file before opening another file? + 您要在開啓其他列車前儲存目前的檔案嗎? Do you want to save the current file before closing? + 您要在關閉本程式前儲存目前的檔案嗎? Language + 語言 Up + Down + Add + 添加 Remove + 移除 Copy @@ -4300,14 +4397,17 @@ Set... + 設定... Open... + 開啓... Train + 列車 General @@ -4327,23 +4427,29 @@ HandleType + 控制桿類型 Separated + 分開 Combined + 聯控 Separated (Interlocked) + 分隔 (連鎖) Separated (Reverser Interlocked) + 分隔 (方向控制桿連鎖) EbHandleBehaviour + 緊急制動時控制桿的動作: No action @@ -4351,21 +4457,25 @@ Return power to neutral + 將動力回復至中性 Return reverser to neutral + 將方向控制桿回復至中性 Return power and reverser to neutral - 將電源和反向器恢復至中性 + 將動力和方向控制桿回復至中性 LocoBrakeHandleType + 機車煞車類型 Combined + 聯控 Independent @@ -4378,59 +4488,76 @@ Handle + 控制桿 PowerNotches + 動力控制級數 BrakeNotches + 煞車控制級數 PowerNotchReduceSteps + 動力控制桿動作分段 DriverPowerNotches + 司機可用的動力級數 DriverBrakeNotches + 司機可用的煞車級數 LocoBrakeNotches + 機車煞車級數 BrakeNotches must be at least 1 if HoldBrake is set. + 如有安裝抑速煞車, 就必須至少有1個煞車級位。 DriverPowerNotches must be less than or equal to PowerNotches. + "司機可用的動力級數" 一定要少過或等於 "動力控制級數"。 DriverBrakeNotches must be less than or equal to BrakeNotches. + "司機可用的煞車級數" 一定要少過或等於 "煞車控制級數"。 Cab + 駕駛室 X + X Y + Y Z + Z DriverCar + 駕駛室所在車卡 Ats + Ats None + 沒有 ATS-SN @@ -4444,89 +4571,115 @@ Atc + Atc None + 沒有 Manual switching + 手動切換 Automatic switching + 自動切換 ReAdhesionDevice + 防滑設備 None + 沒有 Type A (instant) + Type A (即時) Type B (slow) + Type B (緩慢) Type C (medium) + Type C (適中) Type D (fast) + Type D (快速) PassAlarm + 停車鈴: None + 沒有 Single + 單一 Looping + 重複 DoorOpenMode + 車門開啟模式 DoorCloseMode + 車門關閉模式 Semi-automatic + 半自動 Automatic + 全自動 Manual + 手動 Device + 裝置 Eb + 列車警醒設備 (Deadman) ConstSpeed + 定速設備 HoldBrake + 抑速煞車 DoorWidth + 車門闊度 DoorMaxTolerance + 車門最大偏差 General settings + 一般設定 @@ -4534,29 +4687,32 @@ Axles + FrontAxle - FrontAxle + 前軸距離 RearAxle - RearAxle + 後軸距離 RearAxle must be less than FrontAxle. + "後軸距離" 必須小過 "前軸距離" General + 一般 IsMotorCar - IsMotorCar + 是動力車卡 Mass - 質量 + 重量 Length @@ -4572,28 +4728,31 @@ CenterOfGravityHeight + 重心高度 ExposedFrontalArea + 暴露的前端面積 UnexposedFrontalArea + 未暴露的前端面積 DefinedAxles - DefinedAxles + 應用軸 FrontBogie - FrontBogie + 前轉向架 RearBogie - RearBogie + 後轉向架 LoadingSway - LoadingSway + 裝載時搖擺 Reversed @@ -4607,64 +4766,82 @@ Performance + 性能 Deceleration + 減速 CoefficientOfStaticFriction + 靜摩擦係數 CoefficientOfRollingResistance + 滾動摩擦係數 AerodynamicDragCoefficient + 空氣阻力係數 Move + 速率 JerkPowerUp + 功率增加 JerkPowerDown + 功率減少 JerkBrakeUp + 煞車增加 JerkBrakeDown + 煞車減少 BrakeCylinderUp + 煞車風缸充氣 BrakeCylinderDown + 煞車風缸充氣 BrakeType + 煞車類型 Electromagnetic straight air brake + 直通式空氣製動 Electro-pneumatic air brake without brake pipe + 電控空氣製動 Air brake with partial release feature + 三壓力機構自動空氣製動 LocoBrakeType + 機車煞車類型 Not fitted + 沒有安裝 Notched air brake @@ -4672,92 +4849,116 @@ Air brake with partial release + 三壓力機構自動空氣製動 BrakeControlSystem + 煞車控制系统 None + 沒有 Closing electromagnetic valve + 電磁關斷閥 Delay-including control + 延遲補償控制 Brake + 煞車 BrakeControlSpeed - BrakeControlSpeed + 煞車控制速度 Pressure + 壓力 BrakeCylinderServiceMaximumPressure + 煞車風缸常用最大壓力 BrakeCylinderEmergencyMaximumPressure + 煞車風缸緊急煞車最大壓力 MainReservoirMinimumPressure + 主風缸最小壓力 MainReservoirMaximumPressure + 主風缸最大壓力 BrakePipeNormalPressure + 煞車管正常壓力 Edit entry + 編輯項目 Up + Down + Delay + 延遲 Power + 動力 Brake + 煞車 LocoBrake + 機車煞車 Notch + 級位: Value + 數值 ElectricBrake + 電動煞車 Car settings + 車卡設定 Parameter + 參數 a0 @@ -4777,36 +4978,41 @@ e (2.0) + 指數 (2.0) Preview + 預覽 Subtract deceleration due to air and rolling resistance + 減去由於空氣與滾動摩擦產生的阻力 X + X Y + Y x-min - x-最低 + x-min x-max - x-最高 + x-max y-min - y-最低 + y-min y-max - y-最高 + y-max Zoom In @@ -4818,13 +5024,16 @@ Reset + 重置 Acceleration settings + 加速度設定 Notch + 級位 @@ -4832,6 +5041,7 @@ Edit + 編輯 Undo @@ -4847,6 +5057,7 @@ Copy + 複製 Paste @@ -4858,34 +5069,43 @@ Delete + 刪除 View + 顯示 Power + 動力 Brake + 煞車 Track + 音軌 Input + 編輯器 Pitch + 音調 Volume + 音量 Sound source index + 聲音索引 None @@ -4895,6 +5115,7 @@ Tool + 工具 Select @@ -4902,6 +5123,7 @@ Move + 移動 Dot @@ -4916,6 +5138,7 @@ View setting + 顯示設定 x-min(Velocity) @@ -4943,35 +5166,44 @@ Zoom In + 放大 Zoom Out + 縮小 Reset + 重置 Direct input + 放置頂點 x coordinate + X 位置 y coordinate + Y 位置 Dot + Move + 移動 Sound source setting + 聲源設定 Running sound @@ -4979,11 +5211,13 @@ Track + 音軌 Area setting + 播放範圍設定 Loop playback @@ -4995,6 +5229,7 @@ Acceleration + 加速 Swap @@ -5003,6 +5238,7 @@ Playback setting + 電機音播放 Playback @@ -5010,6 +5246,7 @@ Pause + 暫停 Stop @@ -5019,6 +5256,7 @@ Vertex information + 頂點參數 Velocity @@ -5026,71 +5264,90 @@ Pitch + 音調 Volume + 音量 Sound source index + 聲音索引 Type + 類型 Power + 動力 Brake + 煞車 Track + 音軌 Mode + 模式 Pitch + 音調 Volume + 音量 Sound source index + 聲音索引 Tool + 工具 Select + 選擇 Move + 速率 Dot + Line + Velocity + 速率 Pitch + 音調 Volume + 音量 @@ -5102,12 +5359,14 @@ Motor sound settings + 編輯馬達音 General + 一般 Min @@ -5120,6 +5379,7 @@ Coupler settings + 車鉤設定 @@ -5127,36 +5387,46 @@ Center origin + 中心點 X + X Y + Y Track origin + 軌道交點 X + X Y + Y This + 駕駛室 Resolution + 解像度 Left + 左邊 Right + 右邊 Top @@ -5168,20 +5438,21 @@ DaytimeImage - DaytimeImage + 日間圖片 NighttimeImage - NighttimeImage + 夜間圖片 TransparentColor - TransparentColor + 去地顏色 Screen + 屏幕 Number @@ -5196,66 +5467,82 @@ Location + 位置 X + X Y + Y PilotLamp + 指示燈 Subject - Subject + 物件 DaytimeImage + 日間圖片 NighttimeImage + 夜間圖片 TransparentColor + 去地顏色 Layer + 圖層 Location + 位置 X + X Y + Y Origin + 源點 X + X Y + Y Needle + 指示針 Subject + 物件 DefinedRadius - DefinedRadius + 應用半徑 Radius @@ -5263,9 +5550,11 @@ DaytimeImage + 日間圖片 NighttimeImage + 夜間圖片 Color @@ -5273,18 +5562,19 @@ TransparentColor + 去地顏色 DefinedOrigin - DefinedOrigin + 應用原點 InitialAngle - InitialAngle + 開始角度 LastAngle - LastAngle + 終止角度 Minimum @@ -5296,19 +5586,19 @@ DefinedNaturalFreq - DefinedNaturalFreq + 使用自然頻率 NaturalFreq - NaturalFreq + 自然頻率 DefiedDampingRatio - DefiedDampingRatio + 使用阻尼 DampingRatio - DampingRatio + 阻尼比值 Backstop @@ -5320,37 +5610,47 @@ Layer + 圖層 Location + 位置 X + X Y + Y DigitalNumber + 數碼數字 Subject + 物件 DaytimeImage + 日間圖片 NighttimeImage + 夜間圖片 TransparentColor + 去地顏色 Layer + 圖層 Interval @@ -5361,37 +5661,48 @@ Location + 位置 X + X Y + Y DigitalGauge + 數碼測量儀 Subject + 物件 Radius + 半徑 Color + 顏色 InitialAngle + 開始角度 LastAngle + 終止角度 Minimum + 最低 Maximum + 最高 Step @@ -5399,119 +5710,151 @@ Layer + 圖層 Location + 位置 X + X Y + Y Direction + 方向 X + X Y + Y LinearGauge + 線性測量儀 Subject + 物件 DaytimeImage + 日間圖片 NighttimeImage + 夜間圖片 TransparentColor + 去地顏色 Minimum + 最低 Maximum + 最高 Width + 寬度 Layer + 圖層 Location + 位置 X + X Y + Y Timetable + 時間表 Height + 高度 Width + 寬度 TransparentColor + 去地顏色 Layer + 圖層 Location + 位置 X + X Y + Y Size + 大小 X + X Y + Y Touch + 觸按範圍 JumpScreen - JumpScreen + 跳轉螢幕 SoundIndex + 聲音索引 Command @@ -5519,74 +5862,92 @@ CommandOption - CommandOption + 指令選項 Sound and command + 聲音及指令 Layer + 圖層 Subject + 物件 Base + 基礎 Base option + 基礎選項 Suffix + 後綴 Suffix option + 後綴選項 Touch element + 觸按物件 Sounds + 聲效 Commands + 指令 Index + 索引 Key + Option + 選項 Edit entry + 編輯項目 Sound + 聲效 Command + 控制 Sound and command + 聲音及指令 Panel settings + 駕駛室設定 @@ -5594,43 +5955,54 @@ Section select + 部分選擇 Key type select + 鍵值類型 Position + 位置 X + X Y + Y Z + Z Input value + 參數 Filename + 檔案名 Radius + 半徑 Position setting + 位置設定 Edit entry + 編輯項目 @@ -5645,6 +6017,7 @@ Sound settings + 電機音設定 Key @@ -5656,9 +6029,11 @@ Position + 位置 Radius + 半徑 @@ -5669,6 +6044,7 @@ Warning + 警告 Information @@ -5676,10 +6052,12 @@ Clear + 清除 Status + 狀態 Level @@ -5687,17 +6065,21 @@ Description + 描述 Error + 錯誤 Warning + 警告 Information + 資訊 positive @@ -5721,79 +6103,101 @@ The specified number is already set. + 指定的數值已被使用。 Max must be greater than or equal to Min. + 最大值必須大於或等於最小值。 Min must be less than the Max. + 最小值必須小於最大值。 Filename + 檔案名 Folder + 資料夾 Type + 類型 OK + 確定 Train setting file + 列車設定檔案 Old format + 舊格式 Train.dat + Train.dat Extensions.cfg + Extensions.cfg Panel Setting File + 駕駛室設定檔案 Panel2.cfg + Panel2.cfg Panel.xml + Panel.xml Sound setting file + 電機音設定檔案 No setting file + 沒有設定檔案 Sound.cfg + Sound.cfg Sound.xml + Sound.xml Import + 匯入 Export + 匯出 Folder + 資料夾 Type + 類型 From 3eb1deabe1f0bb924d26af183e60ffb11bf481dd Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Mon, 9 Sep 2024 13:05:08 +0100 Subject: [PATCH 32/41] First implementation in RouteViewer --- source/LibRender2/Menu/MenuBase.cs | 45 +++ source/ObjectViewer/Game/Menu.SingleMenu.cs | 40 +- source/OpenBVE/Game/Menu/Menu.SingleMenu.cs | 41 +-- source/RouteViewer/Game/Menu.SingleMenu.cs | 178 +++++++++ source/RouteViewer/Game/Menu.cs | 387 ++++++++++++++++++++ source/RouteViewer/GameR.cs | 2 + source/RouteViewer/InterfaceR.cs | 1 + source/RouteViewer/Options.cs | 17 +- source/RouteViewer/RouteViewer.csproj | 2 + 9 files changed, 634 insertions(+), 79 deletions(-) create mode 100644 source/RouteViewer/Game/Menu.SingleMenu.cs create mode 100644 source/RouteViewer/Game/Menu.cs diff --git a/source/LibRender2/Menu/MenuBase.cs b/source/LibRender2/Menu/MenuBase.cs index f7dbe4607..e5f518032 100644 --- a/source/LibRender2/Menu/MenuBase.cs +++ b/source/LibRender2/Menu/MenuBase.cs @@ -24,6 +24,8 @@ using OpenBveApi.Graphics; using System; +using LibRender2.Text; +using OpenBveApi.Math; namespace LibRender2.Menu { @@ -91,5 +93,48 @@ public MenuBase(MenuType type) { Type = type; } + + /// Computes the on-screen extent of the menu + public void ComputeExtent(MenuType menuType, OpenGlFont menuFont, double MaxWidth) + { + for (int i = 0; i < Items.Length; i++) + { + if (Items[i] == null) + { + continue; + } + Vector2 size = menuFont.MeasureString(Items[i].Text); + if (Items[i].Icon != null) + { + size.X += size.Y * 1.25; + } + if (size.X > Width) + { + Width = size.X; + } + + if (MaxWidth != 0 && size.X > MaxWidth) + { + for (int j = Items[i].Text.Length - 1; j > 0; j--) + { + string trimmedText = Items[i].Text.Substring(0, j); + size = menuFont.MeasureString(trimmedText); + double mwi = MaxWidth; + if (Items[i].Icon != null) + { + mwi -= size.Y * 1.25; + } + if (size.X < mwi) + { + Items[i].DisplayLength = trimmedText.Length; + break; + } + } + Width = MaxWidth; + } + if (!(Items[i] is MenuCaption && menuType != MenuType.RouteList && menuType != MenuType.GameStart && menuType != MenuType.Packages) && size.X > ItemWidth) + ItemWidth = size.X; + } + } } } diff --git a/source/ObjectViewer/Game/Menu.SingleMenu.cs b/source/ObjectViewer/Game/Menu.SingleMenu.cs index 4495b8c4d..5eb63ef75 100644 --- a/source/ObjectViewer/Game/Menu.SingleMenu.cs +++ b/source/ObjectViewer/Game/Menu.SingleMenu.cs @@ -167,45 +167,7 @@ public SingleMenu(AbstractMenu menu, MenuType menuType, int data = 0, double Max break; } - // compute menu extent - for (i = 0; i < Items.Length; i++) - { - if (Items[i] == null) - { - continue; - } - Vector2 size = Game.Menu.MenuFont.MeasureString(Items[i].Text); - if (Items[i].Icon != null) - { - size.X += size.Y * 1.25; - } - if (size.X > Width) - { - Width = size.X; - } - - if (MaxWidth != 0 && size.X > MaxWidth) - { - for (int j = Items[i].Text.Length - 1; j > 0; j--) - { - string trimmedText = Items[i].Text.Substring(0, j); - size = Game.Menu.MenuFont.MeasureString(trimmedText); - double mwi = MaxWidth; - if (Items[i].Icon != null) - { - mwi -= size.Y * 1.25; - } - if (size.X < mwi) - { - Items[i].DisplayLength = trimmedText.Length; - break; - } - } - Width = MaxWidth; - } - if (!(Items[i] is MenuCaption && menuType != MenuType.RouteList && menuType != MenuType.GameStart && menuType != MenuType.Packages) && size.X > ItemWidth) - ItemWidth = size.X; - } + ComputeExtent(menuType, Game.Menu.MenuFont, MaxWidth); Height = Items.Length * Game.Menu.lineHeight; TopItem = 0; diff --git a/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs b/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs index 5c730e304..9b80e46cf 100644 --- a/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs +++ b/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs @@ -523,45 +523,8 @@ public SingleMenu(AbstractMenu menu, MenuType menuType, int data = 0, double Max } break; } - // compute menu extent - for (i = 0; i < Items.Length; i++) - { - if (Items[i] == null) - { - continue; - } - Vector2 size = Game.Menu.MenuFont.MeasureString(Items[i].Text); - if (Items[i].Icon != null) - { - size.X += size.Y * 1.25; - } - if (size.X > Width) - { - Width = size.X; - } - - if (MaxWidth != 0 && size.X > MaxWidth) - { - for (int j = Items[i].Text.Length - 1; j > 0; j--) - { - string trimmedText = Items[i].Text.Substring(0, j); - size = Game.Menu.MenuFont.MeasureString(trimmedText); - double mwi = MaxWidth; - if (Items[i].Icon != null) - { - mwi -= size.Y * 1.25; - } - if (size.X < mwi) - { - Items[i].DisplayLength = trimmedText.Length; - break; - } - } - Width = MaxWidth; - } - if (!(Items[i] is MenuCaption && menuType!= MenuType.RouteList && menuType != MenuType.GameStart && menuType != MenuType.Packages) && size.X > ItemWidth) - ItemWidth = size.X; - } + + ComputeExtent(menuType, Game.Menu.MenuFont, MaxWidth); Height = Items.Length * Game.Menu.lineHeight; TopItem = 0; } diff --git a/source/RouteViewer/Game/Menu.SingleMenu.cs b/source/RouteViewer/Game/Menu.SingleMenu.cs new file mode 100644 index 000000000..12e3a6795 --- /dev/null +++ b/source/RouteViewer/Game/Menu.SingleMenu.cs @@ -0,0 +1,178 @@ +using LibRender2.Menu; +using OpenBveApi.Graphics; +using OpenBveApi.Hosts; +using OpenBveApi.Interface; +using OpenBveApi.Textures; +using System; +using System.IO; +using OpenBveApi.Math; +using Path = OpenBveApi.Path; +using RouteViewer; + +namespace RouteViewer +{ + public sealed partial class GameMenu + { + /// Provides implementation for a single menu of the menu stack. + /// The class is private to Menu, but all its fields are public to allow 'quick-and-dirty' + /// access from Menu itself. + private class SingleMenu : MenuBase + { + public SingleMenu(AbstractMenu menu, MenuType menuType, int data = 0, double MaxWidth = 0) : base(menuType) + { + int i; + int jump = 0; + //Vector2 size; + Align = TextAlignment.TopMiddle; + Height = Width = 0; + Selection = 0; // defaults to first menu item + switch (menuType) + { + case MenuType.GameStart: // top level menu + Items = new MenuEntry[4]; + Items[0] = new MenuCommand(menu, "Open Object File", MenuTag.ObjectList, 0); + Items[1] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "title" }), MenuTag.Options, 0); + Items[2] = new MenuCommand(menu, "Show Errors", MenuTag.ErrorList, 0); + Items[3] = new MenuCommand(menu, "Close", MenuTag.BackToSim, 0); + if (string.IsNullOrEmpty(SearchDirectory)) + { + SearchDirectory = Program.FileSystem.InitialRouteFolder; + } + Align = TextAlignment.TopLeft; + break; + case MenuType.ObjectList: + string[] potentialFiles = { }; + string[] directoryList = { }; + bool drives = false; + if (SearchDirectory != string.Empty) + { + try + { + potentialFiles = Directory.GetFiles(SearchDirectory); + directoryList = Directory.GetDirectories(SearchDirectory); + } + catch + { + // Ignored + } + } + else + { + DriveInfo[] systemDrives = DriveInfo.GetDrives(); + directoryList = new string[systemDrives.Length]; + for (int k = 0; k < systemDrives.Length; k++) + { + directoryList[k] = systemDrives[k].Name; + } + drives = true; + } + + Items = new MenuEntry[potentialFiles.Length + directoryList.Length + 2]; + Items[0] = new MenuCaption(menu, SearchDirectory); + Items[1] = new MenuCommand(menu, "...", MenuTag.ParentDirectory, 0); + int totalEntries = 2; + for (int j = 0; j < directoryList.Length; j++) + { + DirectoryInfo directoryInfo = new DirectoryInfo(directoryList[j]); + if (Program.CurrentHost.Platform != HostPlatform.MicrosoftWindows && directoryInfo.Name[0] == '.') + { + continue; + } + Items[totalEntries] = new MenuCommand(menu, directoryInfo.Name, MenuTag.Directory, 0); + if (drives) + { + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_disk.png"), new TextureParameters(null, null), out Items[totalEntries].Icon); + } + else + { + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_folder.png"), new TextureParameters(null, null), out Items[totalEntries].Icon); + } + + totalEntries++; + } + + for (int j = 0; j < potentialFiles.Length; j++) + { + string fileName = System.IO.Path.GetFileName(potentialFiles[j]); + if (Program.CurrentHost.Platform != HostPlatform.MicrosoftWindows && fileName[0] == '.') + { + continue; + } + FileInfo fi = new FileInfo(fileName); + switch (fi.Extension.ToLowerInvariant()) + { + case ".csv": + case ".b3d": + case ".animated": + Items[totalEntries] = new MenuCommand(menu, fileName, MenuTag.ObjectFile, 0); + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_object.png"), new TextureParameters(null, null), out Items[totalEntries].Icon); + totalEntries++; + break; + case ".obj": + Items[totalEntries] = new MenuCommand(menu, fileName, MenuTag.ObjectFile, 0); + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_wavefront.png"), new TextureParameters(null, null), out Items[totalEntries].Icon); + totalEntries++; + break; + case ".x": + Items[totalEntries] = new MenuCommand(menu, fileName, MenuTag.ObjectFile, 0); + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_xobject.png"), new TextureParameters(null, null), out Items[totalEntries].Icon); + totalEntries++; + break; + } + } + Array.Resize(ref Items, totalEntries); + Align = TextAlignment.TopLeft; + break; + case MenuType.Options: + Items = new MenuEntry[8]; + Items[0] = new MenuCaption(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "panel", "options" })); + Items[1] = new MenuOption(menu, OptionType.ScreenResolution, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "resolution" }), Program.Renderer.Screen.AvailableResolutions.ToArray()); + Items[2] = new MenuOption(menu, OptionType.FullScreen, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "display_mode_fullscreen" }), new[] { "true", "false" }); + Items[3] = new MenuOption(menu, OptionType.Interpolation, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "quality_interpolation" }), new[] + { + Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_mode_nearest"}), + Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_mode_bilinear"}), + Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_mode_nearestmipmap"}), + Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_mode_bilinearmipmap"}), + Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_mode_trilinearmipmap"}), + Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","quality_interpolation_mode_anisotropic"}) + }); + Items[4] = new MenuOption(menu, OptionType.AnisotropicLevel, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "quality_interpolation_anisotropic_level" }), new[] { "0", "2", "4", "8", "16" }); + Items[5] = new MenuOption(menu, OptionType.AntialiasingLevel, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "quality_interpolation_antialiasing_level" }), new[] { "0", "2", "4", "8", "16" }); + Items[6] = new MenuOption(menu, OptionType.ViewingDistance, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "quality_distance_viewingdistance" }), new[] { "400", "600", "800", "1000", "1500", "2000" }); + Items[7] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "menu", "back" }), MenuTag.MenuBack, 0); + Align = TextAlignment.TopLeft; + break; + case MenuType.ErrorList: + Items = new MenuEntry[Interface.LogMessages.Count + 2]; + Items[0] = Interface.LogMessages.Count == 0 ? new MenuCaption(menu, "No current errors / warnings.") : new MenuCaption(menu, Interface.LogMessages.Count + " total errors / warnings."); + + for (int j = 0; j < Interface.LogMessages.Count; j++) + { + Items[j + 1] = new MenuErrorDisplay(menu, Interface.LogMessages[j].Text); + switch (Interface.LogMessages[j].Type) + { + case MessageType.Information: + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_information.png"), new TextureParameters(null, null), out Items[j + 1].Icon); + break; + case MessageType.Warning: + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_warning.png"), new TextureParameters(null, null), out Items[j + 1].Icon); + break; + case MessageType.Error: + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_error.png"), new TextureParameters(null, null), out Items[j + 1].Icon); + break; + } + } + Items[Items.Length - 1] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "menu", "back" }), MenuTag.MenuBack, 0); + Align = TextAlignment.TopLeft; + break; + } + + ComputeExtent(menuType, Game.Menu.MenuFont, MaxWidth); + Height = Items.Length * Game.Menu.lineHeight; + TopItem = 0; + + } + } + } +} diff --git a/source/RouteViewer/Game/Menu.cs b/source/RouteViewer/Game/Menu.cs new file mode 100644 index 000000000..82942761e --- /dev/null +++ b/source/RouteViewer/Game/Menu.cs @@ -0,0 +1,387 @@ +using System; +using System.IO; +using LibRender2.Menu; +using LibRender2.Primitives; +using LibRender2.Screens; +using OpenBveApi.Colors; +using OpenBveApi.Graphics; +using OpenBveApi.Hosts; +using OpenBveApi.Input; +using OpenBveApi.Interface; +using OpenBveApi.Math; +using OpenBveApi.Textures; +using RouteViewer; +using Path = OpenBveApi.Path; + +namespace RouteViewer +{ + public sealed partial class GameMenu : AbstractMenu + { + + internal Picturebox filePictureBox; + internal Textbox fileTextBox; + private double lastTimeElapsed; + private static string SearchDirectory; + private static string currentFile; + + /// Returns the current menu instance (If applicable) + public static GameMenu Instance; + + internal GameMenu() : base(Program.Renderer, Interface.CurrentOptions) + { + } + + public override void Initialize() + { + filePictureBox = new Picturebox(Renderer); + fileTextBox = new Textbox(Renderer, Renderer.Fonts.NormalFont, Color128.White, Color128.Black); + Reset(); + // choose the text font size according to screen height + // the boundaries follow approximately the progression + // of font sizes defined in Graphics/Fonts.cs + if (Renderer.Screen.Height <= 512) MenuFont = Renderer.Fonts.SmallFont; + else if (Renderer.Screen.Height <= 680) MenuFont = Renderer.Fonts.NormalFont; + else if (Renderer.Screen.Height <= 890) MenuFont = Renderer.Fonts.LargeFont; + else if (Renderer.Screen.Height <= 1150) MenuFont = Renderer.Fonts.VeryLargeFont; + else MenuFont = Renderer.Fonts.EvenLargerFont; + + lineHeight = (int)(MenuFont.FontSize * LineSpacing); + MenuBackKey = Key.Escape; // fixed in viewers + int quarterWidth = (int)(Renderer.Screen.Width / 4.0); + int quarterHeight = (int)(Renderer.Screen.Height / 4.0); + int descriptionLoc = Renderer.Screen.Width - quarterWidth - quarterWidth / 2; + int descriptionWidth = quarterWidth + quarterWidth / 2; + int descriptionHeight = descriptionWidth; + if (descriptionHeight + quarterWidth > Renderer.Screen.Height - 50) + { + descriptionHeight = Renderer.Screen.Height - quarterWidth - 50; + } + fileTextBox.Location = new Vector2(descriptionLoc, quarterWidth); + fileTextBox.Size = new Vector2(descriptionWidth, descriptionHeight); + int imageLoc = Renderer.Screen.Width - quarterWidth - quarterWidth / 4; + filePictureBox.Location = new Vector2(imageLoc, 0); + filePictureBox.Size = new Vector2(quarterWidth, quarterWidth); + filePictureBox.BackgroundColor = Color128.White; + SearchDirectory = Interface.CurrentOptions.RouteSearchDirectory; + IsInitialized = true; + } + + public override void PushMenu(MenuType type, int data = 0, bool replace = false) + { + if (Renderer.CurrentInterface < InterfaceType.Menu) + { + // Deliberately set to the standard cursor, as touch controls may have set to something else + Renderer.SetCursor(OpenTK.MouseCursor.Default); + } + if (!IsInitialized) + Initialize(); + if (!replace) + { + CurrMenu++; + } + + if (Menus.Length <= CurrMenu) + Array.Resize(ref Menus, CurrMenu + 1); + int MaxWidth = 0; + if ((int)type >= 100) + { + MaxWidth = Renderer.Screen.Width / 2; + } + Menus[CurrMenu] = new SingleMenu(this, type, data, MaxWidth); + if (replace) + { + Menus[CurrMenu].Selection = 1; + } + ComputePosition(); + Renderer.CurrentInterface = InterfaceType.Menu; + } + + public override void ProcessCommand(Translations.Command cmd, double timeElapsed) + { + if (CurrMenu < 0) + { + return; + } + MenuBase menu = Menus[CurrMenu]; + // MenuBack is managed independently from single menu data + if (cmd == Translations.Command.MenuBack) + { + if (menu.Type == MenuType.GameStart) + { + Reset(); + Renderer.CurrentInterface = InterfaceType.Normal; + } + else + { + PopMenu(); + } + return; + } + if (menu.Selection == -1) // if menu has no selection, do nothing + return; + switch (cmd) + { + case Translations.Command.MenuUp: // UP + if (menu.Selection > 0 && + !(menu.Items[menu.Selection - 1] is MenuCaption)) + { + menu.Selection--; + ComputePosition(); + } + + break; + case Translations.Command.MenuDown: // DOWN + if (menu.Selection < menu.Items.Length - 1) + { + menu.Selection++; + ComputePosition(); + } + + break; + // case Translations.Command.MenuBack: // ESC: managed above + // break; + case Translations.Command.MenuEnter: // ENTER + if (menu.Items[menu.Selection] is MenuCommand menuItem) + { + switch (menuItem.Tag) + { + // menu management commands + case MenuTag.MenuBack: // BACK TO PREVIOUS MENU + Instance.PopMenu(); + break; + case MenuTag.MenuJumpToStation: // TO STATIONS MENU + Instance.PushMenu(MenuType.JumpToStation); + break; + case MenuTag.MenuExitToMainMenu: // TO EXIT MENU + Instance.PushMenu(MenuType.ExitToMainMenu); + break; + case MenuTag.MenuQuit: // TO QUIT MENU + Instance.PushMenu(MenuType.Quit); + break; + case MenuTag.MenuControls: // TO CONTROLS MENU + Instance.PushMenu(MenuType.Controls); + break; + case MenuTag.BackToSim: // OUT OF MENU BACK TO SIMULATION + Reset(); + Renderer.CurrentInterface = InterfaceType.Normal; + break; + case MenuTag.ObjectList: // TO OBJECT LIST MENU + Instance.PushMenu(MenuType.ObjectList); + fileTextBox.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "errors", "route_please_select" }); + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\please_select.png"), new TextureParameters(null, null), out filePictureBox.Texture); + break; + case MenuTag.ErrorList: + Instance.PushMenu(MenuType.ErrorList); + break; + case MenuTag.Directory: // SHOWS THE LIST OF FILES IN THE SELECTED DIR + SearchDirectory = SearchDirectory == string.Empty ? menu.Items[menu.Selection].Text : Path.CombineDirectory(SearchDirectory, menu.Items[menu.Selection].Text); + Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + break; + case MenuTag.ParentDirectory: // SHOWS THE LIST OF FILES IN THE PARENT DIR + if (string.IsNullOrEmpty(SearchDirectory)) + { + return; + } + + string oldSearchDirectory = SearchDirectory; + try + { + DirectoryInfo newDirectory = Directory.GetParent(SearchDirectory); + SearchDirectory = newDirectory == null ? string.Empty : Directory.GetParent(SearchDirectory)?.ToString(); + } + catch + { + SearchDirectory = oldSearchDirectory; + return; + } + Instance.PushMenu(Instance.Menus[CurrMenu].Type, 0, true); + break; + case MenuTag.Options: + Instance.PushMenu(MenuType.Options); + break; + } + } + else if (menu.Items[menu.Selection] is MenuOption opt) + { + opt.Flip(); + } + break; + } + + } + + public override bool ProcessMouseMove(int x, int y) + { + Program.currentGameWindow.CursorVisible = true; + if (CurrMenu < 0) + { + return false; + } + // if not in menu or during control customisation or down outside menu area, do nothing + if (Renderer.CurrentInterface < InterfaceType.Menu) + return false; + + // Load the current menu + MenuBase menu = Menus[CurrMenu]; + if (menu.TopItem > 1 && y < topItemY && y > menuMin.Y) + { + //Item is the scroll up ellipsis + menu.Selection = menu.TopItem - 1; + return true; + } + if (menu.Type == MenuType.RouteList || menu.Type == MenuType.TrainList || menu.Type == MenuType.PackageInstall || menu.Type == MenuType.Packages || (int)menu.Type >= 107) + { + fileTextBox.MouseMove(x, y); + //HACK: Use this to trigger our menu start button! + if (x > Renderer.Screen.Width - 200 && x < Renderer.Screen.Width - 10 && y > Renderer.Screen.Height - 40 && y < Renderer.Screen.Height - 10) + { + menu.Selection = int.MaxValue; + return true; + } + } + if (x < menuMin.X || x > menuMax.X || y < menuMin.Y || y > menuMax.Y) + { + return false; + } + + int item = (int)((y - topItemY) / lineHeight + menu.TopItem); + // if the mouse is above a command item, select it + if (item >= 0 && item < menu.Items.Length && (menu.Items[item] is MenuCommand || menu.Items[item] is MenuOption)) + { + if (item < visibleItems + menu.TopItem + 1) + { + //Item is a standard menu entry or the scroll down elipsis + menu.Selection = item; + return true; + } + } + return false; + } + + public override void Draw(double RealTimeElapsed) + { + double TimeElapsed = RealTimeElapsed - lastTimeElapsed; + lastTimeElapsed = RealTimeElapsed; + int i; + + if (CurrMenu < 0 || CurrMenu >= Menus.Length) + return; + + MenuBase menu = Menus[CurrMenu]; + // overlay background + Renderer.Rectangle.Draw(null, Vector2.Null, new Vector2(Renderer.Screen.Width, Renderer.Screen.Height), overlayColor); + + + double itemLeft, itemX; + if (menu.Align == TextAlignment.TopLeft) + { + itemLeft = 0; + itemX = 16; + Renderer.Rectangle.Draw(null, new Vector2(0, menuMin.Y - Border.Y), new Vector2(menuMax.X - menuMin.X + 2.0f * Border.X, menuMax.Y - menuMin.Y + 2.0f * Border.Y), backgroundColor); + } + else + { + itemLeft = (Renderer.Screen.Width - menu.ItemWidth) / 2; // item left edge + // if menu alignment is left, left-align items, otherwise centre them in the screen + itemX = (menu.Align & TextAlignment.Left) != 0 ? itemLeft : Renderer.Screen.Width / 2.0; + Renderer.Rectangle.Draw(null, new Vector2(menuMin.X - Border.X, menuMin.Y - Border.Y), new Vector2(menuMax.X - menuMin.X + 2.0f * Border.X, menuMax.Y - menuMin.Y + 2.0f * Border.Y), backgroundColor); + } + + // draw the menu background + + + int menuBottomItem = menu.TopItem + visibleItems - 1; + + + + // if not starting from the top of the menu, draw a dimmed ellipsis item + if (menu.Selection == menu.TopItem - 1) + { + Renderer.Rectangle.Draw(null, new Vector2(itemLeft - ItemBorder.X, menuMin.Y /*-ItemBorder.Y*/), new Vector2(menu.ItemWidth + ItemBorder.X, MenuFont.FontSize + ItemBorder.Y * 2), highlightColor); + } + if (menu.TopItem > 0) + Renderer.OpenGlString.Draw(MenuFont, @"...", new Vector2(itemX, menuMin.Y), + menu.Align, ColourDimmed, false); + // draw the items + double itemY = topItemY; + for (i = menu.TopItem; i <= menuBottomItem && i < menu.Items.Length; i++) + { + if (menu.Items[i] == null) + { + continue; + } + + double itemHeight = MenuFont.MeasureString(menu.Items[i].Text).Y; + double iconX = itemX; + if (menu.Items[i].Icon != null) + { + itemX += itemHeight * 1.25; + } + if (i == menu.Selection) + { + // draw a solid highlight rectangle under the text + // HACK! the highlight rectangle has to be shifted a little down to match + // the text body. OpenGL 'feature'? + Color128 color = highlightColor; + if (menu.Items[i] is MenuCommand command) + { + switch (command.Tag) + { + case MenuTag.Directory: + case MenuTag.ParentDirectory: + color = folderHighlightColor; + break; + case MenuTag.RouteFile: + color = routeHighlightColor; + break; + default: + color = highlightColor; + break; + } + } + + if (itemLeft == 0) + { + Renderer.Rectangle.Draw(null, new Vector2(ItemBorder.X, itemY /*-ItemBorder.Y*/), new Vector2(menu.Width + 2.0f * ItemBorder.X, MenuFont.FontSize + ItemBorder.Y * 2), color); + } + else + { + Renderer.Rectangle.Draw(null, new Vector2(itemLeft - ItemBorder.X, itemY /*-ItemBorder.Y*/), new Vector2(menu.ItemWidth + 2.0f * ItemBorder.X, MenuFont.FontSize + ItemBorder.Y * 2), color); + } + + // draw the text + Renderer.OpenGlString.Draw(MenuFont, menu.Items[i].DisplayText(TimeElapsed), new Vector2(itemX, itemY), + menu.Align, ColourHighlight, false); + } + else if (menu.Items[i] is MenuCaption) + Renderer.OpenGlString.Draw(MenuFont, menu.Items[i].DisplayText(TimeElapsed), new Vector2(itemX, itemY), + menu.Align, ColourCaption, false); + else + Renderer.OpenGlString.Draw(MenuFont, menu.Items[i].DisplayText(TimeElapsed), new Vector2(itemX, itemY), + menu.Align, ColourNormal, false); + if (menu.Items[i] is MenuOption opt) + { + Renderer.OpenGlString.Draw(MenuFont, opt.CurrentOption.ToString(), new Vector2((menuMax.X - menuMin.X + 2.0f * Border.X) + 4.0f, itemY), + menu.Align, backgroundColor, false); + } + itemY += lineHeight; + if (menu.Items[i].Icon != null) + { + Renderer.Rectangle.DrawAlpha(menu.Items[i].Icon, new Vector2(iconX, itemY - itemHeight * 1.5), new Vector2(itemHeight, itemHeight), Color128.White); + itemX = iconX; + } + + } + + + if (menu.Selection == menu.TopItem + visibleItems) + { + Renderer.Rectangle.Draw(null, new Vector2(itemLeft - ItemBorder.X, itemY /*-ItemBorder.Y*/), new Vector2(menu.ItemWidth + 2.0f * ItemBorder.X, MenuFont.FontSize + ItemBorder.Y * 2), highlightColor); + } + // if not at the end of the menu, draw a dimmed ellipsis item at the bottom + if (i < menu.Items.Length - 1) + Renderer.OpenGlString.Draw(MenuFont, @"...", new Vector2(itemX, itemY), + menu.Align, ColourDimmed, false); + } + } +} diff --git a/source/RouteViewer/GameR.cs b/source/RouteViewer/GameR.cs index b900374e7..653122277 100644 --- a/source/RouteViewer/GameR.cs +++ b/source/RouteViewer/GameR.cs @@ -24,6 +24,8 @@ internal static class Game { // date and time internal static double SecondsSinceMidnight = 0.0; + /// The in-game menu system + internal static readonly GameMenu Menu = GameMenu.Instance; // ================================ diff --git a/source/RouteViewer/InterfaceR.cs b/source/RouteViewer/InterfaceR.cs index ec278b0b5..b7176deaa 100644 --- a/source/RouteViewer/InterfaceR.cs +++ b/source/RouteViewer/InterfaceR.cs @@ -19,6 +19,7 @@ internal class Options : BaseOptions internal bool LoadingProgressBar; internal bool LoadingLogo; internal bool LoadingBackground; + internal string RouteSearchDirectory; internal Options() { diff --git a/source/RouteViewer/Options.cs b/source/RouteViewer/Options.cs index d4afe90ec..ead3058d0 100644 --- a/source/RouteViewer/Options.cs +++ b/source/RouteViewer/Options.cs @@ -1,10 +1,11 @@ using System; using System.Globalization; +using System.IO; using System.Reflection; using System.Windows.Forms; -using OpenBveApi; using OpenBveApi.Graphics; using OpenBveApi.Objects; +using Path = OpenBveApi.Path; namespace RouteViewer { @@ -186,6 +187,17 @@ internal static void LoadOptions() } } break; + case "folders": + switch (Key) + { + case "routesearch": + if (Directory.Exists(Value)) + { + Interface.CurrentOptions.RouteSearchDirectory = Value; + } + break; + } + break; } } } @@ -237,6 +249,9 @@ internal static void SaveOptions() Builder.AppendLine("[parsers]"); Builder.AppendLine("xObject = " + (int)Interface.CurrentOptions.CurrentXParser); Builder.AppendLine("objObject = " + (int)Interface.CurrentOptions.CurrentObjParser); + Builder.AppendLine(); + Builder.AppendLine("[Folders]"); + Builder.AppendLine($"routesearch = {Interface.CurrentOptions.RouteSearchDirectory}"); string configFile = Path.CombineFile(Program.FileSystem.SettingsFolder, "1.5.0/options_rv.cfg"); System.IO.File.WriteAllText(configFile, Builder.ToString(), new System.Text.UTF8Encoding(true)); } diff --git a/source/RouteViewer/RouteViewer.csproj b/source/RouteViewer/RouteViewer.csproj index a686709b1..3c656085f 100644 --- a/source/RouteViewer/RouteViewer.csproj +++ b/source/RouteViewer/RouteViewer.csproj @@ -94,6 +94,8 @@ formRailPaths.cs + + From 0ff9d58e7202763717a9d48aab27f6dfa33cf923 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Mon, 9 Sep 2024 17:24:23 +0100 Subject: [PATCH 33/41] Initial basic menu drawing in RouteViewer --- source/ObjectViewer/ProgramS.cs | 1 - source/RouteViewer/Game/Menu.SingleMenu.cs | 31 ++------ source/RouteViewer/Game/Menu.cs | 4 +- source/RouteViewer/NewRendererR.cs | 14 +++- source/RouteViewer/ProgramR.cs | 89 +++++++++++++++++----- source/RouteViewer/System/Gamewindow.cs | 4 +- 6 files changed, 91 insertions(+), 52 deletions(-) diff --git a/source/ObjectViewer/ProgramS.cs b/source/ObjectViewer/ProgramS.cs index f08204bad..fdd3a1321 100644 --- a/source/ObjectViewer/ProgramS.cs +++ b/source/ObjectViewer/ProgramS.cs @@ -190,7 +190,6 @@ internal static void MouseWheelEvent(object sender, MouseWheelEventArgs e) } break; } - } internal static void MouseMoveEvent(object sender, MouseMoveEventArgs e) diff --git a/source/RouteViewer/Game/Menu.SingleMenu.cs b/source/RouteViewer/Game/Menu.SingleMenu.cs index 12e3a6795..a76c02774 100644 --- a/source/RouteViewer/Game/Menu.SingleMenu.cs +++ b/source/RouteViewer/Game/Menu.SingleMenu.cs @@ -30,7 +30,7 @@ public SingleMenu(AbstractMenu menu, MenuType menuType, int data = 0, double Max { case MenuType.GameStart: // top level menu Items = new MenuEntry[4]; - Items[0] = new MenuCommand(menu, "Open Object File", MenuTag.ObjectList, 0); + Items[0] = new MenuCommand(menu, "Open Route File", MenuTag.RouteList, 0); Items[1] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "title" }), MenuTag.Options, 0); Items[2] = new MenuCommand(menu, "Show Errors", MenuTag.ErrorList, 0); Items[3] = new MenuCommand(menu, "Close", MenuTag.BackToSim, 0); @@ -40,9 +40,9 @@ public SingleMenu(AbstractMenu menu, MenuType menuType, int data = 0, double Max } Align = TextAlignment.TopLeft; break; - case MenuType.ObjectList: - string[] potentialFiles = { }; - string[] directoryList = { }; + case MenuType.RouteList: + string[] potentialFiles = new string[] { }; + string[] directoryList = new string[] { }; bool drives = false; if (SearchDirectory != string.Empty) { @@ -98,26 +98,11 @@ public SingleMenu(AbstractMenu menu, MenuType menuType, int data = 0, double Max { continue; } - FileInfo fi = new FileInfo(fileName); - switch (fi.Extension.ToLowerInvariant()) + if (fileName.ToLowerInvariant().EndsWith(".csv") || fileName.ToLowerInvariant().EndsWith(".rw")) { - case ".csv": - case ".b3d": - case ".animated": - Items[totalEntries] = new MenuCommand(menu, fileName, MenuTag.ObjectFile, 0); - Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_object.png"), new TextureParameters(null, null), out Items[totalEntries].Icon); - totalEntries++; - break; - case ".obj": - Items[totalEntries] = new MenuCommand(menu, fileName, MenuTag.ObjectFile, 0); - Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_wavefront.png"), new TextureParameters(null, null), out Items[totalEntries].Icon); - totalEntries++; - break; - case ".x": - Items[totalEntries] = new MenuCommand(menu, fileName, MenuTag.ObjectFile, 0); - Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_xobject.png"), new TextureParameters(null, null), out Items[totalEntries].Icon); - totalEntries++; - break; + Items[totalEntries] = new MenuCommand(menu, fileName, MenuTag.RouteFile, 0); + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_route.png"), new TextureParameters(null, null), out Items[totalEntries].Icon); + totalEntries++; } } Array.Resize(ref Items, totalEntries); diff --git a/source/RouteViewer/Game/Menu.cs b/source/RouteViewer/Game/Menu.cs index 82942761e..a6c91ffe0 100644 --- a/source/RouteViewer/Game/Menu.cs +++ b/source/RouteViewer/Game/Menu.cs @@ -165,8 +165,8 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed Reset(); Renderer.CurrentInterface = InterfaceType.Normal; break; - case MenuTag.ObjectList: // TO OBJECT LIST MENU - Instance.PushMenu(MenuType.ObjectList); + case MenuTag.RouteList: // TO ROUTE LIST MENU + Instance.PushMenu(MenuType.RouteList); fileTextBox.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "errors", "route_please_select" }); Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\please_select.png"), new TextureParameters(null, null), out filePictureBox.Texture); break; diff --git a/source/RouteViewer/NewRendererR.cs b/source/RouteViewer/NewRendererR.cs index 8689df471..d1c6443ba 100644 --- a/source/RouteViewer/NewRendererR.cs +++ b/source/RouteViewer/NewRendererR.cs @@ -5,6 +5,7 @@ using System.Windows.Forms; using LibRender2; using LibRender2.Objects; +using LibRender2.Screens; using OpenBveApi; using OpenBveApi.Colors; using OpenBveApi.FileSystem; @@ -72,7 +73,7 @@ public override void Initialize() } // render scene - internal void RenderScene(double TimeElapsed) + internal void RenderScene(double timeElapsed) { lastObjectState = null; ReleaseResources(); @@ -148,7 +149,7 @@ internal void RenderScene(double TimeElapsed) // render background GL.Disable(EnableCap.DepthTest); - Program.CurrentRoute.UpdateBackground(TimeElapsed, false); + Program.CurrentRoute.UpdateBackground(timeElapsed, false); if (OptionEvents) { @@ -331,7 +332,7 @@ internal void RenderScene(double TimeElapsed) UnsetAlphaFunc(); GL.Disable(EnableCap.DepthTest); SetBlendFunc(BlendingFactor.SrcAlpha, BlendingFactor.OneMinusSrcAlpha); //FIXME: Remove when text switches between two renderer types - RenderOverlays(); + RenderOverlays(timeElapsed); OptionLighting = true; } @@ -515,7 +516,7 @@ private void RenderEvents() OptionLighting = true; } - private void RenderOverlays() + private void RenderOverlays(double timeElapsed) { //Initialize openGL SetBlendFunc(); @@ -748,6 +749,11 @@ private void RenderOverlays() } } + if (CurrentInterface == InterfaceType.Menu) + { + Game.Menu.Draw(timeElapsed); + } + // finalize PopMatrix(MatrixMode.Projection); PopMatrix(MatrixMode.Modelview); diff --git a/source/RouteViewer/ProgramR.cs b/source/RouteViewer/ProgramR.cs index eba3b0c9d..38758f755 100644 --- a/source/RouteViewer/ProgramR.cs +++ b/source/RouteViewer/ProgramR.cs @@ -28,6 +28,8 @@ using OpenBveApi.Hosts; using OpenBveApi.Objects; using ButtonState = OpenTK.Input.ButtonState; +using LibRender2.Menu; +using LibRender2.Screens; namespace RouteViewer { @@ -84,7 +86,7 @@ internal static void Main(string[] args) MessageBox.Show(error, @"OpenBVE", MessageBoxButtons.OK, MessageBoxIcon.Error); return; } - + GameMenu.Instance = new GameMenu(); // command line arguments string objectsToLoad = string.Empty; if (args.Length != 0) @@ -291,28 +293,64 @@ internal static void UpdateGraphicsSettings() } } - internal static void MouseEvent(object sender, MouseButtonEventArgs e) + internal static void MouseWheelEvent(object sender, MouseWheelEventArgs e) { - if (e.Button == OpenTK.Input.MouseButton.Left) - { - MouseButton = e.Mouse.LeftButton == ButtonState.Pressed ? 1 : 0; - } - if (e.Button == OpenTK.Input.MouseButton.Right) + switch (Program.Renderer.CurrentInterface) { - MouseButton = e.Mouse.RightButton == ButtonState.Pressed ? 2 : 0; + case InterfaceType.Menu: + case InterfaceType.GLMainMenu: + Game.Menu.ProcessMouseScroll(e.Delta); + break; } - if (e.Button == OpenTK.Input.MouseButton.Middle) + } + + internal static void MouseMoveEvent(object sender, MouseMoveEventArgs e) + { + switch (Program.Renderer.CurrentInterface) { - MouseButton = e.Mouse.RightButton == ButtonState.Pressed ? 3 : 0; + case InterfaceType.Menu: + case InterfaceType.GLMainMenu: + Game.Menu.ProcessMouseMove(e.X, e.Y); + break; } - previousMouseState = Mouse.GetState(); - if (MouseButton == 0) + } + + internal static void MouseEvent(object sender, MouseButtonEventArgs e) + { + switch (Renderer.CurrentInterface) { - Renderer.Camera.AlignmentDirection.Yaw = 0.0; - Renderer.Camera.AlignmentDirection.Pitch = 0.0; - Renderer.Camera.AlignmentDirection.Position.X = 0.0; - Renderer.Camera.AlignmentDirection.Position.Y = 0.0; + case InterfaceType.Menu: + case InterfaceType.GLMainMenu: + if (e.IsPressed) + { + // viewer hooks up and down to same event + Game.Menu.ProcessMouseDown(e.X, e.Y); + } + break; + default: + if (e.Button == OpenTK.Input.MouseButton.Left) + { + MouseButton = e.Mouse.LeftButton == ButtonState.Pressed ? 1 : 0; + } + if (e.Button == OpenTK.Input.MouseButton.Right) + { + MouseButton = e.Mouse.RightButton == ButtonState.Pressed ? 2 : 0; + } + if (e.Button == OpenTK.Input.MouseButton.Middle) + { + MouseButton = e.Mouse.RightButton == ButtonState.Pressed ? 3 : 0; + } + previousMouseState = Mouse.GetState(); + if (MouseButton == 0) + { + Renderer.Camera.AlignmentDirection.Yaw = 0.0; + Renderer.Camera.AlignmentDirection.Pitch = 0.0; + Renderer.Camera.AlignmentDirection.Position.X = 0.0; + Renderer.Camera.AlignmentDirection.Position.Y = 0.0; + } + break; } + } internal static MouseState currentMouseState; @@ -320,10 +358,8 @@ internal static void MouseEvent(object sender, MouseButtonEventArgs e) internal static void MouseMovement() { - if (MouseButton == 0) - { - return; - } + if (MouseButton == 0 || Program.Renderer.CurrentInterface != InterfaceType.Normal) return; + currentMouseState = Mouse.GetState(); if (currentMouseState != previousMouseState) { @@ -700,7 +736,18 @@ internal static void keyDownEvent(object sender, KeyboardKeyEventArgs e) JumpToPositionEnabled = false; break; case Key.Escape: - JumpToPositionEnabled = false; + if (JumpToPositionEnabled) + { + JumpToPositionEnabled = false; + } + else + { + if (IntPtr.Size != 4) + { + Program.Renderer.CurrentInterface = InterfaceType.Menu; + Game.Menu.PushMenu(MenuType.GameStart); + } + } break; case Key.R: Renderer.SwitchOpenGLVersion(); diff --git a/source/RouteViewer/System/Gamewindow.cs b/source/RouteViewer/System/Gamewindow.cs index 5884089cc..0971265b0 100644 --- a/source/RouteViewer/System/Gamewindow.cs +++ b/source/RouteViewer/System/Gamewindow.cs @@ -87,7 +87,9 @@ protected override void OnLoad(EventArgs e) MouseDown += Program.MouseEvent; MouseUp += Program.MouseEvent; FileDrop += Program.FileDrop; - Program.Renderer.Camera.Reset(new Vector3(0.0, 2.5, -5.0)); + MouseMove += Program.MouseMoveEvent; + MouseWheel += Program.MouseWheelEvent; + Program.Renderer.Camera.Reset(new Vector3(0.0, 2.5, -5.0)); Program.CurrentRoute.CurrentBackground.BackgroundImageDistance = 600.0; Program.Renderer.Camera.ForwardViewingDistance = 600.0; Program.Renderer.Camera.BackwardViewingDistance = 0.0; From 6d06d037509f585d43e488c2996b8c5ec16e962c Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Mon, 9 Sep 2024 17:32:18 +0100 Subject: [PATCH 34/41] Fix: BVE5 routes missing from GL menu --- source/OpenBVE/Game/Menu/Menu.SingleMenu.cs | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs b/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs index 5a68ca8bf..0fbd6ab0d 100644 --- a/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs +++ b/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs @@ -301,8 +301,13 @@ public SingleMenu(MenuType menuType, int data = 0, double MaxWidth = 0) : base(m { continue; } - if (fileName.ToLowerInvariant().EndsWith(".csv") || fileName.ToLowerInvariant().EndsWith(".rw")) + if (fileName.ToLowerInvariant().EndsWith(".csv") || fileName.ToLowerInvariant().EndsWith(".rw") || fileName.EndsWith(".txt")) { + if (fileName.IndexOf("readme", StringComparison.CurrentCultureIgnoreCase) != -1) + { + // block most readme files from trying to be shown as a route + continue; + } Items[totalEntries] = new MenuCommand(fileName, MenuTag.RouteFile, 0); Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\icon_route.png"), new TextureParameters(null, null), out Items[totalEntries].Icon); totalEntries++; From 228c75ac32d1a3ef31c3f03fdb68cab4b59904b7 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Mon, 9 Sep 2024 20:06:50 +0100 Subject: [PATCH 35/41] Minor cleaning --- .../Wavefront/ObjFileMtlImporter.cs | 21 +++++---------- .../AssimpParser/Wavefront/ObjFileParser.cs | 27 ++++++------------- source/AssimpParser/Wavefront/ObjTools.cs | 3 +-- .../Objects/ObjectTypes/AnimatedObject.cs | 3 +-- .../OpenBveApi/System/Hosts/HostInterface.cs | 4 ++- source/RouteViewer/System/Gamewindow.cs | 3 +-- 6 files changed, 21 insertions(+), 40 deletions(-) diff --git a/source/AssimpParser/Wavefront/ObjFileMtlImporter.cs b/source/AssimpParser/Wavefront/ObjFileMtlImporter.cs index fab1a8c5c..be9de0fad 100644 --- a/source/AssimpParser/Wavefront/ObjFileMtlImporter.cs +++ b/source/AssimpParser/Wavefront/ObjFileMtlImporter.cs @@ -279,8 +279,7 @@ private void GetColorRGBA(ref Color128 color) // Loads a single float value. private void GetFloatValue(out float result) { - string tmp; - CopyNextWord(out tmp); + CopyNextWord(out string tmp); result = float.Parse(tmp, NumberStyles.Number, CultureInfo.InvariantCulture); } @@ -389,8 +388,7 @@ private void GetTextureOptionAndName(int clampIndex, ref string result) if (string.Compare(Buffer, DataIt, ClampOption, 0, ClampOption.Length, StringComparison.OrdinalIgnoreCase) == 0) { DataIt = GetNextToken(DataIt, DataEnd); - string tmp; - CopyNextWord(out tmp); + CopyNextWord(out string tmp); if (string.Compare(tmp, 0, "on", 0, 2, StringComparison.OrdinalIgnoreCase) == 0) { clamp = true; @@ -401,8 +399,7 @@ private void GetTextureOptionAndName(int clampIndex, ref string result) else if (string.Compare(Buffer, DataIt, TypeOption, 0, TypeOption.Length, StringComparison.OrdinalIgnoreCase) == 0) { DataIt = GetNextToken(DataIt, DataEnd); - string tmp; - CopyNextWord(out tmp); + CopyNextWord(out string tmp); if (string.Compare(tmp, 0, "cube_top", 0, 8, StringComparison.OrdinalIgnoreCase) == 0) { clampIndex = (int)Material.TextureType.TextureReflectionCubeTopType; @@ -484,8 +481,7 @@ private void GetTextureOptionAndName(int clampIndex, ref string result) private void GetTextureName(ref string result) { - string texture; - DataIt = GetName(DataIt, DataEnd, out texture); + DataIt = GetName(DataIt, DataEnd, out string texture); if (result == null) { result = texture; @@ -501,8 +497,7 @@ private void GetTextureName(ref string result) // Creates a material from loaded data. private void CreateMaterial() { - List token; - int numToken = Tokenize(Buffer, out token, " \t"); + int numToken = Tokenize(Buffer, out List token, " \t"); string name; if (numToken <= 1) { @@ -515,8 +510,7 @@ private void CreateMaterial() } name = name.Trim(new char[] { }); - Material tmp; - if (!Model.MaterialMap.TryGetValue(name, out tmp)) + if (!Model.MaterialMap.TryGetValue(name, out Material tmp)) { // New Material created Model.CurrentMaterial = new Material(name); @@ -537,8 +531,7 @@ private void CreateMaterial() // Loads the kind of illumination model. private void GetIlluminationModel(out int illumModel) { - string tmp; - CopyNextWord(out tmp); + CopyNextWord(out string tmp); illumModel = int.Parse(tmp, NumberStyles.Number, CultureInfo.InvariantCulture); } } diff --git a/source/AssimpParser/Wavefront/ObjFileParser.cs b/source/AssimpParser/Wavefront/ObjFileParser.cs index 811f09550..73682c07b 100644 --- a/source/AssimpParser/Wavefront/ObjFileParser.cs +++ b/source/AssimpParser/Wavefront/ObjFileParser.cs @@ -236,9 +236,7 @@ protected void ParseFile(string[] lines) break; case 'u': // Parse a material desc. setter { - string name; - - GetNameNoSpace(DataIt, DataEnd, out name); + GetNameNoSpace(DataIt, DataEnd, out string name); int nextSpace = name.IndexOf(" ", StringComparison.OrdinalIgnoreCase); if (nextSpace != -1) @@ -254,9 +252,7 @@ protected void ParseFile(string[] lines) break; case 'm': // Parse a material library or merging group ('mg') { - string name; - - GetNameNoSpace(DataIt, DataEnd, out name); + GetNameNoSpace(DataIt, DataEnd, out string name); int nextSpace = name.IndexOf(" ", StringComparison.OrdinalIgnoreCase); if (nextSpace != -1) @@ -336,8 +332,7 @@ protected void GetVector(List point3dArray) protected void GetVector3(List point3dArray) { Vector3 v; - string tmp; - CopyNextWord(out tmp); + CopyNextWord(out string tmp); v.X = float.Parse(tmp, NumberStyles.Number | NumberStyles.AllowExponent, CultureInfo.InvariantCulture); CopyNextWord(out tmp); @@ -353,8 +348,7 @@ protected void GetVector3(List point3dArray) protected void GetHomogeneousVector3(List point3dArray) { Vector3 v; - string tmp; - CopyNextWord(out tmp); + CopyNextWord(out string tmp); v.X = float.Parse(tmp, NumberStyles.Number | NumberStyles.AllowExponent, CultureInfo.InvariantCulture); CopyNextWord(out tmp); @@ -376,8 +370,7 @@ protected void GetHomogeneousVector3(List point3dArray) protected void GetTwoVectors3(List point3dArrayA, List point3dArrayB) { Vector3 a; - string tmp; - CopyNextWord(out tmp); + CopyNextWord(out string tmp); a.X = float.Parse(tmp, NumberStyles.Number | NumberStyles.AllowExponent, CultureInfo.InvariantCulture); CopyNextWord(out tmp); @@ -642,8 +635,7 @@ protected void GetMaterialDesc() if (!skip) { // Search for material - Material tmp; - if (!Model.MaterialMap.TryGetValue(name, out tmp)) + if (!Model.MaterialMap.TryGetValue(name, out Material tmp)) { // Not found, so we don't know anything about the material except for its name. // This may be the case if the material library is missing. We don't want to lose all @@ -765,11 +757,9 @@ protected void GetMaterialLib() // Getter for a group name. protected void GetGroupName() { - string groupName; - // here we skip 'g ' from line DataIt = GetNextToken(DataIt, DataEnd); - DataIt = GetName(DataIt, DataEnd, out groupName); + DataIt = GetName(DataIt, DataEnd, out string groupName); if (IsEndOfBuffer(DataIt, DataEnd)) { return; @@ -783,8 +773,7 @@ protected void GetGroupName() // Search for already existing entry // New group name, creating a new entry - List tmp; - if (!Model.Groups.TryGetValue(groupName, out tmp)) + if (!Model.Groups.TryGetValue(groupName, out List tmp)) { List faceIDArray = new List(); Model.Groups[groupName] = faceIDArray; diff --git a/source/AssimpParser/Wavefront/ObjTools.cs b/source/AssimpParser/Wavefront/ObjTools.cs index 28fb453a9..5e35893dc 100644 --- a/source/AssimpParser/Wavefront/ObjTools.cs +++ b/source/AssimpParser/Wavefront/ObjTools.cs @@ -246,8 +246,7 @@ protected void CopyNextWord(out string result) protected void GetFloat(out float result) { - string tmp; - CopyNextWord(out tmp); + CopyNextWord(out string tmp); result = float.Parse(tmp, NumberStyles.Number, CultureInfo.InvariantCulture); } diff --git a/source/OpenBveApi/Objects/ObjectTypes/AnimatedObject.cs b/source/OpenBveApi/Objects/ObjectTypes/AnimatedObject.cs index 9ec89ab14..9d0a92312 100644 --- a/source/OpenBveApi/Objects/ObjectTypes/AnimatedObject.cs +++ b/source/OpenBveApi/Objects/ObjectTypes/AnimatedObject.cs @@ -7,9 +7,8 @@ using OpenBveApi.Textures; using OpenBveApi.Trains; using OpenBveApi.World; -using static System.Windows.Forms.AxHost; -#pragma warning disable CS0659 // Type overrides Object.Equals(object o) but does not override Object.GetHashCode() +#pragma warning disable CS0659, CS0661 // Type overrides Object.Equals(object o) but does not override Object.GetHashCode() namespace OpenBveApi.Objects { /// The base type for an animated object diff --git a/source/OpenBveApi/System/Hosts/HostInterface.cs b/source/OpenBveApi/System/Hosts/HostInterface.cs index f78e0cd32..7bffbcef3 100644 --- a/source/OpenBveApi/System/Hosts/HostInterface.cs +++ b/source/OpenBveApi/System/Hosts/HostInterface.cs @@ -13,7 +13,6 @@ using OpenBveApi.Textures; using OpenBveApi.Trains; using OpenBveApi.World; -using SharpCompress.Common; using SoundHandle = OpenBveApi.Sounds.SoundHandle; namespace OpenBveApi.Hosts { @@ -151,9 +150,12 @@ public virtual void ReportProblem(ProblemType type, string text) { } + /// Clears the error log public void ClearErrors() { MissingFiles.Clear(); + FailedObjects.Clear(); + FailedTextures.Clear(); } diff --git a/source/RouteViewer/System/Gamewindow.cs b/source/RouteViewer/System/Gamewindow.cs index 5884089cc..fdafe1aaf 100644 --- a/source/RouteViewer/System/Gamewindow.cs +++ b/source/RouteViewer/System/Gamewindow.cs @@ -1,6 +1,5 @@ using System; using System.Collections.Concurrent; -using System.Collections.Generic; using System.ComponentModel; using System.Threading; using OpenBveApi; @@ -183,7 +182,7 @@ public static void LoadingScreenLoop() #pragma warning disable 0649 private static ConcurrentQueue jobs; -#pragma warning enable 0649 +#pragma warning restore 0649 /// This method is used during loading to run commands requiring an OpenGL context in the main render loop /// The OpenGL command From 6b3cb9ffc65a8af41c55d2113e4abf9fe377c5eb Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Mon, 9 Sep 2024 20:26:09 +0100 Subject: [PATCH 36/41] Further cleaning --- source/AssimpParser/Wavefront/ObjFileData.cs | 6 +- source/OpenBVE/Graphics/Renderers/Events.cs | 2 +- .../System/Input/ProcessControls.Analog.cs | 112 +++++------------- 3 files changed, 34 insertions(+), 86 deletions(-) diff --git a/source/AssimpParser/Wavefront/ObjFileData.cs b/source/AssimpParser/Wavefront/ObjFileData.cs index a437c4a75..c732cd7c0 100644 --- a/source/AssimpParser/Wavefront/ObjFileData.cs +++ b/source/AssimpParser/Wavefront/ObjFileData.cs @@ -128,9 +128,9 @@ enum ObjectType //! Object name public readonly string ObjName; //! Transformation matrix, stored in OpenGL format -#pragma warning disable 169 +#pragma warning disable 169, IDE0051 Matrix4D Transformation; -#pragma warning restore 169 +#pragma warning restore 169, IDE0051 //! All sub-objects referenced by this object readonly List SubObjects = new List(); /// Assigned meshes @@ -223,7 +223,7 @@ public class Mesh public const uint NoMaterial = ~0u; /// The name for the mesh - string Name; + readonly string Name; /// Array with pointer to all stored faces public List Faces = new List(); /// Assigned material diff --git a/source/OpenBVE/Graphics/Renderers/Events.cs b/source/OpenBVE/Graphics/Renderers/Events.cs index 3cb979e95..d13544779 100644 --- a/source/OpenBVE/Graphics/Renderers/Events.cs +++ b/source/OpenBVE/Graphics/Renderers/Events.cs @@ -31,7 +31,7 @@ internal class Events private Texture LightingEventTexture; private Texture WeatherEventTexture; private Texture SwitchEventTexture; - private List renderedSwitches = new List(); + private readonly List renderedSwitches = new List(); private bool Initialized; diff --git a/source/OpenBVE/System/Input/ProcessControls.Analog.cs b/source/OpenBVE/System/Input/ProcessControls.Analog.cs index 6e47394c7..c30331ebe 100644 --- a/source/OpenBVE/System/Input/ProcessControls.Analog.cs +++ b/source/OpenBVE/System/Input/ProcessControls.Analog.cs @@ -155,13 +155,8 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control { if (TrainManager.PlayerTrain.Handles.HasHoldBrake) { - double a = Control.AnalogState; - int p = - (int) - Math.Round(a * TrainManager.PlayerTrain.Handles.Power.MaximumNotch); - int b = - (int) - Math.Round(-a * (TrainManager.PlayerTrain.Handles.Brake.MaximumNotch + 2.0)); + int p = (int)Math.Round(Control.AnalogState * TrainManager.PlayerTrain.Handles.Power.MaximumNotch); + int b = (int)Math.Round(-Control.AnalogState * (TrainManager.PlayerTrain.Handles.Brake.MaximumNotch + 2.0)); if (p < 0) p = 0; if (b < 0) b = 0; bool q = b == 1; @@ -184,14 +179,8 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control } else { - double a = Control.AnalogState; - int p = - (int) - Math.Round(a * TrainManager.PlayerTrain.Handles.Power.MaximumNotch); - int b = - (int) - Math.Round(-a * - (TrainManager.PlayerTrain.Handles.Brake.MaximumNotch + 1.0)); + int p = (int)Math.Round(Control.AnalogState * TrainManager.PlayerTrain.Handles.Power.MaximumNotch); + int b = (int)Math.Round(-Control.AnalogState * (TrainManager.PlayerTrain.Handles.Brake.MaximumNotch + 1.0)); if (p < 0) p = 0; if (b < 0) b = 0; if (b <= TrainManager.PlayerTrain.Handles.Brake.MaximumNotch) @@ -219,8 +208,7 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control } // reverser full axis - double als = Control.AnalogState; - TrainManager.PlayerTrain.Handles.Reverser.ApplyState((ReverserPosition)(int)Math.Round(als)); + TrainManager.PlayerTrain.Handles.Reverser.ApplyState((ReverserPosition)(int)Math.Round(Control.AnalogState)); break; case Translations.Command.CameraMoveForward: // camera move forward @@ -232,9 +220,7 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead ? CameraProperties.InteriorTopSpeed : CameraProperties.ExteriorTopSpeed; - Program.Renderer.Camera.AlignmentDirection.Position.Z = s * - Control - .AnalogState; + Program.Renderer.Camera.AlignmentDirection.Position.Z = s * Control.AnalogState; } else { @@ -244,9 +230,7 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control break; } - Program.Renderer.Camera.AlignmentDirection.TrackPosition = CameraProperties.ExteriorTopSpeed * - Control - .AnalogState; + Program.Renderer.Camera.AlignmentDirection.TrackPosition = CameraProperties.ExteriorTopSpeed * Control.AnalogState; } break; @@ -260,9 +244,7 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead ? CameraProperties.InteriorTopSpeed : CameraProperties.ExteriorTopSpeed; - Program.Renderer.Camera.AlignmentDirection.Position.Z = -s * - Control - .AnalogState; + Program.Renderer.Camera.AlignmentDirection.Position.Z = -s * Control.AnalogState; } else { @@ -278,9 +260,7 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead ? CameraProperties.InteriorTopSpeed : CameraProperties.ExteriorTopSpeed; - Program.Renderer.Camera.AlignmentDirection.Position.X = -s * - Control - .AnalogState; + Program.Renderer.Camera.AlignmentDirection.Position.X = -s * Control.AnalogState; } break; case Translations.Command.CameraMoveRight: @@ -290,9 +270,7 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead ? CameraProperties.InteriorTopSpeed : CameraProperties.ExteriorTopSpeed; - Program.Renderer.Camera.AlignmentDirection.Position.X = s * - Control - .AnalogState; + Program.Renderer.Camera.AlignmentDirection.Position.X = s * Control.AnalogState; } break; case Translations.Command.CameraMoveUp: @@ -302,9 +280,7 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead ? CameraProperties.InteriorTopSpeed : CameraProperties.ExteriorTopSpeed; - Program.Renderer.Camera.AlignmentDirection.Position.Y = s * - Control - .AnalogState; + Program.Renderer.Camera.AlignmentDirection.Position.Y = s * Control.AnalogState; } break; case Translations.Command.CameraMoveDown: @@ -314,9 +290,7 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead ? CameraProperties.InteriorTopSpeed : CameraProperties.ExteriorTopSpeed; - Program.Renderer.Camera.AlignmentDirection.Position.Y = -s * - Control - .AnalogState; + Program.Renderer.Camera.AlignmentDirection.Position.Y = -s * Control.AnalogState; } break; case Translations.Command.CameraRotateLeft: @@ -346,8 +320,7 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead ? CameraProperties.InteriorTopAngularSpeed : CameraProperties.ExteriorTopAngularSpeed; - Program.Renderer.Camera.AlignmentDirection.Pitch = s * - Control.AnalogState; + Program.Renderer.Camera.AlignmentDirection.Pitch = s * Control.AnalogState; } break; case Translations.Command.CameraRotateDown: @@ -357,8 +330,7 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead ? CameraProperties.InteriorTopAngularSpeed : CameraProperties.ExteriorTopAngularSpeed; - Program.Renderer.Camera.AlignmentDirection.Pitch = -s * - Control.AnalogState; + Program.Renderer.Camera.AlignmentDirection.Pitch = -s * Control.AnalogState; } break; case Translations.Command.CameraRotateCCW: @@ -371,9 +343,7 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead ? CameraProperties.InteriorTopAngularSpeed : CameraProperties.ExteriorTopAngularSpeed; - Program.Renderer.Camera.AlignmentDirection.Roll = -s * - Control - .AnalogState; + Program.Renderer.Camera.AlignmentDirection.Roll = -s * Control.AnalogState; } break; @@ -387,9 +357,7 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control Program.Renderer.Camera.CurrentMode == CameraViewMode.InteriorLookAhead ? CameraProperties.InteriorTopAngularSpeed : CameraProperties.ExteriorTopAngularSpeed; - Program.Renderer.Camera.AlignmentDirection.Roll = s * - Control - .AnalogState; + Program.Renderer.Camera.AlignmentDirection.Roll = s * Control.AnalogState; } break; @@ -397,9 +365,7 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control // camera zoom in if (TimeElapsed > 0.0) { - Program.Renderer.Camera.AlignmentDirection.Zoom = -CameraProperties.ZoomTopSpeed * - Control - .AnalogState; + Program.Renderer.Camera.AlignmentDirection.Zoom = -CameraProperties.ZoomTopSpeed * Control.AnalogState; } break; @@ -407,9 +373,7 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control // camera zoom out if (TimeElapsed > 0.0) { - Program.Renderer.Camera.AlignmentDirection.Zoom = CameraProperties.ZoomTopSpeed * - Control - .AnalogState; + Program.Renderer.Camera.AlignmentDirection.Zoom = CameraProperties.ZoomTopSpeed * Control.AnalogState; } break; @@ -420,17 +384,13 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control const double scrollSpeed = 250.0; if (Program.Renderer.CurrentTimetable == DisplayedTimetable.Default) { - Timetable.DefaultTimetablePosition += scrollSpeed * - Control - .AnalogState * TimeElapsed; + Timetable.DefaultTimetablePosition += scrollSpeed * Control.AnalogState * TimeElapsed; if (Timetable.DefaultTimetablePosition > 0.0) Timetable.DefaultTimetablePosition = 0.0; } else if (Program.Renderer.CurrentTimetable == DisplayedTimetable.Custom) { - Timetable.CustomTimetablePosition += scrollSpeed * - Control - .AnalogState * TimeElapsed; + Timetable.CustomTimetablePosition += scrollSpeed * Control.AnalogState * TimeElapsed; if (Timetable.CustomTimetablePosition > 0.0) Timetable.CustomTimetablePosition = 0.0; } @@ -444,18 +404,12 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control const double scrollSpeed = 250.0; if (Program.Renderer.CurrentTimetable == DisplayedTimetable.Default) { - Timetable.DefaultTimetablePosition -= scrollSpeed * - Control - .AnalogState * TimeElapsed; + Timetable.DefaultTimetablePosition -= scrollSpeed * Control.AnalogState * TimeElapsed; double max; if (Timetable.DefaultTimetableTexture != null) { - Program.CurrentHost.LoadTexture(ref Timetable.DefaultTimetableTexture, - OpenGlTextureWrapMode.ClampClamp); - max = - Math.Min( - Program.Renderer.Screen.Height - Timetable.DefaultTimetableTexture.Height, - 0.0); + Program.CurrentHost.LoadTexture(ref Timetable.DefaultTimetableTexture, OpenGlTextureWrapMode.ClampClamp); + max = Math.Min(Program.Renderer.Screen.Height - Timetable.DefaultTimetableTexture.Height, 0.0); } else { @@ -463,25 +417,18 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control } if (Timetable.DefaultTimetablePosition < max) + { Timetable.DefaultTimetablePosition = max; + } } else if (Program.Renderer.CurrentTimetable == DisplayedTimetable.Custom) { - Timetable.CustomTimetablePosition -= scrollSpeed * - Control - .AnalogState * TimeElapsed; - Texture texture = - Timetable.CurrentCustomTimetableDaytimeTexture; - if (texture == null) - { - texture = Timetable.CurrentCustomTimetableNighttimeTexture; - } - + Timetable.CustomTimetablePosition -= scrollSpeed * Control.AnalogState * TimeElapsed; + Texture texture = Timetable.CurrentCustomTimetableDaytimeTexture ?? Timetable.CurrentCustomTimetableNighttimeTexture; double max; if (texture != null) { - Program.CurrentHost.LoadTexture(ref texture, - OpenGlTextureWrapMode.ClampClamp); + Program.CurrentHost.LoadTexture(ref texture, OpenGlTextureWrapMode.ClampClamp); max = Math.Min(Program.Renderer.Screen.Height - texture.Height, 0.0); } else @@ -490,10 +437,11 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control } if (Timetable.CustomTimetablePosition < max) + { Timetable.CustomTimetablePosition = max; + } } } - break; } } From 0efea734a306367d894d024c8ecf98b0fefb2aa1 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Wed, 11 Sep 2024 10:37:13 +0100 Subject: [PATCH 37/41] Get things previewing and loading --- source/RouteViewer/Game/Menu.SingleMenu.cs | 11 ++ source/RouteViewer/Game/Menu.cs | 193 +++++++++++++++++++-- source/RouteViewer/GameR.cs | 8 +- 3 files changed, 196 insertions(+), 16 deletions(-) diff --git a/source/RouteViewer/Game/Menu.SingleMenu.cs b/source/RouteViewer/Game/Menu.SingleMenu.cs index a76c02774..b5d1cf736 100644 --- a/source/RouteViewer/Game/Menu.SingleMenu.cs +++ b/source/RouteViewer/Game/Menu.SingleMenu.cs @@ -8,6 +8,8 @@ using OpenBveApi.Math; using Path = OpenBveApi.Path; using RouteViewer; +using OpenBveApi.Packages; +using System.ComponentModel; namespace RouteViewer { @@ -29,6 +31,15 @@ public SingleMenu(AbstractMenu menu, MenuType menuType, int data = 0, double Max switch (menuType) { case MenuType.GameStart: // top level menu + if (routeWorkerThread == null) + { + //Create the worker threads on first launch of main menu + routeWorkerThread = new BackgroundWorker(); + routeWorkerThread.DoWork += routeWorkerThread_doWork; + routeWorkerThread.RunWorkerCompleted += routeWorkerThread_completed; + //Load texture + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\loading.png"), new TextureParameters(null, null), out routePictureBox.Texture); + } Items = new MenuEntry[4]; Items[0] = new MenuCommand(menu, "Open Route File", MenuTag.RouteList, 0); Items[1] = new MenuCommand(menu, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "title" }), MenuTag.Options, 0); diff --git a/source/RouteViewer/Game/Menu.cs b/source/RouteViewer/Game/Menu.cs index a6c91ffe0..e5212f194 100644 --- a/source/RouteViewer/Game/Menu.cs +++ b/source/RouteViewer/Game/Menu.cs @@ -1,28 +1,34 @@ using System; +using System.ComponentModel; using System.IO; +using System.Text; using LibRender2.Menu; using LibRender2.Primitives; using LibRender2.Screens; +using OpenBveApi; using OpenBveApi.Colors; using OpenBveApi.Graphics; using OpenBveApi.Hosts; using OpenBveApi.Input; using OpenBveApi.Interface; using OpenBveApi.Math; +using OpenBveApi.Routes; using OpenBveApi.Textures; -using RouteViewer; +using RouteManager2; using Path = OpenBveApi.Path; namespace RouteViewer { public sealed partial class GameMenu : AbstractMenu { - - internal Picturebox filePictureBox; - internal Textbox fileTextBox; private double lastTimeElapsed; private static string SearchDirectory; private static string currentFile; + private static RouteState RoutefileState; + private static BackgroundWorker routeWorkerThread; + private static Textbox routeDescriptionBox; + private static Picturebox routePictureBox = new Picturebox(Program.Renderer); + private static Encoding RouteEncoding; /// Returns the current menu instance (If applicable) public static GameMenu Instance; @@ -33,8 +39,8 @@ internal GameMenu() : base(Program.Renderer, Interface.CurrentOptions) public override void Initialize() { - filePictureBox = new Picturebox(Renderer); - fileTextBox = new Textbox(Renderer, Renderer.Fonts.NormalFont, Color128.White, Color128.Black); + routePictureBox = new Picturebox(Renderer); + routeDescriptionBox = new Textbox(Renderer, Renderer.Fonts.NormalFont, Color128.White, Color128.Black); Reset(); // choose the text font size according to screen height // the boundaries follow approximately the progression @@ -56,13 +62,14 @@ public override void Initialize() { descriptionHeight = Renderer.Screen.Height - quarterWidth - 50; } - fileTextBox.Location = new Vector2(descriptionLoc, quarterWidth); - fileTextBox.Size = new Vector2(descriptionWidth, descriptionHeight); + routeDescriptionBox.Location = new Vector2(descriptionLoc, quarterWidth); + routeDescriptionBox.Size = new Vector2(descriptionWidth, descriptionHeight); int imageLoc = Renderer.Screen.Width - quarterWidth - quarterWidth / 4; - filePictureBox.Location = new Vector2(imageLoc, 0); - filePictureBox.Size = new Vector2(quarterWidth, quarterWidth); - filePictureBox.BackgroundColor = Color128.White; + routePictureBox.Location = new Vector2(imageLoc, 0); + routePictureBox.Size = new Vector2(quarterWidth, quarterWidth); + routePictureBox.BackgroundColor = Color128.White; SearchDirectory = Interface.CurrentOptions.RouteSearchDirectory; + IsInitialized = true; } @@ -119,6 +126,22 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed } if (menu.Selection == -1) // if menu has no selection, do nothing return; + if (menu.Selection == int.MaxValue) + { + if (menu.Type == MenuType.RouteList && RoutefileState == RouteState.Processed) + { + Program.CurrentRouteFile = currentFile; + Program.UpdateCaption(); + Program.LoadRoute(); + ObjectManager.UpdateAnimatedWorldObjects(0.0, true); + Program.CurrentlyLoading = false; + Renderer.Camera.Reset(Program.CurrentRoute.Tracks[0].Direction == TrackDirection.Reverse); + Program.UpdateCaption(); + Reset(); + Renderer.CurrentInterface = InterfaceType.Normal; + } + return; + } switch (cmd) { case Translations.Command.MenuUp: // UP @@ -167,8 +190,16 @@ public override void ProcessCommand(Translations.Command cmd, double timeElapsed break; case MenuTag.RouteList: // TO ROUTE LIST MENU Instance.PushMenu(MenuType.RouteList); - fileTextBox.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "errors", "route_please_select" }); - Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\please_select.png"), new TextureParameters(null, null), out filePictureBox.Texture); + routeDescriptionBox.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "errors", "route_please_select" }); + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\please_select.png"), new TextureParameters(null, null), out routePictureBox.Texture); + break; + case MenuTag.RouteFile: + RoutefileState = RouteState.Loading; + currentFile = Path.CombineFile(SearchDirectory, menu.Items[menu.Selection].Text); + if (!routeWorkerThread.IsBusy) + { + routeWorkerThread.RunWorkerAsync(); + } break; case MenuTag.ErrorList: Instance.PushMenu(MenuType.ErrorList); @@ -231,13 +262,17 @@ public override bool ProcessMouseMove(int x, int y) } if (menu.Type == MenuType.RouteList || menu.Type == MenuType.TrainList || menu.Type == MenuType.PackageInstall || menu.Type == MenuType.Packages || (int)menu.Type >= 107) { - fileTextBox.MouseMove(x, y); + routeDescriptionBox.MouseMove(x, y); //HACK: Use this to trigger our menu start button! if (x > Renderer.Screen.Width - 200 && x < Renderer.Screen.Width - 10 && y > Renderer.Screen.Height - 40 && y < Renderer.Screen.Height - 10) { menu.Selection = int.MaxValue; return true; } + else + { + menu.Selection = int.MinValue; + } } if (x < menuMin.X || x > menuMax.X || y < menuMin.Y || y > menuMax.Y) { @@ -382,6 +417,136 @@ public override void Draw(double RealTimeElapsed) if (i < menu.Items.Length - 1) Renderer.OpenGlString.Draw(MenuFont, @"...", new Vector2(itemX, itemY), menu.Align, ColourDimmed, false); + + if (menu.Type == MenuType.RouteList) + { + routePictureBox.Draw(); + routeDescriptionBox.Draw(); + bool allowNextPhase = menu.Type == MenuType.RouteList && RoutefileState == RouteState.Processed; + + if (menu.Selection == int.MaxValue && allowNextPhase) //HACK: Special value to make this work with minimum extra code + { + Program.Renderer.Rectangle.Draw(null, new Vector2(Program.Renderer.Screen.Width - 200, Program.Renderer.Screen.Height - 40), new Vector2(190, 30), Color128.Black); + Program.Renderer.Rectangle.Draw(null, new Vector2(Program.Renderer.Screen.Width - 197, Program.Renderer.Screen.Height - 37), new Vector2(184, 24), highlightColor); + Program.Renderer.OpenGlString.Draw(MenuFont, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "start", "start_start" }), new Vector2(Program.Renderer.Screen.Width - 180, Program.Renderer.Screen.Height - 35), TextAlignment.TopLeft, Color128.Black); + } + else + { + Program.Renderer.Rectangle.Draw(null, new Vector2(Program.Renderer.Screen.Width - 200, Program.Renderer.Screen.Height - 40), new Vector2(190, 30), Color128.Black); + Program.Renderer.OpenGlString.Draw(MenuFont, Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "start", "start_start" }), new Vector2(Program.Renderer.Screen.Width - 180, Program.Renderer.Screen.Height - 35), TextAlignment.TopLeft, Color128.Grey); + } + } + } + + private static void routeWorkerThread_doWork(object sender, DoWorkEventArgs e) + { + if (string.IsNullOrEmpty(currentFile)) + { + return; + } + RouteEncoding = TextEncoding.GetSystemEncodingFromFile(currentFile); + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\loading.png"), new TextureParameters(null, null), out routePictureBox.Texture); + routeDescriptionBox.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "start", "route_processing" }); + Game.Reset(false); + bool loaded = false; + for (int i = 0; i < Program.CurrentHost.Plugins.Length; i++) + { + if (Program.CurrentHost.Plugins[i].Route != null && Program.CurrentHost.Plugins[i].Route.CanLoadRoute(currentFile)) + { + // ReSharper disable once RedundantCast + object Route = (object)Program.CurrentRoute; // must cast to allow us to use the ref keyword correctly. + string RailwayFolder = Loading.GetRailwayFolder(currentFile); + string ObjectFolder = Path.CombineDirectory(RailwayFolder, "Object"); + string SoundFolder = Path.CombineDirectory(RailwayFolder, "Sound"); + if (Program.CurrentHost.Plugins[i].Route.LoadRoute(currentFile, RouteEncoding, null, ObjectFolder, SoundFolder, true, ref Route)) + { + Program.CurrentRoute = (CurrentRoute)Route; + } + else + { + if (Program.CurrentHost.Plugins[i].Route.LastException != null) + { + throw Program.CurrentHost.Plugins[i].Route.LastException; //Re-throw last exception generated by the route parser plugin so that the UI thread captures it + } + routeDescriptionBox.Text = "An unknown error was enountered whilst attempting to parse the routefile " + currentFile; + RoutefileState = RouteState.Error; + } + loaded = true; + break; + } + } + + if (!loaded) + { + throw new Exception("No plugins capable of loading routefile " + currentFile + " were found."); + } + } + + private static void routeWorkerThread_completed(object sender, RunWorkerCompletedEventArgs e) + { + RoutefileState = RouteState.Processed; + if (e.Error != null || Program.CurrentRoute == null) + { + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\route_error.png"), new TextureParameters(null, null), out routePictureBox.Texture); + if (e.Error != null) + { + routeDescriptionBox.Text = e.Error.Message; + RoutefileState = RouteState.Error; + } + routeWorkerThread.Dispose(); + return; + } + try + { + // image + if (!string.IsNullOrEmpty(Program.CurrentRoute.Image)) + { + + try + { + if (File.Exists(Program.CurrentRoute.Image)) + { + Program.CurrentHost.RegisterTexture(Program.CurrentRoute.Image, new TextureParameters(null, null), out routePictureBox.Texture); + } + else + { + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\route_unknown.png"), new TextureParameters(null, null), out routePictureBox.Texture); + } + + } + catch + { + routePictureBox.Texture = null; + } + } + else + { + string[] f = { ".png", ".bmp", ".gif", ".tiff", ".tif", ".jpeg", ".jpg" }; + int i; + for (i = 0; i < f.Length; i++) + { + string g = Path.CombineFile(Path.GetDirectoryName(currentFile), + System.IO.Path.GetFileNameWithoutExtension(currentFile) + f[i]); + if (!File.Exists(g)) continue; + Program.CurrentHost.RegisterTexture(g, new TextureParameters(null, null), out routePictureBox.Texture); + break; + } + if (i == f.Length) + { + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\route_unknown.png"), new TextureParameters(null, null), out routePictureBox.Texture); + } + } + + // description + string Description = Program.CurrentRoute.Comment.ConvertNewlinesToCrLf(); + routeDescriptionBox.Text = Description.Length != 0 ? Description : System.IO.Path.GetFileNameWithoutExtension(currentFile); + } + catch (Exception ex) + { + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\route_error.png"), new TextureParameters(null, null), out routePictureBox.Texture); + routeDescriptionBox.Text = ex.Message; + currentFile = null; + } } } } diff --git a/source/RouteViewer/GameR.cs b/source/RouteViewer/GameR.cs index 653122277..49e83eacd 100644 --- a/source/RouteViewer/GameR.cs +++ b/source/RouteViewer/GameR.cs @@ -29,8 +29,12 @@ internal static class Game { // ================================ - internal static void Reset() { - Program.Renderer.Reset(); + internal static void Reset(bool resetRenderer = true) { + if (resetRenderer) + { + Program.Renderer.Reset(); + } + // track manager Program.CurrentRoute.Tracks = new Dictionary(); Program.CurrentRoute.Tracks.Add(0, new Track()); From 21325c0d281d296d51ef813d4374d0214b047e81 Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Wed, 11 Sep 2024 16:36:56 +0100 Subject: [PATCH 38/41] Implement keyconfigs --- source/RouteViewer/Game/Menu.cs | 5 +---- source/RouteViewer/NewRendererR.cs | 21 ++++++++++++++++----- source/RouteViewer/ProgramR.cs | 19 ++++++++++++++++++- 3 files changed, 35 insertions(+), 10 deletions(-) diff --git a/source/RouteViewer/Game/Menu.cs b/source/RouteViewer/Game/Menu.cs index e5212f194..5169f315c 100644 --- a/source/RouteViewer/Game/Menu.cs +++ b/source/RouteViewer/Game/Menu.cs @@ -269,10 +269,7 @@ public override bool ProcessMouseMove(int x, int y) menu.Selection = int.MaxValue; return true; } - else - { - menu.Selection = int.MinValue; - } + menu.Selection = int.MinValue; } if (x < menuMin.X || x > menuMax.X || y < menuMin.Y || y > menuMax.Y) { diff --git a/source/RouteViewer/NewRendererR.cs b/source/RouteViewer/NewRendererR.cs index d1c6443ba..0feb3d02c 100644 --- a/source/RouteViewer/NewRendererR.cs +++ b/source/RouteViewer/NewRendererR.cs @@ -567,11 +567,22 @@ private void RenderOverlays(double timeElapsed) else if (OptionInterface) { // keys - keys = new[] { new[] { "F5" }, new[] { "F7" }, new[] { "F8" } }; - Keys.Render(4, 4, 24, Fonts.SmallFont, keys); - OpenGlString.Draw(Fonts.SmallFont, "Reload route", new Vector2(32, 4), TextAlignment.TopLeft, Color128.White, true); - OpenGlString.Draw(Fonts.SmallFont, "Open route", new Vector2(32, 24), TextAlignment.TopLeft, Color128.White, true); - OpenGlString.Draw(Fonts.SmallFont, "Display the options window", new Vector2(32, 44), TextAlignment.TopLeft, Color128.White, true); + if (Program.CurrentHost.Platform == HostPlatform.AppleOSX && IntPtr.Size != 4) + { + keys = new[] { new[] { "F5" }, new[] { "esc" } }; + Keys.Render(4, 4, 24, Fonts.SmallFont, keys); + OpenGlString.Draw(Fonts.SmallFont, "Reload route", new Vector2(32, 4), TextAlignment.TopLeft, Color128.White, true); + OpenGlString.Draw(Fonts.SmallFont, "Display the menu", new Vector2(32, 24), TextAlignment.TopLeft, Color128.White, true); + } + else + { + keys = new[] { new[] { "F5" }, new[] { "F7" }, new[] { "F8" } }; + Keys.Render(4, 4, 24, Fonts.SmallFont, keys); + OpenGlString.Draw(Fonts.SmallFont, "Reload route", new Vector2(32, 4), TextAlignment.TopLeft, Color128.White, true); + OpenGlString.Draw(Fonts.SmallFont, "Open route", new Vector2(32, 24), TextAlignment.TopLeft, Color128.White, true); + OpenGlString.Draw(Fonts.SmallFont, "Display the options window", new Vector2(32, 44), TextAlignment.TopLeft, Color128.White, true); + } + keys = new[] { new[] { "F" }, new[] { "N" }, new[] { "E" }, new[] { "M" }, new[] { "I" } }; Keys.Render(Screen.Width - 20, 4, 16, Fonts.SmallFont, keys); diff --git a/source/RouteViewer/ProgramR.cs b/source/RouteViewer/ProgramR.cs index 38758f755..c2e4612fe 100644 --- a/source/RouteViewer/ProgramR.cs +++ b/source/RouteViewer/ProgramR.cs @@ -462,6 +462,11 @@ internal static void keyDownEvent(object sender, KeyboardKeyEventArgs e) } break; case Key.F7: + if (Program.CurrentHost.Platform == HostPlatform.AppleOSX && IntPtr.Size != 4) + { + return; + } + if (CurrentlyLoading) { break; @@ -539,6 +544,11 @@ internal static void keyDownEvent(object sender, KeyboardKeyEventArgs e) Dialog.Dispose(); break; case Key.F8: + if (Program.CurrentHost.Platform == HostPlatform.AppleOSX && IntPtr.Size != 4) + { + return; + } + if (CurrentlyLoading) { //Don't allow the user to update the settings during loading, bad idea.. @@ -554,6 +564,13 @@ internal static void keyDownEvent(object sender, KeyboardKeyEventArgs e) Renderer.Camera.AlignmentDirection.Position.Y = 0; break; case Key.F9: + if (Program.CurrentHost.Platform == HostPlatform.AppleOSX && IntPtr.Size != 4) + { + Program.Renderer.CurrentInterface = InterfaceType.Menu; + Game.Menu.PushMenu(MenuType.ErrorList); + return; + } + if (Interface.LogMessages.Count != 0) { formMessages.ShowMessages(); @@ -742,7 +759,7 @@ internal static void keyDownEvent(object sender, KeyboardKeyEventArgs e) } else { - if (IntPtr.Size != 4) + if (Program.CurrentHost.Platform == HostPlatform.AppleOSX && IntPtr.Size != 4) { Program.Renderer.CurrentInterface = InterfaceType.Menu; Game.Menu.PushMenu(MenuType.GameStart); From 3577b56d25346a54325812800b8381dd5d38579e Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Wed, 11 Sep 2024 16:54:37 +0100 Subject: [PATCH 39/41] Update contributing and readme files [skip ci] --- Contributing.md | 17 +++++++++++++++-- Readme.md | 7 +++++-- 2 files changed, 20 insertions(+), 4 deletions(-) diff --git a/Contributing.md b/Contributing.md index 80acd5bfe..3a4de7fb6 100644 --- a/Contributing.md +++ b/Contributing.md @@ -11,8 +11,21 @@ This file is a work in progress, and is intended to serve as a general set of gu #### Code Licencing -The basic licence for openBVE is Public Domain. -Please only contribute code which is licenced under either Public Domain, or loose permissive licences (e.g. BSD-2 and compatible) +The original codebase for OpenBVE is licenced under the public domain. (Please see https://github.com/leezer3/OpenBVE/issues/305 for further details and discussion) + +However, over the last 10+ years, we've found that not having a recognised OSS licence can be more of a hindrance than a help. + + +With this in mind, we've chosen to move to using the BSD-2 clause licence for newer code contributions. + +We're also happy to accept code under similar loose, permissive licences that maintain the spirit of the original public domain aims. + + +New code should clearly state the author and licence (if applicable) in the file header. + + +Please do not contribute code under the GPL or simiar 'viral' or restrictive licences. + ### Backwards Compatibility diff --git a/Readme.md b/Readme.md index 606fd4fd7..cb8c1fcdd 100644 --- a/Readme.md +++ b/Readme.md @@ -6,7 +6,10 @@ This repository contains the source code for the Train Simulator OpenBVE, a 3D cab based simulator. -The simulator supports both native CSV / RW routes, and routes built for the legacy DOS based simulator Mechanik. +The simulator supports the following route formats: +* Native CSV / RW. +* BVE5 TXT format. +* Mechanik DAT format. OpenBVE is built in OpenGL, using the OpenTK framework for windowing. @@ -53,7 +56,7 @@ http://bveworldwide.forumotion.com/f14-the-sim-in-time-general-discussion ### License The original founder of this project, Michelle intended for this program to be placed in the public domain. -In practice over the last 10 years I've been maintaining this, we've found that whilst public domain was a noble idea, having no recognised licence and attempting to disclaim copyright tends to produce many of it's own challenges. +In practice over the last 10+ years I've been maintaining this, we've found that whilst public domain was a noble idea, having no recognised licence and attempting to disclaim copyright tends to produce many of it's own challenges. As a result, all new code is licenced under BSD-2 or a similar permissive licence (as appropriate)- Please see the source headers. From 6c8d3afef0af7212c7a9ec27efd1384b05adb69a Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Wed, 11 Sep 2024 18:41:30 +0100 Subject: [PATCH 40/41] Cleaning --- source/AssimpParser/Wavefront/ObjFileData.cs | 6 ----- .../DenshaDeGoInput/DenshaDeGoInput.csproj | 1 + .../LibRender2/Menu/MenuEntries/MenuEntry.cs | 2 +- source/ObjectViewer/Game/Menu.SingleMenu.cs | 2 -- source/ObjectViewer/ProgramS.cs | 3 ++- source/OpenBVE/Game/Menu/Menu.SingleMenu.cs | 3 --- source/OpenBVE/UserInterface/formMain.cs | 1 - .../Plugins/Object.DirectX/Helpers/Block.cs | 2 +- .../Route.CsvRw/Namespaces/NonTrack/Train.cs | 2 +- source/Plugins/Texture.Ace/Plugin.Parser.cs | 3 ++- source/Plugins/Texture.Tga/Plugin.Parser.cs | 2 +- .../RouteManager2/Illustrations/RouteMap.cs | 3 ++- source/RouteViewer/Game/Menu.SingleMenu.cs | 2 -- source/TrainEditor/Options.cs | 1 - .../IO/IntermediateFile/Parser.cs | 4 +-- .../IO/IntermediateFile/Writer.cs | 6 ++--- source/TrainEditor2/Models/App.cs | 9 ++----- source/TrainEditor2/Models/Panels/Panel.cs | 27 +++++-------------- .../Models/Panels/TouchElement.cs | 8 ++---- source/TrainEditor2/Models/Sounds/Sound.cs | 4 +-- .../ViewModels/Sounds/SoundViewModel.cs | 14 +++------- 21 files changed, 30 insertions(+), 75 deletions(-) diff --git a/source/AssimpParser/Wavefront/ObjFileData.cs b/source/AssimpParser/Wavefront/ObjFileData.cs index c732cd7c0..3dbb2c43e 100644 --- a/source/AssimpParser/Wavefront/ObjFileData.cs +++ b/source/AssimpParser/Wavefront/ObjFileData.cs @@ -119,12 +119,6 @@ public Face(PrimitiveType pt = PrimitiveType.PrimitiveType_POLYGON) // ------------------------------------------------------------------------------------------------ public class WavefrontObject { - enum ObjectType - { - ObjType, - GroupType - }; - //! Object name public readonly string ObjName; //! Transformation matrix, stored in OpenGL format diff --git a/source/InputDevicePlugins/DenshaDeGoInput/DenshaDeGoInput.csproj b/source/InputDevicePlugins/DenshaDeGoInput/DenshaDeGoInput.csproj index c449bb613..c050af905 100644 --- a/source/InputDevicePlugins/DenshaDeGoInput/DenshaDeGoInput.csproj +++ b/source/InputDevicePlugins/DenshaDeGoInput/DenshaDeGoInput.csproj @@ -79,6 +79,7 @@ Help.cs + Designer udev_rules diff --git a/source/LibRender2/Menu/MenuEntries/MenuEntry.cs b/source/LibRender2/Menu/MenuEntries/MenuEntry.cs index dde63643d..9f8434c2d 100644 --- a/source/LibRender2/Menu/MenuEntries/MenuEntry.cs +++ b/source/LibRender2/Menu/MenuEntries/MenuEntry.cs @@ -88,7 +88,7 @@ public int DisplayLength private int scroll; private bool pause; - public MenuEntry(AbstractMenu menu) + protected MenuEntry(AbstractMenu menu) { BaseMenu = menu; } diff --git a/source/ObjectViewer/Game/Menu.SingleMenu.cs b/source/ObjectViewer/Game/Menu.SingleMenu.cs index 5eb63ef75..f5590cd2d 100644 --- a/source/ObjectViewer/Game/Menu.SingleMenu.cs +++ b/source/ObjectViewer/Game/Menu.SingleMenu.cs @@ -19,8 +19,6 @@ private class SingleMenu : MenuBase { public SingleMenu(AbstractMenu menu, MenuType menuType, int data = 0, double MaxWidth = 0) : base(menuType) { - int i; - int jump = 0; //Vector2 size; Align = TextAlignment.TopMiddle; Height = Width = 0; diff --git a/source/ObjectViewer/ProgramS.cs b/source/ObjectViewer/ProgramS.cs index fdd3a1321..34b52d817 100644 --- a/source/ObjectViewer/ProgramS.cs +++ b/source/ObjectViewer/ProgramS.cs @@ -565,8 +565,9 @@ internal static void KeyDown(object sender, KeyboardKeyEventArgs e) case Key.B: if (ShiftPressed) { - using (ColorDialog dialog = new ColorDialog {FullOpen = true}) + using (ColorDialog dialog = new ColorDialog()) { + dialog.FullOpen = true; if (dialog.ShowDialog() == DialogResult.OK) { Renderer.BackgroundColor = -1; diff --git a/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs b/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs index c2c125ea3..c18dae528 100644 --- a/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs +++ b/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs @@ -22,9 +22,6 @@ public sealed partial class GameMenu /// access from Menu itself. private class SingleMenu : MenuBase { - /// The previous menu selection - internal int LastSelection = int.MaxValue; - private int currentSelection; public sealed override int Selection diff --git a/source/OpenBVE/UserInterface/formMain.cs b/source/OpenBVE/UserInterface/formMain.cs index 2d4e31993..ae6dd6502 100644 --- a/source/OpenBVE/UserInterface/formMain.cs +++ b/source/OpenBVE/UserInterface/formMain.cs @@ -52,7 +52,6 @@ internal static LaunchParameters ShowMainDialog(LaunchParameters initial) Dialog.trainWatcher.Dispose(); Dialog.routeWatcher.Dispose(); } - Dialog.Dispose(); return result; } } diff --git a/source/Plugins/Object.DirectX/Helpers/Block.cs b/source/Plugins/Object.DirectX/Helpers/Block.cs index 2398d9ccc..d3dfb56d5 100644 --- a/source/Plugins/Object.DirectX/Helpers/Block.cs +++ b/source/Plugins/Object.DirectX/Helpers/Block.cs @@ -92,7 +92,7 @@ public static Block ReadBlock(string text, TemplateID token) /// The type of the new block will always match that of the base block public abstract Block ReadSubBlock(); - public Block(int floatingPointSize = -1) + protected Block(int floatingPointSize = -1) { FloatingPointSize = floatingPointSize; } diff --git a/source/Plugins/Route.CsvRw/Namespaces/NonTrack/Train.cs b/source/Plugins/Route.CsvRw/Namespaces/NonTrack/Train.cs index 3442f7ecf..292e13c0b 100644 --- a/source/Plugins/Route.CsvRw/Namespaces/NonTrack/Train.cs +++ b/source/Plugins/Route.CsvRw/Namespaces/NonTrack/Train.cs @@ -126,7 +126,7 @@ private void ParseTrainCommand(TrainCommand Command, string[] Arguments, int Ind { Arguments[0] = "http://" + Arguments[0]; } - if (Uri.TryCreate(Arguments[0], UriKind.Absolute, out Uri uriResult) && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps) && uriResult.Host.Replace("www.", "").Split('.').Count() > 1 && uriResult.HostNameType == UriHostNameType.Dns && uriResult.Host.Length > uriResult.Host.LastIndexOf(".") + 1 && 100 >= Arguments[0].Length) + if (Uri.TryCreate(Arguments[0], UriKind.Absolute, out Uri uriResult) && (uriResult.Scheme == Uri.UriSchemeHttp || uriResult.Scheme == Uri.UriSchemeHttps) && uriResult.Host.Replace("www.", "").Split('.').Count() > 1 && uriResult.HostNameType == UriHostNameType.Dns && uriResult.Host.Length > uriResult.Host.LastIndexOf(".", StringComparison.InvariantCulture) + 1 && 100 >= Arguments[0].Length) { // Why not save to the log... Plugin.FileSystem.AppendToLogFile("INFO: Route default train download location " + Arguments[0]); diff --git a/source/Plugins/Texture.Ace/Plugin.Parser.cs b/source/Plugins/Texture.Ace/Plugin.Parser.cs index 9a69ee9e1..e02c9292e 100644 --- a/source/Plugins/Texture.Ace/Plugin.Parser.cs +++ b/source/Plugins/Texture.Ace/Plugin.Parser.cs @@ -5,7 +5,8 @@ using OpenBveApi.Textures; namespace Texture.Ace { - public partial class Plugin : TextureInterface { + public partial class Plugin + { // --- get colors --- diff --git a/source/Plugins/Texture.Tga/Plugin.Parser.cs b/source/Plugins/Texture.Tga/Plugin.Parser.cs index 74a546962..b7e0b13f6 100644 --- a/source/Plugins/Texture.Tga/Plugin.Parser.cs +++ b/source/Plugins/Texture.Tga/Plugin.Parser.cs @@ -13,7 +13,7 @@ namespace Texture.Tga { - public partial class Plugin : TextureInterface + public partial class Plugin { //Extension area information private int ExtensionAreaSize; diff --git a/source/RouteManager2/Illustrations/RouteMap.cs b/source/RouteManager2/Illustrations/RouteMap.cs index a7e7469aa..52e324c24 100644 --- a/source/RouteManager2/Illustrations/RouteMap.cs +++ b/source/RouteManager2/Illustrations/RouteMap.cs @@ -1,6 +1,7 @@ using System; using System.Collections.Generic; using System.Drawing; +using System.Globalization; using System.IO; using System.Linq; using OpenBveApi; @@ -693,7 +694,7 @@ private static void DrawPlayerPath(Graphics g, TrackFollower follower, int first { // turns out centering text in a circle using System.Drawing is a PITA // numbers are fudges, need to check whether they work OK on non windows.... - string limitString = Math.Round(lim.NextSpeedLimit * 3.6, 2).ToString(); + string limitString = Math.Round(lim.NextSpeedLimit * 3.6, 2).ToString(CultureInfo.InvariantCulture); float radius = g.MeasureString(limitString, boldFont).Width * 0.9f; RectangleF r = new RectangleF((float)x - radius - 20, (float)z - radius, radius * 2.0f, radius * 2.0f); diff --git a/source/RouteViewer/Game/Menu.SingleMenu.cs b/source/RouteViewer/Game/Menu.SingleMenu.cs index b5d1cf736..3a45496ef 100644 --- a/source/RouteViewer/Game/Menu.SingleMenu.cs +++ b/source/RouteViewer/Game/Menu.SingleMenu.cs @@ -22,8 +22,6 @@ private class SingleMenu : MenuBase { public SingleMenu(AbstractMenu menu, MenuType menuType, int data = 0, double MaxWidth = 0) : base(menuType) { - int i; - int jump = 0; //Vector2 size; Align = TextAlignment.TopMiddle; Height = Width = 0; diff --git a/source/TrainEditor/Options.cs b/source/TrainEditor/Options.cs index 1bc91bd52..4ab8e41a5 100644 --- a/source/TrainEditor/Options.cs +++ b/source/TrainEditor/Options.cs @@ -28,7 +28,6 @@ internal static void LoadOptions() System.IO.Directory.CreateDirectory(optionsFolder); } CurrentOptions = new Options(); - CultureInfo Culture = CultureInfo.InvariantCulture; string configFile = OpenBveApi.Path.CombineFile(optionsFolder, "options_te.cfg"); if (!System.IO.File.Exists(configFile)) { diff --git a/source/TrainEditor2/IO/IntermediateFile/Parser.cs b/source/TrainEditor2/IO/IntermediateFile/Parser.cs index 6c95f89c3..6a4f284e1 100644 --- a/source/TrainEditor2/IO/IntermediateFile/Parser.cs +++ b/source/TrainEditor2/IO/IntermediateFile/Parser.cs @@ -126,9 +126,7 @@ private static Car ParseCarNode(XElement parent) car.Brake = ParseBrakeNode(parent.Element("Brake")); car.Pressure = ParsePressureNode(parent.Element("Pressure")); - MotorCar motorCar = car as MotorCar; - - if (motorCar != null) + if (car is MotorCar motorCar) { motorCar.Acceleration = ParseAccelerationNode(parent.Element("Acceleration")); motorCar.Motor = ParseMotorNode(parent.Element("Motor")); diff --git a/source/TrainEditor2/IO/IntermediateFile/Writer.cs b/source/TrainEditor2/IO/IntermediateFile/Writer.cs index 308ee5c03..1182444ff 100644 --- a/source/TrainEditor2/IO/IntermediateFile/Writer.cs +++ b/source/TrainEditor2/IO/IntermediateFile/Writer.cs @@ -121,10 +121,8 @@ private static void WriteCarNode(XElement parent, Car car) WriteMoveNode(carNode, car.Move); WriteBrakeNode(carNode, car.Brake); WritePressureNode(carNode, car.Pressure); - - MotorCar motorCar = car as MotorCar; - - if (motorCar != null) + + if (car is MotorCar motorCar) { WriteAccelerationNode(carNode, motorCar.Acceleration); WriteMotorNode(carNode, motorCar.Motor); diff --git a/source/TrainEditor2/Models/App.cs b/source/TrainEditor2/Models/App.cs index 32c600cd7..50ecbad86 100644 --- a/source/TrainEditor2/Models/App.cs +++ b/source/TrainEditor2/Models/App.cs @@ -903,18 +903,13 @@ internal void DownCoupler() internal void ChangeCarClass(int carIndex) { - MotorCar motorCar = Train.Cars[carIndex] as MotorCar; - TrailerCar trailerCar = Train.Cars[carIndex] as TrailerCar; - - if (motorCar != null) + if (Train.Cars[carIndex] is MotorCar motorCar) { Train.Cars[carIndex] = new TrailerCar(motorCar); } - - if (trailerCar != null) + else if (Train.Cars[carIndex] is TrailerCar trailerCar) { Train.Cars[carIndex] = new MotorCar(trailerCar); - Train.ApplyPowerNotchesToCar(); } diff --git a/source/TrainEditor2/Models/Panels/Panel.cs b/source/TrainEditor2/Models/Panels/Panel.cs index 723090b3a..889957365 100644 --- a/source/TrainEditor2/Models/Panels/Panel.cs +++ b/source/TrainEditor2/Models/Panels/Panel.cs @@ -254,9 +254,7 @@ internal void CreateListItems() if (TreeItem.Children[1].Children.Any(y => SelectedTreeItem == y.Children[0].Children[0]) || SelectedTreeItem == TreeItem.Children[2].Children[0]) { - Screen screen = SelectedTreeItem.Parent.Parent.Tag as Screen; - - IEnumerable pilotLamps = screen != null ? screen.PanelElements.OfType() : PanelElements.OfType(); + IEnumerable pilotLamps = SelectedTreeItem.Parent.Parent.Tag is Screen screen ? screen.PanelElements.OfType() : PanelElements.OfType(); foreach (PilotLampElement pilotLamp in pilotLamps) { @@ -268,9 +266,7 @@ internal void CreateListItems() if (TreeItem.Children[1].Children.Any(y => SelectedTreeItem == y.Children[0].Children[1]) || SelectedTreeItem == TreeItem.Children[2].Children[1]) { - Screen screen = SelectedTreeItem.Parent.Parent.Tag as Screen; - - IEnumerable needles = screen != null ? screen.PanelElements.OfType() : PanelElements.OfType(); + IEnumerable needles = SelectedTreeItem.Parent.Parent.Tag is Screen screen ? screen.PanelElements.OfType() : PanelElements.OfType(); foreach (NeedleElement needle in needles) { @@ -282,9 +278,7 @@ internal void CreateListItems() if (TreeItem.Children[1].Children.Any(y => SelectedTreeItem == y.Children[0].Children[2]) || SelectedTreeItem == TreeItem.Children[2].Children[2]) { - Screen screen = SelectedTreeItem.Parent.Parent.Tag as Screen; - - IEnumerable digitalNumbers = screen != null ? screen.PanelElements.OfType() : PanelElements.OfType(); + IEnumerable digitalNumbers = SelectedTreeItem.Parent.Parent.Tag is Screen screen ? screen.PanelElements.OfType() : PanelElements.OfType(); foreach (DigitalNumberElement digitalNumber in digitalNumbers) { @@ -296,9 +290,7 @@ internal void CreateListItems() if (TreeItem.Children[1].Children.Any(y => SelectedTreeItem == y.Children[0].Children[3]) || SelectedTreeItem == TreeItem.Children[2].Children[3]) { - Screen screen = SelectedTreeItem.Parent.Parent.Tag as Screen; - - IEnumerable digitalGauges = screen != null ? screen.PanelElements.OfType() : PanelElements.OfType(); + IEnumerable digitalGauges = SelectedTreeItem.Parent.Parent.Tag is Screen screen ? screen.PanelElements.OfType() : PanelElements.OfType(); foreach (DigitalGaugeElement digitalGauge in digitalGauges) { @@ -310,9 +302,7 @@ internal void CreateListItems() if (TreeItem.Children[1].Children.Any(y => SelectedTreeItem == y.Children[0].Children[4]) || SelectedTreeItem == TreeItem.Children[2].Children[4]) { - Screen screen = SelectedTreeItem.Parent.Parent.Tag as Screen; - - IEnumerable linearGauges = screen != null ? screen.PanelElements.OfType() : PanelElements.OfType(); + IEnumerable linearGauges = SelectedTreeItem.Parent.Parent.Tag is Screen screen ? screen.PanelElements.OfType() : PanelElements.OfType(); foreach (LinearGaugeElement linearGauge in linearGauges) { @@ -324,9 +314,7 @@ internal void CreateListItems() if (TreeItem.Children[1].Children.Any(y => SelectedTreeItem == y.Children[0].Children[5]) || SelectedTreeItem == TreeItem.Children[2].Children[5]) { - Screen screen = SelectedTreeItem.Parent.Parent.Tag as Screen; - - IEnumerable timetables = screen != null ? screen.PanelElements.OfType() : PanelElements.OfType(); + IEnumerable timetables = SelectedTreeItem.Parent.Parent.Tag is Screen screen ? screen.PanelElements.OfType() : PanelElements.OfType(); foreach (TimetableElement timetable in timetables) { @@ -351,7 +339,6 @@ internal void CreateListItems() internal void UpdateListItem(ListViewItemModel item) { - Screen screen = item.Tag as Screen; PilotLampElement pilotLamp = item.Tag as PilotLampElement; NeedleElement needle = item.Tag as NeedleElement; DigitalNumberElement digitalNumber = item.Tag as DigitalNumberElement; @@ -360,7 +347,7 @@ internal void UpdateListItem(ListViewItemModel item) TimetableElement timetable = item.Tag as TimetableElement; TouchElement touch = item.Tag as TouchElement; - if (screen != null) + if (item.Tag is Screen screen) { item.Texts[0] = screen.Number.ToString(culture); item.Texts[1] = screen.Layer.ToString(culture); diff --git a/source/TrainEditor2/Models/Panels/TouchElement.cs b/source/TrainEditor2/Models/Panels/TouchElement.cs index 8b2f86228..d76642285 100644 --- a/source/TrainEditor2/Models/Panels/TouchElement.cs +++ b/source/TrainEditor2/Models/Panels/TouchElement.cs @@ -294,15 +294,11 @@ internal void CreateListItems() internal void UpdateListItem(ListViewItemModel item) { - SoundEntry soundEntry = item.Tag as SoundEntry; - CommandEntry commandEntry = item.Tag as CommandEntry; - - if (soundEntry != null) + if (item.Tag is SoundEntry soundEntry) { item.Texts[0] = soundEntry.Index.ToString(culture); } - - if (commandEntry != null) + else if (item.Tag is CommandEntry commandEntry) { item.Texts[0] = commandEntry.Info.Name; item.Texts[1] = commandEntry.Option.ToString(culture); diff --git a/source/TrainEditor2/Models/Sounds/Sound.cs b/source/TrainEditor2/Models/Sounds/Sound.cs index 241b727f6..8f31cb492 100644 --- a/source/TrainEditor2/Models/Sounds/Sound.cs +++ b/source/TrainEditor2/Models/Sounds/Sound.cs @@ -259,9 +259,7 @@ internal void CreateListItems() internal void UpdateListItem(ListViewItemModel item) { SoundElement element = (SoundElement)item.Tag; - Enum key = element.Key as Enum; - - item.Texts[0] = key != null ? key.GetStringValues().First() : element.Key.ToString(); + item.Texts[0] = element.Key is Enum key ? key.GetStringValues().First() : element.Key.ToString(); item.Texts[1] = element.FilePath; item.Texts[2] = element.DefinedPosition ? $"{element.PositionX.ToString(culture)}, {element.PositionY.ToString(culture)}, {element.PositionZ.ToString(culture)}" : string.Empty; item.Texts[3] = element.DefinedRadius ? element.Radius.ToString(culture) : string.Empty; diff --git a/source/TrainEditor2/ViewModels/Sounds/SoundViewModel.cs b/source/TrainEditor2/ViewModels/Sounds/SoundViewModel.cs index b0a4826ec..cdd270540 100644 --- a/source/TrainEditor2/ViewModels/Sounds/SoundViewModel.cs +++ b/source/TrainEditor2/ViewModels/Sounds/SoundViewModel.cs @@ -380,15 +380,12 @@ internal SoundViewModel(Sound sound) .ObserveAddChanged() .Subscribe(x => { - RunElement run = x as RunElement; - MotorElement motor = x as MotorElement; - - if (run != null) + if (x is RunElement run) { Simulation.TrainManager.TrainManager.RunSounds.Add(run); } - if (motor != null) + if (x is MotorElement motor) { Simulation.TrainManager.TrainManager.MotorSounds.Add(motor); } @@ -399,15 +396,12 @@ internal SoundViewModel(Sound sound) .ObserveRemoveChanged() .Subscribe(x => { - RunElement run = x as RunElement; - MotorElement motor = x as MotorElement; - - if (run != null) + if (x is RunElement run) { Simulation.TrainManager.TrainManager.RunSounds.Remove(run); } - if (motor != null) + if (x is MotorElement motor) { Simulation.TrainManager.TrainManager.MotorSounds.Remove(motor); } From ba4b40644d63563f82568af0872041d44c2cfa8f Mon Sep 17 00:00:00 2001 From: Christopher Lees Date: Mon, 16 Sep 2024 12:58:35 +0100 Subject: [PATCH 41/41] New: Add route maps to GL menu --- source/LibRender2/Menu/AbstractMenu.cs | 8 ++++++ source/LibRender2/Primitives/Button.cs | 4 +++ source/OpenBVE/Game/Menu/Menu.Route.cs | 29 +++++++++++++++++---- source/OpenBVE/Game/Menu/Menu.SingleMenu.cs | 5 ++++ source/OpenBVE/Game/Menu/Menu.cs | 10 +++++++ 5 files changed, 51 insertions(+), 5 deletions(-) diff --git a/source/LibRender2/Menu/AbstractMenu.cs b/source/LibRender2/Menu/AbstractMenu.cs index 24f789366..3c7346d55 100644 --- a/source/LibRender2/Menu/AbstractMenu.cs +++ b/source/LibRender2/Menu/AbstractMenu.cs @@ -22,6 +22,7 @@ //(INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS //SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE. +using System; using LibRender2.Screens; using LibRender2.Text; using OpenBveApi.Colors; @@ -176,6 +177,13 @@ public virtual bool ProcessMouseMove(int x, int y) /// The screen-relative y coordinate of the down event public void ProcessMouseDown(int x, int y) { + for (int i = 0; i < menuControls.Count; i++) + { + if (menuControls[i].IsVisible) + { + menuControls[i].MouseDown(x, y); + } + } if (ProcessMouseMove(x, y)) { if (Menus[CurrMenu].Selection == Menus[CurrMenu].TopItem + visibleItems) diff --git a/source/LibRender2/Primitives/Button.cs b/source/LibRender2/Primitives/Button.cs index 865e8e44b..a95878a7a 100644 --- a/source/LibRender2/Primitives/Button.cs +++ b/source/LibRender2/Primitives/Button.cs @@ -53,6 +53,10 @@ public Button(BaseRenderer renderer, string text) : base(renderer) public override void Draw() { + if (!IsVisible) + { + return; + } Renderer.Rectangle.Draw(Texture, Location, Size, BackgroundColor); if (CurrentlySelected) { diff --git a/source/OpenBVE/Game/Menu/Menu.Route.cs b/source/OpenBVE/Game/Menu/Menu.Route.cs index 7a06a671d..0538e8de3 100644 --- a/source/OpenBVE/Game/Menu/Menu.Route.cs +++ b/source/OpenBVE/Game/Menu/Menu.Route.cs @@ -35,6 +35,11 @@ public partial class GameMenu private static readonly Picturebox switchMainPictureBox = new Picturebox(Program.Renderer); private static readonly Picturebox switchSettingPictureBox = new Picturebox(Program.Renderer); private static readonly Picturebox switchMapPictureBox = new Picturebox(Program.Renderer); + private static readonly Button nextImageButton = new Button(Program.Renderer, "->"); + private static readonly Button previousImageButton = new Button(Program.Renderer, "<-"); + + private static Texture routeImageTexture; + private static Texture routeMapTexture; private static void packageWorkerThread_doWork(object sender, DoWorkEventArgs e) { @@ -62,6 +67,11 @@ private static void packageWorkerThread_doWork(object sender, DoWorkEventArgs e) } } + private static void nextImageButton_Click(object sender, EventArgs e) + { + routePictureBox.Texture = routePictureBox.Texture == routeImageTexture ? routeMapTexture : routeImageTexture; + } + private static void packageWorkerThread_completed(object sender, RunWorkerCompletedEventArgs e) { if (currentPackage != null) @@ -79,6 +89,9 @@ private static void routeWorkerThread_doWork(object sender, DoWorkEventArgs e) { return; } + + nextImageButton.IsVisible = false; + previousImageButton.IsVisible = false; RouteEncoding = TextEncoding.GetSystemEncodingFromFile(currentFile); Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\loading.png"), new TextureParameters(null, null), out routePictureBox.Texture); routeDescriptionBox.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"start","route_processing"}); @@ -141,17 +154,18 @@ private static void routeWorkerThread_completed(object sender, RunWorkerComplete { if (File.Exists(Program.CurrentRoute.Image)) { - Program.CurrentHost.RegisterTexture(Program.CurrentRoute.Image, new TextureParameters(null, null), out routePictureBox.Texture); + Program.CurrentHost.RegisterTexture(Program.CurrentRoute.Image, new TextureParameters(null, null), out routeImageTexture); } else { - Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\route_unknown.png"), new TextureParameters(null, null), out routePictureBox.Texture); + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\route_unknown.png"), new TextureParameters(null, null), out routeImageTexture); } + } catch { - routePictureBox.Texture = null; + routeImageTexture = null; } } else @@ -163,15 +177,20 @@ private static void routeWorkerThread_completed(object sender, RunWorkerComplete string g = Path.CombineFile(Path.GetDirectoryName(currentFile), System.IO.Path.GetFileNameWithoutExtension(currentFile) + f[i]); if (!File.Exists(g)) continue; - Program.CurrentHost.RegisterTexture(g, new TextureParameters(null, null), out routePictureBox.Texture); + Program.CurrentHost.RegisterTexture(g, new TextureParameters(null, null), out routeImageTexture); break; } if (i == f.Length) { - Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\route_unknown.png"), new TextureParameters(null, null), out routePictureBox.Texture); + Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\route_unknown.png"), new TextureParameters(null, null), out routeImageTexture); } } + routeMapTexture = new Texture(Illustrations.CreateRouteMap((int)routePictureBox.Size.X, (int)routePictureBox.Size.Y, false, out _)); + nextImageButton.IsVisible = true; + previousImageButton.IsVisible = true; + routePictureBox.Texture = routeImageTexture; + // description string Description = Program.CurrentRoute.Comment.ConvertNewlinesToCrLf(); routeDescriptionBox.Text = Description.Length != 0 ? Description : System.IO.Path.GetFileNameWithoutExtension(currentFile); diff --git a/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs b/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs index c18dae528..a86a399d1 100644 --- a/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs +++ b/source/OpenBVE/Game/Menu/Menu.SingleMenu.cs @@ -44,6 +44,8 @@ public sealed override int Selection public SingleMenu(AbstractMenu menu, MenuType menuType, int data = 0, double MaxWidth = 0) : base(menuType) { + nextImageButton.IsVisible = false; + previousImageButton.IsVisible = false; int i; int jump = 0; //Vector2 size; @@ -67,6 +69,9 @@ public SingleMenu(AbstractMenu menu, MenuType menuType, int data = 0, double Max Manipulation.OperationCompleted += OnPackageOperationCompleted; //Load texture Program.CurrentHost.RegisterTexture(Path.CombineFile(Program.FileSystem.DataFolder, "Menu\\loading.png"), new TextureParameters(null, null), out routePictureBox.Texture); + // n.b. only cycling between two images at the minute, so use the same method + nextImageButton.OnClick += nextImageButton_Click; + previousImageButton.OnClick += nextImageButton_Click; } Items = new MenuEntry[5]; Items[0] = new MenuCommand(menu, "Open Route File", MenuTag.RouteList, 0); diff --git a/source/OpenBVE/Game/Menu/Menu.cs b/source/OpenBVE/Game/Menu/Menu.cs index db37f0700..a53a63a5d 100644 --- a/source/OpenBVE/Game/Menu/Menu.cs +++ b/source/OpenBVE/Game/Menu/Menu.cs @@ -110,6 +110,10 @@ public override void Initialize() routePictureBox.Location = new Vector2(imageLoc, 0); routePictureBox.Size = new Vector2(quarterWidth, quarterWidth); routePictureBox.BackgroundColor = Color128.White; + nextImageButton.Location = new Vector2(imageLoc + quarterWidth + nextImageButton.Size.X, quarterWidth / 2.0); + nextImageButton.IsVisible = false; + previousImageButton.Location = new Vector2(imageLoc - previousImageButton.Size.X * 2, quarterWidth / 2.0); + previousImageButton.IsVisible = false; switchMainPictureBox.Location = new Vector2(imageLoc, quarterHeight); switchMainPictureBox.Size = new Vector2(quarterWidth, quarterWidth); switchMainPictureBox.BackgroundColor = Color128.Transparent; @@ -138,6 +142,8 @@ public override void Initialize() menuControls.Add(LogoPictureBox); menuControls.Add(controlTextBox); menuControls.Add(routeDescriptionBox); + menuControls.Add(nextImageButton); + menuControls.Add(previousImageButton); } public override void Reset() @@ -286,6 +292,8 @@ public override bool ProcessMouseMove(int x, int y) } if (menu.Type == MenuType.RouteList || menu.Type == MenuType.TrainList || menu.Type == MenuType.PackageInstall || menu.Type == MenuType.Packages || (int)menu.Type >= 107) { + nextImageButton.MouseMove(x, y); + previousImageButton.MouseMove(x, y); routeDescriptionBox.MouseMove(x, y); //HACK: Use this to trigger our menu start button! if (x > Program.Renderer.Screen.Width - 200 && x < Program.Renderer.Screen.Width - 10 && y > Program.Renderer.Screen.Height - 40 && y < Program.Renderer.Screen.Height - 10) @@ -869,6 +877,8 @@ public override void Draw(double RealTimeElapsed) case MenuType.RouteList: case MenuType.TrainList: { + nextImageButton.Draw(); + previousImageButton.Draw(); routePictureBox.Draw(); routeDescriptionBox.Draw();