Browse Source

Buggy implementation of layer/group opacity

Equbuxu 3 years ago
parent
commit
4a94593e81
22 changed files with 308 additions and 50 deletions
  1. 0 9
      src/ChangeableDocument/Actions/IStartChangeAction.cs
  2. 2 1
      src/ChangeableDocument/Actions/IStartOrUpdateChangeAction.cs
  3. 31 0
      src/ChangeableDocument/Actions/OpacityActions.cs
  4. 3 10
      src/ChangeableDocument/ChangeInfos/StructureChangeInfos.cs
  5. 7 0
      src/ChangeableDocument/ChangeInfos/StructureMemberOpacity_ChangeInfo.cs
  6. 9 0
      src/ChangeableDocument/ChangeInfos/StructureMemberProperties_ChangeInfo.cs
  7. 1 0
      src/ChangeableDocument/Changeables/Folder.cs
  8. 1 0
      src/ChangeableDocument/Changeables/Interfaces/IReadOnlyStructureMember.cs
  9. 2 1
      src/ChangeableDocument/Changeables/Layer.cs
  10. 1 0
      src/ChangeableDocument/Changeables/StructureMember.cs
  11. 2 2
      src/ChangeableDocument/Changes/CreateStructureMember_Change.cs
  12. 2 2
      src/ChangeableDocument/Changes/DeleteStructureMember_Change.cs
  13. 2 2
      src/ChangeableDocument/Changes/MoveStructureMember_Change.cs
  14. 2 2
      src/ChangeableDocument/Changes/SetStructureMemberProperties_Change.cs
  15. 46 0
      src/ChangeableDocument/Changes/UpdateStructureMemberOpacity_Change.cs
  16. 5 8
      src/ChangeableDocument/DocumentChangeTracker.cs
  17. 111 0
      src/PixiEditorPrototype/Behaviors/SliderUpdateBehavior.cs
  18. 18 9
      src/PixiEditorPrototype/Models/DocumentUpdater.cs
  19. 6 1
      src/PixiEditorPrototype/RelayCommand.cs
  20. 10 1
      src/PixiEditorPrototype/ViewModels/DocumentViewModel.cs
  21. 34 2
      src/PixiEditorPrototype/ViewModels/StructureMemberViewModel.cs
  22. 13 0
      src/PixiEditorPrototype/Views/DocumentView.xaml

+ 0 - 9
src/ChangeableDocument/Actions/IStartChangeAction.cs

@@ -1,9 +0,0 @@
-using ChangeableDocument.Changes;
-
-namespace ChangeableDocument.Actions
-{
-    internal interface IStartChangeAction : IAction
-    {
-        IUpdateableChange CreateCorrespondingChange();
-    }
-}

+ 2 - 1
src/ChangeableDocument/Actions/IUpdateChangeAction.cs → src/ChangeableDocument/Actions/IStartOrUpdateChangeAction.cs

@@ -2,8 +2,9 @@
 
 namespace ChangeableDocument.Actions
 {
-    internal interface IUpdateChangeAction
+    internal interface IStartOrUpdateChangeAction : IAction
     {
         void UpdateCorrespodingChange(IUpdateableChange change);
+        IUpdateableChange CreateCorrespondingChange();
     }
 }

+ 31 - 0
src/ChangeableDocument/Actions/OpacityActions.cs

@@ -0,0 +1,31 @@
+using ChangeableDocument.Changes;
+
+namespace ChangeableDocument.Actions
+{
+    public record OpacityChange_Action : IStartOrUpdateChangeAction
+    {
+        public OpacityChange_Action(Guid memberGuid, float opacity)
+        {
+            Opacity = opacity;
+            MemberGuid = memberGuid;
+        }
+
+        public Guid MemberGuid { get; }
+        public float Opacity { get; }
+
+        IUpdateableChange IStartOrUpdateChangeAction.CreateCorrespondingChange()
+        {
+            return new UpdateStructureMemberOpacity_Change(MemberGuid, Opacity);
+        }
+
+        void IStartOrUpdateChangeAction.UpdateCorrespodingChange(IUpdateableChange change)
+        {
+            ((UpdateStructureMemberOpacity_Change)change).Update(Opacity);
+        }
+    }
+
+    public record EndOpacityChange_Action : IEndChangeAction
+    {
+        bool IEndChangeAction.IsChangeTypeMatching(IChange change) => change is UpdateStructureMemberOpacity_Change;
+    }
+}

+ 3 - 10
src/ChangeableDocument/ChangeInfos/StructureChangeInfos.cs

@@ -1,24 +1,17 @@
 namespace ChangeableDocument.ChangeInfos
 {
-    public record Document_CreateStructureMember_ChangeInfo : IChangeInfo
+    public record CreateStructureMember_ChangeInfo : IChangeInfo
     {
         public Guid GuidValue { get; init; }
     }
 
-    public record Document_DeleteStructureMember_ChangeInfo : IChangeInfo
+    public record DeleteStructureMember_ChangeInfo : IChangeInfo
     {
         public Guid GuidValue { get; init; }
     }
 
-    public record Document_MoveStructureMember_ChangeInfo : IChangeInfo
+    public record MoveStructureMember_ChangeInfo : IChangeInfo
     {
         public Guid GuidValue { get; init; }
     }
-
-    public record Document_UpdateStructureMemberProperties_ChangeInfo : IChangeInfo
-    {
-        public Guid GuidValue { get; init; }
-        public bool IsVisibleChanged { get; init; } = false;
-        public bool NameChanged { get; init; } = false;
-    }
 }

+ 7 - 0
src/ChangeableDocument/ChangeInfos/StructureMemberOpacity_ChangeInfo.cs

@@ -0,0 +1,7 @@
+namespace ChangeableDocument.ChangeInfos
+{
+    public record StructureMemberOpacity_ChangeInfo : IChangeInfo
+    {
+        public Guid GuidValue { get; init; }
+    }
+}

+ 9 - 0
src/ChangeableDocument/ChangeInfos/StructureMemberProperties_ChangeInfo.cs

@@ -0,0 +1,9 @@
+namespace ChangeableDocument.ChangeInfos
+{
+    public record StructureMemberProperties_ChangeInfo : IChangeInfo
+    {
+        public Guid GuidValue { get; init; }
+        public bool IsVisibleChanged { get; init; } = false;
+        public bool NameChanged { get; init; } = false;
+    }
+}

+ 1 - 0
src/ChangeableDocument/Changeables/Folder.cs

@@ -20,6 +20,7 @@ namespace ChangeableDocument.Changeables
                 GuidValue = GuidValue,
                 IsVisible = IsVisible,
                 Name = Name,
+                Opacity = Opacity,
                 Children = clonedChildren
             };
         }

+ 1 - 0
src/ChangeableDocument/Changeables/Interfaces/IReadOnlyStructureMember.cs

@@ -5,5 +5,6 @@
         bool IsVisible { get; }
         string Name { get; }
         Guid GuidValue { get; }
+        float Opacity { get; }
     }
 }

+ 2 - 1
src/ChangeableDocument/Changeables/Layer.cs

@@ -12,7 +12,8 @@ namespace ChangeableDocument.Changeables
             {
                 GuidValue = GuidValue,
                 IsVisible = IsVisible,
-                Name = Name
+                Name = Name,
+                Opacity = Opacity
             };
         }
     }

+ 1 - 0
src/ChangeableDocument/Changeables/StructureMember.cs

@@ -4,6 +4,7 @@ namespace ChangeableDocument.Changeables
 {
     internal abstract class StructureMember : IChangeable, IReadOnlyStructureMember
     {
+        public float Opacity { get; set; } = 1f;
         public bool IsVisible { get; set; } = true;
         public string Name { get; set; } = "Unnamed";
         public Guid GuidValue { get; init; }

+ 2 - 2
src/ChangeableDocument/Changes/CreateStructureMember_Change.cs

@@ -36,7 +36,7 @@ namespace ChangeableDocument.Changes
 
             folder.Children.Insert(parentFolderIndex, member);
 
-            return new Document_CreateStructureMember_ChangeInfo() { GuidValue = newMemberGuid };
+            return new CreateStructureMember_ChangeInfo() { GuidValue = newMemberGuid };
         }
 
         public IChangeInfo Revert(Document document)
@@ -44,7 +44,7 @@ namespace ChangeableDocument.Changes
             var folder = (Folder)document.FindMemberOrThrow(parentFolderGuid);
             folder.Children.RemoveAt(folder.Children.FindIndex(child => child.GuidValue == newMemberGuid));
 
-            return new Document_DeleteStructureMember_ChangeInfo() { GuidValue = newMemberGuid };
+            return new DeleteStructureMember_ChangeInfo() { GuidValue = newMemberGuid };
         }
     }
 }

+ 2 - 2
src/ChangeableDocument/Changes/DeleteStructureMember_Change.cs

@@ -27,7 +27,7 @@ namespace ChangeableDocument.Changes
         {
             var (member, parent) = document.FindChildAndParentOrThrow(memberGuid);
             parent.Children.Remove(member);
-            return new Document_DeleteStructureMember_ChangeInfo() { GuidValue = memberGuid };
+            return new DeleteStructureMember_ChangeInfo() { GuidValue = memberGuid };
         }
 
         public IChangeInfo Revert(Document doc)
@@ -35,7 +35,7 @@ namespace ChangeableDocument.Changes
             var parent = (Folder)doc.FindMemberOrThrow(parentGuid);
 
             parent.Children.Insert(originalIndex, savedCopy!.Clone());
-            return new Document_CreateStructureMember_ChangeInfo() { GuidValue = memberGuid };
+            return new CreateStructureMember_ChangeInfo() { GuidValue = memberGuid };
         }
     }
 }

+ 2 - 2
src/ChangeableDocument/Changes/MoveStructureMember_Change.cs

@@ -39,13 +39,13 @@ namespace ChangeableDocument.Changes
         public IChangeInfo? Apply(Document target)
         {
             Move(target, memberGuid, targetFolderGuid, targetFolderIndex);
-            return new Document_MoveStructureMember_ChangeInfo() { GuidValue = memberGuid };
+            return new MoveStructureMember_ChangeInfo() { GuidValue = memberGuid };
         }
 
         public IChangeInfo? Revert(Document target)
         {
             Move(target, memberGuid, originalFolderGuid, originalFolderIndex);
-            return new Document_MoveStructureMember_ChangeInfo() { GuidValue = memberGuid };
+            return new MoveStructureMember_ChangeInfo() { GuidValue = memberGuid };
         }
     }
 }

+ 2 - 2
src/ChangeableDocument/Changes/SetStructureMemberProperties_Change.cs

@@ -31,7 +31,7 @@ namespace ChangeableDocument.Changes
             if (NewIsVisible != null) member.IsVisible = NewIsVisible.Value;
             if (NewName != null) member.Name = NewName;
 
-            return new Document_UpdateStructureMemberProperties_ChangeInfo()
+            return new StructureMemberProperties_ChangeInfo()
             {
                 GuidValue = member.GuidValue,
                 IsVisibleChanged = NewIsVisible != null,
@@ -45,7 +45,7 @@ namespace ChangeableDocument.Changes
             if (NewIsVisible != null) member.IsVisible = originalIsVisible;
             if (NewName != null) member.Name = originalName!;
 
-            return new Document_UpdateStructureMemberProperties_ChangeInfo()
+            return new StructureMemberProperties_ChangeInfo()
             {
                 GuidValue = member.GuidValue,
                 IsVisibleChanged = NewIsVisible != null,

+ 46 - 0
src/ChangeableDocument/Changes/UpdateStructureMemberOpacity_Change.cs

@@ -0,0 +1,46 @@
+using ChangeableDocument.Changeables;
+using ChangeableDocument.ChangeInfos;
+
+namespace ChangeableDocument.Changes
+{
+    internal class UpdateStructureMemberOpacity_Change : IUpdateableChange
+    {
+        private Guid memberGuid;
+
+        private float originalOpacity;
+        public float NewOpacity { get; private set; }
+
+        public UpdateStructureMemberOpacity_Change(Guid memberGuid, float opacity)
+        {
+            this.memberGuid = memberGuid;
+            NewOpacity = opacity;
+        }
+
+        public void Update(float updatedOpacity)
+        {
+            NewOpacity = updatedOpacity;
+        }
+
+        public void Initialize(Document document)
+        {
+            var member = document.FindMemberOrThrow(memberGuid);
+            originalOpacity = member.Opacity;
+        }
+
+        public IChangeInfo? Apply(Document document)
+        {
+            var member = document.FindMemberOrThrow(memberGuid);
+            member.Opacity = NewOpacity;
+
+            return new StructureMemberOpacity_ChangeInfo() { GuidValue = memberGuid };
+        }
+
+        public IChangeInfo? Revert(Document document)
+        {
+            var member = document.FindMemberOrThrow(memberGuid);
+            member.Opacity = originalOpacity;
+
+            return new StructureMemberOpacity_ChangeInfo() { GuidValue = memberGuid };
+        }
+    }
+}

+ 5 - 8
src/ChangeableDocument/DocumentChangeTracker.cs

@@ -64,15 +64,12 @@ namespace ChangeableDocument
                             changeInfos.Add(change.Apply(document));
                             AddToUndo(change);
                             break;
-                        case IStartChangeAction act:
-                            if (activeChange != null)
-                                throw new Exception("Can't start a change while another change is active");
-                            activeChange = act.CreateCorrespondingChange();
-                            activeChange.Initialize(document);
-                            break;
-                        case IUpdateChangeAction act:
+                        case IStartOrUpdateChangeAction act:
                             if (activeChange == null)
-                                throw new Exception("Can't update a change: no changes are active");
+                            {
+                                activeChange = act.CreateCorrespondingChange();
+                                activeChange.Initialize(document);
+                            }
                             act.UpdateCorrespodingChange(activeChange);
                             changeInfos.Add(activeChange.Apply(document));
                             break;

+ 111 - 0
src/PixiEditorPrototype/Behaviors/SliderUpdateBehavior.cs

@@ -0,0 +1,111 @@
+using Microsoft.Xaml.Behaviors;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Controls.Primitives;
+using System.Windows.Input;
+
+namespace PixiEditorPrototype.Behaviors
+{
+    class SliderUpdateBehavior : Behavior<Slider>
+    {
+        public static DependencyProperty DragValueChangedProperty = DependencyProperty.Register(nameof(DragValueChanged), typeof(ICommand), typeof(SliderUpdateBehavior));
+        public ICommand? DragValueChanged
+        {
+            get => (ICommand)GetValue(DragValueChangedProperty);
+            set => SetValue(DragValueChangedProperty, value);
+        }
+        public static DependencyProperty DragEndedProperty = DependencyProperty.Register(nameof(DragEnded), typeof(ICommand), typeof(SliderUpdateBehavior));
+        public ICommand? DragEnded
+        {
+            get => (ICommand)GetValue(DragEndedProperty);
+            set => SetValue(DragEndedProperty, value);
+        }
+        public static DependencyProperty RegularValueChangedProperty = DependencyProperty.Register(nameof(RegularValueChanged), typeof(ICommand), typeof(SliderUpdateBehavior));
+        public ICommand? RegularValueChanged
+        {
+            get => (ICommand)GetValue(RegularValueChangedProperty);
+            set => SetValue(RegularValueChangedProperty, value);
+        }
+
+        private bool attached = false;
+        private bool dragging = false;
+        private bool valueChangedWhileDragging = false;
+        protected override void OnAttached()
+        {
+            AssociatedObject.Loaded += AssociatedObject_Loaded;
+            if (AssociatedObject.IsLoaded)
+                AttachEvents();
+        }
+
+        private void AssociatedObject_Loaded(object sender, RoutedEventArgs e)
+        {
+            AttachEvents();
+        }
+
+        private void AttachEvents()
+        {
+            if (attached)
+                return;
+            attached = true;
+            var thumb = GetThumb(AssociatedObject);
+            if (thumb == null)
+                return;
+
+            thumb.DragStarted += Thumb_DragStarted;
+            thumb.DragCompleted += Thumb_DragCompleted;
+            AssociatedObject.ValueChanged += Slider_ValueChanged;
+        }
+
+        protected override void OnDetaching()
+        {
+            AssociatedObject.Loaded -= AssociatedObject_Loaded;
+            if (!attached)
+                return;
+            var thumb = GetThumb(AssociatedObject);
+            if (thumb == null)
+                return;
+
+            thumb.DragStarted -= Thumb_DragStarted;
+            thumb.DragCompleted -= Thumb_DragCompleted;
+            AssociatedObject.ValueChanged -= Slider_ValueChanged;
+        }
+
+
+
+        private void Slider_ValueChanged(object sender, System.Windows.RoutedPropertyChangedEventArgs<double> e)
+        {
+            if (dragging)
+            {
+                if (DragValueChanged != null && DragValueChanged.CanExecute(e.NewValue))
+                    DragValueChanged.Execute(e.NewValue);
+                valueChangedWhileDragging = true;
+            }
+            else
+            {
+                if (RegularValueChanged != null && RegularValueChanged.CanExecute(e.NewValue))
+                    RegularValueChanged.Execute(e.NewValue);
+            }
+        }
+
+        private void Thumb_DragCompleted(object sender, DragCompletedEventArgs e)
+        {
+            dragging = false;
+            if (valueChangedWhileDragging == true && DragEnded != null && DragEnded.CanExecute(null))
+                DragEnded.Execute(null);
+            valueChangedWhileDragging = false;
+        }
+
+        private void Thumb_DragStarted(object sender, DragStartedEventArgs e)
+        {
+            dragging = true;
+        }
+
+        private static Thumb? GetThumb(Slider slider)
+        {
+            var track = slider.Template.FindName("PART_Track", slider) as Track;
+            return track == null ? null : track.Thumb;
+        }
+
+
+    }
+}

+ 18 - 9
src/PixiEditorPrototype/Models/DocumentUpdater.cs

@@ -20,22 +20,25 @@ namespace PixiEditorPrototype.Models
 
             switch (arbitraryInfo)
             {
-                case Document_CreateStructureMember_ChangeInfo info:
+                case CreateStructureMember_ChangeInfo info:
                     ProcessCreateStructureMember(info);
                     break;
-                case Document_DeleteStructureMember_ChangeInfo info:
+                case DeleteStructureMember_ChangeInfo info:
                     ProcessDeleteStructureMember(info);
                     break;
-                case Document_UpdateStructureMemberProperties_ChangeInfo info:
+                case StructureMemberProperties_ChangeInfo info:
                     ProcessUpdateStructureMemberProperties(info);
                     break;
-                case Document_MoveStructureMember_ChangeInfo info:
+                case StructureMemberOpacity_ChangeInfo info:
+                    ProcessUpdateStructureMemberOpacity(info);
+                    break;
+                case MoveStructureMember_ChangeInfo info:
                     ProcessMoveStructureMember(info);
                     break;
             }
         }
 
-        private void ProcessCreateStructureMember(Document_CreateStructureMember_ChangeInfo info)
+        private void ProcessCreateStructureMember(CreateStructureMember_ChangeInfo info)
         {
             var (member, parentFolder) = doc.Tracker.Document.FindChildAndParentOrThrow(info.GuidValue);
             var parentFolderVM = (FolderViewModel)doc.StructureHelper.FindOrThrow(parentFolder.GuidValue);
@@ -55,25 +58,31 @@ namespace PixiEditorPrototype.Models
             {
                 foreach (IReadOnlyStructureMember child in folder2.ReadOnlyChildren)
                 {
-                    ProcessCreateStructureMember(new Document_CreateStructureMember_ChangeInfo() { GuidValue = child.GuidValue });
+                    ProcessCreateStructureMember(new CreateStructureMember_ChangeInfo() { GuidValue = child.GuidValue });
                 }
             }
         }
 
-        private void ProcessDeleteStructureMember(Document_DeleteStructureMember_ChangeInfo info)
+        private void ProcessDeleteStructureMember(DeleteStructureMember_ChangeInfo info)
         {
             var (memberVM, folderVM) = doc.StructureHelper.FindChildAndParentOrThrow(info.GuidValue);
             folderVM.Children.Remove(memberVM);
         }
 
-        private void ProcessUpdateStructureMemberProperties(Document_UpdateStructureMemberProperties_ChangeInfo info)
+        private void ProcessUpdateStructureMemberProperties(StructureMemberProperties_ChangeInfo info)
         {
             var memberVM = doc.StructureHelper.FindOrThrow(info.GuidValue);
             if (info.NameChanged) memberVM.RaisePropertyChanged(nameof(memberVM.Name));
             if (info.IsVisibleChanged) memberVM.RaisePropertyChanged(nameof(memberVM.IsVisible));
         }
 
-        private void ProcessMoveStructureMember(Document_MoveStructureMember_ChangeInfo info)
+        private void ProcessUpdateStructureMemberOpacity(StructureMemberOpacity_ChangeInfo info)
+        {
+            var memberVM = doc.StructureHelper.FindOrThrow(info.GuidValue);
+            memberVM.RaisePropertyChanged(nameof(memberVM.Opacity));
+        }
+
+        private void ProcessMoveStructureMember(MoveStructureMember_ChangeInfo info)
         {
             var (memberVM, curFolderVM) = doc.StructureHelper.FindChildAndParentOrThrow(info.GuidValue);
             var (member, targetFolder) = doc.Tracker.Document.FindChildAndParentOrThrow(info.GuidValue);

+ 6 - 1
src/PixiEditorPrototype/RelayCommand.cs

@@ -8,7 +8,7 @@ namespace PixiEditorPrototype
         public event EventHandler? CanExecuteChanged;
 
         private Action<object?> execute;
-        private Func<object?, bool> canExecute;
+        private Func<object?, bool>? canExecute;
 
         public RelayCommand(Action<object?> execute, Func<object?, bool> canExecute)
         {
@@ -16,6 +16,11 @@ namespace PixiEditorPrototype
             this.canExecute = canExecute;
         }
 
+        public RelayCommand(Action<object?> execute)
+        {
+            this.execute = execute;
+        }
+
         public void RaiseCanExecuteChanged()
         {
             CanExecuteChanged?.Invoke(this, EventArgs.Empty);

+ 10 - 1
src/PixiEditorPrototype/ViewModels/DocumentViewModel.cs

@@ -8,7 +8,16 @@ namespace PixiEditorPrototype.ViewModels
 {
     internal class DocumentViewModel : INotifyPropertyChanged
     {
-        public StructureMemberViewModel? SelectedStructureMember { get; private set; }
+        private StructureMemberViewModel? selectedStructureMember;
+        public StructureMemberViewModel? SelectedStructureMember
+        {
+            get => selectedStructureMember;
+            private set
+            {
+                selectedStructureMember = value;
+                PropertyChanged?.Invoke(this, new(nameof(SelectedStructureMember)));
+            }
+        }
 
         public event PropertyChangedEventHandler? PropertyChanged;
 

+ 34 - 2
src/PixiEditorPrototype/ViewModels/StructureMemberViewModel.cs

@@ -23,6 +23,12 @@ namespace PixiEditorPrototype.ViewModels
             set => Document.ActionAccumulator.AddAction(new SetStructureMemberVisibility_Action(value, member.GuidValue));
         }
 
+        public float Opacity
+        {
+            get => member.Opacity;
+            set => SetOpacity(value);
+        }
+
         public Guid GuidValue
         {
             get => member.GuidValue;
@@ -31,6 +37,12 @@ namespace PixiEditorPrototype.ViewModels
         public RelayCommand MoveUpCommand { get; }
         public RelayCommand MoveDownCommand { get; }
 
+        public RelayCommand UpdateOpacityCommand { get; }
+
+        public RelayCommand EndOpacityUpdateCommand { get; }
+
+        public RelayCommand SetOpacityCommand { get; }
+
         public void RaisePropertyChanged(string name)
         {
             PropertyChanged?.Invoke(this, new PropertyChangedEventArgs(name));
@@ -40,8 +52,28 @@ namespace PixiEditorPrototype.ViewModels
         {
             this.member = member;
             Document = doc;
-            MoveUpCommand = new(_ => Document.StructureHelper.MoveStructureMember(GuidValue, true), _ => true);
-            MoveDownCommand = new(_ => Document.StructureHelper.MoveStructureMember(GuidValue, false), _ => true);
+            MoveUpCommand = new(_ => Document.StructureHelper.MoveStructureMember(GuidValue, true));
+            MoveDownCommand = new(_ => Document.StructureHelper.MoveStructureMember(GuidValue, false));
+            UpdateOpacityCommand = new(UpdateOpacity);
+            EndOpacityUpdateCommand = new(EndOpacityUpdate);
+            SetOpacityCommand = new((value) => { if (value != null) SetOpacity((float)(double)value); });
+        }
+
+        private void EndOpacityUpdate(object? opacity)
+        {
+            Document.ActionAccumulator.AddAction(new EndOpacityChange_Action());
+        }
+
+        private void UpdateOpacity(object? opacity)
+        {
+            if (opacity != null)
+                Document.ActionAccumulator.AddAction(new OpacityChange_Action(GuidValue, (float)(double)opacity));
+        }
+
+        private void SetOpacity(float value)
+        {
+            //Document.ActionAccumulator.AddAction(new OpacityChange_Action(GuidValue, value));
+            //Document.ActionAccumulator.AddAction(new EndOpacityChange_Action());
         }
     }
 }

+ 13 - 0
src/PixiEditorPrototype/Views/DocumentView.xaml

@@ -4,6 +4,7 @@
              xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006" 
              xmlns:d="http://schemas.microsoft.com/expression/blend/2008" 
              xmlns:local="clr-namespace:PixiEditorPrototype.Views"
+             xmlns:behaviors="clr-namespace:PixiEditorPrototype.Behaviors"
              xmlns:i="http://schemas.microsoft.com/xaml/behaviors"
              xmlns:cmd="mvvm"
              xmlns:vm="clr-namespace:PixiEditorPrototype.ViewModels"
@@ -18,6 +19,18 @@
                     <Button Margin="5" Command="{Binding CreateNewFolderCommand}" Width="80">New Folder</Button>
                     <Button Margin="5" Command="{Binding DeleteStructureMemberCommand}" Width="80">Delete</Button>
                 </StackPanel>
+                <StackPanel Orientation="Horizontal" DockPanel.Dock="Top" HorizontalAlignment="Center">
+                    <Slider Width="100" Minimum="0" Maximum="1" SmallChange="0.01" LargeChange="0.1" IsSnapToTickEnabled="True" TickFrequency="0.01" 
+                            Value="{Binding SelectedStructureMember.Opacity, Mode=OneWay}">
+                        <i:Interaction.Behaviors>
+                            <behaviors:SliderUpdateBehavior
+                                DragValueChanged="{Binding SelectedStructureMember.UpdateOpacityCommand}"
+                                DragEnded="{Binding SelectedStructureMember.EndOpacityUpdateCommand}"
+                                RegularValueChanged="{Binding SelectedStructureMember.SetOpacityCommand}"/>
+                        </i:Interaction.Behaviors>
+                    </Slider>
+                    <TextBlock Text="{Binding SelectedStructureMember.Opacity, StringFormat=N2}" TextAlignment="Center" d:Text="1.00" Width="30"></TextBlock>
+                </StackPanel>
                 <TreeView ItemsSource="{Binding StructureRoot.Children}">
                     <i:Interaction.Triggers>
                         <i:EventTrigger EventName="SelectedItemChanged">