diff --git a/StageManager/3D/Panel3D.cs b/StageManager/3D/Panel3D.cs
deleted file mode 100644
index 3f7f491..0000000
--- a/StageManager/3D/Panel3D.cs
+++ /dev/null
@@ -1,349 +0,0 @@
-// TAKEN FROM https://joshsmithonwpf.wordpress.com/2008/03/30/animating-images-in-a-3d-itemscontrol/
-
-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.Documents;
-using System.Windows.Media;
-using System.Windows.Media.Animation;
-using System.Windows.Media.Effects;
-using System.Windows.Media.Media3D;
-
-namespace StageManager;
-
-///
-/// A Panel that displays its children in a
-/// Viewport3D hosted in the adorner layer.
-///
-public class Panel3D : Panel
-{
- #region Data
-
- static readonly Point ORIGIN_POINT = new Point(0, 0);
-
- bool _isMovingItems;
- int _registeredNameCounter = 0;
- readonly Viewport3D _viewport;
- readonly Dictionary _visualTo3DModelMap = new Dictionary();
-
- #endregion // Data
-
- #region Constructor
-
- public Panel3D()
- {
- _viewport = Application.LoadComponent(new Uri("3D/Scene.xaml", UriKind.Relative)) as Viewport3D;
-
- this.Loaded += delegate
- {
- var adornerLayer = AdornerLayer.GetAdornerLayer(this);
- var adorner = new Panel3DAdorner(this, _viewport);
-
- adornerLayer.IsHitTestVisible = false;
- adorner.IsHitTestVisible = false;
-
- adornerLayer.Add(adorner);
- };
- }
-
- protected override void OnInitialized(EventArgs e)
- {
- base.OnInitialized(e);
- _viewport.DataContext = this.DataContext;
- }
-
- protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
- {
- base.OnPropertyChanged(e);
-
- if (e.Property.Name == nameof(IsMouseOver))
- _viewport.Opacity = ((bool)e.NewValue) ? 1.0 : 0.8;
- else if (e.Property.Name == nameof(IsVisible))
- _viewport.Visibility = ((bool)e.NewValue) ? Visibility.Visible : Visibility.Hidden;
- }
-
- #endregion // Constructor
-
- #region MoveItems
-
- public void MoveItems(bool forward)
- {
- if (_isMovingItems)
- return;
-
- // We cannot move items less than two items.
- if (_viewport.Children.Count < 2)
- return;
-
- #region Create Lists
-
- // Get a list of all the GeometryModel3D and TranslateTransform3D objects in the viewport.
- List geometries = new List();
- List transforms = new List();
- foreach (ModelVisual3D model in _viewport.Children)
- {
- GeometryModel3D geo = model.Content as GeometryModel3D;
- if (geo != null)
- {
- geometries.Add(geo);
- transforms.Add(geo.Transform as TranslateTransform3D);
- }
- }
-
- #endregion // Create Lists
-
- #region Relocate Target Item
-
- // Move the first or last item to the opposite end of the list.
- if (forward)
- {
- var firstGeo = geometries[0];
- geometries.RemoveAt(0);
- geometries.Add(firstGeo);
-
- // The item at index 0 holds the scene's light
- // so don't remove that, instead remove the first
- // model that we added to the scene in code.
- var firstChild = _viewport.Children[1];
- _viewport.Children.RemoveAt(1);
- _viewport.Children.Add(firstChild);
- }
- else
- {
- int idx = geometries.Count - 1;
- var lastGeo = geometries[idx];
- geometries.RemoveAt(idx);
- geometries.Insert(0, lastGeo);
-
- idx = _viewport.Children.Count - 1;
- var lastChild = _viewport.Children[idx];
- _viewport.Children.RemoveAt(idx);
- _viewport.Children.Insert(1, lastChild);
- }
-
- #endregion // Relocate Target Item
-
- #region Animate All Items to New Locations and Opacitys
-
- Storyboard story = new Storyboard();
-
- // Apply the new transforms via animations.
- for (int i = 0; i < transforms.Count; ++i)
- {
- double targetX = transforms[i].OffsetX;
- double targetY = transforms[i].OffsetY;
- double targetZ = transforms[i].OffsetZ;
-
- var trans = geometries[i].Transform as TranslateTransform3D;
-
- // In order to animate the transform it must have a name registered
- // with the viewport. Since a transform does not have a Name property
- // I just create an arbitrary name for each transform and register that.
- string name = this.GetNextName();
- _viewport.RegisterName(name, trans);
-
- Duration duration = new Duration(TimeSpan.FromSeconds(1.25));
-
- DoubleAnimation animX = new DoubleAnimation();
- animX.To = targetX;
- animX.Duration = duration;
- animX.AccelerationRatio = 0.1;
- animX.DecelerationRatio = 0.9;
- Storyboard.SetTargetProperty(animX, new PropertyPath("OffsetX"));
- Storyboard.SetTargetName(animX, name);
- story.Children.Add(animX);
-
- DoubleAnimation animY = new DoubleAnimation();
- animY.To = targetY;
- animY.AccelerationRatio = 0.7;
- animY.DecelerationRatio = 0.3;
- animY.Duration = duration;
- Storyboard.SetTargetProperty(animY, new PropertyPath("OffsetY"));
- Storyboard.SetTargetName(animY, name);
- story.Children.Add(animY);
-
- DoubleAnimation animZ = new DoubleAnimation();
- animZ.To = targetZ;
- animZ.AccelerationRatio = 0.3;
- animZ.DecelerationRatio = 0.7;
- animZ.Duration = duration;
- Storyboard.SetTargetProperty(animZ, new PropertyPath("OffsetZ"));
- Storyboard.SetTargetName(animZ, name);
- story.Children.Add(animZ);
-
- DoubleAnimation animOpacity = new DoubleAnimation();
- var material = geometries[i].Material as DiffuseMaterial;
- var brush = material.Brush as VisualBrush;
- name = this.GetNextName();
- _viewport.RegisterName(name, brush);
- animOpacity.To = 1.0 - (i / (double)transforms.Count);
- animOpacity.AccelerationRatio = 0.2;
- animOpacity.DecelerationRatio = 0.8;
- animOpacity.Duration = duration;
- Storyboard.SetTargetProperty(animOpacity, new PropertyPath("Opacity"));
- Storyboard.SetTargetName(animOpacity, name);
- story.Children.Add(animOpacity);
-
- if (i == 0)
- animX.Completed += delegate { _isMovingItems = false; };
- }
-
- _isMovingItems = true;
- story.Begin(_viewport);
-
- #endregion // Animate All Items to New Locations and Opacitys
- }
-
- string GetNextName()
- {
- return "name" + _registeredNameCounter++;
- }
-
- #endregion // MoveItems
-
- #region DPs
-
- public static readonly DependencyProperty ElementHeightProperty =
- DependencyProperty.Register("ElementHeight", typeof(double), typeof(Panel3D),
- new FrameworkPropertyMetadata(30.0));
-
- public static readonly DependencyProperty ElementWidthProperty =
- DependencyProperty.Register("ElementWidth", typeof(double), typeof(Panel3D),
- new FrameworkPropertyMetadata(40.0));
-
-
- public double ElementWidth
- {
- get { return (double)GetValue(ElementWidthProperty); }
- set { SetValue(ElementWidthProperty, value); }
- }
-
- public double ElementHeight
- {
- get { return (double)GetValue(ElementHeightProperty); }
- set { SetValue(ElementHeightProperty, value); }
- }
- #endregion
-
- #region Layout Overrides
-
- protected override Size ArrangeOverride(Size finalSize)
- {
- Size size = new Size(ElementWidth, ElementHeight);
-
- // Arrange children so that their visualbrush has a valid width/height.
- foreach (UIElement child in Children)
- child.Arrange(new Rect(ORIGIN_POINT, size));
-
- _viewport.Arrange(new Rect(ORIGIN_POINT, finalSize));
-
- return finalSize;
- }
-
- protected override Size MeasureOverride(Size availableSize)
- {
- Size size = new Size(ElementWidth, ElementHeight);
-
- foreach (UIElement child in Children)
- child.Measure(size);
-
- _viewport.Measure(availableSize);
-
- if (availableSize.Width > 10000)
- availableSize.Width = availableSize.Height;
-
- if (availableSize.Height > 10000)
- availableSize.Height = availableSize.Width;
-
- return size;
- }
-
- #endregion // Layout Overrides
-
- #region OnVisualChildrenChanged
-
- protected override void OnVisualChildrenChanged(DependencyObject visualAdded, DependencyObject visualRemoved)
- {
- base.OnVisualChildrenChanged(visualAdded, visualRemoved);
-
- bool add = visualAdded != null && !_visualTo3DModelMap.ContainsKey(visualAdded);
- if (add)
- {
- // effects the PerspectiveCamera in Scene.xaml like for 20 here its Position="-3,0,3.5" and for 100 its Position="-1.7,0,2.1"
- (visualAdded as ContentPresenter).Effect = new DropShadowEffect { BlurRadius = 30, Direction = 200 /* pretty leftish */ };
- var model = Build3DModel(visualAdded as Visual);
- _visualTo3DModelMap.Add(visualAdded, model);
- _viewport.Children.Add(model);
- }
-
- bool remove = visualRemoved != null && _visualTo3DModelMap.ContainsKey(visualRemoved);
- if (remove)
- {
- var model = _visualTo3DModelMap[visualRemoved];
- _viewport.Children.Remove(model);
- _visualTo3DModelMap.Remove(visualRemoved);
- }
- }
-
- #endregion // OnVisualChildrenChanged
-
- #region Build3DModel
-
- ModelVisual3D Build3DModel(Visual visual)
- {
- double opacityDivisor = 1;
- //_viewport.Children.Count > 0 ?
- //_viewport.Children.Count : 1;
-
- var model = new ModelVisual3D
- {
- Content = new GeometryModel3D
- {
- Geometry = new MeshGeometry3D
- {
- TriangleIndices = new Int32Collection(
- new int[] { 0, 1, 2, 2, 3, 0 }),
- TextureCoordinates = new PointCollection(
- new Point[]
- {
- new Point(0, 1),
- new Point(1, 1),
- new Point(1, 0),
- new Point(0, 0)
- }),
- Positions = new Point3DCollection(
- new Point3D[]
- {
- new Point3D(-1, -1, 0),
- new Point3D(1, -1, 0),
- new Point3D(1, 1, 0),
- new Point3D(-1, 1, 0)
- })
- },
- Material = new DiffuseMaterial
- {
- Brush = new VisualBrush
- {
- Visual = visual,
- Opacity = 1.0 / opacityDivisor
- }
- },
- Transform = new TranslateTransform3D
- {
- OffsetX = _viewport.Children.Count * 0.1,
- OffsetY = 0,
- OffsetZ = _viewport.Children.Count * 0.2
- }
- }
- };
-
- return model;
- }
-
- #endregion // Build3DModel
-}
-
diff --git a/StageManager/3D/Panel3DAdorner.cs b/StageManager/3D/Panel3DAdorner.cs
deleted file mode 100644
index 85a2900..0000000
--- a/StageManager/3D/Panel3DAdorner.cs
+++ /dev/null
@@ -1,119 +0,0 @@
-using System;
-using System.Collections;
-using System.Windows;
-using System.Windows.Controls;
-using System.Windows.Documents;
-using System.Windows.Media;
-using System.Windows.Media.Effects;
-
-namespace StageManager;
-
-///
-/// Hosts an opaque Viewport3D in the adorner layer above a Panel3D.
-///
-public class Panel3DAdorner : Adorner
-{
- #region Data
-
- private ArrayList _logicalChildren;
- private readonly DockPanel _viewportHost = new DockPanel();
-
- #endregion // Data
-
- #region Constructor
-
- public Panel3DAdorner(Panel3D adornedPanel3D, Viewport3D viewport)
- : base(adornedPanel3D)
- {
- _viewportHost.Children.Add(viewport);
- _viewportHost.Background = Brushes.Transparent;
- base.AddLogicalChild(_viewportHost);
- base.AddVisualChild(_viewportHost);
-
-
- }
-
- #endregion // Constructor
-
- #region Measure/Arrange
-
- /////
- ///// Allows the control to determine how big it wants to be.
- /////
- ///// A limiting size for the control.
- //protected override Size MeasureOverride(Size constraint)
- //{
- // //_viewport.Measure(constraint);
- // //return _viewport.DesiredSize;
-
- // //if (constraint.Width > 10000)
- // // constraint.Width = constraint.Height;
-
- // //if (constraint.Height > 10000)
- // // constraint.Height = constraint.Width;
-
- // //return constraint;
-
- // return new Size(100, 100);
- //}
-
- ///
- /// Positions and sizes the control.
- ///
- /// The actual size of the control.
- protected override Size ArrangeOverride(Size finalSize)
- {
- Rect rect = new Rect(new Point(), finalSize);
-
- _viewportHost.Arrange(rect);
-
- return finalSize;
- }
-
- #endregion // Measure/Arrange
-
- #region Visual Children
-
- ///
- /// Required for the element to be rendered.
- ///
- protected override int VisualChildrenCount
- {
- get { return 1; }
- }
-
- ///
- /// Required for the element to be rendered.
- ///
- protected override Visual GetVisualChild(int index)
- {
- if (index != 0)
- throw new ArgumentOutOfRangeException("index");
-
- return _viewportHost;
- }
-
- #endregion // Visual Children
-
- #region Logical Children
-
- ///
- /// Required for the displayed element to inherit property values
- /// from the logical tree, such as FontSize.
- ///
- protected override IEnumerator LogicalChildren
- {
- get
- {
- if (_logicalChildren == null)
- {
- _logicalChildren = new ArrayList();
- _logicalChildren.Add(_viewportHost);
- }
-
- return _logicalChildren.GetEnumerator();
- }
- }
-
- #endregion // Logical Children
-}
\ No newline at end of file
diff --git a/StageManager/3D/Scene.xaml b/StageManager/3D/Scene.xaml
deleted file mode 100644
index 11ffdac..0000000
--- a/StageManager/3D/Scene.xaml
+++ /dev/null
@@ -1,16 +0,0 @@
-
-
-
-
-
-
-
-
-
-
\ No newline at end of file
diff --git a/StageManager/DwmThumbnail.xaml b/StageManager/DwmThumbnail.xaml
new file mode 100644
index 0000000..cde1d2d
--- /dev/null
+++ b/StageManager/DwmThumbnail.xaml
@@ -0,0 +1,21 @@
+
+
+
+
+
+
+
+
+
+
diff --git a/StageManager/DwmThumbnail.xaml.cs b/StageManager/DwmThumbnail.xaml.cs
new file mode 100644
index 0000000..5fa0b12
--- /dev/null
+++ b/StageManager/DwmThumbnail.xaml.cs
@@ -0,0 +1,121 @@
+using StageManager.Native.Interop;
+using System;
+using System.Windows;
+using System.Windows.Controls;
+using System.Windows.Media;
+
+namespace StageManager
+{
+ ///
+ /// Interaction logic for DwmThumbnail.xaml
+ ///
+ public partial class DwmThumbnail : UserControl
+ {
+ public DwmThumbnail()
+ {
+ InitializeComponent();
+ LayoutUpdated += DwmThumbnail_LayoutUpdated;
+ }
+
+ private IntPtr _dwmThumbnail;
+ private Window _window;
+ private Point? _dpiScaleFactor;
+
+ public static readonly DependencyProperty PreviewHandleProperty = DependencyProperty.Register(nameof(PreviewHandle),
+ typeof(IntPtr),
+ typeof(DwmThumbnail),
+ new PropertyMetadata(IntPtr.Zero));
+
+ public IntPtr PreviewHandle
+ {
+ get { return (IntPtr)GetValue(PreviewHandleProperty); }
+ set { SetValue(PreviewHandleProperty, value); }
+ }
+
+ private Point GetDpiScaleFactor()
+ {
+ if (_dpiScaleFactor is null)
+ {
+ var source = PresentationSource.FromVisual(this);
+ _dpiScaleFactor = source?.CompositionTarget != null ? new Point(source.CompositionTarget.TransformToDevice.M11, source.CompositionTarget.TransformToDevice.M22) : new Point(1.0d, 1.0d);
+ }
+
+ return _dpiScaleFactor.Value;
+ }
+
+ protected override void OnDpiChanged(DpiScale oldDpi, DpiScale newDpi)
+ {
+ _dpiScaleFactor = null;
+ base.OnDpiChanged(oldDpi, newDpi);
+ }
+
+ protected override void OnPropertyChanged(DependencyPropertyChangedEventArgs e)
+ {
+ base.OnPropertyChanged(e);
+
+ if (nameof(PreviewHandle).Equals(e.Property.Name))
+ {
+ if ((IntPtr)e.OldValue == IntPtr.Zero && (IntPtr)e.NewValue != IntPtr.Zero)
+ StartCapture();
+
+ UpdateThumbnailProperties();
+ }
+
+ if (nameof(IsVisible).Equals(e.Property.Name) && !(bool)e.NewValue && _dwmThumbnail != IntPtr.Zero)
+ {
+ NativeMethods.DwmUnregisterThumbnail(_dwmThumbnail);
+ _dwmThumbnail = IntPtr.Zero;
+ }
+ }
+
+ private void DwmThumbnail_LayoutUpdated(object? sender, EventArgs e)
+ {
+ UpdateThumbnailProperties();
+ }
+
+ public static Rect BoundsRelativeTo(FrameworkElement element, Visual relativeTo)
+ {
+ return element.TransformToVisual(relativeTo)
+ .TransformBounds(System.Windows.Controls.Primitives.LayoutInformation.GetLayoutSlot(element));
+ }
+
+ private void StartCapture()
+ {
+ var windowHandle = new System.Windows.Interop.WindowInteropHelper(FindWindow()).Handle;
+
+ var hr = NativeMethods.DwmRegisterThumbnail(windowHandle, PreviewHandle, out _dwmThumbnail);
+ if (hr != 0)
+ return;
+ }
+
+ private Window FindWindow() => _window ??= Window.GetWindow(this);
+
+ private void UpdateThumbnailProperties()
+ {
+ if (_dwmThumbnail == IntPtr.Zero)
+ return;
+
+ var dpi = GetDpiScaleFactor();
+
+ var previewBounds = BoundsRelativeTo(this, FindWindow());
+
+ var thumbnailRect = new RECT
+ {
+ top = (int)(previewBounds.Top * dpi.Y),
+ left = (int)(previewBounds.Left * dpi.X),
+ bottom = (int)((previewBounds.Bottom - Margin.Top - Margin.Bottom) * dpi.Y) + 1,
+ right = (int)((previewBounds.Right - Margin.Left - Margin.Right) * dpi.X) + 1
+ };
+
+ var props = new DWM_THUMBNAIL_PROPERTIES
+ {
+ fVisible = true,
+ dwFlags = (int)(DWM_TNP.DWM_TNP_VISIBLE | DWM_TNP.DWM_TNP_OPACITY | DWM_TNP.DWM_TNP_RECTDESTINATION | DWM_TNP.DWM_TNP_SOURCECLIENTAREAONLY),
+ opacity = 255,
+ rcDestination = thumbnailRect,
+ fSourceClientAreaOnly = true
+ };
+ NativeMethods.DwmUpdateThumbnailProperties(_dwmThumbnail, ref props);
+ }
+ }
+}
diff --git a/StageManager/MainWindow.xaml b/StageManager/MainWindow.xaml
index 247a5de..805d344 100644
--- a/StageManager/MainWindow.xaml
+++ b/StageManager/MainWindow.xaml
@@ -20,8 +20,8 @@
Name="thisWindow">