This repository has been archived by the owner on Nov 3, 2020. It is now read-only.
-
Notifications
You must be signed in to change notification settings - Fork 572
/
CartesianLayout.cs
138 lines (115 loc) · 5.19 KB
/
CartesianLayout.cs
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
using System;
using System.ComponentModel;
using Xamarin.Forms;
namespace Xamarin.FormsBook.Toolkit
{
public class CartesianLayout : Layout<BoxView>
{
public static readonly BindableProperty Point1Property =
BindableProperty.CreateAttached("Point1",
typeof(Point),
typeof(CartesianLayout),
new Point());
public static readonly BindableProperty Point2Property =
BindableProperty.CreateAttached("Point2",
typeof(Point),
typeof(CartesianLayout),
new Point());
public static readonly BindableProperty ThicknessProperty =
BindableProperty.CreateAttached("Thickness",
typeof(Double),
typeof(CartesianLayout),
1.0); // must be explicitly Double!
public static void SetPoint1(BindableObject bindable, Point point)
{
bindable.SetValue(Point1Property, point);
}
public static Point GetPoint1(BindableObject bindable)
{
return (Point)bindable.GetValue(Point1Property);
}
public static void SetPoint2(BindableObject bindable, Point point)
{
bindable.SetValue(Point2Property, point);
}
public static Point GetPoint2(BindableObject bindable)
{
return (Point)bindable.GetValue(Point2Property);
}
public static void SetThickness(BindableObject bindable, double thickness)
{
bindable.SetValue(ThicknessProperty, thickness);
}
public static double GetThickness(BindableObject bindable)
{
return (double)bindable.GetValue(ThicknessProperty);
}
// Monitor PropertyChanged events for items in the Children collection.
protected override void OnAdded(BoxView boxView)
{
base.OnAdded(boxView);
boxView.PropertyChanged += OnChildPropertyChanged;
}
protected override void OnRemoved(BoxView boxView)
{
base.OnRemoved(boxView);
boxView.PropertyChanged -= OnChildPropertyChanged;
}
void OnChildPropertyChanged(object sender, PropertyChangedEventArgs args)
{
if (args.PropertyName == Point1Property.PropertyName ||
args.PropertyName == Point2Property.PropertyName ||
args.PropertyName == ThicknessProperty.PropertyName)
{
InvalidateLayout();
}
}
protected override SizeRequest OnMeasure(double widthConstraint,
double heightConstraint)
{
if (Double.IsInfinity(widthConstraint) && Double.IsInfinity(heightConstraint))
throw new InvalidOperationException(
"CartesianLayout requires at least one dimension to be constrained.");
// Make it square!
double minimum = Math.Min(widthConstraint, heightConstraint);
return new SizeRequest(new Size(minimum, minimum));
}
protected override void LayoutChildren(double x, double y, double width, double height)
{
foreach (View child in Children)
{
if (!child.IsVisible)
continue;
double angle;
Rectangle bounds = GetChildBounds(child, x, y, width, height, out angle);
// Lay out the child.
child.Layout(bounds);
// Rotate the child.
child.Rotation = angle;
}
}
protected Rectangle GetChildBounds(View child,
double x, double y, double width, double height,
out double angle)
{
// Get coordinate system information.
Point coordCenter = new Point(x + width / 2, y + height / 2);
double unitLength = Math.Min(width, height) / 2;
// Get child information.
Point point1 = GetPoint1(child);
Point point2 = GetPoint2(child);
double thickness = GetThickness(child);
double length = unitLength * Math.Sqrt(Math.Pow(point2.X - point1.X, 2) +
Math.Pow(point2.Y - point1.Y, 2));
// Calculate child bounds.
Point centerChild = new Point((point1.X + point2.X) / 2,
(point1.Y + point2.Y) / 2);
double xChild = coordCenter.X + unitLength * centerChild.X - length / 2;
double yChild = coordCenter.Y - unitLength * centerChild.Y - thickness / 2;
Rectangle bounds = new Rectangle(xChild, yChild, length, thickness);
angle = 180 / Math.PI * Math.Atan2(point1.Y - point2.Y,
point2.X - point1.X);
return bounds;
}
}
}