瀏覽代碼

Styled treeview

flabbet 4 年之前
父節點
當前提交
5c5d1a3411

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

@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Globalization;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+using System.Windows.Data;
+
+namespace PixiEditor.Helpers.Converters
+{
+    public class IndentConverter : IValueConverter
+    {
+        private const int IndentSize = 16;  // hard-coded into the XAML template
+
+        public object Convert(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            return new GridLength(((GridLength)value).Value + IndentSize);
+        }
+
+        public object ConvertBack(object value, Type targetType, object parameter, CultureInfo culture)
+        {
+            return Binding.DoNothing;
+        }
+    }
+}

+ 26 - 0
PixiEditor/Helpers/UI/TreeViewItemHelper.cs

@@ -0,0 +1,26 @@
+using System;
+using System.Collections.Generic;
+using System.Linq;
+using System.Text;
+using System.Threading.Tasks;
+using System.Windows;
+
+namespace PixiEditor.Helpers.UI
+{
+    public static class TreeViewItemHelper
+    {
+        public static GridLength GetIndent(DependencyObject obj)
+        {
+            return (GridLength)obj.GetValue(IndentProperty);
+        }
+
+        public static void SetIndent(DependencyObject obj, GridLength value)
+        {
+            obj.SetValue(IndentProperty, value);
+        }
+
+        // Using a DependencyProperty as the backing store for Indent.  This enables animation, styling, binding, etc...
+        public static readonly DependencyProperty IndentProperty =
+            DependencyProperty.RegisterAttached("Indent", typeof(GridLength), typeof(TreeViewItemHelper), new PropertyMetadata(new GridLength(0)));
+    }
+}

二進制
PixiEditor/Images/transparentbg_mini.png


+ 27 - 6
PixiEditor/Models/ImageManipulation/BitmapUtils.cs

@@ -83,25 +83,46 @@ namespace PixiEditor.Models.ImageManipulation
       /// <summary>
         /// Generates simplified preview from Document, very fast, great for creating small previews. Creates uniform streched image.
         /// </summary>
-        /// <param name="document">Document which be used to generate preview.</param>
+        /// <param name="document">Document which will be used to generate preview.</param>
         /// <param name="maxPreviewWidth">Max width of preview.</param>
         /// <param name="maxPreviewHeight">Max height of preview.</param>
         /// <returns>WriteableBitmap image.</returns>
         public static WriteableBitmap GeneratePreviewBitmap(Document document, int maxPreviewWidth, int maxPreviewHeight)
         {
-            WriteableBitmap previewBitmap = BitmapFactory.New(document.Width, document.Height);
+            return GeneratePreviewBitmap(document.Layers, maxPreviewWidth, maxPreviewHeight, document.Width, document.Height, 0, 0);
+        }
+
+        /// <summary>
+        /// Generates simplified preview from layers, very fast, great for creating small previews. Creates uniform streched image.
+        /// </summary>
+        /// <param name="layers">Layers which will be used to generate preview.</param>
+        /// <param name="maxPreviewWidth">Max width of preview.</param>
+        /// <param name="maxPreviewHeight">Max height of preview.</param>
+        /// <returns>WriteableBitmap image.</returns>
+        public static WriteableBitmap GeneratePreviewBitmap(IEnumerable<Layer> layers, int maxPreviewWidth, int maxPreviewHeight)
+        {
+            int minOffsetX = layers.Min(x => x.OffsetX);
+            int minOffsetY = layers.Min(x => x.OffsetY);
+            int width = layers.Max(x => x.OffsetX + x.Width) - minOffsetX;
+            int height = layers.Max(x => x.OffsetY + x.Height) - minOffsetY;
+            return GeneratePreviewBitmap(layers, maxPreviewWidth, maxPreviewHeight, width, height, minOffsetX, minOffsetY);
+        }
+
+        private static WriteableBitmap GeneratePreviewBitmap(IEnumerable<Layer> layers, int maxPreviewWidth, int maxPreviewHeight, int width, int height, int minOffsetX, int minOffsetY)
+        {
+            WriteableBitmap previewBitmap = BitmapFactory.New(width, height);
 
             // 0.8 because blit doesn't take into consideration layer opacity. Small images with opacity > 80% are simillar enough.
-            foreach (var layer in document.Layers.Where(x => x.IsVisible && x.Opacity > 0.8f))
+            foreach (var layer in layers.Where(x => x.IsVisible && x.Opacity > 0.8f))
             {
                 previewBitmap.Blit(
-                    new Rect(layer.OffsetX, layer.OffsetY, layer.Width, layer.Height),
+                    new Rect(layer.OffsetX - minOffsetX, layer.OffsetY - minOffsetY, layer.Width, layer.Height),
                     layer.LayerBitmap,
                     new Rect(0, 0, layer.Width, layer.Height));
             }
 
-            int width = document.Width >= document.Height ? maxPreviewWidth : (int)Math.Ceiling(document.Width / ((float)document.Height / maxPreviewHeight));
-            int height = document.Height > document.Width ? maxPreviewHeight : (int)Math.Ceiling(document.Height / ((float)document.Width / maxPreviewWidth));
+            int finalWidth = width >= height ? maxPreviewWidth : (int)Math.Ceiling(width / ((float)height / maxPreviewHeight));
+            int finalHeight = height > width ? maxPreviewHeight : (int)Math.Ceiling(height / ((float)width / maxPreviewWidth));
 
             return previewBitmap.Resize(width, height, WriteableBitmapExtensions.Interpolation.NearestNeighbor);
         }

+ 4 - 0
PixiEditor/PixiEditor.csproj

@@ -44,6 +44,8 @@
     <None Remove="Images\PixiEditorLogo.png" />
     <None Remove="Images\SelectImage.png" />
     <None Remove="Images\ZoomImage.png" />
+    <None Remove="Views\UserControls\transparentbg.png" />
+    <None Remove="Views\UserControls\transparentbg_mini.png" />
     <None Include="..\icon.ico">
       <Pack>True</Pack>
       <PackagePath></PackagePath>
@@ -89,6 +91,8 @@
     <Resource Include="Images\SelectImage.png" />
     <Resource Include="Images\transparentbg.png" />
     <Resource Include="Images\ZoomImage.png" />
+    <Resource Include="Views\UserControls\transparentbg.png" />
+    <Resource Include="Views\UserControls\transparentbg_mini.png" />
   </ItemGroup>
   <ItemGroup>
     <None Include="..\LICENSE">

+ 45 - 68
PixiEditor/Styles/TreeViewStyle.xaml

@@ -1,28 +1,15 @@
 <ResourceDictionary xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
                     xmlns:views="clr-namespace:PixiEditor.Views.UserControls"
-                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml">
+                    xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml" xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters" xmlns:local="clr-namespace:PixiEditor.Helpers.UI">
+
+    <converters:IndentConverter x:Key="IndentConverter" />
+    
     <Style TargetType="TreeView">
         <Setter Property="Background" Value="{StaticResource AccentColor}"/>
         <Setter Property="BorderThickness" Value="0"/>
     </Style>
 
-    <Style TargetType="{x:Type TreeViewItem}">
-        <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
-    </Style>
-
-    <Style x:Key="TreeViewItemFocusVisual">
-        <Setter Property="Control.Template">
-            <Setter.Value>
-                <ControlTemplate>
-                    <Rectangle/>
-                </ControlTemplate>
-            </Setter.Value>
-        </Setter>
-    </Style>
-
-
-    <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}"
-                      Color="Transparent" />
+    <SolidColorBrush x:Key="{x:Static SystemColors.HighlightBrushKey}" Color="Transparent"/>
     <SolidColorBrush x:Key="{x:Static SystemColors.HighlightTextBrushKey}"
                       Color="Black" />
     <SolidColorBrush x:Key="{x:Static SystemColors.InactiveSelectionHighlightBrushKey}"
@@ -39,62 +26,54 @@
     <SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Fill" Color="#FFFFFFFF"/>
     <SolidColorBrush x:Key="TreeViewItem.TreeArrow.Static.Stroke" Color="#FF818181"/>
 
+    <Style x:Key="TreeViewItemFocusVisual">
+        <Setter Property="Control.Template">
+            <Setter.Value>
+                <ControlTemplate>
+                    <Rectangle/>
+                </ControlTemplate>
+            </Setter.Value>
+        </Setter>
+    </Style>
 
-
-
-    <Style x:Key="ExpandCollapseToggleStyle" TargetType="{x:Type ToggleButton}">
+    <Style x:Key="ExpandCollapseToggleStyle" TargetType="{x:Type ToggleButton}" >
         <Setter Property="Focusable" Value="False"/>
         <Setter Property="Width" Value="16"/>
         <Setter Property="Height" Value="16"/>
         <Setter Property="Template">
             <Setter.Value>
                 <ControlTemplate TargetType="{x:Type ToggleButton}">
-                    <Border Background="Transparent" Height="16" Padding="5,5,5,5" Width="16">
-                        <Path x:Name="ExpandPath" Data="{StaticResource TreeArrow}" Fill="{StaticResource TreeViewItem.TreeArrow.Static.Fill}" Stroke="{StaticResource TreeViewItem.TreeArrow.Static.Stroke}">
+                    <Border Width="16" Height="16" Background="Transparent" Padding="5,5,5,5">
+                        <Path x:Name="ExpandPath" Fill="Transparent" Stroke="#FF989898" Data="{StaticResource TreeArrow}">
                             <Path.RenderTransform>
-                                <RotateTransform Angle="135" CenterY="3" CenterX="3"/>
+                                <RotateTransform Angle="135" CenterX="3" CenterY="3"/>
                             </Path.RenderTransform>
                         </Path>
                     </Border>
                     <ControlTemplate.Triggers>
+                        <Trigger Property="IsMouseOver" Value="True">
+                            <Setter Property="Stroke" TargetName="ExpandPath" Value="#FF1BBBFA"/>
+                            <Setter Property="Fill" TargetName="ExpandPath" Value="Transparent"/>
+                        </Trigger>
                         <Trigger Property="IsChecked" Value="True">
                             <Setter Property="RenderTransform" TargetName="ExpandPath">
                                 <Setter.Value>
-                                    <RotateTransform Angle="180" CenterY="3" CenterX="3"/>
+                                    <RotateTransform Angle="180" CenterX="3" CenterY="3"/>
                                 </Setter.Value>
                             </Setter>
-                            <Setter Property="Fill" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.Static.Checked.Fill}"/>
-                            <Setter Property="Stroke" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.Static.Checked.Stroke}"/>
+                            <Setter Property="Fill" TargetName="ExpandPath" Value="#FF595959"/>
+                            <Setter Property="Stroke" TargetName="ExpandPath" Value="#FF262626"/>
                         </Trigger>
-                        <Trigger Property="IsMouseOver" Value="True">
-                            <Setter Property="Stroke" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Stroke}"/>
-                            <Setter Property="Fill" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Fill}"/>
-                        </Trigger>
-                        <MultiTrigger>
-                            <MultiTrigger.Conditions>
-                                <Condition Property="IsMouseOver" Value="True"/>
-                                <Condition Property="IsChecked" Value="True"/>
-                            </MultiTrigger.Conditions>
-                            <Setter Property="Stroke" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Checked.Stroke}"/>
-                            <Setter Property="Fill" TargetName="ExpandPath" Value="{StaticResource TreeViewItem.TreeArrow.MouseOver.Checked.Fill}"/>
-                        </MultiTrigger>
                     </ControlTemplate.Triggers>
                 </ControlTemplate>
             </Setter.Value>
         </Setter>
     </Style>
-
-
-
-
-
-
-
-    <Style x:Key="TreeViewItemStyle1" TargetType="{x:Type TreeViewItem}">
+    <Style x:Key="TreeViewItemStyle" TargetType="{x:Type TreeViewItem}">
         <Setter Property="Background" Value="Transparent"/>
-        <Setter Property="HorizontalContentAlignment" Value="{Binding HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
-        <Setter Property="VerticalContentAlignment" Value="{Binding VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
-        <Setter Property="Padding" Value="1,0,0,0"/>
+        <Setter Property="HorizontalContentAlignment" Value="{Binding Path=HorizontalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
+        <Setter Property="VerticalContentAlignment" Value="{Binding Path=VerticalContentAlignment, RelativeSource={RelativeSource AncestorType={x:Type ItemsControl}}}"/>
+        <Setter Property="Padding" Value="0,0,0,0"/>
         <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
         <Setter Property="FocusVisualStyle" Value="{StaticResource TreeViewItemFocusVisual}"/>
         <Setter Property="Template">
@@ -102,18 +81,20 @@
                 <ControlTemplate TargetType="{x:Type TreeViewItem}">
                     <Grid>
                         <Grid.ColumnDefinitions>
-                            <ColumnDefinition MinWidth="19" Width="Auto"/>
+                            <ColumnDefinition MinWidth="15" Width="Auto"/>
+                            <ColumnDefinition Width="Auto"/>
                             <ColumnDefinition Width="*"/>
                         </Grid.ColumnDefinitions>
                         <Grid.RowDefinitions>
                             <RowDefinition Height="Auto"/>
                             <RowDefinition/>
                         </Grid.RowDefinitions>
-                        <ToggleButton x:Name="Expander" ClickMode="Press" IsChecked="{Binding IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" Style="{StaticResource ExpandCollapseToggleStyle}"/>
-                        <Border x:Name="Bd" Grid.Column="1" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Background="{TemplateBinding Background}" Padding="{TemplateBinding Padding}" SnapsToDevicePixels="true">
-                            <ContentPresenter x:Name="PART_Header" ContentSource="Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}"/>
+                        <ToggleButton x:Name="Expander"  Style="{StaticResource ExpandCollapseToggleStyle}" ClickMode="Press" IsChecked="{Binding Path=IsExpanded, RelativeSource={RelativeSource TemplatedParent}}" />
+                        <Border x:Name="Bd" SnapsToDevicePixels="true" Grid.Column="1" Grid.ColumnSpan="2" Background="{TemplateBinding Background}" BorderBrush="{TemplateBinding BorderBrush}" BorderThickness="{TemplateBinding BorderThickness}" Padding="{TemplateBinding Padding}">
+                            <ContentPresenter x:Name="PART_Header" HorizontalAlignment="{TemplateBinding HorizontalContentAlignment}" SnapsToDevicePixels="{TemplateBinding SnapsToDevicePixels}" ContentSource="Header"/>
                         </Border>
-                        <ItemsPresenter x:Name="ItemsHost" Grid.Row="1" Grid.Column="1" />
+                        <ItemsPresenter x:Name="ItemsHost" Grid.Column="0" Grid.ColumnSpan="3" Grid.Row="1"
+                                        local:TreeViewItemHelper.Indent="{Binding Path=(local:TreeViewItemHelper.Indent), Mode=OneWay, RelativeSource={RelativeSource AncestorType=ItemsPresenter}, Converter={StaticResource IndentConverter}}"/>
                     </Grid>
                     <ControlTemplate.Triggers>
                         <Trigger Property="IsExpanded" Value="false">
@@ -131,8 +112,8 @@
                                 <Condition Property="IsSelected" Value="true"/>
                                 <Condition Property="IsSelectionActive" Value="false"/>
                             </MultiTrigger.Conditions>
-                            <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightBrushKey}}"/>
-                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.InactiveSelectionHighlightTextBrushKey}}"/>
+                            <Setter Property="Background" TargetName="Bd" Value="{DynamicResource {x:Static SystemColors.ControlBrushKey}}"/>
+                            <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.ControlTextBrushKey}}"/>
                         </MultiTrigger>
                         <Trigger Property="IsEnabled" Value="false">
                             <Setter Property="Foreground" Value="{DynamicResource {x:Static SystemColors.GrayTextBrushKey}}"/>
@@ -141,16 +122,12 @@
                 </ControlTemplate>
             </Setter.Value>
         </Setter>
-        <Style.Triggers>
-            <Trigger Property="VirtualizingPanel.IsVirtualizing" Value="true">
-                <Setter Property="ItemsPanel">
-                    <Setter.Value>
-                        <ItemsPanelTemplate>
-                            <VirtualizingStackPanel/>
-                        </ItemsPanelTemplate>
-                    </Setter.Value>
-                </Setter>
-            </Trigger>
-        </Style.Triggers>
     </Style>
+
+    <Style TargetType="{x:Type TreeViewItem}" BasedOn="{StaticResource TreeViewItemStyle}">
+        <Setter Property="IsExpanded" Value="{Binding IsExpanded, Mode=TwoWay}" />
+        <Setter Property="IsSelected" Value="{Binding IsSelected, Mode=TwoWay}" />
+        <Setter Property="HorizontalContentAlignment" Value="Stretch" />
+    </Style>
+
 </ResourceDictionary>

+ 15 - 7
PixiEditor/Views/UserControls/LayerGroupControl.xaml

@@ -3,13 +3,13 @@
              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:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:behaviors="clr-namespace:PixiEditor.Helpers.Behaviours" xmlns:userControls="clr-namespace:PixiEditor.Views" xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters"
+             xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:behaviors="clr-namespace:PixiEditor.Helpers.Behaviours" xmlns:userControls="clr-namespace:PixiEditor.Views" xmlns:converters="clr-namespace:PixiEditor.Helpers.Converters" xmlns:helpers="clr-namespace:PixiEditor.Helpers.UI"
              mc:Ignorable="d" Focusable="True"
              d:DesignHeight="60" d:DesignWidth="250" Name="groupControl">
     <UserControl.Resources>
         <converters:InverseBooleanConverter x:Key="InverseBooleanConverter"/>
     </UserControl.Resources>
-    <Border BorderThickness="0 0 0 0.5" BorderBrush="Gray" MinWidth="60" Focusable="True" Tag="{Binding ElementName=groupControl}">
+    <Border BorderThickness="0 0 0 0.5" BorderBrush="Gray" MinWidth="60" Focusable="True" Tag="{Binding ElementName=groupControl}" MouseDown="Border_MouseDown">
         <i:Interaction.Behaviors>
             <behaviors:ClearFocusOnClickBehavior/>
         </i:Interaction.Behaviors>
@@ -22,20 +22,28 @@
             <Grid AllowDrop="True" DragEnter="Grid_DragEnter" Drop="Grid_Drop_Top" DragLeave="Grid_DragLeave" Grid.Row="0" Grid.ColumnSpan="3" Background="Transparent"/>
             <Grid Grid.Row="0" Grid.RowSpan="3" Margin="5 0 5 0">
                 <Grid.ColumnDefinitions>
-                    <ColumnDefinition Width="30"/>
                     <ColumnDefinition Width="1*"/>
                     <ColumnDefinition Width="20"/>
                 </Grid.ColumnDefinitions>
-                <Image Source="/Images/Folder.png" Height="20"/>
-                <StackPanel Grid.Row="1" Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Left" Margin="5,0,0,0">
-                    <userControls:EditableTextBlock
+                <StackPanel Orientation="Horizontal">
+                <Rectangle Width="{Binding Path=(helpers:TreeViewItemHelper.Indent).Value, Mode=OneWay, RelativeSource={RelativeSource AncestorType=ItemsPresenter}}" Fill="Transparent" StrokeThickness="0"/>
+                
+                <StackPanel Grid.Row="1" Orientation="Horizontal" Grid.Column="0" HorizontalAlignment="Left">
+                    <Image Source="/Images/Folder.png" Height="20" Margin="0,0,10,0"/>
+                        <Border Width="30" Height="30" BorderThickness="1" BorderBrush="Black" Background="{StaticResource MainColor}"
+                           Margin="5, 0, 10, 0">
+                            <Image Source="{Binding PreviewImage, ElementName=groupControl}" Stretch="Uniform" Width="20" Height="20" 
+                       RenderOptions.BitmapScalingMode="NearestNeighbor"/>
+                        </Border>
+                        <userControls:EditableTextBlock
                     FontSize="16"
                     VerticalAlignment="Center"
                     IsEditing="{Binding GroupData.IsRenaming, ElementName=groupControl, Mode=TwoWay}"
                     Text="{Binding GroupData.Name, ElementName=groupControl, Mode=TwoWay}" />
                 </StackPanel>
+                </StackPanel>
             </Grid>
-            <Grid DragEnter="Grid_DragEnter" Drop="Grid_Drop_Bottom"  DragLeave="Grid_DragLeave" Grid.Row="2" AllowDrop="{Binding  GroupData.IsExpanded, ElementName=groupControl, Converter={StaticResource InverseBooleanConverter}}" Grid.ColumnSpan="3" Background="Transparent"/>
+            <Grid DragEnter="Grid_DragEnter" Drop="Grid_Drop_Bottom"  DragLeave="Grid_DragLeave" Grid.Row="2" AllowDrop="{Binding  GroupData.IsExpanded, ElementName=groupControl, Converter={StaticResource InverseBooleanConverter}}" Grid.ColumnSpan="2" Background="Transparent"/>
         </Grid>
         <Border.ContextMenu>
             <ContextMenu>

+ 51 - 2
PixiEditor/Views/UserControls/LayerGroupControl.xaml.cs

@@ -3,6 +3,9 @@ using System.Linq;
 using System.Windows;
 using System.Windows.Controls;
 using System.Windows.Input;
+using System.Windows.Media.Imaging;
+using PixiEditor.Models.Controllers;
+using PixiEditor.Models.ImageManipulation;
 using PixiEditor.Models.Layers;
 using PixiEditor.ViewModels.SubViewModels.Main;
 
@@ -31,7 +34,21 @@ namespace PixiEditor.Views.UserControls
 
         // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
         public static readonly DependencyProperty LayersViewModelProperty =
-            DependencyProperty.Register("LayersViewModel", typeof(LayersViewModel), typeof(LayerGroupControl), new PropertyMetadata(default(LayersViewModel)));
+            DependencyProperty.Register("LayersViewModel", typeof(LayersViewModel), typeof(LayerGroupControl), new PropertyMetadata(default(LayersViewModel), LayersViewModelCallback));
+
+        private static void LayersViewModelCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
+        {
+            LayerGroupControl control = (LayerGroupControl)d;
+            if(e.OldValue is LayersViewModel oldVm && oldVm != e.NewValue)
+            {
+                oldVm.Owner.BitmapManager.MouseController.StoppedRecordingChanges -= control.MouseController_StoppedRecordingChanges;
+            }
+
+            if(e.NewValue is LayersViewModel vm)
+            {
+                vm.Owner.BitmapManager.MouseController.StoppedRecordingChanges += control.MouseController_StoppedRecordingChanges;
+            }
+        }
 
         public string GroupName
         {
@@ -51,13 +68,39 @@ namespace PixiEditor.Views.UserControls
 
         // Using a DependencyProperty as the backing store for MyProperty.  This enables animation, styling, binding, etc...
         public static readonly DependencyProperty GroupDataProperty =
-            DependencyProperty.Register("GroupData", typeof(GuidStructureItem), typeof(LayerGroupControl), new PropertyMetadata(default(GuidStructureItem)));
+            DependencyProperty.Register("GroupData", typeof(GuidStructureItem), typeof(LayerGroupControl), new PropertyMetadata(default(GuidStructureItem), GroupDataChangedCallback));
+
+        private static void GroupDataChangedCallback(DependencyObject d, DependencyPropertyChangedEventArgs e)
+        {
+            ((LayerGroupControl)d).GeneratePreviewImage();
+        }
+
+        public WriteableBitmap PreviewImage
+        {
+            get { return (WriteableBitmap)GetValue(PreviewImageProperty); }
+            set { SetValue(PreviewImageProperty, value); }
+        }
+
+        // Using a DependencyProperty as the backing store for PreviewImage.  This enables animation, styling, binding, etc...
+        public static readonly DependencyProperty PreviewImageProperty =
+            DependencyProperty.Register("PreviewImage", typeof(WriteableBitmap), typeof(LayerGroupControl), new PropertyMetadata(default(WriteableBitmap)));
 
         public LayerGroupControl()
         {
             InitializeComponent();
         }
 
+        private void MouseController_StoppedRecordingChanges(object sender, EventArgs e)
+        {
+            GeneratePreviewImage();
+        }
+
+        public void GeneratePreviewImage()
+        {
+            var layers = LayersViewModel.Owner.BitmapManager.ActiveDocument.LayerStructure.GetGroupLayers(GroupData);
+            PreviewImage = BitmapUtils.GeneratePreviewBitmap(layers, 25, 25);
+        }
+
         private void Grid_DragEnter(object sender, DragEventArgs e)
         {
             Grid item = sender as Grid;
@@ -121,5 +164,11 @@ namespace PixiEditor.Views.UserControls
         {
             HandleDrop(e.Data, false);
         }
+
+        private void Border_MouseDown(object sender, MouseButtonEventArgs e)
+        {
+            var doc = LayersViewModel.Owner.BitmapManager.ActiveDocument;
+            doc.SetMainActiveLayer(doc.Layers.IndexOf(doc.Layers.First(x => x.LayerGuid == GroupData.EndLayerGuid)));
+        }
     }
 }

+ 13 - 8
PixiEditor/Views/UserControls/LayerItem.xaml

@@ -4,7 +4,7 @@
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
              xmlns:local="clr-namespace:PixiEditor.Views"
-             xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:behaviors="clr-namespace:PixiEditor.Helpers.Behaviours" xmlns:layers="clr-namespace:PixiEditor.Models.Layers"
+             xmlns:i="http://schemas.microsoft.com/expression/2010/interactivity" xmlns:behaviors="clr-namespace:PixiEditor.Helpers.Behaviours" xmlns:layers="clr-namespace:PixiEditor.Models.Layers" xmlns:helpers="clr-namespace:PixiEditor.Helpers.UI"
              mc:Ignorable="d" Focusable="True"
              d:DesignHeight="60" d:DesignWidth="250" Name="uc"
              MouseLeave="LayerItem_OnMouseLeave" MouseEnter="LayerItem_OnMouseEnter">
@@ -22,23 +22,28 @@
         </i:Interaction.Triggers>
         <Grid>
             <Grid.RowDefinitions>
-                <RowDefinition Height="7.5"/>
-                <RowDefinition Height="20"/>
-                <RowDefinition Height="7.5"/>
+                <RowDefinition Height="10"/>
+                <RowDefinition Height="15"/>
+                <RowDefinition Height="10"/>
             </Grid.RowDefinitions>
             <Grid AllowDrop="True" DragEnter="Grid_DragEnter" Drop="Grid_Drop_Top" DragLeave="Grid_DragLeave" Grid.Row="0" Grid.ColumnSpan="3" Background="Transparent"/>
-            <Grid Grid.Row="1" DragEnter="Grid_DragEnter" DragLeave="Grid_DragLeave">
+            <Grid Grid.Row="1" Grid.RowSpan="3" Margin="0,-10,0,0" VerticalAlignment="Center" DragEnter="Grid_DragEnter" DragLeave="Grid_DragLeave">
                 <Grid.ColumnDefinitions>
                     <ColumnDefinition Width="30"/>
-                    <ColumnDefinition Width="199*"/>
+                    <ColumnDefinition Width="*"/>
                     <ColumnDefinition Width="20"/>
                 </Grid.ColumnDefinitions>
                 <CheckBox Style="{StaticResource ImageCheckBox}" VerticalAlignment="Center"
                       IsThreeState="False" HorizontalAlignment="Center" 
                       IsChecked="{Binding Path=IsVisibleUndoTriggerable, Mode=TwoWay}" Grid.Column="0" Height="16" />
-                <StackPanel Grid.Row="1" Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Left" Margin="5,0,0,0">
-                    <Image Source="{Binding PreviewImage,ElementName=uc}" Stretch="Uniform" Width="50" Height="20" Margin="0,0,20,0"
+                <StackPanel Orientation="Horizontal" Grid.Column="1" HorizontalAlignment="Left">
+                    <Rectangle Width="{Binding Path=(helpers:TreeViewItemHelper.Indent).Value, Mode=OneWay, RelativeSource={RelativeSource AncestorType=ItemsPresenter}}" Fill="Transparent" StrokeThickness="0"/>
+                    <Border Width="30" Height="30" BorderThickness="1" BorderBrush="Black" Background="{StaticResource MainColor}"
+                           Margin="5, 0, 10, 0">
+                        <Image Source="{Binding PreviewImage,ElementName=uc}" Stretch="Uniform" Width="20" Height="20" 
                        RenderOptions.BitmapScalingMode="NearestNeighbor"/>
+                    </Border>
+
                     <local:EditableTextBlock
                     IsEditing="{Binding IsRenaming, ElementName=uc, Mode=TwoWay}" FontSize="15"
                     VerticalAlignment="Center"

二進制
PixiEditor/Views/UserControls/transparentbg.png


二進制
PixiEditor/Views/UserControls/transparentbg_mini.png