Browse Source

Added Navigation Window

CPKreuz 4 years ago
parent
commit
a0c0a709b3

+ 20 - 0
PixiEditor/Helpers/Converters/NotNullToVisibiltyConverter.cs

@@ -0,0 +1,20 @@
+using System;
+using System.Globalization;
+using System.Windows;
+using System.Windows.Data;
+
+namespace PixiEditor.Helpers.Converters
+{
+    class NotNullToVisibiltyConverter : IValueConverter
+    {
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            return value != null ? Visibility.Visible : Visibility.Hidden;
+        }
+
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            throw new NotImplementedException();
+        }
+    }
+}

+ 7 - 1
PixiEditor/Models/DataHolders/Document/Document.Layers.cs

@@ -4,11 +4,12 @@ using System.Collections.ObjectModel;
 using System.Linq;
 using System.Linq;
 using System.Text.RegularExpressions;
 using System.Text.RegularExpressions;
 using System.Windows;
 using System.Windows;
+using System.Windows.Media;
 using System.Windows.Media.Imaging;
 using System.Windows.Media.Imaging;
-using GalaSoft.MvvmLight.Messaging;
 using PixiEditor.Helpers;
 using PixiEditor.Helpers;
 using PixiEditor.Models.Controllers;
 using PixiEditor.Models.Controllers;
 using PixiEditor.Models.Enums;
 using PixiEditor.Models.Enums;
+using PixiEditor.Models.ImageManipulation;
 using PixiEditor.Models.Layers;
 using PixiEditor.Models.Layers;
 using PixiEditor.Models.Position;
 using PixiEditor.Models.Position;
 using PixiEditor.Models.Undo;
 using PixiEditor.Models.Undo;
@@ -339,6 +340,11 @@ namespace PixiEditor.Models.DataHolders
             return layer;
             return layer;
         }
         }
 
 
+        public Color GetColorAtPoint(int x, int y)
+        {
+            return BitmapUtils.GetColorAtPointCombined(x, y, Layers.ToArray());
+        }
+
         private void InjectRemoveActiveLayersUndo(object[] guidArgs, StorageBasedChange change)
         private void InjectRemoveActiveLayersUndo(object[] guidArgs, StorageBasedChange change)
         {
         {
             Action<Layer[], UndoLayer[]> undoAction = RestoreLayersProcess;
             Action<Layer[], UndoLayer[]> undoAction = RestoreLayersProcess;

+ 47 - 22
PixiEditor/Models/ImageManipulation/BitmapUtils.cs

@@ -5,6 +5,7 @@ using PixiEditor.Parser;
 using System;
 using System;
 using System.Collections.Generic;
 using System.Collections.Generic;
 using System.Linq;
 using System.Linq;
+using System.Runtime.CompilerServices;
 using System.Windows;
 using System.Windows;
 using System.Windows.Media;
 using System.Windows.Media;
 using System.Windows.Media.Imaging;
 using System.Windows.Media.Imaging;
@@ -56,30 +57,14 @@ namespace PixiEditor.Models.ImageManipulation
                         throw new InvalidOperationException("Layers must not extend beyond canvas borders");
                         throw new InvalidOperationException("Layers must not extend beyond canvas borders");
                     }
                     }
 
 
-                    for (int y = 0; y < layers[i].Height; y++)
+                    for (int y = 0; y < height; y++)
                     {
                     {
-                        for (int x = 0; x < layers[i].Width; x++)
+                        for (int x = 0; x < width; x++)
                         {
                         {
-                            Color color = layer.GetPixel(x, y);
-                            if (i > 0 && ((color.A < 255 && color.A > 0) || (layerOpacity < 1f && layerOpacity > 0 && color.A > 0)))
-                            {
-                                var lastLayerPixel = finalBitmap.GetPixel(x + layer.OffsetX, y + layer.OffsetY);
-                                byte pixelA = (byte)(color.A * layerOpacity);
-                                byte r = (byte)((color.R * pixelA / 255) + (lastLayerPixel.R * lastLayerPixel.A * (255 - pixelA) / (255 * 255)));
-                                byte g = (byte)((color.G * pixelA / 255) + (lastLayerPixel.G * lastLayerPixel.A * (255 - pixelA) / (255 * 255)));
-                                byte b = (byte)((color.B * pixelA / 255) + (lastLayerPixel.B * lastLayerPixel.A * (255 - pixelA) / (255 * 255)));
-                                byte a = (byte)(pixelA + (lastLayerPixel.A * (255 - pixelA) / 255));
-                                color = Color.FromArgb(a, r, g, b);
-                            }
-                            else
-                            {
-                                color = Color.FromArgb(color.A, color.R, color.G, color.B);
-                            }
-
-                            if (color.A > 0)
-                            {
-                                finalBitmap.SetPixel(x + layer.OffsetX, y + layer.OffsetY, color);
-                            }
+                            Color previousColor = finalBitmap.GetPixel(x, y);
+                            Color color = layer.GetPixelWithOffset(x, y);
+
+                            finalBitmap.SetPixel(x, y, BlendColor(previousColor, color, layerOpacity));
                         }
                         }
                     }
                     }
                 }
                 }
@@ -88,6 +73,21 @@ namespace PixiEditor.Models.ImageManipulation
             return finalBitmap;
             return finalBitmap;
         }
         }
 
 
+        public static Color GetColorAtPointCombined(int x, int y, params Layer[] layers)
+        {
+            Color prevColor = Color.FromArgb(0, 0, 0, 0);
+
+            for (int i = 0; i < layers.Length; i++)
+            {
+                Color color = layers[i].GetPixelWithOffset(x, y);
+                float layerOpacity = layers[i].Opacity;
+
+                prevColor = BlendColor(prevColor, color, layerOpacity);
+            }
+
+            return prevColor;
+        }
+
         /// <summary>
         /// <summary>
         /// Generates simplified preview from Document, very fast, great for creating small previews. Creates uniform streched image.
         /// Generates simplified preview from Document, very fast, great for creating small previews. Creates uniform streched image.
         /// </summary>
         /// </summary>
@@ -152,6 +152,31 @@ namespace PixiEditor.Models.ImageManipulation
             return result;
             return result;
         }
         }
 
 
+        [MethodImpl(MethodImplOptions.AggressiveInlining)]
+        private static Color BlendColor(Color previousColor, Color color, float opacity)
+        {
+            if ((color.A < 255 && color.A > 0) || (opacity < 1f && opacity > 0 && color.A > 0))
+            {
+                byte pixelA = (byte)(color.A * opacity);
+                byte r = (byte)((color.R * pixelA / 255) + (previousColor.R * previousColor.A * (255 - pixelA) / (255 * 255)));
+                byte g = (byte)((color.G * pixelA / 255) + (previousColor.G * previousColor.A * (255 - pixelA) / (255 * 255)));
+                byte b = (byte)((color.B * pixelA / 255) + (previousColor.B * previousColor.A * (255 - pixelA) / (255 * 255)));
+                byte a = (byte)(pixelA + (previousColor.A * (255 - pixelA) / 255));
+                color = Color.FromArgb(a, r, g, b);
+            }
+            else
+            {
+                color = Color.FromArgb(color.A, color.R, color.G, color.B);
+            }
+
+            if (color.A > 0)
+            {
+                return color;
+            }
+
+            return previousColor;
+        }
+
         private static WriteableBitmap GeneratePreviewBitmap(
         private static WriteableBitmap GeneratePreviewBitmap(
             IEnumerable<WriteableBitmap> layerBitmaps,
             IEnumerable<WriteableBitmap> layerBitmaps,
             IEnumerable<int> offsetsX,
             IEnumerable<int> offsetsX,

+ 18 - 10
PixiEditor/Views/MainWindow.xaml

@@ -203,16 +203,6 @@
             </ItemsControl>
             </ItemsControl>
         </StackPanel>
         </StackPanel>
         <Grid Grid.Column="1" Grid.Row="2" Background="#303030">
         <Grid Grid.Column="1" Grid.Row="2" Background="#303030">
-            <Grid.ContextMenu>
-                <ContextMenu>
-                    <MenuItem Header="_Select All" Command="{Binding SelectionSubViewModel.SelectAllCommand}" InputGestureText="Ctrl+A" />
-                    <MenuItem Header="_Deselect" Command="{Binding SelectionSubViewModel.DeselectCommand}" InputGestureText="Ctrl+D" />
-                    <Separator/>
-                    <MenuItem Header="_Cut" Command="{Binding ClipboardSubViewModel.CutCommand}" InputGestureText="Ctrl+X" />
-                    <MenuItem Header="_Copy" Command="{Binding ClipboardSubViewModel.CopyCommand}" InputGestureText="Ctrl+C" />
-                    <MenuItem Header="_Paste" Command="{Binding ClipboardSubViewModel.PasteCommand}" InputGestureText="Ctrl+V" />
-                </ContextMenu>
-            </Grid.ContextMenu>
             <Grid>
             <Grid>
                 <DockingManager ActiveContent="{Binding BitmapManager.ActiveDocument, Mode=TwoWay}" 
                 <DockingManager ActiveContent="{Binding BitmapManager.ActiveDocument, Mode=TwoWay}" 
                                            DocumentsSource="{Binding BitmapManager.Documents}">
                                            DocumentsSource="{Binding BitmapManager.Documents}">
@@ -250,6 +240,16 @@
                                                 <i:InvokeCommandAction Command="{Binding SetAsActiveOnClickCommand}"/>
                                                 <i:InvokeCommandAction Command="{Binding SetAsActiveOnClickCommand}"/>
                                             </i:EventTrigger>
                                             </i:EventTrigger>
                                         </i:Interaction.Triggers>
                                         </i:Interaction.Triggers>
+                                        <usercontrols:DrawingViewPort.ContextMenu>
+                                            <ContextMenu>
+                                                <MenuItem Header="_Select All" Command="{Binding SelectionSubViewModel.SelectAllCommand}" InputGestureText="Ctrl+A" />
+                                                <MenuItem Header="_Deselect" Command="{Binding SelectionSubViewModel.DeselectCommand}" InputGestureText="Ctrl+D" />
+                                                <Separator/>
+                                                <MenuItem Header="_Cut" Command="{Binding ClipboardSubViewModel.CutCommand}" InputGestureText="Ctrl+X" />
+                                                <MenuItem Header="_Copy" Command="{Binding ClipboardSubViewModel.CopyCommand}" InputGestureText="Ctrl+C" />
+                                                <MenuItem Header="_Paste" Command="{Binding ClipboardSubViewModel.PasteCommand}" InputGestureText="Ctrl+V" />
+                                            </ContextMenu>
+                                        </usercontrols:DrawingViewPort.ContextMenu>
                                     </usercontrols:DrawingViewPort>
                                     </usercontrols:DrawingViewPort>
                                 </DataTemplate>
                                 </DataTemplate>
                             </ui:DocumentsTemplateSelector.DocumentsViewTemplate>
                             </ui:DocumentsTemplateSelector.DocumentsViewTemplate>
@@ -431,6 +431,14 @@
                                         </Grid>
                                         </Grid>
                                     </LayoutAnchorable>
                                     </LayoutAnchorable>
                                 </LayoutAnchorablePane>
                                 </LayoutAnchorablePane>
+                                <LayoutAnchorablePane>
+                                    <LayoutAnchorable ContentId="navigation" Title="Navigation" 
+                                                      CanHide="True" CanAutoHide="False"
+                                                      CanDockAsTabbedDocument="False" CanFloat="True">
+                                        <usercontrols:PreviewWindow Document="{Binding BitmapManager.ActiveDocument}"
+                                                                    PrimaryColor="{Binding ColorsSubViewModel.PrimaryColor, Mode=TwoWay}"/>
+                                    </LayoutAnchorable>
+                                </LayoutAnchorablePane>
                             </LayoutAnchorablePaneGroup>
                             </LayoutAnchorablePaneGroup>
                         </LayoutPanel>
                         </LayoutPanel>
                     </avalondock:LayoutRoot>
                     </avalondock:LayoutRoot>

+ 24 - 0
PixiEditor/Views/UserControls/PrependTextBlock.xaml

@@ -0,0 +1,24 @@
+<UserControl x:Class="PixiEditor.Views.UserControls.PrependTextBlock"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             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:local="clr-namespace:PixiEditor.Views.UserControls"
+             mc:Ignorable="d" 
+             d:DesignHeight="450" d:DesignWidth="800"
+             x:Name="uc">
+    <StackPanel Orientation="Horizontal">
+        <TextBlock Text="{Binding Prepend, ElementName=uc}"/>
+        
+        <TextBlock>
+            <TextBlock.Text>
+                <PriorityBinding>
+                    <Binding Path="Text" ElementName="uc"/>
+                    <Binding Path="Content" ElementName="uc"/>
+                </PriorityBinding>
+            </TextBlock.Text>
+        </TextBlock>
+
+        <TextBlock Text="{Binding Append, ElementName=uc}"/>
+    </StackPanel>
+</UserControl>

+ 73 - 0
PixiEditor/Views/UserControls/PrependTextBlock.xaml.cs

@@ -0,0 +1,73 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace PixiEditor.Views.UserControls
+{
+    /// <summary>
+    /// Interaction logic for PrependTextBlock.xaml
+    /// </summary>
+    public partial class PrependTextBlock : UserControl
+    {
+        public static readonly DependencyProperty TextProperty =
+            DependencyProperty.Register(nameof(Text), typeof(string), typeof(PrependTextBlock));
+
+        public string Text
+        {
+            get => (string)GetValue(TextProperty);
+            set => SetValue(TextProperty, value);
+        }
+
+        public static readonly DependencyProperty PrependProperty =
+            DependencyProperty.Register(nameof(Prepend), typeof(string), typeof(PrependTextBlock));
+
+        public string Prepend
+        {
+            get => (string)GetValue(PrependProperty);
+            set => SetValue(PrependProperty, value);
+        }
+
+        public static readonly DependencyProperty AppendProperty =
+            DependencyProperty.Register(nameof(Append), typeof(string), typeof(PrependTextBlock));
+
+        public string Append
+        {
+            get => (string)GetValue(AppendProperty);
+            set => SetValue(AppendProperty, value);
+        }
+
+        public static readonly DependencyProperty PrependColorProperty =
+            DependencyProperty.Register(nameof(PrependColor), typeof(Brush), typeof(PrependTextBlock));
+
+        public Brush PrependColor
+        {
+            get => (Brush)GetValue(PrependColorProperty);
+            set => SetValue(PrependColorProperty, value);
+        }
+
+        public static readonly DependencyProperty AppendColorProperty =
+            DependencyProperty.Register(nameof(AppendColor), typeof(Brush), typeof(PrependTextBlock));
+
+        public Brush AppendColor
+        {
+            get => (Brush)GetValue(AppendColorProperty);
+            set => SetValue(AppendColorProperty, value);
+        }
+
+        public PrependTextBlock()
+        {
+            InitializeComponent();
+        }
+    }
+}

+ 77 - 0
PixiEditor/Views/UserControls/PreviewWindow.xaml

@@ -0,0 +1,77 @@
+<UserControl x:Class="PixiEditor.Views.UserControls.PreviewWindow"
+             xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
+             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:local="clr-namespace:PixiEditor.Views.UserControls"
+             xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
+             mc:Ignorable="d" 
+             d:DesignHeight="400" d:DesignWidth="400" x:Name="uc"
+             Foreground="White">
+
+    <UserControl.Resources>
+        <BoolToVisibilityConverter x:Key="BoolToVisibilityConverter"/>
+        <converters:NotNullToVisibiltyConverter x:Key="NullToVisibiltyConverter"/>
+    </UserControl.Resources>
+    <Grid>
+        <Grid.RowDefinitions>
+            <RowDefinition Height="*"/>
+            <RowDefinition Height="5"/>
+            <RowDefinition Height="Auto"/>
+        </Grid.RowDefinitions>
+        <Viewbox Margin="30" VerticalAlignment="Top">
+            <Grid Cursor="None" x:Name="imageGrid"
+              Visibility="{Binding Document, Converter={StaticResource NullToVisibiltyConverter}, ElementName=uc}"
+              Height="{Binding Document.Height, ElementName=uc}" Width="{Binding Document.Width, ElementName=uc}">
+                <ItemsControl ItemsSource="{Binding Document.Layers, ElementName=uc}">
+                    <ItemsControl.ItemsPanel>
+                        <ItemsPanelTemplate>
+                            <Grid/>
+                        </ItemsPanelTemplate>
+                    </ItemsControl.ItemsPanel>
+                    <ItemsControl.ItemTemplate>
+                        <DataTemplate>
+                            <Image VerticalAlignment="Top" HorizontalAlignment="Left" Source="{Binding LayerBitmap}"
+                                               Visibility="{Binding IsVisible, Converter={StaticResource BoolToVisibilityConverter}}"
+                                               RenderOptions.BitmapScalingMode="NearestNeighbor" Stretch="Uniform"
+                                               Opacity="{Binding Opacity}"
+                                               Width="{Binding Width}" Height="{Binding Height}" Margin="{Binding Offset}"  />
+                        </DataTemplate>
+                    </ItemsControl.ItemTemplate>
+                </ItemsControl>
+                <Border x:Name="colorCursor" Width="1" Height="1"
+                    Margin="{Binding ColorCursorPosition, ElementName=uc}"
+                    HorizontalAlignment="Left" VerticalAlignment="Top"
+                    BorderBrush="Black" BorderThickness=".1"
+                    Visibility="{Binding IsMouseOver, ElementName=uc, Converter={StaticResource BoolToVisibilityConverter}}">
+                    <Border BorderThickness=".1" BorderBrush="White"/>
+                </Border>
+            </Grid>
+        </Viewbox>
+        <Grid Grid.Row="1">
+            <Grid.Background>
+                <SolidColorBrush Color="{Binding ColorCursorColor, ElementName=uc, FallbackValue=Black}"/>
+            </Grid.Background>
+        </Grid>
+        <StackPanel Grid.Row="2" Orientation="Horizontal" MinHeight="30"
+                    Background="{StaticResource MainColor}" MaxHeight="60">
+            <StackPanel.Resources>
+                <Style TargetType="local:PrependTextBlock">
+                    <Setter Property="VerticalAlignment" Value="Center"/>
+                </Style>
+            </StackPanel.Resources>
+
+            <local:PrependTextBlock Prepend=" X: " Text="{Binding ColorCursorPosition.Left, ElementName=uc}"/>
+            <local:PrependTextBlock Prepend=" Y: " Text="{Binding ColorCursorPosition.Top, ElementName=uc}"/>
+
+            <Grid Width="15"/>
+
+            <local:PrependTextBlock Prepend=" R: " Text="{Binding ColorCursorColor.R, ElementName=uc}"/>
+            <local:PrependTextBlock Prepend=" G: " Text="{Binding ColorCursorColor.G, ElementName=uc}"/>
+            <local:PrependTextBlock Prepend=" B: " Text="{Binding ColorCursorColor.B, ElementName=uc}"/>
+            <local:PrependTextBlock Prepend=" A: " Text="{Binding ColorCursorColor.A, ElementName=uc}"/>
+
+            <local:PrependTextBlock Prepend="  (" Text="{Binding ColorCursorColor, ElementName=uc, FallbackValue=#00000000}" Append=")"/>
+        </StackPanel>
+    </Grid>
+</UserControl>

+ 100 - 0
PixiEditor/Views/UserControls/PreviewWindow.xaml.cs

@@ -0,0 +1,100 @@
+using PixiEditor.Models.DataHolders;
+using PixiEditor.Models.ImageManipulation;
+using PixiEditor.Models.Layers;
+using System;
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Data;
+using System.Windows.Documents;
+using System.Windows.Input;
+using System.Windows.Media;
+using System.Windows.Media.Imaging;
+using System.Windows.Navigation;
+using System.Windows.Shapes;
+
+namespace PixiEditor.Views.UserControls
+{
+    /// <summary>
+    /// Interaction logic for PreviewWindow.xaml
+    /// </summary>
+    public partial class PreviewWindow : UserControl
+    {
+        public static readonly DependencyProperty DocumentProperty =
+            DependencyProperty.Register(nameof(Document), typeof(Document), typeof(PreviewWindow));
+
+        public Document Document
+        { 
+            get => (Document)GetValue(DocumentProperty);
+            set => SetValue(DocumentProperty, value);
+        }
+
+        public static readonly DependencyProperty ColorCursorPositionProperty =
+            DependencyProperty.Register(nameof(ColorCursorPosition), typeof(Thickness), typeof(PreviewWindow));
+
+        public Thickness ColorCursorPosition
+        {
+            get => (Thickness)GetValue(ColorCursorPositionProperty);
+            private set => SetValue(ColorCursorPositionProperty, value);
+        }
+
+        public static readonly DependencyProperty ColorCursorColorProperty =
+            DependencyProperty.Register(nameof(ColorCursorColor), typeof(Color), typeof(PreviewWindow));
+
+        public Color ColorCursorColor
+        {
+            get => (Color)GetValue(ColorCursorColorProperty);
+            set => SetValue(ColorCursorColorProperty, value);
+        }
+
+        public static readonly DependencyProperty PrimaryColorProperty =
+            DependencyProperty.Register(nameof(PrimaryColor), typeof(Color), typeof(PreviewWindow));
+
+        public Color PrimaryColor
+        {
+            get => (Color)GetValue(PrimaryColorProperty);
+            set => SetValue(PrimaryColorProperty, value);
+        }
+
+        public PreviewWindow()
+        {
+            InitializeComponent();
+
+            MouseMove += PreviewWindow_MouseMove;
+            MouseRightButtonDown += PreviewWindow_MouseRightButtonDown;
+        }
+
+        private void PreviewWindow_MouseRightButtonDown(object sender, MouseButtonEventArgs e)
+        {
+            PrimaryColor = ColorCursorColor;
+        }
+
+        private void PreviewWindow_MouseMove(object sender, MouseEventArgs e)
+        {
+            if (Document == null)
+            {
+                return;
+            }
+
+            Point mousePos = e.GetPosition(imageGrid);
+
+            int x = (int)mousePos.X;
+            int y = (int)mousePos.Y;
+
+            Thickness newPos = new Thickness(x, y, 0, 0);
+
+            if (ColorCursorPosition == newPos)
+            {
+                return;
+            }
+
+            ColorCursorPosition = newPos;
+
+            ColorCursorColor = BitmapUtils.GetColorAtPointCombined(x, y, Document.Layers.ToArray());
+        }
+    }
+}