1717
1818// This file is the responsibility of the 3D & Environment Team.
1919
20+ using System ;
21+ using System . Collections . Generic ;
22+ using System . Linq ;
2023using Microsoft . Xna . Framework ;
2124using Microsoft . Xna . Framework . Graphics ;
2225using Orts . Formats . Msts ;
2528using Orts . Viewer3D . RollingStock . SubSystems . ETCS ;
2629using ORTS . Common ;
2730using ORTS . Scripting . Api . ETCS ;
28- using System ;
29- using System . Collections . Generic ;
30- using System . Linq ;
3131using static Orts . Viewer3D . RollingStock . Subsystems . ETCS . DriverMachineInterface ;
3232
3333namespace Orts . Viewer3D . RollingStock . Subsystems . ETCS
3434{
3535 public class DriverMachineInterface
3636 {
3737 public readonly MSTSLocomotive Locomotive ;
38- public readonly bool GaugeOnly ;
3938 public readonly Viewer Viewer ;
4039 public IList < DMIWindow > Windows = new List < DMIWindow > ( ) ;
4140 float PrevScale = 1 ;
@@ -44,8 +43,8 @@ public class DriverMachineInterface
4443 bool Active ;
4544 public float Scale { get ; private set ; }
4645 public float MipMapScale { get ; private set ; }
47- readonly int Height = 480 ;
48- readonly int Width = 640 ;
46+ public readonly int Height ;
47+ public readonly int Width ;
4948
5049 public readonly ETCSDefaultWindow ETCSDefaultWindow ;
5150
@@ -70,6 +69,16 @@ public class DriverMachineInterface
7069
7170 public bool Blinker2Hz { get ; private set ; }
7271 public bool Blinker4Hz { get ; private set ; }
72+
73+ public enum DMIMode
74+ {
75+ FullSize ,
76+ SpeedArea ,
77+ PlanningArea ,
78+ GaugeOnly
79+ }
80+ public DMIMode CurrentDMIMode ;
81+
7382 float BlinkerTime ;
7483
7584 public float CurrentTime => ( float ) Viewer . Simulator . ClockTime ;
@@ -88,12 +97,40 @@ public class DriverMachineInterface
8897 DMIButton ActiveButton ;
8998 public DriverMachineInterface ( float height , float width , MSTSLocomotive locomotive , Viewer viewer , CabViewControl control )
9099 {
100+ if ( control is CVCScreen )
101+ {
102+ CurrentDMIMode = DMIMode . FullSize ;
103+ if ( ( control as CVCScreen ) . CustomParameters . TryGetValue ( "mode" , out string mode ) )
104+ {
105+ if ( mode == "planningarea" ) CurrentDMIMode = DMIMode . PlanningArea ;
106+ else if ( mode == "speedarea" ) CurrentDMIMode = DMIMode . SpeedArea ;
107+ }
108+ }
109+ else
110+ {
111+ CurrentDMIMode = DMIMode . GaugeOnly ;
112+ }
113+ switch ( CurrentDMIMode )
114+ {
115+ case DMIMode . GaugeOnly :
116+ Width = 280 ;
117+ Height = 300 ;
118+ break ;
119+ case DMIMode . FullSize :
120+ Width = 640 ;
121+ Height = 480 ;
122+ break ;
123+ case DMIMode . PlanningArea :
124+ case DMIMode . SpeedArea :
125+ Width = 334 ;
126+ Height = 480 ;
127+ break ;
128+ }
91129 Viewer = viewer ;
92130 Locomotive = locomotive ;
93131 Scale = Math . Min ( width / Width , height / Height ) ;
94132 if ( Scale < 0.5 ) MipMapScale = 2 ;
95133 else MipMapScale = 1 ;
96- GaugeOnly = control is CVCDigital ;
97134
98135 Shader = new DriverMachineInterfaceShader ( Viewer . GraphicsDevice ) ;
99136 ETCSDefaultWindow = new ETCSDefaultWindow ( this , control ) ;
@@ -259,20 +296,22 @@ public class ETCSDefaultWindow : DMIWindow
259296 TargetDistance TargetDistance ;
260297 TTIandLSSMArea TTIandLSSMArea ;
261298 MenuBar MenuBar ;
262- public ETCSDefaultWindow ( DriverMachineInterface dmi , CabViewControl control ) : base ( dmi , 640 , 480 )
299+ public ETCSDefaultWindow ( DriverMachineInterface dmi , CabViewControl control ) : base ( dmi , dmi . Width , dmi . Height )
263300 {
264- if ( control is CVCDigital )
301+ if ( dmi . CurrentDMIMode == DMIMode . GaugeOnly )
265302 {
266303 var dig = control as CVCDigital ;
267304 CircularSpeedGauge = new CircularSpeedGauge (
268- ( int ) dig . MaxValue ,
269- dig . Units != CABViewControlUnits . MILES_PER_HOUR ,
270- dig . Units != CABViewControlUnits . NONE ,
271- dig . MaxValue == 240 || dig . MaxValue == 260 ,
272- ( int ) dig . MinValue ,
273- DMI ) ;
305+ ( int ) dig . MaxValue ,
306+ dig . Units != CABViewControlUnits . MILES_PER_HOUR ,
307+ dig . Units != CABViewControlUnits . NONE ,
308+ dig . MaxValue == 240 || dig . MaxValue == 260 ,
309+ ( int ) dig . MinValue ,
310+ DMI ) ;
311+ AddToLayout ( CircularSpeedGauge , new Point ( 0 , 0 ) ) ;
312+ return ;
274313 }
275- else
314+ if ( dmi . CurrentDMIMode != DMIMode . PlanningArea )
276315 {
277316 var param = ( control as CVCScreen ) . CustomParameters ;
278317 int maxSpeed = 400 ;
@@ -286,34 +325,37 @@ public ETCSDefaultWindow(DriverMachineInterface dmi, CabViewControl control) : b
286325 maxSpeed == 240 || maxSpeed == 260 ,
287326 maxVisibleSpeed ,
288327 dmi
289- ) ;
290- }
291- if ( DMI . GaugeOnly )
292- {
293- AddToLayout ( CircularSpeedGauge , new Point ( 0 , 0 ) ) ;
294- return ;
295- }
296- PlanningWindow = new PlanningWindow ( dmi ) ;
297- TTIandLSSMArea = new TTIandLSSMArea ( dmi ) ;
298- TargetDistance = new TargetDistance ( dmi ) ;
299- MessageArea = new MessageArea ( dmi ) ;
300- MenuBar = new MenuBar ( dmi ) ;
301- CircularSpeedGauge . Layer = - 1 ;
302- TargetDistance . Layer = - 1 ;
303- TTIandLSSMArea . Layer = - 1 ;
304- MessageArea . Layer = - 1 ;
305- AddToLayout ( CircularSpeedGauge , new Point ( 54 , DMI . IsSoftLayout ? 0 : 15 ) ) ;
306- AddToLayout ( PlanningWindow , new Point ( 334 , DMI . IsSoftLayout ? 0 : 15 ) ) ;
307- AddToLayout ( PlanningWindow . ButtonScaleDown , new Point ( 334 , DMI . IsSoftLayout ? 0 : 15 ) ) ;
308- AddToLayout ( PlanningWindow . ButtonScaleUp , new Point ( 334 , 285 + ( DMI . IsSoftLayout ? 0 : 15 ) ) ) ;
309- AddToLayout ( TTIandLSSMArea , new Point ( 0 , DMI . IsSoftLayout ? 0 : 15 ) ) ;
310- AddToLayout ( TargetDistance , new Point ( 0 , 54 + ( DMI . IsSoftLayout ? 0 : 15 ) ) ) ;
311- AddToLayout ( MessageArea , new Point ( 54 , DMI . IsSoftLayout ? 350 : 365 ) ) ;
312- AddToLayout ( MessageArea . ButtonScrollUp , new Point ( 54 + 234 , DMI . IsSoftLayout ? 350 : 365 ) ) ;
313- AddToLayout ( MessageArea . ButtonScrollDown , new Point ( 54 + 234 , MessageArea . Height / 2 + ( DMI . IsSoftLayout ? 350 : 365 ) ) ) ;
314- foreach ( int i in Enumerable . Range ( 0 , MenuBar . Buttons . Count ) )
315- {
316- AddToLayout ( MenuBar . Buttons [ i ] , new Point ( 580 , 15 + 50 * i ) ) ;
328+ ) ;
329+ TTIandLSSMArea = new TTIandLSSMArea ( dmi ) ;
330+ TargetDistance = new TargetDistance ( dmi ) ;
331+ MessageArea = new MessageArea ( dmi ) ;
332+ CircularSpeedGauge . Layer = - 1 ;
333+ TargetDistance . Layer = - 1 ;
334+ TTIandLSSMArea . Layer = - 1 ;
335+ MessageArea . Layer = - 1 ;
336+ AddToLayout ( CircularSpeedGauge , new Point ( 54 , DMI . IsSoftLayout ? 0 : 15 ) ) ;
337+ AddToLayout ( TTIandLSSMArea , new Point ( 0 , DMI . IsSoftLayout ? 0 : 15 ) ) ;
338+ AddToLayout ( TargetDistance , new Point ( 0 , 54 + ( DMI . IsSoftLayout ? 0 : 15 ) ) ) ;
339+ AddToLayout ( MessageArea , new Point ( 54 , DMI . IsSoftLayout ? 350 : 365 ) ) ;
340+ AddToLayout ( MessageArea . ButtonScrollUp , new Point ( 54 + 234 , DMI . IsSoftLayout ? 350 : 365 ) ) ;
341+ AddToLayout ( MessageArea . ButtonScrollDown , new Point ( 54 + 234 , MessageArea . Height / 2 + ( DMI . IsSoftLayout ? 350 : 365 ) ) ) ;
342+ }
343+ if ( dmi . CurrentDMIMode != DMIMode . SpeedArea )
344+ {
345+ // Calculate start position of the planning area when a two-screen display is used
346+ // Real width of the left area in ETCS specs is 306 px, however in order to have
347+ // both screens with the same size I assumed both have 334 px
348+ // To be checked
349+ int startPos = dmi . CurrentDMIMode == DMIMode . FullSize ? 334 : ( 334 - 306 ) / 2 ;
350+ PlanningWindow = new PlanningWindow ( dmi ) ;
351+ MenuBar = new MenuBar ( dmi ) ;
352+ AddToLayout ( PlanningWindow , new Point ( startPos , DMI . IsSoftLayout ? 0 : 15 ) ) ;
353+ AddToLayout ( PlanningWindow . ButtonScaleDown , new Point ( startPos , DMI . IsSoftLayout ? 0 : 15 ) ) ;
354+ AddToLayout ( PlanningWindow . ButtonScaleUp , new Point ( startPos , 285 + ( DMI . IsSoftLayout ? 0 : 15 ) ) ) ;
355+ foreach ( int i in Enumerable . Range ( 0 , MenuBar . Buttons . Count ) )
356+ {
357+ AddToLayout ( MenuBar . Buttons [ i ] , new Point ( 580 , 15 + 50 * i ) ) ;
358+ }
317359 }
318360 }
319361 }
@@ -324,8 +366,8 @@ public class DMIArea
324366 public readonly DriverMachineInterface DMI ;
325367 protected Texture2D ColorTexture => DMI . ColorTexture ;
326368 public float Scale => DMI . Scale ;
327- public int Height ;
328- public int Width ;
369+ public readonly int Height ;
370+ public readonly int Width ;
329371 protected List < RectanglePrimitive > Rectangles = new List < RectanglePrimitive > ( ) ;
330372 protected List < TextPrimitive > Texts = new List < TextPrimitive > ( ) ;
331373 protected List < TexturePrimitive > Textures = new List < TexturePrimitive > ( ) ;
@@ -574,13 +616,6 @@ public class DMIButton : DMIArea
574616 public bool ShowButtonBorder ;
575617 public float FirstPressed ;
576618 public float LastPressed ;
577- public DMIButton ( string displayName , bool upType , DriverMachineInterface dmi , bool showButtonBorder ) : base ( dmi )
578- {
579- DisplayName = displayName ;
580- Enabled = false ;
581- UpType = upType ;
582- ShowButtonBorder = showButtonBorder ;
583- }
584619 public DMIButton ( string displayName , bool upType , Action pressedAction , int width , int height , DriverMachineInterface dmi , bool showButtonBorder = false ) : base ( dmi , width , height )
585620 {
586621 DisplayName = displayName ;
@@ -725,13 +760,11 @@ public CircularSpeedGaugeRenderer(Viewer viewer, MSTSLocomotive locomotive, CVCD
725760 : base ( viewer , locomotive , control , shader )
726761 {
727762 // Height is adjusted to keep compatibility
728- DMI = new DriverMachineInterface ( ( int ) ( Control . Width * 640 / 280 ) , ( int ) ( Control . Height * 480 / 300 ) , locomotive , viewer , control ) ;
763+ DMI = new DriverMachineInterface ( ( int ) Control . Width , ( int ) Control . Height , locomotive , viewer , control ) ;
729764 }
730765 public override void PrepareFrame ( RenderFrame frame , ElapsedTime elapsedTime )
731766 {
732767 base . PrepareFrame ( frame , elapsedTime ) ;
733- DrawPosition . Width = DrawPosition . Width * 640 / 280 ;
734- DrawPosition . Height = DrawPosition . Height * 480 / 300 ;
735768 DMI . SizeTo ( DrawPosition . Width , DrawPosition . Height ) ;
736769 DMI . ETCSDefaultWindow . BackgroundColor = Color . Transparent ;
737770 DMI . PrepareFrame ( elapsedTime . ClockSeconds ) ;
@@ -769,19 +802,19 @@ public override void PrepareFrame(RenderFrame frame, ElapsedTime elapsedTime)
769802 return ;
770803
771804 base . PrepareFrame ( frame , elapsedTime ) ;
772- var xScale = Viewer . CabWidthPixels / 640f ;
773- var yScale = Viewer . CabHeightPixels / 480f ;
805+ var xScale = ( float ) Viewer . CabWidthPixels / 640 ;
806+ var yScale = ( float ) Viewer . CabHeightPixels / 480 ;
774807 DrawPosition . X = ( int ) ( Position . X * xScale ) - Viewer . CabXOffsetPixels + Viewer . CabXLetterboxPixels ;
775808 DrawPosition . Y = ( int ) ( Position . Y * yScale ) + Viewer . CabYOffsetPixels + Viewer . CabYLetterboxPixels ;
776809 DrawPosition . Width = ( int ) ( Control . Width * xScale ) ;
777810 DrawPosition . Height = ( int ) ( Control . Height * yScale ) ;
778811 if ( Zoomed )
779812 {
780- DrawPosition . Width = 640 ;
781- DrawPosition . Height = 480 ;
813+ DrawPosition . Width = DMI . Width ;
814+ DrawPosition . Height = DMI . Height ;
782815 DMI . SizeTo ( DrawPosition . Width , DrawPosition . Height ) ;
783- DrawPosition . X -= 320 ;
784- DrawPosition . Y -= 240 ;
816+ DrawPosition . X -= DMI . Width / 2 ;
817+ DrawPosition . Y -= DMI . Height / 2 ;
785818 DMI . ETCSDefaultWindow . BackgroundColor = ColorBackground ;
786819 }
787820 else
@@ -796,7 +829,7 @@ public bool IsMouseWithin()
796829 {
797830 int x = ( int ) ( ( UserInput . MouseX - DrawPosition . X ) / DMI . Scale ) ;
798831 int y = ( int ) ( ( UserInput . MouseY - DrawPosition . Y ) / DMI . Scale ) ;
799- if ( UserInput . IsMouseRightButtonPressed && new Rectangle ( 0 , 0 , 640 , 480 ) . Contains ( x , y ) ) Zoomed = ! Zoomed ;
832+ if ( UserInput . IsMouseRightButtonPressed && new Rectangle ( 0 , 0 , DMI . Width , DMI . Height ) . Contains ( x , y ) ) Zoomed = ! Zoomed ;
800833 foreach ( var area in DMI . ActiveWindow . SubAreas )
801834 {
802835 if ( ! ( area is DMIButton ) ) continue ;
0 commit comments