2
using System.Collections.Generic;
9
public class ReliefFrame : Canvas
11
// http://graphics.stanford.edu/courses/cs248-98-fall/Final/q1.html
12
const double ArcToBezier = 0.55228475;
13
double padding = 12.0;
14
double? radius = null;
19
bgcolor = base.BackgroundColor;
22
public ReliefFrame (Widget content)
28
public new Color BackgroundColor
30
get { return bgcolor; }
38
public new Widget Content
40
get { return Children.SingleOrDefault (); }
44
RemoveChild (Content);
50
public double? CornerRadius
52
get { return radius; }
65
get { return padding; }
72
OnPreferredSizeChanged ();
76
protected override WidgetSize OnGetPreferredHeight ()
78
return Content.Surface.GetPreferredHeight () + (2 * padding);
81
protected override WidgetSize OnGetPreferredWidth ()
83
return Content.Surface.GetPreferredWidth () + (2 * padding);
86
protected override WidgetSize OnGetPreferredHeightForWidth (double width)
88
return Content.Surface.GetPreferredHeightForWidth (Math.Max (width - (2 * padding), 0)) + (2 * padding);
91
protected override WidgetSize OnGetPreferredWidthForHeight (double height)
93
return Content.Surface.GetPreferredWidthForHeight (Math.Max (height - (2 * padding), 0)) + (2 * padding);
96
protected override void OnReallocate ()
102
void UpdateChildBounds ()
104
SetChildBounds (Content, new Rectangle (padding, padding, Math.Max (Size.Width - (2 * padding), 0), Math.Max (Size.Height - (2 * padding), 0)));
107
static void DrawBorder (Context ctx, double x, double y, double w, double h, double radius)
111
// test limits (without using multiplication)
112
if (radius > w - radius)
114
if (radius > h - radius)
117
// approximate (quite close) the arc using a bezier curve
118
double arc = ArcToBezier * radius;
121
ctx.MoveTo (x + radius, y);
124
ctx.LineTo (x + w - radius, y);
127
ctx.CurveTo (x + w - radius + arc, y, x + w, y + arc, x + w, y + radius);
130
ctx.LineTo (x + w, y + h - radius);
132
// bottom-right corner
133
ctx.CurveTo (x + w, y + h - radius + arc, x + w + arc - radius, y + h, x + w - radius, y + h);
136
ctx.LineTo (x + radius, y + h);
138
// bottom-left corner
139
ctx.CurveTo (x + radius - arc, y + h, x, y + h - arc, x, y + h - radius);
142
ctx.LineTo (x, y + radius);
145
ctx.CurveTo (x, y + radius - arc, x + radius - arc, y, x + radius, y);
148
static Color GetColor (Color color, double percent)
150
return new Color (color.Red * percent, color.Green * percent, color.Blue * percent);
153
RadialGradient GetCornerGradient (double x, double y, double radius, double thickness)
155
var gradient = new RadialGradient (x, y, radius - thickness, x, y, radius + thickness);
156
gradient.AddColorStop (0, BackgroundColor);
157
gradient.AddColorStop (1, GetColor (BackgroundColor, 0.75));
161
LinearGradient GetBottomEdgeGradient (double bottom, double thickness)
163
var gradient = new LinearGradient (0, bottom - thickness, 0, bottom + thickness);
164
gradient.AddColorStop (0, BackgroundColor);
165
gradient.AddColorStop (1, GetColor (BackgroundColor, 0.75));
169
LinearGradient GetTopEdgeGradient (double top, double thickness)
171
var gradient = new LinearGradient (0, top - thickness, 0, top + thickness);
172
gradient.AddColorStop (0, GetColor (BackgroundColor, 0.75));
173
gradient.AddColorStop (1, BackgroundColor);
177
LinearGradient GetRightEdgeGradient (double right, double thickness)
179
var gradient = new LinearGradient (right - thickness, 0, right + thickness, 0);
180
gradient.AddColorStop (0, BackgroundColor);
181
gradient.AddColorStop (1, GetColor (BackgroundColor, 0.75));
185
LinearGradient GetLeftEdgeGradient (double left, double thickness)
187
var gradient = new LinearGradient (left - thickness, 0, left + thickness, 0);
188
gradient.AddColorStop (0, GetColor (BackgroundColor, 0.75));
189
gradient.AddColorStop (1, BackgroundColor);
193
void DrawBorder (Context ctx, double x, double y, double w, double h, double radius, double thickness)
195
// test limits (without using multiplication)
196
if (radius > w - radius)
198
if (radius > h - radius)
201
// approximate (quite close) the arc using a bezier curve
202
double arc = ArcToBezier * radius;
204
ctx.SetLineWidth (thickness);
208
ctx.MoveTo (x, y + radius);
209
ctx.CurveTo (x, y + radius - arc, x + radius - arc, y, x + radius, y);
210
ctx.Pattern = GetCornerGradient (x + radius, y + radius, radius, thickness / 2);
215
ctx.MoveTo (x + radius - 0.5, y);
216
ctx.LineTo (x + w - radius + 0.5, y);
217
ctx.Pattern = GetTopEdgeGradient (y, thickness / 2);
222
ctx.MoveTo (x + w - radius, y);
223
ctx.CurveTo (x + w - radius + arc, y, x + w, y + arc, x + w, y + radius);
224
ctx.Pattern = GetCornerGradient (x + w - radius, y + radius, radius, thickness / 2);
229
ctx.MoveTo (x + w, y + radius - 0.5);
230
ctx.LineTo (x + w, y + h - radius + 0.5);
231
ctx.Pattern = GetRightEdgeGradient (x + w, thickness / 2);
234
// bottom-right corner
236
ctx.MoveTo (x + w, y + h - radius);
237
ctx.CurveTo (x + w, y + h - radius + arc, x + w + arc - radius, y + h, x + w - radius, y + h);
238
ctx.Pattern = GetCornerGradient (x + w - radius, y + h - radius, radius, thickness / 2);
243
ctx.MoveTo (x + w - radius + 0.5, y + h);
244
ctx.LineTo (x + radius - 0.5, y + h);
245
ctx.Pattern = GetBottomEdgeGradient (y + h, thickness / 2);
248
// bottom-left corner
250
ctx.MoveTo (x + radius, y + h);
251
ctx.CurveTo (x + radius - arc, y + h, x, y + h - arc, x, y + h - radius);
252
ctx.Pattern = GetCornerGradient (x + radius, y + h - radius, radius, thickness / 2);
257
ctx.MoveTo (x, y + h - radius + 0.5);
258
ctx.LineTo (x, y + radius - 0.5);
259
ctx.Pattern = GetLeftEdgeGradient (x, thickness / 2);
263
protected override void OnDraw (Context ctx, Rectangle dirtyRect)
265
double radius = CornerRadius ?? Math.Min (Size.Width, Size.Height) / 6.4;
266
double h = Size.Height - 1.0;
267
double w = Size.Width - 1.0;
274
DrawBorder (ctx, x, y, w, h, radius);
275
ctx.SetColor (BackgroundColor);
282
DrawBorder (ctx, x, y, w, h, radius, 6);