diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/ControlImplementations/ContainerImplementation.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/ControlImplementations/ContainerImplementation.cs new file mode 100644 index 0000000..7518461 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/ControlImplementations/ContainerImplementation.cs @@ -0,0 +1,49 @@ +using MBS.Core.Drawing; +using MBS.Desktop.Controls; +using MBS.Desktop.Engines.GTK3.Internal.GTK.Classes; +using MBS.Desktop.Engines.GTK3.Internal.GTK.Constants; + +namespace MBS.Desktop.Engines.GTK3.ControlImplementations; + +public abstract class ContainerImplementation : GTK3NativeImplementation, Container.IImplementation +{ + public void InsertControl(Control control, int index) + { + Container container = (Container)Control; + GtkContainer native = (GtkContainer)((GTK3NativeHandle)container.Layout.Implementation.Handle).Handle; + + control.CreateImplementation(); + + + //!FIXME: we need to use the Layout here + native.Add(((GTK3NativeHandle)control.Implementation.Handle).Handle); + } + + public void RemoveControl(Control control) + { + GtkContainer container = (GtkContainer)((GTK3NativeHandle)Handle).Handle; + container.Remove(((GTK3NativeHandle)control.Implementation.Handle).Handle); + } + + public void RemoveAllControls() + { + } + + protected override void OnNativeHandleCreated(EventArgs e) + { + base.OnNativeHandleCreated(e); + + Container container = (Container)Control; + Layout layout = container.Layout; + + GTK3NativeHandle nhControl = (GTK3NativeHandle)Handle; + + layout.CreateImplementation(); + GTK3NativeHandle nhLayout = (GTK3NativeHandle)layout.Implementation.Handle; + + GtkContainer ct = (GtkContainer)nhControl.Handle; + ct.Add(nhLayout.Handle); + } + + +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/ControlImplementations/LabelImplementation.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/ControlImplementations/LabelImplementation.cs new file mode 100644 index 0000000..149c522 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/ControlImplementations/LabelImplementation.cs @@ -0,0 +1,33 @@ +using MBS.Core.Drawing; +using MBS.Desktop.Controls; +using MBS.Desktop.Engines.GTK3.Internal.GTK.Classes; +using MBS.Desktop.Engines.GTK3.Internal.GTK.Constants; + +namespace MBS.Desktop.Engines.GTK3.ControlImplementations; + +[ImplementsFor(typeof(Label))] +public class LabelImplementation : GTK3NativeImplementation, Label.IImplementation +{ + protected override NativeHandle CreateNativeHandle() + { + return new GTK3NativeHandle(new GtkLabel()); + } + public string GetText() + { + return ((GtkLabel)((GTK3NativeHandle)Handle).Handle).Text; + } + + public void SetText(string value) + { + ((GtkLabel)((GTK3NativeHandle)Handle).Handle).Text = value; + } + public bool GetUseMarkup() + { + return ((GtkLabel)((GTK3NativeHandle)Handle).Handle).UseMarkup; + } + + public void SetUseMarkup(bool value) + { + ((GtkLabel)((GTK3NativeHandle)Handle).Handle).UseMarkup = value; + } +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/ControlImplementations/WindowImplementation.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/ControlImplementations/WindowImplementation.cs new file mode 100644 index 0000000..c43dbe2 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/ControlImplementations/WindowImplementation.cs @@ -0,0 +1,65 @@ +using MBS.Core.Drawing; +using MBS.Desktop.Controls; +using MBS.Desktop.Engines.GTK3.Internal.GTK.Classes; +using MBS.Desktop.Engines.GTK3.Internal.GTK.Constants; + +namespace MBS.Desktop.Engines.GTK3.ControlImplementations; + +[ImplementsFor(typeof(Window))] +public class WindowImplementation : ContainerImplementation, Window.IImplementation +{ + public void Show() + { + GtkWindow window = (GtkWindow)((GTK3NativeHandle)Handle).Handle; + window.ShowAll(); + } + public bool GetVisible() + { + GtkWindow window = (GtkWindow)((GTK3NativeHandle)Handle).Handle; + return window.IsVisible; + } + public void SetVisible(bool value) + { + GtkWindow window = (GtkWindow)((GTK3NativeHandle)Handle).Handle; + if (value) + { + window.ShowAll(); + } + else + { + window.Hide(); + } + } + + public string GetTitle() + { + GtkWindow window = (GtkWindow)((GTK3NativeHandle)Handle).Handle; + return window.Title; + } + public void SetTitle(string value) + { + GtkWindow window = (GtkWindow)((GTK3NativeHandle)Handle).Handle; + window.Title = value; + } + + public Dimension2D GetDefaultSize() + { + GtkWindow window = (GtkWindow)((GTK3NativeHandle)Handle).Handle; + int width = 0, height = 0; + window.GetDefaultSize(out width, out height); + + return new Dimension2D(width, height); + } + public void SetDefaultSize(Dimension2D value) + { + GtkWindow window = (GtkWindow)((GTK3NativeHandle)Handle).Handle; + window.SetDefaultSize((int)value.Width, (int)value.Height); + } + + protected override NativeHandle CreateNativeHandle() + { + Window window = (Window)Control; + GtkWindow native = new GtkWindow(((GTK3DesktopApplicationEngine)((DesktopApplication)DesktopApplication.Instance).Engine).ApplicationHandle); + return new GTK3NativeHandle(native); + } +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/GTK3DesktopApplicationEngine.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/GTK3DesktopApplicationEngine.cs new file mode 100644 index 0000000..4b2938f --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/GTK3DesktopApplicationEngine.cs @@ -0,0 +1,70 @@ +namespace MBS.Desktop.Engines.GTK3; + +using MBS.Core; +using MBS.Core.Reflection; +using MBS.Desktop.Controls; +using MBS.Desktop.Engines.GTK3.Internal.GIO.Constants; +using MBS.Desktop.Engines.GTK3.Internal.GTK.Classes; +using static MBS.Desktop.Engines.GTK3.Internal.GObject.Delegates; + +public class GTK3DesktopApplicationEngine : DesktopApplicationEngine +{ + protected string GetApplicationId() + { + return "net.alcetech.framework.desktop__" + this.GetType().FullName; + } + + public GtkApplication? ApplicationHandle { get; private set; } + + protected override void InitializeInternal() + { + ApplicationHandle = new GtkApplication(GetApplicationId(), GApplicationFlags.HandlesCommandLine); + } + + Action2P startup_d; + Action2P activate_d; + Action3P commandline_d; + + public GTK3DesktopApplicationEngine() + { + startup_d = new Action2P(startup); + activate_d = new Action2P(activate); + commandline_d = new Action3P(commandline); + } + + private void activate(IntPtr application, IntPtr user_data) + { + // Invoker.Invoke(Application.Instance, "OnStartup", new object[] { EventArgs.Empty }); + Console.WriteLine("activate() called , we should be using commandline ()"); + } + private void startup(IntPtr application, IntPtr user_data) + { + Console.WriteLine("startup() called"); + Invoker.Invoke(Application.Instance, "OnStartup", new object[] { EventArgs.Empty }); + } + + private static bool _firstRun = true; + private void commandline(IntPtr handle, IntPtr commandLine, IntPtr data) + { + Console.WriteLine("commandline() called"); + + int argc = 0; + IntPtr hwpp = Internal.GIO.Methods.g_application_command_line_get_arguments(commandLine, ref argc); + + string[] arguments = MBS.Core.Interop.InteropServices.PtrToStringArray(hwpp, argc); + + CommandLine cline = new CommandLine(arguments); + ApplicationActivatedEventArgs e = new ApplicationActivatedEventArgs(_firstRun, ApplicationActivationType.Launch, cline); + Invoker.Invoke(Application.Instance, "OnActivated", new object[] { e }); + } + + protected override int StartInternal() + { + ApplicationHandle.Connect("startup", startup_d); + ApplicationHandle.Connect("activate", activate_d); + ApplicationHandle.Connect("command_line", commandline_d); + + int retval = ApplicationHandle.Run(); + return retval; + } +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/GTK3NativeHandle.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/GTK3NativeHandle.cs new file mode 100644 index 0000000..71bbd69 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/GTK3NativeHandle.cs @@ -0,0 +1,14 @@ +using MBS.Desktop.Engines.GTK3.Internal.GTK.Classes; + +namespace MBS.Desktop.Engines.GTK3; + +public class GTK3NativeHandle : NativeHandle +{ + public GtkWidget Handle { get; private set; } + + public GTK3NativeHandle(GtkWidget handle) + { + Handle = handle; + } + +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/GTK3NativeImplementation.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/GTK3NativeImplementation.cs new file mode 100644 index 0000000..69eb814 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/GTK3NativeImplementation.cs @@ -0,0 +1,6 @@ +namespace MBS.Desktop.Engines.GTK3; + +public abstract class GTK3NativeImplementation : NativeImplementation +{ + +} diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GIO/Classes/GApplication.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GIO/Classes/GApplication.cs new file mode 100644 index 0000000..593c6bb --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GIO/Classes/GApplication.cs @@ -0,0 +1,18 @@ +using System.Runtime.InteropServices; +using MBS.Desktop.Engines.GTK3.Internal.GIO.Constants; + +namespace MBS.Desktop.Engines.GTK3.Internal.GIO.Classes; + +public class GApplication : GObject.Classes.GObject +{ + [DllImport(LIBRARY_FILENAME_GIO)] + private static extern int g_application_run(IntPtr /*GApplication*/ application, int argc, string[] argv); + + public int Run() + { + string[] argv = Environment.GetCommandLineArgs(); + int argc = argv.Length; + int retval = g_application_run(Handle, argc, argv); + return retval; + } +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GIO/Constants/GApplicationFlags.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GIO/Constants/GApplicationFlags.cs new file mode 100644 index 0000000..1484439 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GIO/Constants/GApplicationFlags.cs @@ -0,0 +1,63 @@ +namespace MBS.Desktop.Engines.GTK3.Internal.GIO.Constants; + +/// +/// Flags used to define the behaviour of a . +/// +public enum GApplicationFlags +{ + /// + /// Default. Deprecated in 2.74, use G_APPLICATION_DEFAULT_FLAGS instead. + /// + None = 0, + /// + /// Default flags. Since: 2.74 + /// + Default = 0, + /// + /// Run as a service. In this mode, registration fails if the service is already running, and the application will initially wait up to 10 seconds for an initial activation message to arrive. + /// + Service = (1 << 0), + /// + /// Don't try to become the primary instance. + /// + Launcher = (1 << 1), + /// + /// This application handles opening files (in the primary instance). Note that this flag + /// only affects the default implementation of local_command_line(), and has no effect if + /// G_APPLICATION_HANDLES_COMMAND_LINE is given. See g_application_run() for details. + /// + HandlesOpen = (1 << 2), + /// + /// This application handles command line arguments (in the primary instance). Note that + /// this flag only affect the default implementation of local_command_line(). See + /// g_application_run() for details. + /// + HandlesCommandLine = (1 << 3), + /// + /// Send the environment of the launching process to the primary instance. Set this flag + /// if your application is expected to behave differently depending on certain environment + /// variables. For instance, an editor might be expected to use the GIT_COMMITTER_NAME + /// environment variable when editing a git commit message. The environment is available to + /// the "command-line" signal handler, via g_application_command_line_getenv(). + /// + SendEnvironment = (1 << 4), + /// + /// Make no attempts to do any of the typical single-instance application negotiation, + /// even if the application ID is given. The application neither attempts to become the + /// owner of the application ID nor does it check if an existing owner already exists. + /// Everything occurs in the local process. Since: 2.30. + /// + NonUnique = (1 << 5), + /// + /// Allow users to override the application ID from the command line with --gapplication-app-id. Since: 2.48 + /// + CanOverrideAppId = (1 << 6), + /// + /// Allow another instance to take over the bus name. Since: 2.60 + /// + AllowReplacement = (1 << 7), + /// + /// Take over from another instance. This flag is usually set by passing --gapplication-replace on the commandline. Since: 2.60 + /// + Replace = (1 << 8) +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GIO/Methods.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GIO/Methods.cs new file mode 100644 index 0000000..bb0df29 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GIO/Methods.cs @@ -0,0 +1,11 @@ +using System.Runtime.InteropServices; + +namespace MBS.Desktop.Engines.GTK3.Internal.GIO; + +internal static class Methods +{ + public const string LIBRARY_FILENAME_GIO = "gio-2.0"; + + [DllImport(LIBRARY_FILENAME_GIO)] + public static extern IntPtr g_application_command_line_get_arguments(IntPtr command_line, ref int argc); +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GObject/Classes/GObject.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GObject/Classes/GObject.cs new file mode 100644 index 0000000..d7d6db1 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GObject/Classes/GObject.cs @@ -0,0 +1,106 @@ +using System.Linq.Expressions; +using System.Reflection.Metadata.Ecma335; +using System.Runtime.InteropServices; +using MBS.Desktop.Engines.GTK3.Internal.GObject.Constants; +using static MBS.Desktop.Engines.GTK3.Internal.GObject.Delegates; + +namespace MBS.Desktop.Engines.GTK3.Internal.GObject.Classes; + +/// +/// The base object type +/// +public class GObject +{ + public const string LIBRARY_FILENAME_GTK = "gtk-3"; + public const string LIBRARY_FILENAME_GLIB = "glib-2.0"; + public const string LIBRARY_FILENAME_GOBJECT = "gobject-2.0"; + public const string LIBRARY_FILENAME_GIO = "gio-2.0"; + + internal GObject(IntPtr handle) + { + Handle = handle; + } + protected GObject() + { + } + + public IntPtr Handle { get; protected set; } + + // private static extern void g_object_set_property (IntPtr obj, string property_name, ref GValue value); + [DllImport(LIBRARY_FILENAME_GOBJECT)] + private static extern void g_object_get_property (IntPtr obj, string property_name, IntPtr value); + [DllImport(LIBRARY_FILENAME_GOBJECT)] + private static extern void g_object_set_property (IntPtr obj, string property_name, IntPtr value); + + public T GetProperty(string property_name) + { + if (typeof(T) == typeof(bool)) + { + GValue value = new GValue(GValueType.Boolean); + g_object_get_property(Handle, property_name, value.Handle); + + bool val = value.GetBoolean(); + return (T)((object)val); + } + else if (typeof(T) == typeof(IntPtr)) + { + GValue value = new GValue(GValueType.Pointer); + g_object_get_property(Handle, property_name, value.Handle); + IntPtr val = value.GetPointer(); + return (T)((object)val); + } + throw new NotImplementedException(); + } + public void SetProperty(string property_name, object value) + { + if (value is bool) + { + GValue gvalue = new GValue(GValueType.Boolean); + gvalue.SetBoolean((bool)value); + g_object_set_property(Handle, property_name, gvalue.Handle); + } + else if (value is IntPtr) + { + GValue gvalue = new GValue(GValueType.Pointer); + gvalue.SetPointer((IntPtr)value); + g_object_set_property(Handle, property_name, gvalue.Handle); + } + else if (value is GObject) + { + GValue gvalue = new GValue(GValueType.Object); + gvalue.SetObject((GObject)value); + g_object_set_property(Handle, property_name, gvalue.Handle); + } + else + { + throw new NotImplementedException(); + } + } + + [DllImport(LIBRARY_FILENAME_GOBJECT)] + private static extern IntPtr g_type_from_name (string name); + + + [DllImport(LIBRARY_FILENAME_GOBJECT)] + private static extern void g_signal_connect_data(IntPtr instance, string detailed_signal, Action c_handler, IntPtr data, IntPtr destroy_data, GConnectFlags connect_flags); + [DllImport(LIBRARY_FILENAME_GOBJECT)] + private static extern void g_signal_connect_data(IntPtr instance, string detailed_signal, Action1P c_handler, IntPtr data, IntPtr destroy_data, GConnectFlags connect_flags); + [DllImport(LIBRARY_FILENAME_GOBJECT)] + private static extern void g_signal_connect_data(IntPtr instance, string detailed_signal, Action2P c_handler, IntPtr data, IntPtr destroy_data, GConnectFlags connect_flags); + [DllImport(LIBRARY_FILENAME_GOBJECT)] + private static extern void g_signal_connect_data(IntPtr instance, string detailed_signal, Action3P c_handler, IntPtr data, IntPtr destroy_data, GConnectFlags connect_flags); + + public void Connect(string detailed_signal, Action1P c_handler, IntPtr data = default(IntPtr)) + { + g_signal_connect_data(Handle, detailed_signal, c_handler, data, IntPtr.Zero, GConnectFlags.Default); + } + public void Connect(string detailed_signal, Action2P c_handler, IntPtr data = default(IntPtr)) + { + g_signal_connect_data(Handle, detailed_signal, c_handler, data, IntPtr.Zero, GConnectFlags.Default); + } + public void Connect(string detailed_signal, Action3P c_handler, IntPtr data = default(IntPtr)) + { + g_signal_connect_data(Handle, detailed_signal, c_handler, data, IntPtr.Zero, GConnectFlags.Default); + } + +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GObject/Classes/GValue.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GObject/Classes/GValue.cs new file mode 100644 index 0000000..33c3796 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GObject/Classes/GValue.cs @@ -0,0 +1,80 @@ +using System.Runtime.InteropServices; + +namespace MBS.Desktop.Engines.GTK3.Internal.GObject.Classes; + +public class GValue +{ + [DllImport(GObject.LIBRARY_FILENAME_GOBJECT)] + private static extern IntPtr g_value_init(IntPtr gvalue, IntPtr gtype); + [DllImport(GObject.LIBRARY_FILENAME_GOBJECT)] + private static extern IntPtr g_value_get_object(IntPtr gvalue); + + [DllImport(GObject.LIBRARY_FILENAME_GOBJECT)] + private static extern void g_value_set_object(IntPtr gvalue, IntPtr ptr); + + [DllImport(GObject.LIBRARY_FILENAME_GOBJECT)] + private static extern IntPtr g_value_get_pointer(IntPtr gvalue); + + [DllImport(GObject.LIBRARY_FILENAME_GOBJECT)] + private static extern void g_value_set_pointer(IntPtr gvalue, IntPtr ptr); + + [DllImport(GObject.LIBRARY_FILENAME_GOBJECT)] + private static extern long g_value_get_int64(IntPtr gvalue); + [DllImport(GObject.LIBRARY_FILENAME_GOBJECT)] + private static extern void g_value_set_int64(IntPtr gvalue, long value); + + [DllImport(GObject.LIBRARY_FILENAME_GOBJECT)] + private static extern bool g_value_get_boolean(IntPtr gvalue); + [DllImport(GObject.LIBRARY_FILENAME_GOBJECT)] + private static extern void g_value_set_boolean(IntPtr gvalue, bool value); + + private const int G_VALUE_SIZE = 24; // found by calling sizeof(G_VALUE_INIT) in C + private IntPtr g_value_new(IntPtr gtype) + { + IntPtr gvalue = Marshal.AllocHGlobal(G_VALUE_SIZE); + for (int i = 0; i < G_VALUE_SIZE; i++) + { + Marshal.WriteByte(gvalue, i, 0); + } + + Console.WriteLine("g_value_new: initializing new GValue of type {0}", gtype); + IntPtr gvalue2 = g_value_init(gvalue, gtype); + return gvalue2; + } + + public IntPtr Handle { get; } + + public GValue(GValueType type) + { + Handle = g_value_new(type.Handle); + } + + public bool GetBoolean() + { + return g_value_get_boolean(Handle); + } + public void SetBoolean(bool value) + { + g_value_set_boolean(Handle, value); + } + + public IntPtr GetPointer() + { + return g_value_get_pointer(Handle); + } + public void SetPointer(IntPtr value) + { + g_value_set_pointer(Handle, value); + } + + public GObject GetObject() + { + IntPtr h = g_value_get_object(Handle); + // !FIXME: look up in our table to see if we have a .NET object for this + return new GObject(h); + } + public void SetObject(GObject value) + { + + } +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GObject/Classes/GValueType.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GObject/Classes/GValueType.cs new file mode 100644 index 0000000..b0f1f98 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GObject/Classes/GValueType.cs @@ -0,0 +1,30 @@ +namespace MBS.Desktop.Engines.GTK3.Internal.GObject.Classes; + +public class GValueType +{ + private const int G_TYPE_FUNDAMENTAL_SHIFT = 2; + + private static IntPtr G_TYPE_MAKE_FUNDAMENTAL(int x) + { + return new IntPtr(x << G_TYPE_FUNDAMENTAL_SHIFT); + } + + public IntPtr Handle { get; } + public GValueType(IntPtr handle) + { + Handle = handle; + } + + private static readonly IntPtr G_TYPE_BOOLEAN = G_TYPE_MAKE_FUNDAMENTAL(5); + public static GValueType Boolean { get; } = new GValueType(G_TYPE_BOOLEAN); + + private static readonly IntPtr G_TYPE_INT64 = G_TYPE_MAKE_FUNDAMENTAL(10); + public static GValueType Int64 { get; } = new GValueType(G_TYPE_INT64); + + private static readonly IntPtr G_TYPE_POINTER = G_TYPE_MAKE_FUNDAMENTAL(17); + public static GValueType Pointer { get; } = new GValueType(G_TYPE_POINTER); + + private static readonly IntPtr G_TYPE_OBJECT = G_TYPE_MAKE_FUNDAMENTAL(20); + public static GValueType Object { get; } = new GValueType(G_TYPE_OBJECT); + +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GObject/Constants/GConnectFlags.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GObject/Constants/GConnectFlags.cs new file mode 100644 index 0000000..af96351 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GObject/Constants/GConnectFlags.cs @@ -0,0 +1,8 @@ +namespace MBS.Desktop.Engines.GTK3.Internal.GObject.Constants; + +public enum GConnectFlags +{ + Default, + After, + Swapped +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GObject/Delegates.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GObject/Delegates.cs new file mode 100644 index 0000000..d63e41f --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GObject/Delegates.cs @@ -0,0 +1,13 @@ +using System.Runtime.InteropServices; +using MBS.Desktop.Engines.GTK3.Internal.GObject.Constants; + +namespace MBS.Desktop.Engines.GTK3.Internal.GObject; + +public static class Delegates +{ + + public delegate void Action1P(IntPtr parm1); + public delegate void Action2P(IntPtr parm1, IntPtr parm2); + public delegate void Action3P(IntPtr parm1, IntPtr parm2, IntPtr parm3); + +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/Gtk.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/Gtk.cs new file mode 100644 index 0000000..ecec138 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/Gtk.cs @@ -0,0 +1,38 @@ +using System.Runtime.InteropServices; + +namespace MBS.Desktop.Engines.GTK3.Internal.GTK.Classes; + +public static class Gtk +{ + [DllImport("gtk-3")] + private static extern void gtk_init(ref int argc, ref string[] argv); + [DllImport("gtk-3")] + private static extern bool gtk_init_check(ref int argc, ref string[] argv); + + public static void Init() + { + string[] argv = System.Environment.GetCommandLineArgs(); + int argc = argv.Length; + gtk_init(ref argc, ref argv); + } + /// + /// This function does the same work as with only a single + /// change: It does not terminate the program if the commandline arguments + /// couldn’t be parsed or the windowing system can’t be initialized. + /// + /// + /// of command-line arguments after the call to gtk_init_check, + /// or if gtk_init_check returned FALSE. + /// + public static string[] InitCheck() + { + string[] argv = System.Environment.GetCommandLineArgs(); + int argc = argv.Length; + bool value = gtk_init_check(ref argc, ref argv); + if (value) + { + return argv; + } + return null; + } +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/GtkApplication.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/GtkApplication.cs new file mode 100644 index 0000000..84984e8 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/GtkApplication.cs @@ -0,0 +1,30 @@ +using System.Runtime.InteropServices; +using MBS.Desktop.Engines.GTK3.Internal.GIO.Classes; +using MBS.Desktop.Engines.GTK3.Internal.GIO.Constants; + +namespace MBS.Desktop.Engines.GTK3.Internal.GTK.Classes; + +public class GtkApplication : GApplication +{ + public string Id { get; } + public GApplicationFlags Flags { get; } + + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern IntPtr gtk_application_new(string application_id, GApplicationFlags flags); + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern IntPtr gtk_application_add_window(IntPtr application, IntPtr window); + + public void AddWindow(GtkWindow window) + { + gtk_application_add_window(Handle, window.Handle); + } + + public GtkApplication(string id, GApplicationFlags flags) + { + Console.WriteLine("creating new GtkApplication with id {0}", id); + Handle = gtk_application_new(id, flags); + + Id = id; + Flags = flags; + } +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/GtkBin.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/GtkBin.cs new file mode 100644 index 0000000..174bd2b --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/GtkBin.cs @@ -0,0 +1,6 @@ +namespace MBS.Desktop.Engines.GTK3.Internal.GTK.Classes; + +public class GtkBin : GtkContainer +{ + +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/GtkBox.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/GtkBox.cs new file mode 100644 index 0000000..457d9c5 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/GtkBox.cs @@ -0,0 +1,45 @@ +using System.Runtime.InteropServices; +using MBS.Desktop.Engines.GTK3.Internal.GTK.Constants; +using MBS.Desktop.Engines.GTK3.Internal.GTK.Interfaces; + +namespace MBS.Desktop.Engines.GTK3.Internal.GTK.Classes; + +public class GtkBox : GtkContainer, GtkOrientable +{ + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern IntPtr /*GtkBox*/ gtk_box_new(GtkOrientation orientation, int spacing); + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern void gtk_box_pack_start(IntPtr /*GtkBox*/ handle, IntPtr /*GtkWidget*/ child, bool expand, bool fill, uint padding); + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern void gtk_box_pack_end(IntPtr /*GtkBox*/ handle, IntPtr /*GtkWidget*/ child, bool expand, bool fill, uint padding); + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern bool gtk_box_get_homogenous(IntPtr /*GtkBox*/ handle); + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern void gtk_box_set_homogenous(IntPtr /*GtkBox*/ handle, bool value); + + public GtkBox(GtkOrientation orientation, int spacing) + { + Handle = gtk_box_new(orientation, spacing); + } + + public void PackStart(GtkWidget child, bool expand, bool fill, uint padding) + { + gtk_box_pack_start(Handle, child.Handle, expand, fill, padding); + } + public void PackEnd(GtkWidget child, bool expand, bool fill, uint padding) + { + gtk_box_pack_end(Handle, child.Handle, expand, fill, padding); + } + + public bool Homogenous + { + get { return gtk_box_get_homogenous(Handle); } + set { gtk_box_set_homogenous(Handle, value); } + } + + public GtkOrientation Orientation + { + get { return GtkOrientable.gtk_orientable_get_orientation(Handle); } + set { GtkOrientable.gtk_orientable_set_orientation(Handle, value); } + } +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/GtkContainer.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/GtkContainer.cs new file mode 100644 index 0000000..82e3802 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/GtkContainer.cs @@ -0,0 +1,22 @@ +using System.Runtime.InteropServices; + +namespace MBS.Desktop.Engines.GTK3.Internal.GTK.Classes; + +public class GtkContainer : GtkWidget +{ + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern void gtk_container_add(IntPtr /*GtkContainer*/ container, IntPtr /*GtkWidget*/ widget); + + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern void gtk_container_remove(IntPtr /*GtkContainer*/ container, IntPtr /*GtkWidget*/ widget); + + public void Add(GtkWidget widget) + { + gtk_container_add(Handle, widget.Handle); + } + public void Remove(GtkWidget widget) + { + gtk_container_remove(Handle, widget.Handle); + } + +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/GtkLabel.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/GtkLabel.cs new file mode 100644 index 0000000..5e26996 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/GtkLabel.cs @@ -0,0 +1,31 @@ +using System.Runtime.InteropServices; + +namespace MBS.Desktop.Engines.GTK3.Internal.GTK.Classes; + +public class GtkLabel : GtkWidget +{ + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern IntPtr gtk_label_new (string str); + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern IntPtr gtk_label_set_label (IntPtr /*GtkLabel*/ label, string str); + + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern string gtk_label_get_label (IntPtr /*GtkLabel*/ label); + + public GtkLabel() + { + Handle = gtk_label_new("Hello World!"); + } + + public string Text + { + get { return gtk_label_get_label(Handle); } + set { gtk_label_set_label(Handle, value); } + } + public bool UseMarkup + { + get { return GetProperty("use-markup"); } + set { SetProperty("use-markup", value); } + } + +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/GtkWidget.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/GtkWidget.cs new file mode 100644 index 0000000..6740aa6 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/GtkWidget.cs @@ -0,0 +1,46 @@ +namespace MBS.Desktop.Engines.GTK3.Internal.GTK.Classes; + +using System.Runtime.InteropServices; +using MBS.Desktop.Engines.GTK3.Internal.GObject.Classes; + +public class GtkWidget : GObject +{ + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern void gtk_widget_show(IntPtr widget); + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern void gtk_widget_show_all(IntPtr widget); + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern void gtk_widget_hide(IntPtr widget); + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern void gtk_widget_destroy(IntPtr widget); + + + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern bool gtk_widget_is_visible(IntPtr widget); + + public bool IsVisible + { + get + { + return gtk_widget_is_visible(Handle); + } + } + + public void Show() + { + gtk_widget_show(Handle); + } + public void ShowAll() + { + gtk_widget_show_all(Handle); + } + public void Hide() + { + gtk_widget_hide(Handle); + } + public void Destroy() + { + gtk_widget_destroy(Handle); + } + +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/GtkWindow.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/GtkWindow.cs new file mode 100644 index 0000000..1ffc1f5 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Classes/GtkWindow.cs @@ -0,0 +1,60 @@ +using System.Runtime.InteropServices; +using MBS.Desktop.Engines.GTK3.Internal.GTK.Constants; + +namespace MBS.Desktop.Engines.GTK3.Internal.GTK.Classes; + +public class GtkWindow : GtkBin +{ + + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern IntPtr gtk_window_new(GtkWindowType type); + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern IntPtr gtk_application_window_new(IntPtr application); + + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern void gtk_window_get_default_size(IntPtr window, ref int width, ref int height); + + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern void gtk_window_set_default_size(IntPtr window, int width, int height); + + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern void gtk_window_set_title(IntPtr window, string title); + + [DllImport(LIBRARY_FILENAME_GTK)] + private static extern string gtk_window_get_title(IntPtr window); + + public string Title + { + get + { + return gtk_window_get_title(Handle); + } + set + { + gtk_window_set_title(Handle, value); + } + } + + public GtkWindow(GtkWindowType type) + { + Handle = gtk_window_new(type); + } + public GtkWindow(GtkApplication application) + { + Handle = gtk_application_window_new(application.Handle); + } + + public void GetDefaultSize(out int width, out int height) + { + int w = 0, h = 0; + gtk_window_get_default_size(Handle, ref w, ref h); + + width = w; + height = h; + } + public void SetDefaultSize(int width, int height) + { + gtk_window_set_default_size(Handle, width, height); + } + +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Constants/GtkOrientation.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Constants/GtkOrientation.cs new file mode 100644 index 0000000..4fa30c1 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Constants/GtkOrientation.cs @@ -0,0 +1,7 @@ +namespace MBS.Desktop.Engines.GTK3.Internal.GTK.Constants; + +public enum GtkOrientation +{ + Horizontal, + Vertical +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Constants/GtkWindowType.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Constants/GtkWindowType.cs new file mode 100644 index 0000000..d241cb1 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Constants/GtkWindowType.cs @@ -0,0 +1,7 @@ +namespace MBS.Desktop.Engines.GTK3.Internal.GTK.Constants; + +public enum GtkWindowType +{ + Toplevel, + Popup +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Interfaces/GtkOrientable.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Interfaces/GtkOrientable.cs new file mode 100644 index 0000000..dcdfe0d --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/Internal/GTK/Interfaces/GtkOrientable.cs @@ -0,0 +1,14 @@ +using System.Runtime.InteropServices; +using MBS.Desktop.Engines.GTK3.Internal.GTK.Constants; + +namespace MBS.Desktop.Engines.GTK3.Internal.GTK.Interfaces; + +public interface GtkOrientable +{ + GtkOrientation Orientation { get; set; } + + [DllImport(GObject.Classes.GObject.LIBRARY_FILENAME_GTK)] + public static extern GtkOrientation gtk_orientable_get_orientation(IntPtr /*GtkOrientable*/ orientable); + [DllImport(GObject.Classes.GObject.LIBRARY_FILENAME_GTK)] + public static extern void gtk_orientable_set_orientation(IntPtr /*GtkOrientable*/ orientable, GtkOrientation value); +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/LayoutImplementations/BoxLayoutImplementation.cs b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/LayoutImplementations/BoxLayoutImplementation.cs new file mode 100644 index 0000000..09f0645 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/LayoutImplementations/BoxLayoutImplementation.cs @@ -0,0 +1,47 @@ +using MBS.Core; +using MBS.Core.Drawing; +using MBS.Desktop.Controls; +using MBS.Desktop.Engines.GTK3.Internal.GTK.Classes; +using MBS.Desktop.Engines.GTK3.Internal.GTK.Constants; +using MBS.Desktop.Layouts; + +namespace MBS.Desktop.Engines.GTK3.LayoutImplementations; + +[ImplementsFor(typeof(BoxLayout))] +public class BoxLayoutImplementation : GTK3NativeImplementation, BoxLayout.IImplementation +{ + protected override NativeHandle CreateNativeHandle() + { + return new GTK3NativeHandle(new GtkBox(GtkOrientation.Horizontal, 0)); + } + + public Orientation GetOrientation() + { + GtkBox box = (GtkBox) ((GTK3NativeHandle)Handle).Handle; + switch (box.Orientation) + { + case GtkOrientation.Horizontal: return Orientation.Horizontal; + case GtkOrientation.Vertical: return Orientation.Vertical; + } + throw new NotSupportedException(); + } + public void SetOrientation(Orientation value) + { + GtkBox box = (GtkBox) ((GTK3NativeHandle)Handle).Handle; + switch (value) + { + case Orientation.Horizontal: + { + box.Orientation = GtkOrientation.Horizontal; + return; + } + case Orientation.Vertical: + { + box.Orientation = GtkOrientation.Vertical; + return; + } + } + throw new NotSupportedException(); + } + +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/MBS.Desktop.Engines.GTK3.csproj b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/MBS.Desktop.Engines.GTK3.csproj new file mode 100644 index 0000000..6dfc2b7 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/MBS.Desktop.Engines.GTK3.csproj @@ -0,0 +1,15 @@ + + + + + + + PreserveNewest + + + + net8.0 + enable + enable + + \ No newline at end of file diff --git a/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/MBS.Desktop.Engines.GTK3.dll.config b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/MBS.Desktop.Engines.GTK3.dll.config new file mode 100644 index 0000000..5830065 --- /dev/null +++ b/desktop-framework-dotnet/src/engines/MBS.Desktop.Engines.GTK3/MBS.Desktop.Engines.GTK3.dll.config @@ -0,0 +1,16 @@ + + + + + + + + + + + + + + + + diff --git a/desktop-framework-dotnet/src/lib/MBS.Desktop/Controls/Container.cs b/desktop-framework-dotnet/src/lib/MBS.Desktop/Controls/Container.cs new file mode 100644 index 0000000..c3a45b7 --- /dev/null +++ b/desktop-framework-dotnet/src/lib/MBS.Desktop/Controls/Container.cs @@ -0,0 +1,50 @@ +using System.ComponentModel; + +namespace MBS.Desktop.Controls; + +public abstract class Container : Control +{ + public interface IImplementation + { + void InsertControl(Control control, int index); + void RemoveControl(Control control); + void RemoveAllControls(); + } + + private Layout _Layout = null; + public Layout Layout + { + get { return _Layout; } + set + { + _Layout = value; + } + } + public Control.ControlCollection Controls { get; } + + protected override void OnNativeHandleCreating(CancelEventArgs e) + { + base.OnNativeHandleCreating(e); + + // ensure the layout is created first + if (Layout != null) + { + Layout.CreateImplementation(); + } + } + + public Container() + { + Controls = new Control.ControlCollection(this); + } + + protected override void InitializeImplementedProperties() + { + base.InitializeImplementedProperties(); + + foreach (Control ctl in Controls) + { + (Implementation as Container.IImplementation).InsertControl(ctl, Controls.IndexOf(ctl)); + } + } +} diff --git a/desktop-framework-dotnet/src/lib/MBS.Desktop/Controls/Control.cs b/desktop-framework-dotnet/src/lib/MBS.Desktop/Controls/Control.cs new file mode 100644 index 0000000..92591fa --- /dev/null +++ b/desktop-framework-dotnet/src/lib/MBS.Desktop/Controls/Control.cs @@ -0,0 +1,29 @@ +namespace MBS.Desktop.Controls; + +public class Control : Implementable +{ + public class ControlCollection : System.Collections.ObjectModel.Collection + { + private Container _parent; + public ControlCollection(Container parent) + { + _parent = parent; + } + + protected override void ClearItems() + { + ((Container.IImplementation?)_parent.Implementation)?.RemoveAllControls(); + base.ClearItems(); + } + protected override void InsertItem(int index, Control item) + { + base.InsertItem(index, item); + ((Container.IImplementation?)_parent.Implementation)?.InsertControl(item, index); + } + protected override void RemoveItem(int index) + { + ((Container.IImplementation?)_parent.Implementation)?.RemoveControl(this[index]); + base.RemoveItem(index); + } + } +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/lib/MBS.Desktop/Controls/Label.cs b/desktop-framework-dotnet/src/lib/MBS.Desktop/Controls/Label.cs new file mode 100644 index 0000000..5c175f3 --- /dev/null +++ b/desktop-framework-dotnet/src/lib/MBS.Desktop/Controls/Label.cs @@ -0,0 +1,65 @@ +namespace MBS.Desktop.Controls; + +public class Label : Control +{ + public interface IImplementation + { + string GetText(); + void SetText(string value); + + bool GetUseMarkup(); + void SetUseMarkup(bool value); + } + + public Label() + { + } + public Label(string text) + { + this.Text = text; + } + + protected override void InitializeImplementedProperties() + { + base.InitializeImplementedProperties(); + + Text = _Text; + UseMarkup = _UseMarkup; + } + + private string _Text = null; + public string Text + { + get + { + if (Implementation is IImplementation impl) + { + _Text = impl.GetText(); + } + return _Text; + } + set + { + _Text = value; + (Implementation as IImplementation)?.SetText(value); + } + } + + private bool _UseMarkup = false; + public bool UseMarkup + { + get + { + if (Implementation is IImplementation impl) + { + _UseMarkup = impl.GetUseMarkup(); + } + return _UseMarkup; + } + set + { + _UseMarkup = value; + (Implementation as IImplementation)?.SetUseMarkup(value); + } + } +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/lib/MBS.Desktop/Controls/MainWindow.cs b/desktop-framework-dotnet/src/lib/MBS.Desktop/Controls/MainWindow.cs new file mode 100644 index 0000000..ce708af --- /dev/null +++ b/desktop-framework-dotnet/src/lib/MBS.Desktop/Controls/MainWindow.cs @@ -0,0 +1,12 @@ +using MBS.Core; +using MBS.Desktop.Layouts; + +namespace MBS.Desktop.Controls; + +public class MainWindow : Window +{ + public MainWindow() + { + Layout = new BoxLayout(Orientation.Vertical); + } +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/lib/MBS.Desktop/Controls/Window.cs b/desktop-framework-dotnet/src/lib/MBS.Desktop/Controls/Window.cs new file mode 100644 index 0000000..a282afe --- /dev/null +++ b/desktop-framework-dotnet/src/lib/MBS.Desktop/Controls/Window.cs @@ -0,0 +1,71 @@ +using MBS.Core.Drawing; + +namespace MBS.Desktop.Controls; + +public class Window : Container +{ + public new interface IImplementation : Container.IImplementation + { + bool GetVisible(); + void SetVisible(bool value); + + string GetTitle(); + void SetTitle(string title); + + Dimension2D GetDefaultSize(); + void SetDefaultSize(Dimension2D size); + + void Show(); + } + + public void Show() + { + CreateImplementation(); + ((Window.IImplementation)Implementation).Show(); + } + + protected override void InitializeImplementedProperties() + { + base.InitializeImplementedProperties(); + + Title = _Title; + DefaultSize = _DefaultSize; + } + + private string? _Title; + public string? Title + { + get + { + string? title = (Implementation as Window.IImplementation)?.GetTitle(); + if (title is null) + return _Title; + + return title; + } + set + { + _Title = value; + (Implementation as Window.IImplementation)?.SetTitle(value); + } + } + + private Dimension2D _DefaultSize = new Dimension2D(-1, -1); + public Dimension2D DefaultSize + { + get + { + Dimension2D? value = (Implementation as Window.IImplementation)?.GetDefaultSize(); + if (value is null) + return _DefaultSize; + + return value; + } + set + { + _DefaultSize = value; + (Implementation as Window.IImplementation)?.SetDefaultSize(value); + } + } + +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/lib/MBS.Desktop/DesktopApplication.cs b/desktop-framework-dotnet/src/lib/MBS.Desktop/DesktopApplication.cs index e9c96fe..caa859e 100644 --- a/desktop-framework-dotnet/src/lib/MBS.Desktop/DesktopApplication.cs +++ b/desktop-framework-dotnet/src/lib/MBS.Desktop/DesktopApplication.cs @@ -1,14 +1,34 @@ -namespace MBS.Desktop; +using MBS.Desktop.Controls; + +namespace MBS.Desktop; public class DesktopApplication : MBS.Core.Application { - public DesktopApplicationEngine Engine { get; } + public DesktopApplicationEngine Engine { get; private set; } protected override int StartInternal() { - // find the appropriate DesktopApplicationEngine for this platform - - return base.StartInternal(); + Console.WriteLine("DesktopApplication::StartInternal"); + + // find the appropriate DesktopApplicationEngine for this platform + DesktopApplicationEngine[] engines = MBS.Core.Reflection.TypeLoader.GetAvailableTypes(); + Console.WriteLine("DesktopApplicationEngine loader: found {0} engines", engines.Length); + if (engines.Length > 0) + { + DesktopApplicationEngine engine = engines[0]; + if (engine != null) + { + Engine = engine; + + Console.WriteLine("Using engine '{0}'", engine.GetType().FullName); + return engine.Start(); + } + } + else + { + Console.Error.WriteLine("no engines were found or could be loaded"); + } + return 2; } protected override void StopInternal(int exitCode = 0) diff --git a/desktop-framework-dotnet/src/lib/MBS.Desktop/DesktopApplicationEngine.cs b/desktop-framework-dotnet/src/lib/MBS.Desktop/DesktopApplicationEngine.cs new file mode 100644 index 0000000..919f8b7 --- /dev/null +++ b/desktop-framework-dotnet/src/lib/MBS.Desktop/DesktopApplicationEngine.cs @@ -0,0 +1,28 @@ +namespace MBS.Desktop; + +public abstract class DesktopApplicationEngine +{ + protected abstract void InitializeInternal(); + + private bool _Initialized = false; + public bool Initialize() + { + if (_Initialized) + return false; + + InitializeInternal(); + return true; + } + + public int Start() + { + Initialize(); + return StartInternal(); + } + + protected virtual int StartInternal() + { + return 0; + } + +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/lib/MBS.Desktop/IImplementable.cs b/desktop-framework-dotnet/src/lib/MBS.Desktop/IImplementable.cs new file mode 100644 index 0000000..9b30ab7 --- /dev/null +++ b/desktop-framework-dotnet/src/lib/MBS.Desktop/IImplementable.cs @@ -0,0 +1,8 @@ +namespace MBS.Desktop; + +public interface IImplementable +{ + Implementation? Implementation { get; } + bool IsCreated { get; } + void CreateImplementation(); +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/lib/MBS.Desktop/Implementable.cs b/desktop-framework-dotnet/src/lib/MBS.Desktop/Implementable.cs new file mode 100644 index 0000000..3fe6fa3 --- /dev/null +++ b/desktop-framework-dotnet/src/lib/MBS.Desktop/Implementable.cs @@ -0,0 +1,62 @@ +using System.ComponentModel; + +namespace MBS.Desktop; + +public abstract class Implementable : IImplementable +{ + public Implementation? Implementation { get; protected set; } + + public bool IsCreated { get; private set; } + + protected virtual void InitializeImplementedProperties() + { + } + + protected virtual void OnNativeHandleCreating(CancelEventArgs e) + { + } + protected virtual void OnNativeHandleCreated(EventArgs e) + { + } + protected virtual void OnCreated(EventArgs e) + { + } + + public void CreateImplementation() + { + if (Implementation == null) + { + // determine which Implementation to use to create this Control + Implementation[] impls = Core.Reflection.TypeLoader.GetAvailableTypes(); + foreach (Implementation impl in impls) + { + if (impl.Supports(GetType())) + { + Implementation = impl; + break; + } + } + } + if (!IsCreated) + { + if (Implementation == null) + { + throw new ImplementationNotFoundException(); + } + + CancelEventArgs ce = new CancelEventArgs(); + OnNativeHandleCreating(ce); + if (ce.Cancel) + return; + + Implementation.Create(this); + IsCreated = true; + + InitializeImplementedProperties(); + OnNativeHandleCreated(EventArgs.Empty); + + OnCreated(EventArgs.Empty); + } + } + +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/lib/MBS.Desktop/Implementation.cs b/desktop-framework-dotnet/src/lib/MBS.Desktop/Implementation.cs new file mode 100644 index 0000000..6528184 --- /dev/null +++ b/desktop-framework-dotnet/src/lib/MBS.Desktop/Implementation.cs @@ -0,0 +1,42 @@ +using MBS.Desktop.Controls; + +namespace MBS.Desktop; + +public abstract class Implementation +{ + public object Control { get; private set; } + public NativeHandle Handle { get; private set; } + + protected abstract NativeHandle CreateNativeHandle(); + + public void Create(IImplementable control) + { + Control = control; + Handle = CreateNativeHandle(); + + OnNativeHandleCreated(EventArgs.Empty); + OnCreated(EventArgs.Empty); + } + + protected virtual void OnNativeHandleCreated(EventArgs e) + { + } + protected virtual void OnCreated(EventArgs e) + { + } + + public bool Supports(Type typ) + { + Type typImpl = this.GetType(); + object[] attrs = typImpl.GetCustomAttributes(false); + foreach (object attr in attrs) + { + if (attr is ImplementsForAttribute ifa) + { + if (ifa.Type == typ || typ.IsSubclassOf(ifa.Type)) + return true; + } + } + return false; + } +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/lib/MBS.Desktop/ImplementationNotFoundException.cs b/desktop-framework-dotnet/src/lib/MBS.Desktop/ImplementationNotFoundException.cs new file mode 100644 index 0000000..af8853f --- /dev/null +++ b/desktop-framework-dotnet/src/lib/MBS.Desktop/ImplementationNotFoundException.cs @@ -0,0 +1,9 @@ +namespace MBS.Desktop; + +public class ImplementationNotFoundException : Exception +{ + + public ImplementationNotFoundException() : base("No implementation for the specified IImplementable could be found") { } + public ImplementationNotFoundException(string message) : base(message) { } + public ImplementationNotFoundException(string message, Exception innerException) : base(message, innerException) { } +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/lib/MBS.Desktop/ImplementsForAttribute.cs b/desktop-framework-dotnet/src/lib/MBS.Desktop/ImplementsForAttribute.cs new file mode 100644 index 0000000..0e6b364 --- /dev/null +++ b/desktop-framework-dotnet/src/lib/MBS.Desktop/ImplementsForAttribute.cs @@ -0,0 +1,11 @@ +namespace MBS.Desktop; + +public class ImplementsForAttribute : Attribute +{ + public Type Type { get; } + + public ImplementsForAttribute(Type type) + { + Type = type; + } +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/lib/MBS.Desktop/Layout.cs b/desktop-framework-dotnet/src/lib/MBS.Desktop/Layout.cs new file mode 100644 index 0000000..615dca6 --- /dev/null +++ b/desktop-framework-dotnet/src/lib/MBS.Desktop/Layout.cs @@ -0,0 +1,40 @@ +namespace MBS.Desktop; + +public abstract class Layout : IImplementable +{ + public interface IImplementation + { + + } + + public Implementation? Implementation { get; private set; } + public bool IsCreated { get; private set; } + public virtual void CreateImplementation() + { + if (Implementation == null) + { + // determine which Implementation to use to create this Control + Implementation[] impls = Core.Reflection.TypeLoader.GetAvailableTypes(); + foreach (Implementation impl in impls) + { + if (impl.Supports(GetType())) + { + Implementation = impl; + break; + } + } + } + if (!IsCreated) + { + if (Implementation == null) + { + throw new ImplementationNotFoundException(); + } + Implementation.Create(this); + IsCreated = true; + + // InitializeControlProperties(); + // OnCreated(EventArgs.Empty); + } + } +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/lib/MBS.Desktop/Layouts/BoxLayout.cs b/desktop-framework-dotnet/src/lib/MBS.Desktop/Layouts/BoxLayout.cs new file mode 100644 index 0000000..4294fcd --- /dev/null +++ b/desktop-framework-dotnet/src/lib/MBS.Desktop/Layouts/BoxLayout.cs @@ -0,0 +1,35 @@ +namespace MBS.Desktop.Layouts; + +using MBS.Core; + +public class BoxLayout : Layout +{ + public new interface IImplementation : Layout.IImplementation + { + Orientation GetOrientation(); + void SetOrientation(Orientation value); + } + + private Orientation _Orientation = Orientation.Horizontal; + public Orientation Orientation + { + get + { + if (Implementation is BoxLayout.IImplementation impl) + { + return impl.GetOrientation(); + } + return _Orientation; + } + set + { + (Implementation as BoxLayout.IImplementation)?.SetOrientation(value); + _Orientation = value; + } + } + + public BoxLayout(Orientation orientation = Orientation.Horizontal) + { + Orientation = orientation; + } +} diff --git a/desktop-framework-dotnet/src/lib/MBS.Desktop/MBS.Desktop.csproj b/desktop-framework-dotnet/src/lib/MBS.Desktop/MBS.Desktop.csproj index 020ce4d..a73dd10 100644 --- a/desktop-framework-dotnet/src/lib/MBS.Desktop/MBS.Desktop.csproj +++ b/desktop-framework-dotnet/src/lib/MBS.Desktop/MBS.Desktop.csproj @@ -1,7 +1,7 @@  - + diff --git a/desktop-framework-dotnet/src/lib/MBS.Desktop/NativeHandle.cs b/desktop-framework-dotnet/src/lib/MBS.Desktop/NativeHandle.cs new file mode 100644 index 0000000..9345a40 --- /dev/null +++ b/desktop-framework-dotnet/src/lib/MBS.Desktop/NativeHandle.cs @@ -0,0 +1,5 @@ +namespace MBS.Desktop; + +public abstract class NativeHandle +{ +} \ No newline at end of file diff --git a/desktop-framework-dotnet/src/lib/MBS.Desktop/NativeImplementation.cs b/desktop-framework-dotnet/src/lib/MBS.Desktop/NativeImplementation.cs new file mode 100644 index 0000000..f3642af --- /dev/null +++ b/desktop-framework-dotnet/src/lib/MBS.Desktop/NativeImplementation.cs @@ -0,0 +1,6 @@ +namespace MBS.Desktop; + +public abstract class NativeImplementation : Implementation +{ + +} \ No newline at end of file