Browse Source

Snapline for middle of Object (like in VisualStudio)

pull/446/head
jkuehner 11 years ago
parent
commit
3dd49163c9
  1. 88
      src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/SnaplinePlacementBehavior.cs

88
src/AddIns/DisplayBindings/WpfDesign/WpfDesign.Designer/Project/Extensions/SnaplinePlacementBehavior.cs

@ -41,51 +41,51 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions @@ -41,51 +41,51 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
List<Snapline> horizontalMap;
List<Snapline> verticalMap;
double? baseline;
public const double Accuracy = 5;
public const double Margin = 8;
public override void BeginPlacement(PlacementOperation operation)
{
base.BeginPlacement(operation);
CreateSurface(operation);
}
public override void EndPlacement(PlacementOperation operation)
{
base.EndPlacement(operation);
DeleteSurface();
}
public override void EnterContainer(PlacementOperation operation)
{
base.EnterContainer(operation);
CreateSurface(operation);
}
public override void LeaveContainer(PlacementOperation operation)
{
base.LeaveContainer(operation);
DeleteSurface();
}
public override void BeforeSetPosition(PlacementOperation operation)
{
base.BeforeSetPosition(operation);
if (surface == null) return;
DesignPanel designPanel = ExtendedItem.Services.DesignPanel as DesignPanel;
if (designPanel == null || !designPanel.UseSnaplinePlacement)
return;
surface.Children.Clear();
if (Keyboard.IsKeyDown(Key.LeftCtrl)) return;
Rect bounds = Rect.Empty;
foreach (var item in operation.PlacedItems) {
bounds.Union(item.Bounds);
}
var horizontalInput = new List<Snapline>();
var verticalInput = new List<Snapline>();
var info = operation.PlacedItems[0];
@ -99,7 +99,7 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions @@ -99,7 +99,7 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
horizontalInput.Add(new Snapline() { Group = 1, Offset = textOffset, Start = bounds.Left, End = bounds.Right });
}
}
// debug
//foreach (var t in horizontalMap.Concat(horizontalInput)) {
// surface.Children.Add(new Line() { X1 = t.Start, X2 = t.End, Y1 = t.Offset, Y2 = t.Offset, Stroke = Brushes.Black });
@ -108,12 +108,12 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions @@ -108,12 +108,12 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
// surface.Children.Add(new Line() { X1 = t.Offset, X2 = t.Offset, Y1 = t.Start , Y2 = t.End, Stroke = Brushes.Black });
//}
//return;
List<Snapline> drawLines;
double delta;
if (Snap(horizontalInput, horizontalMap, Accuracy, out drawLines, out delta)) {
if (operation.Type == PlacementType.Resize) {
if (info.ResizeThumbAlignment.Vertical == VerticalAlignment.Top) {
bounds.Y += delta;
@ -129,14 +129,14 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions @@ -129,14 +129,14 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
item.Bounds = r;
}
}
foreach (var d in drawLines) {
DrawLine(d.Start, d.Offset, d.End, d.Offset);
}
}
if (Snap(verticalInput, verticalMap, Accuracy, out drawLines, out delta)) {
if (operation.Type == PlacementType.Resize) {
if (info.ResizeThumbAlignment.Horizontal == HorizontalAlignment.Left) {
bounds.X += delta;
@ -158,52 +158,52 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions @@ -158,52 +158,52 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
}
}
}
void CreateSurface(PlacementOperation operation)
{
if (ExtendedItem.Services.GetService<IDesignPanel>() != null) {
surface = new Canvas();
adornerPanel = new AdornerPanel();
adornerPanel.SetAdornedElement(ExtendedItem.View, ExtendedItem);
AdornerPanel.SetPlacement(surface, AdornerPlacement.FillContent);
adornerPanel.Children.Add(surface);
ExtendedItem.Services.DesignPanel.Adorners.Add(adornerPanel);
BuildMaps(operation);
if (operation.Type != PlacementType.Resize && operation.PlacedItems.Count == 1) {
baseline = GetBaseline(operation.PlacedItems[0].Item.View);
}
}
}
void BuildMaps(PlacementOperation operation)
{
horizontalMap = new List<Snapline>();
verticalMap = new List<Snapline>();
var containerRect = new Rect(0, 0, ModelTools.GetWidth(ExtendedItem.View), ModelTools.GetHeight(ExtendedItem.View));
AddLines(containerRect, -Margin, false);
AddLines(containerRect, 0, false);
foreach (var item in ExtendedItem.ContentProperty.CollectionElements
.Except(operation.PlacedItems.Select(f => f.Item)))
.Except(operation.PlacedItems.Select(f => f.Item)))
{
var bounds = GetPosition(operation, item);
AddLines(bounds, 0, false);
AddLines(bounds, Margin, true);
AddBaseline(item, bounds, horizontalMap);
}
}
void AddLines(Rect r, double inflate, bool requireOverlap)
{
AddLines(r, inflate, requireOverlap, horizontalMap, verticalMap, null);
}
void AddLines(Rect r, double inflate, bool requireOverlap, List<Snapline> h, List<Snapline> v, PlacementAlignment? filter)
{
Rect r2 = r;
@ -217,8 +217,14 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions @@ -217,8 +217,14 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
v.Add(new Snapline() { RequireOverlap = requireOverlap, Offset = r2.Left - 1, Start = r.Top, End = r.Bottom });
if (filter == null || filter.Value.Horizontal == HorizontalAlignment.Right)
v.Add(new Snapline() { RequireOverlap = requireOverlap, Offset = r2.Right - 1, Start = r.Top, End = r.Bottom });
if (filter == null)
{
h.Add(new Snapline() { RequireOverlap = requireOverlap, Offset = r2.Top + Math.Abs((r2.Top - r2.Bottom) / 2), Start = r.Left, End = r.Right });
v.Add(new Snapline() { RequireOverlap = requireOverlap, Offset = r2.Left + Math.Abs((r2.Left - r2.Right) / 2), Start = r.Top, End = r.Bottom });
}
}
void AddBaseline(DesignItem item, Rect bounds, List<Snapline> list)
{
var baseline = GetBaseline(item.View);
@ -227,7 +233,7 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions @@ -227,7 +233,7 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
list.Add(new Snapline() { Group = 1, Offset = textOffset, Start = bounds.Left, End = bounds.Right });
}
}
void DeleteSurface()
{
if (surface != null) {
@ -238,7 +244,7 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions @@ -238,7 +244,7 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
verticalMap = null;
}
}
void DrawLine(double x1, double y1, double x2, double y2)
{
var line1 = new Line() {
@ -250,7 +256,7 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions @@ -250,7 +256,7 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
Stroke = Brushes.White
};
surface.Children.Add(line1);
var line2 = new Line() {
X1 = x1,
Y1 = y1,
@ -263,7 +269,7 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions @@ -263,7 +269,7 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
};
surface.Children.Add(line2);
}
//TODO: GlyphRun must be used
static double? GetBaseline(UIElement element) {
var textBox = element as TextBox;
@ -274,21 +280,21 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions @@ -274,21 +280,21 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
var textBlock = element as TextBlock;
if (textBlock != null)
return textBlock.TranslatePoint(new Point(0, textBlock.ActualHeight), element).Y;
return null;
}
static bool Snap(List<Snapline> input, List<Snapline> map, double accuracy,
out List<Snapline> drawLines, out double delta)
out List<Snapline> drawLines, out double delta)
{
delta = double.MaxValue;
drawLines = null;
foreach (var inputLine in input) {
foreach (var mapLine in map) {
if (Math.Abs(mapLine.Offset - inputLine.Offset) <= accuracy) {
if (!inputLine.RequireOverlap && !mapLine.RequireOverlap ||
Math.Max(inputLine.Start, mapLine.Start) < Math.Min(inputLine.End, mapLine.End))
Math.Max(inputLine.Start, mapLine.Start) < Math.Min(inputLine.End, mapLine.End))
{
if (mapLine.Group == inputLine.Group)
delta = mapLine.Offset - inputLine.Offset;
@ -296,10 +302,10 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions @@ -296,10 +302,10 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
}
}
}
if (delta == double.MaxValue) return false;
var offsetDict = new Dictionary<double, Snapline>();
foreach (var inputLine in input) {
inputLine.Offset += delta;
foreach (var mapLine in map) {
@ -318,11 +324,11 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions @@ -318,11 +324,11 @@ namespace ICSharpCode.WpfDesign.Designer.Extensions
}
}
}
drawLines = offsetDict.Values.ToList();
return true;
}
[DebuggerDisplay("Snapline: {Offset}")]
class Snapline
{

Loading…
Cancel
Save