diff --git a/Dat/FileParsing/LocoBinaryReader.cs b/Dat/FileParsing/LocoBinaryReader.cs index e3012996..ef3ed0dd 100644 --- a/Dat/FileParsing/LocoBinaryReader.cs +++ b/Dat/FileParsing/LocoBinaryReader.cs @@ -283,7 +283,6 @@ public EmitterAnimation[] ReadEmitterAnimations(int count) public FrictionSound ReadFrictionSound() => new() { - SoundObjectId = ReadByte(), MinSpeed = ReadInt32(), SpeedFreqFactor = ReadByte(), BaseFrequency = ReadUInt16(), @@ -295,7 +294,6 @@ public FrictionSound ReadFrictionSound() public SimpleMotorSound ReadSimpleMotorSound() => new() { - SoundObjectId = ReadByte(), IdleFrequency = ReadUInt16(), IdleVolume = ReadByte(), CoastingFrequency = ReadUInt16(), @@ -312,7 +310,6 @@ public SimpleMotorSound ReadSimpleMotorSound() public GearboxMotorSound ReadGearboxMotorSound() => new() { - SoundObjectId = ReadByte(), IdleFrequency = ReadUInt16(), IdleVolume = ReadByte(), FirstGearFrequency = ReadUInt16(), diff --git a/Dat/FileParsing/LocoBinaryWriter.cs b/Dat/FileParsing/LocoBinaryWriter.cs index ebdbb309..1c70e857 100644 --- a/Dat/FileParsing/LocoBinaryWriter.cs +++ b/Dat/FileParsing/LocoBinaryWriter.cs @@ -167,7 +167,6 @@ public void Write(EmitterAnimation[] animations) public void Write(FrictionSound sound) { - Write(sound.SoundObjectId); Write(sound.MinSpeed); Write(sound.SpeedFreqFactor); Write(sound.BaseFrequency); @@ -178,7 +177,6 @@ public void Write(FrictionSound sound) public void Write(SimpleMotorSound sound) { - Write(sound.SoundObjectId); Write(sound.IdleFrequency); Write(sound.IdleVolume); Write(sound.CoastingFrequency); @@ -194,7 +192,6 @@ public void Write(SimpleMotorSound sound) public void Write(GearboxMotorSound sound) { - Write(sound.SoundObjectId); Write(sound.IdleFrequency); Write(sound.IdleVolume); Write(sound.FirstGearFrequency); diff --git a/Dat/Loaders/Vehicle/VehicleObjectLoader.cs b/Dat/Loaders/Vehicle/VehicleObjectLoader.cs index 5f4bf213..bb7f797b 100644 --- a/Dat/Loaders/Vehicle/VehicleObjectLoader.cs +++ b/Dat/Loaders/Vehicle/VehicleObjectLoader.cs @@ -73,7 +73,7 @@ private static void LoadVariable(LocoBinaryReader br, VehicleObject model, byte // track type if (!model.Flags.HasFlag(VehicleObjectFlags.AnyRoadType) && (model.Mode == TransportMode.Rail || model.Mode == TransportMode.Road)) { - model.TrackType = br.ReadS5Header(); + model.RoadOrTrackType = br.ReadS5Header(); } // required track extra @@ -187,14 +187,17 @@ private static void LoadFixed(LocoBinaryReader br, VehicleObject model, out byte switch (model.DrivingSoundType) { case DrivingSoundType.Friction: + br.SkipByte(); // this is the object id which is the first byte of all of the sound union structs. it will be read from Sound property model.FrictionSound = br.ReadFrictionSound(); br.SkipByte(StructSizes.SoundData - StructSizes.FrictionSound); break; case DrivingSoundType.SimpleMotor: + br.SkipByte(); // this is the object id which is the first byte of all of the sound union structs. it will be read from Sound property model.SimpleMotorSound = br.ReadSimpleMotorSound(); br.SkipByte(StructSizes.SoundData - StructSizes.SimpleMotorSound); break; case DrivingSoundType.GearboxMotor: + br.SkipByte(); // this is the object id which is the first byte of all of the sound union structs. it will be read from Sound property model.GearboxMotorSound = br.ReadGearboxMotorSound(); br.SkipByte(StructSizes.SoundData - StructSizes.GearboxMotorSound); break; @@ -256,16 +259,19 @@ public static void Save(Stream stream, LocoObject obj) { case DrivingSoundType.Friction: ArgumentNullException.ThrowIfNull(model.FrictionSound); + bw.WriteEmptyBytes(1); // this is the object id which is the first byte of all of the sound union structs bw.Write(model.FrictionSound); bw.WriteEmptyBytes(StructSizes.SoundData - StructSizes.FrictionSound); break; case DrivingSoundType.SimpleMotor: ArgumentNullException.ThrowIfNull(model.SimpleMotorSound); + bw.WriteEmptyBytes(1); // this is the object id which is the first byte of all of the sound union structs bw.Write(model.SimpleMotorSound); bw.WriteEmptyBytes(StructSizes.SoundData - StructSizes.SimpleMotorSound); break; case DrivingSoundType.GearboxMotor: ArgumentNullException.ThrowIfNull(model.GearboxMotorSound); + bw.WriteEmptyBytes(1); // this is the object id which is the first byte of all of the sound union structs bw.Write(model.GearboxMotorSound); bw.WriteEmptyBytes(StructSizes.SoundData - StructSizes.GearboxMotorSound); break; @@ -299,7 +305,7 @@ private static void SaveVariable(VehicleObject model, LocoBinaryWriter bw) // track type if (!model.Flags.HasFlag(VehicleObjectFlags.AnyRoadType) && (model.Mode == TransportMode.Rail || model.Mode == TransportMode.Road)) { - bw.WriteS5Header(model.TrackType); + bw.WriteS5Header(model.RoadOrTrackType); } // track extras diff --git a/Definitions/ObjectModels/Objects/Vehicle/EmitterAnimation.cs b/Definitions/ObjectModels/Objects/Vehicle/EmitterAnimation.cs index fb604e13..39c051ee 100644 --- a/Definitions/ObjectModels/Objects/Vehicle/EmitterAnimation.cs +++ b/Definitions/ObjectModels/Objects/Vehicle/EmitterAnimation.cs @@ -7,7 +7,7 @@ namespace Definitions.ObjectModels.Objects.Vehicle; [TypeConverter(typeof(ExpandableObjectConverter))] public class EmitterAnimation : ILocoStruct { - public ObjectModelHeader AnimationObject { get; set; } // will be SteamObject + public ObjectModelHeader AnimationObject { get; set; } // will be SteamObject public uint8_t EmitterVerticalPos { get; set; } public SimpleAnimationType Type { get; set; } diff --git a/Definitions/ObjectModels/Objects/Vehicle/FrictionSound.cs b/Definitions/ObjectModels/Objects/Vehicle/FrictionSound.cs index 6586e3ac..1cb378f7 100644 --- a/Definitions/ObjectModels/Objects/Vehicle/FrictionSound.cs +++ b/Definitions/ObjectModels/Objects/Vehicle/FrictionSound.cs @@ -1,3 +1,4 @@ +using Definitions.ObjectModels.Types; using System.ComponentModel; namespace Definitions.ObjectModels.Objects.Vehicle; @@ -5,7 +6,7 @@ namespace Definitions.ObjectModels.Objects.Vehicle; [TypeConverter(typeof(ExpandableObjectConverter))] public class FrictionSound { - public uint8_t SoundObjectId { get; set; } + public ObjectModelHeader SoundObject { get; set; } public int32_t MinSpeed { get; set; } public uint8_t SpeedFreqFactor { get; set; } public uint16_t BaseFrequency { get; set; } diff --git a/Definitions/ObjectModels/Objects/Vehicle/GearboxMotorSound.cs b/Definitions/ObjectModels/Objects/Vehicle/GearboxMotorSound.cs index 6876c950..55c72409 100644 --- a/Definitions/ObjectModels/Objects/Vehicle/GearboxMotorSound.cs +++ b/Definitions/ObjectModels/Objects/Vehicle/GearboxMotorSound.cs @@ -1,3 +1,4 @@ +using Definitions.ObjectModels.Types; using System.ComponentModel; namespace Definitions.ObjectModels.Objects.Vehicle; @@ -5,7 +6,7 @@ namespace Definitions.ObjectModels.Objects.Vehicle; [TypeConverter(typeof(ExpandableObjectConverter))] public class GearboxMotorSound { - public uint8_t SoundObjectId { get; set; } + public ObjectModelHeader SoundObject { get; set; } public uint16_t IdleFrequency { get; set; } public uint8_t IdleVolume { get; set; } public uint16_t FirstGearFrequency { get; set; } // All subsequent gears are based on this frequency diff --git a/Definitions/ObjectModels/Objects/Vehicle/SimpleMotorSound.cs b/Definitions/ObjectModels/Objects/Vehicle/SimpleMotorSound.cs index 867afa39..7e438189 100644 --- a/Definitions/ObjectModels/Objects/Vehicle/SimpleMotorSound.cs +++ b/Definitions/ObjectModels/Objects/Vehicle/SimpleMotorSound.cs @@ -1,3 +1,4 @@ +using Definitions.ObjectModels.Types; using System.ComponentModel; namespace Definitions.ObjectModels.Objects.Vehicle; @@ -5,7 +6,7 @@ namespace Definitions.ObjectModels.Objects.Vehicle; [TypeConverter(typeof(ExpandableObjectConverter))] public class SimpleMotorSound { - public uint8_t SoundObjectId { get; set; } + public ObjectModelHeader SoundObject { get; set; } public uint16_t IdleFrequency { get; set; } public uint8_t IdleVolume { get; set; } public uint16_t CoastingFrequency { get; set; } diff --git a/Definitions/ObjectModels/Objects/Vehicle/VehicleObject.cs b/Definitions/ObjectModels/Objects/Vehicle/VehicleObject.cs index 28146626..ea29946e 100644 --- a/Definitions/ObjectModels/Objects/Vehicle/VehicleObject.cs +++ b/Definitions/ObjectModels/Objects/Vehicle/VehicleObject.cs @@ -9,7 +9,7 @@ public class VehicleObject : ILocoStruct public TransportMode Mode { get; set; } public VehicleType Type { get; set; } public uint8_t NumCarComponents { get; set; } - public ObjectModelHeader? TrackType { get; set; } + public ObjectModelHeader? RoadOrTrackType { get; set; } public object_id TrackTypeId { get; set; } public uint8_t CostIndex { get; set; } public int16_t CostFactor { get; set; } diff --git a/Definitions/ObjectModels/ColourSwatch.cs b/Definitions/ObjectModels/Types/ColourSwatch.cs similarity index 85% rename from Definitions/ObjectModels/ColourSwatch.cs rename to Definitions/ObjectModels/Types/ColourSwatch.cs index 0bc31010..5c59176e 100644 --- a/Definitions/ObjectModels/ColourSwatch.cs +++ b/Definitions/ObjectModels/Types/ColourSwatch.cs @@ -1,4 +1,4 @@ -namespace Definitions.ObjectModels; +namespace Definitions.ObjectModels.Types; public enum ColourSwatch { diff --git a/Definitions/ObjectModels/Types/ObjectModelHeader.cs b/Definitions/ObjectModels/Types/ObjectModelHeader.cs index d6a9148d..d9fa0292 100644 --- a/Definitions/ObjectModels/Types/ObjectModelHeader.cs +++ b/Definitions/ObjectModels/Types/ObjectModelHeader.cs @@ -6,6 +6,10 @@ namespace Definitions.ObjectModels.Types; [TypeConverter(typeof(ExpandableObjectConverter))] public class ObjectModelHeader(string name, ObjectType objectType, ObjectSource objectSource, uint datchecksum) : ILocoStruct { + public ObjectModelHeader() + : this(string.Empty, ObjectType.Airport, ObjectSource.Custom, 0) + { } + public string Name { get; set; } = name; public ObjectType ObjectType { get; set; } = objectType; public ObjectSource ObjectSource { get; set; } = objectSource; diff --git a/Definitions/ObjectModels/Types/Pos.cs b/Definitions/ObjectModels/Types/Pos.cs index bdc04946..1f098171 100644 --- a/Definitions/ObjectModels/Types/Pos.cs +++ b/Definitions/ObjectModels/Types/Pos.cs @@ -8,7 +8,7 @@ public class Pos2 public coord_t X { get; set; } public coord_t Y { get; set; } - public static Pos2 Zero => new Pos2 { X = 0, Y = 0 }; + public static Pos2 Zero => new() { X = 0, Y = 0 }; } [TypeConverter(typeof(ExpandableObjectConverter))] @@ -18,5 +18,5 @@ public class Pos3 public coord_t Y { get; set; } public coord_t Z { get; set; } - public static Pos3 Zero => new Pos3 { X = 0, Y = 0, Z = 0 }; + public static Pos3 Zero => new() { X = 0, Y = 0, Z = 0 }; } diff --git a/Gui/App.axaml b/Gui/App.axaml index 45a17c64..29d2584c 100644 --- a/Gui/App.axaml +++ b/Gui/App.axaml @@ -18,6 +18,8 @@ + + - + + @@ -109,7 +118,7 @@ - + diff --git a/Gui/Gui.csproj b/Gui/Gui.csproj index 69b63b17..b06e9855 100644 --- a/Gui/Gui.csproj +++ b/Gui/Gui.csproj @@ -81,5 +81,9 @@ ObjectEditorView.axaml + + Pos3View.axaml + Code + diff --git a/Gui/ViewModels/Graphics/ColourRemapSwatchViewModel.cs b/Gui/ViewModels/Graphics/ColourRemapSwatchViewModel.cs index 0e5477e8..36648ade 100644 --- a/Gui/ViewModels/Graphics/ColourRemapSwatchViewModel.cs +++ b/Gui/ViewModels/Graphics/ColourRemapSwatchViewModel.cs @@ -1,4 +1,4 @@ -using Definitions.ObjectModels; +using Definitions.ObjectModels.Types; using ReactiveUI.Fody.Helpers; using AvaColour = Avalonia.Media.Color; diff --git a/Gui/ViewModels/LocoTypes/Objects/AirportViewModel.cs b/Gui/ViewModels/LocoTypes/Objects/AirportViewModel.cs index 307426df..2e0d49db 100644 --- a/Gui/ViewModels/LocoTypes/Objects/AirportViewModel.cs +++ b/Gui/ViewModels/LocoTypes/Objects/AirportViewModel.cs @@ -80,13 +80,16 @@ public int16_t SellCostFactor set => Model.SellCostFactor = value; } - [Category("Building"), Length(1, AirportObjectLoader.Constants.BuildingVariationCount)] + [Category("Building")] + [Length(1, AirportObjectLoader.Constants.BuildingVariationCount)] public BindingList> BuildingVariations { get; init; } = new(model.BuildingComponents.BuildingVariations.Select(x => x.ToBindingList()).ToBindingList()); - [Category("Building"), Length(1, AirportObjectLoader.Constants.BuildingHeightCount)] + [Category("Building")] + [Length(1, AirportObjectLoader.Constants.BuildingHeightCount)] public BindingList BuildingHeights { get; init; } = model.BuildingComponents.BuildingHeights.ToBindingList(); - [Category("Building"), Length(1, AirportObjectLoader.Constants.BuildingAnimationCount)] + [Category("Building")] + [Length(1, AirportObjectLoader.Constants.BuildingAnimationCount)] public BindingList BuildingAnimations { get; init; } = model.BuildingComponents.BuildingAnimations.ToBindingList(); [Category("Building")] @@ -111,16 +114,4 @@ public uint32_t var_B6 get => Model.var_B6; set => Model.var_B6 = value; } - - //public AirportViewModel(AirportObject model) - // : base(model) - //{ - // BuildingHeights = new(model.BuildingComponents.BuildingHeights); - // BuildingAnimations = new(model.BuildingComponents.BuildingAnimations); - // BuildingVariations = new(model.BuildingComponents.BuildingVariations.Select(x => new BindingList(x))); - // BuildingPositions = new(model.BuildingPositions); - // MovementNodes = new(model.MovementNodes); - // MovementEdges = new(model.MovementEdges); - // var_B6 = new BindingList(model.var_B6); - //} } diff --git a/Gui/ViewModels/LocoTypes/Objects/BridgeViewModel.cs b/Gui/ViewModels/LocoTypes/Objects/BridgeViewModel.cs index 897dca15..5a860eab 100644 --- a/Gui/ViewModels/LocoTypes/Objects/BridgeViewModel.cs +++ b/Gui/ViewModels/LocoTypes/Objects/BridgeViewModel.cs @@ -92,9 +92,11 @@ public int16_t SellCostFactor set => Model.SellCostFactor = value; } - [Category("Compatible")] public BindingList CompatibleTrackObjects { get; init; } = new(model.CompatibleTrackObjects); + [Category("Compatible")] + public BindingList CompatibleTrackObjects { get; init; } = new(model.CompatibleTrackObjects); - [Category("Compatible")] public BindingList CompatibleRoadObjects { get; init; } = new(model.CompatibleRoadObjects); + [Category("Compatible")] + public BindingList CompatibleRoadObjects { get; init; } = new(model.CompatibleRoadObjects); [Category("")] public uint8_t var_03 diff --git a/Gui/ViewModels/LocoTypes/Objects/DockViewModel.cs b/Gui/ViewModels/LocoTypes/Objects/DockViewModel.cs index f8b187f0..9671277a 100644 --- a/Gui/ViewModels/LocoTypes/Objects/DockViewModel.cs +++ b/Gui/ViewModels/LocoTypes/Objects/DockViewModel.cs @@ -59,13 +59,16 @@ public int16_t SellCostFactor set => Model.SellCostFactor = value; } - [Category("Building"), Length(1, DockObjectLoader.Constants.BuildingVariationCount)] + [Category("Building")] + [Length(1, DockObjectLoader.Constants.BuildingVariationCount)] public BindingList> BuildingVariations { get; init; } = new(model.BuildingComponents.BuildingVariations.Select(x => x.ToBindingList()).ToBindingList()); - [Category("Building"), Length(1, DockObjectLoader.Constants.BuildingHeightCount)] + [Category("Building")] + [Length(1, DockObjectLoader.Constants.BuildingHeightCount)] public BindingList BuildingHeights { get; init; } = model.BuildingComponents.BuildingHeights.ToBindingList(); - [Category("Building"), Length(1, DockObjectLoader.Constants.BuildingAnimationCount)] + [Category("Building")] + [Length(1, DockObjectLoader.Constants.BuildingAnimationCount)] public BindingList BuildingAnimations { get; init; } = model.BuildingComponents.BuildingAnimations.ToBindingList(); [Category("")] diff --git a/Gui/ViewModels/LocoTypes/Objects/IndustryViewModel.cs b/Gui/ViewModels/LocoTypes/Objects/IndustryViewModel.cs index 50344a15..141b3ab5 100644 --- a/Gui/ViewModels/LocoTypes/Objects/IndustryViewModel.cs +++ b/Gui/ViewModels/LocoTypes/Objects/IndustryViewModel.cs @@ -56,10 +56,12 @@ public uint32_t Colours [Category("Production")] public BindingList InitialProductionRate { get; init; } = new(model.InitialProductionRate); - [Category("Production"), Length(0, IndustryObjectLoader.Constants.MaxProducedCargoType)] + [Category("Production")] + [Length(0, IndustryObjectLoader.Constants.MaxProducedCargoType)] public BindingList ProducedCargo { get; init; } = new(model.ProducedCargo); - [Category("Production"), Length(0, IndustryObjectLoader.Constants.MaxProducedCargoType)] + [Category("Production")] + [Length(0, IndustryObjectLoader.Constants.MaxProducedCargoType)] public BindingList RequiredCargo { get; init; } = new(model.RequiredCargo); [Category("Production")] @@ -118,16 +120,20 @@ public uint8_t FarmNumStagesOfGrowth set => Model.FarmNumStagesOfGrowth = value; } - [Category("Building"), Length(IndustryObjectLoader.Constants.AnimationSequencesCount, IndustryObjectLoader.Constants.AnimationSequencesCount)] + [Category("Building")] + [Length(IndustryObjectLoader.Constants.AnimationSequencesCount, IndustryObjectLoader.Constants.AnimationSequencesCount)] public BindingList> AnimationSequences { get; init; } = model.AnimationSequences.Select(x => x.ToBindingList()).ToBindingList(); - [Category("Building"), Length(1, IndustryObjectLoader.Constants.BuildingVariationCount)] + [Category("Building")] + [Length(1, IndustryObjectLoader.Constants.BuildingVariationCount)] public BindingList> BuildingVariations { get; init; } = new(model.BuildingComponents.BuildingVariations.Select(x => x.ToBindingList()).ToBindingList()); - [Category("Building"), Length(1, IndustryObjectLoader.Constants.BuildingHeightCount)] + [Category("Building")] + [Length(1, IndustryObjectLoader.Constants.BuildingHeightCount)] public BindingList BuildingHeights { get; init; } = model.BuildingComponents.BuildingHeights.ToBindingList(); - [Category("Building"), Length(1, IndustryObjectLoader.Constants.BuildingAnimationCount)] + [Category("Building")] + [Length(1, IndustryObjectLoader.Constants.BuildingAnimationCount)] public BindingList BuildingAnimations { get; init; } = model.BuildingComponents.BuildingAnimations.ToBindingList(); [Category("Building")] @@ -168,7 +174,8 @@ public Colour ScaffoldingColour set => Model.ScaffoldingColour = value; } - [Category("Building"), Length(0, IndustryObjectLoader.Constants.MaxWallTypeCount)] + [Category("Building")] + [Length(0, IndustryObjectLoader.Constants.MaxWallTypeCount)] public BindingList WallTypes { get; init; } = model.WallTypes.ToBindingList(); [Category("Building")] diff --git a/Gui/ViewModels/LocoTypes/Objects/RegionViewModel.cs b/Gui/ViewModels/LocoTypes/Objects/RegionViewModel.cs index 69ceeb64..dbc29001 100644 --- a/Gui/ViewModels/LocoTypes/Objects/RegionViewModel.cs +++ b/Gui/ViewModels/LocoTypes/Objects/RegionViewModel.cs @@ -19,9 +19,11 @@ public uint8_t pad_07 set => Model.pad_07 = value; } - [Category("Cargo")] public BindingList CargoInfluenceObjects { get; init; } = new(model.CargoInfluenceObjects); public BindingList DependentObjects { get; init; } = new(model.DependentObjects); + [Category("Cargo")] + public BindingList CargoInfluenceObjects { get; init; } = new(model.CargoInfluenceObjects); + [Category("Cargo")] public BindingList CargoInfluenceTownFilter { get; init; } = new(model.CargoInfluenceTownFilter); } diff --git a/Gui/ViewModels/LocoTypes/Objects/RoadViewModel.cs b/Gui/ViewModels/LocoTypes/Objects/RoadViewModel.cs index 320518ff..517a5b9c 100644 --- a/Gui/ViewModels/LocoTypes/Objects/RoadViewModel.cs +++ b/Gui/ViewModels/LocoTypes/Objects/RoadViewModel.cs @@ -81,8 +81,15 @@ public ObjectModelHeader Tunnel set => Model.Tunnel = value; } - [Category("Compatible Objects")] public BindingList Bridges { get; set; } = new(model.Bridges); - [Category("Compatible Objects")] public BindingList Stations { get; set; } = new(model.Stations); - [Category("Compatible Objects")] public BindingList Mods { get; set; } = new(model.RoadMods); - [Category("Compatible Objects")] public BindingList TracksAndRoads { get; set; } = new(model.TracksAndRoads); + [Category("Compatible Objects")] + public BindingList Bridges { get; set; } = new(model.Bridges); + + [Category("Compatible Objects")] + public BindingList Stations { get; set; } = new(model.Stations); + + [Category("Compatible Objects")] + public BindingList Mods { get; set; } = new(model.RoadMods); + + [Category("Compatible Objects")] + public BindingList TracksAndRoads { get; set; } = new(model.TracksAndRoads); } diff --git a/Gui/ViewModels/LocoTypes/Objects/TownNamesViewModel.cs b/Gui/ViewModels/LocoTypes/Objects/TownNamesViewModel.cs index 76894ee4..0f72c819 100644 --- a/Gui/ViewModels/LocoTypes/Objects/TownNamesViewModel.cs +++ b/Gui/ViewModels/LocoTypes/Objects/TownNamesViewModel.cs @@ -8,7 +8,8 @@ namespace Gui.ViewModels; public class TownNamesViewModel(TownNamesObject model) : LocoObjectViewModel(model) { - [Length(6, 6), Editable(false)] + [Length(6, 6)] + [Editable(false)] public BindingList Categories { get; set; } = model.Categories.ToBindingList(); } diff --git a/Gui/ViewModels/LocoTypes/Objects/TrackStationViewModel.cs b/Gui/ViewModels/LocoTypes/Objects/TrackStationViewModel.cs index adf4aa23..94104e04 100644 --- a/Gui/ViewModels/LocoTypes/Objects/TrackStationViewModel.cs +++ b/Gui/ViewModels/LocoTypes/Objects/TrackStationViewModel.cs @@ -7,9 +7,9 @@ namespace Gui.ViewModels; -public class TrackStationViewModel(TrackStationObject model) : LocoObjectViewModel(model) +public class TrackStationViewModel(TrackStationObject model) + : LocoObjectViewModel(model) { - public uint8_t PaintStyle { get => Model.PaintStyle; diff --git a/Gui/ViewModels/LocoTypes/Objects/TrackViewModel.cs b/Gui/ViewModels/LocoTypes/Objects/TrackViewModel.cs index f6d8fdf1..f44f32e1 100644 --- a/Gui/ViewModels/LocoTypes/Objects/TrackViewModel.cs +++ b/Gui/ViewModels/LocoTypes/Objects/TrackViewModel.cs @@ -84,9 +84,18 @@ public ObjectModelHeader Tunnel set => Model.Tunnel = value; } - [Category("Compatible Objects")] public BindingList TracksAndRoads { get; init; } = new(model.TracksAndRoads); - [Category("Compatible Objects")] public BindingList TrackExtras { get; init; } = new(model.TrackMods); - [Category("Compatible Objects")] public BindingList Signals { get; init; } = new(model.Signals); - [Category("Compatible Objects")] public BindingList Bridges { get; init; } = new(model.Bridges); - [Category("Compatible Objects")] public BindingList Stations { get; init; } = new(model.Stations); + [Category("Compatible Objects")] + public BindingList TracksAndRoads { get; init; } = new(model.TracksAndRoads); + + [Category("Compatible Objects")] + public BindingList TrackExtras { get; init; } = new(model.TrackMods); + + [Category("Compatible Objects")] + public BindingList Signals { get; init; } = new(model.Signals); + + [Category("Compatible Objects")] + public BindingList Bridges { get; init; } = new(model.Bridges); + + [Category("Compatible Objects")] + public BindingList Stations { get; init; } = new(model.Stations); } diff --git a/Gui/ViewModels/LocoTypes/Objects/VehicleViewModel.cs b/Gui/ViewModels/LocoTypes/Objects/VehicleViewModel.cs index 678930ea..08185998 100644 --- a/Gui/ViewModels/LocoTypes/Objects/VehicleViewModel.cs +++ b/Gui/ViewModels/LocoTypes/Objects/VehicleViewModel.cs @@ -2,6 +2,8 @@ using Definitions.ObjectModels.Objects.Cargo; using Definitions.ObjectModels.Objects.Vehicle; using Definitions.ObjectModels.Types; +using DynamicData.Binding; +using PropertyModels.ComponentModel; using PropertyModels.ComponentModel.DataAnnotations; using ReactiveUI; using ReactiveUI.Fody.Helpers; @@ -30,16 +32,59 @@ public VehicleViewModel(VehicleObject model) : base(model) CargoTypeSpriteOffsets = new([.. model.CargoTypeSpriteOffsets.Select(x => new CargoTypeSpriteOffset(x.Key, x.Value))]); StartSounds = new(model.StartSounds); var_135 = new(model.var_135); - TrackType = model.TrackType; + RoadOrTrackType = model.RoadOrTrackType; RackRail = model.RackRail; HasRackRail = model.Flags.HasFlag(VehicleObjectFlags.RackRail); + SimpleMotorSound = model.SimpleMotorSound ?? new SimpleMotorSound(); + FrictionSound = model.FrictionSound ?? new FrictionSound(); + GearboxMotorSound = model.GearboxMotorSound ?? new GearboxMotorSound(); + Sound = model.Sound; + + _ = this.WhenAnyValue(x => x.RackRail) + .Subscribe((_) => model.RackRail = RackRail); + + #region Road/Track Type Binding + _ = this.WhenAnyValue(x => x.Mode, x => x.Flags) .Subscribe((_) => this.RaisePropertyChanged(nameof(IsTrackTypeSettable))); _ = this.WhenAnyValue(x => x.IsTrackTypeSettable) - .Subscribe((_) => this.RaisePropertyChanged(nameof(TrackType))); + .Subscribe((_) => this.RaisePropertyChanged(nameof(RoadOrTrackType))); + + _ = this.WhenAnyValue(x => x.RoadOrTrackType) + .Subscribe((_) => model.RoadOrTrackType = RoadOrTrackType); + + #endregion + + #region Sound Properties Binding + _ = this.WhenAnyValue(x => x.DrivingSoundType) + .Subscribe((_) => + { + this.RaisePropertyChanged(nameof(SimpleMotorSound)); + this.RaisePropertyChanged(nameof(FrictionSound)); + this.RaisePropertyChanged(nameof(GearboxMotorSound)); + }); + + _ = this.WhenAnyValue(x => x.Sound) + .Subscribe((_) => model.Sound = Sound); + + _ = this.WhenAnyValue(x => x.SimpleMotorSound) + .Subscribe((_) => model.SimpleMotorSound = SimpleMotorSound); + _ = this.WhenAnyValue(x => x.FrictionSound) + .Subscribe((_) => model.FrictionSound = FrictionSound); + _ = this.WhenAnyValue(x => x.GearboxMotorSound) + .Subscribe((_) => model.GearboxMotorSound = GearboxMotorSound); + + _ = this.WhenPropertyChanged(x => x.SimpleMotorSound) + .Subscribe((_) => model.SimpleMotorSound = SimpleMotorSound); + _ = this.WhenPropertyChanged(x => x.FrictionSound) + .Subscribe((_) => model.FrictionSound = FrictionSound); + _ = this.WhenPropertyChanged(x => x.GearboxMotorSound) + .Subscribe((_) => model.GearboxMotorSound = GearboxMotorSound); + + #endregion } [Category("Stats")] @@ -116,12 +161,16 @@ public VehicleObjectFlags Flags } } + [Browsable(false)] bool IsTrackTypeSettable - => (!model.Flags.HasFlag(VehicleObjectFlags.AnyRoadType) && (model.Mode == TransportMode.Rail || model.Mode == TransportMode.Road)); + => !model.Flags.HasFlag(VehicleObjectFlags.AnyRoadType) && (model.Mode == TransportMode.Rail || model.Mode == TransportMode.Road); - [Reactive, ConditionTarget, PropertyVisibilityCondition(nameof(IsTrackTypeSettable), true)] - public ObjectModelHeader? TrackType { get; set; } + [Reactive] + [ConditionTarget] + [PropertyVisibilityCondition(nameof(IsTrackTypeSettable), true)] + public ObjectModelHeader? RoadOrTrackType { get; set; } + [ConditionTarget] public bool HasRackRail { get => model.Flags.HasFlag(VehicleObjectFlags.RackRail); @@ -134,7 +183,9 @@ public bool HasRackRail } } - [Reactive, ConditionTarget, PropertyVisibilityCondition(nameof(HasRackRail), true)] + [Reactive] + [ConditionTarget] + [PropertyVisibilityCondition(nameof(HasRackRail), true)] public ObjectModelHeader? RackRail { get; set; } [Range(0, 4)] @@ -157,28 +208,32 @@ public uint8_t ShipWakeSpacing set => model.ShipWakeSpacing = value; } - [Category("Cost"), Range(0, 32)] + [Category("Cost")] + [Range(0, 32)] public uint8_t CostIndex { get => model.CostIndex; set => model.CostIndex = value; } - [Category("Cost"), Range(1, int16_t.MaxValue)] + [Category("Cost")] + [Range(1, int16_t.MaxValue)] public int16_t CostFactor { get => model.CostFactor; set => model.CostFactor = value; } - [Category("Cost"), Range(0, 32)] + [Category("Cost")] + [Range(0, 32)] public uint8_t RunCostIndex { get => model.RunCostIndex; set => model.RunCostIndex = value; } - [Category("Cost"), Range(0, int16_t.MaxValue)] + [Category("Cost")] + [Range(0, int16_t.MaxValue)] public int16_t RunCostFactor { get => model.RunCostFactor; @@ -192,10 +247,17 @@ public CompanyColourType SpecialColourSchemeIndex set => model.CompanyColourSchemeIndex = value; } // called "ColourType" in the loco codebase - [Category("Sprites"), Editable(false)] public BindingList CarComponents { get; init; } - [Category("Sprites"), Editable(false)] public BindingList BodySprites { get; init; } - [Category("Sprites"), Editable(false)] public BindingList BogieSprites { get; init; } - [Category("Sprites"), Editable(false)] public BindingList Animation { get; init; } + [Category("Sprites")] + public BindingList CarComponents { get; init; } + + [Category("Sprites")] + public BindingList BodySprites { get; init; } + + [Category("Sprites")] + public BindingList BogieSprites { get; init; } + + [Category("Sprites")] + public BindingList Animation { get; init; } [Category("Cargo")] public CompatibleCargo CompatibleCargo1 { get; init; } @@ -203,43 +265,46 @@ public CompanyColourType SpecialColourSchemeIndex [Category("Cargo")] public CompatibleCargo CompatibleCargo2 { get; init; } - [Category("Cargo"), Length(0, 32), Description("This is a dictionary. For every cargo defined in both CompatibleCargoCategories, an entry must exist in this dictionary.")] + [Category("Cargo")] + [Length(0, 32)] + [Description("This is a dictionary. For every cargo defined in both CompatibleCargoCategories, an entry must exist in this dictionary.")] public BindingList CargoTypeSpriteOffsets { get; init; } [Category("Sound")] - public ObjectModelHeader? Sound - { - get => model.Sound; - set => model.Sound = value; - } - - [Category("Sound")] + [ConditionTarget] public DrivingSoundType DrivingSoundType { get => model.DrivingSoundType; - set => model.DrivingSoundType = value; + set + { + model.DrivingSoundType = value; + this.RaisePropertyChanged(nameof(DrivingSoundType)); + } } + [Browsable(false)] + [DependsOnProperty(nameof(DrivingSoundType))] + [ConditionTarget] + bool IsDrivingSoundTypeSet + => model.DrivingSoundType != DrivingSoundType.None; + [Category("Sound")] - public FrictionSound? FrictionSound - { - get => model.FrictionSound; - set => model.FrictionSound = value; - } + [Reactive] + [PropertyVisibilityCondition(nameof(IsDrivingSoundTypeSet), true)] + public ObjectModelHeader? Sound { get; set; } [Category("Sound")] - public SimpleMotorSound? SimpleMotorSound - { - get => model.SimpleMotorSound; - set => model.SimpleMotorSound = value; - } + [PropertyVisibilityCondition(nameof(DrivingSoundType), DrivingSoundType.Friction)] + public FrictionSound FrictionSound { get; set; } [Category("Sound")] - public GearboxMotorSound? GearboxMotorSound - { - get => model.GearboxMotorSound; - set => model.GearboxMotorSound = value; - } + [PropertyVisibilityCondition(nameof(DrivingSoundType), DrivingSoundType.SimpleMotor)] + public SimpleMotorSound SimpleMotorSound { get; set; } + + [Category("Sound")] + [ConditionTarget] + [PropertyVisibilityCondition(nameof(DrivingSoundType), DrivingSoundType.GearboxMotor)] + public GearboxMotorSound GearboxMotorSound { get; set; } [Category("Sound")] public BindingList StartSounds { get; init; } @@ -249,6 +314,7 @@ public GearboxMotorSound? GearboxMotorSound public override void CopyBackToModel() { + // this should be done with the reactive properties, but for now we'll leave it like this Model.MaxCargo = [CompatibleCargo1.MaxCargo, CompatibleCargo2.MaxCargo]; Model.CompatibleCargoCategories = [ diff --git a/Gui/ViewModels/Pos3ViewModel.cs b/Gui/ViewModels/Pos3ViewModel.cs new file mode 100644 index 00000000..a994b5d9 --- /dev/null +++ b/Gui/ViewModels/Pos3ViewModel.cs @@ -0,0 +1,27 @@ +using Definitions.ObjectModels.Types; +using PropertyModels.ComponentModel; + +namespace Gui.ViewModels; + +public class Pos3ViewModel : MiniReactiveObject +{ + public Pos3 Pos; + + public coord_t X + { + get => Pos.X; + set => Pos.X = value; + } + + public coord_t Y + { + get => Pos.Y; + set => Pos.Y = value; + } + + public coord_t Z + { + get => Pos.Z; + set => Pos.Z = value; + } +} diff --git a/Gui/Views/ExtendedPropertyGrid.cs b/Gui/Views/ExtendedPropertyGrid.cs new file mode 100644 index 00000000..10a12f8f --- /dev/null +++ b/Gui/Views/ExtendedPropertyGrid.cs @@ -0,0 +1,63 @@ +using Avalonia.Controls; +using Avalonia.PropertyGrid.Controls; +using Avalonia.PropertyGrid.Controls.Factories; +using Definitions.ObjectModels.Types; +using Gui.ViewModels; + +namespace Gui.Views; + +public class ExtendedPropertyGrid : PropertyGrid +{ + public ExtendedPropertyGrid() + { + Factories.AddFactory(new Pos3CellEditFactory()); + } +} + +internal class Pos3CellEditFactory : AbstractCellEditFactory +{ + public override bool Accept(object accessToken) => accessToken is ExtendedPropertyGrid; + + public override Control? HandleNewProperty(PropertyCellContext context) + { + var propertyDescriptor = context.Property; + _ = context.Target; + + if (propertyDescriptor.PropertyType != typeof(Pos3)) + { + return null; + } + + var control = new Pos3View(); + + return control; + } + + public override bool HandlePropertyChanged(PropertyCellContext context) + { + var propertyDescriptor = context.Property; + var target = context.Target; + var control = context.CellEdit!; + + if (propertyDescriptor.PropertyType != typeof(Pos3)) + { + return false; + } + + ValidateProperty(control, propertyDescriptor, target); + + if (control is Pos3View vv) + { + var pos = (Pos3)propertyDescriptor.GetValue(target)!; + + var model = new Pos3ViewModel { Pos = pos }; + vv.DataContext = model; + + model.PropertyChanged += (s, e) => SetAndRaise(context, control, model.Pos); + + return true; + } + + return false; + } +} diff --git a/Gui/Views/ImageView.axaml b/Gui/Views/ImageView.axaml index f67379ba..74fce643 100644 --- a/Gui/Views/ImageView.axaml +++ b/Gui/Views/ImageView.axaml @@ -5,7 +5,7 @@ xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" xmlns:vmg="using:Gui.ViewModels.Graphics" xmlns:materialIcons="clr-namespace:Material.Icons.Avalonia;assembly=Material.Icons.Avalonia" - xmlns:pgc="clr-namespace:Avalonia.PropertyGrid.Controls;assembly=Avalonia.PropertyGrid" + xmlns:pgc="clr-namespace:Avalonia.PropertyGrid.Controls;assembly=Avalonia.PropertyGrid" xmlns:amxc="using:Avalonia.Markup.Xaml.Converters" xmlns:gmc="using:Gui.Models.Converters" mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450" @@ -15,7 +15,7 @@ - + diff --git a/Gui/Views/Pos3View.axaml b/Gui/Views/Pos3View.axaml new file mode 100644 index 00000000..f4772b4a --- /dev/null +++ b/Gui/Views/Pos3View.axaml @@ -0,0 +1,34 @@ + + + + + + + diff --git a/Gui/Views/Pos3View.cs b/Gui/Views/Pos3View.cs new file mode 100644 index 00000000..da46ea30 --- /dev/null +++ b/Gui/Views/Pos3View.cs @@ -0,0 +1,5 @@ +using Avalonia.Controls.Primitives; + +namespace Gui.Views; + +public class Pos3View : TemplatedControl; diff --git a/Tests/IdempotenceTests.cs b/Tests/IdempotenceTests.cs index 3001878a..ffbeeade 100644 --- a/Tests/IdempotenceTests.cs +++ b/Tests/IdempotenceTests.cs @@ -1,6 +1,7 @@ using Dat.Converters; using Dat.FileParsing; using Definitions.ObjectModels; +using Definitions.ObjectModels.Types; using Gui.ViewModels; using NUnit.Framework; using NUnit.Framework.Internal; diff --git a/Tests/ImagePaletteConversionTests.cs b/Tests/ImagePaletteConversionTests.cs index b0c38a6d..5fdd8e08 100644 --- a/Tests/ImagePaletteConversionTests.cs +++ b/Tests/ImagePaletteConversionTests.cs @@ -4,6 +4,7 @@ using SixLabors.ImageSharp; using SixLabors.ImageSharp.PixelFormats; using Definitions.ObjectModels; +using Definitions.ObjectModels.Types; namespace Dat.Tests;