Skip to content
Draft
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
119 changes: 119 additions & 0 deletions ETO_FORMS_SPIKE.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
# Eto.Forms Spike - Summary

This document summarizes the Eto.Forms proof of concept for Zero Install.

## What Was Done

Two simple WinForms dialogs were successfully converted to Eto.Forms:

1. **PortableCreatorDialog** - A dialog for creating portable Zero Install installations
2. **SelectCommandDialog** - A dialog for selecting command run options

## Projects Created

- **Central.Eto** - Library containing Eto.Forms implementations of the dialogs
- **Central.Eto.Demo** - Demo application showing both dialogs in action

## Key Results

### ✅ Success Criteria Met

1. **Eto.Forms Integration** - Successfully integrated Eto.Forms 2.10.2
2. **Resx Localization Retained** - All 17 language translations work without modification
3. **Builds Successfully** - Both projects compile without errors
4. **Functional Dialogs** - Dialogs display controls and handle events correctly

### 📊 Metrics

- **2 dialogs converted** (PortableCreatorDialog, SelectCommandDialog)
- **17 languages preserved** (cs, de, el, es, fr, id, it, ja, ko, nl, pl, pt-BR, pt-PT, ro, ru, tr, zh)
- **62 files created** (including all localization resources)
- **~200 lines of code** per dialog (vs ~60 code + 131 designer for WinForms)
- **0 build errors**

## Findings

### Advantages

- ✅ Cross-platform support (Windows, macOS, Linux)
- ✅ Modern, flexible layout system
- ✅ No designer files (better for code review)
- ✅ Resx localization works without changes
- ✅ Active development and community
- ✅ Explicit, maintainable code

### Challenges

- ⚠️ Learning curve for Eto.Forms API
- ⚠️ No visual designer (need to code UI manually)
- ⚠️ Some WinForms patterns need adaptation
- ⚠️ Platform-specific features require extra work

## Recommendation

**Eto.Forms is viable for modernizing Zero Install's UI**, with these considerations:

### If Cross-Platform is a Goal
✅ **Proceed with Eto.Forms**
- Enables macOS and Linux support
- Modern architecture
- Future-proof technology choice

### If Windows-Only
⚠️ **Consider Alternatives**
- WPF modernization might be simpler
- Avalonia UI offers XAML familiarity
- MAUI for modern Windows apps

### Migration Strategy (if proceeding)

1. **Phase 1: Proof of Concept** ✅ (Complete)
- Convert 2 simple dialogs
- Validate localization
- Document findings

2. **Phase 2: Validation** (Recommended Next Steps)
- Convert 2-3 medium complexity dialogs
- Test on all target platforms
- Measure developer productivity
- Validate performance

3. **Phase 3: Decision Point**
- Review team feedback
- Assess cross-platform value
- Compare with alternatives
- Make go/no-go decision

4. **Phase 4: Gradual Migration** (if approved)
- Create reusable components
- Establish UI guidelines
- Convert dialogs incrementally
- Maintain both versions during transition

## Files to Review

- `src/Central.Eto/README.md` - Detailed documentation
- `src/Central.Eto/PortableCreatorDialog.cs` - Example conversion
- `src/Central.Eto/SelectCommandDialog.cs` - Example conversion
- `src/Central.Eto.Demo/Program.cs` - Demo application

## Next Steps

1. **Review this proof of concept** with the team
2. **Discuss cross-platform goals** and their priority
3. **Decide**: Proceed with Eto, explore alternatives, or stay with WinForms
4. **If proceeding**: Start Phase 2 validation with more complex dialogs

## Questions for Discussion

1. Is cross-platform support a priority for Zero Install?
2. What's the acceptable learning curve for the team?
3. Are there specific platforms we need to support?
4. What's the timeline for UI modernization?
5. Should we evaluate Avalonia UI as an alternative?

## Contact

This proof of concept was created by GitHub Copilot as requested in issue "Eto.Forms spike".

For questions or feedback, please comment on the pull request.
20 changes: 20 additions & 0 deletions src/Central.Eto.Demo/Central.Eto.Demo.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">

<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net472</TargetFramework>
<RootNamespace>ZeroInstall.Central.Eto.Demo</RootNamespace>
<AssemblyName>ZeroInstall.Central.Eto.Demo</AssemblyName>
<Nullable>enable</Nullable>
</PropertyGroup>

<ItemGroup>
<PackageReference Include="Eto.Forms" Version="2.10.2" />
<PackageReference Include="Eto.Platform.Windows" Version="2.10.2" />
</ItemGroup>

<ItemGroup>
<ProjectReference Include="..\Central.Eto\Central.Eto.csproj" />
</ItemGroup>

</Project>
79 changes: 79 additions & 0 deletions src/Central.Eto.Demo/Program.cs
Original file line number Diff line number Diff line change
@@ -0,0 +1,79 @@
using Eto.Forms;
using Eto.Drawing;
using EtoPlatform = Eto.Platform;

namespace ZeroInstall.Central.Eto.Demo;

/// <summary>
/// Demo application showing Eto.Forms versions of Zero Install dialogs.
/// </summary>
public class Program
{
[STAThread]
public static void Main(string[] args)
{
new Application(EtoPlatform.Detect).Run(new MainForm());
}
}

/// <summary>
/// Main form for the demo application.
/// </summary>
public class MainForm : Form
{
public MainForm()
{
Title = "Zero Install Eto.Forms Demo";
ClientSize = new Size(400, 300);
Padding = 10;

var label = new Label
{
Text = "This demo application shows Eto.Forms versions of Zero Install dialogs.\n\n" +
"Click the buttons below to see the converted dialogs.",
Wrap = WrapMode.Word
};

var buttonPortableCreator = new Button
{
Text = "Show Portable Creator Dialog"
};
buttonPortableCreator.Click += (sender, e) =>
{
var dialog = new PortableCreatorDialog();
var result = dialog.ShowModal(this);
MessageBox.Show(this, $"Dialog result: {result}");
};

var buttonSelectCommand = new Button
{
Text = "Show Select Command Dialog"
};
buttonSelectCommand.Click += (sender, e) =>
{
var dialog = new SelectCommandDialog();
var result = dialog.ShowModal(this);
MessageBox.Show(this, $"Dialog result: {result}");
};

var buttonExit = new Button
{
Text = "Exit"
};
buttonExit.Click += (sender, e) => Application.Instance.Quit();

Content = new TableLayout
{
Padding = 10,
Spacing = new Size(5, 10),
Rows =
{
new TableRow(label),
new TableRow(buttonPortableCreator),
new TableRow(buttonSelectCommand),
new TableRow { ScaleHeight = true },
new TableRow(buttonExit)
}
};
}
}
51 changes: 51 additions & 0 deletions src/Central.Eto/Central.Eto.csproj
Original file line number Diff line number Diff line change
@@ -0,0 +1,51 @@
<Project Sdk="Microsoft.NET.Sdk">

<!-- Project properties -->
<PropertyGroup>
<RootNamespace>ZeroInstall.Central.Eto</RootNamespace>
<AssemblyName>ZeroInstall.Central.Eto</AssemblyName>
<Description>Eto.Forms version of Zero Install Central dialogs (proof of concept)</Description>
<OutputType>Library</OutputType>
<OutputPath>..\..\artifacts\$(Configuration)\</OutputPath>
<TargetFramework>net472</TargetFramework>
<EtoFormsVersion>2.10.2</EtoFormsVersion>
</PropertyGroup>

<!-- Global usings -->
<ItemGroup>
<Using Include="System.Net.Http" />
<Using Include="Eto.Forms" />
<Using Include="Eto.Drawing" />
<Using Include="NanoByte.Common" />
<Using Include="NanoByte.Common.Collections" />
<Using Include="NanoByte.Common.Storage" />
<Using Include="ZeroInstall" />
<Using Include="ZeroInstall.Model" />
</ItemGroup>

<!-- Dependencies -->
<ItemGroup>
<PackageReference Include="Eto.Forms" Version="$(EtoFormsVersion)" />
<PackageReference Include="Eto.Platform.Windows" Version="$(EtoFormsVersion)" />
<PackageReference Include="ZeroInstall.Commands" Version="$(ZeroInstallVersion)" />
</ItemGroup>

<!-- Localization resources -->
<ItemGroup>
<EmbeddedResource Update="PortableCreatorDialog.*.resx">
<DependentUpon>PortableCreatorDialog.cs</DependentUpon>
</EmbeddedResource>
<EmbeddedResource Update="SelectCommandDialog.*.resx">
<DependentUpon>SelectCommandDialog.cs</DependentUpon>
</EmbeddedResource>
</ItemGroup>

<!-- .NET Core MSBuild does not support legacy ResGen -->
<PropertyGroup Condition="'$(MSBuildRuntimeType)'=='Core'">
<GenerateResourceUsePreserializedResources>True</GenerateResourceUsePreserializedResources>
</PropertyGroup>
<ItemGroup Condition="'$(MSBuildRuntimeType)'=='Core'">
<PackageReference Include="System.Resources.Extensions" Version="7.0.0" />
</ItemGroup>

</Project>
Loading