Skip to content

Commit ab0ac30

Browse files
authored
Initial avalonia GUI (#148)
Still not usable, but most of the massive work is done
1 parent 1a203f1 commit ab0ac30

37 files changed

Lines changed: 1629 additions & 0 deletions

EDSEditor.sln

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Tests", "Tests\Tests.csproj
1414
EndProject
1515
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EDSSharp", "EDSSharp\EDSSharp.csproj", "{8B7A7545-6257-44BF-8868-F429E1B72C77}"
1616
EndProject
17+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "EDSEditorGUI2", "EDSEditorGUI2\EDSEditorGUI2.csproj", "{F175A47B-8BB8-480F-8D31-AF802086B8B4}"
18+
EndProject
19+
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "GUITests", "GUITests\GUITests.csproj", "{9B9B5461-1864-484D-A49D-D39422DA16E0}"
20+
EndProject
1721
Global
1822
GlobalSection(SolutionConfigurationPlatforms) = preSolution
1923
Debug|Any CPU = Debug|Any CPU
@@ -36,6 +40,14 @@ Global
3640
{8B7A7545-6257-44BF-8868-F429E1B72C77}.Debug|Any CPU.Build.0 = Debug|Any CPU
3741
{8B7A7545-6257-44BF-8868-F429E1B72C77}.Release|Any CPU.ActiveCfg = Release|Any CPU
3842
{8B7A7545-6257-44BF-8868-F429E1B72C77}.Release|Any CPU.Build.0 = Release|Any CPU
43+
{F175A47B-8BB8-480F-8D31-AF802086B8B4}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
44+
{F175A47B-8BB8-480F-8D31-AF802086B8B4}.Debug|Any CPU.Build.0 = Debug|Any CPU
45+
{F175A47B-8BB8-480F-8D31-AF802086B8B4}.Release|Any CPU.ActiveCfg = Release|Any CPU
46+
{F175A47B-8BB8-480F-8D31-AF802086B8B4}.Release|Any CPU.Build.0 = Release|Any CPU
47+
{9B9B5461-1864-484D-A49D-D39422DA16E0}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
48+
{9B9B5461-1864-484D-A49D-D39422DA16E0}.Debug|Any CPU.Build.0 = Debug|Any CPU
49+
{9B9B5461-1864-484D-A49D-D39422DA16E0}.Release|Any CPU.ActiveCfg = Release|Any CPU
50+
{9B9B5461-1864-484D-A49D-D39422DA16E0}.Release|Any CPU.Build.0 = Release|Any CPU
3951
EndGlobalSection
4052
GlobalSection(SolutionProperties) = preSolution
4153
HideSolutionNode = FALSE

EDSEditorGUI2/.gitignore

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
/obj/*
2+
/bin/*

EDSEditorGUI2/App.axaml

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
<Application xmlns="https://github.com/avaloniaui"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
3+
xmlns:dialogHostAvalonia="clr-namespace:DialogHostAvalonia;assembly=DialogHost.Avalonia"
4+
x:Class="EDSEditorGUI2.App"
5+
xmlns:local="using:EDSEditorGUI2"
6+
RequestedThemeVariant="Default">
7+
<!-- "Default" ThemeVariant follows system theme variant. "Dark" or "Light" are other available options. -->
8+
9+
<Application.DataTemplates>
10+
<local:ViewLocator/>
11+
</Application.DataTemplates>
12+
13+
<Application.Styles>
14+
<FluentTheme />
15+
<StyleInclude Source="avares://Avalonia.Controls.DataGrid/Themes/Fluent.xaml"/>
16+
<StyleInclude Source="avares://EDSEditorGUI2/Icons.axaml"/>
17+
<dialogHostAvalonia:DialogHostStyles />
18+
</Application.Styles>
19+
</Application>

EDSEditorGUI2/App.axaml.cs

Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
using Avalonia;
2+
using Avalonia.Controls.ApplicationLifetimes;
3+
using Avalonia.Data.Core.Plugins;
4+
using Avalonia.Markup.Xaml;
5+
using EDSEditorGUI2.ViewModels;
6+
using EDSEditorGUI2.Views;
7+
8+
namespace EDSEditorGUI2;
9+
10+
public partial class App : Application
11+
{
12+
public override void Initialize()
13+
{
14+
AvaloniaXamlLoader.Load(this);
15+
}
16+
17+
public override void OnFrameworkInitializationCompleted()
18+
{
19+
if (ApplicationLifetime is IClassicDesktopStyleApplicationLifetime desktop)
20+
{
21+
// Line below is needed to remove Avalonia data validation.
22+
// Without this line you will get duplicate validations from both Avalonia and CT
23+
BindingPlugins.DataValidators.RemoveAt(0);
24+
desktop.MainWindow = new MainWindow
25+
{
26+
DataContext = new MainWindowViewModel(),
27+
};
28+
}
29+
30+
base.OnFrameworkInitializationCompleted();
31+
}
32+
}
172 KB
Binary file not shown.
Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,46 @@
1+
using Avalonia.Data;
2+
using Avalonia.Data.Converters;
3+
using Avalonia.Media.Immutable;
4+
using System;
5+
using System.Collections.Generic;
6+
using System.Globalization;
7+
using System.Linq;
8+
9+
namespace EDSEditorGUI2.Converter;
10+
11+
public class NewIndexRequest(int index, string name, LibCanOpen.OdObject.Types.ObjectType type)
12+
{
13+
public int Index { get; } = index;
14+
public string Name { get; } = name;
15+
public LibCanOpen.OdObject.Types.ObjectType Type { get; } = type;
16+
}
17+
18+
public sealed class NewIndexMultiConvert : IMultiValueConverter
19+
{
20+
public object? Convert(IList<object?> values, Type targetType, object? parameter, CultureInfo culture)
21+
{
22+
// Ensure all bindings are provided and attached to correct target type
23+
if (values?.Count != 3 || !targetType.IsAssignableFrom(typeof(ImmutableSolidColorBrush)))
24+
throw new NotSupportedException();
25+
26+
if (values[0] is not string rawindex ||
27+
values[1] is not string name ||
28+
values[2] is not int typeIndex)
29+
return BindingOperations.DoNothing;
30+
31+
int index = int.Parse(rawindex, NumberStyles.HexNumber);
32+
33+
var typeValues = Enum.GetNames(typeof(LibCanOpen.OdObject.Types.ObjectType)).Skip(1).ToArray();
34+
bool parseOk = Enum.TryParse(typeValues[typeIndex], out LibCanOpen.OdObject.Types.ObjectType type);
35+
36+
if (parseOk)
37+
{
38+
var indexRequest = new NewIndexRequest(index, name, type);
39+
return indexRequest;
40+
}
41+
else
42+
{
43+
return BindingOperations.DoNothing;
44+
}
45+
}
46+
}

EDSEditorGUI2/EDSEditorGUI2.csproj

Lines changed: 30 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,30 @@
1+
<Project Sdk="Microsoft.NET.Sdk">
2+
<PropertyGroup>
3+
<OutputType>WinExe</OutputType>
4+
<TargetFramework>net8.0</TargetFramework>
5+
<Nullable>enable</Nullable>
6+
<BuiltInComInteropSupport>true</BuiltInComInteropSupport>
7+
<ApplicationManifest>app.manifest</ApplicationManifest>
8+
<AvaloniaUseCompiledBindingsByDefault>true</AvaloniaUseCompiledBindingsByDefault>
9+
</PropertyGroup>
10+
11+
<ItemGroup>
12+
<Folder Include="Models\" />
13+
<AvaloniaResource Include="Assets\**" />
14+
<ProjectReference Include="..\libEDSsharp\libEDSsharp.csproj" />
15+
</ItemGroup>
16+
17+
<ItemGroup>
18+
<PackageReference Include="Avalonia" Version="11.1.5" />
19+
<PackageReference Include="Avalonia.Desktop" Version="11.1.5" />
20+
<PackageReference Include="Avalonia.Themes.Fluent" Version="11.1.5" />
21+
<PackageReference Include="Avalonia.Fonts.Inter" Version="11.1.5" />
22+
<PackageReference Include="Avalonia.Controls.ItemsRepeater" Version="11.1.5" />
23+
<PackageReference Include="Avalonia.Controls.DataGrid" Version="11.1.5" />
24+
<!--Condition below is needed to remove Avalonia.Diagnostics package from build output in Release configuration.-->
25+
<PackageReference Condition="'$(Configuration)' == 'Debug'" Include="Avalonia.Diagnostics" Version="11.1.5" />
26+
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.3.2" />
27+
<PackageReference Include="DialogHost.Avalonia" Version="0.8.1" />
28+
<PackageReference Include="AutoMapper" Version="13.0.1" />
29+
</ItemGroup>
30+
</Project>

EDSEditorGUI2/Extensions.cs

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
using System;
2+
3+
namespace EDSEditorGUI2
4+
{
5+
public static class StringExtensions
6+
{
7+
/// <summary>
8+
/// Convert different types of hex/dec string to integer
9+
/// </summary>
10+
public static UInt16 ToInteger(this String val)
11+
{
12+
return (UInt16)Convert.ToInt32(val, 16);
13+
}
14+
}
15+
}

EDSEditorGUI2/Icons.axaml

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
<Styles xmlns="https://github.com/avaloniaui"
2+
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
3+
<Design.PreviewWith>
4+
<Border Padding="5" >
5+
<StackPanel Orientation="Vertical" >
6+
<PathIcon Data="{StaticResource remove_regular}" />
7+
<PathIcon Data="{StaticResource add_regular}" />
8+
<PathIcon Data="{StaticResource save_regular}" />
9+
</StackPanel>
10+
</Border>
11+
</Design.PreviewWith>
12+
13+
<!-- source http://avaloniaui.github.io/icons.html -->
14+
<Styles>
15+
<Styles.Resources>
16+
<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>
17+
<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>
18+
<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>
19+
</Styles.Resources>
20+
</Styles>
21+
</Styles>
Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
using AutoMapper;
2+
using Google.Protobuf.WellKnownTypes;
3+
using LibCanOpen;
4+
using System;
5+
6+
namespace EDSEditorGUI2.Mapper
7+
{
8+
public partial class ProtobufferViewModelMapper
9+
{
10+
public static ViewModels.Device MapFromProtobuffer(CanOpenDevice source)
11+
{
12+
var config = new MapperConfiguration(cfg =>
13+
{
14+
cfg.CreateMap<Timestamp, DateTime>().ConvertUsing(ts => ts.ToDateTime());
15+
cfg.CreateMap<CanOpen_FileInfo, ViewModels.FileInfo>()
16+
.ForMember(dest => dest.FileVersion, opt => opt.MapFrom(src => src.FileVersion))
17+
.ForMember(dest => dest.Description, opt => opt.MapFrom(src => src.Description))
18+
.ForMember(dest => dest.CreationTime, opt => opt.MapFrom(src => src.CreationTime))
19+
.ForMember(dest => dest.CreatedBy, opt => opt.MapFrom(src => src.CreatedBy))
20+
.ForMember(dest => dest.ModificationTime, opt => opt.MapFrom(src => src.ModificationTime))
21+
.ForMember(dest => dest.ModifiedBy, opt => opt.MapFrom(src => src.ModifiedBy));
22+
cfg.CreateMap<CanOpenDevice, ViewModels.Device>()
23+
.ForMember(dest => dest.FileInfo, opt => opt.MapFrom(src => src.FileInfo))
24+
.ForMember(dest => dest.DeviceInfo, opt => opt.MapFrom(src => src.DeviceInfo))
25+
.ForMember(dest => dest.DeviceCommissioning, opt => opt.MapFrom(src => src.DeviceCommissioning))
26+
.ForPath(dest => dest.Objects.Data, opt => opt.MapFrom(src => src.Objects));
27+
28+
cfg.CreateMap<CanOpen_DeviceInfo, ViewModels.DeviceInfo>();
29+
cfg.CreateMap<CanOpen_DeviceCommissioning, ViewModels.DeviceCommissioning>();
30+
cfg.CreateMap<OdObject, ViewModels.OdObject>();
31+
32+
});
33+
config.AssertConfigurationIsValid();
34+
var mapper = config.CreateMapper();
35+
var result = mapper.Map<ViewModels.Device>(source);
36+
return result;
37+
}
38+
39+
public static CanOpenDevice MapToProtobuffer(ViewModels.Device source)
40+
{
41+
var config = new MapperConfiguration(cfg =>
42+
{
43+
//TODO
44+
});
45+
config.AssertConfigurationIsValid();
46+
var mapper = config.CreateMapper();
47+
var result = mapper.Map<CanOpenDevice>(source);
48+
return result;
49+
}
50+
}
51+
}

0 commit comments

Comments
 (0)