Browse Source

Added RadioButton control.

pull/13/head
Steven Kirk 12 years ago
parent
commit
cf959fd8eb
  1. 6
      Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs
  2. 4
      Perspex.Controls/Image.cs
  3. 2
      Perspex.Controls/Perspex.Controls.csproj
  4. 7
      Perspex.Controls/Primitives/ToggleButton.cs
  5. 46
      Perspex.Controls/RadioButton.cs
  6. 38
      Perspex.Controls/Shapes/Ellipse.cs
  7. 59
      Perspex.SceneGraph/Media/EllipseGeometry.cs
  8. 5
      Perspex.SceneGraph/Media/StreamGeometryContext.cs
  9. 14
      Perspex.SceneGraph/Media/SweepDirection.cs
  10. 2
      Perspex.SceneGraph/Perspex.SceneGraph.csproj
  11. 3
      Perspex.SceneGraph/Platform/IStreamGeometryContextImpl.cs
  12. 10
      Perspex.SceneGraph/Rect.cs
  13. 1
      Perspex.Themes.Default/DefaultTheme.cs
  14. 1
      Perspex.Themes.Default/Perspex.Themes.Default.csproj
  15. 97
      Perspex.Themes.Default/RadioButtonStyle.cs
  16. 9
      TestApplication/Program.cs
  17. BIN
      TestFiles/Direct2D1/Shapes/Ellipse/Circle_1px_Stroke.expected.png
  18. 1
      Windows/Perspex.Direct2D1.RenderTests/Perspex.Direct2D1.RenderTests.csproj
  19. 41
      Windows/Perspex.Direct2D1.RenderTests/Shapes/EllipseTests.cs
  20. 17
      Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs
  21. 5
      Windows/Perspex.Direct2D1/PrimitiveExtensions.cs

6
Cairo/Perspex.Cairo/Media/StreamGeometryContextImpl.cs

@ -6,6 +6,7 @@
namespace Perspex.Cairo.Media
{
using Perspex.Media;
using Perspex.Platform;
public class StreamGeometryContextImpl : IStreamGeometryContextImpl
@ -15,6 +16,11 @@ namespace Perspex.Cairo.Media
// TODO: Implement
}
public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection)
{
// TODO: Implement
}
public void BeginFigure(Point startPoint, bool isFilled)
{
// TODO: Implement

4
Perspex.Controls/Image.cs

@ -47,10 +47,10 @@ namespace Perspex.Controls
Vector scale = CalculateScaling(this.ActualSize, sourceSize, this.Stretch);
Size scaledSize = sourceSize * scale;
Rect destRect = viewPort
.Center(new Rect(scaledSize))
.CenterIn(new Rect(scaledSize))
.Intersect(viewPort);
Rect sourceRect = new Rect(sourceSize)
.Center(new Rect(destRect.Size / scale));
.CenterIn(new Rect(destRect.Size / scale));
drawingContext.DrawImage(source, 1, sourceRect, destRect);
}

2
Perspex.Controls/Perspex.Controls.csproj

@ -36,6 +36,7 @@
<ItemGroup>
<Compile Include="Border.cs" />
<Compile Include="Button.cs" />
<Compile Include="RadioButton.cs" />
<Compile Include="CheckBox.cs" />
<Compile Include="ColumnDefinition.cs" />
<Compile Include="ColumnDefinitions.cs" />
@ -75,6 +76,7 @@
<Compile Include="Primitives\Track.cs" />
<Compile Include="Primitives\Thumb.cs" />
<Compile Include="RequestBringIntoViewEventArgs.cs" />
<Compile Include="Shapes\Ellipse.cs" />
<Compile Include="TextWrapping.cs" />
<Compile Include="Utils\StringUtils.cs" />
<Compile Include="Window.cs" />

7
Perspex.Controls/Primitives/ToggleButton.cs

@ -20,7 +20,7 @@ namespace Perspex.Controls.Primitives
public ToggleButton()
{
this.Click += (s, e) => this.IsChecked = !this.IsChecked;
this.Click += (s, e) => this.Toggle();
}
public bool IsChecked
@ -28,5 +28,10 @@ namespace Perspex.Controls.Primitives
get { return this.GetValue(IsCheckedProperty); }
set { this.SetValue(IsCheckedProperty, value); }
}
protected virtual void Toggle()
{
this.IsChecked = !this.IsChecked;
}
}
}

46
Perspex.Controls/RadioButton.cs

@ -0,0 +1,46 @@
// -----------------------------------------------------------------------
// <copyright file="RadioButton.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Controls
{
using System;
using System.Linq;
using Perspex.Controls.Primitives;
public class RadioButton : ToggleButton
{
public RadioButton()
{
this.GetObservable(IsCheckedProperty).Subscribe(this.IsCheckedChanged);
}
protected override void Toggle()
{
if (!this.IsChecked)
{
this.IsChecked = true;
}
}
private void IsCheckedChanged(bool value)
{
var parent = this.GetVisualParent();
if (value && parent != null)
{
var siblings = parent
.GetVisualChildren()
.OfType<RadioButton>()
.Where(x => x != this);
foreach (var sibling in siblings)
{
sibling.IsChecked = false;
}
}
}
}
}

38
Perspex.Controls/Shapes/Ellipse.cs

@ -0,0 +1,38 @@
// -----------------------------------------------------------------------
// <copyright file="Rectangle.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Controls.Shapes
{
using Perspex.Media;
public class Ellipse : Shape
{
private Geometry geometry;
private Size geometrySize;
public override Geometry DefiningGeometry
{
get
{
if (this.geometry == null || this.geometrySize != this.ActualSize)
{
var rect = new Rect(0, 0, this.ActualSize.Width, this.ActualSize.Height);
rect = rect.Deflate(this.StrokeThickness / 2);
this.geometry = new EllipseGeometry(rect);
this.geometrySize = this.ActualSize;
}
return this.geometry;
}
}
protected override Size MeasureOverride(Size availableSize)
{
return new Size(this.StrokeThickness, this.StrokeThickness);
}
}
}

59
Perspex.SceneGraph/Media/EllipseGeometry.cs

@ -0,0 +1,59 @@
// -----------------------------------------------------------------------
// <copyright file="EllipseGeometry.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Media
{
using System;
using Perspex.Platform;
using Splat;
public class EllipseGeometry : Geometry
{
public EllipseGeometry(Rect rect)
{
IPlatformRenderInterface factory = Locator.Current.GetService<IPlatformRenderInterface>();
IStreamGeometryImpl impl = factory.CreateStreamGeometry();
using (IStreamGeometryContextImpl ctx = impl.Open())
{
double ControlPointRatio = (Math.Sqrt(2) - 1) * 4 / 3;
var center = rect.Center;
var radius = new Vector(rect.Width / 2, rect.Height / 2);
var x0 = center.X - radius.X;
var x1 = center.X - radius.X * ControlPointRatio;
var x2 = center.X;
var x3 = center.X + radius.X * ControlPointRatio;
var x4 = center.X + radius.X;
var y0 = center.Y - radius.Y;
var y1 = center.Y - radius.Y * ControlPointRatio;
var y2 = center.Y;
var y3 = center.Y + radius.Y * ControlPointRatio;
var y4 = center.Y + radius.Y;
ctx.BeginFigure(new Point(x2, y0), true);
ctx.BezierTo(new Point(x3, y0), new Point(x4, y1), new Point(x4, y2));
ctx.BezierTo(new Point(x4, y3), new Point(x3, y4), new Point(x2, y4));
ctx.BezierTo(new Point(x1, y4), new Point(x0, y3), new Point(x0, y2));
ctx.BezierTo(new Point(x0, y1), new Point(x1, y0), new Point(x2, y0));
ctx.EndFigure(true);
}
this.PlatformImpl = impl;
}
public override Rect Bounds
{
get { return this.PlatformImpl.Bounds; }
}
public override Geometry Clone()
{
return new EllipseGeometry(this.Bounds);
}
}
}

5
Perspex.SceneGraph/Media/StreamGeometryContext.cs

@ -18,6 +18,11 @@ namespace Perspex.Media
this.impl = impl;
}
public void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection)
{
this.impl.ArcTo(point, size, rotationAngle, isLargeArc, sweepDirection);
}
public void BeginFigure(Point startPoint, bool isFilled)
{
this.impl.BeginFigure(startPoint, isFilled);

14
Perspex.SceneGraph/Media/SweepDirection.cs

@ -0,0 +1,14 @@
// -----------------------------------------------------------------------
// <copyright file="StreamGeometryContextImpl.cs" company="Steven Kirk">
// Copyright 2013 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Media
{
public enum SweepDirection
{
CounterClockwise,
Clockwise,
}
}

2
Perspex.SceneGraph/Perspex.SceneGraph.csproj

@ -58,6 +58,7 @@
<Compile Include="Media\ITransform.cs" />
<Compile Include="Media\PathMarkupParser.cs" />
<Compile Include="Media\Pen.cs" />
<Compile Include="Media\EllipseGeometry.cs" />
<Compile Include="Media\RectangleGeometry.cs" />
<Compile Include="Media\MatrixTransform.cs" />
<Compile Include="Media\RotateTransform.cs" />
@ -65,6 +66,7 @@
<Compile Include="Media\StreamGeometry.cs" />
<Compile Include="Media\StreamGeometryContext.cs" />
<Compile Include="Media\Stretch.cs" />
<Compile Include="Media\SweepDirection.cs" />
<Compile Include="Media\TextHitTestResult.cs" />
<Compile Include="Media\Transform.cs" />
<Compile Include="Origin.cs" />

3
Perspex.SceneGraph/Platform/IStreamGeometryContextImpl.cs

@ -7,9 +7,12 @@
namespace Perspex.Platform
{
using System;
using Perspex.Media;
public interface IStreamGeometryContextImpl : IDisposable
{
void ArcTo(Point point, Size size, double rotationAngle, bool isLargeArc, SweepDirection sweepDirection);
void BeginFigure(Point startPoint, bool isFilled);
void BezierTo(Point point1, Point point2, Point point3);

10
Perspex.SceneGraph/Rect.cs

@ -183,6 +183,14 @@ namespace Perspex
get { return new Point(this.Right, this.Bottom); }
}
/// <summary>
/// Gets the center point of the rectangle.
/// </summary>
public Point Center
{
get { return new Point(this.x + (this.width / 2), this.y + (this.height / 2)); }
}
/// <summary>
/// Gets a value that indicates whether the rectangle is empty.
/// </summary>
@ -255,7 +263,7 @@ namespace Perspex
p.Y >= this.y && p.Y < this.y + this.height;
}
public Rect Center(Rect rect)
public Rect CenterIn(Rect rect)
{
return new Rect(
this.x + ((this.width - rect.width) / 2),

1
Perspex.Themes.Default/DefaultTheme.cs

@ -19,6 +19,7 @@ namespace Perspex.Themes.Default
this.Add(new ItemsControlStyle());
this.Add(new ListBoxStyle());
this.Add(new ListBoxItemStyle());
this.Add(new RadioButtonStyle());
this.Add(new ScrollBarStyle());
this.Add(new ScrollViewerStyle());
this.Add(new TabControlStyle());

1
Perspex.Themes.Default/Perspex.Themes.Default.csproj

@ -66,6 +66,7 @@
</ProjectReference>
</ItemGroup>
<ItemGroup>
<Compile Include="RadioButtonStyle.cs" />
<Compile Include="ToggleButtonStyle.cs" />
<Compile Include="ListBoxStyle.cs" />
<Compile Include="ListBoxItemStyle.cs" />

97
Perspex.Themes.Default/RadioButtonStyle.cs

@ -0,0 +1,97 @@
// -----------------------------------------------------------------------
// <copyright file="RadioButtonStyle.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Themes.Default
{
using System;
using System.Linq;
using Perspex.Controls;
using Perspex.Layout;
using Perspex.Media;
using Perspex.Controls.Shapes;
using Perspex.Styling;
using Perspex.Controls.Presenters;
public class RadioButtonStyle : Styles
{
public RadioButtonStyle()
{
this.AddRange(new[]
{
new Style(x => x.OfType<RadioButton>())
{
Setters = new[]
{
new Setter(Button.TemplateProperty, ControlTemplate.Create<RadioButton>(this.Template)),
},
},
new Style(x => x.OfType<RadioButton>().Template().Id("checkMark"))
{
Setters = new[]
{
new Setter(Shape.IsVisibleProperty, false),
},
},
new Style(x => x.OfType<RadioButton>().Class(":checked").Template().Id("checkMark"))
{
Setters = new[]
{
new Setter(Shape.IsVisibleProperty, true),
},
},
});
}
private Control Template(RadioButton control)
{
Border result = new Border
{
[~Border.BackgroundProperty] = control[~RadioButton.BackgroundProperty],
Content = new Grid
{
ColumnDefinitions = new ColumnDefinitions
{
new ColumnDefinition(GridLength.Auto),
new ColumnDefinition(new GridLength(1, GridUnitType.Star)),
},
Children = new Controls
{
new Ellipse
{
Id = "checkBorder",
Stroke = Brushes.Black,
StrokeThickness = 2,
Width = 18,
Height = 18,
VerticalAlignment = VerticalAlignment.Center,
[Grid.ColumnProperty] = 0,
},
new Ellipse
{
Id = "checkMark",
Fill = Brushes.Black,
Width = 10,
Height = 10,
Stretch = Stretch.Uniform,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
[Grid.ColumnProperty] = 0,
},
new ContentPresenter
{
Margin = new Thickness(4, 0, 0, 0),
VerticalAlignment = VerticalAlignment.Center,
[~ContentPresenter.ContentProperty] = control[~RadioButton.ContentProperty],
[Grid.ColumnProperty] = 1,
},
},
},
};
return result;
}
}
}

9
TestApplication/Program.cs

@ -198,6 +198,15 @@ namespace TestApplication
{
Content = "Checkbox",
},
new RadioButton
{
Content = "RadioButton 1",
IsChecked = true,
},
new RadioButton
{
Content = "RadioButton 2",
},
}
},
};

BIN
TestFiles/Direct2D1/Shapes/Ellipse/Circle_1px_Stroke.expected.png

Binary file not shown.

After

Width:  |  Height:  |  Size: 3.2 KiB

1
Windows/Perspex.Direct2D1.RenderTests/Perspex.Direct2D1.RenderTests.csproj

@ -62,6 +62,7 @@
<Compile Include="Controls\ImageTests.cs" />
<Compile Include="Controls\BorderTests.cs" />
<Compile Include="Shapes\PathTests.cs" />
<Compile Include="Shapes\EllipseTests.cs" />
<Compile Include="Shapes\RectangleTests.cs" />
<Compile Include="TestBase.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />

41
Windows/Perspex.Direct2D1.RenderTests/Shapes/EllipseTests.cs

@ -0,0 +1,41 @@
// -----------------------------------------------------------------------
// <copyright file="EllipseTests.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Direct2D1.RenderTests.Shapes
{
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Perspex.Controls;
using Perspex.Media;
using Perspex.Controls.Shapes;
[TestClass]
public class EllipseTests : TestBase
{
public EllipseTests()
: base(@"Shapes\Ellipse")
{
}
[TestMethod]
public void Circle_1px_Stroke()
{
Decorator target = new Decorator
{
Padding = new Thickness(8),
Width = 200,
Height = 200,
Content = new Ellipse
{
Stroke = Brushes.Black,
StrokeThickness = 1,
}
};
this.RenderToFile(target);
this.CompareImages();
}
}
}

17
Windows/Perspex.Direct2D1/Media/StreamGeometryContextImpl.cs

@ -18,6 +18,23 @@ namespace Perspex.Direct2D1.Media
this.sink = sink;
}
public void ArcTo(
Point point,
Size size,
double rotationAngle,
bool isLargeArc,
Perspex.Media.SweepDirection sweepDirection)
{
this.sink.AddArc(new ArcSegment
{
Point = point.ToSharpDX(),
Size = size.ToSharpDX(),
RotationAngle = (float)rotationAngle,
ArcSize = isLargeArc ? ArcSize.Large : ArcSize.Small,
SweepDirection = (SweepDirection)sweepDirection,
});
}
public void BeginFigure(Point startPoint, bool isFilled)
{
this.sink.BeginFigure(startPoint.ToSharpDX(), isFilled ? FigureBegin.Filled : FigureBegin.Hollow);

5
Windows/Perspex.Direct2D1/PrimitiveExtensions.cs

@ -26,6 +26,11 @@ namespace Perspex.Direct2D1
return new Vector2((float)p.X, (float)p.Y);
}
public static Size2F ToSharpDX(this Perspex.Size p)
{
return new Size2F((float)p.Width, (float)p.Height);
}
/// <summary>
/// Converts a brush to Direct2D.
/// </summary>

Loading…
Cancel
Save