Browse Source

Improve textbox experience

Equbuxu 3 years ago
parent
commit
f36a2118e5

+ 43 - 26
PixiEditor/Helpers/Behaviours/TextBoxFocusBehavior.cs

@@ -1,5 +1,4 @@
-using System.Text.RegularExpressions;
-using System.Windows;
+using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Controls;
 using System.Windows.Input;
 using System.Windows.Input;
 using System.Windows.Interactivity;
 using System.Windows.Interactivity;
@@ -8,27 +7,42 @@ namespace PixiEditor.Helpers.Behaviours
 {
 {
     internal class TextBoxFocusBehavior : Behavior<TextBox>
     internal class TextBoxFocusBehavior : Behavior<TextBox>
     {
     {
-        // Using a DependencyProperty as the backing store for FillSize.  This enables animation, styling, binding, etc...
-        public static readonly DependencyProperty SelectOnFocusProperty =
+        public static readonly DependencyProperty SelectOnMouseClickProperty =
             DependencyProperty.Register(
             DependencyProperty.Register(
-                nameof(SelectOnFocus),
+                nameof(SelectOnMouseClick),
                 typeof(bool),
                 typeof(bool),
                 typeof(TextBoxFocusBehavior),
                 typeof(TextBoxFocusBehavior),
-                new PropertyMetadata(true));
+                new PropertyMetadata(false));
 
 
-        public static readonly DependencyProperty NextControlProperty =
-            DependencyProperty.Register(nameof(NextControl), typeof(FrameworkElement), typeof(TextBoxFocusBehavior));
+        public static readonly DependencyProperty ConfirmOnEnterProperty =
+            DependencyProperty.Register(
+                nameof(ConfirmOnEnter),
+                typeof(bool),
+                typeof(TextBoxFocusBehavior),
+                new PropertyMetadata(false));
 
 
-        public FrameworkElement NextControl
+        public static readonly DependencyProperty DeselectOnFocusLossProperty =
+            DependencyProperty.Register(
+                nameof(DeselectOnFocusLoss),
+                typeof(bool),
+                typeof(TextBoxFocusBehavior),
+                new PropertyMetadata(false));
+
+        public bool SelectOnMouseClick
         {
         {
-            get => (FrameworkElement)GetValue(NextControlProperty);
-            set => SetValue(NextControlProperty, value);
+            get => (bool)GetValue(SelectOnMouseClickProperty);
+            set => SetValue(SelectOnMouseClickProperty, value);
         }
         }
 
 
-        public bool SelectOnFocus
+        public bool ConfirmOnEnter
+        {
+            get => (bool)GetValue(ConfirmOnEnterProperty);
+            set => SetValue(ConfirmOnEnterProperty, value);
+        }
+        public bool DeselectOnFocusLoss
         {
         {
-            get => (bool)GetValue(SelectOnFocusProperty);
-            set => SetValue(SelectOnFocusProperty, value);
+            get => (bool)GetValue(DeselectOnFocusLossProperty);
+            set => SetValue(DeselectOnFocusLossProperty, value);
         }
         }
 
 
         protected override void OnAttached()
         protected override void OnAttached()
@@ -36,6 +50,7 @@ namespace PixiEditor.Helpers.Behaviours
             base.OnAttached();
             base.OnAttached();
             AssociatedObject.GotKeyboardFocus += AssociatedObjectGotKeyboardFocus;
             AssociatedObject.GotKeyboardFocus += AssociatedObjectGotKeyboardFocus;
             AssociatedObject.GotMouseCapture += AssociatedObjectGotMouseCapture;
             AssociatedObject.GotMouseCapture += AssociatedObjectGotMouseCapture;
+            AssociatedObject.LostFocus += AssociatedObject_LostFocus;
             AssociatedObject.PreviewMouseLeftButtonDown += AssociatedObjectPreviewMouseLeftButtonDown;
             AssociatedObject.PreviewMouseLeftButtonDown += AssociatedObjectPreviewMouseLeftButtonDown;
             AssociatedObject.KeyUp += AssociatedObject_KeyUp;
             AssociatedObject.KeyUp += AssociatedObject_KeyUp;
         }
         }
@@ -45,6 +60,7 @@ namespace PixiEditor.Helpers.Behaviours
             base.OnDetaching();
             base.OnDetaching();
             AssociatedObject.GotKeyboardFocus -= AssociatedObjectGotKeyboardFocus;
             AssociatedObject.GotKeyboardFocus -= AssociatedObjectGotKeyboardFocus;
             AssociatedObject.GotMouseCapture -= AssociatedObjectGotMouseCapture;
             AssociatedObject.GotMouseCapture -= AssociatedObjectGotMouseCapture;
+            AssociatedObject.LostFocus -= AssociatedObject_LostFocus;
             AssociatedObject.PreviewMouseLeftButtonDown -= AssociatedObjectPreviewMouseLeftButtonDown;
             AssociatedObject.PreviewMouseLeftButtonDown -= AssociatedObjectPreviewMouseLeftButtonDown;
             AssociatedObject.KeyUp -= AssociatedObject_KeyUp;
             AssociatedObject.KeyUp -= AssociatedObject_KeyUp;
         }
         }
@@ -52,10 +68,8 @@ namespace PixiEditor.Helpers.Behaviours
         // Converts number to proper format if enter is clicked and moves focus to next object
         // Converts number to proper format if enter is clicked and moves focus to next object
         private void AssociatedObject_KeyUp(object sender, KeyEventArgs e)
         private void AssociatedObject_KeyUp(object sender, KeyEventArgs e)
         {
         {
-            if (e.Key != Key.Enter)
-            {
+            if (e.Key != Key.Enter || !ConfirmOnEnter)
                 return;
                 return;
-            }
 
 
             RemoveFocus();
             RemoveFocus();
         }
         }
@@ -63,13 +77,6 @@ namespace PixiEditor.Helpers.Behaviours
         private void RemoveFocus()
         private void RemoveFocus()
         {
         {
             DependencyObject scope = FocusManager.GetFocusScope(AssociatedObject);
             DependencyObject scope = FocusManager.GetFocusScope(AssociatedObject);
-
-            if (NextControl != null)
-            {
-                FocusManager.SetFocusedElement(scope, NextControl);
-                return;
-            }
-
             FrameworkElement parent = (FrameworkElement)AssociatedObject.Parent;
             FrameworkElement parent = (FrameworkElement)AssociatedObject.Parent;
 
 
             while (parent != null && parent is IInputElement element && !element.Focusable)
             while (parent != null && parent is IInputElement element && !element.Focusable)
@@ -78,13 +85,14 @@ namespace PixiEditor.Helpers.Behaviours
             }
             }
 
 
             FocusManager.SetFocusedElement(scope, parent);
             FocusManager.SetFocusedElement(scope, parent);
+            Keyboard.ClearFocus();
         }
         }
 
 
         private void AssociatedObjectGotKeyboardFocus(
         private void AssociatedObjectGotKeyboardFocus(
             object sender,
             object sender,
             KeyboardFocusChangedEventArgs e)
             KeyboardFocusChangedEventArgs e)
         {
         {
-            if (SelectOnFocus)
+            if (SelectOnMouseClick || e.KeyboardDevice.IsKeyDown(Key.Tab))
                 AssociatedObject.SelectAll();
                 AssociatedObject.SelectAll();
         }
         }
 
 
@@ -92,12 +100,21 @@ namespace PixiEditor.Helpers.Behaviours
             object sender,
             object sender,
             MouseEventArgs e)
             MouseEventArgs e)
         {
         {
-            if (SelectOnFocus)
+            if (SelectOnMouseClick)
                 AssociatedObject.SelectAll();
                 AssociatedObject.SelectAll();
         }
         }
 
 
+        private void AssociatedObject_LostFocus(object sender, RoutedEventArgs e)
+        {
+            if (DeselectOnFocusLoss)
+                AssociatedObject.Select(0, 0);
+        }
+
         private void AssociatedObjectPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
         private void AssociatedObjectPreviewMouseLeftButtonDown(object sender, MouseButtonEventArgs e)
         {
         {
+            if (!SelectOnMouseClick)
+                return;
+
             if (!AssociatedObject.IsKeyboardFocusWithin)
             if (!AssociatedObject.IsKeyboardFocusWithin)
             {
             {
                 AssociatedObject.Focus();
                 AssociatedObject.Focus();

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

@@ -43,8 +43,7 @@
             <local:SizePicker Margin="0,20" HorizontalAlignment="Center" Height="110"
             <local:SizePicker Margin="0,20" HorizontalAlignment="Center" Height="110"
                               ChosenHeight="{Binding FileHeight, Mode=TwoWay, ElementName=newFilePopup}"
                               ChosenHeight="{Binding FileHeight, Mode=TwoWay, ElementName=newFilePopup}"
                               ChosenWidth="{Binding FileWidth, Mode=TwoWay, ElementName=newFilePopup}" 
                               ChosenWidth="{Binding FileWidth, Mode=TwoWay, ElementName=newFilePopup}" 
-                              x:Name="sizePicker"
-                              NextControl="{Binding ElementName=createButton}"/>
+                              x:Name="sizePicker"/>
         </StackPanel>
         </StackPanel>
         <Button VerticalAlignment="Bottom" HorizontalAlignment="Right" FontSize="20" Height="30" Width="120"
         <Button VerticalAlignment="Bottom" HorizontalAlignment="Right" FontSize="20" Height="30" Width="120"
                 Style="{StaticResource DarkRoundButton}" Content="Create" Margin="0,0,10,10" Grid.Row="1"
                 Style="{StaticResource DarkRoundButton}" Content="Create" Margin="0,0,10,10" Grid.Row="1"

+ 9 - 4
PixiEditor/Views/Dialogs/NewFilePopup.xaml.cs

@@ -18,9 +18,14 @@ namespace PixiEditor.Views
         {
         {
             InitializeComponent();
             InitializeComponent();
             Owner = Application.Current.MainWindow;
             Owner = Application.Current.MainWindow;
-            sizePicker.FocusWidthPicker();
-        }
-
+            Loaded += OnDialogShown;
+        }
+
+        private void OnDialogShown(object sender, RoutedEventArgs e)
+        {
+            sizePicker.FocusWidthPicker();
+        }
+
         public int FileHeight
         public int FileHeight
         {
         {
             get => (int)GetValue(FileHeightProperty);
             get => (int)GetValue(FileHeightProperty);
@@ -43,4 +48,4 @@ namespace PixiEditor.Views
             SystemCommands.CloseWindow(this);
             SystemCommands.CloseWindow(this);
         }
         }
     }
     }
-}
+}

+ 2 - 2
PixiEditor/Views/UserControls/NumberInput.xaml

@@ -11,8 +11,8 @@
              InputScope="Number" MouseWheel="TextBox_MouseWheel"
              InputScope="Number" MouseWheel="TextBox_MouseWheel"
              PreviewTextInput="TextBox_PreviewTextInput" Text="{Binding ElementName=numberInput, Path=Value}">
              PreviewTextInput="TextBox_PreviewTextInput" Text="{Binding ElementName=numberInput, Path=Value}">
         <i:Interaction.Behaviors>
         <i:Interaction.Behaviors>
-            <behaviours:TextBoxFocusBehavior/>
+            <behaviours:TextBoxFocusBehavior SelectOnMouseClick="True" ConfirmOnEnter="True"/>
             <behaviours:GlobalShortcutFocusBehavior/>
             <behaviours:GlobalShortcutFocusBehavior/>
         </i:Interaction.Behaviors>
         </i:Interaction.Behaviors>
     </TextBox>
     </TextBox>
-</UserControl>
+</UserControl>

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

@@ -43,7 +43,10 @@
                      d:Text="22">
                      d:Text="22">
                 <i:Interaction.Behaviors>
                 <i:Interaction.Behaviors>
                     <behaviors:GlobalShortcutFocusBehavior/>
                     <behaviors:GlobalShortcutFocusBehavior/>
-                    <behaviors:TextBoxFocusBehavior SelectOnFocus="{Binding SelectOnFocus, ElementName=uc}" NextControl="{Binding NextControl, ElementName=uc}"/>
+                    <behaviors:TextBoxFocusBehavior 
+                        SelectOnMouseClick="{Binding BehaveLikeSmallEmbeddedField, ElementName=uc}" 
+                        ConfirmOnEnter="{Binding BehaveLikeSmallEmbeddedField, ElementName=uc}"
+                        DeselectOnFocusLoss="True"/>
                 </i:Interaction.Behaviors>
                 </i:Interaction.Behaviors>
             </TextBox>
             </TextBox>
             <Grid Grid.Column="1" Background="{Binding BorderBrush, ElementName=border}"
             <Grid Grid.Column="1" Background="{Binding BorderBrush, ElementName=border}"

+ 46 - 48
PixiEditor/Views/UserControls/SizeInput.xaml.cs

@@ -13,58 +13,20 @@ namespace PixiEditor.Views
         public static readonly DependencyProperty SizeProperty =
         public static readonly DependencyProperty SizeProperty =
             DependencyProperty.Register(nameof(Size), typeof(int), typeof(SizeInput), new PropertyMetadata(1, InputSizeChanged));
             DependencyProperty.Register(nameof(Size), typeof(int), typeof(SizeInput), new PropertyMetadata(1, InputSizeChanged));
 
 
+        public static readonly DependencyProperty MaxSizeProperty =
+            DependencyProperty.Register(nameof(MaxSize), typeof(int), typeof(SizeInput), new PropertyMetadata(int.MaxValue));
+
         public static readonly DependencyProperty PreserveAspectRatioProperty =
         public static readonly DependencyProperty PreserveAspectRatioProperty =
-            DependencyProperty.Register(
-                nameof(PreserveAspectRatio),
-                typeof(bool),
-                typeof(SizeInput));
+            DependencyProperty.Register(nameof(PreserveAspectRatio), typeof(bool), typeof(SizeInput));
 
 
         public static readonly DependencyProperty AspectRatioValueProperty =
         public static readonly DependencyProperty AspectRatioValueProperty =
-            DependencyProperty.Register(
-                nameof(AspectRatioValue),
-                typeof(int),
-                typeof(SizeInput),
-                new PropertyMetadata(1));
-
-        public SizeInput AspectRatioControl
-        {
-            get { return (SizeInput)GetValue(AspectRatioControlProperty); }
-            set { SetValue(AspectRatioControlProperty, value); }
-        }
+            DependencyProperty.Register(nameof(AspectRatioValue), typeof(int), typeof(SizeInput), new PropertyMetadata(1));
 
 
         public static readonly DependencyProperty AspectRatioControlProperty =
         public static readonly DependencyProperty AspectRatioControlProperty =
             DependencyProperty.Register(nameof(AspectRatioControl), typeof(SizeInput), typeof(SizeInput), new PropertyMetadata(default));
             DependencyProperty.Register(nameof(AspectRatioControl), typeof(SizeInput), typeof(SizeInput), new PropertyMetadata(default));
 
 
-        public static readonly DependencyProperty MaxSizeProperty =
-            DependencyProperty.Register(nameof(MaxSize), typeof(int), typeof(SizeInput), new PropertyMetadata(int.MaxValue));
-
-        public static readonly DependencyProperty SelectOnFocusProperty =
-            DependencyProperty.Register(nameof(SelectOnFocus), typeof(bool), typeof(SizeInput), new PropertyMetadata(true));
-
-        private int loadedAspectRatioSize = -1;
-
-        private int loadedSize = -1;
-        private bool blockUpdate = false;
-
-        public static readonly DependencyProperty NextControlProperty =
-            DependencyProperty.Register(nameof(NextControl), typeof(FrameworkElement), typeof(SizeInput));
-
-        public SizeInput()
-        {
-            GotKeyboardFocus += SizeInput_GotKeyboardFocus;
-            InitializeComponent();
-        }
-
-        public bool SelectOnFocus
-        {
-            get => (bool)GetValue(SelectOnFocusProperty);
-            set => SetValue(SelectOnFocusProperty, value);
-        }
-
-        private void SizeInput_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
-        {
-            textBox.Focus();
-        }
+        public static readonly DependencyProperty BehaveLikeSmallEmbeddedFieldProperty =
+            DependencyProperty.Register(nameof(BehaveLikeSmallEmbeddedField), typeof(bool), typeof(SizeInput), new PropertyMetadata(true));
 
 
         public int Size
         public int Size
         {
         {
@@ -90,10 +52,46 @@ namespace PixiEditor.Views
             set => SetValue(AspectRatioValueProperty, value);
             set => SetValue(AspectRatioValueProperty, value);
         }
         }
 
 
-        public FrameworkElement NextControl
+        public SizeInput AspectRatioControl
         {
         {
-            get => (FrameworkElement)GetValue(NextControlProperty);
-            set => SetValue(NextControlProperty, value);
+            get { return (SizeInput)GetValue(AspectRatioControlProperty); }
+            set { SetValue(AspectRatioControlProperty, value); }
+        }
+
+        public bool BehaveLikeSmallEmbeddedField
+        {
+            get => (bool)GetValue(BehaveLikeSmallEmbeddedFieldProperty);
+            set => SetValue(BehaveLikeSmallEmbeddedFieldProperty, value);
+        }
+
+        private int loadedAspectRatioSize = -1;
+
+        private int loadedSize = -1;
+        private bool blockUpdate = false;
+
+        public SizeInput()
+        {
+            GotKeyboardFocus += SizeInput_GotKeyboardFocus;
+            InitializeComponent();
+        }
+
+        public void FocusAndSelect()
+        {
+            Focus();
+            textBox.SelectAll();
+        }
+
+        private void SizeInput_GotKeyboardFocus(object sender, KeyboardFocusChangedEventArgs e)
+        {
+            textBox.Focus();
+            Point pos = Mouse.GetPosition(textBox);
+            int charIndex = textBox.GetCharacterIndexFromPoint(pos, true);
+            var charRect = textBox.GetRectFromCharacterIndex(charIndex);
+            double middleX = (charRect.Left + charRect.Right) / 2;
+            if (pos.X > middleX)
+                textBox.CaretIndex = charIndex + 1;
+            else
+                textBox.CaretIndex = charIndex;
         }
         }
 
 
         private static void InputSizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)
         private static void InputSizeChanged(DependencyObject d, DependencyPropertyChangedEventArgs e)

+ 1 - 3
PixiEditor/Views/UserControls/SizePicker.xaml

@@ -10,7 +10,7 @@
         <Style TargetType="local:SizeInput">
         <Style TargetType="local:SizeInput">
             <Setter Property="HorizontalAlignment" Value="Left"/>
             <Setter Property="HorizontalAlignment" Value="Left"/>
             <Setter Property="MaxSize" Value="9999"/>
             <Setter Property="MaxSize" Value="9999"/>
-            <Setter Property="SelectOnFocus" Value="False"/>
+            <Setter Property="BehaveLikeSmallEmbeddedField" Value="False"/>
             <Setter Property="FontSize" Value="16"/>
             <Setter Property="FontSize" Value="16"/>
             <Setter Property="Margin" Value="10,0,0,0"/>
             <Setter Property="Margin" Value="10,0,0,0"/>
             <Setter Property="Width" Value="150"/>
             <Setter Property="Width" Value="150"/>
@@ -26,7 +26,6 @@
                              PreserveAspectRatio="{Binding Path=IsChecked, ElementName=aspectRatio}"
                              PreserveAspectRatio="{Binding Path=IsChecked, ElementName=aspectRatio}"
                              AspectRatioValue="{Binding Path=ChosenHeight, ElementName=uc}"
                              AspectRatioValue="{Binding Path=ChosenHeight, ElementName=uc}"
                              AspectRatioControl="{Binding ElementName=HeightPicker}"
                              AspectRatioControl="{Binding ElementName=HeightPicker}"
-                             NextControl="{Binding ElementName=HeightPicker}"
                              Size="{Binding Path=ChosenWidth, ElementName=uc, Mode=TwoWay}" />
                              Size="{Binding Path=ChosenWidth, ElementName=uc, Mode=TwoWay}" />
         </DockPanel>
         </DockPanel>
         <DockPanel Margin="5,10,0,0" HorizontalAlignment="Center" VerticalAlignment="Center">
         <DockPanel Margin="5,10,0,0" HorizontalAlignment="Center" VerticalAlignment="Center">
@@ -38,7 +37,6 @@
                              PreserveAspectRatio="{Binding Path=IsChecked, ElementName=aspectRatio}"
                              PreserveAspectRatio="{Binding Path=IsChecked, ElementName=aspectRatio}"
                              AspectRatioValue="{Binding Path=ChosenWidth, ElementName=uc}"
                              AspectRatioValue="{Binding Path=ChosenWidth, ElementName=uc}"
                              AspectRatioControl="{Binding ElementName=WidthPicker}"
                              AspectRatioControl="{Binding ElementName=WidthPicker}"
-                             NextControl="{Binding NextControl, ElementName=uc}"
                              Size="{Binding ChosenHeight, ElementName=uc, Mode=TwoWay}" />
                              Size="{Binding ChosenHeight, ElementName=uc, Mode=TwoWay}" />
         </DockPanel>
         </DockPanel>
         <CheckBox Name="aspectRatio" Content="Preserve aspect ratio" Foreground="White" HorizontalAlignment="Left" Margin="50,10,0,0" />
         <CheckBox Name="aspectRatio" Content="Preserve aspect ratio" Foreground="White" HorizontalAlignment="Left" Margin="50,10,0,0" />

+ 2 - 11
PixiEditor/Views/UserControls/SizePicker.xaml.cs

@@ -17,9 +17,6 @@ namespace PixiEditor.Views
         public static readonly DependencyProperty ChosenHeightProperty =
         public static readonly DependencyProperty ChosenHeightProperty =
             DependencyProperty.Register(nameof(ChosenHeight), typeof(int), typeof(SizePicker), new PropertyMetadata(1));
             DependencyProperty.Register(nameof(ChosenHeight), typeof(int), typeof(SizePicker), new PropertyMetadata(1));
 
 
-        public static readonly DependencyProperty NextControlProperty =
-            DependencyProperty.Register(nameof(NextControl), typeof(FrameworkElement), typeof(SizePicker));
-
         public SizePicker()
         public SizePicker()
         {
         {
             InitializeComponent();
             InitializeComponent();
@@ -43,15 +40,9 @@ namespace PixiEditor.Views
             set => SetValue(ChosenHeightProperty, value);
             set => SetValue(ChosenHeightProperty, value);
         }
         }
 
 
-        public FrameworkElement NextControl
-        {
-            get => (FrameworkElement)GetValue(NextControlProperty);
-            set => SetValue(NextControlProperty, value);
-        }
-
         public void FocusWidthPicker()
         public void FocusWidthPicker()
         {
         {
-            WidthPicker.Focus();
+            WidthPicker.FocusAndSelect();
         }
         }
     }
     }
-}
+}