Browse Source

Merge pull request #107 from PixiEditor/aspectratio-bug

Fixed sizeinput empty bug and aspect ratio infinite loop
Krzysztof Krysiński 4 years ago
parent
commit
0ee160b782

+ 3 - 3
PixiEditor/Helpers/Behaviours/TextBoxFocusBehavior.cs

@@ -95,14 +95,14 @@ namespace PixiEditor.Helpers.Behaviours
         /// </summary>
         private void ConvertValue()
         {
-            if (valueConverted || FillSize == false)
+            if (valueConverted || FillSize == false || AssociatedObject.Text == oldText)
             {
                 return;
             }
 
-            if (int.TryParse(Regex.Replace(AssociatedObject.Text, "\\p{L}", string.Empty), out int result) && result > 0)
+            if (int.TryParse(Regex.Replace(AssociatedObject.Text, "\\p{L}", string.Empty).Trim(), out int result) && result > 0)
             {
-                AssociatedObject.Text = $"{AssociatedObject.Text} px";
+                AssociatedObject.Text = $"{result} px";
             }
 
             // If text in textbox isn't number, set it to old value

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

@@ -9,7 +9,7 @@
              xmlns:converters="clr-namespace:PixiEditor.Helpers"
              xmlns:validators="clr-namespace:PixiEditor.Helpers.Validators"
              mc:Ignorable="d"
-             d:DesignHeight="30" d:DesignWidth="160" Name="uc" LayoutUpdated="uc_LayoutUpdated">
+             d:DesignHeight="30" d:DesignWidth="160" Name="uc" LayoutUpdated="UserControlLayoutUpdated">
     <UserControl.Resources>
         <converters:ToolSizeToIntConverter x:Key="ToolSizeToIntConverter" />
     </UserControl.Resources>

+ 49 - 22
PixiEditor/Views/UserControls/SizeInput.xaml.cs

@@ -1,75 +1,102 @@
 using System;
+using System.Diagnostics;
 using System.Windows;
 using System.Windows.Controls;
 
 namespace PixiEditor.Views
 {
     /// <summary>
-    ///     Interaction logic for SizeInput.xaml
+    ///     Interaction logic for SizeInput.xaml.
     /// </summary>
     public partial class SizeInput : UserControl
     {
         // Using a DependencyProperty as the backing store for Size.  This enables animation, styling, binding, etc...
         public static readonly DependencyProperty SizeProperty =
-            DependencyProperty.Register("Size", typeof(int), typeof(SizeInput), new PropertyMetadata(1));
+            DependencyProperty.Register("Size", typeof(int), typeof(SizeInput), new PropertyMetadata(1, InputSizeChanged));
 
         // Using a DependencyProperty as the backing store for PreserveAspectRatio.  This enables animation, styling, binding, etc...
         public static readonly DependencyProperty PreserveAspectRatioProperty =
-            DependencyProperty.Register("PreserveAspectRatio", typeof(bool), typeof(SizeInput),
+            DependencyProperty.Register(
+                "PreserveAspectRatio",
+                typeof(bool),
+                typeof(SizeInput),
                 new PropertyMetadata(false));
 
         // Using a DependencyProperty as the backing store for AspectRatioValue.  This enables animation, styling, binding, etc...
         public static readonly DependencyProperty AspectRatioValueProperty =
-            DependencyProperty.Register("AspectRatioValue", typeof(int), typeof(SizeInput),
-                new PropertyMetadata(1, AspectRatioValChanged));
+            DependencyProperty.Register(
+                "AspectRatioValue",
+                typeof(int),
+                typeof(SizeInput),
+                new PropertyMetadata(1));
 
-        private int _loadedAspectRatioSize = -1;
+        public SizeInput AspectRatioControl
+        {
+            get { return (SizeInput)GetValue(AspectRatioControlProperty); }
+            set { SetValue(AspectRatioControlProperty, value); }
+        }
+
+        // Using a DependencyProperty as the backing store for AspectRatioControl.  This enables animation, styling, binding, etc...
+        public static readonly DependencyProperty AspectRatioControlProperty =
+            DependencyProperty.Register("AspectRatioControl", typeof(SizeInput), typeof(SizeInput), new PropertyMetadata(default));
 
-        private int _loadedSize = -1;
+        private int loadedAspectRatioSize = -1;
+
+        private int loadedSize = -1;
+        private bool blockUpdate = false;
 
         public SizeInput()
         {
             InitializeComponent();
         }
 
-
         public int Size
         {
-            get => (int) GetValue(SizeProperty);
+            get => (int)GetValue(SizeProperty);
             set => SetValue(SizeProperty, value);
         }
 
         public bool PreserveAspectRatio
         {
-            get => (bool) GetValue(PreserveAspectRatioProperty);
+            get => (bool)GetValue(PreserveAspectRatioProperty);
             set => SetValue(PreserveAspectRatioProperty, value);
         }
 
-
         public int AspectRatioValue
         {
-            get => (int) GetValue(AspectRatioValueProperty);
+            get => (int)GetValue(AspectRatioValueProperty);
             set => SetValue(AspectRatioValueProperty, value);
         }
 
-        private static void AspectRatioValChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
+        private static void InputSizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
         {
-            SizeInput input = (SizeInput) d;
+            SizeInput input = ((SizeInput)d).AspectRatioControl;
+            if (input == null)
+            {
+                return;
+            }
+
+            int newVal = (int)e.NewValue;
+            if (input.PreserveAspectRatio && !input.IsFocused && !input.blockUpdate)
+            {
+                float ratio = newVal / Math.Clamp(input.loadedAspectRatioSize, 1f, float.MaxValue);
+                int newSize = (int)(input.loadedSize * ratio);
+                input.AspectRatioControl.blockUpdate = true; // Block update is used to prevent infinite feedback loop.
+                input.Size = newSize;
+            }
 
-            if (input.PreserveAspectRatio && input._loadedSize != -1)
+            if (input.blockUpdate)
             {
-                int newVal = (int) e.NewValue;
-                float ratio = newVal / Math.Clamp(input._loadedAspectRatioSize, 1f, float.MaxValue);
-                input.Size = (int) (input._loadedSize * ratio);
+                input.blockUpdate = false;
             }
         }
 
-        private void uc_LayoutUpdated(object sender, EventArgs e)
+        private void UserControlLayoutUpdated(object sender, EventArgs e)
         {
-            if (_loadedSize == -1)
+            if (loadedSize == -1)
             {
-                _loadedSize = Size;
-                _loadedAspectRatioSize = AspectRatioValue;
+                loadedSize = Size;
+                loadedAspectRatioSize = AspectRatioValue;
             }
         }
     }

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

@@ -10,18 +10,20 @@
         <DockPanel Margin="5,10,0,0" HorizontalAlignment="Center" VerticalAlignment="Center">
             <TextBlock Height="30" Foreground="Snow" Text="Width:" TextAlignment="Center" FontSize="16"
                        HorizontalAlignment="Center" VerticalAlignment="Center" />
-            <local:SizeInput IsEnabled="{Binding EditingEnabled, ElementName=uc}" Width="150" Height="30"
+            <local:SizeInput x:Name="WidthPicker" IsEnabled="{Binding EditingEnabled, ElementName=uc}" Width="150" Height="30"
                              PreserveAspectRatio="{Binding Path=IsChecked, ElementName=aspectRatio}"
                              AspectRatioValue="{Binding Path=ChosenHeight, ElementName=uc}"
+                             AspectRatioControl="{Binding ElementName=HeightPicker}"
                              HorizontalAlignment="Left" Margin="10,0,0,0"
                              Size="{Binding Path=ChosenWidth, ElementName=uc, Mode=TwoWay}" />
         </DockPanel>
         <DockPanel Margin="5,10,0,0" HorizontalAlignment="Center" VerticalAlignment="Center">
             <TextBlock Height="30" Foreground="Snow" Text="Height:" TextAlignment="Center" FontSize="16"
                        HorizontalAlignment="Center" VerticalAlignment="Center" />
-            <local:SizeInput IsEnabled="{Binding EditingEnabled, ElementName=uc}" Margin="5,0,0,0"
+            <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}"
                              HorizontalAlignment="Left" Width="150" Height="30"
                              Size="{Binding ChosenHeight, ElementName=uc, Mode=TwoWay}" />
         </DockPanel>