Browse Source

Added Percentage/Absolute options on SizePicker control

tomaszkot 3 years ago
parent
commit
b4a474a023

+ 37 - 0
PixiEditor/Helpers/Converters/EnumBooleanConverter.cs

@@ -0,0 +1,37 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace PixiEditor.Helpers.Converters
+{
+    public class EnumBooleanConverter : SingleInstanceConverter<EnumBooleanConverter>
+    {
+        #region IValueConverter Members
+        public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            string parameterString = parameter as string;
+            if (parameterString == null)
+                return DependencyProperty.UnsetValue;
+
+            if (Enum.IsDefined(value.GetType(), value) == false)
+                return DependencyProperty.UnsetValue;
+
+            object parameterValue = Enum.Parse(value.GetType(), parameterString);
+
+            return parameterValue.Equals(value);
+        }
+
+        public override object ConvertBack(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+        {
+            string parameterString = parameter as string;
+            if (parameterString == null)
+                return DependencyProperty.UnsetValue;
+
+            return Enum.Parse(targetType, parameterString);
+        }
+        #endregion
+    }
+}

+ 29 - 0
PixiEditor/Helpers/Converters/EnumToStringConverter.cs

@@ -0,0 +1,29 @@
+using PixiEditor.Models.Enums;
+using System;
+
+namespace PixiEditor.Helpers.Converters
+{
+  internal class EnumToStringConverter : SingleInstanceConverter<EnumToStringConverter>
+  {
+    public override object Convert(object value, Type targetType, object parameter, System.Globalization.CultureInfo culture)
+    {
+      try
+      {
+        var type = value.GetType();
+        if (type == typeof(SizeUnit))
+        {
+          var valueCasted = (SizeUnit)value;
+          if (valueCasted == SizeUnit.Percentage)
+            return "%";
+          
+          return "px";
+        }
+        return Enum.GetName((value.GetType()), value);
+      }
+      catch
+      {
+        return string.Empty;
+      }
+    }
+  }
+}

+ 13 - 0
PixiEditor/Helpers/SizeCalculator.cs

@@ -0,0 +1,13 @@
+namespace PixiEditor.Helpers
+{
+    public static class SizeCalculator
+    {
+        public static System.Drawing.Size CalcAbsoluteFromPercentage(int percentage, System.Drawing.Size currentSize)
+        {
+            var percFactor = ((float)percentage) / 100f;
+            var newWidth = currentSize.Width * percFactor;
+            var newHeight = currentSize.Height * percFactor;
+            return new System.Drawing.Size((int)newWidth, (int)newHeight);
+        }
+    }
+}

+ 6 - 4
PixiEditor/Models/Dialogs/ResizeDocumentDialog.cs

@@ -72,15 +72,17 @@ namespace PixiEditor.Models.Dialogs
         {
             ResizeCanvasPopup popup = new ResizeCanvasPopup
             {
-                NewHeight = Height,
-                NewWidth = Width
+                NewAbsoluteHeight = Height,
+                NewAbsoluteWidth = Width,
+                NewPercentageSize = 100,
+                NewSelectedUnit = SizeUnit.Pixel
             };
 
             popup.ShowDialog();
             if (popup.DialogResult == true)
             {
-                Width = popup.NewWidth;
-                Height = popup.NewHeight;
+                Width = popup.NewAbsoluteWidth;
+                Height = popup.NewAbsoluteHeight;
                 ResizeAnchor = popup.SelectedAnchorPoint;
             }
 

+ 4 - 0
PixiEditor/Models/Enums/SizeUnit.cs

@@ -0,0 +1,4 @@
+namespace PixiEditor.Models.Enums
+{
+  public enum SizeUnit { Pixel, Percentage }
+}

+ 10 - 5
PixiEditor/Views/Dialogs/ResizeCanvasPopup.xaml

@@ -8,7 +8,7 @@
         xmlns:behaviors="clr-namespace:PixiEditor.Helpers.Behaviours"
         mc:Ignorable="d" Name="window"
         Title="ResizeCanvasPopup" Topmost="True" ShowInTaskbar="False" WindowStartupLocation="CenterScreen"
-        Height="390" Width="400" WindowStyle="None">
+        Height="450" Width="400" WindowStyle="None">
 
     <WindowChrome.WindowChrome>
         <WindowChrome CaptionHeight="32"  GlassFrameThickness="0.1"
@@ -37,10 +37,15 @@
         <Label Grid.Row="1" VerticalAlignment="Top" Foreground="White" FontSize="24" HorizontalAlignment="Center"
                Content="Resize Canvas" />
         <StackPanel HorizontalAlignment="Center" Margin="0,50,0,0" Background="{StaticResource MainColor}"
-                    VerticalAlignment="Top" Grid.Row="1" Width="300" Height="250">
-            <local:SizePicker Margin="0,10,0,0" Width="300" Height="110"
-                              ChosenHeight="{Binding NewHeight, Mode=TwoWay, ElementName=window}"
-                              ChosenWidth="{Binding NewWidth, Mode=TwoWay, ElementName=window}" />
+                    VerticalAlignment="Top" Grid.Row="1" Width="300" Height="310">
+            <local:SizePicker Margin="0,10,0,0" Width="300" Height="180"
+                              ChosenHeight="{Binding NewAbsoluteHeight, Mode=TwoWay, ElementName=window}"
+                              ChosenWidth="{Binding NewAbsoluteWidth, Mode=TwoWay, ElementName=window}"
+                              ChosenPercentageSize="{Binding NewPercentageSize, Mode=TwoWay, ElementName=window}"
+                              x:Name="ThisSizePicker"
+                              SelectedUnit="{ Binding NewSelectedUnit, Mode=TwoWay, ElementName=window}"
+                              SizeUnitSelectionVisibility="Visible"
+                              />
             <Separator Margin="10,20,10,0" Background="{StaticResource AccentColor}" Height="1" />
             <Label Content="Anchor point:" Foreground="White" Margin="10,5,0,0" HorizontalAlignment="Left"
                    FontSize="16" />

+ 26 - 10
PixiEditor/Views/Dialogs/ResizeCanvasPopup.xaml.cs

@@ -15,12 +15,18 @@ namespace PixiEditor.Views
                 new PropertyMetadata(AnchorPoint.Top | AnchorPoint.Left));
 
         // Using a DependencyProperty as the backing store for NewHeight.  This enables animation, styling, binding, etc...
-        public static readonly DependencyProperty NewHeightProperty =
-            DependencyProperty.Register("NewHeight", typeof(int), typeof(ResizeCanvasPopup), new PropertyMetadata(0));
+        public static readonly DependencyProperty NewAbsoluteHeightProperty =
+            DependencyProperty.Register("NewAbsoluteHeight", typeof(int), typeof(ResizeCanvasPopup), new PropertyMetadata(0));
 
         // Using a DependencyProperty as the backing store for NewWidth.  This enables animation, styling, binding, etc...
-        public static readonly DependencyProperty NewWidthProperty =
-            DependencyProperty.Register("NewWidth", typeof(int), typeof(ResizeCanvasPopup), new PropertyMetadata(0));
+        public static readonly DependencyProperty NewAbsoluteWidthProperty =
+            DependencyProperty.Register("NewAbsoluteWidth", typeof(int), typeof(ResizeCanvasPopup), new PropertyMetadata(0));
+
+        public static readonly DependencyProperty NewPercentageSizeProperty =
+            DependencyProperty.Register("NewPercentageSize", typeof(int), typeof(ResizeCanvasPopup), new PropertyMetadata(0));
+
+        public static readonly DependencyProperty NewSelectedUnitProperty =
+            DependencyProperty.Register(nameof(NewSelectedUnit), typeof(SizeUnit), typeof(SizePicker), new PropertyMetadata(SizeUnit.Pixel));
 
         public ResizeCanvasPopup()
         {
@@ -36,19 +42,29 @@ namespace PixiEditor.Views
         }
 
 
-        public int NewHeight
+        public int NewAbsoluteHeight
         {
-            get => (int)GetValue(NewHeightProperty);
-            set => SetValue(NewHeightProperty, value);
+            get => (int)GetValue(NewAbsoluteHeightProperty);
+            set => SetValue(NewAbsoluteHeightProperty, value);
         }
 
+        public int NewAbsoluteWidth
+        {
+            get => (int)GetValue(NewAbsoluteWidthProperty);
+            set => SetValue(NewAbsoluteWidthProperty, value);
+        }
 
-        public int NewWidth
+        public int NewPercentageSize 
         {
-            get => (int)GetValue(NewWidthProperty);
-            set => SetValue(NewWidthProperty, value);
+            get => (int)GetValue(NewPercentageSizeProperty);
+            set => SetValue(NewPercentageSizeProperty, value);
         }
 
+        public SizeUnit NewSelectedUnit
+        {
+            get => (SizeUnit)GetValue(NewSelectedUnitProperty);
+            set => SetValue(NewSelectedUnitProperty, value);
+        }
 
         private void CommandBinding_CanExecute(object sender, CanExecuteRoutedEventArgs e)
         {

+ 5 - 3
PixiEditor/Views/Dialogs/ResizeDocumentPopup.xaml

@@ -7,7 +7,7 @@
         xmlns:local="clr-namespace:PixiEditor.Views" xmlns:behaviors="clr-namespace:PixiEditor.Helpers.Behaviours"
         mc:Ignorable="d" Name="window"
         Title="ResizeDocumentPopup" Topmost="True" ShowInTaskbar="False" WindowStartupLocation="CenterScreen"
-        Height="300" Width="400" WindowStyle="None">
+        Height="400" Width="400" WindowStyle="None">
 
     <WindowChrome.WindowChrome>
         <WindowChrome CaptionHeight="32" GlassFrameThickness="0.1"
@@ -36,9 +36,11 @@
         <Label Grid.Row="1" VerticalAlignment="Top" Foreground="White" FontSize="24" HorizontalAlignment="Center"
                Content="Resize document" />
         <StackPanel HorizontalAlignment="Center" Margin="0,50,0,0" Background="{StaticResource MainColor}"
-                    VerticalAlignment="Top" Grid.Row="1" Width="350" Height="150">
+                    VerticalAlignment="Top" Grid.Row="1" Width="350" Height="250">
             <local:SizePicker Margin="0,20" ChosenHeight="{Binding Path=NewHeight, Mode=TwoWay, ElementName=window}"
-                              ChosenWidth="{Binding Path=NewWidth, Mode=TwoWay, ElementName=window}" />
+                              ChosenWidth="{Binding Path=NewWidth, Mode=TwoWay, ElementName=window}"
+                              SizeUnitSelectionVisibility="Visible"
+                              />
         </StackPanel>
         <Button Grid.Row="1" Height="30" Width="60" VerticalAlignment="Bottom" HorizontalAlignment="Right" Margin="10"
                 Style="{StaticResource DarkRoundButton}" Content="OK" Click="Button_Click" />

+ 2 - 1
PixiEditor/Views/Dialogs/SaveFilePopup.xaml

@@ -39,7 +39,8 @@
             <StackPanel Orientation="Vertical" Grid.Row="1" Margin="0,50,0,0">
                 <local:SizePicker Width="250" Height="120"
                                   ChosenHeight="{Binding Path=SaveHeight, Mode=TwoWay, ElementName=saveFilePopup}"
-                                  ChosenWidth="{Binding Path=SaveWidth, Mode=TwoWay, ElementName=saveFilePopup}" />
+                                  ChosenWidth="{Binding Path=SaveWidth, Mode=TwoWay, ElementName=saveFilePopup}" 
+                                  />
                 <Button Foreground="Snow" Height="40" Width="160" Margin="0,10,0,0" Content="Path"
                         Background="{StaticResource MainColor}" BorderBrush="{Binding PathButtonBorder}"
                         Command="{Binding ChoosePathCommand}" />

+ 4 - 2
PixiEditor/Views/UserControls/SizeInput.xaml

@@ -48,8 +48,10 @@
             </TextBox>
             <Grid Grid.Column="1" Background="{Binding BorderBrush, ElementName=border}"
                   d:Background="{StaticResource BrighterAccentColor}"/>
-            <TextBlock Text="px" TextAlignment="Right"
-                       Grid.Column="2" Margin="5,0" VerticalAlignment="Center"/>
+                      <TextBlock Text="{Binding Unit, ElementName=uc, Converter={converters:EnumToStringConverter}}" TextAlignment="Right"
+                       Grid.Column="2" Margin="5,0" VerticalAlignment="Center" d:Text="%"
+                       
+                       />
         </Grid>
     </Border>
 </UserControl>

+ 11 - 1
PixiEditor/Views/UserControls/SizeInput.xaml.cs

@@ -1,4 +1,5 @@
-using System;
+using PixiEditor.Models.Enums;
+using System;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Input;
@@ -49,6 +50,9 @@ namespace PixiEditor.Views
         public static readonly DependencyProperty NextControlProperty =
             DependencyProperty.Register(nameof(NextControl), typeof(FrameworkElement), typeof(SizeInput));
 
+        public static readonly DependencyProperty UnitProperty =
+            DependencyProperty.Register(nameof(Unit), typeof(SizeUnit), typeof(SizeInput));
+
         public SizeInput()
         {
             GotKeyboardFocus += SizeInput_GotKeyboardFocus;
@@ -96,6 +100,12 @@ namespace PixiEditor.Views
             set => SetValue(NextControlProperty, value);
         }
 
+        public SizeUnit Unit
+        {
+          get => (SizeUnit)GetValue(UnitProperty);
+          set => SetValue(UnitProperty, value);
+        }
+
         private static void InputSizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
         {
             int newValue = (int)e.NewValue;

+ 52 - 10
PixiEditor/Views/UserControls/SizePicker.xaml

@@ -4,8 +4,10 @@
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
              xmlns:local="clr-namespace:PixiEditor.Views"
+             xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
+             xmlns:enums="clr-namespace:PixiEditor.Models.Enums"
              mc:Ignorable="d"
-             d:DesignHeight="110" d:DesignWidth="215" Name="uc">
+             d:DesignHeight="220" d:DesignWidth="290" Name="uc">
     <UserControl.Resources>
         <Style TargetType="local:SizeInput">
             <Setter Property="HorizontalAlignment" Value="Left"/>
@@ -17,30 +19,70 @@
             <Setter Property="Height" Value="30"/>
         </Style>
     </UserControl.Resources>
-    <StackPanel Background="{StaticResource MainColor}">
-        <DockPanel Margin="5,10,0,0" HorizontalAlignment="Center" VerticalAlignment="Center">
+    <DockPanel Background="{StaticResource MainColor}">
+        <DockPanel DockPanel.Dock="Top" Margin="5,10,0,0" HorizontalAlignment="Stretch" VerticalAlignment="Center" 
+                   Visibility="{Binding SizeUnitSelectionVisibility, ElementName=uc}">
+            <StackPanel x:Name="UnitSelectionPanel" Orientation="Vertical" >
+                <StackPanel Orientation="Horizontal" >
+                    <RadioButton  x:Name="PercentageRb" 
+                                  Foreground="White" 
+                                  FontSize="16"
+                                  GroupName="Unit"
+                                  Checked="PercentageRb_Checked"
+                                  IsChecked="{Binding Path=SelectedUnit,  
+                                              ElementName=uc, 
+                                              Converter={converters:EnumBooleanConverter}, 
+                                              ConverterParameter=Percentage
+                                              }"
+                                  >Percentage:</RadioButton>
+                    <local:SizeInput x:Name="PercentageSizePicker"
+                                    Unit="Percentage"
+                                    Width ="135"
+                                    Size="{Binding Path=ChosenPercentageSize, ElementName=uc, Mode=TwoWay}" 
+                                    />
+                </StackPanel>
+                <Separator Margin="10,20,10,10" Background="{StaticResource AccentColor}" Height="1" />
+                <RadioButton  x:Name="AbsoluteRb" 
+                              Foreground="White" 
+                              FontSize="16"
+                              GroupName="Unit"
+                              Checked="AbsoluteRb_Checked"
+                              IsChecked="{Binding Path=SelectedUnit,  
+                                              ElementName=uc, 
+                                              Converter={converters:EnumBooleanConverter}, 
+                                              ConverterParameter=Pixel}"
+                              >Absolute:</RadioButton>
+            </StackPanel>
+        </DockPanel>
+
+        <DockPanel DockPanel.Dock="Top" Margin="5,10,0,0" HorizontalAlignment="Center" VerticalAlignment="Center">
             <TextBlock Height="20" Foreground="Snow" Text="Width:" TextAlignment="Center" FontSize="16"
                        HorizontalAlignment="Center" VerticalAlignment="Center" />
             <local:SizeInput x:Name="WidthPicker"
-                             IsEnabled="{Binding EditingEnabled, ElementName=uc}"
                              PreserveAspectRatio="{Binding Path=IsChecked, ElementName=aspectRatio}"
                              AspectRatioValue="{Binding Path=ChosenHeight, ElementName=uc}"
                              AspectRatioControl="{Binding ElementName=HeightPicker}"
                              NextControl="{Binding ElementName=HeightPicker}"
-                             Size="{Binding Path=ChosenWidth, ElementName=uc, Mode=TwoWay}" />
+                             Size="{Binding Path=ChosenWidth, ElementName=uc, Mode=TwoWay}" 
+                             Unit="Pixel"
+                             />
         </DockPanel>
-        <DockPanel Margin="5,10,0,0" HorizontalAlignment="Center" VerticalAlignment="Center">
+        <DockPanel DockPanel.Dock="Top" Margin="5,10,0,0" HorizontalAlignment="Center" VerticalAlignment="Center">
             <TextBlock Height="20" Foreground="Snow" Text="Height:" TextAlignment="Center" FontSize="16"
                        HorizontalAlignment="Center" VerticalAlignment="Center" />
             <local:SizeInput x:Name="HeightPicker" 
-                             IsEnabled="{Binding EditingEnabled, ElementName=uc}"
                              Margin="5,0,0,0"
                              PreserveAspectRatio="{Binding Path=IsChecked, ElementName=aspectRatio}"
                              AspectRatioValue="{Binding Path=ChosenWidth, ElementName=uc}"
                              AspectRatioControl="{Binding ElementName=WidthPicker}"
                              NextControl="{Binding NextControl, ElementName=uc}"
-                             Size="{Binding ChosenHeight, ElementName=uc, Mode=TwoWay}" />
+                             Size="{Binding ChosenHeight, ElementName=uc, Mode=TwoWay}"
+                             Unit="Pixel"
+                             IsEnabled="{Binding IsChecked, ElementName=PercentageRb}"
+                             />
+        </DockPanel>
+        <DockPanel DockPanel.Dock="Top">
+            <CheckBox Name="aspectRatio" Content="Preserve aspect ratio" Foreground="White" HorizontalAlignment="Left" Margin="50,10,0,0" />
         </DockPanel>
-        <CheckBox Name="aspectRatio" Content="Preserve aspect ratio" Foreground="White" HorizontalAlignment="Left" Margin="50,10,0,0" />
-    </StackPanel>
+    </DockPanel>
 </UserControl>

+ 63 - 1
PixiEditor/Views/UserControls/SizePicker.xaml.cs

@@ -1,4 +1,7 @@
-using System.Windows;
+using PixiEditor.Helpers;
+using PixiEditor.Models.Enums;
+using PixiEditor.ViewModels;
+using System.Windows;
 using System.Windows.Controls;
 
 namespace PixiEditor.Views
@@ -20,9 +23,30 @@ namespace PixiEditor.Views
         public static readonly DependencyProperty NextControlProperty =
             DependencyProperty.Register(nameof(NextControl), typeof(FrameworkElement), typeof(SizePicker));
 
+        public static readonly DependencyProperty ChosenPercentageSizeProperty =
+            DependencyProperty.Register(nameof(ChosenPercentageSize), typeof(int), typeof(SizePicker), new PropertyMetadata(1, InputSizeChanged));
+
+        public static readonly DependencyProperty SelectedUnitProperty =
+            DependencyProperty.Register(nameof(SelectedUnit), typeof(SizeUnit), typeof(SizePicker), new PropertyMetadata(SizeUnit.Pixel));
+
+        public static readonly DependencyProperty SizeUnitSelectionVisibilityProperty =
+            DependencyProperty.Register(nameof(SizeUnitSelectionVisibility), typeof(Visibility), typeof(SizePicker), new PropertyMetadata(Visibility.Collapsed));
+
+
         public SizePicker()
         {
             InitializeComponent();
+
+            EnableSizeEditors();
+
+        }
+
+        private static void InputSizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+        {
+            var newValue = (int)e.NewValue;
+            var newSize = SizeCalculator.CalcAbsoluteFromPercentage(newValue, new System.Drawing.Size((int)d.GetValue(ChosenWidthProperty), (int)d.GetValue(ChosenHeightProperty)));
+            d.SetValue(ChosenWidthProperty, newSize.Width);
+            d.SetValue(ChosenHeightProperty, newSize.Height);
         }
 
         public bool EditingEnabled
@@ -43,6 +67,24 @@ namespace PixiEditor.Views
             set => SetValue(ChosenHeightProperty, value);
         }
 
+        public int ChosenPercentageSize
+        {
+            get => (int)GetValue(ChosenPercentageSizeProperty);
+            set => SetValue(ChosenPercentageSizeProperty, value);
+        }
+
+        public SizeUnit SelectedUnit 
+        {
+            get => (SizeUnit)GetValue(SelectedUnitProperty);
+            set => SetValue(SelectedUnitProperty, value);
+        }
+
+        public Visibility SizeUnitSelectionVisibility
+        {
+            get => (Visibility)GetValue(SizeUnitSelectionVisibilityProperty);
+            set => SetValue(SizeUnitSelectionVisibilityProperty, value);
+        }
+        
         public FrameworkElement NextControl
         {
             get => (FrameworkElement)GetValue(NextControlProperty);
@@ -53,5 +95,25 @@ namespace PixiEditor.Views
         {
             WidthPicker.Focus();
         }
+                
+        private void PercentageRb_Checked(object sender, RoutedEventArgs e)
+        {
+            EnableSizeEditors();
+        }
+
+        private void AbsoluteRb_Checked(object sender, RoutedEventArgs e)
+        {
+            EnableSizeEditors();
+        }
+
+        private void EnableSizeEditors()
+        {
+            if (PercentageSizePicker != null)
+                PercentageSizePicker.IsEnabled = EditingEnabled && PercentageRb.IsChecked.Value;
+            if (WidthPicker != null)
+                WidthPicker.IsEnabled = EditingEnabled && !PercentageRb.IsChecked.Value;
+            if (HeightPicker != null)
+                HeightPicker.IsEnabled = EditingEnabled && !PercentageRb.IsChecked.Value;
+        }
     }
 }

+ 19 - 0
PixiEditorTests/HelpersTests/SizeCalculatorTest.cs

@@ -0,0 +1,19 @@
+using PixiEditor.Helpers;
+using Xunit;
+
+namespace PixiEditorTests.HelpersTests
+{
+    public class SizeCalculatorTest
+    {
+        [Theory]
+        [InlineData(50, 64, 64, 32, 32)]
+        [InlineData(100, 64, 64, 64, 64)]
+        [InlineData(200, 128, 128, 256, 256)]
+        public void TestCalculationOfPercentsWorks(int percent, int currentWidth, int currentHeight, int expectedWidth, int expectedHeight)
+        {
+            var newSize = SizeCalculator.CalcAbsoluteFromPercentage(percent, new System.Drawing.Size(currentWidth, currentHeight));
+            Assert.Equal(expectedWidth, newSize.Width);
+            Assert.Equal(expectedHeight, newSize.Height);
+        }
+    }
+}