Browse Source

Added (VERY!) basic checkbox

pull/4/head
Steven Kirk 12 years ago
parent
commit
c1a0931445
  1. 17
      Perspex.Windows/DrawingContext.cs
  2. 26
      Perspex/Controls/Border.cs
  3. 12
      Perspex/Controls/CheckBox.cs
  4. 19
      Perspex/Controls/ContentControl.cs
  5. 19
      Perspex/Controls/ContentPresenter.cs
  6. 19
      Perspex/Controls/Decorator.cs
  7. 77
      Perspex/Controls/StackPanel.cs
  8. 34
      Perspex/Controls/TextBlock.cs
  9. 39
      Perspex/Controls/ToggleButton.cs
  10. 3
      Perspex/Perspex.csproj
  11. 2
      Perspex/Styling/Selectors.cs
  12. 16
      Perspex/Themes/Default/ButtonStyle.cs
  13. 80
      Perspex/Themes/Default/CheckBoxStyle.cs
  14. 1
      Perspex/Themes/Default/DefaultTheme.cs
  15. 42
      Perspex/Visual.cs
  16. 6
      TestApplication/Program.cs

17
Perspex.Windows/DrawingContext.cs

@ -75,14 +75,17 @@ namespace Perspex.Windows
/// <param name="text">The text.</param>
public void DrawText(Perspex.Media.Brush foreground, Rect rect, FormattedText text)
{
using (SharpDX.Direct2D1.SolidColorBrush brush = this.Convert(foreground))
using (SharpDX.DirectWrite.TextFormat format = TextService.Convert(this.directWriteFactory, text))
if (!string.IsNullOrEmpty(text.Text))
{
this.renderTarget.DrawText(
text.Text,
format,
this.Convert(rect),
brush);
using (SharpDX.Direct2D1.SolidColorBrush brush = this.Convert(foreground))
using (SharpDX.DirectWrite.TextFormat format = TextService.Convert(this.directWriteFactory, text))
{
this.renderTarget.DrawText(
text.Text,
format,
this.Convert(rect),
brush);
}
}
}

26
Perspex/Controls/Border.cs

@ -14,27 +14,29 @@ namespace Perspex.Controls
{
public Border()
{
// Hacky hack hack!
Observable.Merge(
this.GetObservable(BackgroundProperty),
this.GetObservable(BorderBrushProperty))
.Subscribe(_ => this.InvalidateArrange());
.Subscribe(_ => this.InvalidateVisual());
}
public override void Render(IDrawingContext context)
{
Brush background = this.Background;
Brush borderBrush = this.BorderBrush;
double borderThickness = this.BorderThickness;
if (background != null)
if (this.Visibility == Visibility.Visible)
{
context.FillRectange(background, new Rect(this.Bounds.Size));
}
Brush background = this.Background;
Brush borderBrush = this.BorderBrush;
double borderThickness = this.BorderThickness;
if (borderBrush != null && borderThickness > 0)
{
context.DrawRectange(new Pen(borderBrush, borderThickness), new Rect(this.Bounds.Size));
if (background != null)
{
context.FillRectange(background, new Rect(this.Bounds.Size));
}
if (borderBrush != null && borderThickness > 0)
{
context.DrawRectange(new Pen(borderBrush, borderThickness), new Rect(this.Bounds.Size));
}
}
}
}

12
Perspex/Controls/CheckBox.cs

@ -0,0 +1,12 @@
// -----------------------------------------------------------------------
// <copyright file="CheckBox.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Controls
{
public class CheckBox : ToggleButton
{
}
}

19
Perspex/Controls/ContentControl.cs

@ -65,17 +65,18 @@ namespace Perspex.Controls
protected override Size MeasureContent(Size availableSize)
{
Control child = ((IVisual)this).VisualChildren.SingleOrDefault() as Control;
if (child != null)
{
child.Measure(availableSize);
return child.DesiredSize.Value;
}
else
if (this.Visibility != Visibility.Collapsed)
{
return new Size();
Control child = ((IVisual)this).VisualChildren.SingleOrDefault() as Control;
if (child != null)
{
child.Measure(availableSize);
return child.DesiredSize.Value;
}
}
return new Size();
}
}
}

19
Perspex/Controls/ContentPresenter.cs

@ -145,17 +145,18 @@ namespace Perspex.Controls
protected override Size MeasureContent(Size availableSize)
{
Control child = ((IVisual)this).VisualChildren.SingleOrDefault() as Control;
if (child != null)
{
child.Measure(availableSize);
return child.DesiredSize.Value;
}
else
if (this.Visibility != Visibility.Collapsed)
{
return new Size();
Control child = ((IVisual)this).VisualChildren.SingleOrDefault() as Control;
if (child != null)
{
child.Measure(availableSize);
return child.DesiredSize.Value;
}
}
return new Size();
}
}
}

19
Perspex/Controls/Decorator.cs

@ -77,17 +77,18 @@ namespace Perspex.Controls
protected override Size MeasureContent(Size availableSize)
{
Control content = this.Content;
if (content != null)
{
content.Measure(availableSize);
return content.DesiredSize.Value.Inflate(this.Padding);
}
else
if (this.Visibility != Visibility.Collapsed)
{
return new Size();
Control content = this.Content;
if (content != null)
{
content.Measure(availableSize);
return content.DesiredSize.Value.Inflate(this.Padding);
}
}
return new Size();
}
}
}

77
Perspex/Controls/StackPanel.cs

@ -40,56 +40,61 @@ namespace Perspex.Controls
protected override Size MeasureContent(Size availableSize)
{
double childAvailableWidth = double.PositiveInfinity;
double childAvailableHeight = double.PositiveInfinity;
if (this.Orientation == Orientation.Vertical)
if (this.Visibility != Visibility.Collapsed)
{
childAvailableWidth = availableSize.Width;
double childAvailableWidth = double.PositiveInfinity;
double childAvailableHeight = double.PositiveInfinity;
if (!double.IsNaN(this.Width))
if (this.Orientation == Orientation.Vertical)
{
childAvailableWidth = this.Width;
}
childAvailableWidth = availableSize.Width;
childAvailableWidth = Math.Min(childAvailableWidth, this.MaxWidth);
childAvailableWidth = Math.Max(childAvailableWidth, this.MinWidth);
}
else
{
childAvailableHeight = availableSize.Height;
if (!double.IsNaN(this.Width))
{
childAvailableWidth = this.Width;
}
if (!double.IsNaN(this.Height))
{
childAvailableHeight = this.Height;
childAvailableWidth = Math.Min(childAvailableWidth, this.MaxWidth);
childAvailableWidth = Math.Max(childAvailableWidth, this.MinWidth);
}
else
{
childAvailableHeight = availableSize.Height;
childAvailableHeight = Math.Min(childAvailableHeight, this.MaxHeight);
childAvailableHeight = Math.Max(childAvailableHeight, this.MinHeight);
}
if (!double.IsNaN(this.Height))
{
childAvailableHeight = this.Height;
}
double measuredWidth = 0;
double measuredHeight = 0;
double gap = this.Gap;
childAvailableHeight = Math.Min(childAvailableHeight, this.MaxHeight);
childAvailableHeight = Math.Max(childAvailableHeight, this.MinHeight);
}
foreach (Control child in this.Children)
{
child.Measure(new Size(childAvailableWidth, childAvailableHeight));
Size size = child.DesiredSize.Value;
double measuredWidth = 0;
double measuredHeight = 0;
double gap = this.Gap;
if (Orientation == Orientation.Vertical)
{
measuredHeight += size.Height + gap;
measuredWidth = Math.Max(measuredWidth, size.Width);
}
else
foreach (Control child in this.Children)
{
measuredWidth += size.Width + gap;
measuredHeight = Math.Max(measuredHeight, size.Height);
child.Measure(new Size(childAvailableWidth, childAvailableHeight));
Size size = child.DesiredSize.Value;
if (Orientation == Orientation.Vertical)
{
measuredHeight += size.Height + gap;
measuredWidth = Math.Max(measuredWidth, size.Width);
}
else
{
measuredWidth += size.Width + gap;
measuredHeight = Math.Max(measuredHeight, size.Height);
}
}
return new Size(measuredWidth, measuredHeight);
}
return new Size(measuredWidth, measuredHeight);
return new Size();
}
protected override Size ArrangeContent(Size finalSize)

34
Perspex/Controls/TextBlock.cs

@ -6,6 +6,7 @@
namespace Perspex.Controls
{
using System;
using Perspex.Media;
using Splat;
@ -20,6 +21,11 @@ namespace Perspex.Controls
public static readonly PerspexProperty<string> TextProperty =
PerspexProperty.Register<Border, string>("Text");
public TextBlock()
{
this.GetObservable(TextProperty).Subscribe(_ => this.InvalidateVisual());
}
public double FontSize
{
get { return this.GetValue(FontSizeProperty); }
@ -47,20 +53,32 @@ namespace Perspex.Controls
public override void Render(IDrawingContext context)
{
Brush background = this.Background;
if (background != null)
if (this.Visibility == Visibility.Visible)
{
context.FillRectange(background, this.Bounds);
}
Brush background = this.Background;
if (background != null)
{
context.FillRectange(background, this.Bounds);
}
context.DrawText(this.Foreground, new Rect(this.Bounds.Size), this.FormattedText);
context.DrawText(this.Foreground, new Rect(this.Bounds.Size), this.FormattedText);
}
}
protected override Size MeasureContent(Size availableSize)
{
ITextService service = Locator.Current.GetService<ITextService>();
return service.Measure(this.FormattedText);
if (this.Visibility != Visibility.Collapsed)
{
ITextService service = Locator.Current.GetService<ITextService>();
if (!string.IsNullOrEmpty(this.Text))
{
return service.Measure(this.FormattedText);
}
}
return new Size();
}
}
}

39
Perspex/Controls/ToggleButton.cs

@ -0,0 +1,39 @@
// -----------------------------------------------------------------------
// <copyright file="ToggleButton.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Controls
{
using System;
public class ToggleButton : Button
{
public static readonly PerspexProperty<bool> IsCheckedProperty =
PerspexProperty.Register<ToggleButton, bool>("IsChecked");
public ToggleButton()
{
this.Click += (s, e) => this.IsChecked = !this.IsChecked;
this.GetObservable(IsCheckedProperty).Subscribe(x =>
{
if (x)
{
this.Classes.Add(":checked");
}
else
{
this.Classes.Remove(":checked");
}
});
}
public bool IsChecked
{
get { return this.GetValue(IsCheckedProperty); }
set { this.SetValue(IsCheckedProperty, value); }
}
}
}

3
Perspex/Perspex.csproj

@ -70,6 +70,8 @@
<ItemGroup>
<Compile Include="Application.cs" />
<Compile Include="BindingExtensions.cs" />
<Compile Include="Controls\CheckBox.cs" />
<Compile Include="Controls\ToggleButton.cs" />
<Compile Include="Controls\LogicalChildren.cs" />
<Compile Include="Controls\Panel.cs" />
<Compile Include="Controls\StackPanel.cs" />
@ -131,6 +133,7 @@
<Compile Include="Controls\TemplatedControl.cs" />
<Compile Include="Styling\Style.cs" />
<Compile Include="Styling\Styles.cs" />
<Compile Include="Themes\Default\CheckBoxStyle.cs" />
<Compile Include="Themes\Default\ButtonStyle.cs" />
<Compile Include="Themes\Default\DefaultTheme.cs" />
<Compile Include="Thickness.cs" />

2
Perspex/Styling/Selectors.cs

@ -71,7 +71,7 @@ namespace Perspex.Styling
return new Selector(previous)
{
GetObservable = control => Observable.Return(control is T),
GetObservable = control => Observable.Return(control.GetType() == typeof(T)),
SelectorString = typeof(T).Name,
};
}

16
Perspex/Themes/Default/ButtonStyle.cs

@ -61,15 +61,15 @@ namespace Perspex.Themes.Default
private Control Template(Button control)
{
Border border = new Border();
border.Id = "border";
border.Padding = new Thickness(3);
border.TemplateBinding(control, Border.BackgroundProperty);
ContentPresenter contentPresenter = new ContentPresenter();
contentPresenter.TemplateBinding(control, ContentPresenter.ContentProperty);
Border border = new Border
{
Id = "border",
Padding = new Thickness(3),
Content = new ContentPresenter(),
};
border.Content = contentPresenter;
border.TemplateBinding(control, Border.BackgroundProperty);
border.Content.TemplateBinding(control, ContentPresenter.ContentProperty);
return border;
}
}

80
Perspex/Themes/Default/CheckBoxStyle.cs

@ -0,0 +1,80 @@
// -----------------------------------------------------------------------
// <copyright file="ButtonStyle.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Themes.Default
{
using System.Linq;
using Perspex.Controls;
using Perspex.Media;
using Perspex.Styling;
public class CheckBoxStyle : Styles
{
public CheckBoxStyle()
{
this.AddRange(new[]
{
new Style(x => x.OfType<CheckBox>())
{
Setters = new[]
{
new Setter(Button.TemplateProperty, ControlTemplate.Create<CheckBox>(this.Template)),
},
},
new Style(x => x.OfType<CheckBox>().Template().Id("checkMark"))
{
Setters = new[]
{
new Setter(TextBlock.VisibilityProperty, Visibility.Hidden),
},
},
new Style(x => x.OfType<CheckBox>().Class(":checked").Template().Id("checkMark"))
{
Setters = new[]
{
new Setter(TextBlock.VisibilityProperty, Visibility.Visible),
},
},
});
}
private Control Template(CheckBox control)
{
Border result = new Border
{
Content = new StackPanel
{
Orientation = Orientation.Horizontal,
Gap = 8,
Children = new PerspexList<Control>
{
new Border
{
BorderThickness = 2.0,
BorderBrush = new SolidColorBrush(0xff000000),
Padding = new Thickness(2),
Content = new TextBlock
{
Id = "checkMark",
Text = "Y",
Background = null,
},
},
new ContentPresenter
{
},
},
},
};
result.TemplateBinding(control, Border.BackgroundProperty);
StackPanel stack = (StackPanel)result.Content;
ContentPresenter cp = (ContentPresenter)stack.Children[1];
cp.TemplateBinding(control, ContentPresenter.ContentProperty);
return result;
}
}
}

1
Perspex/Themes/Default/DefaultTheme.cs

@ -13,6 +13,7 @@ namespace Perspex.Themes.Default
public DefaultTheme()
{
this.Add(new ButtonStyle());
this.Add(new CheckBoxStyle());
}
}
}

42
Perspex/Visual.cs

@ -14,16 +14,37 @@ namespace Perspex
using Perspex.Media;
using Splat;
public enum Visibility
{
Visible,
Hidden,
Collapsed,
}
public abstract class Visual : PerspexObject, IVisual
{
public static readonly PerspexProperty<Visibility> VisibilityProperty =
PerspexProperty.Register<Visual, Visibility>("Visibility");
private IVisual visualParent;
public Visual()
{
this.GetObservable(VisibilityProperty).Subscribe(_ => this.InvalidateVisual());
}
public Rect Bounds
{
get;
protected set;
}
public Visibility Visibility
{
get { return this.GetValue(VisibilityProperty); }
set { this.SetValue(VisibilityProperty, value); }
}
IEnumerable<IVisual> IVisual.ExistingVisualChildren
{
get { return ((IVisual)this).VisualChildren; }
@ -52,17 +73,23 @@ namespace Perspex
if (this.GetVisualAncestor<ILayoutRoot>() != null)
{
this.Log().Debug(string.Format(
"Attached {0} (#{1:x8}) to visual tree",
this.GetType().Name,
this.GetHashCode()));
this.AttachedToVisualTree();
}
}
}
}
public void InvalidateVisual()
{
ILayoutRoot root = this.GetVisualAncestorOrSelf<ILayoutRoot>();
if (root != null && root.LayoutManager != null)
{
// HACK HACK HACK!
root.LayoutManager.InvalidateArrange((ILayoutable)this);
}
}
public virtual void Render(IDrawingContext context)
{
Contract.Requires<ArgumentNullException>(context != null);
@ -70,6 +97,11 @@ namespace Perspex
protected virtual void AttachedToVisualTree()
{
this.Log().Debug(string.Format(
"Attached {0} (#{1:x8}) to visual tree",
this.GetType().Name,
this.GetHashCode()));
foreach (Visual child in ((IVisual)this).ExistingVisualChildren.OfType<Visual>())
{
child.AttachedToVisualTree();

6
TestApplication/Program.cs

@ -71,7 +71,11 @@ namespace TestApplication
{
Content = "Explict Background",
Background = new SolidColorBrush(0xffa0a0ff),
}
},
new CheckBox
{
Content = "Checkbox",
},
}
}
};

Loading…
Cancel
Save