Code development platform for open source projects from the European Union institutions

Skip to content
Snippets Groups Projects
VehicleForm.vb 28.5 KiB
Newer Older
' Copyright 2014 European Union.
' Licensed under the EUPL (the 'Licence');
'
' * You may not use this work except in compliance with the Licence.
' * You may obtain a copy of the Licence at: http://ec.europa.eu/idabc/eupl
' * Unless required by applicable law or agreed to in writing,
'   software distributed under the Licence is distributed on an "AS IS" basis,
'   WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
'
' See the LICENSE.txt for the specific language governing permissions and limitations.

Imports System.IO
Imports System.Linq
Imports System.Text.RegularExpressions
Imports TUGraz.VectoCommon.InputData
Imports TUGraz.VectoCommon.Models
Imports TUGraz.VectoCommon.Utils
Imports TUGraz.VectoCore.InputData.FileIO.JSON
Imports TUGraz.VectoCore.InputData.Impl
Imports TUGraz.VectoCore.Models.Declaration

''' <summary>
''' Vehicle Editor.
''' </summary>
	Private Enum AxleTbl
		AxleNumber = 0
		RelativeLoad = 1
		TwinTyres = 2
		RRC = 3
		FzISO = 4
		WheelsDimension = 5
		Inertia = 6
	Private Enum TorqueLimitsTbl
		Gear = 0
		MaxTorque = 1
	End Enum

	Private _axlDlog As VehicleAxleDialog
	Private _hdVclass As String
	Private _vehFile As String
	Private _changed As Boolean = False
	Private _cmFiles As String()

	Public AutoSendTo As Boolean = False
	Public JobDir As String = ""
	Private _torqueLimitDlog As VehicleTorqueLimitDialog

	'Close - Check for unsaved changes
Markus Quaritsch's avatar
Markus Quaritsch committed
	Private Sub VehicleFormClosing(sender As Object, e As FormClosingEventArgs) Handles Me.FormClosing
		If e.CloseReason <> CloseReason.ApplicationExitCall And e.CloseReason <> CloseReason.WindowsShutDown Then
			e.Cancel = ChangeCheckCancel()
		End If
	End Sub

	'Initialise form
Markus Quaritsch's avatar
Markus Quaritsch committed
	Private Sub VehicleFormLoad(sender As Object, e As EventArgs) Handles MyBase.Load
		TbLoadingMax.Text = "-"
		PnLoad.Enabled = Not Cfg.DeclMode
		ButAxlAdd.Enabled = Not Cfg.DeclMode
		ButAxlRem.Enabled = Not Cfg.DeclMode
		CbCdMode.Enabled = Not Cfg.DeclMode
		PnWheelDiam.Enabled = Not Cfg.DeclMode
		'gbPTO.Enabled = Not Cfg.DeclMode
		pnPTO.Enabled = Not Cfg.DeclMode
		CbCdMode.ValueMember = "Value"
		CbCdMode.DisplayMember = "Label"
		CbCdMode.DataSource = [Enum].GetValues(GetType(CrossWindCorrectionMode)) _
			.Cast(Of CrossWindCorrectionMode) _
			.Select(Function(mode) New With {Key .Value = mode, .Label = mode.GetLabel()}).ToList()

		CbRtType.ValueMember = "Value"
		CbRtType.DisplayMember = "Label"
		CbRtType.DataSource = [Enum].GetValues(GetType(RetarderType)) _
			.Select(Function(type) New With {Key .Value = type, .Label = type.GetLabel()}).ToList()

		CbAxleConfig.ValueMember = "Value"
		CbAxleConfig.DisplayMember = "Label"
		CbAxleConfig.DataSource = [Enum].GetValues(GetType(AxleConfiguration)) _
			.Cast(Of AxleConfiguration) _
			.Select(Function(category) New With {Key .Value = category, .Label = category.GetName()}).ToList()

		CbCat.ValueMember = "Value"
		CbCat.DisplayMember = "Label"
		CbCat.DataSource = [Enum].GetValues(GetType(VehicleCategory)) _
			.Select(Function(category) New With {Key .Value = category, .label = category.GetLabel()}).ToList()

		cbAngledriveType.ValueMember = "Value"
		cbAngledriveType.DisplayMember = "Label"
		cbAngledriveType.DataSource = [Enum].GetValues(GetType(AngledriveType)) _
			.Cast(Of AngledriveType).Select(Function(type) New With {Key .Value = type, .Label = type.GetLabel()}).ToList()
		_axlDlog = New VehicleAxleDialog
		_torqueLimitDlog = New VehicleTorqueLimitDialog()
		cbPTOType.ValueMember = "Value"
		cbPTOType.DisplayMember = "Label"
		cbPTOType.DataSource = DeclarationData.PTOTransmission.GetTechnologies.Select(
			Function(technology) New With {Key .Value = technology, .Label = technology}).ToList()
		'Items.AddRange(PtoTypeStrings.Values.Cast(Of Object).ToArray())

		_changed = False

		NewVehicle()
	End Sub

	'Set HDVclasss
	Private Sub SetHdVclass()
		If String.IsNullOrEmpty(TbMassMass.Text) OrElse Not IsNumeric(TbMassMass.Text) Then
			TbHDVclass.Text = "-"
			Exit Sub
		End If
		Dim vehC As VehicleCategory = CType(CbCat.SelectedValue, VehicleCategory)
		Dim axlC As AxleConfiguration = CType(CbAxleConfig.SelectedValue, AxleConfiguration)
		Dim maxMass As Kilogram = (TbMassMass.Text.ToDouble() * 1000).SI(Of Kilogram)()
		Dim s0 As Segment = Nothing
		Try
			s0 = DeclarationData.Segments.Lookup(vehC, axlC, maxMass, 0.SI(Of Kilogram), True)

		Catch
			' no segment found - ignore
		End Try
		If Not s0 Is Nothing Then
			_hdVclass = s0.VehicleClass.GetClassNumber()
		PicVehicle.Image = ConvPicPath(If(s0 Is Nothing, -1, _hdVclass.ToInt()), False)
	End Sub


	'Set generic values for Declaration mode
	Private Sub DeclInit()
		If Not Cfg.DeclMode Then Exit Sub

		If String.IsNullOrEmpty(TbMassMass.Text) Then
			TbHDVclass.Text = "-"
			Exit Sub
		End If
		Dim vehC As VehicleCategory = CType(CbCat.SelectedValue, VehicleCategory)
		Dim axlC As AxleConfiguration = CType(CbAxleConfig.SelectedValue, AxleConfiguration)
		Dim maxMass As Kilogram = (TbMassMass.Text.ToDouble() * 1000).SI(Of Kilogram)()
			s0 = DeclarationData.Segments.Lookup(vehC, axlC, maxMass, 0.SI(Of Kilogram), True)
		Catch
			' no segment found - ignore
		End Try
			_hdVclass = s0.VehicleClass.GetClassNumber()
			Dim axleCount As Integer = s0.Missions(0).AxleWeightDistribution.Count()
			If axleCount > i0 Then
				For i = 1 To axleCount - LvRRC.Items.Count
					LvRRC.Items.Add(CreateListViewItem(i + i0, Double.NaN, False, Double.NaN, Double.NaN, "", Double.NaN,
														AxleType.VehicleNonDriven))
				Next

			ElseIf axleCount < LvRRC.Items.Count Then
				For i = axleCount To LvRRC.Items.Count - 1
					LvRRC.Items.RemoveAt(LvRRC.Items.Count - 1)
				Next
			End If

			'PnAll.Enabled = False
			_hdVclass = "-"
		End If

		TbMassExtra.Text = "-"
		TbLoad.Text = "-"
		CbCdMode.SelectedValue = CrossWindCorrectionMode.DeclarationModeCorrection
		End If
	End Sub


#Region "Toolbar"

	'New
	Private Sub ToolStripBtNew_Click(sender As Object, e As EventArgs) Handles ToolStripBtNew.Click
		NewVehicle()
	End Sub

	'Open
	Private Sub ToolStripBtOpen_Click(sender As Object, e As EventArgs) Handles ToolStripBtOpen.Click
		If VehicleFileBrowser.OpenDialog(_vehFile) Then
			Try
				OpenVehicle(VehicleFileBrowser.Files(0))
			Catch ex As Exception
				MsgBox(ex.Message, MsgBoxStyle.OkOnly, "Error loading Vehicle File")
			End Try

		End If
	End Sub

	'Save
	Private Sub ToolStripBtSave_Click(sender As Object, e As EventArgs) Handles ToolStripBtSave.Click
		SaveOrSaveAs(False)
	End Sub

	'Save As
	Private Sub ToolStripBtSaveAs_Click(sender As Object, e As EventArgs) Handles ToolStripBtSaveAs.Click
		SaveOrSaveAs(True)
	End Sub

	'Send to VECTO Editor
	Private Sub ToolStripBtSendTo_Click(sender As Object, e As EventArgs) Handles ToolStripBtSendTo.Click

		If ChangeCheckCancel() Then Exit Sub

		If _vehFile = "" Then
			If MsgBox("Save file now?", MsgBoxStyle.YesNo) = MsgBoxResult.Yes Then
				If Not SaveOrSaveAs(True) Then Exit Sub
			Else
				Exit Sub
			End If
		End If


		If Not VectoJobForm.Visible Then
			VectoJobForm.WindowState = FormWindowState.Normal
		VectoJobForm.TbVEH.Text = GetFilenameWithoutDirectory(_vehFile, JobDir)
	End Sub

	'Help
	Private Sub ToolStripButton1_Click(sender As Object, e As EventArgs) Handles ToolStripButton1.Click
		If File.Exists(MyAppPath & "User Manual\help.html") Then
			Dim registryString As String =
					My.Computer.Registry.ClassesRoot.OpenSubKey("\http\shell\open\command\").GetValue("").ToString
			Dim defaultBrowserPath As String = Regex.Match(registryString, "(\"".*?\"")").Captures(0).ToString
			Process.Start(defaultBrowserPath, String.Format("""{0}{1}""", MyAppPath, "User Manual\help.html#vehicle-editor"))
		Else
			MsgBox("User Manual not found!", MsgBoxStyle.Critical)
		End If
	End Sub

#End Region

	'Save and Close
	Private Sub ButOK_Click(sender As Object, e As EventArgs) Handles ButOK.Click
		If SaveOrSaveAs(False) Then Close()
	End Sub

	'Cancel
	Private Sub ButCancel_Click(sender As Object, e As EventArgs) Handles ButCancel.Click
		Close()
	End Sub

	'Save or Save As function = true if file is saved
	Private Function SaveOrSaveAs(saveAs As Boolean) As Boolean
		If _vehFile = "" Or saveAs Then
			If VehicleFileBrowser.SaveDialog(_vehFile) Then
				_vehFile = VehicleFileBrowser.Files(0)
			Else
				Return False
			End If
		End If
		Return SaveVehicle(_vehFile)
	End Function

	'New VEH
	Private Sub NewVehicle()
		If ChangeCheckCancel() Then Exit Sub

		TbMass.Text = ""
		TbLoad.Text = ""
		TBrdyn.Text = ""
		TBcdA.Text = ""

		CbCdMode.SelectedIndex = 0
		TbCdFile.Text = ""

		CbRtType.SelectedIndex = 0
		TbRtRatio.Text = ""
		TbRtPath.Text = ""

		CbRtType.SelectedIndex = 0
		TbRtRatio.Text = ""
		TbRtPath.Text = ""

		CbCat.SelectedIndex = 0

		LvRRC.Items.Clear()

		TbMassMass.Text = ""
		TbMassExtra.Text = ""
		CbAxleConfig.SelectedIndex = 0

		cbPTOType.SelectedIndex = 0
		tbPTOLossMap.Text = ""

		DeclInit()

		_vehFile = ""
		Text = "VEH Editor"
		LbStatus.Text = ""

		_changed = False
	End Sub

	'Open VEH
	Sub OpenVehicle(file As String)

		If ChangeCheckCancel() Then Exit Sub

		Dim inputData As IEngineeringInputDataProvider = TryCast(JSONInputDataFactory.ReadComponentData(file), 
		Dim vehicle As IVehicleEngineeringInputData = inputData.VehicleInputData
		Dim airdrag As IAirdragEngineeringInputData = inputData.AirdragInputData
		Dim retarder As IRetarderInputData = inputData.RetarderInputData
		Dim angledrive As IAngledriveInputData = inputData.AngledriveInputData
		Dim pto As IPTOTransmissionInputData = inputData.PTOTransmissionInputData
		If Cfg.DeclMode <> vehicle.SavedInDeclarationMode Then
					MainForm.RbDecl.Checked = Not MainForm.RbDecl.Checked
					MainForm.OpenVectoFile(file)
Markus Quaritsch's avatar
Markus Quaritsch committed
		_vehFile = file
		Dim basePath As String = Path.GetDirectoryName(file)
		CbCat.SelectedValue = vehicle.VehicleCategory
		CbAxleConfig.SelectedValue = vehicle.AxleConfiguration
		TbMassMass.Text = (vehicle.GrossVehicleMassRating.Value() / 1000).ToGUIFormat()
		TbMass.Text = vehicle.CurbMassChassis.ToGUIFormat()
		TbMassExtra.Text = vehicle.CurbMassExtra.ToGUIFormat()
		TbLoad.Text = vehicle.Loading.ToGUIFormat()
		TBrdyn.Text = (vehicle.DynamicTyreRadius.Value() * 1000).ToGUIFormat()
		tbVehIdlingSpeed.Text = If(vehicle.EngineIdleSpeed Is Nothing, "", vehicle.EngineIdleSpeed.AsRPM.ToGUIFormat())
		CbCdMode.SelectedValue = airdrag.CrossWindCorrectionMode
			If(airdrag.CrosswindCorrectionMap Is Nothing, "", GetRelativePath(airdrag.CrosswindCorrectionMap.Source, basePath))

		CbRtType.SelectedValue = retarder.Type
		TbRtRatio.Text = retarder.Ratio.ToGUIFormat()
		TbRtPath.Text = If(retarder.LossMap Is Nothing, "", GetRelativePath(retarder.LossMap.Source, basePath))
		Dim i As Integer = 0
		Dim a0 As IAxleEngineeringInputData
		For Each a0 In vehicle.Axles
				Dim inertia As Double = DeclarationData.Wheels.Lookup(a0.Wheels).Inertia.Value()
				LvRRC.Items.Add(CreateListViewItem(i, Double.NaN, a0.TwinTyres, a0.RollResistanceCoefficient,
													a0.TyreTestLoad.Value(), a0.Wheels, inertia, a0.AxleType))
				LvRRC.Items.Add(CreateListViewItem(i, a0.AxleWeightShare, a0.TwinTyres, a0.RollResistanceCoefficient,
													a0.TyreTestLoad.Value(), a0.Wheels, a0.Inertia.Value(), a0.AxleType))
		lvTorqueLimits.Items.Clear()
		For Each entry As ITorqueLimitInputData In vehicle.TorqueLimits
			lvTorqueLimits.Items.Add(CreateMaxTorqueListViewItem(entry.Gear(), entry.MaxTorque.Value()))
		Next
		'TbMassExtra.Text = veh.MassExtra.ToGUIFormat()
		TBcdA.Text = If(airdrag.AirDragArea Is Nothing, "", airdrag.AirDragArea.ToGUIFormat())
		cbPTOType.SelectedValue = pto.PTOTransmissionType
		tbPTOLossMap.Text =
			If(Cfg.DeclMode OrElse pto.PTOLossMap Is Nothing, "", GetRelativePath(pto.PTOLossMap.Source, basePath))
		tbPTOCycle.Text = If(Cfg.DeclMode OrElse pto.PTOCycle Is Nothing, "", GetRelativePath(pto.PTOCycle.Source, basePath))
Markus Quaritsch's avatar
Markus Quaritsch committed
		cbAngledriveType.SelectedValue = angledrive.Type
		tbAngledriveRatio.Text = angledrive.Ratio.ToGUIFormat()
		tbAngledriveLossMapPath.Text =
			If(angledrive.LossMap Is Nothing, "", GetRelativePath(angledrive.LossMap.Source, basePath))

		VehicleFileBrowser.UpdateHistory(file)
Markus Quaritsch's avatar
Markus Quaritsch committed

	Private Function CreateListViewItem(axleNumber As Integer, share As Double, twinTire As Boolean, rrc As Double,
										fzIso As Double, wheels As String, inertia As Double, axletype As AxleType) As ListViewItem
		Dim retVal As New ListViewItem
		retVal.SubItems(0).Text = axleNumber.ToGUIFormat()
		FillDoubleValue(retVal, share, "-")
		retVal.SubItems.Add(If(twinTire, "yes", "no"))
		FillDoubleValue(retVal, rrc)
		FillDoubleValue(retVal, fzIso)
		retVal.SubItems.Add(wheels)
		FillDoubleValue(retVal, inertia)
		Return retVal
	End Function

	Private Sub FillDoubleValue(listViewItem As ListViewItem, share As Double, Optional defaultValue As String = "")

		If Double.IsNaN(share) Then
			listViewItem.SubItems.Add(defaultValue)
		Else
			listViewItem.SubItems.Add(share.ToGUIFormat())
		End If
	End Sub

	'Save VEH
	Private Function SaveVehicle(file As String) As Boolean

		veh.MassExtra = TbMassExtra.Text.ToDouble(0)
		veh.Loading = TbLoad.Text.ToDouble(0)
		veh.CdA0 = If(String.IsNullOrWhiteSpace(TBcdA.Text), Double.NaN, TBcdA.Text.ToDouble(0))
		veh.DynamicTyreRadius = TBrdyn.Text.ToDouble(0)
		veh.CrossWindCorrectionMode = CType(CbCdMode.SelectedValue, CrossWindCorrectionMode)
		veh.CrossWindCorrectionFile.Init(GetPath(file), TbCdFile.Text)
		veh.RetarderType = CType(CbRtType.SelectedValue, RetarderType)
		veh.RetarderRatio = TbRtRatio.Text.ToDouble(0)
		veh.RetarderLossMapFile.Init(GetPath(file), TbRtPath.Text)
		veh.VehicleidlingSpeed = _tbVehIdlingSpeed.Text.ToDouble(0).RPMtoRad()

		veh.AngledriveType = CType(cbAngledriveType.SelectedValue, AngledriveType)
		veh.AngledriveRatio = tbAngledriveRatio.Text.ToDouble(0)
		veh.AngledriveLossMapFile.Init(GetPath(file), tbAngledriveLossMapPath.Text)
		veh.VehicleCategory = CType(CbCat.SelectedValue, VehicleCategory) 'CType(CbCat.SelectedIndex, tVehCat)
		For Each entry As ListViewItem In LvRRC.Items
			Dim a0 As AxleInputData = New AxleInputData()
			a0.AxleWeightShare = entry.SubItems(AxleTbl.RelativeLoad).Text.ToDouble(0)
			a0.TwinTyres = (entry.SubItems(AxleTbl.TwinTyres).Text = "yes")
			a0.RollResistanceCoefficient = entry.SubItems(AxleTbl.RRC).Text.ToDouble(0)
			a0.TyreTestLoad = entry.SubItems(AxleTbl.FzISO).Text.ToDouble(0).SI(Of Newton)()
			a0.Wheels = entry.SubItems(AxleTbl.WheelsDimension).Text
			a0.Inertia = entry.SubItems(AxleTbl.Inertia).Text.ToDouble(0).SI(Of KilogramSquareMeter)()
			a0.AxleType = entry.SubItems(AxleTbl.AxleType).Text.ParseEnum(Of AxleType)()
		veh.PtoType = CType(cbPTOType.SelectedValue, String)
		veh.PtoLossMap.Init(GetPath(file), tbPTOLossMap.Text)
		veh.PtoCycle.Init(GetPath(file), tbPTOCycle.Text)
		veh.MassExtra = TbMassExtra.Text.ToDouble(0)
		veh.AxleConfiguration = CType(CbAxleConfig.SelectedValue, AxleConfiguration)
		For Each item As ListViewItem In lvTorqueLimits.Items
			Dim tl As TorqueLimitInputData = New TorqueLimitInputData()
			tl.Gear() = item.SubItems(TorqueLimitsTbl.Gear).Text.ToInt(0)
			tl.MaxTorque = item.SubItems(TorqueLimitsTbl.MaxTorque).Text.ToDouble(0).SI(Of NewtonMeter)()
			veh.torqueLimitsList.Add(tl)
		Next


		'---------------------------------------------------------------------------------
		If Not veh.SaveFile Then
			MsgBox("Cannot safe to " & file, MsgBoxStyle.Critical)
			Return False
		End If

		If AutoSendTo Then
			If VectoJobForm.Visible Then
				If UCase(FileRepl(VectoJobForm.TbVEH.Text, JobDir)) <> UCase(file) Then _
					VectoJobForm.TbVEH.Text = GetFilenameWithoutDirectory(file, JobDir)
		VehicleFileBrowser.UpdateHistory(file)
		LbStatus.Text = ""

		_changed = False

		Return True
	End Function

#Region "Cd"

	'Cd Mode Change
	Private Sub CbCdMode_SelectedIndexChanged(sender As Object, e As EventArgs) _
		Handles CbCdMode.SelectedIndexChanged
		Dim bEnabled As Boolean

		Select Case CType(CbCdMode.SelectedValue, CrossWindCorrectionMode)
			Case CrossWindCorrectionMode.VAirBetaLookupTable
				bEnabled = True
				LbCdMode.Text = "Input file: Yaw Angle [°], Cd Scaling Factor [-]"

			Case CrossWindCorrectionMode.SpeedDependentCorrectionFactor
				LbCdMode.Text = "Input file: Vehicle Speed [km/h], Cd Scaling Factor [-]" _
				'TODO: MQ 20160901: check if scaling factor or absolue value!

			Case Else ' tCdMode.ConstCd0, tCdMode.CdOfVdecl
				bEnabled = False
				LbCdMode.Text = ""

		End Select

		If Not Cfg.DeclMode Then
			TbCdFile.Enabled = bEnabled
			BtCdFileBrowse.Enabled = bEnabled
			BtCdFileOpen.Enabled = bEnabled
		End If

		Change()
	End Sub

	'Cd File Browse
	Private Sub BtCdFileBrowse_Click(sender As Object, e As EventArgs) Handles BtCdFileBrowse.Click
		Dim ex As String

		If CbCdMode.SelectedIndex = 1 Then
			ex = "vcdv"
		Else
			ex = "vcdb"
		End If

		If CrossWindCorrectionFileBrowser.OpenDialog(FileRepl(TbCdFile.Text, GetPath(_vehFile)), False, ex) Then _
			TbCdFile.Text = GetFilenameWithoutDirectory(CrossWindCorrectionFileBrowser.Files(0), GetPath(_vehFile))
	End Sub

	'Open Cd File
	Private Sub BtCdFileOpen_Click(sender As Object, e As EventArgs) Handles BtCdFileOpen.Click
		OpenFiles(FileRepl(TbCdFile.Text, GetPath(_vehFile)))
	End Sub

#End Region

#Region "Retarder"

	'Rt Type Change
	Private Sub CbRtType_SelectedIndexChanged(sender As Object, e As EventArgs) _
		Handles CbRtType.SelectedIndexChanged
		Select Case CbRtType.SelectedIndex
			Case 1 'Primary
				LbRtRatio.Text = "Ratio to engine speed"
				PnRt.Enabled = True
			Case 2 'Secondary
				LbRtRatio.Text = "Ratio to cardan shaft speed"
				TbRtPath.Enabled = True
				BtRtBrowse.Enabled = True
				PnRt.Enabled = True
			Case Else '0 None
				LbRtRatio.Text = "Ratio"
				PnRt.Enabled = False
		End Select

		Change()
	End Sub

	'Rt File Browse
	Private Sub BtRtBrowse_Click(sender As Object, e As EventArgs) Handles BtRtBrowse.Click
		If RetarderLossMapFileBrowser.OpenDialog(FileRepl(TbRtPath.Text, GetPath(_vehFile))) Then _
			TbRtPath.Text = GetFilenameWithoutDirectory(RetarderLossMapFileBrowser.Files(0), GetPath(_vehFile))
	End Sub

#End Region

#Region "Track changes"

	Private Sub Change()
		If Not _changed Then
			LbStatus.Text = "Unsaved changes in current file"
			_changed = True
		End If
	End Sub

	' "Save changes? "... Returns True if user aborts
	Private Function ChangeCheckCancel() As Boolean

			Select Case MsgBox("Save changes ?", MsgBoxStyle.YesNoCancel)
				Case MsgBoxResult.Yes
					Return Not SaveOrSaveAs(False)
				Case MsgBoxResult.Cancel
					Return True
				Case Else 'MsgBoxResult.No
					_changed = False
					Return False
			End Select
	End Function

	Private Sub TBmass_TextChanged(sender As Object, e As EventArgs) Handles TbMass.TextChanged
		SetMaxLoad()
		Change()
	End Sub

	Private Sub TBcw_TextChanged(sender As Object, e As EventArgs) _
		Handles TbLoad.TextChanged, TBrdyn.TextChanged, TBcdA.TextChanged, TbCdFile.TextChanged, TbRtRatio.TextChanged,
				cbAngledriveType.SelectedIndexChanged, TbRtPath.TextChanged, tbAngledriveLossMapPath.TextChanged,
				tbAngledriveRatio.TextChanged, tbPTOLossMap.TextChanged
		Change()
	End Sub

	Private Sub CbCat_SelectedIndexChanged(sender As Object, e As EventArgs) Handles CbCat.SelectedIndexChanged
		Change()
		SetHdVclass()
		DeclInit()
	End Sub

	Private Sub TbMassTrailer_TextChanged(sender As Object, e As EventArgs) Handles TbMassExtra.TextChanged
		SetMaxLoad()
		Change()
	End Sub

	Private Sub TbMassMax_TextChanged(sender As Object, e As EventArgs) Handles TbMassMass.TextChanged
		SetMaxLoad()
		Change()
		SetHdVclass()
		DeclInit()
	End Sub

	Private Sub CbAxleConfig_SelectedIndexChanged(sender As Object, e As EventArgs) _
		Handles CbAxleConfig.SelectedIndexChanged
		Change()
		SetHdVclass()
		DeclInit()
	End Sub

#End Region

	'Update maximum load when truck/trailer mass was changed
	Private Sub SetMaxLoad()
		If Not Cfg.DeclMode Then
			If IsNumeric(TbMass.Text) And IsNumeric(TbMassExtra.Text) And IsNumeric(TbMassMass.Text) Then
				TbLoadingMax.Text = CStr(CSng(TbMassMass.Text) * 1000 - CSng(TbMass.Text) - CSng(TbMassExtra.Text))
			Else
				TbLoadingMax.Text = ""
			End If
		End If
	End Sub

#Region "Axle Configuration"

	Private Sub ButAxlAdd_Click(sender As Object, e As EventArgs) Handles ButAxlAdd.Click
		_axlDlog.Clear()
		If _axlDlog.ShowDialog = DialogResult.OK Then
			LvRRC.Items.Add(CreateListViewItem(LvRRC.Items.Count + 1, _axlDlog.TbAxleShare.Text.ToDouble(0),
												_axlDlog.CbTwinT.Checked, _axlDlog.TbRRC.Text.ToDouble(0), _axlDlog.TbFzISO.Text.ToDouble(0),
												_axlDlog.CbWheels.Text, _axlDlog.TbI_wheels.Text.ToDouble(0), AxleType.VehicleNonDriven))
			Change()
			DeclInit()

		End If
	End Sub

	Private Sub ButAxlRem_Click(sender As Object, e As EventArgs) Handles ButAxlRem.Click
		RemoveAxleItem()
	End Sub

	Private Sub LvAxle_DoubleClick(sender As Object, e As EventArgs) Handles LvRRC.DoubleClick
		EditAxleItem()
	End Sub

	Private Sub LvAxle_KeyDown(sender As Object, e As KeyEventArgs) Handles LvRRC.KeyDown
		Select Case e.KeyCode
			Case Keys.Delete, Keys.Back
				If Not Cfg.DeclMode Then RemoveAxleItem()
			Case Keys.Enter
				EditAxleItem()
		End Select
	End Sub

	Private Sub RemoveAxleItem()
		Dim lv0 As ListViewItem
		Dim i As Integer

		If LvRRC.SelectedItems.Count = 0 Then
			If LvRRC.Items.Count = 0 Then
				Exit Sub
			Else
				LvRRC.Items(LvRRC.Items.Count - 1).Selected = True
			End If
		End If

		LvRRC.SelectedItems(0).Remove()

		If LvRRC.Items.Count > 0 Then

			i = 0
			For Each lv0 In LvRRC.Items
				i += 1
				lv0.SubItems(AxleTbl.AxleNumber).Text = i.ToString
			Next

			LvRRC.Items(LvRRC.Items.Count - 1).Selected = True
			LvRRC.Focus()
		End If

		Change()
	End Sub

	Private Sub EditAxleItem()
		If LvRRC.SelectedItems.Count = 0 Then Exit Sub

		Dim lv0 As ListViewItem = LvRRC.SelectedItems(0)
		_axlDlog.TbAxleShare.Text = lv0.SubItems(AxleTbl.RelativeLoad).Text
		_axlDlog.CbTwinT.Checked = (lv0.SubItems(AxleTbl.TwinTyres).Text = "yes")
		_axlDlog.TbRRC.Text = lv0.SubItems(AxleTbl.RRC).Text
		_axlDlog.TbFzISO.Text = lv0.SubItems(AxleTbl.FzISO).Text
		_axlDlog.TbI_wheels.Text = lv0.SubItems(AxleTbl.Inertia).Text
		_axlDlog.CbWheels.Text = lv0.SubItems(AxleTbl.WheelsDimension).Text
		_axlDlog.cbAxleType.SelectedValue = lv0.SubItems(AxleTbl.AxleType).Text.ParseEnum(Of AxleType)()

		If _axlDlog.ShowDialog = DialogResult.OK Then
			lv0.SubItems(AxleTbl.RelativeLoad).Text = _axlDlog.TbAxleShare.Text
			If _axlDlog.CbTwinT.Checked Then
				lv0.SubItems(AxleTbl.TwinTyres).Text = "yes"
				lv0.SubItems(AxleTbl.TwinTyres).Text = "no"
			lv0.SubItems(AxleTbl.RRC).Text = _axlDlog.TbRRC.Text
			lv0.SubItems(AxleTbl.FzISO).Text = _axlDlog.TbFzISO.Text
			lv0.SubItems(AxleTbl.WheelsDimension).Text = _axlDlog.CbWheels.Text
			lv0.SubItems(AxleTbl.Inertia).Text = _axlDlog.TbI_wheels.Text
			lv0.SubItems(AxleTbl.AxleType).Text = CType(_axlDlog.cbAxleType.SelectedValue, AxleType).GetLabel()
			Change()
			DeclInit()
		End If
	End Sub

#End Region

#Region "Open File Context Menu"


	Private Sub OpenFiles(ParamArray files() As String)
		If files.Length = 0 Then Exit Sub

		_cmFiles = files
		OpenWithToolStripMenuItem.Text = "Open with " & Cfg.OpenCmdName
		CmOpenFile.Show(Cursor.Position)
	End Sub

	Private Sub OpenWithToolStripMenuItem_Click(sender As Object, e As EventArgs) _
		Handles OpenWithToolStripMenuItem.Click
		If Not FileOpenAlt(_cmFiles(0)) Then MsgBox("Failed to open file!")
	End Sub

	Private Sub ShowInFolderToolStripMenuItem_Click(sender As Object, e As EventArgs) _
		Handles ShowInFolderToolStripMenuItem.Click
		If File.Exists(_cmFiles(0)) Then
			Try
				Process.Start("explorer", "/select,""" & _cmFiles(0) & "")
			Catch ex As Exception
				MsgBox("Failed to open file!")
			End Try
		Else
			MsgBox("File not found!")
		End If
	End Sub

#End Region


#Region "Angular Gear"

	Private Sub cbAngledriveType_SelectedIndexChanged(sender As Object, e As EventArgs) _
		Handles cbAngledriveType.SelectedIndexChanged
		Select Case CType(cbAngledriveType.SelectedValue, AngledriveType)
			Case AngledriveType.SeparateAngledrive
				pnAngledriveFields.Enabled = True
				tbAngledriveRatio.Text = "1.0"
			Case Else 'Losses included in Transmission, None
				tbAngledriveRatio.Text = ""
				tbAngledriveLossMapPath.Text = ""
				pnAngledriveFields.Enabled = False
	Private Sub btAngledriveLossMapBrowse_Click(sender As Object, e As EventArgs) Handles btAngledriveLossMapBrowse.Click
		If TransmissionLossMapFileBrowser.OpenDialog(FileRepl(TbRtPath.Text, GetPath(_vehFile))) Then _
			tbAngledriveLossMapPath.Text = GetFilenameWithoutDirectory(TransmissionLossMapFileBrowser.Files(0),
	End Sub

#End Region

	Private Sub cbPTOType_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cbPTOType.SelectedIndexChanged

		If (cbPTOType.SelectedIndex = 0) Then
			pnPTO.Enabled = False
			tbPTOLossMap.Text = ""
		Else
			pnPTO.Enabled = True
		End If

		Change()
	End Sub

	Private Sub btPTOLossMapBrowse_Click(sender As Object, e As EventArgs) Handles btPTOLossMapBrowse.Click
		If PtoLossMapFileBrowser.OpenDialog(FileRepl(tbPTOLossMap.Text, GetPath(_vehFile))) Then
			tbPTOLossMap.Text = GetFilenameWithoutDirectory(PtoLossMapFileBrowser.Files(0), GetPath(_vehFile))
		End If
	End Sub

	Private Sub btPTOCycle_Click(sender As Object, e As EventArgs) Handles btPTOCycle.Click
		If PTODrivingCycleFileBrowser.OpenDialog(FileRepl(tbPTOCycle.Text, GetPath(_vehFile))) Then
			tbPTOCycle.Text = GetFilenameWithoutDirectory(PTODrivingCycleFileBrowser.Files(0), GetPath(_vehFile))

	Private Sub btAddMaxTorqueEntry_Click(sender As Object, e As EventArgs) Handles btAddMaxTorqueEntry.Click
		_torqueLimitDlog.Clear()
		If _torqueLimitDlog.ShowDialog() = DialogResult.OK Then
			Dim gear As Integer = _torqueLimitDlog.tbGear.Text.ToInt(0)
			For Each entry As ListViewItem In lvTorqueLimits.Items
				If entry.SubItems(TorqueLimitsTbl.Gear).Text.ToInt() = gear Then
					entry.SubItems(TorqueLimitsTbl.MaxTorque).Text = _torqueLimitDlog.tbMaxTorque.Text.ToDouble(0).ToGUIFormat
					Change()
					Return
				End If
			Next

			lvTorqueLimits.Items.Add(CreateMaxTorqueListViewItem(gear, _torqueLimitDlog.tbMaxTorque.Text.ToDouble(0)))

			Change()

		End If
	End Sub

	Private Function CreateMaxTorqueListViewItem(gear As Integer, maxTorque As Double) As ListViewItem
		Dim retVal As New ListViewItem
		retVal.SubItems(0).Text = gear.ToGUIFormat()
		retVal.SubItems.Add(maxTorque.ToGUIFormat())
		Return retVal
	End Function

	Private Sub btDelMaxTorqueEntry_Click(sender As Object, e As EventArgs) Handles btDelMaxTorqueEntry.Click
		RemoveMaxTorqueItem()
	End Sub

	Private Sub RemoveMaxTorqueItem()
		If lvTorqueLimits.SelectedItems.Count = 0 Then
			If lvTorqueLimits.Items.Count = 0 Then
				Exit Sub
			Else
				lvTorqueLimits.Items(lvTorqueLimits.Items.Count - 1).Selected = True
			End If
		End If

		lvTorqueLimits.SelectedItems(0).Remove()

		Change()
	End Sub

	Private Sub lvTorqueLimits_DoubleClick(sender As Object, e As EventArgs) Handles lvTorqueLimits.DoubleClick
		EditMaxTorqueEntry()
	End Sub

	Private Sub EditMaxTorqueEntry()
		If lvTorqueLimits.SelectedItems.Count = 0 Then Exit Sub

		Dim entry As ListViewItem = lvTorqueLimits.SelectedItems(0)
		_torqueLimitDlog.tbGear.Text = entry.SubItems(TorqueLimitsTbl.Gear).Text
		_torqueLimitDlog.tbGear.ReadOnly = True
		_torqueLimitDlog.tbMaxTorque.Text = entry.SubItems(TorqueLimitsTbl.MaxTorque).Text
		_torqueLimitDlog.tbMaxTorque.Focus()
		If (_torqueLimitDlog.ShowDialog() = DialogResult.OK) Then
			entry.SubItems(TorqueLimitsTbl.MaxTorque).Text = _torqueLimitDlog.tbMaxTorque.Text
		End If
		_torqueLimitDlog.tbGear.ReadOnly = False
	End Sub