From 68ac2c96807bacb5c9231fca18957ca72c531294 Mon Sep 17 00:00:00 2001 From: webwarrior Date: Wed, 8 Mar 2023 15:23:57 +0100 Subject: [PATCH 01/10] Core(Gtk): implement date picker cherry pick from https://github.com/nblockchain/Mali/pull/7/commits/33aa7d606071c3599f17138d0037708550f3310c --- .../DatePicker/DatePickerHandler.Gtk.cs | 32 +- src/Core/src/Platform/Gtk/MauiDatePicker.cs | 449 +++++++++++++++++- 2 files changed, 460 insertions(+), 21 deletions(-) diff --git a/src/Core/src/Handlers/DatePicker/DatePickerHandler.Gtk.cs b/src/Core/src/Handlers/DatePicker/DatePickerHandler.Gtk.cs index 9da3f62fbe56..3c22ea883bc6 100644 --- a/src/Core/src/Handlers/DatePicker/DatePickerHandler.Gtk.cs +++ b/src/Core/src/Handlers/DatePicker/DatePickerHandler.Gtk.cs @@ -2,16 +2,30 @@ namespace Microsoft.Maui.Handlers { - public partial class DatePickerHandler : ViewHandler { - protected override MauiDatePicker CreatePlatformView() { return new MauiDatePicker(); } - [MissingMapper] + protected override void ConnectHandler(MauiDatePicker platformView) + { + base.ConnectHandler(platformView); + platformView.DateChanged += DateChanged; + } + + protected override void DisconnectHandler(MauiDatePicker platformView) + { + base.DisconnectHandler(platformView); + platformView.DateChanged -= DateChanged; + } + + private void DateChanged(object? sender, System.EventArgs args) + { + VirtualView.Date = PlatformView.Date; + } + public static partial void MapFormat(IDatePickerHandler handler, IDatePicker datePicker) { handler.PlatformView?.UpdateFormat(datePicker); @@ -24,10 +38,16 @@ public static partial void MapDate(IDatePickerHandler handler, IDatePicker dateP } [MissingMapper] - public static partial void MapMinimumDate(IDatePickerHandler handler, IDatePicker datePicker) { } + public static partial void MapMinimumDate(IDatePickerHandler handler, IDatePicker datePicker) + { + handler.PlatformView.MinDate = handler.VirtualView.MinimumDate; + } [MissingMapper] - public static partial void MapMaximumDate(IDatePickerHandler handler, IDatePicker datePicker) { } + public static partial void MapMaximumDate(IDatePickerHandler handler, IDatePicker datePicker) + { + handler.PlatformView.MaxDate = handler.VirtualView.MaximumDate; + } [MissingMapper] public static partial void MapCharacterSpacing(IDatePickerHandler handler, IDatePicker datePicker) { } @@ -41,7 +61,5 @@ public static partial void MapFont(IDatePickerHandler handler, IDatePicker dateP [MissingMapper] public static partial void MapTextColor(IDatePickerHandler handler, IDatePicker datePicker) { } - } - } \ No newline at end of file diff --git a/src/Core/src/Platform/Gtk/MauiDatePicker.cs b/src/Core/src/Platform/Gtk/MauiDatePicker.cs index d4b185ca7cfe..03197538c8a2 100644 --- a/src/Core/src/Platform/Gtk/MauiDatePicker.cs +++ b/src/Core/src/Platform/Gtk/MauiDatePicker.cs @@ -1,35 +1,456 @@ using System; using System.Runtime.Serialization; +using System.Linq; +using Gtk; +using Microsoft.Maui.Graphics; +using Microsoft.Maui.Graphics.Platform.Gtk; namespace Microsoft.Maui.Platform { - public class MauiDatePicker : Gtk.Label + public class DateEventArgs : EventArgs { + DateTime _date; - public MauiDatePicker() : base() + public DateTime Date { - Format = string.Empty; + get + { + return _date; + } + } + + public DateEventArgs(DateTime date) + { + _date = date; } + } + + public class GrabHelper + { + private static uint CURRENT_TIME = 0; + + public static void GrabWindow(Window window) + { + window.GrabFocus(); -#pragma warning disable 169 - // to simulate - // Tapping either of the DatePicker displays invokes the platform date picker - Gtk.Calendar? _calendar; -#pragma warning restore 169 - - DateTime _time; + Grab.Add(window); + // error CS0612: 'Pointer.Grab(Window, bool, EventMask, Window, Cursor, uint)' is obsolete +#pragma warning disable 612 + Gdk.GrabStatus grabbed = + Gdk.Pointer.Grab(window.Window, true, + Gdk.EventMask.ButtonPressMask + | Gdk.EventMask.ButtonReleaseMask + | Gdk.EventMask.PointerMotionMask, null, null, CURRENT_TIME); +#pragma warning restore 612 + if (grabbed == Gdk.GrabStatus.Success) + { + // error CS0612: 'Keyboard.Grab(Window, bool, uint)' is obsolete +#pragma warning disable 612 + grabbed = Gdk.Keyboard.Grab(window.Window, true, CURRENT_TIME); +#pragma warning restore 612 + if (grabbed != Gdk.GrabStatus.Success) + { + Grab.Remove(window); + window.Destroy(); + } + } + else + { + Grab.Remove(window); + window.Destroy(); + } + } + + public static void RemoveGrab(Window window) + { + Grab.Remove(window); + // error CS0612: 'Pointer.Ungrab(uint)' is obsolete && error CS0612: 'Keyboard.Ungrab(uint)' is obsolete +#pragma warning disable 612 + Gdk.Pointer.Ungrab(CURRENT_TIME); + Gdk.Keyboard.Ungrab(CURRENT_TIME); +#pragma warning restore 612 + } + } + + public partial class DatePickerWindow : Window + { + VBox _datebox; + RangeCalendar _calendar; + public delegate void DateEventHandler(object sender, DateEventArgs args); + + public event DateEventHandler? OnDateTimeChanged; + + public DatePickerWindow() + : base(WindowType.Popup) + { + Title = "DatePicker"; + TypeHint = Gdk.WindowTypeHint.Desktop; + WindowPosition = WindowPosition.Mouse; + BorderWidth = 1; + Resizable = false; + Decorated = false; + DestroyWithParent = true; + SkipPagerHint = true; + SkipTaskbarHint = true; + // error CS0612: 'VBox.VBox()' is obsolete +#pragma warning disable 612 + _datebox = new VBox(); +#pragma warning restore 612 + _datebox.Spacing = 6; + _datebox.BorderWidth = 3; + + _calendar = new RangeCalendar(); + _calendar.CanFocus = true; + _calendar.DisplayOptions = CalendarDisplayOptions.ShowHeading; + _datebox.Add(_calendar); + Box.BoxChild dateBoxChild = ((Box.BoxChild)(_datebox[_calendar])); + dateBoxChild.Position = 0; + + Add(_datebox); + + if ((Child != null)) + { + Child.ShowAll(); + } + + Show(); + ButtonPressEvent += new ButtonPressEventHandler(OnButtonPressEvent); + _calendar.ButtonPressEvent += new ButtonPressEventHandler(OnCalendarButtonPressEvent); + _calendar.DaySelected += new EventHandler(OnCalendarDaySelected); + _calendar.DaySelectedDoubleClick += new EventHandler(OnCalendarDaySelectedDoubleClick); + GrabHelper.GrabWindow(this); + SelectedDate = DateTime.Now; + } + + public DateTime SelectedDate + { + get + { + return _calendar.Date; + } + + set + { + _calendar.Date = value; + } + } + + public DateTime MinimumDate + { + get + { + return _calendar.MinimumDate; + } + + set + { + _calendar.MinimumDate = value; + } + } + + public DateTime MaximumDate + { + get + { + return _calendar.MaximumDate; + } + + set + { + _calendar.MaximumDate = value; + } + } + + protected virtual void OnButtonPressEvent(object sender, ButtonPressEventArgs args) + { + CloseCalendar(); + } + + protected virtual void OnCalendarButtonPressEvent(object sender, ButtonPressEventArgs args) + { + args.RetVal = true; + } + + protected virtual void OnCalendarDaySelected(object? sender, EventArgs eventArgs) + { + OnDateTimeChanged?.Invoke(this, new DateEventArgs(SelectedDate)); + } + + protected virtual void OnCalendarDaySelectedDoubleClick(object? sender, EventArgs eventArgs) + { + OnDateTimeChanged?.Invoke(this, new DateEventArgs(SelectedDate)); + CloseCalendar(); + } + + void CloseCalendar() + { + GrabHelper.RemoveGrab(this); + Destroy(); + } + + void NotifyDateChanged() + { + OnDateTimeChanged?.Invoke(this, new DateEventArgs(SelectedDate)); + } + + class RangeCalendar : Calendar + { + DateTime _minimumDate; + DateTime _maximumDate; + + public RangeCalendar() + { + _minimumDate = new DateTime(1900, 1, 1); + _maximumDate = new DateTime(2199, 1, 1); + } + + public DateTime MinimumDate + { + get + { + return _minimumDate; + } + + set + { + if (MaximumDate < value) + { + throw new InvalidOperationException($"{nameof(MinimumDate)} must be lower than {nameof(MaximumDate)}"); + } + + _minimumDate = value; + } + } + + public DateTime MaximumDate + { + get + { + return _maximumDate; + } + + set + { + if (MinimumDate > value) + { + throw new InvalidOperationException($"{nameof(MaximumDate)} must be greater than {nameof(MinimumDate)}"); + } + + _maximumDate = value; + } + } + + protected override void OnDaySelected() + { + if (Date < MinimumDate) + { + Date = MinimumDate; + } + else if (Date > MaximumDate) + { + Date = MaximumDate; + } + } + } + } + + public class CustomComboBox : Gtk.HBox + { + private Gtk.Entry _entry; + private Gtk.Button _button; + private Gtk.Arrow _arrow; + private Color _color = Colors.Black; + + // error CS0612: 'HBox.HBox()' is obsolete +#pragma warning disable 612 + public CustomComboBox() + { +#pragma warning restore 612 + _entry = new Gtk.Entry(); + _entry.CanFocus = true; + _entry.IsEditable = true; + PackStart(_entry, true, true, 0); + + _button = new Gtk.Button(); + _button.WidthRequest = 30; + _button.CanFocus = true; + // error CS0612: 'Arrow.Arrow(ArrowType, ShadowType)' is obsolete +#pragma warning disable 612 + _arrow = new Gtk.Arrow(Gtk.ArrowType.Down, Gtk.ShadowType.EtchedOut); +#pragma warning restore 612 + _button.Add(_arrow); + PackEnd(_button, false, false, 0); + } + + public Gtk.Entry Entry + { + get + { + return _entry; + } + } + + public Gtk.Button PopupButton + { + get + { + return _button; + } + } + + public Color Color + { + get { return _color; } + set + { + _color = value; + Entry.UpdateTextColor(_color); + } + } + + public void SetBackgroundColor(Gdk.Color color) + { + // error CS0612: 'Widget.ModifyBg(StateType, Color)' is obsolete && error CS0612: 'Widget.OverrideBackgroundColor(StateFlags, RGBA)' is obsolete +#pragma warning disable 612 + ModifyBg(Gtk.StateType.Normal, Colors.Red.ToGdkColor()); + Entry.OverrideBackgroundColor(Gtk.StateFlags.Normal, Colors.Blue.ToGdkRgba()); +#pragma warning restore 612 + } + } + + public class MauiDatePicker : EventBox + { + readonly CustomComboBox _comboBox; + DateTime _currentDate; + string? _dateFormat; + DatePickerWindow? _pickerWindow; + + public event EventHandler DateChanged = new EventHandler((sender, args) => { }); + public event EventHandler GotFocus = new EventHandler((sender, args) => { }); + public event EventHandler LostFocus = new EventHandler((sender, args) => { }); + + public MauiDatePicker() + { + _comboBox = new CustomComboBox(); + Add(_comboBox); + + if ((Child != null)) + Child.ShowAll(); + Show(); + + Date = DateTime.Now; + Format = string.Empty; + MinDate = new DateTime(1900, 1, 1); + MaxDate = new DateTime(2199, 1, 1); + + _comboBox.Entry.CanDefault = false; + _comboBox.Entry.CanFocus = false; + _comboBox.Entry.IsEditable = false; + _comboBox.Entry.SetStateFlags(StateFlags.Normal, true); + _comboBox.Entry.CanFocus = false; + _comboBox.Entry.IsEditable = false; + _comboBox.Entry.FocusGrabbed += new EventHandler(OnEntryFocused); + _comboBox.PopupButton.Clicked += new EventHandler(OnBtnShowCalendarClicked); + } public DateTime Date { - get => _time; + get + { + return _currentDate; + } + set + { + _currentDate = value; + UpdateEntryText(); + } + } + + public DateTime MinDate { get; set; } + + public DateTime MaxDate { get; set; } + + public string? Format + { + get + { + return _dateFormat; + } set { - _time = value; - Text = _time.ToString(); + _dateFormat = value; + UpdateEntryText(); + } + } + + public void SetBackgroundColor(Gdk.Color color) + { + _comboBox.SetBackgroundColor(color); + } + + void ShowPickerWindow() + { + int x = 0; + int y = 0; + + Window.GetOrigin(out x, out y); + y += Allocation.Height; + + var picker = new DatePickerWindow(); + picker.Move(x, y); + picker.SelectedDate = Date; + picker.MinimumDate = MinDate; + picker.MaximumDate = MaxDate; + picker.OnDateTimeChanged += OnPopupDateChanged; + picker.Destroyed += OnPickerClosed; + + _pickerWindow = picker; + } + + void OnPopupDateChanged(object sender, DateEventArgs args) + { + var date = args.Date; + + if (date < MinDate) + { + Date = MinDate; + return; } + + if (date > MaxDate) + { + Date = MaxDate; + return; + } + + Date = args.Date; + DateChanged?.Invoke(this, EventArgs.Empty); + } + + void UpdateEntryText() + { + _comboBox.Entry.Text = _currentDate.ToString(string.IsNullOrEmpty(_dateFormat) ? "D" : _dateFormat); } - public string Format { get; set; } + void OnBtnShowCalendarClicked(object? sender, EventArgs eventArgs) + { + ShowPickerWindow(); + } + void OnEntryFocused(object? sender, EventArgs eventArgs) + { + ShowPickerWindow(); + GotFocus?.Invoke(this, EventArgs.Empty); + } + + void OnPickerClosed(object? sender, EventArgs eventArgs) + { + if (_pickerWindow != null) + { + Remove(_pickerWindow); + LostFocus?.Invoke(this, EventArgs.Empty); + _pickerWindow = null; + } + } } } \ No newline at end of file From dcbd068292a5fa9ef0d7ca837365c0136ea07cbe Mon Sep 17 00:00:00 2001 From: Parham Date: Tue, 14 Mar 2023 16:42:43 +0330 Subject: [PATCH 02/10] Core(Gtk): fix DatePickerWindow crash Fix potential exception if DatePicker is used many times quickly: ``` (GWallet.Frontend.Maui:110296): GLib-GObject-CRITICAL **: 12:14:36.625: g_object_remove_toggle_ref: assertion 'G_IS_OBJECT (object)' failed (GWallet.Frontend.Maui:110296): GLib-GObject-CRITICAL **: 12:14:36.627: g_object_remove_toggle_ref: assertion 'G_IS_OBJECT (object)' failed Marshaling button-press-event signal Exception in Gtk# callback delegate Note: Applications can use GLib.ExceptionManager.UnhandledException to handle the exception. GLib.MissingIntPtrCtorException: Unable to construct instance of type Microsoft.Maui.Platform.DatePickerWindow from native object handle. Instance of managed subclass may have been prematurely disposed. at GLib.ObjectManager.CreateObject(IntPtr raw) at GLib.Object.GetObject(IntPtr o, Boolean owned_ref) at GLib.Value.get_Val() at GLib.SignalClosure.MarshalCallback(IntPtr raw_closure, IntPtr return_val, UInt32 n_param_vals, IntPtr param_values, IntPtr invocation_hint, IntPtr marshal_data) at GLib.ExceptionManager.RaiseUnhandledException(Exception e, Boolean is_terminal) at GLib.SignalClosure.MarshalCallback(IntPtr raw_closure, IntPtr return_val, UInt32 n_param_vals, IntPtr param_values, IntPtr invocation_hint, IntPtr marshal_data) at GLib.Application.Run(String program_name, String[] args) at GLib.Application.Run() at Microsoft.Maui.MauiGtkApplication.Launch(EventArgs args) in /home/ubuntu/geewallet-build/geewallet/dependencies/maui/src/Core/src/Platform/Gtk/MauiGtkApplication.cs:line 127 at Microsoft.Maui.MauiGtkApplication.Run(String[] args) in /home/ubuntu/geewallet-build/geewallet/dependencies/maui/src/Core/src/Platform/Gtk/MauiGtkApplication.cs:line 40 at GWallet.Frontend.Maui.Program.main(String[] _args) in /home/ubuntu/geewallet-build/geewallet/src/GWallet.Frontend.Maui/Platforms/Gtk/Program.fs:line 14 ``` By using Hide instead of Destroy. (cherry picked from commit 7ff3c3a9274a01765dba848b7f01bd65062caccb) --- src/Core/src/Platform/Gtk/MauiDatePicker.cs | 51 ++++++++++++++------- 1 file changed, 35 insertions(+), 16 deletions(-) diff --git a/src/Core/src/Platform/Gtk/MauiDatePicker.cs b/src/Core/src/Platform/Gtk/MauiDatePicker.cs index 03197538c8a2..401509205044 100644 --- a/src/Core/src/Platform/Gtk/MauiDatePicker.cs +++ b/src/Core/src/Platform/Gtk/MauiDatePicker.cs @@ -182,10 +182,21 @@ protected virtual void OnCalendarDaySelectedDoubleClick(object? sender, EventArg CloseCalendar(); } + public void ShowCalendar() + { + if ((Child != null)) + { + Child.ShowAll(); + } + + Show(); + GrabHelper.GrabWindow(this); + } + void CloseCalendar() { GrabHelper.RemoveGrab(this); - Destroy(); + Hide(); } void NotifyDateChanged() @@ -390,21 +401,28 @@ public void SetBackgroundColor(Gdk.Color color) void ShowPickerWindow() { - int x = 0; - int y = 0; + if (_pickerWindow is null) + { + int x = 0; + int y = 0; - Window.GetOrigin(out x, out y); - y += Allocation.Height; + Window.GetOrigin(out x, out y); + y += Allocation.Height; - var picker = new DatePickerWindow(); - picker.Move(x, y); - picker.SelectedDate = Date; - picker.MinimumDate = MinDate; - picker.MaximumDate = MaxDate; - picker.OnDateTimeChanged += OnPopupDateChanged; - picker.Destroyed += OnPickerClosed; + var picker = new DatePickerWindow(); + picker.Move(x, y); + picker.SelectedDate = Date; + picker.MinimumDate = MinDate; + picker.MaximumDate = MaxDate; + picker.OnDateTimeChanged += OnPopupDateChanged; + picker.Destroyed += OnPickerClosed; - _pickerWindow = picker; + _pickerWindow = picker; + } + else + { + _pickerWindow.ShowCalendar(); + } } void OnPopupDateChanged(object sender, DateEventArgs args) @@ -445,11 +463,12 @@ void OnEntryFocused(object? sender, EventArgs eventArgs) void OnPickerClosed(object? sender, EventArgs eventArgs) { - if (_pickerWindow != null) + var window = sender as DatePickerWindow; + + if (window != null) { - Remove(_pickerWindow); + window.Hide(); LostFocus?.Invoke(this, EventArgs.Empty); - _pickerWindow = null; } } } From 0d5c409389f3c8cd02591a4f13986c1363cfaa63 Mon Sep 17 00:00:00 2001 From: webwarrior Date: Tue, 14 Mar 2023 14:45:30 +0100 Subject: [PATCH 03/10] Core(Gtk): fix calendar position Fix position of calendar pop-up when opened more than one time. (cherry picked from commit 1dcf7a9721ae8f246472212c632d3d81c065670f) --- src/Core/src/Platform/Gtk/MauiDatePicker.cs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/src/Core/src/Platform/Gtk/MauiDatePicker.cs b/src/Core/src/Platform/Gtk/MauiDatePicker.cs index 401509205044..d2bc367c810d 100644 --- a/src/Core/src/Platform/Gtk/MauiDatePicker.cs +++ b/src/Core/src/Platform/Gtk/MauiDatePicker.cs @@ -401,14 +401,14 @@ public void SetBackgroundColor(Gdk.Color color) void ShowPickerWindow() { - if (_pickerWindow is null) - { - int x = 0; - int y = 0; + int x = 0; + int y = 0; - Window.GetOrigin(out x, out y); - y += Allocation.Height; + Window.GetOrigin(out x, out y); + y += Allocation.Height; + if (_pickerWindow is null) + { var picker = new DatePickerWindow(); picker.Move(x, y); picker.SelectedDate = Date; @@ -416,11 +416,11 @@ void ShowPickerWindow() picker.MaximumDate = MaxDate; picker.OnDateTimeChanged += OnPopupDateChanged; picker.Destroyed += OnPickerClosed; - _pickerWindow = picker; } else { + _pickerWindow.Move(x, y); _pickerWindow.ShowCalendar(); } } From aec2b7d3cd0934e6c2a18d654b8130f6362ae93b Mon Sep 17 00:00:00 2001 From: webwarrior Date: Mon, 13 Mar 2023 14:47:07 +0100 Subject: [PATCH 04/10] Core(Gtk): no excessive OnDateTimeChanged events Avoid excessive firing of OnDateTimeChanged events when creating DatePickerWindow. (cherry picked from commit a1efe23f3e91207422e0e49e79bb5b8237639456) --- src/Core/src/Platform/Gtk/MauiDatePicker.cs | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/src/Core/src/Platform/Gtk/MauiDatePicker.cs b/src/Core/src/Platform/Gtk/MauiDatePicker.cs index d2bc367c810d..1fdff73b70d7 100644 --- a/src/Core/src/Platform/Gtk/MauiDatePicker.cs +++ b/src/Core/src/Platform/Gtk/MauiDatePicker.cs @@ -80,7 +80,7 @@ public partial class DatePickerWindow : Window public event DateEventHandler? OnDateTimeChanged; - public DatePickerWindow() + public DatePickerWindow(DateTime initialDate) : base(WindowType.Popup) { Title = "DatePicker"; @@ -113,13 +113,13 @@ public DatePickerWindow() Child.ShowAll(); } + SelectedDate = initialDate; Show(); ButtonPressEvent += new ButtonPressEventHandler(OnButtonPressEvent); _calendar.ButtonPressEvent += new ButtonPressEventHandler(OnCalendarButtonPressEvent); _calendar.DaySelected += new EventHandler(OnCalendarDaySelected); _calendar.DaySelectedDoubleClick += new EventHandler(OnCalendarDaySelectedDoubleClick); GrabHelper.GrabWindow(this); - SelectedDate = DateTime.Now; } public DateTime SelectedDate @@ -409,9 +409,8 @@ void ShowPickerWindow() if (_pickerWindow is null) { - var picker = new DatePickerWindow(); + var picker = new DatePickerWindow(Date); picker.Move(x, y); - picker.SelectedDate = Date; picker.MinimumDate = MinDate; picker.MaximumDate = MaxDate; picker.OnDateTimeChanged += OnPopupDateChanged; From 64bf21539055d1078e19163aab870b63645d2138 Mon Sep 17 00:00:00 2001 From: webwarrior Date: Wed, 15 Mar 2023 10:14:25 +0100 Subject: [PATCH 05/10] Core(Gtk): update calendar properties Update calendar properties SelectedDate, MinimumDate, MaximumDate when opening calendar popup when it is already created but hidden. (cherry picked from commit fe92c90fc2920429074cfc365f3150e24e5693b0) --- src/Core/src/Platform/Gtk/MauiDatePicker.cs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/src/Core/src/Platform/Gtk/MauiDatePicker.cs b/src/Core/src/Platform/Gtk/MauiDatePicker.cs index 1fdff73b70d7..ab3bb61b58a1 100644 --- a/src/Core/src/Platform/Gtk/MauiDatePicker.cs +++ b/src/Core/src/Platform/Gtk/MauiDatePicker.cs @@ -419,6 +419,10 @@ void ShowPickerWindow() } else { + if (_pickerWindow.SelectedDate != Date) + _pickerWindow.SelectedDate = Date; + _pickerWindow.MinimumDate = MinDate; + _pickerWindow.MaximumDate = MaxDate; _pickerWindow.Move(x, y); _pickerWindow.ShowCalendar(); } From 9fd3320a0d263b0317520bbafe6144f8b7174c31 Mon Sep 17 00:00:00 2001 From: Parham Date: Wed, 15 Mar 2023 15:36:22 +0330 Subject: [PATCH 06/10] Core(Gtk): fix datePicker window position DatePicker window location was wrong when we didn't use x11 GdkBackend. This problem was fixed by setting the TransientFor property. Co-authored-by: webwarrior-ws (cherry picked from commit 003233971e66f87083654500e1468db0886c19fa) --- src/Core/src/Platform/Gtk/MauiDatePicker.cs | 8 +++++--- 1 file changed, 5 insertions(+), 3 deletions(-) diff --git a/src/Core/src/Platform/Gtk/MauiDatePicker.cs b/src/Core/src/Platform/Gtk/MauiDatePicker.cs index ab3bb61b58a1..80ebd8995010 100644 --- a/src/Core/src/Platform/Gtk/MauiDatePicker.cs +++ b/src/Core/src/Platform/Gtk/MauiDatePicker.cs @@ -80,9 +80,11 @@ public partial class DatePickerWindow : Window public event DateEventHandler? OnDateTimeChanged; - public DatePickerWindow(DateTime initialDate) + public DatePickerWindow(DateTime initialDate, Window? parentWindow) : base(WindowType.Popup) { + if (parentWindow is not null) + TransientFor = parentWindow; Title = "DatePicker"; TypeHint = Gdk.WindowTypeHint.Desktop; WindowPosition = WindowPosition.Mouse; @@ -409,7 +411,7 @@ void ShowPickerWindow() if (_pickerWindow is null) { - var picker = new DatePickerWindow(Date); + var picker = new DatePickerWindow(Date, this.Toplevel as Window); picker.Move(x, y); picker.MinimumDate = MinDate; picker.MaximumDate = MaxDate; @@ -423,8 +425,8 @@ void ShowPickerWindow() _pickerWindow.SelectedDate = Date; _pickerWindow.MinimumDate = MinDate; _pickerWindow.MaximumDate = MaxDate; - _pickerWindow.Move(x, y); _pickerWindow.ShowCalendar(); + _pickerWindow.Move(x, y); } } From 5c357d1e298cbb3d6cce22e21f7101c5124cdf41 Mon Sep 17 00:00:00 2001 From: Parham Date: Wed, 15 Mar 2023 16:56:05 +0330 Subject: [PATCH 07/10] Core(GTK): fix obsolete method calls in datepicker Replace deprecated methods. Used Entry icon instead of defining a new button for datepicker arrow. Co-authored-by: webwarrior-ws (cherry picked from commit 8c3d7c2f58e097930ae92dfd72acf78e0bca7c7c) --- src/Core/src/Platform/Gtk/MauiDatePicker.cs | 84 +++------------------ 1 file changed, 10 insertions(+), 74 deletions(-) diff --git a/src/Core/src/Platform/Gtk/MauiDatePicker.cs b/src/Core/src/Platform/Gtk/MauiDatePicker.cs index 80ebd8995010..196b2ee18a4d 100644 --- a/src/Core/src/Platform/Gtk/MauiDatePicker.cs +++ b/src/Core/src/Platform/Gtk/MauiDatePicker.cs @@ -27,34 +27,14 @@ public DateEventArgs(DateTime date) public class GrabHelper { - private static uint CURRENT_TIME = 0; - public static void GrabWindow(Window window) { window.GrabFocus(); Grab.Add(window); - // error CS0612: 'Pointer.Grab(Window, bool, EventMask, Window, Cursor, uint)' is obsolete -#pragma warning disable 612 Gdk.GrabStatus grabbed = - Gdk.Pointer.Grab(window.Window, true, - Gdk.EventMask.ButtonPressMask - | Gdk.EventMask.ButtonReleaseMask - | Gdk.EventMask.PointerMotionMask, null, null, CURRENT_TIME); -#pragma warning restore 612 - if (grabbed == Gdk.GrabStatus.Success) - { - // error CS0612: 'Keyboard.Grab(Window, bool, uint)' is obsolete -#pragma warning disable 612 - grabbed = Gdk.Keyboard.Grab(window.Window, true, CURRENT_TIME); -#pragma warning restore 612 - if (grabbed != Gdk.GrabStatus.Success) - { - Grab.Remove(window); - window.Destroy(); - } - } - else + Gdk.Display.Default.DefaultSeat.Grab(window.Window, Gdk.SeatCapabilities.All, true, null, null, null); + if (grabbed != Gdk.GrabStatus.Success) { Grab.Remove(window); window.Destroy(); @@ -64,17 +44,13 @@ public static void GrabWindow(Window window) public static void RemoveGrab(Window window) { Grab.Remove(window); - // error CS0612: 'Pointer.Ungrab(uint)' is obsolete && error CS0612: 'Keyboard.Ungrab(uint)' is obsolete -#pragma warning disable 612 - Gdk.Pointer.Ungrab(CURRENT_TIME); - Gdk.Keyboard.Ungrab(CURRENT_TIME); -#pragma warning restore 612 + Gdk.Display.Default.DefaultSeat.Ungrab(); } } public partial class DatePickerWindow : Window { - VBox _datebox; + Box _datebox; RangeCalendar _calendar; public delegate void DateEventHandler(object sender, DateEventArgs args); @@ -87,18 +63,14 @@ public DatePickerWindow(DateTime initialDate, Window? parentWindow) TransientFor = parentWindow; Title = "DatePicker"; TypeHint = Gdk.WindowTypeHint.Desktop; - WindowPosition = WindowPosition.Mouse; + WindowPosition = WindowPosition.None; BorderWidth = 1; Resizable = false; Decorated = false; DestroyWithParent = true; SkipPagerHint = true; SkipTaskbarHint = true; - // error CS0612: 'VBox.VBox()' is obsolete -#pragma warning disable 612 - _datebox = new VBox(); -#pragma warning restore 612 - _datebox.Spacing = 6; + _datebox = new Box(Orientation.Vertical, 6); _datebox.BorderWidth = 3; _calendar = new RangeCalendar(); @@ -267,32 +239,18 @@ protected override void OnDaySelected() } } - public class CustomComboBox : Gtk.HBox + public class CustomComboBox : Gtk.Box { private Gtk.Entry _entry; - private Gtk.Button _button; - private Gtk.Arrow _arrow; private Color _color = Colors.Black; - // error CS0612: 'HBox.HBox()' is obsolete -#pragma warning disable 612 - public CustomComboBox() + public CustomComboBox() : base(Orientation.Horizontal, 0) { -#pragma warning restore 612 _entry = new Gtk.Entry(); _entry.CanFocus = true; _entry.IsEditable = true; + _entry.SetIconFromIconName(Gtk.EntryIconPosition.Secondary, "pan-down-symbolic"); PackStart(_entry, true, true, 0); - - _button = new Gtk.Button(); - _button.WidthRequest = 30; - _button.CanFocus = true; - // error CS0612: 'Arrow.Arrow(ArrowType, ShadowType)' is obsolete -#pragma warning disable 612 - _arrow = new Gtk.Arrow(Gtk.ArrowType.Down, Gtk.ShadowType.EtchedOut); -#pragma warning restore 612 - _button.Add(_arrow); - PackEnd(_button, false, false, 0); } public Gtk.Entry Entry @@ -303,14 +261,6 @@ public Gtk.Entry Entry } } - public Gtk.Button PopupButton - { - get - { - return _button; - } - } - public Color Color { get { return _color; } @@ -320,15 +270,6 @@ public Color Color Entry.UpdateTextColor(_color); } } - - public void SetBackgroundColor(Gdk.Color color) - { - // error CS0612: 'Widget.ModifyBg(StateType, Color)' is obsolete && error CS0612: 'Widget.OverrideBackgroundColor(StateFlags, RGBA)' is obsolete -#pragma warning disable 612 - ModifyBg(Gtk.StateType.Normal, Colors.Red.ToGdkColor()); - Entry.OverrideBackgroundColor(Gtk.StateFlags.Normal, Colors.Blue.ToGdkRgba()); -#pragma warning restore 612 - } } public class MauiDatePicker : EventBox @@ -363,7 +304,7 @@ public MauiDatePicker() _comboBox.Entry.CanFocus = false; _comboBox.Entry.IsEditable = false; _comboBox.Entry.FocusGrabbed += new EventHandler(OnEntryFocused); - _comboBox.PopupButton.Clicked += new EventHandler(OnBtnShowCalendarClicked); + _comboBox.Entry.IconPress += new Gtk.IconPressHandler(OnBtnShowCalendarClicked); } public DateTime Date @@ -396,11 +337,6 @@ public string? Format } } - public void SetBackgroundColor(Gdk.Color color) - { - _comboBox.SetBackgroundColor(color); - } - void ShowPickerWindow() { int x = 0; From 117c9810f6bd066a5fedccd01da6a78511fb6c59 Mon Sep 17 00:00:00 2001 From: lytico Date: Wed, 20 Mar 2024 01:59:09 +0100 Subject: [PATCH 08/10] [Gtk] Core.csproj: DatePicker: cleanup code --- .../DatePicker/DatePickerHandler.Gtk.cs | 3 - src/Core/src/Platform/Gtk/MauiDatePicker.cs | 60 +++++++------------ 2 files changed, 21 insertions(+), 42 deletions(-) diff --git a/src/Core/src/Handlers/DatePicker/DatePickerHandler.Gtk.cs b/src/Core/src/Handlers/DatePicker/DatePickerHandler.Gtk.cs index 3c22ea883bc6..e8f0d5103da0 100644 --- a/src/Core/src/Handlers/DatePicker/DatePickerHandler.Gtk.cs +++ b/src/Core/src/Handlers/DatePicker/DatePickerHandler.Gtk.cs @@ -31,19 +31,16 @@ public static partial void MapFormat(IDatePickerHandler handler, IDatePicker dat handler.PlatformView?.UpdateFormat(datePicker); } - [MissingMapper] public static partial void MapDate(IDatePickerHandler handler, IDatePicker datePicker) { handler.PlatformView?.UpdateDate(datePicker); } - [MissingMapper] public static partial void MapMinimumDate(IDatePickerHandler handler, IDatePicker datePicker) { handler.PlatformView.MinDate = handler.VirtualView.MinimumDate; } - [MissingMapper] public static partial void MapMaximumDate(IDatePickerHandler handler, IDatePicker datePicker) { handler.PlatformView.MaxDate = handler.VirtualView.MaximumDate; diff --git a/src/Core/src/Platform/Gtk/MauiDatePicker.cs b/src/Core/src/Platform/Gtk/MauiDatePicker.cs index 196b2ee18a4d..f41d9bb7bfeb 100644 --- a/src/Core/src/Platform/Gtk/MauiDatePicker.cs +++ b/src/Core/src/Platform/Gtk/MauiDatePicker.cs @@ -1,9 +1,6 @@ using System; -using System.Runtime.Serialization; -using System.Linq; using Gtk; using Microsoft.Maui.Graphics; -using Microsoft.Maui.Graphics.Platform.Gtk; namespace Microsoft.Maui.Platform { @@ -52,6 +49,7 @@ public partial class DatePickerWindow : Window { Box _datebox; RangeCalendar _calendar; + public delegate void DateEventHandler(object sender, DateEventArgs args); public event DateEventHandler? OnDateTimeChanged; @@ -82,10 +80,7 @@ public DatePickerWindow(DateTime initialDate, Window? parentWindow) Add(_datebox); - if ((Child != null)) - { - Child.ShowAll(); - } + Child?.ShowAll(); SelectedDate = initialDate; Show(); @@ -158,10 +153,7 @@ protected virtual void OnCalendarDaySelectedDoubleClick(object? sender, EventArg public void ShowCalendar() { - if ((Child != null)) - { - Child.ShowAll(); - } + Child?.ShowAll(); Show(); GrabHelper.GrabWindow(this); @@ -180,14 +172,8 @@ void NotifyDateChanged() class RangeCalendar : Calendar { - DateTime _minimumDate; - DateTime _maximumDate; - - public RangeCalendar() - { - _minimumDate = new DateTime(1900, 1, 1); - _maximumDate = new DateTime(2199, 1, 1); - } + DateTime _minimumDate = new(1900, 1, 1); + DateTime _maximumDate = new(2199, 1, 1); public DateTime MinimumDate { @@ -239,21 +225,21 @@ protected override void OnDaySelected() } } - public class CustomComboBox : Gtk.Box + public class CustomComboBox : Box { - private Gtk.Entry _entry; - private Color _color = Colors.Black; + Entry _entry; + Color _color = Colors.Black; public CustomComboBox() : base(Orientation.Horizontal, 0) { - _entry = new Gtk.Entry(); + _entry = new Entry(); _entry.CanFocus = true; _entry.IsEditable = true; - _entry.SetIconFromIconName(Gtk.EntryIconPosition.Secondary, "pan-down-symbolic"); + _entry.SetIconFromIconName(EntryIconPosition.Secondary, "pan-down-symbolic"); PackStart(_entry, true, true, 0); } - public Gtk.Entry Entry + public Entry Entry { get { @@ -288,8 +274,7 @@ public MauiDatePicker() _comboBox = new CustomComboBox(); Add(_comboBox); - if ((Child != null)) - Child.ShowAll(); + Child?.ShowAll(); Show(); Date = DateTime.Now; @@ -304,7 +289,7 @@ public MauiDatePicker() _comboBox.Entry.CanFocus = false; _comboBox.Entry.IsEditable = false; _comboBox.Entry.FocusGrabbed += new EventHandler(OnEntryFocused); - _comboBox.Entry.IconPress += new Gtk.IconPressHandler(OnBtnShowCalendarClicked); + _comboBox.Entry.IconPress += new IconPressHandler(OnBtnShowCalendarClicked); } public DateTime Date @@ -339,15 +324,12 @@ public string? Format void ShowPickerWindow() { - int x = 0; - int y = 0; - - Window.GetOrigin(out x, out y); + Window.GetOrigin(out var x, out var y); y += Allocation.Height; - if (_pickerWindow is null) + if (_pickerWindow is not { }) { - var picker = new DatePickerWindow(Date, this.Toplevel as Window); + var picker = new DatePickerWindow(Date, Toplevel as Window); picker.Move(x, y); picker.MinimumDate = MinDate; picker.MaximumDate = MaxDate; @@ -404,13 +386,13 @@ void OnEntryFocused(object? sender, EventArgs eventArgs) void OnPickerClosed(object? sender, EventArgs eventArgs) { - var window = sender as DatePickerWindow; - - if (window != null) + if (sender is not DatePickerWindow window) { - window.Hide(); - LostFocus?.Invoke(this, EventArgs.Empty); + return; } + + window.Hide(); + LostFocus?.Invoke(this, EventArgs.Empty); } } } \ No newline at end of file From 1e5efc755ce479ffc9adff28df242a3f590da541 Mon Sep 17 00:00:00 2001 From: lytico Date: Wed, 20 Mar 2024 02:10:43 +0100 Subject: [PATCH 09/10] [Gtk] Core.csproj: DatePicker: more rider optimazations --- src/Core/src/Platform/Gtk/MauiDatePicker.cs | 47 ++++++--------------- 1 file changed, 13 insertions(+), 34 deletions(-) diff --git a/src/Core/src/Platform/Gtk/MauiDatePicker.cs b/src/Core/src/Platform/Gtk/MauiDatePicker.cs index f41d9bb7bfeb..e011750dac59 100644 --- a/src/Core/src/Platform/Gtk/MauiDatePicker.cs +++ b/src/Core/src/Platform/Gtk/MauiDatePicker.cs @@ -4,22 +4,9 @@ namespace Microsoft.Maui.Platform { - public class DateEventArgs : EventArgs + public class DateEventArgs(DateTime date) : EventArgs { - DateTime _date; - - public DateTime Date - { - get - { - return _date; - } - } - - public DateEventArgs(DateTime date) - { - _date = date; - } + public DateTime Date { get; } = date; } public class GrabHelper @@ -47,7 +34,6 @@ public static void RemoveGrab(Window window) public partial class DatePickerWindow : Window { - Box _datebox; RangeCalendar _calendar; public delegate void DateEventHandler(object sender, DateEventArgs args); @@ -68,17 +54,17 @@ public DatePickerWindow(DateTime initialDate, Window? parentWindow) DestroyWithParent = true; SkipPagerHint = true; SkipTaskbarHint = true; - _datebox = new Box(Orientation.Vertical, 6); - _datebox.BorderWidth = 3; + var datebox = new Box(Orientation.Vertical, 6); + datebox.BorderWidth = 3; _calendar = new RangeCalendar(); _calendar.CanFocus = true; _calendar.DisplayOptions = CalendarDisplayOptions.ShowHeading; - _datebox.Add(_calendar); - Box.BoxChild dateBoxChild = ((Box.BoxChild)(_datebox[_calendar])); + datebox.Add(_calendar); + Box.BoxChild dateBoxChild = ((Box.BoxChild)(datebox[_calendar])); dateBoxChild.Position = 0; - Add(_datebox); + Add(datebox); Child?.ShowAll(); @@ -227,25 +213,18 @@ protected override void OnDaySelected() public class CustomComboBox : Box { - Entry _entry; Color _color = Colors.Black; public CustomComboBox() : base(Orientation.Horizontal, 0) { - _entry = new Entry(); - _entry.CanFocus = true; - _entry.IsEditable = true; - _entry.SetIconFromIconName(EntryIconPosition.Secondary, "pan-down-symbolic"); - PackStart(_entry, true, true, 0); + Entry = new Entry(); + Entry.CanFocus = true; + Entry.IsEditable = true; + Entry.SetIconFromIconName(EntryIconPosition.Secondary, "pan-down-symbolic"); + PackStart(Entry, true, true, 0); } - public Entry Entry - { - get - { - return _entry; - } - } + public Entry Entry { get; } public Color Color { From a824112584c160d07694e3bd44032e017a617d81 Mon Sep 17 00:00:00 2001 From: lytico Date: Wed, 20 Mar 2024 02:14:27 +0100 Subject: [PATCH 10/10] [Gtk] Core.csproj: DatePicker: more rider optimizations II --- src/Core/src/Platform/Gtk/MauiDatePicker.cs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/src/Core/src/Platform/Gtk/MauiDatePicker.cs b/src/Core/src/Platform/Gtk/MauiDatePicker.cs index e011750dac59..48fffe19d5f0 100644 --- a/src/Core/src/Platform/Gtk/MauiDatePicker.cs +++ b/src/Core/src/Platform/Gtk/MauiDatePicker.cs @@ -16,7 +16,7 @@ public static void GrabWindow(Window window) window.GrabFocus(); Grab.Add(window); - Gdk.GrabStatus grabbed = + var grabbed = Gdk.Display.Default.DefaultSeat.Grab(window.Window, Gdk.SeatCapabilities.All, true, null, null, null); if (grabbed != Gdk.GrabStatus.Success) { @@ -61,7 +61,7 @@ public DatePickerWindow(DateTime initialDate, Window? parentWindow) _calendar.CanFocus = true; _calendar.DisplayOptions = CalendarDisplayOptions.ShowHeading; datebox.Add(_calendar); - Box.BoxChild dateBoxChild = ((Box.BoxChild)(datebox[_calendar])); + var dateBoxChild = ((Box.BoxChild)(datebox[_calendar])); dateBoxChild.Position = 0; Add(datebox);