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">