Ver código fonte

Merge branch 'group-layers' into sync-middleman

Krzysztof Krysiński 4 anos atrás
pai
commit
3be88e5144

+ 26 - 0
PixiEditor/Helpers/Converters/LayersToStructuredLayersConverter.cs

@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Windows.Data;
+using PixiEditor.Models.Layers;
+
+namespace PixiEditor.Helpers.Converters
+{
+    public class LayersToStructuredLayersConverter : IMultiValueConverter
+    {
+        public object Convert(object[] values, Type targetType, object parameter, CultureInfo culture)
+        {
+            if (values[0] is IEnumerable<Layer> layers && values[1] is LayerStructure structure)
+            {
+                return new StructuredLayerTree(layers, structure).Items;
+            }
+
+            return new StructuredLayerTree();
+        }
+
+        public object[] ConvertBack(object value, Type[] targetTypes, object parameter, CultureInfo culture)
+        {
+            throw new NotImplementedException();
+        }
+    }
+}

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

@@ -21,7 +21,9 @@ namespace PixiEditor.Models.DataHolders
 
         public ObservableCollection<Layer> Layers { get; set; } = new ObservableCollection<Layer>();
 
-        public Layer ActiveLayer => Layers.Count > 0 ? Layers.FirstOrDefault(x => x.LayerGuid == ActiveLayerGuid) : null;
+        public LayerStructure LayerStructure { get; set; } = new LayerStructure();
+
+        public Layer ActiveLayer => Layers.Count > 0 ? Layers[ActiveLayerIndex] : null;
 
         public Guid ActiveLayerGuid
         {

+ 15 - 0
PixiEditor/Models/Layers/GuidStructureItem.cs

@@ -0,0 +1,15 @@
+using System;
+using System.Collections.ObjectModel;
+
+namespace PixiEditor.Models.Layers
+{
+    public class GuidStructureItem
+    {
+        public ObservableCollection<Guid> Children { get; set; }
+
+        public GuidStructureItem(ObservableCollection<Guid> children)
+        {
+            Children = children;
+        }
+    }
+}

+ 19 - 0
PixiEditor/Models/Layers/LayerStructure.cs

@@ -0,0 +1,19 @@
+using System.Collections.ObjectModel;
+
+namespace PixiEditor.Models.Layers
+{
+    public class LayerStructure
+    {
+        public ObservableCollection<GuidStructureItem> Items { get; set; }
+
+        public LayerStructure(ObservableCollection<GuidStructureItem> items)
+        {
+            Items = items;
+        }
+
+        public LayerStructure()
+        {
+            Items = new ObservableCollection<GuidStructureItem>();
+        }
+    }
+}

+ 14 - 0
PixiEditor/Models/Layers/LayerStructureItem.cs

@@ -0,0 +1,14 @@
+using System.Collections.ObjectModel;
+
+namespace PixiEditor.Models.Layers
+{
+    public class LayerStructureItem
+    {
+        public ObservableCollection<Layer> Children { get; set; } = new ObservableCollection<Layer>();
+
+        public LayerStructureItem(ObservableCollection<Layer> children)
+        {
+            Children = children;
+        }
+    }
+}

+ 40 - 0
PixiEditor/Models/Layers/StructuredLayerTree.cs

@@ -0,0 +1,40 @@
+using System.Collections.Generic;
+using System.Collections.ObjectModel;
+using System.Linq;
+
+namespace PixiEditor.Models.Layers
+{
+    public class StructuredLayerTree
+    {
+        public ObservableCollection<LayerStructureItem> Items { get; set; } = new ObservableCollection<LayerStructureItem>();
+
+        public StructuredLayerTree(IEnumerable<Layer> layers, LayerStructure structure)
+        {
+            if (structure == null || structure.Items.Count == 0)
+            {
+                foreach (var layer in layers)
+                {
+                    Items.Add(new LayerStructureItem(new ObservableCollection<Layer> { layer }));
+                }
+
+                return;
+            }
+
+            for (int i = 0; i < structure.Items.Count; i++)
+            {
+                var itemChildren = new ObservableCollection<Layer>();
+                foreach (var guid in structure.Items[i].Children)
+                {
+                    itemChildren.Add(layers.First(x => x.LayerGuid == guid));
+                }
+
+                Items.Add(new LayerStructureItem(itemChildren));
+            }
+        }
+
+        public StructuredLayerTree()
+        {
+            
+        }
+    }
+}

+ 67 - 153
PixiEditor/Views/MainWindow.xaml

@@ -11,10 +11,10 @@
         xmlns:cmd="http://www.galasoft.ch/mvvmlight" 
         xmlns:avalondock="https://github.com/Dirkster99/AvalonDock"
         xmlns:colorpicker="clr-namespace:ColorPicker;assembly=ColorPicker" xmlns:usercontrols="clr-namespace:PixiEditor.Views.UserControls" xmlns:behaviours="clr-namespace:PixiEditor.Helpers.Behaviours" 
-        xmlns:avalonDockTheme="clr-namespace:PixiEditor.Styles.AvalonDock" d:DataContext="{d:DesignInstance Type=vm:ViewModelMain}"
+        xmlns:avalonDockTheme="clr-namespace:PixiEditor.Styles.AvalonDock"
         mc:Ignorable="d" WindowStyle="None" Initialized="MainWindow_Initialized"
         Title="PixiEditor" Name="mainWindow" Height="1000" Width="1600" Background="{StaticResource MainColor}"
-        WindowStartupLocation="CenterScreen" WindowState="Maximized">
+        WindowStartupLocation="CenterScreen" WindowState="Maximized" DataContext="{DynamicResource ViewModelMain}">
     <WindowChrome.WindowChrome>
         <WindowChrome CaptionHeight="32"
                       ResizeBorderThickness="{x:Static SystemParameters.WindowResizeBorderThickness}" />
@@ -22,11 +22,9 @@
 
     <Window.Resources>
         <ResourceDictionary>
-            <!--<vm:ViewModelMain x:Key="ViewModelMain" />-->
+            <vm:ViewModelMain x:Key="ViewModelMain" />
             <BooleanToVisibilityConverter x:Key="BoolToVisibilityConverter" />
             <converters:BoolToIntConverter x:Key="BoolToIntConverter" />
-            <converters:NotNullToBoolConverter x:Key="NotNullToBoolConverter" />
-            <converters:FloatNormalizeConverter x:Key="FloatNormalizeConverter" />
             <converters:DoubleToIntConverter x:Key="DoubleToIntConverter"/>
             <ResourceDictionary.MergedDictionaries>
                 <ResourceDictionary Source="pack://application:,,,/ColorPicker;component/Styles/DefaultColorPickerStyle.xaml" />
@@ -229,159 +227,75 @@
                             <LayoutDocumentPane/>
                             <LayoutAnchorablePaneGroup Orientation="Vertical" DockWidth="290">
                                 <LayoutAnchorablePane>
-                                <LayoutAnchorable ContentId="colorPicker" Title="Color Picker" CanHide="False"
+                                    <LayoutAnchorable ContentId="colorPicker" Title="Color Picker" CanHide="False"
                                                              CanClose="False" CanAutoHide="False"
                                                              CanDockAsTabbedDocument="False" CanFloat="True">
-                                    <colorpicker:StandardColorPicker Grid.Row="0" SelectedColor="{Binding ColorsSubViewModel.PrimaryColor, Mode=TwoWay}"
+                                        <colorpicker:StandardColorPicker Grid.Row="0" SelectedColor="{Binding ColorsSubViewModel.PrimaryColor, Mode=TwoWay}"
                                      SecondaryColor="{Binding ColorsSubViewModel.SecondaryColor, Mode=TwoWay}" Style="{StaticResource DefaultColorPickerStyle}" >
-                                        <i:Interaction.Behaviors>
-                                            <behaviours:GlobalShortcutFocusBehavior/>
-                                        </i:Interaction.Behaviors>
-                                    </colorpicker:StandardColorPicker>
-                                </LayoutAnchorable>
-                                <avalondock:LayoutAnchorable ContentId="swatches" Title="Swatches" CanHide="False"
+                                            <i:Interaction.Behaviors>
+                                                <behaviours:GlobalShortcutFocusBehavior/>
+                                            </i:Interaction.Behaviors>
+                                        </colorpicker:StandardColorPicker>
+                                    </LayoutAnchorable>
+                                    <avalondock:LayoutAnchorable ContentId="swatches" Title="Swatches" CanHide="False"
                                                          CanClose="False" CanAutoHide="False"
                                                          CanDockAsTabbedDocument="False" CanFloat="True">
-                                    <ScrollViewer HorizontalScrollBarVisibility="Disabled"
+                                        <ScrollViewer HorizontalScrollBarVisibility="Disabled"
                                               VerticalScrollBarVisibility="Auto">
-                                        <ItemsControl ItemsSource="{Binding BitmapManager.ActiveDocument.Swatches}">
-                                            <ItemsControl.ItemsPanel>
-                                                <ItemsPanelTemplate>
-                                                    <WrapPanel Margin="10,10,0,10" Orientation="Horizontal"
+                                            <ItemsControl ItemsSource="{Binding BitmapManager.ActiveDocument.Swatches}">
+                                                <ItemsControl.ItemsPanel>
+                                                    <ItemsPanelTemplate>
+                                                        <WrapPanel Margin="10,10,0,10" Orientation="Horizontal"
                                                            VerticalAlignment="Top" HorizontalAlignment="Left" />
-                                                </ItemsPanelTemplate>
-                                            </ItemsControl.ItemsPanel>
-                                            <ItemsControl.ItemTemplate>
-                                                <DataTemplate>
-                                                    <Grid Width="45" Height="45" Margin="0 5 5 5">
-                                                        <Border CornerRadius="5.5" Width="44" Height="44">
-                                                            <Border.Background>
-                                                                <ImageBrush ImageSource="../Images/transparentbg.png"
+                                                    </ItemsPanelTemplate>
+                                                </ItemsControl.ItemsPanel>
+                                                <ItemsControl.ItemTemplate>
+                                                    <DataTemplate>
+                                                        <Grid Width="45" Height="45" Margin="0 5 5 5">
+                                                            <Border CornerRadius="5.5" Width="44" Height="44">
+                                                                <Border.Background>
+                                                                    <ImageBrush ImageSource="../Images/transparentbg.png"
                                                                         Stretch="UniformToFill">
-                                                                    <ImageBrush.RelativeTransform>
-                                                                        <ScaleTransform ScaleX="6" ScaleY="6" CenterX="0.5"
+                                                                        <ImageBrush.RelativeTransform>
+                                                                            <ScaleTransform ScaleX="6" ScaleY="6" CenterX="0.5"
                                                                                     CenterY="0.5" />
-                                                                    </ImageBrush.RelativeTransform>
-                                                                </ImageBrush>
-                                                            </Border.Background>
-                                                        </Border>
-                                                        <Border CornerRadius="5.5" BorderThickness="0 0 0 0.1" BorderBrush="White" Cursor="Hand">
-                                                            <Border.Background>
-                                                                <SolidColorBrush Color="{Binding}" />
-                                                            </Border.Background>
-                                                        </Border>
-                                                        <i:Interaction.Triggers>
-                                                            <i:EventTrigger EventName="MouseDown">
-                                                                <i:InvokeCommandAction
+                                                                        </ImageBrush.RelativeTransform>
+                                                                    </ImageBrush>
+                                                                </Border.Background>
+                                                            </Border>
+                                                            <Border CornerRadius="5.5" BorderThickness="0 0 0 0.1" BorderBrush="White" Cursor="Hand">
+                                                                <Border.Background>
+                                                                    <SolidColorBrush Color="{Binding}" />
+                                                                </Border.Background>
+                                                            </Border>
+                                                            <i:Interaction.Triggers>
+                                                                <i:EventTrigger EventName="MouseDown">
+                                                                    <i:InvokeCommandAction
                                                                 Command="{Binding
                                                                     RelativeSource={RelativeSource FindAncestor, AncestorType={x:Type Window}}, Path=DataContext.ColorsSubViewModel.SelectColorCommand}"
                                                                 CommandParameter="{Binding}" />
-                                                            </i:EventTrigger>
-                                                        </i:Interaction.Triggers>
-                                                        <Grid.ContextMenu>
-                                                            <ContextMenu>
-                                                                <MenuItem Header="Remove" Foreground="White"
-                                                                      Command="{Binding ColorsSubViewModel.RemoveSwatchCommand}"
+                                                                </i:EventTrigger>
+                                                            </i:Interaction.Triggers>
+                                                            <Grid.ContextMenu>
+                                                                <ContextMenu>
+                                                                    <MenuItem Header="Remove" Foreground="White"
+                                                                      Command="{Binding ColorsSubViewModel.RemoveSwatchCommand, Source={StaticResource ViewModelMain}}"
                                                                       CommandParameter="{Binding}" />
-                                                            </ContextMenu>
-                                                        </Grid.ContextMenu>
-                                                    </Grid>
-                                                </DataTemplate>
-                                            </ItemsControl.ItemTemplate>
-                                        </ItemsControl>
-                                    </ScrollViewer>
-                                </avalondock:LayoutAnchorable>
-                            </LayoutAnchorablePane>
+                                                                </ContextMenu>
+                                                            </Grid.ContextMenu>
+                                                        </Grid>
+                                                    </DataTemplate>
+                                                </ItemsControl.ItemTemplate>
+                                            </ItemsControl>
+                                        </ScrollViewer>
+                                    </avalondock:LayoutAnchorable>
+                                </LayoutAnchorablePane>
                                 <LayoutAnchorablePane>
                                     <LayoutAnchorable ContentId="layers" Title="Layers" CanHide="False"
                                                          CanClose="False" CanAutoHide="False"
                                                          CanDockAsTabbedDocument="True" CanFloat="True">
-                                        <Grid>
-                                            <Grid.RowDefinitions>
-                                                <RowDefinition Height="40"/>
-                                                <RowDefinition Height="30"/>
-                                                <RowDefinition Height="15"/>
-                                                <RowDefinition Height="1*"/>
-                                            </Grid.RowDefinitions>
-                                            <Button Grid.Row="0" Command="{Binding LayersSubViewModel.NewLayerCommand}" Height="30" Content="New Layer"
-                                            HorizontalAlignment="Stretch" Margin="5"
-                                            Style="{StaticResource DarkRoundButton}" />
-                                            <StackPanel Grid.Row="1" Orientation="Horizontal" Margin="10,0">
-                                                <Label Content="Opacity" Foreground="White" VerticalAlignment="Center"/>
-                                                <vws:NumberInput 
-                                                    Min="0" Max="100"
-                                                    IsEnabled="{Binding Path=BitmapManager.ActiveDocument, 
-                                                    Converter={StaticResource NotNullToBoolConverter}}" 
-                                                    Width="40" Height="20"
-                                                    VerticalAlignment="Center"
-                                                   Value="{Binding BitmapManager.ActiveDocument.ActiveLayer.OpacityUndoTriggerable, Mode=TwoWay, 
-                                            Converter={StaticResource FloatNormalizeConverter}}" />
-                                                <Label Content="%" Foreground="White" VerticalAlignment="Center"/>
-                                            </StackPanel>
-                                            <Separator Grid.Row="2" Background="{StaticResource BrighterAccentColor}"/>
-                                            <ScrollViewer Grid.Row="3" VerticalScrollBarVisibility="Auto">
-                                                <ItemsControl ItemsSource="{Binding BitmapManager.ActiveDocument.Layers}"
-                                                      x:Name="layersItemsControl" AlternationCount="9999">
-                                                    <ItemsControl.ItemsPanel>
-                                                        <ItemsPanelTemplate>
-                                                            <ui:ReversedOrderStackPanel Orientation="Vertical" />
-                                                        </ItemsPanelTemplate>
-                                                    </ItemsControl.ItemsPanel>
-                                                    <ItemsControl.ItemTemplate>
-                                                        <DataTemplate>
-                                                            <vws:LayerItem Tag="{Binding DataContext, ElementName=mainWindow}" LayerIndex="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
-                                Path=(ItemsControl.AlternationIndex)}" SetActiveLayerCommand="{Binding Path=DataContext.LayersSubViewModel.SetActiveLayerCommand, ElementName=mainWindow}"
-                                                                   LayerName="{Binding Name, Mode=TwoWay}" IsActive="{Binding IsActive, Mode=TwoWay}"
-                                                                   IsRenaming="{Binding IsRenaming, Mode=TwoWay}"
-                                                                   PreviewImage="{Binding LayerBitmap}" 
-                                                                   LayerColor="{Binding LayerHighlightColor}"
-                                                                   MoveToBackCommand="{Binding DataContext.LayersSubViewModel.MoveToBackCommand, ElementName=mainWindow}"
-                                                                   MoveToFrontCommand="{Binding DataContext.LayersSubViewModel.MoveToFrontCommand, ElementName=mainWindow}">
-                                                                <vws:LayerItem.ContextMenu>
-                                                                    <ContextMenu>
-                                                                        <MenuItem Header="Delete"
-                                                                                  Command="{Binding PlacementTarget.Tag.LayersSubViewModel.DeleteLayersCommand,
-                                                                                    RelativeSource={RelativeSource AncestorType=ContextMenu}}"
-
-                                                                                  CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
-                                Path=(ItemsControl.AlternationIndex)}" />
-                                                                        <MenuItem Header="Rename"
-                                                                                  Command="{Binding PlacementTarget.Tag.LayersSubViewModel.RenameLayerCommand,
-                                                                            RelativeSource={RelativeSource AncestorType=ContextMenu}}"
-                                                                                  CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
-                                Path=(ItemsControl.AlternationIndex)}" />
-                                                                        <MenuItem Header="Move to front"
-                                                                                  Command="{Binding PlacementTarget.Tag.LayersSubViewModel.MoveToFrontCommand, 
-                                                                            RelativeSource={RelativeSource AncestorType=ContextMenu}}"
-                                                                                  CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
-                                Path=(ItemsControl.AlternationIndex)}" />
-                                                                        <MenuItem Header="Move to back"
-                                                                                  Command="{Binding PlacementTarget.Tag.LayersSubViewModel.MoveToBackCommand, 
-                                                                            RelativeSource={RelativeSource AncestorType=ContextMenu}}"
-                                                                                  CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
-                                Path=(ItemsControl.AlternationIndex)}" />
-                                                                        <Separator/>
-                                                                        <MenuItem Header="Merge selected"
-                                                                                  Command="{Binding PlacementTarget.Tag.LayersSubViewModel.MergeSelectedCommand, 
-                                                                            RelativeSource={RelativeSource AncestorType=ContextMenu}}"/>
-                                                                        <MenuItem Header="Merge with above"
-                                                                                  Command="{Binding PlacementTarget.Tag.LayersSubViewModel.MergeWithAboveCommand, 
-                                                                            RelativeSource={RelativeSource AncestorType=ContextMenu}}"
-                                                                                  CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
-                                Path=(ItemsControl.AlternationIndex)}" />
-                                                                        <MenuItem Header="Merge with below"
-                                                                                  Command="{Binding PlacementTarget.Tag.LayersSubViewModel.MergeWithBelowCommand, 
-                                                                            RelativeSource={RelativeSource AncestorType=ContextMenu}}"
-                                                                                  CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
-                                Path=(ItemsControl.AlternationIndex)}" />
-                                                                    </ContextMenu>
-                                                                </vws:LayerItem.ContextMenu>
-                                                            </vws:LayerItem>
-                                                        </DataTemplate>
-                                                    </ItemsControl.ItemTemplate>
-                                                </ItemsControl>
-                                            </ScrollViewer>
-                                        </Grid>
+                                        <usercontrols:LayersManager LayersViewModel="{Binding LayersSubViewModel}"
+                                                                    BitmapManager="{Binding BitmapManager}"/>
                                     </LayoutAnchorable>
                                 </LayoutAnchorablePane>
                             </LayoutAnchorablePaneGroup>
@@ -418,22 +332,22 @@
                 <ColumnDefinition Width="290"/>
             </Grid.ColumnDefinitions>
             <DockPanel>
-            <TextBlock Text="{Binding BitmapManager.SelectedTool.ActionDisplay}" Foreground="White" FontSize="15" Margin="10,0,0,0" VerticalAlignment="Center"/>
-            <StackPanel DockPanel.Dock="Right" Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
-                <TextBlock Text="X:" Foreground="White" FontSize="16"/>
-                <TextBlock Margin="4,0,10,0" Text="{Binding BitmapManager.ActiveDocument.MouseXOnCanvas, Converter={StaticResource DoubleToIntConverter}}" Foreground="White" FontSize="16"/>
-                <TextBlock Text="Y:" Foreground="White" FontSize="16"/>
-                <TextBlock Margin="4,0,10,0" Text="{Binding BitmapManager.ActiveDocument.MouseYOnCanvas, Converter={StaticResource DoubleToIntConverter}}" Foreground="White" FontSize="16"/>
-            </StackPanel>
-        </DockPanel>
-        <StackPanel Margin="10,0,0,0" VerticalAlignment="Center" Grid.Row="3"
+                <TextBlock Text="{Binding BitmapManager.SelectedTool.ActionDisplay}" Foreground="White" FontSize="15" Margin="10,0,0,0" VerticalAlignment="Center"/>
+                <StackPanel DockPanel.Dock="Right" Orientation="Horizontal" HorizontalAlignment="Right" VerticalAlignment="Center">
+                    <TextBlock Text="X:" Foreground="White" FontSize="16"/>
+                    <TextBlock Margin="4,0,10,0" Text="{Binding BitmapManager.ActiveDocument.MouseXOnCanvas, Converter={StaticResource DoubleToIntConverter}}" Foreground="White" FontSize="16"/>
+                    <TextBlock Text="Y:" Foreground="White" FontSize="16"/>
+                    <TextBlock Margin="4,0,10,0" Text="{Binding BitmapManager.ActiveDocument.MouseYOnCanvas, Converter={StaticResource DoubleToIntConverter}}" Foreground="White" FontSize="16"/>
+                </StackPanel>
+            </DockPanel>
+            <StackPanel Margin="10,0,0,0" VerticalAlignment="Center" Grid.Row="3"
                        Grid.Column="3" Orientation="Horizontal">
-            <Button Style="{StaticResource BaseDarkButton}" 
+                <Button Style="{StaticResource BaseDarkButton}" 
                     Visibility="{Binding UpdateSubViewModel.UpdateReadyToInstall, Converter={StaticResource BoolToVisibilityConverter}}" FontSize="14" Height="20" 
                     Command="{Binding UpdateSubViewModel.RestartApplicationCommand}">Restart</Button>
-            <TextBlock VerticalAlignment="Center" Padding="10" HorizontalAlignment="Right"
+                <TextBlock VerticalAlignment="Center" Padding="10" HorizontalAlignment="Right"
                        Foreground="White" FontSize="14"  Text="{Binding UpdateSubViewModel.VersionText}" />
-        </StackPanel>
+            </StackPanel>
         </Grid>
     </Grid>
 </Window>

+ 6 - 10
PixiEditor/Views/UserControls/LayerItem.xaml.cs

@@ -1,21 +1,17 @@
 using System;
-using System.Collections.Generic;
-using System.Text;
+using System.Collections.ObjectModel;
 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;
 using PixiEditor.Helpers;
+using PixiEditor.Helpers.UI;
+using PixiEditor.Models.Layers;
 
 namespace PixiEditor.Views
 {
     /// <summary>
-    /// Interaction logic for LayerItem.xaml
+    /// Interaction logic for LayerItem.xaml.
     /// </summary>
     public partial class LayerItem : UserControl
     {
@@ -29,7 +25,7 @@ namespace PixiEditor.Views
 
         public bool IsRenaming
         {
-            get { return (bool) GetValue(IsRenamingProperty); }
+            get { return (bool)GetValue(IsRenamingProperty); }
             set { SetValue(IsRenamingProperty, value); }
         }
 
@@ -38,7 +34,7 @@ namespace PixiEditor.Views
 
         public bool IsActive
         {
-            get { return (bool) GetValue(IsActiveProperty); }
+            get { return (bool)GetValue(IsActiveProperty); }
             set { SetValue(IsActiveProperty, value); }
         }
 

+ 73 - 0
PixiEditor/Views/UserControls/LayerStructureItemContainer.xaml

@@ -0,0 +1,73 @@
+<UserControl x:Class="PixiEditor.Views.UserControls.LayerStructureItemContainer"
+             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:vws="clr-namespace:PixiEditor.Views" xmlns:ui="clr-namespace:PixiEditor.Helpers.UI"
+             mc:Ignorable="d" 
+             d:DesignHeight="60" d:DesignWidth="250" Name="uc">
+    <Grid>
+        <ItemsControl Name="itemsControl" ItemsSource="{Binding Item.Children, ElementName=uc}">
+            <ItemsControl.ItemsPanel>
+                <ItemsPanelTemplate>
+                    <ui:ReversedOrderStackPanel Orientation="Vertical" />
+                </ItemsPanelTemplate>
+            </ItemsControl.ItemsPanel>
+            <ItemsControl.ItemTemplate>
+                <DataTemplate>
+            <vws:LayerItem Tag="{Binding Path=DataContext, ElementName=layersItemsControl}" 
+                                       LayerIndex="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
+                                Path=(ItemsControl.AlternationIndex)}" 
+                                       SetActiveLayerCommand="{Binding DataContext.LayersViewModel.SetActiveLayerCommand, 
+                            ElementName=layersItemsControl}"
+                                       LayerName="{Binding Name, Mode=TwoWay}" 
+                                       IsActive="{Binding IsActive, Mode=TwoWay}"
+                                       IsRenaming="{Binding IsRenaming, Mode=TwoWay}"
+                                       PreviewImage="{Binding LayerBitmap}"
+                                      MoveToBackCommand="{Binding DataContext.LayersViewModel.MoveToBackCommand, ElementName=layersItemsControl}"
+                                      MoveToFrontCommand="{Binding DataContext.LayersViewModel.MoveToFrontCommand, ElementName=layersItemsControl}">
+                <vws:LayerItem.ContextMenu>
+                    <ContextMenu>
+                        <MenuItem Header="Delete"
+                                         Command="{Binding PlacementTarget.Tag.LayersViewModel.DeleteLayersCommand, 
+                                            RelativeSource={RelativeSource AncestorType=ContextMenu}}"
+                                         CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
+                                Path=(ItemsControl.AlternationIndex)}" />
+                        <MenuItem Header="Rename"
+                                     Command="{Binding PlacementTarget.Tag.LayersViewModel.RenameLayerCommand, 
+                                            RelativeSource={RelativeSource AncestorType=ContextMenu}}"
+                                     CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
+                                Path=(ItemsControl.AlternationIndex)}" />
+                        <MenuItem Header="Move to front"
+                                     Command="{Binding PlacementTarget.Tag.LayersViewModel.MoveToFrontCommand, 
+                                            RelativeSource={RelativeSource AncestorType=ContextMenu}}"
+                                     CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
+                                Path=(ItemsControl.AlternationIndex)}" />
+                        <MenuItem Header="Move to back"
+                                    Command="{Binding PlacementTarget.Tag.LayersViewModel.MoveToBackCommand, 
+                                            RelativeSource={RelativeSource AncestorType=ContextMenu}}"
+                                     CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
+                                Path=(ItemsControl.AlternationIndex)}" />
+                        <Separator/>
+                        <MenuItem Header="Merge selected"
+                                     Command="{Binding PlacementTarget.Tag.LayersViewModel.MergeSelectedCommand, 
+                                            RelativeSource={RelativeSource AncestorType=ContextMenu}}"/>
+                        <MenuItem Header="Merge with above"
+                                     Command="{Binding PlacementTarget.Tag.LayersViewModel.MergeWithAboveCommand, 
+                                            RelativeSource={RelativeSource AncestorType=ContextMenu}}"
+                                     CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
+                                Path=(ItemsControl.AlternationIndex)}" />
+                        <MenuItem Header="Merge with below"
+                                    Command="{Binding PlacementTarget.Tag.LayersViewModel.MergeWithBelowCommand, 
+                                            RelativeSource={RelativeSource AncestorType=ContextMenu}}"
+                                    CommandParameter="{Binding RelativeSource={RelativeSource Mode=TemplatedParent},
+                                Path=(ItemsControl.AlternationIndex)}" />
+                    </ContextMenu>
+                </vws:LayerItem.ContextMenu>
+            </vws:LayerItem>
+                </DataTemplate>
+            </ItemsControl.ItemTemplate>
+        </ItemsControl>
+    </Grid>
+</UserControl>

+ 44 - 0
PixiEditor/Views/UserControls/LayerStructureItemContainer.xaml.cs

@@ -0,0 +1,44 @@
+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;
+using PixiEditor.Models.Layers;
+
+namespace PixiEditor.Views.UserControls
+{
+    /// <summary>
+    /// Interaction logic for LayerStructureItemContainer.xaml.
+    /// </summary>
+    public partial class LayerStructureItemContainer : UserControl
+    {
+
+        public LayerStructureItem Item
+        {
+            get { return (LayerStructureItem)GetValue(ItemProperty); }
+            set { SetValue(ItemProperty, value); }
+        }
+
+        // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
+        public static readonly DependencyProperty ItemProperty =
+            DependencyProperty.Register(
+                "Item",
+                typeof(LayerStructureItem),
+                typeof(LayerStructureItemContainer),
+                new PropertyMetadata(default(LayerStructureItem)));
+
+        public LayerStructureItemContainer()
+        {
+            InitializeComponent();
+        }
+    }
+}

+ 64 - 0
PixiEditor/Views/UserControls/LayersManager.xaml

@@ -0,0 +1,64 @@
+<UserControl x:Class="PixiEditor.Views.UserControls.LayersManager"
+             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:ui="clr-namespace:PixiEditor.Helpers.UI"
+             xmlns:local="clr-namespace:PixiEditor.Views.UserControls"
+             xmlns:vws="clr-namespace:PixiEditor.Views" 
+             xmlns:layers="clr-namespace:PixiEditor.Models.Layers"
+             xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters" 
+             d:DataContext="{d:DesignInstance Type=local:LayersManager}"
+             mc:Ignorable="d"
+             d:DesignHeight="450" d:DesignWidth="250" Name="uc">
+    <UserControl.Resources>
+        <converters:NotNullToBoolConverter x:Key="NotNullToBoolConverter" />
+        <converters:FloatNormalizeConverter x:Key="FloatNormalizeConverter" />
+        <converters:LayersToStructuredLayersConverter x:Key="LayersToStructuredLayersConverter"/>
+    </UserControl.Resources>
+    <Grid>
+        <Grid.RowDefinitions>
+            <RowDefinition Height="40"/>
+            <RowDefinition Height="30"/>
+            <RowDefinition Height="15"/>
+            <RowDefinition Height="1*"/>
+        </Grid.RowDefinitions>
+        <Button Grid.Row="0" Command="{Binding LayersViewModel.NewLayerCommand, ElementName=uc}" Height="30" Content="New Layer"
+                                            HorizontalAlignment="Stretch" Margin="5"
+                                            Style="{StaticResource DarkRoundButton}" />
+        <StackPanel Grid.Row="1" Orientation="Horizontal" Margin="10,0">
+            <Label Content="Opacity" Foreground="White" VerticalAlignment="Center"/>
+            <vws:NumberInput                                         
+                    Min="0" Max="100"
+                    IsEnabled="{Binding Path=BitmapManager.ActiveDocument, 
+                    Converter={StaticResource NotNullToBoolConverter}, ElementName=uc}" 
+                    Width="40" Height="20"
+                    VerticalAlignment="Center"
+                    Value="{Binding BitmapManager.ActiveDocument.ActiveLayer.OpacityUndoTriggerable, Mode=TwoWay, 
+                    Converter={StaticResource FloatNormalizeConverter}, ElementName=uc}" />
+            <Label Content="%" Foreground="White" VerticalAlignment="Center"/>
+        </StackPanel>
+        <Separator Grid.Row="2" Background="{StaticResource BrighterAccentColor}"/>
+        <ScrollViewer Grid.Row="3" VerticalScrollBarVisibility="Auto">
+            <ItemsControl DataContext="{Binding ElementName=uc}" 
+                          x:Name="layersItemsControl" AlternationCount="9999" d:DataContext="{x:Type layers:LayerStructureItem}">
+                <ItemsControl.ItemsSource>
+                    <MultiBinding Converter="{StaticResource LayersToStructuredLayersConverter}">
+                        <Binding Path="BitmapManager.ActiveDocument.Layers" ElementName="uc"/>
+                        <Binding Path="BitmapManager.ActiveDocument.LayerStructure" ElementName="uc"/>
+                    </MultiBinding>
+                </ItemsControl.ItemsSource>
+                <ItemsControl.ItemsPanel>
+                    <ItemsPanelTemplate>
+                        <ui:ReversedOrderStackPanel Orientation="Vertical" />
+                    </ItemsPanelTemplate>
+                </ItemsControl.ItemsPanel>
+                <ItemsControl.ItemTemplate>
+                    <DataTemplate>
+                        <local:LayerStructureItemContainer Item="{Binding}"/>
+                    </DataTemplate>
+                </ItemsControl.ItemTemplate>
+            </ItemsControl>
+        </ScrollViewer>
+    </Grid>
+</UserControl>

+ 38 - 0
PixiEditor/Views/UserControls/LayersManager.xaml.cs

@@ -0,0 +1,38 @@
+using System.Windows;
+using System.Windows.Controls;
+using PixiEditor.Models.Controllers;
+using PixiEditor.ViewModels.SubViewModels.Main;
+
+namespace PixiEditor.Views.UserControls
+{
+    /// <summary>
+    /// Interaction logic for LayersManager.xaml.
+    /// </summary>
+    public partial class LayersManager : UserControl
+    {
+        public LayersViewModel LayersViewModel
+        {
+            get { return (LayersViewModel)GetValue(LayersViewModelProperty); }
+            set { SetValue(LayersViewModelProperty, value); }
+        }
+
+        // Using a DependencyProperty as the backing store for LayersViewModel.  This enables animation, styling, binding, etc...
+        public static readonly DependencyProperty LayersViewModelProperty =
+            DependencyProperty.Register("LayersViewModel", typeof(LayersViewModel), typeof(LayersManager), new PropertyMetadata(default(LayersViewModel)));
+
+        public BitmapManager BitmapManager
+        {
+            get { return (BitmapManager)GetValue(BitmapManagerProperty); }
+            set { SetValue(BitmapManagerProperty, value); }
+        }
+
+        // Using a DependencyProperty as the backing store for BitmapManager.  This enables animation, styling, binding, etc...
+        public static readonly DependencyProperty BitmapManagerProperty =
+            DependencyProperty.Register("BitmapManager", typeof(BitmapManager), typeof(LayersManager), new PropertyMetadata(default(BitmapManager)));
+
+        public LayersManager()
+        {
+            InitializeComponent();
+        }
+    }
+}