Skip to content

Commit 46bc0c8

Browse files
authored
feat: gui2 profile import (#200)
1 parent c2f9c49 commit 46bc0c8

File tree

11 files changed

+778
-9
lines changed

11 files changed

+778
-9
lines changed
Lines changed: 42 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,42 @@
1+
using System;
2+
using System.Globalization;
3+
using Avalonia;
4+
using Avalonia.Data.Converters;
5+
using Avalonia.Media;
6+
7+
namespace EDSEditorGUI2.Converter;
8+
9+
public sealed class BrushConverter : IValueConverter
10+
{
11+
public object Convert(object? value, Type targetType, object? parameter, CultureInfo culture)
12+
{
13+
// TODO: Get theme and use the correct brush based on that
14+
if (value is Boolean bValue)
15+
{
16+
if (bValue)
17+
{
18+
return new SolidColorBrush(Colors.Red);
19+
}
20+
else
21+
{
22+
var currentThemeVariant = Application.Current?.ActualThemeVariant;
23+
24+
// TODO: figure out how to get the default forground from theme instead of hardcoding it
25+
if (currentThemeVariant == Avalonia.Styling.ThemeVariant.Dark)
26+
{
27+
return new SolidColorBrush(Colors.White);
28+
}
29+
else
30+
{
31+
return new SolidColorBrush(Colors.Black);
32+
}
33+
}
34+
}
35+
return new SolidColorBrush(Colors.Orange);
36+
}
37+
38+
public object ConvertBack(object? value, Type targetType, object? parameter, CultureInfo culture)
39+
{
40+
throw new NotImplementedException();
41+
}
42+
}

EDSEditorGUI2/EDSEditorGUI2.csproj

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,17 @@
1414
<ProjectReference Include="..\libEDSsharp\libEDSsharp.csproj" />
1515
</ItemGroup>
1616

17+
<Target Name="CopyProfilesDirectory" AfterTargets="Build">
18+
<ItemGroup>
19+
<ResourceFiles Include="../EDSEditorGUI/Profiles/**/*.*" />
20+
</ItemGroup>
21+
22+
<Copy
23+
SourceFiles="@(ResourceFiles)"
24+
DestinationFolder="$(OutDir)Profiles\%(RecursiveDir)"
25+
SkipUnchangedFiles="true" />
26+
</Target>
27+
1728
<ItemGroup>
1829
<PackageReference Include="Avalonia" Version="11.1.5" />
1930
<PackageReference Include="Avalonia.Desktop" Version="11.1.5" />

EDSEditorGUI2/Icons.axaml

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@
66
<PathIcon Data="{StaticResource remove_regular}" />
77
<PathIcon Data="{StaticResource add_regular}" />
88
<PathIcon Data="{StaticResource save_regular}" />
9+
<PathIcon Data="{StaticResource book_add_regular}" />
910
</StackPanel>
1011
</Border>
1112
</Design.PreviewWith>
@@ -16,6 +17,7 @@
1617
<StreamGeometry x:Key="remove_regular">M3.7547787,12.4995322 L20.2466903,12.4995322 C20.6609039,12.4995322 20.9966903,12.1637458 20.9966903,11.7495322 C20.9966903,11.3353187 20.6609039,10.9995322 20.2466903,10.9995322 L3.7547787,10.9995322 C3.34056514,10.9995322 3.0047787,11.3353187 3.0047787,11.7495322 C3.0047787,12.1637458 3.34056514,12.4995322 3.7547787,12.4995322 Z</StreamGeometry>
1718
<StreamGeometry x:Key="add_regular">M14.5,13 L14.5,3.75378577 C14.5,3.33978577 14.164,3.00378577 13.75,3.00378577 C13.336,3.00378577 13,3.33978577 13,3.75378577 L13,13 L3.75387573,13 C3.33987573,13 3.00387573,13.336 3.00387573,13.75 C3.00387573,14.164 3.33987573,14.5 3.75387573,14.5 L13,14.5 L13,23.7523651 C13,24.1663651 13.336,24.5023651 13.75,24.5023651 C14.164,24.5023651 14.5,24.1663651 14.5,23.7523651 L14.5,14.5 L23.7498262,14.5030754 C24.1638262,14.5030754 24.4998262,14.1670754 24.4998262,13.7530754 C24.4998262,13.3390754 24.1638262,13.0030754 23.7498262,13.0030754 L14.5,13 Z</StreamGeometry>
1819
<StreamGeometry x:Key="save_regular">M3 5.75C3 4.23122 4.23122 3 5.75 3H15.7145C16.5764 3 17.4031 3.34241 18.0126 3.9519L20.0481 5.98744C20.6576 6.59693 21 7.42358 21 8.28553V18.25C21 19.7688 19.7688 21 18.25 21H5.75C4.23122 21 3 19.7688 3 18.25V5.75ZM5.75 4.5C5.05964 4.5 4.5 5.05964 4.5 5.75V18.25C4.5 18.9404 5.05964 19.5 5.75 19.5H6V14.25C6 13.0074 7.00736 12 8.25 12H15.75C16.9926 12 18 13.0074 18 14.25V19.5H18.25C18.9404 19.5 19.5 18.9404 19.5 18.25V8.28553C19.5 7.8214 19.3156 7.37629 18.9874 7.0481L16.9519 5.01256C16.6918 4.75246 16.3582 4.58269 16 4.52344V7.25C16 8.49264 14.9926 9.5 13.75 9.5H9.25C8.00736 9.5 7 8.49264 7 7.25V4.5H5.75ZM16.5 19.5V14.25C16.5 13.8358 16.1642 13.5 15.75 13.5H8.25C7.83579 13.5 7.5 13.8358 7.5 14.25V19.5H16.5ZM8.5 4.5V7.25C8.5 7.66421 8.83579 8 9.25 8H13.75C14.1642 8 14.5 7.66421 14.5 7.25V4.5H8.5Z</StreamGeometry>
20+
<StreamGeometry x:Key="book_add_regular">M3 4.5C3 3.11929 4.11929 2 5.5 2H17C18.3807 2 19.5 3.11929 19.5 4.5V11.3135C19.0218 11.159 18.5195 11.0585 18 11.0189V4.5C18 3.94772 17.5523 3.5 17 3.5H5.5C4.94772 3.5 4.5 3.94772 4.5 4.5V18H11.0189C11.0585 18.5195 11.159 19.0218 11.3135 19.5H4.5C4.5 20.0523 4.94772 20.5 5.5 20.5H11.7322C12.0194 21.051 12.3832 21.5557 12.8096 22H5.5C4.11929 22 3 20.8807 3 19.5V4.5Z M17.5 12C20.5376 12 23 14.4624 23 17.5C23 20.5376 20.5376 23 17.5 23C14.4624 23 12 20.5376 12 17.5C12 14.4624 14.4624 12 17.5 12ZM18.0011 20.5035L18.0006 18H20.503C20.7792 18 21.003 17.7762 21.003 17.5C21.003 17.2239 20.7792 17 20.503 17H18.0005L18 14.4993C18 14.2231 17.7761 13.9993 17.5 13.9993C17.2239 13.9993 17 14.2231 17 14.4993L17.0005 17H14.4961C14.22 17 13.9961 17.2239 13.9961 17.5C13.9961 17.7762 14.22 18 14.4961 18H17.0006L17.0011 20.5035C17.0011 20.7797 17.225 21.0035 17.5011 21.0035C17.7773 21.0035 18.0011 20.7797 18.0011 20.5035Z M6 6C6 5.44772 6.44772 5 7 5H15C15.5523 5 16 5.44772 16 6V8C16 8.55228 15.5523 9 15 9H7C6.44772 9 6 8.55228 6 8V6ZM7.5 7.5H14.5V6.5H7.5V7.5Z</StreamGeometry>
1921
</Styles.Resources>
2022
</Styles>
2123
</Styles>

EDSEditorGUI2/ViewModels/Device.cs

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,18 @@ public Device()
88
{
99
}
1010

11+
public override string ToString()
12+
{
13+
if (DeviceInfo == null)
14+
{
15+
return "unnamed device";
16+
}
17+
else
18+
{
19+
return DeviceInfo.ProductName;
20+
}
21+
}
22+
1123
[ObservableProperty]
1224
private FileInfo _fileInfo = new();
1325

EDSEditorGUI2/ViewModels/MainWindowViewModel.cs

Lines changed: 108 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,8 @@
1-
using CommunityToolkit.Mvvm.ComponentModel;
1+
using Avalonia.Media;
2+
using CommunityToolkit.Mvvm.ComponentModel;
23
using EDSEditorGUI2.Mapper;
4+
using System;
5+
using System.Collections.Generic;
36
using System.Collections.ObjectModel;
47

58
namespace EDSEditorGUI2.ViewModels;
@@ -33,13 +36,115 @@ public void AddNewDevice(object sender)
3336
var DeviceView = ProtobufferViewModelMapper.MapFromProtobuffer(device);
3437
Network.Add(DeviceView);
3538
}
39+
40+
public void InitMergeStatus(Device profile, List<int> offsets)
41+
{
42+
MergeStatus.Clear();
43+
if (SelectedDevice is not null)
44+
{
45+
foreach (var obj in profile.Objects)
46+
{
47+
int mergeIndex = Int32.Parse(obj.Key);
48+
List<ODIndexMergeOffsetStatus> objectOffset = [];
49+
foreach (var offset in offsets)
50+
{
51+
objectOffset.Add(new(mergeIndex + offset, false));
52+
}
53+
54+
ODIndexMergeStatus ms = new()
55+
{
56+
Insert = true,
57+
OriginalObject = $"0x{mergeIndex:x} - {obj.Value.Name}",
58+
Offsets = objectOffset,
59+
OriginalIndex = mergeIndex,
60+
#pragma warning disable MVVMTK0034 // Direct field reference to [ObservableProperty] backing field
61+
_object = obj.Value,
62+
#pragma warning restore MVVMTK0034 // Direct field reference to [ObservableProperty] backing field
63+
TextBrush = new SolidColorBrush(Colors.Black),
64+
};
65+
66+
MergeStatus.Add(ms);
67+
}
68+
UpdateMergeStatus(offsets);
69+
}
70+
}
71+
72+
/// <summary>
73+
/// Update profile merge status by checking for collisions
74+
/// </summary>
75+
/// <param name="offsets">list of offsets in profile import</param>
76+
public void UpdateMergeStatus(List<int> offsets)
77+
{
78+
if (SelectedDevice is not null && MergeStatus.Count != 0)
79+
{
80+
foreach (var obj in MergeStatus)
81+
{
82+
//first calculate all the offsets
83+
//remember that the number of offsets could have changed
84+
List<ODIndexMergeOffsetStatus> objectOffset = [];
85+
foreach (var offset in offsets)
86+
{
87+
int mergeIndex = obj.OriginalIndex + offset;
88+
objectOffset.Add(new(mergeIndex, false));
89+
}
90+
obj.Offsets = objectOffset;
91+
}
92+
93+
// check for collision with selected device objects
94+
foreach (var obj in MergeStatus)
95+
{
96+
foreach (var offsetStatus in obj.Offsets)
97+
{
98+
foreach (var ob in SelectedDevice.Objects)
99+
{
100+
if (offsetStatus.Index == ob.Key.ToInteger())
101+
{
102+
offsetStatus.Collision = true;
103+
offsetStatus.Index *= -1;
104+
}
105+
}
106+
}
107+
}
108+
109+
// check for collision with other offsets objects, collum by collum
110+
var numberOfOffsets = MergeStatus[0].Offsets.Count;
111+
112+
// Check each collum from left to right.
113+
// you only check for collision with collums to the left
114+
for (int i = 0; i < numberOfOffsets; i++)
115+
{
116+
foreach (var leftRow in MergeStatus)
117+
{
118+
int rightCollumIndex = leftRow.Offsets[i].Index;
119+
for (int j = i; j >= 0; j--)
120+
{
121+
if (j != i)
122+
{
123+
foreach (var rightRow in MergeStatus)
124+
{
125+
int leftCollumIndex = rightRow.Offsets[j].Index;
126+
if (rightCollumIndex == leftCollumIndex)
127+
{
128+
leftRow.Offsets[i].Collision = true;
129+
}
130+
}
131+
}
132+
}
133+
}
134+
}
135+
}
136+
}
36137
#pragma warning disable CA1822 // Mark members as static
37138
public string Greeting => "Welcome to Avalonia!";
38139
#pragma warning restore CA1822 // Mark members as static
39140
public ObservableCollection<Device> Network { get; set; } = [];
40141

41-
[ObservableProperty]
42-
public Device? selectedDevice;
142+
//Used for profile import
143+
public ObservableCollection<ODIndexMergeStatus> MergeStatus { get; set; } = [];
43144

145+
[ObservableProperty]
146+
public int _insertObjectsOffset;
44147

148+
[ObservableProperty]
149+
public Device? _selectedDevice;
45150
}
Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,49 @@
1+
using Avalonia.Media;
2+
using CommunityToolkit.Mvvm.ComponentModel;
3+
using System.Collections.Generic;
4+
5+
namespace EDSEditorGUI2.ViewModels;
6+
7+
/// <summary>
8+
/// Viewmodel for merging one index
9+
/// </summary>
10+
public partial class ODIndexMergeOffsetStatus : ObservableObject
11+
{
12+
public ODIndexMergeOffsetStatus(int index, bool collision)
13+
{
14+
Index = index;
15+
Collision = collision;
16+
}
17+
[ObservableProperty]
18+
private int _index;
19+
20+
[ObservableProperty]
21+
private bool _collision;
22+
}
23+
24+
/// <summary>
25+
/// Used as a view model when merging ODs or inserting profiles
26+
/// </summary>
27+
public partial class ODIndexMergeStatus : ObservableObject
28+
{
29+
[ObservableProperty]
30+
private bool _insert;
31+
32+
[ObservableProperty]
33+
private string _originalObject = string.Empty;
34+
35+
[ObservableProperty]
36+
private List<ODIndexMergeOffsetStatus> _offsets = [];
37+
38+
[ObservableProperty]
39+
private bool _indexCollision;
40+
41+
[ObservableProperty]
42+
private int _originalIndex;
43+
44+
[ObservableProperty]
45+
public required OdObject _object;
46+
47+
[ObservableProperty]
48+
public IBrush _textBrush = new SolidColorBrush(Colors.Black);
49+
}

EDSEditorGUI2/Views/MainWindow.axaml

Lines changed: 36 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,9 @@
11
<Window xmlns="https://github.com/avaloniaui"
22
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:dialogHost="clr-namespace:DialogHostAvalonia;assembly=DialogHost.Avalonia"
34
xmlns:vm="using:EDSEditorGUI2.ViewModels"
45
xmlns:view="using:EDSEditorGUI2.Views"
6+
xmlns:converter="using:EDSEditorGUI2.Converter"
57
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
68
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
79
mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
@@ -15,10 +17,10 @@
1517
to set the actual DataContext for runtime, set the DataContext property in code (look at App.axaml.cs) -->
1618
<vm:MainWindowViewModel/>
1719
</Design.DataContext>
18-
20+
<dialogHost:DialogHost Identifier="RootDialogHost" >
1921
<DockPanel>
20-
<Menu DockPanel.Dock="Top">
21-
<MenuItem Header="_File">
22+
<Menu DockPanel.Dock="Top" x:Name="menu">
23+
<MenuItem Header="_File" x:Name="fileMenu" >
2224
<MenuItem Header="_New" Command="{Binding AddNewDevice}"/>
2325
<MenuItem Header="_Open"/>
2426
<MenuItem Header="_Save Project" IsEnabled="{Binding SelectedDevice, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
@@ -35,8 +37,7 @@
3537
<Separator/>
3638
<MenuItem Header="_Quit"/>
3739
</MenuItem>
38-
<MenuItem Header="_Insert Profile">
39-
</MenuItem>
40+
<MenuItem Header="_Insert Profile" x:Name="profileMenu" IsEnabled="{Binding SelectedDevice, Converter={x:Static StringConverters.IsNotNullOrEmpty}}"/>
4041
<MenuItem Header="_Reports">
4142
</MenuItem>
4243
<MenuItem Header="Tools">
@@ -55,7 +56,36 @@
5556
</ListBox>
5657
</StackPanel>
5758
<view:DeviceView DataContext="{Binding SelectedDevice}" />
58-
</DockPanel>
59+
</DockPanel>
60+
</dialogHost:DialogHost>
61+
62+
<Window.Resources>
63+
<!-- Insert Objects dialog -->
64+
<StackPanel x:Key="InsertObjectsDialog" MaxWidth="900">
65+
<TextBlock Text="Target:" />
66+
<ComboBox x:Name="InsertObjects_target" ItemsSource="{Binding Network}" SelectedItem="{Binding SelectedDevice}" MaxDropDownHeight="100" />
67+
<TextBlock Text="Index Offset (single or space separated list for multiple insert)" />
68+
<TextBox x:Name="InsertObjects_Offsets" Watermark="1 100 500" Text="0" TextChanged="OnOffsetTextChanged"/>
5969

70+
<ScrollViewer>
71+
<DataGrid Margin="20" ItemsSource="{Binding MergeStatus}"
72+
GridLinesVisibility="All"
73+
BorderThickness="1" BorderBrush="Gray"
74+
MaxHeight="500"
75+
x:Name="grid">
6076

77+
<DataGrid.Columns>
78+
<DataGridCheckBoxColumn Header="Insert" Width="*"
79+
Binding="{Binding Insert}"/>
80+
<DataGridTextColumn Header="Original Object" Width="*" IsReadOnly="True"
81+
Binding="{Binding OriginalObject}" />
82+
</DataGrid.Columns>
83+
</DataGrid>
84+
</ScrollViewer>
85+
<StackPanel Orientation="Horizontal">
86+
<Button x:Name="InsertObjects_Insert" IsDefault="True" Margin="10" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=dialogHost:DialogHost}, Path=CloseDialogCommand}" CommandParameter="insert">Insert</Button>
87+
<Button x:Name="InsertObjects_Cancel" IsCancel="True" Margin="10" Command="{Binding RelativeSource={RelativeSource FindAncestor, AncestorType=dialogHost:DialogHost}, Path=CloseDialogCommand}">Cancel</Button>
88+
</StackPanel>
89+
</StackPanel>
90+
</Window.Resources>
6191
</Window>

0 commit comments

Comments
 (0)