Browse Source
git-svn-id: svn://svn.sharpdevelop.net/sharpdevelop/trunk@2441 1ccf3a8d-04fe-1044-b7c0-cef0b8235c61shortcuts
24 changed files with 462 additions and 68 deletions
@ -0,0 +1,195 @@
@@ -0,0 +1,195 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using System.Diagnostics; |
||||
using ICSharpCode.WpfDesign.Adorners; |
||||
using ICSharpCode.WpfDesign.Extensions; |
||||
using System.Windows; |
||||
using System.Windows.Controls; |
||||
using System.Windows.Shapes; |
||||
using System.Windows.Media; |
||||
using System.Windows.Input; |
||||
|
||||
namespace ICSharpCode.WpfDesign.Designer.Controls |
||||
{ |
||||
/// <summary>
|
||||
/// Adorner that displays the blue bar next to grids that can be used to create new rows/column.
|
||||
/// </summary>
|
||||
public class GridRailAdorner : Control |
||||
{ |
||||
static GridRailAdorner() |
||||
{ |
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(GridRailAdorner), new FrameworkPropertyMetadata(typeof(GridRailAdorner))); |
||||
} |
||||
|
||||
readonly DesignItem gridItem; |
||||
readonly Grid grid; |
||||
readonly AdornerPanel adornerPanel; |
||||
readonly GridSplitterAdorner previewAdorner; |
||||
readonly Orientation orientation; |
||||
|
||||
public const double RailSize = 10; |
||||
public const double SplitterWidth = 10; |
||||
|
||||
public GridRailAdorner(DesignItem gridItem, AdornerPanel adornerPanel, Orientation orientation) |
||||
{ |
||||
Debug.Assert(gridItem != null); |
||||
Debug.Assert(adornerPanel != null); |
||||
|
||||
this.gridItem = gridItem; |
||||
this.grid = (Grid)gridItem.Component; |
||||
this.adornerPanel = adornerPanel; |
||||
this.orientation = orientation; |
||||
|
||||
if (orientation == Orientation.Horizontal) { |
||||
this.Height = RailSize; |
||||
previewAdorner = new GridColumnSplitterAdorner(); |
||||
} else { // vertical
|
||||
this.Width = RailSize; |
||||
previewAdorner = new GridRowSplitterAdorner(); |
||||
} |
||||
previewAdorner.IsPreview = true; |
||||
previewAdorner.IsHitTestVisible = false; |
||||
} |
||||
|
||||
#region Handle mouse events to add a new row/column
|
||||
protected override void OnMouseEnter(MouseEventArgs e) |
||||
{ |
||||
base.OnMouseEnter(e); |
||||
adornerPanel.Children.Add(previewAdorner); |
||||
} |
||||
|
||||
protected override void OnMouseMove(MouseEventArgs e) |
||||
{ |
||||
base.OnMouseMove(e); |
||||
RelativePlacement rp = new RelativePlacement(); |
||||
if (orientation == Orientation.Vertical) { |
||||
rp.XOffset = -RailSize; |
||||
rp.WidthOffset = RailSize; |
||||
rp.WidthRelativeToContentWidth = 1; |
||||
rp.HeightOffset = SplitterWidth; |
||||
rp.YOffset = e.GetPosition(this).Y - SplitterWidth / 2; |
||||
} else { |
||||
rp.YOffset = -RailSize; |
||||
rp.HeightOffset = RailSize; |
||||
rp.HeightRelativeToContentHeight = 1; |
||||
rp.WidthOffset = SplitterWidth; |
||||
rp.XOffset = e.GetPosition(this).X - SplitterWidth / 2; |
||||
} |
||||
AdornerPanel.SetPlacement(previewAdorner, rp); |
||||
} |
||||
|
||||
protected override void OnMouseLeave(MouseEventArgs e) |
||||
{ |
||||
base.OnMouseLeave(e); |
||||
adornerPanel.Children.Remove(previewAdorner); |
||||
} |
||||
|
||||
protected override void OnMouseLeftButtonDown(MouseButtonEventArgs e) |
||||
{ |
||||
base.OnMouseLeftButtonDown(e); |
||||
e.Handled = true; |
||||
adornerPanel.Children.Remove(previewAdorner); |
||||
if (orientation == Orientation.Vertical) { |
||||
using (ChangeGroup changeGroup = gridItem.OpenGroup("Split grid row")) { |
||||
DesignItemProperty rowCollection = gridItem.Properties["RowDefinitions"]; |
||||
if (rowCollection.CollectionElements.Count == 0) { |
||||
DesignItem firstRow = gridItem.Services.Component.RegisterComponentForDesigner(new RowDefinition()); |
||||
rowCollection.CollectionElements.Add(firstRow); |
||||
grid.UpdateLayout(); // let WPF assign firstRow.ActualHeight
|
||||
} |
||||
double insertionPosition = e.GetPosition(this).Y; |
||||
for (int i = 0; i < grid.RowDefinitions.Count; i++) { |
||||
RowDefinition row = grid.RowDefinitions[i]; |
||||
if (row.Offset > insertionPosition) continue; |
||||
if (row.Offset + row.ActualHeight < insertionPosition) continue; |
||||
|
||||
// split row
|
||||
GridLength oldLength = (GridLength)row.GetValue(RowDefinition.HeightProperty); |
||||
GridLength newLength1, newLength2; |
||||
SplitLength(oldLength, insertionPosition - row.Offset, row.ActualHeight, out newLength1, out newLength2); |
||||
DesignItem newRowDefinition = gridItem.Services.Component.RegisterComponentForDesigner(new RowDefinition()); |
||||
rowCollection.CollectionElements.Insert(i + 1, newRowDefinition); |
||||
rowCollection.CollectionElements[i].Properties[RowDefinition.HeightProperty].SetValue(newLength1); |
||||
newRowDefinition.Properties[RowDefinition.HeightProperty].SetValue(newLength2); |
||||
changeGroup.Commit(); |
||||
break; |
||||
} |
||||
} |
||||
} else { |
||||
using (ChangeGroup changeGroup = gridItem.OpenGroup("Split grid column")) { |
||||
DesignItemProperty columnCollection = gridItem.Properties["ColumnDefinitions"]; |
||||
if (columnCollection.CollectionElements.Count == 0) { |
||||
DesignItem firstColumn = gridItem.Services.Component.RegisterComponentForDesigner(new ColumnDefinition()); |
||||
columnCollection.CollectionElements.Add(firstColumn); |
||||
grid.UpdateLayout(); // let WPF assign firstColumn.ActualWidth
|
||||
} |
||||
double insertionPosition = e.GetPosition(this).X; |
||||
for (int i = 0; i < grid.ColumnDefinitions.Count; i++) { |
||||
ColumnDefinition column = grid.ColumnDefinitions[i]; |
||||
if (column.Offset > insertionPosition) continue; |
||||
if (column.Offset + column.ActualWidth < insertionPosition) continue; |
||||
|
||||
// split column
|
||||
GridLength oldLength = (GridLength)column.GetValue(ColumnDefinition.WidthProperty); |
||||
GridLength newLength1, newLength2; |
||||
SplitLength(oldLength, insertionPosition - column.Offset, column.ActualWidth, out newLength1, out newLength2); |
||||
columnCollection.CollectionElements[i].Properties[ColumnDefinition.WidthProperty].SetValue(newLength1); |
||||
DesignItem newColumnDefinition = gridItem.Services.Component.RegisterComponentForDesigner(new ColumnDefinition()); |
||||
newColumnDefinition.Properties[ColumnDefinition.WidthProperty].SetValue(newLength2); |
||||
columnCollection.CollectionElements.Insert(i + 1, newColumnDefinition); |
||||
changeGroup.Commit(); |
||||
break; |
||||
} |
||||
} |
||||
} |
||||
} |
||||
|
||||
void SplitLength(GridLength oldLength, double insertionPosition, double oldActualValue, |
||||
out GridLength newLength1, out GridLength newLength2) |
||||
{ |
||||
if (oldLength.IsAuto) { |
||||
oldLength = new GridLength(oldActualValue); |
||||
} |
||||
double percentage = insertionPosition / oldActualValue; |
||||
newLength1 = new GridLength(oldLength.Value * percentage, oldLength.GridUnitType); |
||||
newLength2 = new GridLength(oldLength.Value - newLength1.Value, oldLength.GridUnitType); |
||||
} |
||||
#endregion
|
||||
} |
||||
|
||||
public class GridSplitterAdorner : Control |
||||
{ |
||||
public static readonly DependencyProperty IsPreviewProperty |
||||
= DependencyProperty.Register("IsPreview", typeof(bool), typeof(GridSplitterAdorner), new PropertyMetadata(SharedInstances.BoxedFalse)); |
||||
|
||||
public bool IsPreview { |
||||
get { return (bool)GetValue(IsPreviewProperty); } |
||||
set { SetValue(IsPreviewProperty, SharedInstances.Box(value)); } |
||||
} |
||||
} |
||||
|
||||
public class GridRowSplitterAdorner : GridSplitterAdorner |
||||
{ |
||||
static GridRowSplitterAdorner() |
||||
{ |
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(GridRowSplitterAdorner), new FrameworkPropertyMetadata(typeof(GridRowSplitterAdorner))); |
||||
CursorProperty.OverrideMetadata(typeof(GridRowSplitterAdorner), new FrameworkPropertyMetadata(Cursors.SizeNS)); |
||||
} |
||||
} |
||||
|
||||
public class GridColumnSplitterAdorner : GridSplitterAdorner |
||||
{ |
||||
static GridColumnSplitterAdorner() |
||||
{ |
||||
DefaultStyleKeyProperty.OverrideMetadata(typeof(GridColumnSplitterAdorner), new FrameworkPropertyMetadata(typeof(GridColumnSplitterAdorner))); |
||||
CursorProperty.OverrideMetadata(typeof(GridColumnSplitterAdorner), new FrameworkPropertyMetadata(Cursors.SizeWE)); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,130 @@
@@ -0,0 +1,130 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
using System.Collections.Generic; |
||||
using ICSharpCode.WpfDesign.Adorners; |
||||
using ICSharpCode.WpfDesign.Extensions; |
||||
using System.Windows; |
||||
using System.Windows.Controls; |
||||
using System.Windows.Shapes; |
||||
using System.Windows.Media; |
||||
using System.Windows.Threading; |
||||
using ICSharpCode.WpfDesign.Designer.Controls; |
||||
|
||||
namespace ICSharpCode.WpfDesign.Designer.Extensions |
||||
{ |
||||
/// <summary>
|
||||
/// Allows arranging the rows/column on a grid.
|
||||
/// </summary>
|
||||
[ExtensionFor(typeof(Grid))] |
||||
public class GridAdornerProvider : PrimarySelectionAdornerProvider |
||||
{ |
||||
sealed class RowSplitterPlacement : AdornerPlacement |
||||
{ |
||||
readonly RowDefinition row; |
||||
public RowSplitterPlacement(RowDefinition row) { this.row = row; } |
||||
|
||||
public override void Arrange(AdornerPanel panel, UIElement adorner, Size adornedElementSize) |
||||
{ |
||||
adorner.Arrange(new Rect(-GridRailAdorner.RailSize, |
||||
row.Offset - GridRailAdorner.SplitterWidth / 2, |
||||
GridRailAdorner.RailSize + adornedElementSize.Width, |
||||
GridRailAdorner.SplitterWidth)); |
||||
} |
||||
} |
||||
|
||||
sealed class ColumnSplitterPlacement : AdornerPlacement |
||||
{ |
||||
readonly ColumnDefinition column; |
||||
public ColumnSplitterPlacement(ColumnDefinition column) { this.column = column; } |
||||
|
||||
public override void Arrange(AdornerPanel panel, UIElement adorner, Size adornedElementSize) |
||||
{ |
||||
adorner.Arrange(new Rect(column.Offset - GridRailAdorner.SplitterWidth / 2, |
||||
-GridRailAdorner.RailSize, |
||||
GridRailAdorner.SplitterWidth, |
||||
GridRailAdorner.RailSize + adornedElementSize.Height)); |
||||
} |
||||
} |
||||
|
||||
AdornerPanel adornerPanel = new AdornerPanel(); |
||||
GridRailAdorner topBar, leftBar; |
||||
|
||||
protected override void OnInitialized() |
||||
{ |
||||
leftBar = new GridRailAdorner(this.ExtendedItem, adornerPanel, Orientation.Vertical); |
||||
topBar = new GridRailAdorner(this.ExtendedItem, adornerPanel, Orientation.Horizontal); |
||||
|
||||
AdornerPanel.SetPlacement(leftBar, new RelativePlacement(HorizontalAlignment.Left, VerticalAlignment.Stretch)); |
||||
AdornerPanel.SetPlacement(topBar, new RelativePlacement(HorizontalAlignment.Stretch, VerticalAlignment.Top)); |
||||
|
||||
adornerPanel.Children.Add(leftBar); |
||||
adornerPanel.Children.Add(topBar); |
||||
this.Adorners.Add(adornerPanel); |
||||
|
||||
CreateSplitter(); |
||||
this.ExtendedItem.PropertyChanged += OnPropertyChanged; |
||||
|
||||
base.OnInitialized(); |
||||
} |
||||
|
||||
protected override void OnRemove() |
||||
{ |
||||
this.ExtendedItem.PropertyChanged -= OnPropertyChanged; |
||||
base.OnRemove(); |
||||
} |
||||
|
||||
void OnPropertyChanged(object sender, System.ComponentModel.PropertyChangedEventArgs e) |
||||
{ |
||||
if (e.PropertyName == "RowDefinitions" || e.PropertyName == "ColumnDefinitions") { |
||||
CreateSplitter(); |
||||
} |
||||
} |
||||
|
||||
readonly List<GridSplitterAdorner> splitterList = new List<GridSplitterAdorner>(); |
||||
/// <summary>
|
||||
/// flag used to unsure that the asynchronus splitter creation is only enqueued once
|
||||
/// </summary>
|
||||
bool requireSplitterRecreation; |
||||
|
||||
void CreateSplitter() |
||||
{ |
||||
if (requireSplitterRecreation) return; |
||||
requireSplitterRecreation = true; |
||||
|
||||
// splitter creation is asynchronous to prevent unnecessary splitter re-creation when multiple
|
||||
// changes to the collection are done.
|
||||
// It also ensures that the Offset property of new rows/columns is initialized when the splitter
|
||||
// is added.
|
||||
Dispatcher.CurrentDispatcher.BeginInvoke( |
||||
DispatcherPriority.Loaded, // Loaded = after layout, but before input
|
||||
(Action)delegate { |
||||
requireSplitterRecreation = false; |
||||
foreach (GridSplitterAdorner splitter in splitterList) { |
||||
adornerPanel.Children.Remove(splitter); |
||||
} |
||||
splitterList.Clear(); |
||||
Grid grid = (Grid)this.ExtendedItem.Component; |
||||
for (int i = 1; i < grid.RowDefinitions.Count; i++) { |
||||
RowDefinition row = grid.RowDefinitions[i]; |
||||
GridRowSplitterAdorner splitter = new GridRowSplitterAdorner(); |
||||
AdornerPanel.SetPlacement(splitter, new RowSplitterPlacement(row)); |
||||
adornerPanel.Children.Add(splitter); |
||||
splitterList.Add(splitter); |
||||
} |
||||
for (int i = 1; i < grid.ColumnDefinitions.Count; i++) { |
||||
ColumnDefinition column = grid.ColumnDefinitions[i]; |
||||
GridColumnSplitterAdorner splitter = new GridColumnSplitterAdorner(); |
||||
AdornerPanel.SetPlacement(splitter, new ColumnSplitterPlacement(column)); |
||||
adornerPanel.Children.Add(splitter); |
||||
splitterList.Add(splitter); |
||||
} |
||||
}); |
||||
} |
||||
} |
||||
} |
||||
@ -0,0 +1,24 @@
@@ -0,0 +1,24 @@
|
||||
// <file>
|
||||
// <copyright see="prj:///doc/copyright.txt"/>
|
||||
// <license see="prj:///doc/license.txt"/>
|
||||
// <owner name="Daniel Grunwald" email="daniel@danielgrunwald.de"/>
|
||||
// <version>$Revision$</version>
|
||||
// </file>
|
||||
|
||||
using System; |
||||
|
||||
namespace ICSharpCode.WpfDesign.Designer |
||||
{ |
||||
static class SharedInstances |
||||
{ |
||||
internal static readonly object BoxedTrue = true; |
||||
internal static readonly object BoxedFalse = false; |
||||
internal static readonly object[] EmptyObjectArray = new object[0]; |
||||
internal static readonly DesignItem[] EmptyDesignItemArray = new DesignItem[0]; |
||||
|
||||
internal static object Box(bool value) |
||||
{ |
||||
return value ? BoxedTrue : BoxedFalse; |
||||
} |
||||
} |
||||
} |
||||
Loading…
Reference in new issue