Skip to content

Commit 4348412

Browse files
committed
Add CornerRadiusEx and accessories
1 parent 4041a13 commit 4348412

File tree

8 files changed

+422
-130
lines changed

8 files changed

+422
-130
lines changed
Lines changed: 215 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,215 @@
1+
using System;
2+
using System.Collections.Generic;
3+
using System.Diagnostics.CodeAnalysis;
4+
using System.Linq;
5+
using System.Text;
6+
using System.Threading.Tasks;
7+
using System.Windows;
8+
using System.Windows.Media;
9+
10+
namespace iNKORE.UI.WPF.Common
11+
{
12+
/// <summary>
13+
/// This is similar to the CornerRadius class in WPF, but it allows different values in X and Y axis for each corner.
14+
/// </summary>
15+
public struct CornerRadiusEx: IEquatable<CornerRadiusEx>
16+
{
17+
// According to WPF CornerRadius, these properties are mutable, so we can't use readonly fields.
18+
private double _topLeftX;
19+
public double TopLeftX
20+
{
21+
get { return this._topLeftX; }
22+
set { this._topLeftX = value; }
23+
}
24+
25+
private double _topLeftY;
26+
public double TopLeftY
27+
{
28+
get { return this._topLeftY; }
29+
set { this._topLeftY = value; }
30+
}
31+
32+
private double _topRightX;
33+
public double TopRightX
34+
{
35+
get { return this._topRightX; }
36+
set { this._topRightX = value; }
37+
}
38+
39+
private double _topRightY;
40+
public double TopRightY
41+
{
42+
get { return this._topRightY; }
43+
set { this._topRightY = value; }
44+
}
45+
46+
private double _bottomLeftX;
47+
public double BottomLeftX
48+
{
49+
get { return this._bottomLeftX; }
50+
set { this._bottomLeftX = value; }
51+
}
52+
53+
private double _bottomLeftY;
54+
public double BottomLeftY
55+
{
56+
get { return this._bottomLeftY; }
57+
set { this._bottomLeftY = value; }
58+
}
59+
60+
private double _bottomRightX;
61+
public double BottomRightX
62+
{
63+
get { return this._bottomRightX; }
64+
set { this._bottomRightX = value; }
65+
}
66+
67+
private double _bottomRightY;
68+
public double BottomRightY
69+
{
70+
get { return this._bottomRightY; }
71+
set { this._bottomRightY = value; }
72+
}
73+
74+
75+
public CornerRadiusEx(double topLeftX, double topLeftY, double topRightX, double topRightY, double bottomLeftX, double bottomLeftY, double bottomRightX, double bottomRightY)
76+
{
77+
this._topLeftX = topLeftX;
78+
this._topLeftY = topLeftY;
79+
this._topRightX = topRightX;
80+
this._topRightY = topRightY;
81+
this._bottomLeftX = bottomLeftX;
82+
this._bottomLeftY = bottomLeftY;
83+
this._bottomRightX = bottomRightX;
84+
this._bottomRightY = bottomRightY;
85+
}
86+
87+
public CornerRadiusEx(CornerRadius cornerRadius): this(cornerRadius.TopLeft, cornerRadius.TopLeft, cornerRadius.TopRight, cornerRadius.TopRight, cornerRadius.BottomLeft, cornerRadius.BottomLeft, cornerRadius.BottomRight, cornerRadius.BottomRight)
88+
{
89+
}
90+
91+
public CornerRadiusEx(double uniformRadius) : this(uniformRadius, uniformRadius, uniformRadius, uniformRadius, uniformRadius, uniformRadius, uniformRadius, uniformRadius)
92+
{
93+
}
94+
95+
public static implicit operator CornerRadiusEx(CornerRadius cornerRadius)
96+
{
97+
return new CornerRadiusEx(cornerRadius);
98+
}
99+
100+
public override string ToString()
101+
{
102+
return $"{TopLeftX} {TopLeftY}, {TopRightX} {TopRightY}, {BottomLeftX} {BottomLeftY},{BottomRightX} {BottomRightY}";
103+
}
104+
105+
/// <summary>
106+
/// Converts this CornerRadiusEx to regular WPF CornerRadius. When the values are different in X and Y axis, an average is used.
107+
/// </summary>
108+
public CornerRadius ToCornerRadius()
109+
{
110+
return new CornerRadius
111+
(
112+
(TopLeftX + TopLeftY) / 2,
113+
(TopRightX + TopRightY) / 2,
114+
(BottomRightX + BottomRightY) / 2,
115+
(BottomLeftX + BottomLeftY) / 2
116+
);
117+
}
118+
119+
/// <summary>
120+
/// Draws a rounded rectangle geometry with the specified rect and corner radius.
121+
/// </summary>
122+
public static StreamGeometry CreateRoundedRectangleGeometry(Rect rect, CornerRadiusEx radius)
123+
{
124+
var geometry = new StreamGeometry();
125+
126+
using (var context = geometry.Open())
127+
{
128+
// The AI did really a great job! Prompt as follows:
129+
// c# wpf,我有一个 rect 和 CornerRadiusEx(这个CornerRadiusEx包含 TopLeftX, TopLeftY...每个角都可以自定义 X 和 Y),
130+
// 现在请你编写一个方法,生成一个 StreamGeometry,其内容就是指定的 rect 加上这个圆角
131+
132+
context.BeginFigure(new Point(rect.Left + radius.TopLeftX, rect.Top), true, true);
133+
134+
// Top edge
135+
context.LineTo(new Point(rect.Right - radius.TopRightX, rect.Top), true, false);
136+
context.ArcTo(new Point(rect.Right, rect.Top + radius.TopRightY),
137+
new Size(radius.TopRightX, radius.TopRightY),
138+
0, false, SweepDirection.Clockwise, true, false);
139+
140+
// Right edge
141+
context.LineTo(new Point(rect.Right, rect.Bottom - radius.BottomRightY), true, false);
142+
context.ArcTo(new Point(rect.Right - radius.BottomRightX, rect.Bottom),
143+
new Size(radius.BottomRightX, radius.BottomRightY),
144+
0, false, SweepDirection.Clockwise, true, false);
145+
146+
// Bottom edge
147+
context.LineTo(new Point(rect.Left + radius.BottomLeftX, rect.Bottom), true, false);
148+
context.ArcTo(new Point(rect.Left, rect.Bottom - radius.BottomLeftY),
149+
new Size(radius.BottomLeftX, radius.BottomLeftY),
150+
0, false, SweepDirection.Clockwise, true, false);
151+
152+
// Left edge
153+
context.LineTo(new Point(rect.Left, rect.Top + radius.TopLeftY), true, false);
154+
context.ArcTo(new Point(rect.Left + radius.TopLeftX, rect.Top),
155+
new Size(radius.TopLeftX, radius.TopLeftY),
156+
0, false, SweepDirection.Clockwise, true, false);
157+
}
158+
159+
geometry.Freeze(); // 让几何体不可变,提高性能
160+
return geometry;
161+
}
162+
163+
public override bool Equals(object? obj)
164+
{
165+
if (obj is CornerRadiusEx other)
166+
{
167+
return Equals(other);
168+
}
169+
else
170+
{
171+
return false;
172+
}
173+
}
174+
175+
public bool Equals(CornerRadiusEx other)
176+
{
177+
return TopLeftX == other.TopLeftX && TopLeftY == other.TopLeftY &&
178+
TopRightX == other.TopRightX && TopRightY == other.TopRightY &&
179+
BottomLeftX == other.BottomLeftX && BottomLeftY == other.BottomLeftY &&
180+
BottomRightX == other.BottomRightX && BottomRightY == other.BottomRightY;
181+
}
182+
183+
public static bool operator == (CornerRadiusEx left, CornerRadiusEx right)
184+
{
185+
return left.Equals(right);
186+
}
187+
188+
public static bool operator != (CornerRadiusEx left, CornerRadiusEx right)
189+
{
190+
return !left.Equals(right);
191+
}
192+
193+
public override int GetHashCode()
194+
{
195+
return _topLeftX.GetHashCode() ^ _topLeftY.GetHashCode() ^ _topRightX.GetHashCode() ^ _topRightY.GetHashCode()
196+
^ _bottomLeftX.GetHashCode() ^ _bottomLeftY.GetHashCode() ^ _bottomRightX.GetHashCode() ^ _bottomRightY.GetHashCode();
197+
}
198+
199+
/// <summary>
200+
/// Scales every asix of every corner by the specified scale.
201+
/// </summary>
202+
/// <param name="scale"></param>
203+
public void Scale(double scale)
204+
{
205+
TopLeftX = TopLeftX * scale;
206+
TopLeftY = TopLeftY * scale;
207+
TopRightX = TopRightX * scale;
208+
TopRightY = TopRightY * scale;
209+
BottomLeftX = BottomLeftX * scale;
210+
BottomLeftY = BottomLeftY * scale;
211+
BottomRightX = BottomRightX * scale;
212+
BottomRightY = BottomRightY * scale;
213+
}
214+
}
215+
}

source/iNKORE.UI.WPF/Controls/ClippedBorder.cs

Lines changed: 0 additions & 73 deletions
This file was deleted.

0 commit comments

Comments
 (0)