diff --git a/assets/Controls/Default.controls b/assets/Controls/Default.controls
index 0c0d9e75f..db9d111d7 100644
--- a/assets/Controls/Default.controls
+++ b/assets/Controls/Default.controls
@@ -1,4 +1,4 @@
-; Current control configuration
+; Current control configuration
; =============================
; This file was automatically generated. Please modify only if you know what you're doing.
; Last updated 2026.01.16
@@ -79,6 +79,7 @@ CAMERA_ZOOM_OUT, keyboard, Keypad0, 0
CAMERA_POI_PREVIOUS, keyboard, Keypad1, 0
CAMERA_POI_NEXT, keyboard, Keypad7, 0
CAMERA_RESET, keyboard, Keypad5, 0
+CAMERA_GRAB_TOGGLE, mouse, 2, 0
CAMERA_RESTRICTION, keyboard, R, 2
TIMETABLE_TOGGLE, keyboard, T, 2
TIMETABLE_UP, keyboard, Up, 2
diff --git a/assets/Languages/en-US.xlf b/assets/Languages/en-US.xlf
index d678c5016..fb67028e8 100755
--- a/assets/Languages/en-US.xlf
+++ b/assets/Languages/en-US.xlf
@@ -900,6 +900,30 @@
positive direction
+
+ Mouse:
+
+
+ Button:
+
+
+ Mouse
+
+
+ Left Click
+
+
+ Middle Click
+
+
+ Right Click
+
+
+ Scroll Up
+
+
+ Scroll Down
+
invalid direction
@@ -1216,6 +1240,9 @@
Transition duration (sec):
+
+ Zoom Scroll Speed:
+
Detail of simulation
@@ -1312,6 +1339,7 @@
Prefer custom timetable
+
Choose...
@@ -2209,6 +2237,9 @@
Resets the camera view to default values
+
+ Toggles camera grab (Mouse look)
+
Activates or deactivates interior view camera restriction
diff --git a/assets/Languages/id-ID.xlf b/assets/Languages/id-ID.xlf
index 92a6e9bda..3fe8b554b 100644
--- a/assets/Languages/id-ID.xlf
+++ b/assets/Languages/id-ID.xlf
@@ -1,4 +1,4 @@
-
+
@@ -1156,6 +1156,38 @@
positive direction
arah positif
+
+ Mouse:
+ Mouse:
+
+
+ Button:
+ Tombol:
+
+
+ Mouse
+ Mouse
+
+
+ Left Click
+ Klik Kiri
+
+
+ Middle Click
+ Klik Tengah
+
+
+ Right Click
+ Klik Kanan
+
+
+ Scroll Up
+ Scroll Atas
+
+
+ Scroll Down
+ Scroll Bawah
+
invalid direction
arah tidak valid
@@ -1483,6 +1515,26 @@
Miscellaneous
Lainnya
+
+ Camera options
+ Pengaturan kamera
+
+
+ Smooth interior transition
+ Transisi interior halus
+
+
+ Smooth exterior transition
+ Transisi eksterior halus
+
+
+ Transition duration (sec):
+ Durasi transisi (detik):
+
+
+ Zoom Scroll Speed:
+ Kecepatan Scroll Zoom:
+
Detail of simulation
Detail simulasi
@@ -1609,6 +1661,7 @@
Prefer custom timetable
Buat sendiri
+
Choose...
Pilih....
@@ -2772,6 +2825,10 @@
Resets the camera view to default values
Reset kamera
+
+ Toggles camera grab (Mouse look)
+ Aktifkan/nonaktifkan kontrol kamera dengan mouse
+
Activates or deactivates interior view camera restriction
Aktifkan / matikan batasan kamera
diff --git a/source/OpenBVE/Game/Menu/Menu.Controls.cs b/source/OpenBVE/Game/Menu/Menu.Controls.cs
index 4777281e2..53b1e85dd 100644
--- a/source/OpenBVE/Game/Menu/Menu.Controls.cs
+++ b/source/OpenBVE/Game/Menu/Menu.Controls.cs
@@ -1,4 +1,4 @@
-using LibRender2.Primitives;
+using LibRender2.Primitives;
using OpenBveApi.Colors;
using OpenBveApi.Hosts;
using OpenBveApi.Interface;
@@ -71,6 +71,19 @@ private static string GetControlDescription(int idx)
case ControlMethod.Invalid:
str = Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "menu", "joystick_notavailable" });
break;
+ case ControlMethod.Mouse:
+ str = Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "controls", "assignment_mouse" }) + " [";
+ switch (loadedControl.Element)
+ {
+ case 0: str += Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "controls", "assignment_mouse_left" }); break;
+ case 1: str += Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "controls", "assignment_mouse_middle" }); break;
+ case 2: str += Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "controls", "assignment_mouse_right" }); break;
+ case 3: str += Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "controls", "assignment_mouse_scrollup" }); break;
+ case 4: str += Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "controls", "assignment_mouse_scrolldown" }); break;
+ default: str += loadedControl.Element; break;
+ }
+ str += "]";
+ break;
}
return str;
diff --git a/source/OpenBVE/System/GameWindow.cs b/source/OpenBVE/System/GameWindow.cs
index 8d89bd0f7..ca9dc9630 100644
--- a/source/OpenBVE/System/GameWindow.cs
+++ b/source/OpenBVE/System/GameWindow.cs
@@ -267,8 +267,8 @@ protected override void OnRenderFrame(FrameEventArgs e)
MainLoop.UpdateControlRepeats(RealTimeElapsed);
MainLoop.ProcessKeyboard();
- MainLoop.UpdateMouse(RealTimeElapsed);
MainLoop.ProcessControls(TimeElapsed);
+ MainLoop.UpdateMouse(RealTimeElapsed);
if (Program.Joysticks.AttachedJoysticks.TryGetTypedValue(AbstractRailDriver.Guid, out AbstractRailDriver railDriver))
{
if (Interface.CurrentOptions.RailDriverMPH)
diff --git a/source/OpenBVE/System/Input/Controls.cs b/source/OpenBVE/System/Input/Controls.cs
index 1945c8a52..4f667140c 100644
--- a/source/OpenBVE/System/Input/Controls.cs
+++ b/source/OpenBVE/System/Input/Controls.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Collections.Generic;
using System.Globalization;
using System.IO;
@@ -332,6 +332,20 @@ internal static void LoadControls(string FileOrNull, out Control[] Controls)
}
}
+ else if (Method == ControlMethod.Mouse & Terms.Length >= 3)
+ {
+ if (int.TryParse(Terms[2], out int CurrentButton))
+ {
+ Controls[Length].Method = Method;
+ Controls[Length].Element = CurrentButton;
+ Controls[Length].Option = 0;
+ if (Terms.Length >= 4 && int.TryParse(Terms[3], NumberStyles.Integer, Culture, out int Option))
+ {
+ Controls[Length].Option = Option;
+ }
+ Valid = true;
+ }
+ }
if (!Valid)
{
diff --git a/source/OpenBVE/System/Input/ProcessControls.Analog.cs b/source/OpenBVE/System/Input/ProcessControls.Analog.cs
index df0e8d523..c9b0b43df 100644
--- a/source/OpenBVE/System/Input/ProcessControls.Analog.cs
+++ b/source/OpenBVE/System/Input/ProcessControls.Analog.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using LibRender2.Cameras;
using LibRender2.Overlays;
using OpenBveApi.Interface;
@@ -217,7 +217,12 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control
case Translations.Command.CameraMoveRight:
case Translations.Command.CameraMoveUp:
case Translations.Command.CameraMoveDown:
- Program.Renderer.Camera.Move(Control.Command, Control.AnalogState);
+ double moveFactor = Control.AnalogState;
+ if (Control.Method == ControlMethod.Mouse && Control.Element >= 3)
+ {
+ moveFactor *= Interface.CurrentOptions.ZoomScrollSpeed;
+ }
+ Program.Renderer.Camera.Move(Control.Command, moveFactor);
break;
case Translations.Command.CameraRotateLeft:
case Translations.Command.CameraRotateRight:
@@ -225,13 +230,23 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control
case Translations.Command.CameraRotateDown:
case Translations.Command.CameraRotateCCW:
case Translations.Command.CameraRotateCW:
- Program.Renderer.Camera.Rotate(Control.Command, Control.AnalogState);
+ double rotateFactor = Control.AnalogState;
+ if (Control.Method == ControlMethod.Mouse && Control.Element >= 3)
+ {
+ rotateFactor *= 10.0; // Boost scroll rotation
+ }
+ Program.Renderer.Camera.Rotate(Control.Command, rotateFactor);
break;
case Translations.Command.CameraZoomIn:
// camera zoom in
if (TimeElapsed > 0.0)
{
- Program.Renderer.Camera.AlignmentDirection.Zoom = -CameraProperties.ZoomTopSpeed * Control.AnalogState;
+ double factor = Control.AnalogState;
+ if (Control.Method == ControlMethod.Mouse && Control.Element >= 3)
+ {
+ factor *= Interface.CurrentOptions.ZoomScrollSpeed;
+ }
+ Program.Renderer.Camera.AlignmentDirection.Zoom = -CameraProperties.ZoomTopSpeed * factor;
}
break;
@@ -239,7 +254,12 @@ 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;
+ double factor = Control.AnalogState;
+ if (Control.Method == ControlMethod.Mouse && Control.Element >= 3)
+ {
+ factor *= Interface.CurrentOptions.ZoomScrollSpeed;
+ }
+ Program.Renderer.Camera.AlignmentDirection.Zoom = CameraProperties.ZoomTopSpeed * factor;
}
break;
@@ -248,15 +268,20 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control
if (TimeElapsed > 0.0)
{
const double scrollSpeed = 250.0;
+ double timetableFactor = Control.AnalogState;
+ if (Control.Method == ControlMethod.Mouse && Control.Element >= 3)
+ {
+ timetableFactor *= 5.0;
+ }
switch (Program.Renderer.CurrentTimetable)
{
case DisplayedTimetable.Default:
- Timetable.DefaultTimetablePosition += scrollSpeed * Control.AnalogState * TimeElapsed;
+ Timetable.DefaultTimetablePosition += scrollSpeed * timetableFactor * TimeElapsed;
if (Timetable.DefaultTimetablePosition > 0.0)
Timetable.DefaultTimetablePosition = 0.0;
break;
case DisplayedTimetable.Custom:
- Timetable.CustomTimetablePosition += scrollSpeed * Control.AnalogState * TimeElapsed;
+ Timetable.CustomTimetablePosition += scrollSpeed * timetableFactor * TimeElapsed;
if (Timetable.CustomTimetablePosition > 0.0)
Timetable.CustomTimetablePosition = 0.0;
break;
@@ -269,10 +294,15 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control
if (TimeElapsed > 0.0)
{
const double scrollSpeed = 250.0;
+ double timetableFactor = Control.AnalogState;
+ if (Control.Method == ControlMethod.Mouse && Control.Element >= 3)
+ {
+ timetableFactor *= 5.0;
+ }
switch (Program.Renderer.CurrentTimetable)
{
case DisplayedTimetable.Default:
- Timetable.DefaultTimetablePosition -= scrollSpeed * Control.AnalogState * TimeElapsed;
+ Timetable.DefaultTimetablePosition -= scrollSpeed * timetableFactor * TimeElapsed;
double max;
if (Timetable.DefaultTimetableTexture != null)
{
@@ -291,7 +321,7 @@ private static void ProcessAnalogControl(double TimeElapsed, ref Control Control
break;
case DisplayedTimetable.Custom:
- Timetable.CustomTimetablePosition -= scrollSpeed * Control.AnalogState * TimeElapsed;
+ Timetable.CustomTimetablePosition -= scrollSpeed * timetableFactor * TimeElapsed;
Texture texture = Timetable.CurrentCustomTimetableDaytimeTexture ?? Timetable.CurrentCustomTimetableNighttimeTexture;
if (texture != null)
{
diff --git a/source/OpenBVE/System/Input/ProcessControls.Digital.cs b/source/OpenBVE/System/Input/ProcessControls.Digital.cs
index 5a5b81855..50813140a 100644
--- a/source/OpenBVE/System/Input/ProcessControls.Digital.cs
+++ b/source/OpenBVE/System/Input/ProcessControls.Digital.cs
@@ -12,6 +12,7 @@
using OpenBveApi.Motor;
using OpenBveApi.Routes;
using OpenBveApi.Runtime;
+using OpenTK.Input;
using RouteManager2.MessageManager;
using RouteManager2.SignalManager;
using RouteManager2.Stations;
@@ -573,6 +574,19 @@ private static void ProcessDigitalControl(double TimeElapsed, ref Control Contro
break;
}
+ break;
+ case Translations.Command.CameraGrabToggle:
+ if (Program.Renderer.CurrentInterface == InterfaceType.Normal)
+ {
+ MainLoop.MouseGrabEnabled = !MainLoop.MouseGrabEnabled;
+ if (MainLoop.MouseGrabEnabled)
+ {
+ Program.Renderer.GameWindow.CursorVisible = false;
+ System.Drawing.Point center = Program.Renderer.GameWindow.PointToScreen(new System.Drawing.Point(Program.Renderer.GameWindow.ClientRectangle.Width / 2, Program.Renderer.GameWindow.ClientRectangle.Height / 2));
+ Mouse.SetPosition(center.X, center.Y);
+ }
+ MainLoop.MouseGrabIgnoreOnce = true;
+ }
break;
case Translations.Command.DeviceConstSpeed:
// const speed
@@ -941,6 +955,8 @@ private static void ProcessDigitalControl(double TimeElapsed, ref Control Contro
break;
case Translations.Command.MenuActivate:
// menu
+ MainLoop.MouseGrabEnabled = false;
+ Program.Renderer.GameWindow.CursorVisible = true;
Game.Menu.PushMenu(MenuType.Top);
break;
case Translations.Command.MiscPause:
diff --git a/source/OpenBVE/System/MainLoop.cs b/source/OpenBVE/System/MainLoop.cs
index 5bc384c7b..ba7ad8878 100644
--- a/source/OpenBVE/System/MainLoop.cs
+++ b/source/OpenBVE/System/MainLoop.cs
@@ -126,7 +126,10 @@ PROCESS EVENTS
internal static MouseState currentMouseState, previousMouseState;
internal static bool MouseGrabEnabled = false;
+ private static bool scrollUpPressed = false;
+ private static bool scrollDownPressed = false;
internal static bool MouseGrabIgnoreOnce = false;
+ private static int lastMouseX, lastMouseY;
internal static OpenBveApi.Math.Vector2 MouseGrabTarget = new OpenBveApi.Math.Vector2(0.0, 0.0);
/// Called when a mouse button is pressed
@@ -140,11 +143,7 @@ internal static void mouseDownEvent(object sender, MouseButtonEventArgs e)
return;
}
timeSinceLastMouseEvent = 0;
- if (e.Button == MouseButton.Right)
- {
- MouseGrabEnabled = !MouseGrabEnabled;
- MouseGrabIgnoreOnce = true;
- }
+ ProcessMouseControl((int)e.Button, true);
if (e.Button == MouseButton.Left)
{
switch (Program.Renderer.CurrentInterface)
@@ -172,6 +171,7 @@ internal static void mouseUpEvent(object sender, MouseButtonEventArgs e)
return;
}
timeSinceLastMouseEvent = 0;
+ ProcessMouseControl((int)e.Button, false);
if (e.Button == MouseButton.Left)
{
if (Program.Renderer.CurrentInterface == InterfaceType.Normal)
@@ -210,6 +210,21 @@ internal static void mouseWheelEvent(object sender, MouseWheelEventArgs e)
{
Game.Menu.ProcessMouseScroll(e.Delta);
}
+ if (e.Delta != 0)
+ {
+ int element = e.Delta > 0 ? 3 : 4;
+ // Accumulate scroll delta in AnalogState for smoother multi-scroll frames
+ for (int i = 0; i < Interface.CurrentControls.Length; i++)
+ {
+ if (Interface.CurrentControls[i].Method == ControlMethod.Mouse && Interface.CurrentControls[i].Element == element)
+ {
+ Interface.CurrentControls[i].AnalogState += 1.0;
+ Interface.CurrentControls[i].DigitalState = DigitalControlState.Pressed;
+ }
+ }
+ if (element == 3) scrollUpPressed = true;
+ if (element == 4) scrollDownPressed = true;
+ }
}
internal static void UpdateMouse(double TimeElapsed)
@@ -221,15 +236,33 @@ internal static void UpdateMouse(double TimeElapsed)
else
{
timeSinceLastMouseEvent = 0; //Always show the mouse in the menu
+ Program.Renderer.GameWindow.CursorVisible = true;
+ MainLoop.MouseGrabEnabled = false;
}
if (Interface.CurrentOptions.CursorHideDelay > 0 && timeSinceLastMouseEvent > Interface.CurrentOptions.CursorHideDelay)
{
Program.Renderer.GameWindow.CursorVisible = false;
}
- else
+
+ if (scrollUpPressed)
{
- Program.Renderer.GameWindow.CursorVisible = true;
+ ProcessMouseControl(3, false);
+ scrollUpPressed = false;
+ }
+ if (scrollDownPressed)
+ {
+ ProcessMouseControl(4, false);
+ scrollDownPressed = false;
+ }
+
+ if (MainLoop.MouseGrabEnabled)
+ {
+ Program.Renderer.GameWindow.CursorVisible = false;
+ }
+ else if (Interface.CurrentOptions.CursorHideDelay > 0 && timeSinceLastMouseEvent > Interface.CurrentOptions.CursorHideDelay)
+ {
+ Program.Renderer.GameWindow.CursorVisible = false;
}
if (MainLoop.MouseGrabEnabled)
@@ -244,8 +277,10 @@ internal static void UpdateMouse(double TimeElapsed)
factor = 3.0;
}
- Program.Renderer.Camera.AlignmentDirection.Yaw += factor * MouseGrabTarget.X;
- Program.Renderer.Camera.AlignmentDirection.Pitch -= factor * MouseGrabTarget.Y;
+ double zoomFactor = Math.Exp(Program.Renderer.Camera.Alignment.Zoom);
+ Program.Renderer.Camera.Alignment.Yaw += factor * MouseGrabTarget.X * 0.001 * zoomFactor;
+ Program.Renderer.Camera.Alignment.Pitch -= factor * MouseGrabTarget.Y * 0.001 * zoomFactor;
+ Program.Renderer.UpdateViewingDistances(Program.CurrentRoute.CurrentBackground.BackgroundImageDistance);
MouseGrabTarget = OpenBveApi.Math.Vector2.Null;
}
}
@@ -312,17 +347,30 @@ internal static void ProcessKeyboard()
}
if (MouseGrabEnabled)
{
- previousMouseState = currentMouseState;
- currentMouseState = Mouse.GetState();
- if (previousMouseState != currentMouseState)
+ int centerX = Program.Renderer.GameWindow.ClientRectangle.Width / 2;
+ int centerY = Program.Renderer.GameWindow.ClientRectangle.Height / 2;
+ System.Drawing.Point screenCenter = Program.Renderer.GameWindow.PointToScreen(new System.Drawing.Point(centerX, centerY));
+
+ if (MouseGrabIgnoreOnce)
{
- if (MouseGrabIgnoreOnce)
- {
- MouseGrabIgnoreOnce = false;
- }
- else if (MouseGrabEnabled)
+ MouseGrabIgnoreOnce = false;
+ MouseState state = Mouse.GetCursorState();
+ lastMouseX = state.X;
+ lastMouseY = state.Y;
+ MouseGrabTarget = OpenBveApi.Math.Vector2.Null;
+ }
+ else
+ {
+ MouseState state = Mouse.GetCursorState();
+ int curX = state.X;
+ int curY = state.Y;
+ MouseGrabTarget = new OpenBveApi.Math.Vector2(curX - lastMouseX, curY - lastMouseY);
+ lastMouseX = curX;
+ lastMouseY = curY;
+ if (Math.Abs(curX - screenCenter.X) > 400 || Math.Abs(curY - screenCenter.Y) > 400)
{
- MouseGrabTarget = new OpenBveApi.Math.Vector2(currentMouseState.X - previousMouseState.X, currentMouseState.Y - previousMouseState.Y);
+ Mouse.SetPosition(screenCenter.X, screenCenter.Y);
+ MouseGrabIgnoreOnce = true;
}
}
}
@@ -603,5 +651,24 @@ internal static void CheckForOpenGlError(string Location) {
}
}
#endif
+ private static void ProcessMouseControl(int element, bool pressed)
+ {
+ for (int i = 0; i < Interface.CurrentControls.Length; i++)
+ {
+ if (Interface.CurrentControls[i].Method == ControlMethod.Mouse && Interface.CurrentControls[i].Element == element)
+ {
+ if (pressed)
+ {
+ Interface.CurrentControls[i].AnalogState = 1.0;
+ Interface.CurrentControls[i].DigitalState = DigitalControlState.Pressed;
+ }
+ else
+ {
+ Interface.CurrentControls[i].AnalogState = 0.0;
+ Interface.CurrentControls[i].DigitalState = DigitalControlState.Released;
+ }
+ }
+ }
+ }
}
}
diff --git a/source/OpenBVE/System/Options.cs b/source/OpenBVE/System/Options.cs
index 68dc8b0a9..4c78522bf 100644
--- a/source/OpenBVE/System/Options.cs
+++ b/source/OpenBVE/System/Options.cs
@@ -22,6 +22,8 @@ internal class Options : BaseOptions
{
/// The on disk folder in which user interface components are stored
internal string UserInterfaceFolder;
+ /// The speed at which the mouse scroll zooms the camera
+ internal double ZoomScrollSpeed;
/// The accelerated time factor (1x to 5x)
internal int TimeAccelerationFactor;
///// The current type of motion blur
@@ -129,6 +131,7 @@ internal Options()
TransparencyMode = TransparencyMode.Quality;
AnisotropicFilteringLevel = 0;
AnisotropicFilteringMaximum = 0;
+ ZoomScrollSpeed = 30.0;
AntiAliasingLevel = 0;
ViewingDistance = 600;
QuadTreeLeafSize = 60;
@@ -355,6 +358,7 @@ public override void Save(string fileName)
Builder.AppendLine("keyRepeatDelay = " + (1000.0 * KeyRepeatDelay).ToString("0", Culture));
Builder.AppendLine("keyRepeatInterval = " + (1000.0 * KeyRepeatInterval).ToString("0", Culture));
Builder.AppendLine("raildrivermph = " + (RailDriverMPH ? "true" : "false"));
+ Builder.AppendLine("zoomScrollSpeed = " + ZoomScrollSpeed.ToString(Culture));
Builder.AppendLine();
Builder.AppendLine("[sound]");
Builder.AppendLine("model = " + SoundModel);
@@ -565,6 +569,11 @@ internal static void LoadOptions()
CurrentOptions.KeyRepeatInterval = interval * 0.001;
block.GetValue(OptionsKey.RailDriverMPH, out CurrentOptions.RailDriverMPH);
block.GetValue(OptionsKey.CursorHideDelay, out CurrentOptions.CursorHideDelay);
+ block.TryGetValue(OptionsKey.ZoomScrollSpeed, ref CurrentOptions.ZoomScrollSpeed);
+ if (CurrentOptions.ZoomScrollSpeed <= 0.0 || CurrentOptions.ZoomScrollSpeed > 100.0)
+ {
+ CurrentOptions.ZoomScrollSpeed = 30.0;
+ }
break;
case OptionsSection.Sound:
block.GetEnumValue(OptionsKey.Model, out CurrentOptions.SoundModel);
diff --git a/source/OpenBVE/UserInterface/formMain.Controls.cs b/source/OpenBVE/UserInterface/formMain.Controls.cs
index dc97128f6..26d9bd103 100644
--- a/source/OpenBVE/UserInterface/formMain.Controls.cs
+++ b/source/OpenBVE/UserInterface/formMain.Controls.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using System.Drawing;
using System.Linq;
using System.Windows.Forms;
@@ -54,13 +54,18 @@ private void listviewControls_SelectedIndexChanged(object sender, EventArgs e) {
case ControlMethod.RailDriver:
radiobuttonJoystick.Checked = true;
break;
+ case ControlMethod.Mouse:
+ radiobuttonMouse.Checked = true;
+ break;
default:
radiobuttonKeyboard.Checked = false;
radiobuttonJoystick.Checked = false;
+ radiobuttonMouse.Checked = false;
textboxJoystickGrab.Enabled = false;
break;
}
panelKeyboard.Enabled = radiobuttonKeyboard.Checked;
+ panelKeyboard.Visible = radiobuttonKeyboard.Checked;
if (radiobuttonKeyboard.Checked)
{
if (Translations.TranslatedKeys.ContainsKey(Interface.CurrentControls[i].Key))
@@ -72,13 +77,20 @@ private void listviewControls_SelectedIndexChanged(object sender, EventArgs e) {
checkboxKeyboardAlt.Checked = (Interface.CurrentControls[i].Modifier & KeyboardModifier.Alt) != 0;
} else if (radiobuttonJoystick.Checked) {
labelJoystickAssignmentValue.Text = GetControlDetails(i);
+ } else if (radiobuttonMouse.Checked) {
+ comboboxMouseButton.SelectedIndex = Interface.CurrentControls[i].Element;
} else {
comboboxKeyboardKey.SelectedIndex = -1;
checkboxKeyboardShift.Checked = false;
checkboxKeyboardCtrl.Checked = false;
checkboxKeyboardAlt.Checked = false;
+ comboboxMouseButton.SelectedIndex = -1;
}
panelJoystick.Enabled = radiobuttonJoystick.Checked;
+ panelJoystick.Visible = radiobuttonJoystick.Checked;
+ panelMouse.Enabled = radiobuttonMouse.Checked;
+ panelMouse.Visible = radiobuttonMouse.Checked;
+ textboxJoystickGrab.Visible = radiobuttonJoystick.Checked || radiobuttonKeyboard.Checked;
// finalize
Tag = null;
}
@@ -91,11 +103,13 @@ private void listviewControls_SelectedIndexChanged(object sender, EventArgs e) {
comboboxCommand.SelectedIndex = -1;
radiobuttonKeyboard.Checked = false;
radiobuttonJoystick.Checked = false;
+ radiobuttonMouse.Checked = false;
groupboxControl.Enabled = false;
comboboxKeyboardKey.SelectedIndex = -1;
checkboxKeyboardShift.Checked = false;
checkboxKeyboardCtrl.Checked = false;
checkboxKeyboardAlt.Checked = false;
+ comboboxMouseButton.SelectedIndex = -1;
labelJoystickAssignmentValue.Text = "";
Tag = null;
buttonControlRemove.Enabled = false;
@@ -122,6 +136,9 @@ private void UpdateControlListElement(ListViewItem Item, int Index, bool ResizeC
case ControlMethod.Joystick:
Item.ImageKey = Info.Type == Translations.CommandType.AnalogHalf || Info.Type == Translations.CommandType.AnalogFull ? @"joystick" : @"gamepad";
break;
+ case ControlMethod.Mouse:
+ Item.ImageKey = @"mouse";
+ break;
default:
Item.ImageKey = null;
break;
@@ -266,6 +283,18 @@ private string GetControlDetails(int Index) {
}
return t;
}
+ if (Interface.CurrentControls[Index].Method == ControlMethod.Mouse) {
+ string t = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"controls","assignment_mouse"}) + Separator;
+ switch (Interface.CurrentControls[Index].Element) {
+ case 0: t += Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"controls","assignment_mouse_left"}); break;
+ case 1: t += Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"controls","assignment_mouse_middle"}); break;
+ case 2: t += Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"controls","assignment_mouse_right"}); break;
+ case 3: t += Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"controls","assignment_mouse_scrollup"}); break;
+ case 4: t += Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"controls","assignment_mouse_scrolldown"}); break;
+ default: t += "{" + Interface.CurrentControls[Index].Element.ToString(Culture) + "}"; break;
+ }
+ return t;
+ }
return Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"controls","assignment_invalid"});
}
@@ -359,12 +388,34 @@ private void updownCommandOption_ValueChanged(object sender, EventArgs e) {
// keyboard
private void radiobuttonKeyboard_CheckedChanged(object sender, EventArgs e) {
textboxJoystickGrab.Enabled = radiobuttonJoystick.Checked || radiobuttonKeyboard.Checked;
+ textboxJoystickGrab.Visible = radiobuttonJoystick.Checked || radiobuttonKeyboard.Checked;
if (Tag == null & listviewControls.SelectedIndices.Count == 1) {
int i = listviewControls.SelectedIndices[0];
Interface.CurrentControls[i].Method = ControlMethod.Keyboard;
UpdateControlListElement(listviewControls.Items[i], i, true);
}
panelKeyboard.Enabled = radiobuttonKeyboard.Checked;
+ panelKeyboard.Visible = radiobuttonKeyboard.Checked;
+ }
+
+ // mouse
+ private void radiobuttonMouse_CheckedChanged(object sender, EventArgs e) {
+ if (Tag == null & listviewControls.SelectedIndices.Count == 1) {
+ int i = listviewControls.SelectedIndices[0];
+ Interface.CurrentControls[i].Method = ControlMethod.Mouse;
+ UpdateControlListElement(listviewControls.Items[i], i, true);
+ }
+ panelMouse.Enabled = radiobuttonMouse.Checked;
+ panelMouse.Visible = radiobuttonMouse.Checked;
+ textboxJoystickGrab.Visible = radiobuttonJoystick.Checked || radiobuttonKeyboard.Checked;
+ }
+
+ private void comboboxMouseButton_SelectedIndexChanged(object sender, EventArgs e) {
+ if (Tag == null & listviewControls.SelectedIndices.Count == 1) {
+ int i = listviewControls.SelectedIndices[0];
+ Interface.CurrentControls[i].Element = comboboxMouseButton.SelectedIndex;
+ UpdateControlListElement(listviewControls.Items[i], i, true);
+ }
}
// key
@@ -426,6 +477,7 @@ private void radiobuttonJoystick_CheckedChanged(object sender, EventArgs e) {
UpdateControlListElement(listviewControls.Items[i], i, true);
}
panelJoystick.Enabled = radiobuttonJoystick.Checked;
+ panelJoystick.Visible = radiobuttonJoystick.Checked;
if (radiobuttonJoystick.Checked || radiobuttonKeyboard.Checked)
{
textboxJoystickGrab.Enabled = true;
@@ -434,6 +486,7 @@ private void radiobuttonJoystick_CheckedChanged(object sender, EventArgs e) {
{
textboxJoystickGrab.Enabled = false;
}
+ textboxJoystickGrab.Visible = radiobuttonJoystick.Checked || radiobuttonKeyboard.Checked;
textboxJoystickGrab.Text = Translations.GetInterfaceString(HostApplication.OpenBve, radiobuttonJoystick.Checked ? new[] {"controls","selection_joystick_assignment_grab"} : new[] {"controls","selection_keyboard_assignment_grab"});
}
diff --git a/source/OpenBVE/UserInterface/formMain.Designer.cs b/source/OpenBVE/UserInterface/formMain.Designer.cs
index cf15c3aaa..c8d62d789 100644
--- a/source/OpenBVE/UserInterface/formMain.Designer.cs
+++ b/source/OpenBVE/UserInterface/formMain.Designer.cs
@@ -137,6 +137,8 @@ private void InitializeComponent() {
this.trackbarTransparency = new System.Windows.Forms.TrackBar();
this.panelOptionsRight = new System.Windows.Forms.Panel();
this.groupBoxOther = new System.Windows.Forms.GroupBox();
+ this.labelZoomScrollSpeed = new System.Windows.Forms.Label();
+ this.updownZoomScrollSpeed = new System.Windows.Forms.NumericUpDown();
this.comboBoxTimeTableDisplayMode = new System.Windows.Forms.ComboBox();
this.labelTimeTableDisplayMode = new System.Windows.Forms.Label();
this.groupBoxRailDriver = new System.Windows.Forms.GroupBox();
@@ -336,6 +338,10 @@ private void InitializeComponent() {
this.labelJoystickAssignmentValue = new System.Windows.Forms.Label();
this.radiobuttonJoystick = new System.Windows.Forms.RadioButton();
this.radiobuttonKeyboard = new System.Windows.Forms.RadioButton();
+ this.radiobuttonMouse = new System.Windows.Forms.RadioButton();
+ this.panelMouse = new System.Windows.Forms.Panel();
+ this.labelMouseButton = new System.Windows.Forms.Label();
+ this.comboboxMouseButton = new System.Windows.Forms.ComboBox();
this.panelInfo = new System.Windows.Forms.Panel();
this.linkLabelReportBug = new System.Windows.Forms.LinkLabel();
this.linkLabelCheckUpdates = new System.Windows.Forms.LinkLabel();
@@ -2089,11 +2095,43 @@ private void InitializeComponent() {
this.groupBoxOther.ForeColor = System.Drawing.Color.Black;
this.groupBoxOther.Location = new System.Drawing.Point(0, 347);
this.groupBoxOther.Name = "groupBoxOther";
- this.groupBoxOther.Size = new System.Drawing.Size(316, 48);
+ this.groupBoxOther.Size = new System.Drawing.Size(316, 50);
this.groupBoxOther.TabIndex = 19;
this.groupBoxOther.TabStop = false;
this.groupBoxOther.Text = "Other";
//
+ // labelZoomScrollSpeed
+ //
+ this.labelZoomScrollSpeed.Location = new System.Drawing.Point(8, 98);
+ this.labelZoomScrollSpeed.Name = "labelZoomScrollSpeed";
+ this.labelZoomScrollSpeed.Size = new System.Drawing.Size(130, 18);
+ this.labelZoomScrollSpeed.TabIndex = 4;
+ this.labelZoomScrollSpeed.Text = "Zoom Scroll Speed:";
+ this.labelZoomScrollSpeed.TextAlign = System.Drawing.ContentAlignment.MiddleLeft;
+ //
+ // updownZoomScrollSpeed
+ //
+ this.updownZoomScrollSpeed.Location = new System.Drawing.Point(200, 96);
+ this.updownZoomScrollSpeed.Maximum = new decimal(new int[] {
+ 100,
+ 0,
+ 0,
+ 0});
+ this.updownZoomScrollSpeed.Minimum = new decimal(new int[] {
+ 1,
+ 0,
+ 0,
+ 0});
+ this.updownZoomScrollSpeed.Name = "updownZoomScrollSpeed";
+ this.updownZoomScrollSpeed.Size = new System.Drawing.Size(152, 20);
+ this.updownZoomScrollSpeed.TabIndex = 3;
+ this.updownZoomScrollSpeed.Value = new decimal(new int[] {
+ 30,
+ 0,
+ 0,
+ 0});
+ this.updownZoomScrollSpeed.ValueChanged += new System.EventHandler(this.updownZoomScrollSpeed_ValueChanged);
+ //
// comboBoxTimeTableDisplayMode
//
this.comboBoxTimeTableDisplayMode.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Right)));
@@ -2654,10 +2692,12 @@ private void InitializeComponent() {
this.groupboxCamera.Controls.Add(this.checkboxCameraExteriorTransition);
this.groupboxCamera.Controls.Add(this.labelCameraTransitionSpeed);
this.groupboxCamera.Controls.Add(this.updownCameraTransitionSpeed);
+ this.groupboxCamera.Controls.Add(this.labelZoomScrollSpeed);
+ this.groupboxCamera.Controls.Add(this.updownZoomScrollSpeed);
this.groupboxCamera.ForeColor = System.Drawing.Color.Black;
this.groupboxCamera.Location = new System.Drawing.Point(330, 0);
this.groupboxCamera.Name = "groupboxCamera";
- this.groupboxCamera.Size = new System.Drawing.Size(321, 120);
+ this.groupboxCamera.Size = new System.Drawing.Size(321, 150);
this.groupboxCamera.TabIndex = 22;
this.groupboxCamera.TabStop = false;
this.groupboxCamera.Text = "Camera options";
@@ -4312,6 +4352,8 @@ private void InitializeComponent() {
this.groupboxControl.Controls.Add(this.panelJoystick);
this.groupboxControl.Controls.Add(this.radiobuttonJoystick);
this.groupboxControl.Controls.Add(this.radiobuttonKeyboard);
+ this.groupboxControl.Controls.Add(this.radiobuttonMouse);
+ this.groupboxControl.Controls.Add(this.panelMouse);
this.groupboxControl.Enabled = false;
this.groupboxControl.ForeColor = System.Drawing.Color.Black;
this.groupboxControl.Location = new System.Drawing.Point(8, 349);
@@ -4408,22 +4450,22 @@ private void InitializeComponent() {
this.comboboxCommand.FormattingEnabled = true;
this.comboboxCommand.Location = new System.Drawing.Point(88, 21);
this.comboboxCommand.Name = "comboboxCommand";
- this.comboboxCommand.Size = new System.Drawing.Size(587, 21);
+ this.comboboxCommand.Size = new System.Drawing.Size(400, 21);
this.comboboxCommand.TabIndex = 1;
this.comboboxCommand.SelectedIndexChanged += new System.EventHandler(this.comboboxCommand_SelectedIndexChanged);
//
// updownCommandOption
//
- this.updownCommandOption.Location = new System.Drawing.Point(583, 48);
+ this.updownCommandOption.Location = new System.Drawing.Point(615, 21);
this.updownCommandOption.Name = "updownCommandOption";
- this.updownCommandOption.Size = new System.Drawing.Size(52, 20);
+ this.updownCommandOption.Size = new System.Drawing.Size(60, 20);
this.updownCommandOption.TabIndex = 6;
this.updownCommandOption.ValueChanged += new System.EventHandler(this.updownCommandOption_ValueChanged);
//
// labelCommandOption
//
this.labelCommandOption.AutoEllipsis = true;
- this.labelCommandOption.Location = new System.Drawing.Point(463, 51);
+ this.labelCommandOption.Location = new System.Drawing.Point(490, 24);
this.labelCommandOption.Name = "labelCommandOption";
this.labelCommandOption.Size = new System.Drawing.Size(120, 18);
this.labelCommandOption.TabIndex = 7;
@@ -4465,7 +4507,7 @@ private void InitializeComponent() {
this.panelJoystick.Controls.Add(this.labelJoystickAssignmentCaption);
this.panelJoystick.Controls.Add(this.labelJoystickAssignmentValue);
this.panelJoystick.Enabled = false;
- this.panelJoystick.Location = new System.Drawing.Point(264, 72);
+ this.panelJoystick.Location = new System.Drawing.Point(232, 72);
this.panelJoystick.Name = "panelJoystick";
this.panelJoystick.Size = new System.Drawing.Size(235, 48);
this.panelJoystick.TabIndex = 4;
@@ -4491,7 +4533,7 @@ private void InitializeComponent() {
// radiobuttonJoystick
//
this.radiobuttonJoystick.AutoSize = true;
- this.radiobuttonJoystick.Location = new System.Drawing.Point(272, 48);
+ this.radiobuttonJoystick.Location = new System.Drawing.Point(232, 48);
this.radiobuttonJoystick.Name = "radiobuttonJoystick";
this.radiobuttonJoystick.Size = new System.Drawing.Size(66, 17);
this.radiobuttonJoystick.TabIndex = 3;
@@ -4512,6 +4554,51 @@ private void InitializeComponent() {
this.radiobuttonKeyboard.UseVisualStyleBackColor = true;
this.radiobuttonKeyboard.CheckedChanged += new System.EventHandler(this.radiobuttonKeyboard_CheckedChanged);
//
+ // radiobuttonMouse
+ //
+ this.radiobuttonMouse.AutoSize = true;
+ this.radiobuttonMouse.Location = new System.Drawing.Point(456, 48);
+ this.radiobuttonMouse.Name = "radiobuttonMouse";
+ this.radiobuttonMouse.Size = new System.Drawing.Size(60, 17);
+ this.radiobuttonMouse.TabIndex = 11;
+ this.radiobuttonMouse.TabStop = true;
+ this.radiobuttonMouse.Text = "Mouse:";
+ this.radiobuttonMouse.UseVisualStyleBackColor = true;
+ this.radiobuttonMouse.CheckedChanged += new System.EventHandler(this.radiobuttonMouse_CheckedChanged);
+ //
+ // panelMouse
+ //
+ this.panelMouse.Controls.Add(this.comboboxMouseButton);
+ this.panelMouse.Controls.Add(this.labelMouseButton);
+ this.panelMouse.Enabled = false;
+ this.panelMouse.Location = new System.Drawing.Point(8, 72);
+ this.panelMouse.Name = "panelMouse";
+ this.panelMouse.Size = new System.Drawing.Size(192, 48);
+ this.panelMouse.TabIndex = 12;
+ this.panelMouse.Visible = false;
+ //
+ // labelMouseButton
+ //
+ this.labelMouseButton.AutoEllipsis = true;
+ this.labelMouseButton.Location = new System.Drawing.Point(0, 3);
+ this.labelMouseButton.Name = "labelMouseButton";
+ this.labelMouseButton.Size = new System.Drawing.Size(60, 18);
+ this.labelMouseButton.TabIndex = 0;
+ this.labelMouseButton.Text = "Button:";
+ this.labelMouseButton.TextAlign = System.Drawing.ContentAlignment.TopRight;
+ //
+ // comboboxMouseButton
+ //
+ this.comboboxMouseButton.Anchor = ((System.Windows.Forms.AnchorStyles)(((System.Windows.Forms.AnchorStyles.Top | System.Windows.Forms.AnchorStyles.Left)
+ | System.Windows.Forms.AnchorStyles.Right)));
+ this.comboboxMouseButton.DropDownStyle = System.Windows.Forms.ComboBoxStyle.DropDownList;
+ this.comboboxMouseButton.FormattingEnabled = true;
+ this.comboboxMouseButton.Location = new System.Drawing.Point(64, 0);
+ this.comboboxMouseButton.Name = "comboboxMouseButton";
+ this.comboboxMouseButton.Size = new System.Drawing.Size(104, 21);
+ this.comboboxMouseButton.TabIndex = 1;
+ this.comboboxMouseButton.SelectedIndexChanged += new System.EventHandler(this.comboboxMouseButton_SelectedIndexChanged);
+ //
// panelInfo
//
this.panelInfo.Anchor = ((System.Windows.Forms.AnchorStyles)((System.Windows.Forms.AnchorStyles.Bottom | System.Windows.Forms.AnchorStyles.Left)));
@@ -6695,6 +6782,10 @@ private void InitializeComponent() {
private System.Windows.Forms.GroupBox groupboxControl;
private System.Windows.Forms.RadioButton radiobuttonJoystick;
private System.Windows.Forms.RadioButton radiobuttonKeyboard;
+ private System.Windows.Forms.RadioButton radiobuttonMouse;
+ private System.Windows.Forms.Panel panelMouse;
+ private System.Windows.Forms.Label labelMouseButton;
+ private System.Windows.Forms.ComboBox comboboxMouseButton;
private System.Windows.Forms.Panel panelKeyboard;
private System.Windows.Forms.ComboBox comboboxKeyboardKey;
private System.Windows.Forms.Label labelKeyboardKey;
@@ -6889,6 +6980,8 @@ private void InitializeComponent() {
private System.Windows.Forms.Button SaveFileNameButton;
private System.Windows.Forms.TextBox textBoxPackageFileName;
private System.Windows.Forms.GroupBox groupBoxOther;
+ private System.Windows.Forms.Label labelZoomScrollSpeed;
+ private System.Windows.Forms.NumericUpDown updownZoomScrollSpeed;
private System.Windows.Forms.ComboBox comboBoxTimeTableDisplayMode;
private System.Windows.Forms.Label labelTimeTableDisplayMode;
private System.Windows.Forms.Label labelSaveAs;
diff --git a/source/OpenBVE/UserInterface/formMain.Options.cs b/source/OpenBVE/UserInterface/formMain.Options.cs
index 068943f4e..2a39fec87 100644
--- a/source/OpenBVE/UserInterface/formMain.Options.cs
+++ b/source/OpenBVE/UserInterface/formMain.Options.cs
@@ -195,5 +195,10 @@ private void comboboxCursor_SelectedIndexChanged(object sender, EventArgs e)
if (Tag != null) return;
Cursors.SelectedCursor(comboboxCursor, pictureboxCursor);
}
+
+ private void updownZoomScrollSpeed_ValueChanged(object sender, EventArgs e)
+ {
+ Interface.CurrentOptions.ZoomScrollSpeed = (double)updownZoomScrollSpeed.Value;
+ }
}
}
diff --git a/source/OpenBVE/UserInterface/formMain.cs b/source/OpenBVE/UserInterface/formMain.cs
index e9c132ee2..704aa644f 100644
--- a/source/OpenBVE/UserInterface/formMain.cs
+++ b/source/OpenBVE/UserInterface/formMain.cs
@@ -525,6 +525,7 @@ private void formMain_Load(object sender, EventArgs e)
checkboxCameraInteriorTransition.Checked = Interface.CurrentOptions.CameraInteriorTransition;
checkboxCameraExteriorTransition.Checked = Interface.CurrentOptions.CameraExteriorTransition;
updownCameraTransitionSpeed.Value = (decimal)Interface.CurrentOptions.CameraTransitionSpeed;
+ updownZoomScrollSpeed.Value = (decimal)Interface.CurrentOptions.ZoomScrollSpeed;
ListInputDevicePlugins();
if (Program.CurrentHost.MonoRuntime)
{
@@ -779,6 +780,11 @@ private void ApplyLanguage()
checkboxCameraInteriorTransition.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","camera_interior_transition"});
checkboxCameraExteriorTransition.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","camera_exterior_transition"});
labelCameraTransitionSpeed.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","camera_transition_duration"});
+ labelZoomScrollSpeed.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] { "options", "camera_zoom_scroll_speed" });
+ if (labelZoomScrollSpeed.Text == "camera_zoom_scroll_speed")
+ {
+ labelZoomScrollSpeed.Text = "Zoom Scroll Speed:";
+ }
checkboxToppling.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","misc_simulation_toppling"});
checkboxCollisions.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","misc_simulation_collisions"});
checkboxDerailments.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"options","misc_simulation_derailments"});
@@ -994,6 +1000,14 @@ private void ApplyLanguage()
checkboxKeyboardAlt.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"controls","selection_keyboard_modifiers_alt"});
radiobuttonJoystick.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"controls","selection_joystick"});
+ radiobuttonMouse.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"controls","selection_mouse"});
+ labelMouseButton.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"controls","selection_mouse_button"});
+ comboboxMouseButton.Items.Clear();
+ comboboxMouseButton.Items.Add(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"controls","assignment_mouse_left"}));
+ comboboxMouseButton.Items.Add(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"controls","assignment_mouse_middle"}));
+ comboboxMouseButton.Items.Add(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"controls","assignment_mouse_right"}));
+ comboboxMouseButton.Items.Add(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"controls","assignment_mouse_scrollup"}));
+ comboboxMouseButton.Items.Add(Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"controls","assignment_mouse_scrolldown"}));
labelJoystickAssignmentCaption.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"controls","selection_joystick_assignment"});
textboxJoystickGrab.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"controls","selection_keyboard_assignment_grab"});
groupboxJoysticks.Text = Translations.GetInterfaceString(HostApplication.OpenBve, new[] {"controls","attached"});
diff --git a/source/OpenBveApi/Interface/Input/Commands.CommandInfo.cs b/source/OpenBveApi/Interface/Input/Commands.CommandInfo.cs
index 1a997a56d..776b72ba6 100644
--- a/source/OpenBveApi/Interface/Input/Commands.CommandInfo.cs
+++ b/source/OpenBveApi/Interface/Input/Commands.CommandInfo.cs
@@ -238,6 +238,7 @@ public static CommandInfo TryGetInfo(this Dictionary comma
{ Command.CameraPOIPrevious, new CommandInfo(Command.CameraPOIPrevious, CommandType.Digital, "CAMERA_POI_PREVIOUS") },
{ Command.CameraPOINext, new CommandInfo(Command.CameraPOINext, CommandType.Digital, "CAMERA_POI_NEXT") },
{ Command.CameraReset, new CommandInfo(Command.CameraReset, CommandType.Digital, "CAMERA_RESET") },
+ { Command.CameraGrabToggle, new CommandInfo(Command.CameraGrabToggle, CommandType.Digital, "CAMERA_GRAB_TOGGLE") },
{ Command.CameraRestriction, new CommandInfo(Command.CameraRestriction, CommandType.Digital, "CAMERA_RESTRICTION") },
{ Command.TimetableToggle, new CommandInfo(Command.TimetableToggle, CommandType.Digital, "TIMETABLE_TOGGLE") },
{ Command.TimetableUp, new CommandInfo(Command.TimetableUp, CommandType.AnalogHalf, "TIMETABLE_UP") },
diff --git a/source/OpenBveApi/Interface/Input/Commands.cs b/source/OpenBveApi/Interface/Input/Commands.cs
index 18c450ead..e738bf49b 100644
--- a/source/OpenBveApi/Interface/Input/Commands.cs
+++ b/source/OpenBveApi/Interface/Input/Commands.cs
@@ -120,6 +120,8 @@ public enum Command
CameraPOINext,
/// Reset the camera to pointing immediately forwards at track-level
CameraReset,
+ /// Toggles camera grab (Mouse looking)
+ CameraGrabToggle,
/// Toggle camera restriction mode
CameraRestriction,
/// Shows or hides the in-game timetable
diff --git a/source/OpenBveApi/Interface/Input/Control.cs b/source/OpenBveApi/Interface/Input/Control.cs
index bc045e331..bbd8a1d5a 100644
--- a/source/OpenBveApi/Interface/Input/Control.cs
+++ b/source/OpenBveApi/Interface/Input/Control.cs
@@ -1,4 +1,4 @@
-using System;
+using System;
using OpenBveApi.Input;
namespace OpenBveApi.Interface
@@ -58,6 +58,9 @@ public override string ToString()
}
s += ", " + Option;
break;
+ case ControlMethod.Mouse:
+ s += Element + ", " + Option;
+ break;
}
return s;
}
diff --git a/source/OpenBveApi/Interface/Input/ControlMethod.cs b/source/OpenBveApi/Interface/Input/ControlMethod.cs
index 79b2fe4a5..511cc2b5f 100644
--- a/source/OpenBveApi/Interface/Input/ControlMethod.cs
+++ b/source/OpenBveApi/Interface/Input/ControlMethod.cs
@@ -1,4 +1,4 @@
-namespace OpenBveApi.Interface
+namespace OpenBveApi.Interface
{
/// The method by which a control is activated
public enum ControlMethod
@@ -14,6 +14,8 @@ public enum ControlMethod
/// This control is activated using the Input Device Plugin
InputDevicePlugin = 4,
/// This control is activated using a touch element
- Touch = 5
+ Touch = 5,
+ /// This control is activated using a mouse button or wheel
+ Mouse = 6
}
}
diff --git a/source/OpenBveApi/Math/Vectors/Vector3.cs b/source/OpenBveApi/Math/Vectors/Vector3.cs
index 09c77609f..a37d5453e 100644
--- a/source/OpenBveApi/Math/Vectors/Vector3.cs
+++ b/source/OpenBveApi/Math/Vectors/Vector3.cs
@@ -321,6 +321,10 @@ public static implicit operator Vector3f(Vector3 v)
/// The multiplied vector
public static Vector3 operator *(Vector3 v, Transformation t)
{
+ if (t == null)
+ {
+ return v;
+ }
v = t.X * v.X + t.Y * v.Y + t.Z * v.Z;
return v;
}
@@ -497,6 +501,10 @@ public void Rotate(Orientation3 orientation) {
/// The transformation
public void Rotate(Transformation transformation)
{
+ if (transformation == null)
+ {
+ return;
+ }
double x = transformation.X.X * X + transformation.Y.X * Y + transformation.Z.X * Z;
double y = transformation.X.Y * X + transformation.Y.Y * Y + transformation.Z.Y * Z;
double z = transformation.X.Z * X + transformation.Y.Z * Y + transformation.Z.Z * Z;
diff --git a/source/OpenBveApi/System/BaseOptions.OptionsKey.cs b/source/OpenBveApi/System/BaseOptions.OptionsKey.cs
index d0952ff24..d50a1e9d0 100644
--- a/source/OpenBveApi/System/BaseOptions.OptionsKey.cs
+++ b/source/OpenBveApi/System/BaseOptions.OptionsKey.cs
@@ -80,6 +80,7 @@ public enum OptionsKey
KeyRepeatInterval,
RailDriverMPH,
CursorHideDelay,
+ ZoomScrollSpeed,
// Sound
Model,
Range,
diff --git a/source/OpenBveApi/World/Transformations.cs b/source/OpenBveApi/World/Transformations.cs
index 0f3a786d0..d8bbc0a76 100644
--- a/source/OpenBveApi/World/Transformations.cs
+++ b/source/OpenBveApi/World/Transformations.cs
@@ -1,4 +1,4 @@
-using OpenBveApi.Math;
+using OpenBveApi.Math;
namespace OpenBveApi.World
{
@@ -81,6 +81,10 @@ public Transformation(double Yaw, double Pitch, double Roll)
///
public Transformation(Transformation Transformation, double Yaw, double Pitch, double Roll)
{
+ if (Transformation == null)
+ {
+ Transformation = NullTransformation;
+ }
X = new Vector3(Transformation.X);
Y = new Vector3(Transformation.Y);
Z = new Vector3(Transformation.Z);
@@ -99,6 +103,14 @@ public Transformation(Transformation Transformation, double Yaw, double Pitch, d
/// The transformation to apply second
public Transformation(Transformation firstTransformation, Transformation secondTransformation)
{
+ if (firstTransformation == null)
+ {
+ firstTransformation = NullTransformation;
+ }
+ if (secondTransformation == null)
+ {
+ secondTransformation = NullTransformation;
+ }
X = new Vector3(firstTransformation.X);
Y = new Vector3(firstTransformation.Y);
Z = new Vector3(firstTransformation.Z);
@@ -133,6 +145,10 @@ public Transformation(Vector3f direction, Vector3f up, Vector3f side)
/// The transformation to convert
public static explicit operator Matrix4D(Transformation t)
{
+ if (t == null)
+ {
+ return Matrix4D.NoTransformation;
+ }
// X, Y and Z represent the basis vector.
// Arrange them in row-major to create a change-of-basis matrix.
// And converting from the left-handed coordinate system to the right-handed coordinate system by reversing the Z axis.