Browse Source

avalonia: forms and button thing

Kenric Nugteren 7 months ago
parent
commit
0c6583b5fd

+ 22 - 0
InABox.Avalonia/Components/DateSelector/DateSelectorButton.axaml

@@ -0,0 +1,22 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+			 xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+			 xmlns:components="using:InABox.Avalonia.Components"
+			 x:Class="InABox.Avalonia.Components.DateSelectorButton"
+			 x:DataType="components:DateSelectorButton">
+	<UserControl.Resources>
+		<components:DateSelectorDateTimeFormatter x:Key="dateFormatter"/>
+	</UserControl.Resources>
+	<Button Classes="Standard"
+			Command="{Binding $parent[components:DateSelectorButton].ClickCommand}"
+			Padding="{Binding $parent[components:DateSelectorButton].Padding}"
+			Background="{Binding $parent[components:DateSelectorButton].Background}"
+			BorderBrush="{Binding $parent[components:DateSelectorButton].BorderBrush}"
+			BorderThickness="{Binding $parent[components:DateSelectorButton].BorderThickness}">
+		<Button.Content>
+			<MultiBinding Converter="{StaticResource dateFormatter}">
+				<Binding Path="$parent[components:DateSelectorButton].Date"/>
+				<Binding Path="$parent[components:DateSelectorButton]"/>
+			</MultiBinding>
+		</Button.Content>
+	</Button>
+</UserControl>

+ 83 - 0
InABox.Avalonia/Components/DateSelector/DateSelectorButton.axaml.cs

@@ -0,0 +1,83 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.Primitives;
+using Avalonia.Data.Converters;
+using CommunityToolkit.Mvvm.Input;
+using ExCSS;
+using InABox.Avalonia.Components.DateSelector;
+using InABox.Avalonia.Converters;
+using InABox.Core;
+using System.Globalization;
+using System.Windows.Input;
+
+namespace InABox.Avalonia.Components;
+
+public partial class DateSelectorButton : UserControl
+{
+    public static readonly StyledProperty<string> PromptProperty =
+        AvaloniaProperty.Register<DateSelectorButton, string>(nameof(Prompt));
+    public static readonly StyledProperty<string> PrefixProperty =
+        AvaloniaProperty.Register<DateSelectorButton, string>(nameof(Prefix));
+    public static readonly StyledProperty<string> FormatProperty =
+        AvaloniaProperty.Register<DateSelectorButton, string>(nameof(Format));
+    public static readonly StyledProperty<DateTime?> DateProperty =
+        AvaloniaProperty.Register<DateSelectorButton, DateTime?>(nameof(Date));
+
+    public string Prompt
+    {
+        get => GetValue(PromptProperty);
+        set => SetValue(PromptProperty, value);
+    }
+
+    public string Prefix 
+    {
+        get => GetValue(PrefixProperty);
+        set => SetValue(PrefixProperty, value);
+    }
+
+    public string Format 
+    {
+        get => GetValue(FormatProperty);
+        set => SetValue(FormatProperty, value);
+    }
+
+    public DateTime? Date 
+    {
+        get => GetValue(DateProperty);
+        set => SetValue(DateProperty, value);
+    }
+
+    public DateSelectorButton()
+    {
+        InitializeComponent();
+    }
+
+    [RelayCommand]
+    private async Task Click()
+    {
+        var date = await Navigation.Popup<DateSelectorViewModel, DateTime?>(x =>
+        {
+            x.Date = Date;
+        });
+        if (date.HasValue)
+        {
+            Date = date.Value == DateTime.MinValue ? null : date.Value;
+        }
+    }
+}
+
+public class DateSelectorDateTimeFormatter : IMultiValueConverter
+{
+    public object? Convert(IList<object?> values, Type targetType, object? parameter, CultureInfo culture)
+    {
+        var date = values[0] as DateTime?;
+        if (values[1] is not DateSelectorButton btn) return null;
+        if (date.HasValue && !date.Value.IsEmpty())
+        {
+            var sFormat = btn.Format.NotWhiteSpaceOr("dd MMMM yy");
+            var fmt = "{0} {1:" + sFormat + "}";
+            return string.Format(fmt, btn.Prefix, date.Value).Trim();
+        }
+        return btn.Prompt.NotWhiteSpaceOr("Select Date");
+    }
+}

+ 32 - 0
InABox.Avalonia/Components/DateSelector/DateSelectorView.axaml

@@ -0,0 +1,32 @@
+<UserControl xmlns="https://github.com/avaloniaui"
+             xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+             xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
+             xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
+			 xmlns:selector="using:InABox.Avalonia.Components.DateSelector"
+             mc:Ignorable="d" d:DesignWidth="800" d:DesignHeight="450"
+             x:Class="InABox.Avalonia.Components.DateSelector.DateSelectorView"
+			 x:DataType="selector:DateSelectorViewModel">
+	<Grid Margin="10">
+		<Grid.ColumnDefinitions>
+			<ColumnDefinition Width="Auto"/>
+			<ColumnDefinition Width="*"/>
+			<ColumnDefinition Width="*"/>
+			<ColumnDefinition Width="Auto"/>
+		</Grid.ColumnDefinitions>
+		<Grid.RowDefinitions>
+			<RowDefinition Height="*"/>
+			<RowDefinition Height="Auto"/>
+		</Grid.RowDefinitions>
+		<Calendar SelectedDate="{Binding Date}"
+				  Grid.Row="0"
+				  Grid.Column="0" Grid.ColumnSpan="4"/>
+		<Button Grid.Row="1" Grid.Column="0" Command="{Binding CancelCommand}" Classes="Transparent">
+			<Image Classes="Small" Source="{SvgImage /Images/cross.svg}"/>
+		</Button>
+		<Button Grid.Row="1" Grid.Column="1" Content="Clear" Command="{Binding ClearCommand}" Classes="Standard"/>
+		<Button Grid.Row="1" Grid.Column="2" Content="Today" Command="{Binding TodayCommand}" Classes="Standard"/>
+		<Button Grid.Row="1" Grid.Column="3" Command="{Binding SelectCommand}" Classes="Transparent">
+			<Image Classes="Small" Source="{SvgImage /Images/tick.svg}"/>
+		</Button>
+	</Grid>
+</UserControl>

+ 13 - 0
InABox.Avalonia/Components/DateSelector/DateSelectorView.axaml.cs

@@ -0,0 +1,13 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Markup.Xaml;
+
+namespace InABox.Avalonia.Components.DateSelector;
+
+public partial class DateSelectorView : UserControl
+{
+    public DateSelectorView()
+    {
+        InitializeComponent();
+    }
+}

+ 72 - 0
InABox.Avalonia/Components/DateSelector/DateSelectorViewModel.cs

@@ -0,0 +1,72 @@
+using CommunityToolkit.Mvvm.ComponentModel;
+using CommunityToolkit.Mvvm.Input;
+using DialogHostAvalonia;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace InABox.Avalonia.Components.DateSelector;
+
+public partial class DateSelectorViewModel : ObservableObject, IPopupViewModel<DateTime?>, IViewModelBase
+{
+    [ObservableProperty]
+    private DateTime? _date;
+
+    public bool IsClosed { get; private set; }
+
+    public bool BackButtonVisible { get; set; }
+    public bool ProgressVisible { get; set; }
+    public AvaloniaMenuItemCollection PrimaryMenu { get; set; } = new();
+    public AvaloniaMenuItemCollection SecondaryMenu { get; set; } = new();
+
+
+    private DateTime? _result;
+
+    public DateTime? GetResult()
+    {
+        return _result;
+    }
+
+    public void Close(DateTime? result)
+    {
+        _result = result;
+        IsClosed = true;
+        DialogHost.GetDialogSession(null)?.Close();
+    }
+
+    public Task Activate()
+    {
+        return Task.CompletedTask;
+    }
+
+    public Task Deactivate()
+    {
+        return Task.CompletedTask;
+    }
+
+    [RelayCommand]
+    private void Cancel()
+    {
+        Close(null);
+    }
+
+    [RelayCommand]
+    private void Clear()
+    {
+        Close(DateTime.MinValue);
+    }
+
+    [RelayCommand]
+    private void Today()
+    {
+        Close(DateTime.Today);
+    }
+
+    [RelayCommand]
+    private void Select()
+    {
+        Close(Date);
+    }
+}

+ 1 - 1
InABox.Avalonia/Components/Modules/ModuleGrid/AvaloniaModuleGrid.axaml

@@ -36,7 +36,7 @@
             x:Key="ToolGrid"
             x:DataType="components:AvaloniaModule">
 
-            <Button
+            <Button Classes="Standard"
                 Height="100"
                 Padding="0"
                 Margin="{StaticResource PrsControlSpacing}"

+ 1 - 1
InABox.Avalonia/Components/Modules/ModuleList/AvaloniaModuleList.axaml

@@ -31,7 +31,7 @@
         <DataTemplate
             x:Key="ModuleList"
             x:DataType="components:AvaloniaModule">
-            <Button
+            <Button Classes="Standard"
                 Height="80"
                 Padding="0"
                 Background="{Binding Alert, Converter={StaticResource ModuleAlertBackgroundConverter}}"

+ 8 - 0
InABox.Avalonia/Images/cross.svg

@@ -0,0 +1,8 @@
+<svg height="512" viewBox="0 0 32 32" width="512" xmlns="http://www.w3.org/2000/svg">
+    <g id="Ikon">
+        <circle cx="16" cy="16" fill="#f44336" r="13"/>
+    </g>
+    <g id="Line">
+        <path d="m16 2c-18.498.5857-18.5024 27.4115 0 28 18.4977-.5857 18.5021-27.4116 0-28zm0 26c-15.8552-.502-15.8589-23.4957 0-24 15.8552.502 15.8589 23.4956 0 24zm5.657-16.2432-4.2428 4.2432 4.243 4.2432c.931.9033-.51 2.3453-1.414 1.414l-4.2432-4.2431-4.2429 4.2431c-.9038.9313-2.3449-.5107-1.414-1.414l4.2431-4.2432-4.2429-4.2432c-.9309-.9034.51-2.3452 1.414-1.414l4.2427 4.2431 4.243-4.2431c.9041-.9312 2.3451.5106 1.4142 1.414z"/>
+    </g>
+</svg>

+ 8 - 0
InABox.Avalonia/Images/tick.svg

@@ -0,0 +1,8 @@
+<svg height="512" viewBox="0 0 32 32" width="512" xmlns="http://www.w3.org/2000/svg">
+    <g id="Ikon">
+        <circle cx="16" cy="16" fill="#8bc34a" r="13"/>
+    </g>
+    <g id="Line">
+        <path d="m16 30c-18.5021-.5885-18.4977-27.4143 0-28 18.5021.5885 18.4977 27.4143 0 28zm0-26c-15.8589.5044-15.8551 23.498 0 24 15.8589-.5044 15.8551-23.498 0-24zm7.707 7.8613-9.6924 9.6914a.9994.9994 0 0 1 -1.414 0l-4.3076-4.3076c-.9309-.9034.51-2.3452 1.414-1.414l3.6006 3.6005 8.9854-8.9843c.9039-.9312 2.3449.5106 1.414 1.414z"/>
+    </g>
+</svg>

+ 11 - 0
InABox.Avalonia/InABox.Avalonia.csproj

@@ -11,7 +11,9 @@
     </PropertyGroup>
 
     <ItemGroup>
+      <None Remove="Images\cross.svg" />
       <None Remove="Images\search.svg" />
+      <None Remove="Images\tick.svg" />
     </ItemGroup>
 
     <ItemGroup>
@@ -49,12 +51,21 @@
     </ItemGroup>
 
     <ItemGroup>
+      <AvaloniaResource Include="Images\cross.svg">
+        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+      </AvaloniaResource>
       <AvaloniaResource Include="Images\search.svg">
         <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
       </AvaloniaResource>
+      <AvaloniaResource Include="Images\tick.svg">
+        <CopyToOutputDirectory>PreserveNewest</CopyToOutputDirectory>
+      </AvaloniaResource>
     </ItemGroup>
 
     <ItemGroup>
+      <Compile Update="Components\DateSelector\DateSelectorButton.axaml.cs">
+        <DependentUpon>DateSelectorButton.axaml</DependentUpon>
+      </Compile>
       <Compile Update="Components\ModuleGrid\PrsModuleGrid.axaml.cs">
         <DependentUpon>PrsModuleGrid.axaml</DependentUpon>
         <SubType>Code</SubType>

+ 1 - 1
InABox.Avalonia/Router/Router.cs

@@ -36,7 +36,7 @@ public class Router<TViewModelBase> where TViewModelBase:class
         return viewModel;
     }
 
-    public T InstantiateViewModel<T>(Action<T>? configure) where T:TViewModelBase
+    public T InstantiateViewModel<T>(Action<T>? configure) where T : TViewModelBase
     {
         var result = (T)Convert.ChangeType(CreateViewModel(typeof(T)), typeof(T));
         configure?.Invoke(result);

+ 2 - 2
InABox.Avalonia/Theme/Classes/Button.axaml

@@ -1,7 +1,7 @@
 <Styles xmlns="https://github.com/avaloniaui"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
 
-    <Style Selector="Button">
+    <Style Selector="Button.Standard">
         <Setter Property="HorizontalAlignment" Value="Stretch" />
         <Setter Property="VerticalAlignment" Value="Stretch" />
         <Setter Property="HorizontalContentAlignment" Value="Center" />
@@ -20,7 +20,7 @@
     </Style>
 
     <!-- Disable Hover Effects on Buttons -->
-    <Style Selector="Button:pointerover /template/ ContentPresenter#PART_ContentPresenter">
+    <Style Selector="Button.Standard:pointerover /template/ ContentPresenter#PART_ContentPresenter">
         <Setter Property="BorderBrush" Value="{Binding $parent[Button].BorderBrush}" />
         <Setter Property="BorderThickness" Value="{Binding $parent[Button].BorderThickness}" />
         <Setter Property="Background" Value="{Binding $parent[Button].Background}" />

+ 8 - 0
InABox.Avalonia/Theme/Classes/DateSelectorButton.axaml

@@ -0,0 +1,8 @@
+<Styles xmlns="https://github.com/avaloniaui"
+        xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
+		xmlns:components="using:InABox.Avalonia.Components">
+	<Style Selector="components|DateSelectorButton">
+		<Setter Property="Background" Value="{DynamicResource PrsButtonBackground}"/>
+        <Setter Property="BorderBrush" Value="{DynamicResource PrsButtonBorder}" />
+	</Style>
+</Styles>

+ 14 - 9
InABox.Avalonia/Theme/Classes/ListViewButton.axaml

@@ -14,15 +14,20 @@
 		</Style.Resources>
 		<Setter Property="Template">
 			<ControlTemplate>
-				<Button Height="80"
-						Padding="0"
-						Background="{TemplateBinding Background}"
-						Foreground="{TemplateBinding Foreground}"
-						BorderBrush="{StaticResource PrsTileBorder}"
-						HorizontalContentAlignment="Stretch"
-						VerticalContentAlignment="Stretch"
-						Command="{TemplateBinding Command}"
-						CommandParameter="{TemplateBinding CommandParameter}">
+				<Button Classes="Standard">
+					<Button.Styles>
+						<Style Selector="Button.Standard">
+							<Setter Property="Height" Value="80"/>
+							<Setter Property="Padding" Value="0"/>
+							<Setter Property="Background" Value="{TemplateBinding Background}"/>
+							<Setter Property="Foreground" Value="{TemplateBinding Foreground}"/>
+							<Setter Property="BorderBrush" Value="{StaticResource PrsTileBorder}"/>
+							<Setter Property="HorizontalContentAlignment" Value="Stretch"/>
+							<Setter Property="VerticalContentAlignment" Value="Stretch"/>
+							<Setter Property="Command" Value="{TemplateBinding Command}"/>
+							<Setter Property="CommandParameter" Value="{TemplateBinding CommandParameter}"/>
+						</Style>
+					</Button.Styles>
 					<Grid>
 
 						<Grid.RowDefinitions>

+ 1 - 0
InABox.Avalonia/Theme/Classes/TabItem.axaml

@@ -1,6 +1,7 @@
 <Styles xmlns="https://github.com/avaloniaui"
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
 	<Style Selector="TabControl">
+		<Setter Property="Padding" Value="0"/>
 		<Setter Property="ItemsPanel">
 			<Setter.Value>
 				<ItemsPanelTemplate>

+ 1 - 0
InABox.Avalonia/Theme/Styles.axaml

@@ -12,4 +12,5 @@
 	<StyleInclude Source="/Theme/Classes/ListBox.axaml" />
 	<StyleInclude Source="/Theme/Classes/TabStrip.axaml" />
 	<StyleInclude Source="/Theme/Classes/TabItem.axaml" />
+	<StyleInclude Source="/Theme/Classes/DateSelectorButton.axaml" />
 </Styles>

+ 22 - 23
inabox.wpf/DigitalForms/Designer/Controls/Fields/DFDateControl.cs

@@ -8,34 +8,33 @@ using System.Text;
 using System.Threading.Tasks;
 using System.Windows;
 
-namespace InABox.DynamicGrid
+namespace InABox.DynamicGrid;
+
+public class DFDateControl : DynamicFormFieldControl<DFLayoutDateField, DFLayoutDateFieldProperties, DateTime, DateTime?>
 {
-    public class DFDateControl : DynamicFormFieldControl<DFLayoutDateField, DFLayoutDateFieldProperties, DateTime, DateTime?>
-    {
-        private DateTimeEdit Date = null!; // late-initialising
+    private DateTimeEdit Date = null!; // late-initialising
 
-        protected override FrameworkElement Create()
-        {
-            Date = new DateTimeEdit();
-            Date.DateTimeFormat = CultureInfo.CurrentCulture.DateTimeFormat;
-            Date.Pattern = DateTimePattern.ShortDate;
-            var def = Field.Properties.Default;
-            Date.DateTime = def.IsEmpty()
-                ? DateTime.Now
-                : def;
-            Date.DateTimeChanged += (sender, e) => ChangeField();
-            Date.EnableMouseWheelEdit = false;
-            return Date;
-        }
+    protected override FrameworkElement Create()
+    {
+        Date = new DateTimeEdit();
+        Date.DateTimeFormat = CultureInfo.CurrentCulture.DateTimeFormat;
+        Date.Pattern = DateTimePattern.ShortDate;
+        var def = Field.Properties.Default;
+        Date.DateTime = def.IsEmpty()
+            ? DateTime.Now
+            : def;
+        Date.DateTimeChanged += (sender, e) => ChangeField();
+        Date.EnableMouseWheelEdit = false;
+        return Date;
+    }
 
-        public override DateTime? GetSerializedValue() => Date.DateTime ?? DateTime.MinValue;
+    public override DateTime? GetSerializedValue() => Date.DateTime ?? DateTime.MinValue;
 
-        public override void SetSerializedValue(DateTime? value) => Date.DateTime = value;
+    public override void SetSerializedValue(DateTime? value) => Date.DateTime = value;
 
-        public override DateTime GetValue() => Date.DateTime ?? DateTime.MinValue;
+    public override DateTime GetValue() => Date.DateTime ?? DateTime.MinValue;
 
-        public override void SetValue(DateTime value) => Date.DateTime = value;
+    public override void SetValue(DateTime value) => Date.DateTime = value;
 
-        protected override bool IsEmpty() => Date.DateTime == null || Date.DateTime == DateTime.MinValue;
-    }
+    protected override bool IsEmpty() => Date.DateTime == null || Date.DateTime == DateTime.MinValue;
 }