From 82099d61faa5106c83dfaa6b85d605adb6407ed8 Mon Sep 17 00:00:00 2001 From: jkuehner Date: Sun, 4 May 2014 20:08:16 +0200 Subject: [PATCH] Right Click Context Menu for multiple Selected Items to Wrap them in a Container (Grid or Canvas at the Moment!) --- .../RightClickMultipleItemsContextMenu.xaml | 8 + ...RightClickMultipleItemsContextMenu.xaml.cs | 58 ++++++ ...tClickMultipleItemsContextMenuExtension.cs | 54 ++++++ .../WpfDesign.Designer/Project/ModelTools.cs | 172 +++++++++++++++++- .../Project/Translations.cs | 18 ++ .../Project/WpfDesign.Designer.csproj | 5 + .../Extensions/SelectionExtensionServer.cs | 30 ++- 7 files changed, 343 insertions(+), 2 deletions(-) create mode 100644 src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/RightClickMultipleItemsContextMenu.xaml create mode 100644 src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/RightClickMultipleItemsContextMenu.xaml.cs create mode 100644 src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/RightClickMultipleItemsContextMenuExtension.cs diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/RightClickMultipleItemsContextMenu.xaml b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/RightClickMultipleItemsContextMenu.xaml new file mode 100644 index 0000000000..d6c69df71b --- /dev/null +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/RightClickMultipleItemsContextMenu.xaml @@ -0,0 +1,8 @@ + + + + diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/RightClickMultipleItemsContextMenu.xaml.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/RightClickMultipleItemsContextMenu.xaml.cs new file mode 100644 index 0000000000..e616350d12 --- /dev/null +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/RightClickMultipleItemsContextMenu.xaml.cs @@ -0,0 +1,58 @@ +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Collections.Generic; +using System.Linq; +using System.Text; +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 ICSharpCode.WpfDesign.PropertyGrid; +using ICSharpCode.WpfDesign.Designer.Xaml; + +namespace ICSharpCode.WpfDesign.Designer.Extensions +{ + public partial class RightClickMultipleItemsContextMenu + { + private DesignItem designItem; + + public RightClickMultipleItemsContextMenu(DesignItem designItem) + { + this.designItem = designItem; + + InitializeComponent(); + } + + void Click_WrapInCanvas(object sender, System.Windows.RoutedEventArgs e) + { + ModelTools.WrapItemsNewContainer(this.designItem.Services.Selection.SelectedItems, typeof(Canvas)); + } + + void Click_WrapInGrid(object sender, System.Windows.RoutedEventArgs e) + { + ModelTools.WrapItemsNewContainer(this.designItem.Services.Selection.SelectedItems, typeof(Grid)); + } + } +} diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/RightClickMultipleItemsContextMenuExtension.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/RightClickMultipleItemsContextMenuExtension.cs new file mode 100644 index 0000000000..5f24f5caff --- /dev/null +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/RightClickMultipleItemsContextMenuExtension.cs @@ -0,0 +1,54 @@ +// Copyright (c) 2014 AlphaSierraPapa for the SharpDevelop Team +// +// Permission is hereby granted, free of charge, to any person obtaining a copy of this +// software and associated documentation files (the "Software"), to deal in the Software +// without restriction, including without limitation the rights to use, copy, modify, merge, +// publish, distribute, sublicense, and/or sell copies of the Software, and to permit persons +// to whom the Software is furnished to do so, subject to the following conditions: +// +// The above copyright notice and this permission notice shall be included in all copies or +// substantial portions of the Software. +// +// THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR IMPLIED, +// INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR +// PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE +// FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR +// OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER +// DEALINGS IN THE SOFTWARE. + +using System; +using System.Windows; +using System.Windows.Media; +using System.Windows.Shapes; + +using ICSharpCode.WpfDesign.Adorners; +using ICSharpCode.WpfDesign.Extensions; +using ICSharpCode.WpfDesign.Designer; + +namespace ICSharpCode.WpfDesign.Designer.Extensions +{ + /// + /// + /// + [ExtensionServer(typeof(MultipleSelectedExtensionServer))] + [ExtensionFor(typeof(UIElement))] + public class RightClickMultipleItemsContextMenuExtension : SelectionAdornerProvider + { + DesignPanel panel; + + protected override void OnInitialized() + { + base.OnInitialized(); + + panel = ExtendedItem.Context.Services.DesignPanel as DesignPanel; + panel.ContextMenu = new RightClickMultipleItemsContextMenu(ExtendedItem); + } + + protected override void OnRemove() + { + panel.ContextMenu = null; + + base.OnRemove(); + } + } +} diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/ModelTools.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/ModelTools.cs index 73a1510495..f8c8d22406 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/ModelTools.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/ModelTools.cs @@ -27,6 +27,7 @@ using System.Windows.Markup; using System.Windows.Media; using System.Windows.Media.Imaging; using System.Windows.Xps.Serialization; +using ICSharpCode.WpfDesign.Designer.Xaml; namespace ICSharpCode.WpfDesign.Designer { @@ -137,7 +138,7 @@ namespace ICSharpCode.WpfDesign.Designer catch (Exception) { } } - + internal static Size GetDefaultSize(DesignItem createdItem) { CreateVisualTree(createdItem.View); @@ -198,5 +199,174 @@ namespace ICSharpCode.WpfDesign.Designer item.Properties.GetProperty(FrameworkElement.HeightProperty).SetValue(newHeight); } } + + + private class ItemPos + { + public HorizontalAlignment HorizontalAlignment{ get; set; } + + public VerticalAlignment VerticalAlignment{ get; set; } + + public double Xmin { get; set; } + + public double Xmax { get; set; } + + public double Ymin { get; set; } + + public double Ymax { get; set; } + + public DesignItem DesignItem { get; set; } + } + + public static void WrapItemsNewContainer(IEnumerable items, Type containerType) + { + var collection = items; + + var _context = collection.First().Context as XamlDesignContext; + + var oldContainer = collection.First().Parent; + + if (collection.Any(x => x.Parent != oldContainer)) + return; + + var newInstance = Activator.CreateInstance(containerType); + DesignItem newPanel = _context.Services.Component.RegisterComponentForDesigner(newInstance); + var changeGroup = newPanel.OpenGroup("Wrap in Container"); + + List itemList = new List(); + + foreach (var item in collection) { + + var itemPos = new ItemPos(){ DesignItem = item }; + itemList.Add(itemPos); + + if (oldContainer.Component is Canvas) { + var canvas = oldContainer.View as Canvas; + + if (item.Properties.GetAttachedProperty(Canvas.RightProperty) != null && item.Properties.GetAttachedProperty(Canvas.RightProperty).IsSet) { + itemPos.HorizontalAlignment = HorizontalAlignment.Right; + itemPos.Xmax = canvas.ActualWidth - (double)item.Properties.GetAttachedProperty(Canvas.RightProperty).ValueOnInstance; + itemPos.Xmin = itemPos.Xmax - ((FrameworkElement)item.View).ActualWidth; + } + else if (item.Properties.GetAttachedProperty(Canvas.LeftProperty) != null && item.Properties.GetAttachedProperty(Canvas.LeftProperty).IsSet) { + itemPos.HorizontalAlignment = HorizontalAlignment.Left; + itemPos.Xmin = (double)item.Properties.GetAttachedProperty(Canvas.LeftProperty).ValueOnInstance; + itemPos.Xmax = itemPos.Xmin + ((FrameworkElement)item.View).ActualWidth; + } else { + itemPos.HorizontalAlignment = HorizontalAlignment.Left; + itemPos.Xmax = itemPos.Xmin + ((FrameworkElement)item.View).ActualWidth; + } + + if (item.Properties.GetAttachedProperty(Canvas.BottomProperty) != null && item.Properties.GetAttachedProperty(Canvas.BottomProperty).IsSet) { + itemPos.VerticalAlignment = VerticalAlignment.Bottom; + itemPos.Ymax = canvas.ActualHeight - (double)item.Properties.GetAttachedProperty(Canvas.BottomProperty).ValueOnInstance; + itemPos.Ymin = itemPos.Ymax - ((FrameworkElement)item.View).ActualHeight; + } + else if (item.Properties.GetAttachedProperty(Canvas.TopProperty) != null && item.Properties.GetAttachedProperty(Canvas.TopProperty).IsSet) { + itemPos.VerticalAlignment = VerticalAlignment.Top; + itemPos.Ymin = (double)item.Properties.GetAttachedProperty(Canvas.TopProperty).ValueOnInstance; + itemPos.Ymax = itemPos.Ymin + ((FrameworkElement)item.View).ActualHeight; + } else { + itemPos.VerticalAlignment = VerticalAlignment.Top; + itemPos.Ymax = itemPos.Ymin + ((FrameworkElement)item.View).ActualHeight; + } + + item.Properties.GetAttachedProperty(Canvas.RightProperty).Reset(); + item.Properties.GetAttachedProperty(Canvas.LeftProperty).Reset(); + item.Properties.GetAttachedProperty(Canvas.TopProperty).Reset(); + item.Properties.GetAttachedProperty(Canvas.BottomProperty).Reset(); + } else if (oldContainer.Component is Grid) { + var grid = oldContainer.View as Grid; + + if ((HorizontalAlignment)item.Properties.GetProperty(FrameworkElement.HorizontalAlignmentProperty).ValueOnInstance == HorizontalAlignment.Right) { + itemPos.HorizontalAlignment = HorizontalAlignment.Right; + itemPos.Xmax = grid.ActualWidth - ((Thickness)item.Properties.GetProperty(FrameworkElement.MarginProperty).ValueOnInstance).Right; + itemPos.Xmin = itemPos.Xmax - ((FrameworkElement)item.View).ActualWidth; + } else { + itemPos.HorizontalAlignment = HorizontalAlignment.Left; + itemPos.Xmin = ((Thickness)item.Properties.GetProperty(FrameworkElement.MarginProperty).ValueOnInstance).Left; + itemPos.Xmax = itemPos.Xmin + ((FrameworkElement)item.View).ActualWidth; + } + + if ((VerticalAlignment)item.Properties.GetProperty(FrameworkElement.VerticalAlignmentProperty).ValueOnInstance == VerticalAlignment.Bottom) { + itemPos.VerticalAlignment = VerticalAlignment.Bottom; + itemPos.Ymax = grid.ActualHeight - ((Thickness)item.Properties.GetProperty(FrameworkElement.MarginProperty).ValueOnInstance).Bottom; + itemPos.Ymin = itemPos.Ymax - ((FrameworkElement)item.View).ActualHeight; + } else { + itemPos.VerticalAlignment = VerticalAlignment.Top; + itemPos.Ymin = ((Thickness)item.Properties.GetProperty(FrameworkElement.MarginProperty).ValueOnInstance).Top; + itemPos.Ymax = itemPos.Ymin + ((FrameworkElement)item.View).ActualHeight; + } + + item.Properties.GetProperty(FrameworkElement.HorizontalAlignmentProperty).Reset(); + item.Properties.GetProperty(FrameworkElement.VerticalAlignmentProperty).Reset(); + item.Properties.GetProperty(FrameworkElement.MarginProperty).Reset(); + } + + var parCol = item.ParentProperty.CollectionElements; + parCol.Remove(item); + } + + var xmin = itemList.Min(x => x.Xmin); + var xmax = itemList.Max(x => x.Xmax); + var ymin = itemList.Min(x => x.Ymin); + var ymax = itemList.Max(x => x.Ymax); + + if (oldContainer.Component is Canvas) { + newPanel.Properties.GetProperty(FrameworkElement.WidthProperty).SetValue(xmax - xmin); + newPanel.Properties.GetProperty(FrameworkElement.HeightProperty).SetValue(ymax - ymin); + newPanel.Properties.GetAttachedProperty(Canvas.LeftProperty).SetValue(xmin); + newPanel.Properties.GetAttachedProperty(Canvas.TopProperty).SetValue(ymin); + } else if (oldContainer.Component is Grid) { + newPanel.Properties.GetProperty(FrameworkElement.HorizontalAlignmentProperty).SetValue(HorizontalAlignment.Left); + newPanel.Properties.GetProperty(FrameworkElement.VerticalAlignmentProperty).SetValue(VerticalAlignment.Top); + newPanel.Properties.GetProperty(FrameworkElement.MarginProperty).SetValue(new Thickness(xmin, ymin, 0, 0)); + newPanel.Properties.GetProperty(FrameworkElement.WidthProperty).SetValue(xmax - xmin); + newPanel.Properties.GetProperty(FrameworkElement.HeightProperty).SetValue(ymax - ymin); + } + + foreach (var item in itemList) { + newPanel.ContentProperty.CollectionElements.Add(item.DesignItem); + + if (newPanel.Component is Canvas) { + if (item.HorizontalAlignment == HorizontalAlignment.Right) { + item.DesignItem.Properties.GetAttachedProperty(Canvas.RightProperty).SetValue(xmax - item.Xmax); + } else { + item.DesignItem.Properties.GetAttachedProperty(Canvas.LeftProperty).SetValue(item.Xmin - xmin); + } + + if (item.VerticalAlignment == VerticalAlignment.Bottom) { + item.DesignItem.Properties.GetAttachedProperty(Canvas.BottomProperty).SetValue(ymax - item.Ymax); + } else { + item.DesignItem.Properties.GetAttachedProperty(Canvas.TopProperty).SetValue(item.Ymin - ymin); + } + } else if (newPanel.Component is Grid) { + Thickness thickness = new Thickness(0); + if (item.HorizontalAlignment == HorizontalAlignment.Right) { + item.DesignItem.Properties.GetProperty(FrameworkElement.HorizontalAlignmentProperty).SetValue(HorizontalAlignment.Right); + thickness.Right = xmax - item.Xmax; + } else { + item.DesignItem.Properties.GetProperty(FrameworkElement.HorizontalAlignmentProperty).SetValue(HorizontalAlignment.Left); + thickness.Left = item.Xmin - xmin; + } + + if (item.VerticalAlignment == VerticalAlignment.Bottom) { + item.DesignItem.Properties.GetProperty(FrameworkElement.VerticalAlignmentProperty).SetValue(VerticalAlignment.Bottom); + thickness.Bottom = ymax - item.Ymax; + } else { + item.DesignItem.Properties.GetProperty(FrameworkElement.VerticalAlignmentProperty).SetValue(VerticalAlignment.Top); + thickness.Top = item.Ymin - ymin; + } + + item.DesignItem.Properties.GetProperty(FrameworkElement.MarginProperty).SetValue(thickness); + } + } + + oldContainer.ContentProperty.CollectionElements.Add(newPanel); + + changeGroup.Commit(); + + _context.Services.Selection.SetSelectedComponents(new []{ newPanel }); + } } } diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Translations.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Translations.cs index 15677480c9..ebb196ca26 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Translations.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Translations.cs @@ -65,5 +65,23 @@ namespace ICSharpCode.WpfDesign.Designer return "Press \"Alt\" to Enter Container"; } } + + public virtual string WrapInCanvas { + get { + return "Wrap in Canvas"; + } + } + + public virtual string WrapInGrid { + get { + return "Wrap in Grid"; + } + } + + public virtual string WrapInBorder { + get { + return "Wrap in Border"; + } + } } } diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj index 0cb8629e13..ee6c301f7f 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/WpfDesign.Designer.csproj @@ -90,6 +90,10 @@ + + + RightClickMultipleItemsContextMenu.xaml + @@ -263,6 +267,7 @@ + diff --git a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/SelectionExtensionServer.cs b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/SelectionExtensionServer.cs index 75db9cd2c4..fc88c441a9 100644 --- a/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/SelectionExtensionServer.cs +++ b/src/AddIns/DisplayBindings/WpfDesign/WpfDesign/Project/Extensions/SelectionExtensionServer.cs @@ -118,7 +118,7 @@ namespace ICSharpCode.WpfDesign.Extensions void OnSelectionChanged(object sender, EventArgs e) { - ReapplyExtensions(this.Services.Selection.SelectedItems); + ReapplyExtensions(this.Services.Selection.SelectedItems); } /// @@ -130,6 +130,34 @@ namespace ICSharpCode.WpfDesign.Extensions } } + /// + /// Applies an extension only when multiple Items are selected! + /// + public class MultipleSelectedExtensionServer : DefaultExtensionServer + { + /// + /// Is called after the extension server is initialized and the Context property has been set. + /// + protected override void OnInitialized() + { + base.OnInitialized(); + this.Services.Selection.SelectionChanged += OnSelectionChanged; + } + + void OnSelectionChanged(object sender, EventArgs e) + { + ReapplyExtensions(this.Services.Selection.SelectedItems); + } + + /// + /// Gets if the item is in the secondary selection. + /// + public override bool ShouldApplyExtensions(DesignItem extendedItem) + { + return Services.Selection.SelectionCount > 1; + } + } + /// /// Applies an extension to the primary selection if Only One Item is Selected. ///