Browse Source

Fixed bindings, swatches and stuff

flabbet 3 years ago
parent
commit
44587c2242

+ 23 - 0
PixiEditor/Helpers/Converters/IndexToAssociatedKeyConverter.cs

@@ -0,0 +1,23 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+
+namespace PixiEditor.Helpers.Converters
+{
+    public class IndexToAssociatedKeyConverter : SingleInstanceConverter<IndexToAssociatedKeyConverter>
+    {
+        public override object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            if(value is int index && index < 10)
+            {
+                if (index == 9) return 0;
+                return (int?)index + 1;
+            }
+
+            return (int?)null;
+        }
+    }
+}

+ 3 - 3
PixiEditor/ViewModels/SubViewModels/Main/ColorsViewModel.cs

@@ -54,12 +54,12 @@ namespace PixiEditor.ViewModels.SubViewModels.Main
             SelectPaletteColorCommand = new RelayCommand<int>(SelectPaletteColor);
         }
 
-        private void SelectPaletteColor(int number)
+        private void SelectPaletteColor(int index)
         {
             var document = Owner.BitmapManager.ActiveDocument;
-            if(document.Palette != null && document.Palette.Count >= number)
+            if(document.Palette != null && document.Palette.Count > index)
             {
-                PrimaryColor = document.Palette[number - 1];
+                PrimaryColor = document.Palette[index];
             }
         }
 

+ 6 - 4
PixiEditor/ViewModels/ViewModelMain.cs

@@ -209,11 +209,13 @@ namespace PixiEditor.ViewModels
                         "View",
                         new Shortcut(Key.OemTilde, ViewportSubViewModel.ToggleGridLinesCommand, "Toggle gridlines", modifier: ModifierKeys.Control)));
 
-            Shortcut[] colorShortcuts = new Shortcut[9];
-            for (int i = 0; i < colorShortcuts.Length; i++)
+            Shortcut[] colorShortcuts = new Shortcut[10];
+            colorShortcuts[9] = new Shortcut(
+                Key.D0, ColorsSubViewModel.SelectPaletteColorCommand, 9);
+            for (int i = 0; i < colorShortcuts.Length - 1; i++)
             {
-                //34 is a D1 key integer value
-                colorShortcuts[i] = new Shortcut((Key)34 + i, ColorsSubViewModel.SelectPaletteColorCommand, i);
+                //35 is a D1 key integer value
+                colorShortcuts[i] = new Shortcut((Key)35 + i, ColorsSubViewModel.SelectPaletteColorCommand, i);
             }
 
             ShortcutController.ShortcutGroups.Add(new ShortcutGroup("Palette Colors", colorShortcuts));

+ 0 - 1
PixiEditor/Views/MainWindow.xaml

@@ -351,7 +351,6 @@
                                                                  CanDockAsTabbedDocument="False" CanFloat="True">
                                         <usercontrols:SwatchesView
                                             SelectSwatchCommand="{Binding ColorsSubViewModel.SelectColorCommand}"
-                                            RemoveSwatchCommand="{Binding ColorsSubViewModel.RemoveSwatchCommand}"
                                             Swatches="{Binding BitmapManager.ActiveDocument.Swatches}"/>
                                     </avalondock:LayoutAnchorable>
 

+ 299 - 0
PixiEditor/Views/UserControls/OutlinedTextBlock.cs

@@ -0,0 +1,299 @@
+using System;
+using System.ComponentModel;
+using System.Globalization;
+using System.Windows;
+using System.Windows.Documents;
+using System.Windows.Markup;
+using System.Windows.Media;
+
+namespace PixiEditor.Views.UserControls
+{
+
+    [ContentProperty("Text")]
+    public class OutlinedTextBlock : FrameworkElement
+    {
+        private void UpdatePen()
+        {
+            _Pen = new Pen(Stroke, StrokeThickness)
+            {
+                DashCap = PenLineCap.Round,
+                EndLineCap = PenLineCap.Round,
+                LineJoin = PenLineJoin.Round,
+                StartLineCap = PenLineCap.Round
+            };
+
+            InvalidateVisual();
+        }
+
+        public static readonly DependencyProperty FillProperty = DependencyProperty.Register(
+          "Fill",
+          typeof(Brush),
+          typeof(OutlinedTextBlock),
+          new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.AffectsRender));
+
+        public static readonly DependencyProperty StrokeProperty = DependencyProperty.Register(
+          "Stroke",
+          typeof(Brush),
+          typeof(OutlinedTextBlock),
+          new FrameworkPropertyMetadata(Brushes.Black, FrameworkPropertyMetadataOptions.AffectsRender, StrokePropertyChangedCallback));
+
+        private static void StrokePropertyChangedCallback(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs dependencyPropertyChangedEventArgs)
+        {
+            (dependencyObject as OutlinedTextBlock)?.UpdatePen();
+        }
+
+        public static readonly DependencyProperty StrokeThicknessProperty = DependencyProperty.Register(
+          "StrokeThickness",
+          typeof(double),
+          typeof(OutlinedTextBlock),
+          new FrameworkPropertyMetadata(1d, FrameworkPropertyMetadataOptions.AffectsRender, StrokePropertyChangedCallback));
+
+        public static readonly DependencyProperty FontFamilyProperty = TextElement.FontFamilyProperty.AddOwner(
+          typeof(OutlinedTextBlock),
+          new FrameworkPropertyMetadata(OnFormattedTextUpdated));
+
+        public static readonly DependencyProperty FontSizeProperty = TextElement.FontSizeProperty.AddOwner(
+          typeof(OutlinedTextBlock),
+          new FrameworkPropertyMetadata(OnFormattedTextUpdated));
+
+        public static readonly DependencyProperty FontStretchProperty = TextElement.FontStretchProperty.AddOwner(
+          typeof(OutlinedTextBlock),
+          new FrameworkPropertyMetadata(OnFormattedTextUpdated));
+
+        public static readonly DependencyProperty FontStyleProperty = TextElement.FontStyleProperty.AddOwner(
+          typeof(OutlinedTextBlock),
+          new FrameworkPropertyMetadata(OnFormattedTextUpdated));
+
+        public static readonly DependencyProperty FontWeightProperty = TextElement.FontWeightProperty.AddOwner(
+          typeof(OutlinedTextBlock),
+          new FrameworkPropertyMetadata(OnFormattedTextUpdated));
+
+        public static readonly DependencyProperty TextProperty = DependencyProperty.Register(
+          "Text",
+          typeof(string),
+          typeof(OutlinedTextBlock),
+          new FrameworkPropertyMetadata(OnFormattedTextInvalidated));
+
+        public static readonly DependencyProperty TextAlignmentProperty = DependencyProperty.Register(
+          "TextAlignment",
+          typeof(TextAlignment),
+          typeof(OutlinedTextBlock),
+          new FrameworkPropertyMetadata(OnFormattedTextUpdated));
+
+        public static readonly DependencyProperty TextDecorationsProperty = DependencyProperty.Register(
+          "TextDecorations",
+          typeof(TextDecorationCollection),
+          typeof(OutlinedTextBlock),
+          new FrameworkPropertyMetadata(OnFormattedTextUpdated));
+
+        public static readonly DependencyProperty TextTrimmingProperty = DependencyProperty.Register(
+          "TextTrimming",
+          typeof(TextTrimming),
+          typeof(OutlinedTextBlock),
+          new FrameworkPropertyMetadata(OnFormattedTextUpdated));
+
+        public static readonly DependencyProperty TextWrappingProperty = DependencyProperty.Register(
+          "TextWrapping",
+          typeof(TextWrapping),
+          typeof(OutlinedTextBlock),
+          new FrameworkPropertyMetadata(TextWrapping.NoWrap, OnFormattedTextUpdated));
+
+        private FormattedText _FormattedText;
+        private Geometry _TextGeometry;
+        private Pen _Pen;
+
+        public Brush Fill
+        {
+            get { return (Brush)GetValue(FillProperty); }
+            set { SetValue(FillProperty, value); }
+        }
+
+        public FontFamily FontFamily
+        {
+            get { return (FontFamily)GetValue(FontFamilyProperty); }
+            set { SetValue(FontFamilyProperty, value); }
+        }
+
+        [TypeConverter(typeof(FontSizeConverter))]
+        public double FontSize
+        {
+            get { return (double)GetValue(FontSizeProperty); }
+            set { SetValue(FontSizeProperty, value); }
+        }
+
+        public FontStretch FontStretch
+        {
+            get { return (FontStretch)GetValue(FontStretchProperty); }
+            set { SetValue(FontStretchProperty, value); }
+        }
+
+        public FontStyle FontStyle
+        {
+            get { return (FontStyle)GetValue(FontStyleProperty); }
+            set { SetValue(FontStyleProperty, value); }
+        }
+
+        public FontWeight FontWeight
+        {
+            get { return (FontWeight)GetValue(FontWeightProperty); }
+            set { SetValue(FontWeightProperty, value); }
+        }
+
+        public Brush Stroke
+        {
+            get { return (Brush)GetValue(StrokeProperty); }
+            set { SetValue(StrokeProperty, value); }
+        }
+
+        public double StrokeThickness
+        {
+            get { return (double)GetValue(StrokeThicknessProperty); }
+            set { SetValue(StrokeThicknessProperty, value); }
+        }
+
+        public string Text
+        {
+            get { return (string)GetValue(TextProperty); }
+            set { SetValue(TextProperty, value); }
+        }
+
+        public TextAlignment TextAlignment
+        {
+            get { return (TextAlignment)GetValue(TextAlignmentProperty); }
+            set { SetValue(TextAlignmentProperty, value); }
+        }
+
+        public TextDecorationCollection TextDecorations
+        {
+            get { return (TextDecorationCollection)GetValue(TextDecorationsProperty); }
+            set { SetValue(TextDecorationsProperty, value); }
+        }
+
+        public TextTrimming TextTrimming
+        {
+            get { return (TextTrimming)GetValue(TextTrimmingProperty); }
+            set { SetValue(TextTrimmingProperty, value); }
+        }
+
+        public TextWrapping TextWrapping
+        {
+            get { return (TextWrapping)GetValue(TextWrappingProperty); }
+            set { SetValue(TextWrappingProperty, value); }
+        }
+
+        public OutlinedTextBlock()
+        {
+            UpdatePen();
+            TextDecorations = new TextDecorationCollection();
+        }
+
+        protected override void OnRender(DrawingContext drawingContext)
+        {
+            EnsureGeometry();
+
+            drawingContext.DrawGeometry(null, _Pen, _TextGeometry);
+            drawingContext.DrawGeometry(Fill, null, _TextGeometry);
+        }
+
+        protected override Size MeasureOverride(Size availableSize)
+        {
+            EnsureFormattedText();
+
+            // constrain the formatted text according to the available size
+
+            double w = availableSize.Width;
+            double h = availableSize.Height;
+
+            // the Math.Min call is important - without this constraint (which seems arbitrary, but is the maximum allowable text width), things blow up when availableSize is infinite in both directions
+            // the Math.Max call is to ensure we don't hit zero, which will cause MaxTextHeight to throw
+            _FormattedText.MaxTextWidth = Math.Min(3579139, w);
+            _FormattedText.MaxTextHeight = Math.Max(0.0001d, h);
+
+            // return the desired size
+            return new Size(Math.Ceiling(_FormattedText.Width), Math.Ceiling(_FormattedText.Height));
+        }
+
+        protected override Size ArrangeOverride(Size finalSize)
+        {
+            EnsureFormattedText();
+
+            // update the formatted text with the final size
+            _FormattedText.MaxTextWidth = finalSize.Width;
+            _FormattedText.MaxTextHeight = Math.Max(0.0001d, finalSize.Height);
+
+            // need to re-generate the geometry now that the dimensions have changed
+            _TextGeometry = null;
+
+            return finalSize;
+        }
+
+        private static void OnFormattedTextInvalidated(DependencyObject dependencyObject,
+          DependencyPropertyChangedEventArgs e)
+        {
+            var outlinedTextBlock = (OutlinedTextBlock)dependencyObject;
+            outlinedTextBlock._FormattedText = null;
+            outlinedTextBlock._TextGeometry = null;
+
+            outlinedTextBlock.InvalidateMeasure();
+            outlinedTextBlock.InvalidateVisual();
+        }
+
+        private static void OnFormattedTextUpdated(DependencyObject dependencyObject, DependencyPropertyChangedEventArgs e)
+        {
+            var outlinedTextBlock = (OutlinedTextBlock)dependencyObject;
+            outlinedTextBlock.UpdateFormattedText();
+            outlinedTextBlock._TextGeometry = null;
+
+            outlinedTextBlock.InvalidateMeasure();
+            outlinedTextBlock.InvalidateVisual();
+        }
+
+        private void EnsureFormattedText()
+        {
+            if (_FormattedText != null)
+            {
+                return;
+            }
+
+            _FormattedText = new FormattedText(
+              Text ?? "",
+              CultureInfo.CurrentUICulture,
+              FlowDirection,
+              new Typeface(FontFamily, FontStyle, FontWeight, FontStretch),
+              FontSize,
+              Brushes.Black);
+
+            UpdateFormattedText();
+        }
+
+        private void UpdateFormattedText()
+        {
+            if (_FormattedText == null)
+            {
+                return;
+            }
+
+            _FormattedText.MaxLineCount = TextWrapping == TextWrapping.NoWrap ? 1 : int.MaxValue;
+            _FormattedText.TextAlignment = TextAlignment;
+            _FormattedText.Trimming = TextTrimming;
+
+            _FormattedText.SetFontSize(FontSize);
+            _FormattedText.SetFontStyle(FontStyle);
+            _FormattedText.SetFontWeight(FontWeight);
+            _FormattedText.SetFontFamily(FontFamily);
+            _FormattedText.SetFontStretch(FontStretch);
+            _FormattedText.SetTextDecorations(TextDecorations);
+        }
+
+        private void EnsureGeometry()
+        {
+            if (_TextGeometry != null)
+            {
+                return;
+            }
+
+            EnsureFormattedText();
+            _TextGeometry = _FormattedText.BuildGeometry(new Point(0, 0));
+        }
+    }
+}

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

@@ -39,7 +39,7 @@
             <TextBlock Text="Drop palette here" Foreground="White" FontSize="32" HorizontalAlignment="Center" VerticalAlignment="Center"/>
         </Grid>
         <ScrollViewer Grid.Row="2" HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
-           <ItemsControl ItemsSource="{Binding Colors, ElementName=paletteControl}">
+           <ItemsControl ItemsSource="{Binding Colors, ElementName=paletteControl}" AlternationCount="9999">
                <d:ItemsControl.ItemsSource>
                    <x:Array Type="{x:Type Color}">
                        <Color R="0" G="0" B="0" A="255"/>
@@ -59,7 +59,9 @@
                </ItemsControl.ItemsPanel>
                <ItemsControl.ItemTemplate>
                     <DataTemplate>
-                        <local:PaletteColor Color="{Binding}" Margin="0 5 5 5">
+                        <local:PaletteColor Color="{Binding}" Margin="0 5 5 5"
+                                            AssociatedKey="{Binding Path=(ItemsControl.AlternationIndex), 
+                RelativeSource={RelativeSource TemplatedParent}, Converter={converters:IndexToAssociatedKeyConverter}}">
                             <b:Interaction.Triggers>
                                 <b:EventTrigger EventName="MouseDown">
                                     <b:InvokeCommandAction

+ 5 - 1
PixiEditor/Views/UserControls/PaletteColor.xaml

@@ -3,11 +3,12 @@
              xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
-             xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
+             xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters" xmlns:usercontrols="clr-namespace:PixiEditor.Views.UserControls"
              mc:Ignorable="d"
              d:DesignHeight="45" d:DesignWidth="45" Name="uc">
     <UserControl.Resources>
         <converters:SKColorToMediaColorConverter x:Key="SKColorToMediaColorConverter" />
+        <BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter" />
     </UserControl.Resources>
     <Grid Width="45" Height="45">
         <Border CornerRadius="5.5" Width="44" Height="44" RenderOptions.BitmapScalingMode="NearestNeighbor">
@@ -24,5 +25,8 @@
                 <SolidColorBrush Color="{Binding Color, Converter={StaticResource SKColorToMediaColorConverter}, ElementName=uc}" />
             </Border.Background>
         </Border>
+        <usercontrols:OutlinedTextBlock Stroke="White" StrokeThickness="2" FontSize="16" Margin="0, 0, 4, 2" 
+                                        Text="{Binding AssociatedKey, ElementName=uc}" 
+                                        Visibility="{Binding ElementName=uc, Path=AssociatedKey, Converter={converters:NotNullToVisibilityConverter}}" HorizontalAlignment="Right" VerticalAlignment="Bottom"/>
     </Grid>
 </UserControl>

+ 13 - 0
PixiEditor/Views/UserControls/PaletteColor.xaml.cs

@@ -15,6 +15,19 @@ public partial class PaletteColor : UserControl
         set { SetValue(ColorProperty, value); }
     }
 
+
+
+    public int? AssociatedKey
+    {
+        get { return (int?)GetValue(AssociatedKeyProperty); }
+        set { SetValue(AssociatedKeyProperty, value); }
+    }
+
+    // Using a DependencyProperty as the backing store for AssociatedKey.  This enables animation, styling, binding, etc...
+    public static readonly DependencyProperty AssociatedKeyProperty =
+        DependencyProperty.Register("AssociatedKey", typeof(int?), typeof(PaletteColor), new PropertyMetadata(null));
+
+
     public PaletteColor()
     {
         InitializeComponent();

+ 3 - 3
PixiEditor/Views/UserControls/SwatchesView.xaml

@@ -6,7 +6,7 @@
              xmlns:local="clr-namespace:PixiEditor.Views.UserControls" 
              xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity"
              xmlns:conv="clr-namespace:PixiEditor.Helpers.Converters"
-             mc:Ignorable="d" Name="uc"
+             mc:Ignorable="d" Name="swatchesView"
              d:DesignHeight="450" d:DesignWidth="300">
     <UserControl.Resources>
         <ResourceDictionary>
@@ -14,7 +14,7 @@
         </ResourceDictionary>
     </UserControl.Resources>
     <ScrollViewer HorizontalScrollBarVisibility="Disabled" VerticalScrollBarVisibility="Auto">
-        <ItemsControl ItemsSource="{Binding Swatches, ElementName=uc}">
+        <ItemsControl ItemsSource="{Binding Swatches, ElementName=swatchesView}">
             <d:ItemsControl.ItemsSource>
                 <x:Array Type="{x:Type Color}">
                     <Color R="0" G="0" B="0" A="255"/>
@@ -45,7 +45,7 @@
                         <local:PaletteColor.ContextMenu>
                             <ContextMenu>
                                 <MenuItem Header="Remove" Foreground="White"
-                                          Command="{Binding RemoveSwatchCommand, ElementName=uc}"
+                                          Command="{Binding Source={x:Reference Name=swatchesView}, Path=DataContext.ColorsSubViewModel.RemoveSwatchCommand}"
                                           CommandParameter="{Binding}" />
                             </ContextMenu>
                         </local:PaletteColor.ContextMenu>

+ 0 - 9
PixiEditor/Views/UserControls/SwatchesView.xaml.cs

@@ -38,15 +38,6 @@ namespace PixiEditor.Views.UserControls
             set => SetValue(SelectSwatchCommandProperty, value);
         }
 
-        public static readonly DependencyProperty RemoveSwatchCommandProperty =
-            DependencyProperty.Register(nameof(RemoveSwatchCommand), typeof(ICommand), typeof(SwatchesView));
-
-        public ICommand RemoveSwatchCommand
-        {
-            get => (ICommand)GetValue(RemoveSwatchCommandProperty);
-            set => SetValue(RemoveSwatchCommandProperty, value);
-        }
-
         public SwatchesView()
         {
             InitializeComponent();