diff --git a/NativeAot/NativeAot.csproj b/NativeAot/NativeAot.csproj new file mode 100644 index 0000000000..6c5e1f136f --- /dev/null +++ b/NativeAot/NativeAot.csproj @@ -0,0 +1,22 @@ + + + + Exe + net8.0 + enable + enable + true + false + + + + + + + + + + + + + diff --git a/NativeAot/Program.cs b/NativeAot/Program.cs new file mode 100644 index 0000000000..5ef38db051 --- /dev/null +++ b/NativeAot/Program.cs @@ -0,0 +1,113 @@ +// This is a test application for a native Aot file. + +using System.Diagnostics; +using System.Diagnostics.CodeAnalysis; +using System.Globalization; +using Terminal.Gui; + +namespace NativeAot; + +public static class Program +{ + [RequiresUnreferencedCode ("Calls Terminal.Gui.Application.Init(ConsoleDriver, String)")] + [RequiresDynamicCode ("Calls Terminal.Gui.Application.Init(ConsoleDriver, String)")] + private static void Main (string [] args) + { + Application.Init (); + + #region The code in this region is not intended for use in a native Aot self-contained. It's just here to make sure there is no functionality break with localization in Terminal.Gui using self-contained + + if (Equals(Thread.CurrentThread.CurrentUICulture, CultureInfo.InvariantCulture) && Application.SupportedCultures.Count == 0) + { + // Only happens if the project has true + Debug.Assert (Application.SupportedCultures.Count == 0); + } + else + { + Debug.Assert (Application.SupportedCultures.Count > 0); + Debug.Assert (Equals (CultureInfo.CurrentCulture, Thread.CurrentThread.CurrentUICulture)); + } + + #endregion + + ExampleWindow app = new (); + Application.Run (app); + + // Dispose the app object before shutdown + app.Dispose (); + + // Before the application exits, reset Terminal.Gui for clean shutdown + Application.Shutdown (); + + // To see this output on the screen it must be done after shutdown, + // which restores the previous screen. + Console.WriteLine ($@"Username: {ExampleWindow.UserName}"); + } +} + +// Defines a top-level window with border and title +public class ExampleWindow : Window +{ + public static string? UserName; + + public ExampleWindow () + { + Title = $"Example App ({Application.QuitKey} to quit)"; + + // Create input components and labels + var usernameLabel = new Label { Text = "Username:" }; + + var userNameText = new TextField + { + // Position text field adjacent to the label + X = Pos.Right (usernameLabel) + 1, + + // Fill remaining horizontal space + Width = Dim.Fill () + }; + + var passwordLabel = new Label + { + Text = "Password:", X = Pos.Left (usernameLabel), Y = Pos.Bottom (usernameLabel) + 1 + }; + + var passwordText = new TextField + { + Secret = true, + + // align with the text box above + X = Pos.Left (userNameText), + Y = Pos.Top (passwordLabel), + Width = Dim.Fill () + }; + + // Create login button + var btnLogin = new Button + { + Text = "Login", + Y = Pos.Bottom (passwordLabel) + 1, + + // center the login button horizontally + X = Pos.Center (), + IsDefault = true + }; + + // When login button is clicked display a message popup + btnLogin.Accept += (s, e) => + { + if (userNameText.Text == "admin" && passwordText.Text == "password") + { + MessageBox.Query ("Logging In", "Login Successful", "Ok"); + UserName = userNameText.Text; + Application.RequestStop (); + } + else + { + MessageBox.ErrorQuery ("Logging In", "Incorrect username or password", "Ok"); + } + }; + + // Add the views to the Window + Add (usernameLabel, userNameText, passwordLabel, passwordText, btnLogin); + } +} diff --git a/NativeAot/Properties/PublishProfiles/FolderProfile_net8.0_win-x64_Debug.pubxml b/NativeAot/Properties/PublishProfiles/FolderProfile_net8.0_win-x64_Debug.pubxml new file mode 100644 index 0000000000..c883267bf0 --- /dev/null +++ b/NativeAot/Properties/PublishProfiles/FolderProfile_net8.0_win-x64_Debug.pubxml @@ -0,0 +1,18 @@ + + + + + Debug + Any CPU + bin\Debug\net8.0\publish\win-x64\ + FileSystem + <_TargetId>Folder + net8.0 + win-x64 + true + false + false + + \ No newline at end of file diff --git a/NativeAot/Properties/PublishProfiles/FolderProfile_net8.0_win-x64_Release.pubxml b/NativeAot/Properties/PublishProfiles/FolderProfile_net8.0_win-x64_Release.pubxml new file mode 100644 index 0000000000..79576fb52f --- /dev/null +++ b/NativeAot/Properties/PublishProfiles/FolderProfile_net8.0_win-x64_Release.pubxml @@ -0,0 +1,18 @@ + + + + + Release + Any CPU + bin\Release\net8.0\publish\win-x64\ + FileSystem + <_TargetId>Folder + net8.0 + win-x64 + true + false + false + + \ No newline at end of file diff --git a/NativeAot/Publish_linux-x64_Debug.sh b/NativeAot/Publish_linux-x64_Debug.sh new file mode 100644 index 0000000000..b58a83cc1e --- /dev/null +++ b/NativeAot/Publish_linux-x64_Debug.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +dotnet clean +dotnet build +dotnet publish -c Debug -r linux-x64 --self-contained diff --git a/NativeAot/Publish_linux-x64_Release.sh b/NativeAot/Publish_linux-x64_Release.sh new file mode 100644 index 0000000000..3cb8feb267 --- /dev/null +++ b/NativeAot/Publish_linux-x64_Release.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +dotnet clean +dotnet build +dotnet publish -c Release -r linux-x64 --self-contained diff --git a/NativeAot/Publish_osx-x64_Debug.sh b/NativeAot/Publish_osx-x64_Debug.sh new file mode 100644 index 0000000000..1fe41513c6 --- /dev/null +++ b/NativeAot/Publish_osx-x64_Debug.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +dotnet clean +dotnet build +dotnet publish -c Debug -r osx-x64 --self-contained diff --git a/NativeAot/Publish_osx-x64_Release.sh b/NativeAot/Publish_osx-x64_Release.sh new file mode 100644 index 0000000000..06b748b79d --- /dev/null +++ b/NativeAot/Publish_osx-x64_Release.sh @@ -0,0 +1,5 @@ +#!/bin/bash + +dotnet clean +dotnet build +dotnet publish -c Release -r osx-x64 --self-contained diff --git a/NativeAot/README.md b/NativeAot/README.md new file mode 100644 index 0000000000..7a55ccfc7c --- /dev/null +++ b/NativeAot/README.md @@ -0,0 +1,10 @@ +# Terminal.Gui C# SelfContained + +This project aims to test the `Terminal.Gui` library to create a simple `native AOT` `self-container` GUI application in C#, ensuring that all its features are available. + +With `Debug` the `.csproj` is used and with `Release` the latest `nuget package` is used, either in `Solution Configurations` or in `Profile Publish` or in the `Publish_linux-x64` or in the `Publish_osx-x64` files. +Unlike self-contained single-file publishing, native AOT publishing must be generated on the same platform as the target execution version. Therefore, if the target execution is Linux, then the publishing must be generated on a Linux operating system. Attempting to generate on Windows for the Linux target will throw an exception. + +To publish the `native AOT` file in `Debug` or `Release` mode, it is not necessary to select it in the `Solution Configurations`, just choose the `Debug` or `Release` configuration in the `Publish Profile` or the `*.sh` files. + +When executing the file directly from the `native AOT` file and needing to debug it, it will be necessary to attach it to the debugger, just like any other standalone application and selecting `Native Code`. \ No newline at end of file diff --git a/Terminal.Gui/Configuration/SourceGenerationContext.cs b/Terminal.Gui/Configuration/SourceGenerationContext.cs index ed93b68cae..85a438b83c 100644 --- a/Terminal.Gui/Configuration/SourceGenerationContext.cs +++ b/Terminal.Gui/Configuration/SourceGenerationContext.cs @@ -7,17 +7,17 @@ namespace Terminal.Gui; /// [JsonSerializable (typeof (Attribute))] [JsonSerializable (typeof (Color))] -[JsonSerializable (typeof (ThemeScope))] -[JsonSerializable (typeof (ColorScheme))] -[JsonSerializable (typeof (SettingsScope))] [JsonSerializable (typeof (AppScope))] +[JsonSerializable (typeof (SettingsScope))] [JsonSerializable (typeof (Key))] [JsonSerializable (typeof (GlyphDefinitions))] -[JsonSerializable (typeof (ConfigProperty))] +[JsonSerializable (typeof (Alignment))] +[JsonSerializable (typeof (AlignmentModes))] +[JsonSerializable (typeof (LineStyle))] [JsonSerializable (typeof (ShadowStyle))] -[JsonSerializable (typeof (string))] -[JsonSerializable (typeof (bool))] [JsonSerializable (typeof (bool?))] [JsonSerializable (typeof (Dictionary))] +[JsonSerializable (typeof (Dictionary))] +[JsonSerializable (typeof (Dictionary))] internal partial class SourceGenerationContext : JsonSerializerContext { } diff --git a/Terminal.Gui/Drawing/Alignment.cs b/Terminal.Gui/Drawing/Alignment.cs index 6a160096f1..169e4c323a 100644 --- a/Terminal.Gui/Drawing/Alignment.cs +++ b/Terminal.Gui/Drawing/Alignment.cs @@ -1,10 +1,11 @@ - +using System.Text.Json.Serialization; namespace Terminal.Gui; /// /// Determines the position of items when arranged in a container. /// +[JsonConverter (typeof (JsonStringEnumConverter))] public enum Alignment { /// diff --git a/Terminal.Gui/Drawing/AlignmentModes.cs b/Terminal.Gui/Drawing/AlignmentModes.cs index b7e0bb87e0..1b6e262c48 100644 --- a/Terminal.Gui/Drawing/AlignmentModes.cs +++ b/Terminal.Gui/Drawing/AlignmentModes.cs @@ -1,10 +1,11 @@ - +using System.Text.Json.Serialization; namespace Terminal.Gui; /// /// Determines alignment modes for . /// +[JsonConverter (typeof (JsonStringEnumConverter))] [Flags] public enum AlignmentModes { diff --git a/Terminal.Gui/Drawing/Color.Formatting.cs b/Terminal.Gui/Drawing/Color.Formatting.cs index e381289579..406ceff4b1 100644 --- a/Terminal.Gui/Drawing/Color.Formatting.cs +++ b/Terminal.Gui/Drawing/Color.Formatting.cs @@ -284,7 +284,7 @@ in text ), // Any string too short to possibly be any supported format. - { Length: > 0 and < 4 } => throw new ColorParseException ( + { Length: > 0 and < 3 } => throw new ColorParseException ( in text, "Text was too short to be any possible supported format.", in text diff --git a/Terminal.Gui/Drawing/LineStyle.cs b/Terminal.Gui/Drawing/LineStyle.cs index 47e37a97aa..a696bc9435 100644 --- a/Terminal.Gui/Drawing/LineStyle.cs +++ b/Terminal.Gui/Drawing/LineStyle.cs @@ -1,7 +1,10 @@ #nullable enable +using System.Text.Json.Serialization; + namespace Terminal.Gui; /// Defines the style of lines for a . +[JsonConverter (typeof (JsonStringEnumConverter))] public enum LineStyle { /// No border is drawn. diff --git a/Terminal.Gui/View/Adornment/ShadowStyle.cs b/Terminal.Gui/View/Adornment/ShadowStyle.cs index a410292c64..7a95e78ed2 100644 --- a/Terminal.Gui/View/Adornment/ShadowStyle.cs +++ b/Terminal.Gui/View/Adornment/ShadowStyle.cs @@ -1,8 +1,11 @@ -namespace Terminal.Gui; +using System.Text.Json.Serialization; + +namespace Terminal.Gui; /// /// Defines the style of shadow to be drawn on the right and bottom sides of the . /// +[JsonConverter (typeof (JsonStringEnumConverter))] public enum ShadowStyle { /// diff --git a/Terminal.Gui/Views/Button.cs b/Terminal.Gui/Views/Button.cs index f489a8bb4e..e5845fbb59 100644 --- a/Terminal.Gui/Views/Button.cs +++ b/Terminal.Gui/Views/Button.cs @@ -5,8 +5,6 @@ // Miguel de Icaza (miguel@gnome.org) // -using System.Text.Json.Serialization; - namespace Terminal.Gui; /// Button is a that provides an item that invokes raises the event. @@ -39,8 +37,6 @@ public class Button : View, IDesignable /// Gets or sets whether s are shown with a shadow effect by default. /// [SerializableConfigurationProperty (Scope = typeof (ThemeScope))] - [JsonConverter (typeof (JsonStringEnumConverter))] - public static ShadowStyle DefaultShadow { get; set; } = ShadowStyle.None; /// Initializes a new instance of . diff --git a/Terminal.Gui/Views/Dialog.cs b/Terminal.Gui/Views/Dialog.cs index c1f18e8fbc..aefc6eb5a4 100644 --- a/Terminal.Gui/Views/Dialog.cs +++ b/Terminal.Gui/Views/Dialog.cs @@ -1,6 +1,4 @@ -using System.Text.Json.Serialization; - -namespace Terminal.Gui; +namespace Terminal.Gui; /// /// The is a that by default is centered and contains @@ -19,13 +17,11 @@ public class Dialog : Window /// The default for . /// This property can be set in a Theme. [SerializableConfigurationProperty (Scope = typeof (ThemeScope))] - [JsonConverter (typeof (JsonStringEnumConverter))] public static Alignment DefaultButtonAlignment { get; set; } = Alignment.End; // Default is set in config.json - /// The default for . + /// The default for . /// This property can be set in a Theme. [SerializableConfigurationProperty (Scope = typeof (ThemeScope))] - [JsonConverter (typeof (JsonStringEnumConverter))] public static AlignmentModes DefaultButtonAlignmentModes { get; set; } = AlignmentModes.StartToEnd | AlignmentModes.AddSpaceBetweenItems; /// @@ -47,7 +43,6 @@ public class Dialog : Window /// Gets or sets whether all s are shown with a shadow effect by default. /// [SerializableConfigurationProperty (Scope = typeof (ThemeScope))] - [JsonConverter (typeof (JsonStringEnumConverter))] public new static ShadowStyle DefaultShadow { get; set; } = ShadowStyle.None; // Default is set in config.json /// @@ -56,7 +51,6 @@ public class Dialog : Window /// [SerializableConfigurationProperty (Scope = typeof (ThemeScope))] - [JsonConverter (typeof (JsonStringEnumConverter))] public new static LineStyle DefaultBorderStyle { get; set; } = LineStyle.Single; // Default is set in config.json private readonly List