Преглед на файлове

avalonia: adjusted layouting of forms and added boolean and option fields

Kenric Nugteren преди 2 месеца
родител
ревизия
3ff3c1debd

+ 1 - 0
PRS.Avalonia/PRS.Avalonia/Components/FormsEditor/Controls/DFHeaderControl.cs

@@ -32,6 +32,7 @@ partial class DFHeaderControl : DigitalFormControl<DFLayoutHeader>
         {
             HorizontalContentAlignment = HorizontalAlignment.Stretch,
             VerticalContentAlignment = VerticalAlignment.Stretch,
+            Margin = new()
         };
         button.Classes.Add("Standard");
         button.Command = ClickCommand;

+ 5 - 3
PRS.Avalonia/PRS.Avalonia/Components/FormsEditor/DigitalFormViewer.axaml.cs

@@ -51,6 +51,8 @@ public partial class DigitalFormViewer : UserControl, IDFRenderer
 
     private readonly SolidColorBrush RequiredFieldBrush = new(Colors.Orange);
 
+    private static double RowMinHeight = 35;
+
     static DigitalFormViewer()
     {
         LayoutProperty.Changed.AddClassHandler<DigitalFormViewer>(Layout_Changed);
@@ -134,7 +136,7 @@ public partial class DigitalFormViewer : UserControl, IDFRenderer
             else
             {
                 rowDefinition.Height = StringToGridLength(Layout.RowHeights[row]);
-                rowDefinition.MinHeight = 50;
+                rowDefinition.MinHeight = RowMinHeight;
             }
         }
         foreach(var (item, element) in _elementMap)
@@ -165,7 +167,7 @@ public partial class DigitalFormViewer : UserControl, IDFRenderer
         if (column <= 0) return;
         if (row <= 0) return;
 
-        element.MinHeight = 50.0F;
+        element.MinHeight = RowMinHeight;
         element.MinWidth = 50.0F;
         Grid.SetRow(element, row - 1);
         Grid.SetColumn(element, column - 1);
@@ -284,7 +286,7 @@ public partial class DigitalFormViewer : UserControl, IDFRenderer
             Grid.ColumnDefinitions.Add(new ColumnDefinition { Width = StringToGridLength(column) });
 
         foreach (var row in Layout.RowHeights)
-            Grid.RowDefinitions.Add(new RowDefinition { Height = StringToGridLength(row), MinHeight = 50 });
+            Grid.RowDefinitions.Add(new RowDefinition { Height = StringToGridLength(row), MinHeight = RowMinHeight });
 
         foreach (var item in Layout.GetElements(false))
         {

+ 53 - 0
PRS.Avalonia/PRS.Avalonia/Components/FormsEditor/Fields/DFBooleanFieldControl.cs

@@ -0,0 +1,53 @@
+using Avalonia.Controls;
+using Avalonia.Media;
+using InABox.Core;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PRS.Avalonia.DigitalForms;
+
+class DFBooleanFieldControl : DigitalFormFieldControl<DFLayoutBooleanField, DFLayoutBooleanFieldProperties, bool, bool?>
+{
+    private IOptionControl OptionControl = null!; // Late-initialised
+
+    protected override Control Create()
+    {
+        var options = new[] { Field.Properties.TrueValue, Field.Properties.FalseValue };
+        return SetControl(new ButtonsOptionControl(options, ChangeField));
+    }
+
+    private T SetControl<T>(T value)
+        where T : Control, IOptionControl
+    {
+        OptionControl = value;
+        return value;
+    }
+
+    public override bool? GetSerializedValue()
+    {
+        return GetValue();
+    }
+
+    public override void SetSerializedValue(bool? value)
+    {
+        SetValue(value ?? false);
+    }
+
+    public override bool GetValue() => OptionControl.GetValue() == Field.Properties.TrueValue;
+
+    public override void SetValue(bool value) => OptionControl.SetValue(value ? Field.Properties.TrueValue : Field.Properties.FalseValue);
+
+    protected override bool IsEmpty() => Field.Properties.Type switch
+    {
+        DesignBooleanFieldType.Checkbox => GetValue() != true,
+        _ => OptionControl.IsEmpty()
+    };
+
+    public override void SetBackground(IBrush brush)
+    {
+        OptionControl.Background = brush;
+    }
+}

+ 213 - 0
PRS.Avalonia/PRS.Avalonia/Components/FormsEditor/Fields/DFOptionFieldControl.cs

@@ -0,0 +1,213 @@
+using Avalonia;
+using Avalonia.Controls;
+using Avalonia.Controls.Primitives;
+using Avalonia.Data;
+using Avalonia.Layout;
+using Avalonia.Media;
+using InABox.Core;
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PRS.Avalonia.DigitalForms;
+
+internal interface IOptionControl
+{
+    IBrush? Background { get; set; }
+
+    public string? GetValue();
+    public void SetValue(string value);
+
+    public bool IsEmpty();
+}
+public class ButtonsOptionControl : ContentControl, IOptionControl
+{
+    private readonly Action OnChanged;
+
+    private TabStrip _tabStrip;
+
+    public ButtonsOptionControl(string[] options, Action onChanged)
+    {
+        OnChanged = onChanged;
+
+        _tabStrip = new TabStrip();
+        _tabStrip.Classes.Add("ButtonsList");
+
+        foreach (var option in options)
+        {
+            var item = new TabStripItem
+            {
+                Content = option.Replace("\r", "").Replace("\n", ""),
+                Tag = option
+            };
+            _tabStrip.Items.Add(item);
+        }
+        _tabStrip.SelectedValueBinding = new Binding("Tag");
+
+        _tabStrip.SelectionChanged += ButtonsOptionControl_SelectionChanged;
+
+        Content = _tabStrip;
+    }
+
+    private void ButtonsOptionControl_SelectionChanged(object? sender, SelectionChangedEventArgs e)
+    {
+        OnChanged();
+    }
+
+    public string? GetValue()
+    {
+        return _tabStrip.SelectedValue as string;
+    }
+
+    public void SetValue(string value)
+    {
+        _tabStrip.SelectedValue = value;
+    }
+
+    public bool IsEmpty() => GetValue() == null;
+}
+
+public class RadioOptionControl : Grid, IOptionControl
+{
+    private Action OnChanged;
+
+    public RadioOptionControl(string[] options, Action onChanged)
+    {
+        Margin = new Thickness(4, 2, 4, 2);
+        
+        OnChanged = onChanged;
+
+        foreach (var option in options)
+        {
+            RowDefinitions.Add(new RowDefinition() { Height = new GridLength(1, GridUnitType.Auto) });
+            var button = new RadioButton();
+            button.Margin = new Thickness(0, 2, 0, 2);
+            button.Content = option.Replace("\r", "").Replace("\n", "");
+            button.VerticalContentAlignment = VerticalAlignment.Center;
+            button.Padding = new Thickness(5.0F, 0.0F, 5.0F, 0.0F);
+            button.SetValue(RowProperty, Children.Count);
+            button.Tag = option;
+            button.IsCheckedChanged += Button_IsCheckedChanged;
+            Children.Add(button);
+        }
+    }
+
+    private void Button_IsCheckedChanged(object? sender, global::Avalonia.Interactivity.RoutedEventArgs e)
+    {
+        OnChanged();
+    }
+
+    public string? GetValue()
+    {
+        foreach (var child in Children)
+        {
+            if (child is RadioButton radio)
+            {
+                if (radio.IsChecked == true)
+                {
+                    return radio.Tag as string;
+                }
+            }
+        }
+        return null;
+    }
+
+    public void SetValue(string value)
+    {
+        foreach (var child in Children)
+        {
+            if (child is RadioButton radio)
+            {
+                if (radio.Tag as string == value)
+                {
+                    radio.IsChecked = true;
+                }
+            }
+        }
+    }
+    public bool IsEmpty() => GetValue() == null;
+}
+
+public class ComboBoxOptionControl : ComboBox, IOptionControl
+{
+    private readonly Action OnChanged;
+
+    public ComboBoxOptionControl(string[] options, Action onChanged)
+    {
+        // SetResourceReference(StyleProperty, typeof(ComboBox));
+
+        OnChanged = onChanged;
+
+        foreach (var option in options)
+            Items.Add(option);
+        VerticalContentAlignment = VerticalAlignment.Center;
+        SelectionChanged += ComboBoxOptionControl_SelectionChanged;
+    }
+
+    private void ComboBoxOptionControl_SelectionChanged(object? sender, SelectionChangedEventArgs e)
+    {
+        OnChanged();
+    }
+
+    public string? GetValue()
+    {
+        return SelectedValue as string;
+    }
+
+    public void SetValue(string value)
+    {
+        SelectedValue = value;
+    }
+    public bool IsEmpty() => GetValue() == null;
+}
+
+class DFOptionControl : DigitalFormFieldControl<DFLayoutOptionField, DFLayoutOptionFieldProperties, string, string?>
+{
+    private IOptionControl OptionControl = null!; // Late-initialised
+
+    protected override Control Create()
+    {
+        var options = string.IsNullOrWhiteSpace(Field.Properties.Options) 
+            ? new string[] { } 
+            : Field.Properties.Options.Replace(",","\n").Split('\n').Select(x=>x.Trim()).ToArray();
+
+        switch (Field.Properties.OptionType)
+        {
+            case DFLayoutOptionType.Buttons:
+                return SetControl(new ButtonsOptionControl(options, ChangeField));
+            case DFLayoutOptionType.Radio:
+                return SetControl(new RadioOptionControl(options, ChangeField));
+        }
+        return SetControl(new ComboBoxOptionControl(options, ChangeField));
+    }
+
+    private T SetControl<T>(T value)
+        where T : Control, IOptionControl
+    {
+        OptionControl = value;
+        return value;
+    }
+
+    public override void SetSerializedValue(string? value)
+    {
+        SetValue(value);
+    }
+
+    public override string? GetSerializedValue()
+    {
+        return OptionControl.GetValue();
+    }
+
+    public override string GetValue() => OptionControl.GetValue() ?? "";
+
+    public override void SetValue(string? value) => OptionControl.SetValue(value ?? "");
+
+    protected override bool IsEmpty() => OptionControl.IsEmpty();
+
+    public override void SetBackground(IBrush brush)
+    {
+        OptionControl.Background = brush;
+    }
+}

+ 3 - 0
PRS.Avalonia/PRS.Avalonia/Theme/FormControlStyles.axaml

@@ -2,6 +2,9 @@
         xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
 		xmlns:components="using:InABox.Avalonia.Components"
 		xmlns:forms="using:PRS.Avalonia.DigitalForms">
+	<Style Selector=":is(forms|DigitalFormControl).DFFieldControl">
+		<Setter Property="Padding" Value="{DynamicResource PrsControlSpacing}"/>
+	</Style>
 	<Style Selector=":is(forms|DigitalFormControl).DFFieldControl components|DateSelectorButton">
         <Setter Property="BorderBrush" Value="{DynamicResource PrsButtonBorder}" />
         <Setter Property="BorderThickness" Value="{DynamicResource PrsBorderThickness}"/>