diff --git a/Perspex.Windows/DrawingContext.cs b/Perspex.Windows/DrawingContext.cs
index d10ab74e2a..048d3056c2 100644
--- a/Perspex.Windows/DrawingContext.cs
+++ b/Perspex.Windows/DrawingContext.cs
@@ -75,14 +75,17 @@ namespace Perspex.Windows
/// The text.
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);
+ }
}
}
diff --git a/Perspex/Controls/Border.cs b/Perspex/Controls/Border.cs
index e85de3a759..197ef18c28 100644
--- a/Perspex/Controls/Border.cs
+++ b/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));
+ }
}
}
}
diff --git a/Perspex/Controls/CheckBox.cs b/Perspex/Controls/CheckBox.cs
new file mode 100644
index 0000000000..a78e5ab7ae
--- /dev/null
+++ b/Perspex/Controls/CheckBox.cs
@@ -0,0 +1,12 @@
+// -----------------------------------------------------------------------
+//
+// Copyright 2014 MIT Licence. See licence.md for more information.
+//
+// -----------------------------------------------------------------------
+
+namespace Perspex.Controls
+{
+ public class CheckBox : ToggleButton
+ {
+ }
+}
diff --git a/Perspex/Controls/ContentControl.cs b/Perspex/Controls/ContentControl.cs
index ece79b91f1..5a75bb8a28 100644
--- a/Perspex/Controls/ContentControl.cs
+++ b/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();
}
}
}
diff --git a/Perspex/Controls/ContentPresenter.cs b/Perspex/Controls/ContentPresenter.cs
index c0e7991049..373c024633 100644
--- a/Perspex/Controls/ContentPresenter.cs
+++ b/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();
}
}
}
diff --git a/Perspex/Controls/Decorator.cs b/Perspex/Controls/Decorator.cs
index a4157fc422..b8d8963524 100644
--- a/Perspex/Controls/Decorator.cs
+++ b/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();
}
}
}
diff --git a/Perspex/Controls/StackPanel.cs b/Perspex/Controls/StackPanel.cs
index 86888ad6ef..6d2ddc6404 100644
--- a/Perspex/Controls/StackPanel.cs
+++ b/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)
diff --git a/Perspex/Controls/TextBlock.cs b/Perspex/Controls/TextBlock.cs
index 3467a2dd35..ec387f93b1 100644
--- a/Perspex/Controls/TextBlock.cs
+++ b/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 TextProperty =
PerspexProperty.Register("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();
- return service.Measure(this.FormattedText);
+ if (this.Visibility != Visibility.Collapsed)
+ {
+ ITextService service = Locator.Current.GetService();
+
+ if (!string.IsNullOrEmpty(this.Text))
+ {
+ return service.Measure(this.FormattedText);
+ }
+ }
+
+ return new Size();
}
}
}
diff --git a/Perspex/Controls/ToggleButton.cs b/Perspex/Controls/ToggleButton.cs
new file mode 100644
index 0000000000..c26a6517e1
--- /dev/null
+++ b/Perspex/Controls/ToggleButton.cs
@@ -0,0 +1,39 @@
+// -----------------------------------------------------------------------
+//
+// Copyright 2014 MIT Licence. See licence.md for more information.
+//
+// -----------------------------------------------------------------------
+
+namespace Perspex.Controls
+{
+ using System;
+
+ public class ToggleButton : Button
+ {
+ public static readonly PerspexProperty IsCheckedProperty =
+ PerspexProperty.Register("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); }
+ }
+ }
+}
diff --git a/Perspex/Perspex.csproj b/Perspex/Perspex.csproj
index a020101356..ab1013d402 100644
--- a/Perspex/Perspex.csproj
+++ b/Perspex/Perspex.csproj
@@ -70,6 +70,8 @@
+
+
@@ -131,6 +133,7 @@
+
diff --git a/Perspex/Styling/Selectors.cs b/Perspex/Styling/Selectors.cs
index a41529e48d..ed0a9e0685 100644
--- a/Perspex/Styling/Selectors.cs
+++ b/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,
};
}
diff --git a/Perspex/Themes/Default/ButtonStyle.cs b/Perspex/Themes/Default/ButtonStyle.cs
index 28036ec36d..d2d554fab4 100644
--- a/Perspex/Themes/Default/ButtonStyle.cs
+++ b/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;
}
}
diff --git a/Perspex/Themes/Default/CheckBoxStyle.cs b/Perspex/Themes/Default/CheckBoxStyle.cs
new file mode 100644
index 0000000000..b419ce5576
--- /dev/null
+++ b/Perspex/Themes/Default/CheckBoxStyle.cs
@@ -0,0 +1,80 @@
+// -----------------------------------------------------------------------
+//
+// Copyright 2014 MIT Licence. See licence.md for more information.
+//
+// -----------------------------------------------------------------------
+
+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())
+ {
+ Setters = new[]
+ {
+ new Setter(Button.TemplateProperty, ControlTemplate.Create(this.Template)),
+ },
+ },
+ new Style(x => x.OfType().Template().Id("checkMark"))
+ {
+ Setters = new[]
+ {
+ new Setter(TextBlock.VisibilityProperty, Visibility.Hidden),
+ },
+ },
+ new Style(x => x.OfType().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
+ {
+ 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;
+ }
+ }
+}
diff --git a/Perspex/Themes/Default/DefaultTheme.cs b/Perspex/Themes/Default/DefaultTheme.cs
index e0d94d0403..e092d9975a 100644
--- a/Perspex/Themes/Default/DefaultTheme.cs
+++ b/Perspex/Themes/Default/DefaultTheme.cs
@@ -13,6 +13,7 @@ namespace Perspex.Themes.Default
public DefaultTheme()
{
this.Add(new ButtonStyle());
+ this.Add(new CheckBoxStyle());
}
}
}
diff --git a/Perspex/Visual.cs b/Perspex/Visual.cs
index fb934b7d3d..8fb61289da 100644
--- a/Perspex/Visual.cs
+++ b/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 VisibilityProperty =
+ PerspexProperty.Register("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.ExistingVisualChildren
{
get { return ((IVisual)this).VisualChildren; }
@@ -52,17 +73,23 @@ namespace Perspex
if (this.GetVisualAncestor() != 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();
+
+ if (root != null && root.LayoutManager != null)
+ {
+ // HACK HACK HACK!
+ root.LayoutManager.InvalidateArrange((ILayoutable)this);
+ }
+ }
+
public virtual void Render(IDrawingContext context)
{
Contract.Requires(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())
{
child.AttachedToVisualTree();
diff --git a/TestApplication/Program.cs b/TestApplication/Program.cs
index 1b45b30206..13acad45ca 100644
--- a/TestApplication/Program.cs
+++ b/TestApplication/Program.cs
@@ -71,7 +71,11 @@ namespace TestApplication
{
Content = "Explict Background",
Background = new SolidColorBrush(0xffa0a0ff),
- }
+ },
+ new CheckBox
+ {
+ Content = "Checkbox",
+ },
}
}
};