Browse Source

Started refactoring lyaout.

To make it faster. Currently all broken :/
pull/10/head
Steven Kirk 12 years ago
parent
commit
af492b5d75
  1. 0
      NGenerics/Constants.cs
  2. 2
      NGenerics/DataStructures/Comparers/ComparisonComparer.cs
  3. 2
      NGenerics/DataStructures/Comparers/KeyValuePairComparer.cs
  4. 83
      NGenerics/DataStructures/Comparers/ReverseComparer.cs
  5. 429
      NGenerics/DataStructures/General/Heap.cs
  6. 29
      NGenerics/DataStructures/General/HeapType.cs
  7. 41
      NGenerics/DataStructures/General/IHeap.cs
  8. 2
      NGenerics/DataStructures/Queues/IQueue.cs
  9. 2
      NGenerics/DataStructures/Queues/PriorityQueue.cs
  10. 2
      NGenerics/DataStructures/Queues/PriorityQueueType.cs
  11. 2
      NGenerics/DataStructures/Trees/BinarySearchTreeBase.cs
  12. 2
      NGenerics/DataStructures/Trees/BinaryTree.cs
  13. 2
      NGenerics/DataStructures/Trees/ISearchTree.cs
  14. 2
      NGenerics/DataStructures/Trees/ITree.cs
  15. 0
      NGenerics/DataStructures/Trees/NodeColor.cs
  16. 2
      NGenerics/DataStructures/Trees/RedBlackTree.cs
  17. 2
      NGenerics/DataStructures/Trees/RedBlackTreeDictionary.cs
  18. 0
      NGenerics/DataStructures/Trees/RedBlackTreeList.cs
  19. 0
      NGenerics/DataStructures/Trees/RedBlackTreeNode.cs
  20. 76
      NGenerics/NGenerics.csproj
  21. 2
      NGenerics/Patterns/Visitor/IVisitor.cs
  22. 2
      NGenerics/Patterns/Visitor/InOrderVisitor.cs
  23. 2
      NGenerics/Patterns/Visitor/KeyTrackingVisitor.cs
  24. 2
      NGenerics/Patterns/Visitor/OrderedVisitor.cs
  25. 2
      NGenerics/Patterns/Visitor/TrackingVisitor.cs
  26. 2
      NGenerics/Patterns/Visitor/ValueTrackingVisitor.cs
  27. 30
      NGenerics/Properties/AssemblyInfo.cs
  28. 2
      NGenerics/Util/Guard.cs
  29. 5
      Perspex.Application/Application.cs
  30. 29
      Perspex.Base/Perspex.Base.csproj
  31. 2
      Perspex.Controls/Presenters/ContentPresenter.cs
  32. 5
      Perspex.Controls/Primitives/ScrollBar.cs
  33. 4
      Perspex.Controls/Primitives/TemplatedControl.cs
  34. 5
      Perspex.Controls/ScrollViewer.cs
  35. 6
      Perspex.Controls/TextBox.cs
  36. 17
      Perspex.Controls/Window.cs
  37. 2
      Perspex.Diagnostics/DevTools.cs
  38. 2
      Perspex.Diagnostics/ViewModels/PropertyDetails.cs
  39. 51
      Perspex.Layout.UnitTests/LayoutableTests.cs
  40. 122
      Perspex.Layout.UnitTests/Perspex.Layout.UnitTests.csproj
  41. 36
      Perspex.Layout.UnitTests/Properties/AssemblyInfo.cs
  42. 11
      Perspex.Layout.UnitTests/app.config
  43. 6
      Perspex.Layout.UnitTests/packages.config
  44. 44
      Perspex.Layout/ILayoutManager.cs
  45. 13
      Perspex.Layout/ILayoutable.cs
  46. 153
      Perspex.Layout/LayoutManager.cs
  47. 89
      Perspex.Layout/Layoutable.cs
  48. 4
      Perspex.Layout/Perspex.Layout.csproj
  49. 9
      Perspex.sln
  50. 65
      TestApplication/Program.cs
  51. 12
      Windows/Perspex.Direct2D1/Renderer.cs
  52. 2
      Windows/Perspex.Direct2D1/TextService.cs

0
Perspex.Base/Threading/NGenerics/Constants.cs → NGenerics/Constants.cs

2
Perspex.Base/Threading/NGenerics/ComparisonComparer.cs → NGenerics/DataStructures/Comparers/ComparisonComparer.cs

@ -19,7 +19,7 @@ namespace NGenerics.Comparers
/// </summary>
/// <typeparam name="T">The type of the objects to compare.</typeparam>
//[Serializable]
internal sealed class ComparisonComparer<T> : IComparer<T>
public sealed class ComparisonComparer<T> : IComparer<T>
{
#region Globals

2
Perspex.Base/Threading/NGenerics/KeyValuePairComparer.cs → NGenerics/DataStructures/Comparers/KeyValuePairComparer.cs

@ -18,7 +18,7 @@ namespace NGenerics.Comparers {
/// <typeparam name="TKey">The key type.</typeparam>
/// <typeparam name="TValue">The value type.</typeparam>
//[Serializable]
internal class KeyValuePairComparer<TKey, TValue> : IComparer<KeyValuePair<TKey, TValue>> {
public class KeyValuePairComparer<TKey, TValue> : IComparer<KeyValuePair<TKey, TValue>> {
#region Globals

83
NGenerics/DataStructures/Comparers/ReverseComparer.cs

@ -0,0 +1,83 @@
/*
Copyright 2007-2013 The NGenerics Team
(https://github.com/ngenerics/ngenerics/wiki/Team)
This program is licensed under the GNU Lesser General Public License (LGPL). You should
have received a copy of the license along with the source code. If not, an online copy
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
*/
using System;
using System.Collections.Generic;
using NGenerics.Util;
namespace NGenerics.Comparers
{
/// <summary>
/// A comparer that wraps the IComparable interface to reproduce the opposite comparison result.
/// </summary>
/// <typeparam name="T">The type of the objects to compare.</typeparam>
//[Serializable]
public sealed class ReverseComparer<T> : IComparer<T>
{
#region Globals
private IComparer<T> comparerToUse;
#endregion
#region Construction
/// <inheritdoc />
public ReverseComparer()
{
comparerToUse = Comparer<T>.Default;
}
/// <param name="comparer">The comparer to reverse.</param>
/// <exception cref="ArgumentNullException"><paramref name="comparer"/> is a null reference (<c>Nothing</c> in Visual Basic).</exception>
public ReverseComparer(IComparer<T> comparer)
{
Guard.ArgumentNotNull(comparer, "comparer");
comparerToUse = comparer;
}
#endregion
#region IComparer<T> Members
/// <inheritdoc />
public int Compare(T x, T y)
{
return (comparerToUse.Compare(y, x));
}
#endregion
#region Public Members
/// <summary>
/// Gets or sets the comparer used in this instance.
/// </summary>
/// <value>The comparer.</value>
/// <exception cref="ArgumentNullException"><paramref name="value"/> is a null reference (<c>Nothing</c> in Visual Basic).</exception>
public IComparer<T> Comparer
{
get
{
return comparerToUse;
}
set
{
Guard.ArgumentNotNull(value, "value");
comparerToUse = value;
}
}
#endregion
}
}

429
NGenerics/DataStructures/General/Heap.cs

@ -0,0 +1,429 @@
/*
Copyright 2007-2013 The NGenerics Team
(https://github.com/ngenerics/ngenerics/wiki/Team)
This program is licensed under the GNU Lesser General Public License (LGPL). You should
have received a copy of the license along with the source code. If not, an online copy
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
*/
using System;
using System.Collections;
using System.Collections.Generic;
using NGenerics.Comparers;
using System.Diagnostics.CodeAnalysis;
using NGenerics.Util;
namespace NGenerics.DataStructures.General
{
/// <summary>
/// An implementation of a Heap data structure.
/// </summary>
/// <typeparam name="T">The type of item stored in the <see cref="Heap{T}"/>.</typeparam>
//[Serializable]
[SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")]
[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
public class Heap<T> : ICollection<T>, IHeap<T>
{
#region Globals
const string heapIsEmpty = "The heap is empty.";
private readonly List<T> data;
private readonly IComparer<T> comparerToUse;
private readonly HeapType thisType;
#endregion
#region Construction
/// <summary>
/// Initializes a new instance of the <see cref="Heap&lt;T&gt;"/> class.
/// </summary>
/// <param name="type">The type of Heap to create.</param>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="type"/> is not either <see cref="HeapType.Maximum"/> or <see cref="HeapType.Minimum"/> .</exception>
/// <example>
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\General\HeapExamples.cs" region="Constructor" lang="cs" title="The following example shows how to use the default constructor."/>
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\General\HeapExamples.vb" region="Constructor" lang="vbnet" title="The following example shows how to use the default constructor."/>
/// </example>
public Heap(HeapType type) : this(type, Comparer<T>.Default) { }
/// <summary>
/// Initializes a new instance of the <see cref="Heap&lt;T&gt;"/> class.
/// </summary>
/// <param name="type">The type of heap.</param>
/// <param name="capacity">The capacity.</param>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="type"/> is not either <see cref="HeapType.Maximum"/> or <see cref="HeapType.Minimum"/> .</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="capacity"/> is less than 0.</exception>
/// .
/// <example>
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\General\HeapExamples.cs" region="ConstructorCapacity" lang="cs" title="The following example shows how to use the capacity constructor."/>
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\General\HeapExamples.vb" region="ConstructorCapacity" lang="vbnet" title="The following example shows how to use the capacity constructor."/>
/// </example>
public Heap(HeapType type, int capacity) : this(type, capacity, Comparer<T>.Default) { }
/// <summary>
/// Initializes a new instance of the <see cref="Heap&lt;T&gt;"/> class.
/// </summary>
/// <param name="type">The type of heap.</param>
/// <param name="comparer">The comparer.</param>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="type"/> is not either <see cref="HeapType.Maximum"/> or <see cref="HeapType.Minimum"/> .</exception>
public Heap(HeapType type, Comparison<T> comparer) : this(type, new ComparisonComparer<T>(comparer)){}
/// <summary>
/// Initializes a new instance of the <see cref="Heap&lt;T&gt;"/> class.
/// </summary>
/// <param name="type">The type of heap.</param>
/// <param name="capacity">The capacity of the heap to start with.</param>
/// <param name="comparer">The comparer.</param>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="type"/> is not either <see cref="HeapType.Maximum"/> or <see cref="HeapType.Minimum"/> .</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="capacity"/> is less than 0.</exception>
public Heap(HeapType type, int capacity, Comparison<T> comparer) : this(type, capacity, new ComparisonComparer<T>(comparer)) { }
/// <summary>
/// Initializes a new instance of the <see cref="Heap&lt;T&gt;"/> class.
/// </summary>
/// <param name="type">The type of Heap to create.</param>
/// <param name="comparer">The comparer to use.</param>
/// <exception cref="ArgumentNullException"><paramref name="comparer"/> is a null reference (<c>Nothing</c> in Visual Basic).</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="type"/> is not either <see cref="HeapType.Maximum"/> or <see cref="HeapType.Minimum"/> .</exception>
/// <example>
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\General\HeapExamples.cs" region="ConstructorComparer" lang="cs" title="The following example shows how to use the comparer constructor."/>
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\General\HeapExamples.vb" region="ConstructorComparer" lang="vbnet" title="The following example shows how to use the comparer constructor."/>
/// </example>
public Heap(HeapType type, IComparer<T> comparer)
{
Guard.ArgumentNotNull(comparer, "comparer");
if ((type != HeapType.Minimum) && (type != HeapType.Maximum))
{
throw new ArgumentOutOfRangeException("type");
}
thisType = type;
data = new List<T> {default(T)};
comparerToUse = type == HeapType.Minimum ? comparer : new ReverseComparer<T>(comparer);
}
/// <param name="type">The type of heap.</param>
/// <param name="capacity">The initial capacity of the Heap.</param>
/// <param name="comparer">The comparer to use.</param>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="capacity"/> is less than 0.</exception>.
/// <exception cref="ArgumentNullException"><paramref name="comparer"/> is a null reference (<c>Nothing</c> in Visual Basic).</exception>
/// <exception cref="ArgumentOutOfRangeException"><paramref name="type"/> is not either <see cref="HeapType.Maximum"/> or <see cref="HeapType.Minimum"/> .</exception>
public Heap(HeapType type, int capacity, IComparer<T> comparer)
{
Guard.ArgumentNotNull(comparer, "comparer");
if ((type != HeapType.Minimum) && (type != HeapType.Maximum))
{
throw new ArgumentOutOfRangeException("type");
}
thisType = type;
data = new List<T>(capacity) {default(T)};
comparerToUse = type == HeapType.Minimum ? comparer : new ReverseComparer<T>(comparer);
}
#endregion
#region Public Members
/// <inheritdoc />
/// <example>
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\General\HeapExamples.cs" region="Root" lang="cs" title="The following example shows how to use the Root property."/>
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\General\HeapExamples.vb" region="Root" lang="vbnet" title="The following example shows how to use the Root property."/>
/// </example>
public T Root
{
get
{
#region Validation
if (Count == 0)
{
throw new InvalidOperationException(heapIsEmpty);
}
#endregion
return data[1];
}
}
/// <inheritdoc />
/// <example>
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\General\HeapExamples.cs" region="RemoveRoot" lang="cs" title="The following example shows how to use the RemoveRoot method."/>
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\General\HeapExamples.vb" region="RemoveRoot" lang="vbnet" title="The following example shows how to use the RemoveRoot method."/>
/// </example>
public T RemoveRoot()
{
#region Validation
if (Count == 0)
{
throw new InvalidOperationException(heapIsEmpty);
}
#endregion
// The minimum item to return.
var minimum = data[1];
RemoveRootItem(minimum);
return minimum;
}
/// <summary>
/// Removes the root item.
/// </summary>
/// <param name="item">The item.</param>
/// <remarks>
/// <b>Notes to Inheritors: </b>
/// Derived classes can override this method to change the behavior of the <see cref="RemoveRoot"/> method.
/// </remarks>
protected virtual void RemoveRootItem(T item)
{
// The last item in the heap
var last = data[Count];
data.RemoveAt(Count);
// If there's still items left in this heap, re-heapify it.
if (Count > 0)
{
// Re-heapify the binary tree to conform to the heap property
var counter = 1;
while ((counter * 2) < (data.Count))
{
var child = counter * 2;
if (((child + 1) < (data.Count)) &&
(comparerToUse.Compare(data[child + 1], data[child]) < 0))
{
child++;
}
if (comparerToUse.Compare(last, data[child]) <= 0)
{
break;
}
data[counter] = data[child];
counter = child;
}
data[counter] = last;
}
}
/// <summary>
/// Gets the type of heap represented by this instance.
/// </summary>
/// <value>The type of heap.</value>
/// <example>
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\General\HeapExamples.cs" region="Type" lang="cs" title="The following example shows how to use the Type property."/>
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\General\HeapExamples.vb" region="Type" lang="vbnet" title="The following example shows how to use the Type property."/>
/// </example>
[SuppressMessage("Microsoft.Naming", "CA1721:PropertyNamesShouldNotMatchGetMethods")]
public HeapType Type
{
get
{
return thisType;
}
}
#endregion
#region ICollection<T> Members
/// <inheritdoc />
/// <example>
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\General\HeapExamples.cs" region="IsEmpty" lang="cs" title="The following example shows how to use the IsEmpty property."/>
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\General\HeapExamples.vb" region="IsEmpty" lang="vbnet" title="The following example shows how to use the IsEmpty property."/>
/// </example>
public bool IsEmpty
{
get
{
return Count == 0;
}
}
/// <inheritdoc />
/// <example>
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\General\HeapExamples.cs" region="Contains" lang="cs" title="The following example shows how to use the Contains method."/>
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\General\HeapExamples.vb" region="Contains" lang="vbnet" title="The following example shows how to use the Contains method."/>
/// </example>
public bool Contains(T item)
{
return data.Contains(item);
}
/// <inheritdoc />
/// <example>
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\General\HeapExamples.cs" region="CopyTo" lang="cs" title="The following example shows how to use the CopyTo method."/>
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\General\HeapExamples.vb" region="CopyTo" lang="vbnet" title="The following example shows how to use the CopyTo method."/>
/// </example>
public void CopyTo(T[] array, int arrayIndex)
{
#region Validation
Guard.ArgumentNotNull(array, "array");
if ((array.Length - arrayIndex) < Count)
{
throw new ArgumentException(Constants.NotEnoughSpaceInTheTargetArray, "array");
}
#endregion
for (var i = 1; i < data.Count; i++)
{
array[arrayIndex++] = data[i];
}
}
/// <inheritdoc />
/// <example>
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\General\HeapExamples.cs" region="Count" lang="cs" title="The following example shows how to use the Count property."/>
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\General\HeapExamples.vb" region="Count" lang="vbnet" title="The following example shows how to use the Count property."/>
/// </example>
public int Count
{
get
{
return data.Count - 1;
}
}
/// <inheritdoc />
/// <example>
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\General\HeapExamples.cs" region="Add" lang="cs" title="The following example shows how to use the Add method."/>
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\General\HeapExamples.vb" region="Add" lang="vbnet" title="The following example shows how to use the Add method."/>
/// </example>
public void Add(T item)
{
AddItem(item);
}
/// <summary>
/// Adds the item.
/// </summary>
/// <param name="item">The item to add.</param>
/// <remarks>
/// <b>Notes to Inheritors: </b>
/// Derived classes can override this method to change the behavior of the <see cref="Add"/> method.
/// </remarks>
protected virtual void AddItem(T item)
{
// Add a dummy to the end of the list (it will be replaced)
data.Add(default(T));
var counter = data.Count - 1;
while ((counter > 1) && (comparerToUse.Compare(data[counter / 2], item) > 0))
{
data[counter] = data[counter / 2];
counter = counter / 2;
}
data[counter] = item;
}
/// <inheritdoc />
/// <exception cref="NotSupportedException">Always.</exception>
[SuppressMessage("Microsoft.Design", "CA1033:InterfaceMethodsShouldBeCallableByChildTypes")]
bool ICollection<T>.Remove(T item)
{
throw new NotSupportedException();
}
/// <summary>
/// Returns an enumerator that iterates through the collection.
/// </summary>
/// <returns>
/// A <see cref="T:System.Collections.Generic.IEnumerator`1"/> that can be used to iterate through the collection.
/// </returns>
/// <example>
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\General\HeapExamples.cs" region="GetEnumerator" lang="cs" title="The following example shows how to use the GetEnumerator method."/>
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\General\HeapExamples.vb" region="GetEnumerator" lang="vbnet" title="The following example shows how to use the GetEnumerator method."/>
/// </example>
public IEnumerator<T> GetEnumerator()
{
for (var i = 1; i < data.Count; i++)
{
yield return data[i];
}
}
/// <inheritdoc />
/// <example>
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\General\HeapExamples.cs" region="Clear" lang="cs" title="The following example shows how to use the Clear method."/>
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\General\HeapExamples.vb" region="Clear" lang="vbnet" title="The following example shows how to use the Clear method."/>
/// </example>
public void Clear()
{
ClearItems();
}
/// <summary>
/// Clears all the objects in this instance.
/// </summary>
/// <remarks>
/// <b>Notes to Inheritors: </b>
/// Derived classes can override this method to change the behavior of the <see cref="Clear"/> method.
/// </remarks>
protected virtual void ClearItems()
{
data.RemoveRange(1, data.Count - 1); // Clears all objects in this instance except the first dummy one.
}
#endregion
#region ICollection<T> Members
/// <inheritdoc />
/// <example>
/// <code source="..\..\Source\Examples\ExampleLibraryCSharp\DataStructures\General\HeapExamples.cs" region="IsReadOnly" lang="cs" title="The following example shows how to use the IsReadOnly property."/>
/// <code source="..\..\Source\Examples\ExampleLibraryVB\DataStructures\General\HeapExamples.vb" region="IsReadOnly" lang="vbnet" title="The following example shows how to use the IsReadOnly property."/>
/// </example>
public bool IsReadOnly
{
get
{
return false;
}
}
#endregion
#region IEnumerable Members
/// <inheritdoc />
IEnumerator IEnumerable.GetEnumerator()
{
return GetEnumerator();
}
#endregion
}
}

29
NGenerics/DataStructures/General/HeapType.cs

@ -0,0 +1,29 @@
/*
Copyright 2007-2013 The NGenerics Team
(https://github.com/ngenerics/ngenerics/wiki/Team)
This program is licensed under the GNU Lesser General Public License (LGPL). You should
have received a copy of the license along with the source code. If not, an online copy
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
*/
namespace NGenerics.DataStructures.General
{
/// <summary>
/// The type of <see cref="Heap{T}"/> to implemented.
/// </summary>
public enum HeapType
{
/// <summary>
/// Makes the heap a Minimum-Heap - the smallest item is kept in the root of the <see cref="Heap{T}"/>.
/// </summary>
Minimum,
/// <summary>
/// Makes the heap a Maximum-Heap - the largest item is kept in the root of the <see cref="Heap{T}"/>.
/// </summary>
Maximum
}
}

41
NGenerics/DataStructures/General/IHeap.cs

@ -0,0 +1,41 @@
/*
Copyright 2007-2013 The NGenerics Team
(https://github.com/ngenerics/ngenerics/wiki/Team)
This program is licensed under the GNU Lesser General Public License (LGPL). You should
have received a copy of the license along with the source code. If not, an online copy
of the license can be found at http://www.gnu.org/copyleft/lesser.html.
*/
using System;
namespace NGenerics.DataStructures.General
{
/// <summary>
/// An interface for the <see cref="Heap{T}"/> data structure.
/// </summary>
/// <typeparam name="T">The type of elements in the heap.</typeparam>
public interface IHeap<T>
{
/// <summary>
/// Adds the specified item.
/// </summary>
/// <param name="item">The item.</param>
void Add(T item);
/// <summary>
/// Removes the root and returns it.
/// </summary>
/// <returns>The root of the <see cref="Heap{T}"/>.</returns>
/// <exception cref="InvalidOperationException">The <see cref="Graph{T}"/> is empty.</exception>
T RemoveRoot();
/// <summary>
/// Gets the root.
/// </summary>
/// <value>The root.</value>
/// <exception cref="InvalidOperationException">The <see cref="Heap{T}"/> is empty.</exception>
T Root { get; }
}
}

2
Perspex.Base/Threading/NGenerics/IQueue.cs → NGenerics/DataStructures/Queues/IQueue.cs

@ -18,7 +18,7 @@ namespace NGenerics.DataStructures.Queues
/// </summary>
/// <typeparam name="T">The type of the elements in the queue.</typeparam>
[SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")]
internal interface IQueue<T>
public interface IQueue<T>
{
/// <summary>
/// Enqueues the item at the back of the queue.

2
Perspex.Base/Threading/NGenerics/PriorityQueue.cs → NGenerics/DataStructures/Queues/PriorityQueue.cs

@ -29,7 +29,7 @@ namespace NGenerics.DataStructures.Queues
[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
[SuppressMessage("Microsoft.Naming", "CA1711:IdentifiersShouldNotHaveIncorrectSuffix")]
//[Serializable]
internal class PriorityQueue<TValue, TPriority> : ICollection<TValue>, IQueue<TValue>
public class PriorityQueue<TValue, TPriority> : ICollection<TValue>, IQueue<TValue>
{
#region Globals

2
Perspex.Base/Threading/NGenerics/PriorityQueueType.cs → NGenerics/DataStructures/Queues/PriorityQueueType.cs

@ -12,7 +12,7 @@ namespace NGenerics.DataStructures.Queues
/// <summary>
/// Specifies the Priority Queue type (min or max).
/// </summary>
internal enum PriorityQueueType
public enum PriorityQueueType
{
/// <summary>
/// Specify a Minimum <see cref="PriorityQueue{TValue, TPriority}"/>.

2
Perspex.Base/Threading/NGenerics/BinarySearchTreeBase.cs → NGenerics/DataStructures/Trees/BinarySearchTreeBase.cs

@ -24,7 +24,7 @@ namespace NGenerics.DataStructures.Trees
/// </summary>
/// <typeparam name="T"></typeparam>
//[Serializable]
internal abstract class BinarySearchTreeBase<T> : ISearchTree<T>
public abstract class BinarySearchTreeBase<T> : ISearchTree<T>
{
#region Globals

2
Perspex.Base/Threading/NGenerics/BinaryTree.cs → NGenerics/DataStructures/Trees/BinaryTree.cs

@ -23,7 +23,7 @@ namespace NGenerics.DataStructures.Trees
/// <typeparam name="T">The type of elements in the <see cref="BinaryTree{T}"/>.</typeparam>
//[Serializable]
[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
internal class BinaryTree<T> : ICollection<T>, ITree<T>
public class BinaryTree<T> : ICollection<T>, ITree<T>
{
#region Globals

2
Perspex.Base/Threading/NGenerics/ISearchTree.cs → NGenerics/DataStructures/Trees/ISearchTree.cs

@ -21,7 +21,7 @@ namespace NGenerics.DataStructures.Trees
/// </summary>
/// <typeparam name="T">The type of element to hold in the tree.</typeparam>
[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
internal interface ISearchTree<T> : ICollection<T> {
public interface ISearchTree<T> : ICollection<T> {
/// <summary>
/// Gets the largest item in the tree.
/// </summary>

2
Perspex.Base/Threading/NGenerics/ITree.cs → NGenerics/DataStructures/Trees/ITree.cs

@ -14,7 +14,7 @@ namespace NGenerics.DataStructures.Trees {
/// An interface for the tree data structure
/// </summary>
/// <typeparam name="T">The type of elements in the tree.</typeparam>
internal interface ITree<T> {
public interface ITree<T> {
/// <summary>
/// Adds the specified child to the tree.
/// </summary>

0
Perspex.Base/Threading/NGenerics/NodeColor.cs → NGenerics/DataStructures/Trees/NodeColor.cs

2
Perspex.Base/Threading/NGenerics/RedBlackTree.cs → NGenerics/DataStructures/Trees/RedBlackTree.cs

@ -24,7 +24,7 @@ namespace NGenerics.DataStructures.Trees {
/// <typeparam name="T">The type of element to keep in the tree.</typeparam>
[SuppressMessage("Microsoft.Naming", "CA1710:IdentifiersShouldHaveCorrectSuffix")]
//[Serializable]
internal class RedBlackTree<T> : BinarySearchTreeBase<T> {
public class RedBlackTree<T> : BinarySearchTreeBase<T> {
#region Construction

2
Perspex.Base/Threading/NGenerics/RedBlackTreeDictionary.cs → NGenerics/DataStructures/Trees/RedBlackTreeDictionary.cs

@ -31,7 +31,7 @@ namespace NGenerics.DataStructures.Trees
#if (!SILVERLIGHT && !WINDOWSPHONE)
//[Serializable]
#endif
internal class RedBlackTree<TKey, TValue> : RedBlackTree<KeyValuePair<TKey, TValue>>, IDictionary<TKey, TValue> // BinarySearchTreeBase<TKey, TValue>
public class RedBlackTree<TKey, TValue> : RedBlackTree<KeyValuePair<TKey, TValue>>, IDictionary<TKey, TValue> // BinarySearchTreeBase<TKey, TValue>
{
#region Construction
/// <inheritdoc />

0
Perspex.Base/Threading/NGenerics/RedBlackTreeList.cs → NGenerics/DataStructures/Trees/RedBlackTreeList.cs

0
Perspex.Base/Threading/NGenerics/RedBlackTreeNode.cs → NGenerics/DataStructures/Trees/RedBlackTreeNode.cs

76
NGenerics/NGenerics.csproj

@ -0,0 +1,76 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<Import Project="$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props" Condition="Exists('$(MSBuildExtensionsPath)\$(MSBuildToolsVersion)\Microsoft.Common.props')" />
<PropertyGroup>
<MinimumVisualStudioVersion>11.0</MinimumVisualStudioVersion>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{415E048E-4611-4815-9CF2-D774E29079AC}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>NGenerics</RootNamespace>
<AssemblyName>NGenerics</AssemblyName>
<DefaultLanguage>en-US</DefaultLanguage>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{786C830F-07A1-408B-BD7F-6EE04809D6DB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<TargetFrameworkProfile>Profile7</TargetFrameworkProfile>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .NET Framework is automatically included -->
</ItemGroup>
<ItemGroup>
<Compile Include="DataStructures\Comparers\ReverseComparer.cs" />
<Compile Include="DataStructures\General\Heap.cs" />
<Compile Include="DataStructures\General\HeapType.cs" />
<Compile Include="DataStructures\General\IHeap.cs" />
<Compile Include="DataStructures\Trees\BinarySearchTreeBase.cs" />
<Compile Include="DataStructures\Trees\BinaryTree.cs" />
<Compile Include="DataStructures\Comparers\ComparisonComparer.cs" />
<Compile Include="Constants.cs" />
<Compile Include="Util\Guard.cs" />
<Compile Include="Patterns\Visitor\InOrderVisitor.cs" />
<Compile Include="DataStructures\Queues\IQueue.cs" />
<Compile Include="DataStructures\Trees\ISearchTree.cs" />
<Compile Include="DataStructures\Trees\ITree.cs" />
<Compile Include="Patterns\Visitor\IVisitor.cs" />
<Compile Include="Patterns\Visitor\KeyTrackingVisitor.cs" />
<Compile Include="DataStructures\Comparers\KeyValuePairComparer.cs" />
<Compile Include="DataStructures\Trees\NodeColor.cs" />
<Compile Include="Patterns\Visitor\OrderedVisitor.cs" />
<Compile Include="DataStructures\Queues\PriorityQueue.cs" />
<Compile Include="DataStructures\Queues\PriorityQueueType.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
<Compile Include="DataStructures\Trees\RedBlackTree.cs" />
<Compile Include="DataStructures\Trees\RedBlackTreeDictionary.cs" />
<Compile Include="DataStructures\Trees\RedBlackTreeList.cs" />
<Compile Include="DataStructures\Trees\RedBlackTreeNode.cs" />
<Compile Include="Patterns\Visitor\TrackingVisitor.cs" />
<Compile Include="Patterns\Visitor\ValueTrackingVisitor.cs" />
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

2
Perspex.Base/Threading/NGenerics/IVisitor.cs → NGenerics/Patterns/Visitor/IVisitor.cs

@ -14,7 +14,7 @@ namespace NGenerics.Patterns.Visitor
/// Provides an interface for visitors.
/// </summary>
/// <typeparam name="T">The type of objects to be visited.</typeparam>
internal interface IVisitor<T>
public interface IVisitor<T>
{
/// <summary>
/// Gets a value indicating whether this instance is done performing it's work..

2
Perspex.Base/Threading/NGenerics/InOrderVisitor.cs → NGenerics/Patterns/Visitor/InOrderVisitor.cs

@ -14,7 +14,7 @@ namespace NGenerics.Patterns.Visitor
/// An in order implementation of the <see cref="OrderedVisitor{T}"/> class.
/// </summary>
/// <typeparam name="T">The type of objects to be visited.</typeparam>
internal sealed class InOrderVisitor<T> : OrderedVisitor<T>
public sealed class InOrderVisitor<T> : OrderedVisitor<T>
{
#region Construction

2
Perspex.Base/Threading/NGenerics/KeyTrackingVisitor.cs → NGenerics/Patterns/Visitor/KeyTrackingVisitor.cs

@ -17,7 +17,7 @@ namespace NGenerics.Patterns.Visitor
/// </summary>
/// <typeparam name="TKey">The type of the keys for the items to be visited.</typeparam>
/// <typeparam name="TValue">The type of the values for the items to be visited.</typeparam>
internal sealed class KeyTrackingVisitor<TKey, TValue> : IVisitor<KeyValuePair<TKey, TValue>>
public sealed class KeyTrackingVisitor<TKey, TValue> : IVisitor<KeyValuePair<TKey, TValue>>
{
#region Globals

2
Perspex.Base/Threading/NGenerics/OrderedVisitor.cs → NGenerics/Patterns/Visitor/OrderedVisitor.cs

@ -19,7 +19,7 @@ namespace NGenerics.Patterns.Visitor
/// Used primarily as a base class for Visitors specializing in a specific order type.
/// </summary>
/// <typeparam name="T">The type of objects to be visited.</typeparam>
internal class OrderedVisitor<T> : IVisitor<T>
public class OrderedVisitor<T> : IVisitor<T>
{
#region Globals

2
Perspex.Base/Threading/NGenerics/TrackingVisitor.cs → NGenerics/Patterns/Visitor/TrackingVisitor.cs

@ -18,7 +18,7 @@ namespace NGenerics.Patterns.Visitor
/// data structures.
/// </summary>
/// <typeparam name="T">The type of objects to be visited.</typeparam>
internal sealed class TrackingVisitor<T> : IVisitor<T>
public sealed class TrackingVisitor<T> : IVisitor<T>
{
#region Globals

2
Perspex.Base/Threading/NGenerics/ValueTrackingVisitor.cs → NGenerics/Patterns/Visitor/ValueTrackingVisitor.cs

@ -17,7 +17,7 @@ namespace NGenerics.Patterns.Visitor
/// </summary>
/// <typeparam name="TKey">The type of key of the KeyValuePair.</typeparam>
/// <typeparam name="TValue">The type of value of the KeyValuePair.</typeparam>
internal sealed class ValueTrackingVisitor<TKey, TValue> : IVisitor<KeyValuePair<TKey, TValue>>
public sealed class ValueTrackingVisitor<TKey, TValue> : IVisitor<KeyValuePair<TKey, TValue>>
{
#region Globals

30
NGenerics/Properties/AssemblyInfo.cs

@ -0,0 +1,30 @@
using System.Resources;
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("NGenerics")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("NGenerics")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
[assembly: NeutralResourcesLanguage("en")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

2
Perspex.Base/Threading/NGenerics/Guard.cs → NGenerics/Util/Guard.cs

@ -15,7 +15,7 @@ namespace NGenerics.Util
/// <summary>
/// Performs common argument validation.
/// </summary>
internal static class Guard
public static class Guard
{
#region Methods

5
Perspex.Application/Application.cs

@ -10,6 +10,8 @@ namespace Perspex
using System.Threading;
using Perspex.Controls;
using Perspex.Input;
using Perspex.Layout;
using Perspex.Rendering;
using Perspex.Styling;
using Perspex.Threading;
using Splat;
@ -90,6 +92,9 @@ namespace Perspex
Locator.CurrentMutable.Register(() => this.FocusManager, typeof(IFocusManager));
Locator.CurrentMutable.Register(() => this.InputManager, typeof(IInputManager));
Locator.CurrentMutable.Register(() => this.styler, typeof(IStyler));
Locator.CurrentMutable.Register(() => new LayoutManager(), typeof(ILayoutManager));
Locator.CurrentMutable.Register(() => new RenderManager(), typeof(IRenderManager));
}
}
}

29
Perspex.Base/Perspex.Base.csproj

@ -54,28 +54,6 @@
<Compile Include="Threading\DispatcherPriority.cs" />
<Compile Include="Threading\DispatcherTimer.cs" />
<Compile Include="Threading\MainLoop.cs" />
<Compile Include="Threading\NGenerics\BinarySearchTreeBase.cs" />
<Compile Include="Threading\NGenerics\BinaryTree.cs" />
<Compile Include="Threading\NGenerics\ComparisonComparer.cs" />
<Compile Include="Threading\NGenerics\Constants.cs" />
<Compile Include="Threading\NGenerics\Guard.cs" />
<Compile Include="Threading\NGenerics\InOrderVisitor.cs" />
<Compile Include="Threading\NGenerics\IQueue.cs" />
<Compile Include="Threading\NGenerics\ISearchTree.cs" />
<Compile Include="Threading\NGenerics\ITree.cs" />
<Compile Include="Threading\NGenerics\IVisitor.cs" />
<Compile Include="Threading\NGenerics\KeyTrackingVisitor.cs" />
<Compile Include="Threading\NGenerics\KeyValuePairComparer.cs" />
<Compile Include="Threading\NGenerics\NodeColor.cs" />
<Compile Include="Threading\NGenerics\OrderedVisitor.cs" />
<Compile Include="Threading\NGenerics\PriorityQueue.cs" />
<Compile Include="Threading\NGenerics\PriorityQueueType.cs" />
<Compile Include="Threading\NGenerics\RedBlackTree.cs" />
<Compile Include="Threading\NGenerics\RedBlackTreeDictionary.cs" />
<Compile Include="Threading\NGenerics\RedBlackTreeList.cs" />
<Compile Include="Threading\NGenerics\RedBlackTreeNode.cs" />
<Compile Include="Threading\NGenerics\TrackingVisitor.cs" />
<Compile Include="Threading\NGenerics\ValueTrackingVisitor.cs" />
</ItemGroup>
<ItemGroup>
<Reference Include="Splat">
@ -98,7 +76,12 @@
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<ItemGroup />
<ItemGroup>
<ProjectReference Include="..\NGenerics\NGenerics.csproj">
<Project>{415e048e-4611-4815-9cf2-d774e29079ac}</Project>
<Name>NGenerics</Name>
</ProjectReference>
</ItemGroup>
<Import Project="$(MSBuildExtensionsPath32)\Microsoft\Portable\$(TargetFrameworkVersion)\Microsoft.Portable.CSharp.targets" />
<Import Project="..\packages\StyleCop.MSBuild.4.7.49.0\build\StyleCop.MSBuild.Targets" Condition="Exists('..\packages\StyleCop.MSBuild.4.7.49.0\build\StyleCop.MSBuild.Targets')" />
<Target Name="EnsureNuGetPackageBuildImports" BeforeTargets="PrepareForBuild">

2
Perspex.Controls/Presenters/ContentPresenter.cs

@ -15,7 +15,7 @@ namespace Perspex.Controls.Presenters
public class ContentPresenter : Control, IVisual
{
public static readonly PerspexProperty<object> ContentProperty =
ContentControl.ContentProperty.AddOwner<Control>();
ContentControl.ContentProperty.AddOwner<ContentPresenter>();
private bool createdChild;

5
Perspex.Controls/Primitives/ScrollBar.cs

@ -61,5 +61,10 @@ namespace Perspex.Controls.Primitives
get { return this.GetValue(OrientationProperty); }
set { this.SetValue(OrientationProperty, value); }
}
protected override Size MeasureOverride(Size availableSize)
{
return base.MeasureOverride(availableSize);
}
}
}

4
Perspex.Controls/Primitives/TemplatedControl.cs

@ -26,11 +26,11 @@ namespace Perspex.Controls.Primitives
set { this.SetValue(TemplateProperty, value); }
}
public sealed override void Render(IDrawingContext context)
public override void Render(IDrawingContext context)
{
}
protected sealed override void ApplyTemplate()
protected override void ApplyTemplate()
{
if (!this.templateApplied)
{

5
Perspex.Controls/ScrollViewer.cs

@ -46,6 +46,11 @@ namespace Perspex.Controls
private set { this.SetValue(ViewportProperty, value); }
}
protected override Size MeasureOverride(Size availableSize)
{
return base.MeasureOverride(availableSize);
}
protected override void OnTemplateApplied()
{
this.presenter = this.GetTemplateChild<ScrollContentPresenter>("presenter");

6
Perspex.Controls/TextBox.cs

@ -45,7 +45,9 @@ namespace Perspex.Controls
set
{
value = Math.Min(Math.Max(value, 0), this.Text.Length);
var text = this.Text ?? string.Empty;
value = Math.Min(Math.Max(value, 0), text.Length);
if (this.caretIndex != value)
{
@ -80,7 +82,7 @@ namespace Perspex.Controls
private void OnKeyDown(object sender, KeyEventArgs e)
{
string text = this.Text;
string text = this.Text ?? string.Empty;
switch (e.Key)
{

17
Perspex.Controls/Window.cs

@ -45,6 +45,8 @@ namespace Perspex.Controls
this.impl = Locator.Current.GetService<IWindowImpl>();
this.inputManager = Locator.Current.GetService<IInputManager>();
this.LayoutManager = Locator.Current.GetService<ILayoutManager>();
this.RenderManager = Locator.Current.GetService<IRenderManager>();
if (this.impl == null)
{
@ -58,6 +60,18 @@ namespace Perspex.Controls
"Could not create input manager: maybe Application.RegisterServices() wasn't called?");
}
if (this.LayoutManager == null)
{
throw new InvalidOperationException(
"Could not create layout manager: maybe Application.RegisterServices() wasn't called?");
}
if (this.RenderManager == null)
{
throw new InvalidOperationException(
"Could not create render manager: maybe Application.RegisterServices() wasn't called?");
}
this.impl.SetOwner(this);
this.impl.Activated = this.HandleActivated;
this.impl.Closed = this.HandleClosed;
@ -69,10 +83,9 @@ namespace Perspex.Controls
this.dispatcher = Dispatcher.UIThread;
this.renderer = renderInterface.CreateRenderer(this.impl.Handle, clientSize.Width, clientSize.Height);
this.LayoutManager = new LayoutManager(this);
this.LayoutManager.Root = this;
this.LayoutManager.LayoutNeeded.Subscribe(_ => this.HandleLayoutNeeded());
this.RenderManager = new RenderManager();
this.RenderManager.RenderNeeded.Subscribe(_ => this.HandleRenderNeeded());
this.GetObservable(TitleProperty).Subscribe(s => this.impl.SetTitle(s));

2
Perspex.Diagnostics/DevTools.cs

@ -25,7 +25,7 @@ namespace Perspex.Diagnostics
{
DataTemplates = new DataTemplates
{
new TreeDataTemplate<VisualTreeNode>(GetHeader, x => x.Children),
new TreeDataTemplate<VisualTreeNode>(GetHeader, x => x.Children, x => true),
},
[!TreeView.ItemsProperty] = this[!DevTools.RootProperty].Select(x =>
{

2
Perspex.Diagnostics/ViewModels/PropertyDetails.cs

@ -14,7 +14,7 @@ namespace Perspex.Diagnostics.ViewModels
public PropertyDetails(PerspexPropertyValue value)
{
this.Name = value.Property.Name;
this.Value = value.CurrentValue;
this.Value = value.CurrentValue ?? "(null)";
this.Priority = (value.PriorityValue != null) ?
Enum.GetName(typeof(BindingPriority), value.PriorityValue.ValuePriority) :
value.Property.Inherits ? "Inherited" : "Unset";

51
Perspex.Layout.UnitTests/LayoutableTests.cs

@ -0,0 +1,51 @@
// -----------------------------------------------------------------------
// <copyright file="LayoutableTests.cs" company="Steven Kirk">
// Copyright 2014 MIT Licence. See licence.md for more information.
// </copyright>
// -----------------------------------------------------------------------
namespace Perspex.Layout.UnitTests
{
using Microsoft.VisualStudio.TestTools.UnitTesting;
using Moq;
using Moq.AutoMock;
using Perspex.Controls;
using Perspex.Input;
using Perspex.Platform;
using Perspex.Rendering;
using Perspex.Styling;
using Splat;
[TestClass]
public class LayoutableTests
{
private Mock<ILayoutManager> layoutManager;
[TestMethod]
public void Calling_InvalidateMeasure_On_Window_Should_Call_LayoutManager_InvalidateMeasure()
{
using (var d = Locator.Current.WithResolver())
{
this.RegisterServices();
Window target = new Window();
}
}
private void RegisterServices()
{
var l = Locator.CurrentMutable;
var m = new AutoMocker();
var lm = m.CreateInstance<ILayoutManager>();
//this.layoutManager =
l.RegisterConstant(new Mock<IInputManager>().Object, typeof(IInputManager));
l.RegisterConstant(this.layoutManager.Object, typeof(ILayoutManager));
l.RegisterConstant(new Mock<IPlatformRenderInterface>().Object, typeof(IPlatformRenderInterface));
l.RegisterConstant(new Mock<IRenderManager>().Object, typeof(IRenderManager));
l.RegisterConstant(new Mock<IStyler>().Object, typeof(IStyler));
l.RegisterConstant(new Mock<IWindowImpl>().Object, typeof(IWindowImpl));
}
}
}

122
Perspex.Layout.UnitTests/Perspex.Layout.UnitTests.csproj

@ -0,0 +1,122 @@
<?xml version="1.0" encoding="utf-8"?>
<Project ToolsVersion="12.0" DefaultTargets="Build" xmlns="http://schemas.microsoft.com/developer/msbuild/2003">
<PropertyGroup>
<Configuration Condition=" '$(Configuration)' == '' ">Debug</Configuration>
<Platform Condition=" '$(Platform)' == '' ">AnyCPU</Platform>
<ProjectGuid>{DB070A10-BF39-4752-8456-86E9D5928478}</ProjectGuid>
<OutputType>Library</OutputType>
<AppDesignerFolder>Properties</AppDesignerFolder>
<RootNamespace>Perspex.Layout.UnitTests</RootNamespace>
<AssemblyName>Perspex.Layout.UnitTests</AssemblyName>
<TargetFrameworkVersion>v4.5</TargetFrameworkVersion>
<FileAlignment>512</FileAlignment>
<ProjectTypeGuids>{3AC096D0-A1C2-E12C-1390-A8335801FDAB};{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}</ProjectTypeGuids>
<VisualStudioVersion Condition="'$(VisualStudioVersion)' == ''">10.0</VisualStudioVersion>
<VSToolsPath Condition="'$(VSToolsPath)' == ''">$(MSBuildExtensionsPath32)\Microsoft\VisualStudio\v$(VisualStudioVersion)</VSToolsPath>
<ReferencePath>$(ProgramFiles)\Common Files\microsoft shared\VSTT\$(VisualStudioVersion)\UITestExtensionPackages</ReferencePath>
<IsCodedUITest>False</IsCodedUITest>
<TestProjectType>UnitTest</TestProjectType>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Debug|AnyCPU' ">
<DebugSymbols>true</DebugSymbols>
<DebugType>full</DebugType>
<Optimize>false</Optimize>
<OutputPath>bin\Debug\</OutputPath>
<DefineConstants>DEBUG;TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<PropertyGroup Condition=" '$(Configuration)|$(Platform)' == 'Release|AnyCPU' ">
<DebugType>pdbonly</DebugType>
<Optimize>true</Optimize>
<OutputPath>bin\Release\</OutputPath>
<DefineConstants>TRACE</DefineConstants>
<ErrorReport>prompt</ErrorReport>
<WarningLevel>4</WarningLevel>
</PropertyGroup>
<ItemGroup>
<Reference Include="Moq">
<HintPath>..\packages\Moq.4.2.1409.1722\lib\net40\Moq.dll</HintPath>
</Reference>
<Reference Include="Moq.AutoMock">
<HintPath>..\packages\Moq.AutoMock.0.3.2.1\lib\net40\Moq.AutoMock.dll</HintPath>
</Reference>
<Reference Include="Splat">
<HintPath>..\packages\Splat.1.5.1\lib\Net45\Splat.dll</HintPath>
</Reference>
<Reference Include="System" />
</ItemGroup>
<Choose>
<When Condition="('$(VisualStudioVersion)' == '10.0' or '$(VisualStudioVersion)' == '') and '$(TargetFrameworkVersion)' == 'v3.5'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework, Version=10.1.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL" />
</ItemGroup>
</When>
<Otherwise>
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.UnitTestFramework" />
</ItemGroup>
</Otherwise>
</Choose>
<ItemGroup>
<Compile Include="LayoutableTests.cs" />
<Compile Include="Properties\AssemblyInfo.cs" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\Perspex.Base\Perspex.Base.csproj">
<Project>{b09b78d8-9b26-48b0-9149-d64a2f120f3f}</Project>
<Name>Perspex.Base</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.Controls\Perspex.Controls.csproj">
<Project>{d2221c82-4a25-4583-9b43-d791e3f6820c}</Project>
<Name>Perspex.Controls</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.Input\Perspex.Input.csproj">
<Project>{62024b2d-53eb-4638-b26b-85eeaa54866e}</Project>
<Name>Perspex.Input</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.Layout\Perspex.Layout.csproj">
<Project>{42472427-4774-4c81-8aff-9f27b8e31721}</Project>
<Name>Perspex.Layout</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.SceneGraph\Perspex.SceneGraph.csproj">
<Project>{eb582467-6abb-43a1-b052-e981ba910e3a}</Project>
<Name>Perspex.SceneGraph</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.Styling\Perspex.Styling.csproj">
<Project>{f1baa01a-f176-4c6a-b39d-5b40bb1b148f}</Project>
<Name>Perspex.Styling</Name>
</ProjectReference>
</ItemGroup>
<ItemGroup>
<None Include="app.config" />
<None Include="packages.config" />
</ItemGroup>
<Choose>
<When Condition="'$(VisualStudioVersion)' == '10.0' And '$(IsCodedUITest)' == 'True'">
<ItemGroup>
<Reference Include="Microsoft.VisualStudio.QualityTools.CodedUITestFramework, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Common, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITest.Extension, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
<Reference Include="Microsoft.VisualStudio.TestTools.UITesting, Version=10.0.0.0, Culture=neutral, PublicKeyToken=b03f5f7f11d50a3a, processorArchitecture=MSIL">
<Private>False</Private>
</Reference>
</ItemGroup>
</When>
</Choose>
<Import Project="$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets" Condition="Exists('$(VSToolsPath)\TeamTest\Microsoft.TestTools.targets')" />
<Import Project="$(MSBuildToolsPath)\Microsoft.CSharp.targets" />
<!-- To modify your build process, add your task inside one of the targets below and uncomment it.
Other similar extension points exist, see Microsoft.Common.targets.
<Target Name="BeforeBuild">
</Target>
<Target Name="AfterBuild">
</Target>
-->
</Project>

36
Perspex.Layout.UnitTests/Properties/AssemblyInfo.cs

@ -0,0 +1,36 @@
using System.Reflection;
using System.Runtime.CompilerServices;
using System.Runtime.InteropServices;
// General Information about an assembly is controlled through the following
// set of attributes. Change these attribute values to modify the information
// associated with an assembly.
[assembly: AssemblyTitle("Perspex.Layout.UnitTests")]
[assembly: AssemblyDescription("")]
[assembly: AssemblyConfiguration("")]
[assembly: AssemblyCompany("")]
[assembly: AssemblyProduct("Perspex.Layout.UnitTests")]
[assembly: AssemblyCopyright("Copyright © 2014")]
[assembly: AssemblyTrademark("")]
[assembly: AssemblyCulture("")]
// Setting ComVisible to false makes the types in this assembly not visible
// to COM components. If you need to access a type in this assembly from
// COM, set the ComVisible attribute to true on that type.
[assembly: ComVisible(false)]
// The following GUID is for the ID of the typelib if this project is exposed to COM
[assembly: Guid("dbe66cf2-493d-42f4-bd18-d56b15d5dffd")]
// Version information for an assembly consists of the following four values:
//
// Major Version
// Minor Version
// Build Number
// Revision
//
// You can specify all the values or you can default the Build and Revision Numbers
// by using the '*' as shown below:
// [assembly: AssemblyVersion("1.0.*")]
[assembly: AssemblyVersion("1.0.0.0")]
[assembly: AssemblyFileVersion("1.0.0.0")]

11
Perspex.Layout.UnitTests/app.config

@ -0,0 +1,11 @@
<?xml version="1.0" encoding="utf-8"?>
<configuration>
<runtime>
<assemblyBinding xmlns="urn:schemas-microsoft-com:asm.v1">
<dependentAssembly>
<assemblyIdentity name="Moq" publicKeyToken="69f491c39445e920" culture="neutral" />
<bindingRedirect oldVersion="0.0.0.0-4.2.1409.1722" newVersion="4.2.1409.1722" />
</dependentAssembly>
</assemblyBinding>
</runtime>
</configuration>

6
Perspex.Layout.UnitTests/packages.config

@ -0,0 +1,6 @@
<?xml version="1.0" encoding="utf-8"?>
<packages>
<package id="Moq" version="4.2.1409.1722" targetFramework="net45" />
<package id="Moq.AutoMock" version="0.3.2.1" targetFramework="net45" />
<package id="Splat" version="1.5.1" targetFramework="net45" />
</packages>

44
Perspex.Layout/ILayoutManager.cs

@ -9,16 +9,56 @@ namespace Perspex.Layout
using System;
using System.Reactive;
/// <summary>
/// Manages measuring and arranging of controls.
/// </summary>
/// <remarks>
/// Each layout root element such as a window has its own LayoutManager that is responsible
/// for laying out its child controls. When a layout is required the <see cref="LayoutNeeded"/>
/// observable will fire and the root element should respond by calling
/// <see cref="ExecuteLayoutPass"/> at the earliest opportunity to carry out the layout.
/// </remarks>
public interface ILayoutManager
{
/// <summary>
/// Gets or sets the root element that the manager is attached to.
/// </summary>
/// <remarks>
/// This must be set before the layout manager can be used.
/// </remarks>
ILayoutRoot Root { get; set; }
/// <summary>
/// Gets an observable that is fired when a layout pass is needed.
/// </summary>
IObservable<Unit> LayoutNeeded { get; }
/// <summary>
/// Gets a value indicating whether a layout is queued.
/// </summary>
/// <remarks>
/// Returns true when <see cref="LayoutNeeded"/> has been fired, but
/// <see cref="ExecuteLayoutPass"/> has not yet been called.
/// </remarks>
bool LayoutQueued { get; }
/// <summary>
/// Executes a layout pass.
/// </summary>
void ExecuteLayoutPass();
void InvalidateMeasure(ILayoutable item);
/// <summary>
/// Notifies the layout manager that a control requires a measure.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="distance">The control's distance from the layout root.</param>
void InvalidateMeasure(ILayoutable control, int distance);
void InvalidateArrange(ILayoutable item);
/// <summary>
/// Notifies the layout manager that a control requires an arrange.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="distance">The control's distance from the layout root.</param>
void InvalidateArrange(ILayoutable control, int distance);
}
}

13
Perspex.Layout/ILayoutable.cs

@ -6,6 +6,7 @@
namespace Perspex.Layout
{
// TODO: Probably want to move width/height/etc properties to different interface.
public interface ILayoutable : IVisual
{
Size? DesiredSize { get; }
@ -26,12 +27,20 @@ namespace Perspex.Layout
VerticalAlignment VerticalAlignment { get; }
void Arrange(Rect rect);
bool IsMeasureValid { get; }
bool IsArrangeValid { get; }
Size? PreviousMeasure { get; }
Rect? PreviousArrange { get; }
void Measure(Size availableSize);
void InvalidateArrange();
void Arrange(Rect rect);
void InvalidateMeasure();
void InvalidateArrange();
}
}

153
Perspex.Layout/LayoutManager.cs

@ -7,64 +7,191 @@
namespace Perspex.Layout
{
using System;
using System.Linq;
using System.Reactive;
using System.Reactive.Subjects;
using NGenerics.DataStructures.General;
/// <summary>
/// Manages measuring and arranging of controls.
/// </summary>
/// <remarks>
/// Each layout root element such as a window has its own LayoutManager that is responsible
/// for laying out its child controls. When a layout is required the <see cref="LayoutNeeded"/>
/// observable will fire and the root element should respond by calling
/// <see cref="ExecuteLayoutPass"/> at the earliest opportunity to carry out the layout.
/// </remarks>
public class LayoutManager : ILayoutManager
{
private ILayoutRoot root;
/// <summary>
/// The maximum number of times a measure/arrange loop can be retried.
/// </summary>
private const int MaxTries = 3;
/// <summary>
/// Called when a layout is needed.
/// </summary>
private Subject<Unit> layoutNeeded;
public LayoutManager(ILayoutRoot root)
{
Contract.Requires<NullReferenceException>(root != null);
/// <summary>
/// Whether a measure is needed on the next layout pass.
/// </summary>
private bool measureNeeded = true;
/// <summary>
/// The controls that need to be measured, sorted by distance to layout root.
/// </summary>
private Heap<Item> toMeasure = new Heap<Item>(HeapType.Minimum);
this.root = root;
/// <summary>
/// Initializes a new instance of the <see cref="LayoutManager"/> class.
/// </summary>
public LayoutManager()
{
this.layoutNeeded = new Subject<Unit>();
}
/// <summary>
/// Gets or sets the root element that the manager is attached to.
/// </summary>
/// <remarks>
/// This must be set before the layout manager can be used.
/// </remarks>
public ILayoutRoot Root
{
get;
set;
}
/// <summary>
/// Gets an observable that is fired when a layout pass is needed.
/// </summary>
public IObservable<Unit> LayoutNeeded
{
get { return this.layoutNeeded; }
}
/// <summary>
/// Gets a value indicating whether a layout is queued.
/// </summary>
/// <remarks>
/// Returns true when <see cref="LayoutNeeded"/> has been fired, but
/// <see cref="ExecuteLayoutPass"/> has not yet been called.
/// </remarks>
public bool LayoutQueued
{
get;
private set;
}
/// <summary>
/// Executes a layout pass.
/// </summary>
public void ExecuteLayoutPass()
{
this.LayoutQueued = false;
this.root.Measure(this.root.ClientSize);
this.root.Arrange(new Rect(this.root.ClientSize));
Layoutable.DebugMeasureCount = Layoutable.DebugArrangeCount = 0;
if (this.measureNeeded)
{
this.ExecuteMeasure();
this.measureNeeded = false;
}
this.Root.Arrange(new Rect(this.Root.ClientSize));
System.Diagnostics.Debug.WriteLine(Environment.TickCount + " " + Layoutable.DebugMeasureCount + " " + Layoutable.DebugArrangeCount);
}
public void InvalidateMeasure(ILayoutable item)
/// <summary>
/// Notifies the layout manager that a control requires a measure.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="distance">The control's distance from the layout root.</param>
public void InvalidateMeasure(ILayoutable control, int distance)
{
this.measureNeeded = true;
this.toMeasure.Add(new Item(control, distance));
if (!this.LayoutQueued)
{
IVisual visual = item as IVisual;
IVisual visual = control as IVisual;
this.layoutNeeded.OnNext(Unit.Default);
this.LayoutQueued = true;
}
}
public void InvalidateArrange(ILayoutable item)
/// <summary>
/// Notifies the layout manager that a control requires an arrange.
/// </summary>
/// <param name="control">The control.</param>
/// <param name="distance">The control's distance from the layout root.</param>
public void InvalidateArrange(ILayoutable control, int distance)
{
//this.toArrange.Add(item);
if (!this.LayoutQueued)
{
IVisual visual = item as IVisual;
IVisual visual = control as IVisual;
this.layoutNeeded.OnNext(Unit.Default);
this.LayoutQueued = true;
}
}
public void LayoutFinished()
private void ExecuteMeasure()
{
this.LayoutQueued = false;
for (int i = 0; i < MaxTries; ++i)
{
var measure = this.toMeasure;
this.toMeasure = new Heap<Item>(HeapType.Minimum);
if (!this.Root.IsMeasureValid)
{
this.Root.Measure(this.Root.ClientSize);
}
else
{
foreach (var item in measure)
{
if (!item.Control.IsMeasureValid)
{
var control = item.Control;
while (!control.PreviousMeasure.HasValue)
{
control = (ILayoutable)control.VisualParent;
}
control.Measure(control.PreviousMeasure.Value);
}
}
}
if (this.toMeasure.Count == 0)
{
break;
}
}
}
private class Item : IComparable<Item>
{
public Item(ILayoutable control, int distance)
{
this.Control = control;
this.Distance = distance;
}
public ILayoutable Control { get; private set; }
public int Distance { get; private set; }
public int CompareTo(Item other)
{
return this.Distance - other.Distance;
}
}
}
}

89
Perspex.Layout/Layoutable.cs

@ -58,6 +58,24 @@ namespace Perspex.Layout
public static readonly PerspexProperty<VerticalAlignment> VerticalAlignmentProperty =
PerspexProperty.Register<Layoutable, VerticalAlignment>("VerticalAlignment");
private Size? previousMeasure;
private Rect? previousArrange;
static Layoutable()
{
Layoutable.AffectsMeasure(IsVisibleProperty);
Layoutable.AffectsMeasure(WidthProperty);
Layoutable.AffectsMeasure(HeightProperty);
Layoutable.AffectsMeasure(MinWidthProperty);
Layoutable.AffectsMeasure(MaxWidthProperty);
Layoutable.AffectsMeasure(MinHeightProperty);
Layoutable.AffectsMeasure(MaxHeightProperty);
Layoutable.AffectsMeasure(MarginProperty);
Layoutable.AffectsMeasure(HorizontalAlignmentProperty);
Layoutable.AffectsMeasure(VerticalAlignmentProperty);
}
public double Width
{
get { return this.GetValue(WidthProperty); }
@ -123,6 +141,31 @@ namespace Perspex.Layout
set;
}
public bool IsMeasureValid
{
get;
private set;
}
public bool IsArrangeValid
{
get;
private set;
}
Size? ILayoutable.PreviousMeasure
{
get { return this.previousMeasure; }
}
Rect? ILayoutable.PreviousArrange
{
get { return this.previousArrange; }
}
public static int DebugMeasureCount { get; set; }
public static int DebugArrangeCount { get; set; }
public void Measure(Size availableSize)
{
if (double.IsNaN(availableSize.Width) || double.IsNaN(availableSize.Height))
@ -130,8 +173,11 @@ namespace Perspex.Layout
throw new InvalidOperationException("Cannot call Measure using a size with NaN values.");
}
availableSize = availableSize.Deflate(this.Margin);
++DebugMeasureCount;
this.DesiredSize = this.MeasureCore(availableSize).Constrain(availableSize);
this.IsMeasureValid = true;
this.previousMeasure = availableSize;
this.Log().Debug(
"Measure of {0} (#{1:x8}) requested {2} ",
@ -154,35 +200,40 @@ namespace Perspex.Layout
throw new InvalidOperationException("Arrange called before Measure.");
}
++DebugArrangeCount;
this.Log().Debug(
"Arrange of {0} (#{1:x8}) gave {2} ",
this.GetType().Name,
this.GetHashCode(),
rect);
if (this.DesiredSize.HasValue)
{
this.ArrangeCore(rect);
}
this.ArrangeCore(rect);
this.previousArrange = rect;
}
public void InvalidateMeasure()
{
ILayoutRoot root = this.GetLayoutRoot();
var root = this.GetLayoutRoot();
this.IsMeasureValid = false;
if (root != null && root.LayoutManager != null)
if (root != null && root.Item1.LayoutManager != null)
{
root.LayoutManager.InvalidateMeasure(this);
root.Item1.LayoutManager.InvalidateMeasure(this, root.Item2);
}
}
public void InvalidateArrange()
{
ILayoutRoot root = this.GetLayoutRoot();
var root = this.GetLayoutRoot();
if (root != null)
this.IsMeasureValid = false;
this.IsArrangeValid = false;
if (root != null && root.Item1.LayoutManager != null)
{
root.LayoutManager.InvalidateArrange(this);
root.Item1.LayoutManager.InvalidateArrange(this, root.Item2);
}
}
@ -265,7 +316,8 @@ namespace Perspex.Layout
{
this.ApplyTemplate();
var constrained = LayoutHelper.ApplyLayoutConstraints(this, availableSize)
var constrained = LayoutHelper
.ApplyLayoutConstraints(this, availableSize)
.Deflate(this.Margin);
var measured = this.MeasureOverride(constrained);
@ -331,9 +383,18 @@ namespace Perspex.Layout
}
}
private ILayoutRoot GetLayoutRoot()
private Tuple<ILayoutRoot, int> GetLayoutRoot()
{
return this.GetSelfAndVisualAncestors().OfType<ILayoutRoot>().FirstOrDefault();
var control = (IVisual)this;
var distance = 0;
while (control != null && !(control is ILayoutRoot))
{
control = control.GetVisualParent();
++distance;
}
return control != null ? Tuple.Create((ILayoutRoot)control, distance) : null;
}
}
}

4
Perspex.Layout/Perspex.Layout.csproj

@ -35,6 +35,10 @@
</PropertyGroup>
<ItemGroup>
<!-- A reference to the entire .NET Framework is automatically included -->
<ProjectReference Include="..\NGenerics\NGenerics.csproj">
<Project>{415e048e-4611-4815-9cf2-d774e29079ac}</Project>
<Name>NGenerics</Name>
</ProjectReference>
<ProjectReference Include="..\Perspex.Base\Perspex.Base.csproj">
<Project>{B09B78D8-9B26-48B0-9149-D64A2F120F3F}</Project>
<Name>Perspex.Base</Name>

9
Perspex.sln

@ -51,6 +51,10 @@ Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestApplication-Mono", "Tes
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Perspex.Base.UnitTests", "Perspex.Base.UnitTests\Perspex.Base.UnitTests.csproj", "{2905FF23-53FB-45E6-AA49-6AF47A172056}"
EndProject
Project("{2150E333-8FDC-42A3-9474-1A3956D46DE8}") = "Utils", "Utils", "{2BAFBE53-7FA4-4BB9-976F-9AFCC4F9847D}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "NGenerics", "NGenerics\NGenerics.csproj", "{415E048E-4611-4815-9CF2-D774E29079AC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
@ -140,6 +144,10 @@ Global
{2905FF23-53FB-45E6-AA49-6AF47A172056}.Debug|Any CPU.Build.0 = Debug|Any CPU
{2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|Any CPU.ActiveCfg = Release|Any CPU
{2905FF23-53FB-45E6-AA49-6AF47A172056}.Release|Any CPU.Build.0 = Release|Any CPU
{415E048E-4611-4815-9CF2-D774E29079AC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{415E048E-4611-4815-9CF2-D774E29079AC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{415E048E-4611-4815-9CF2-D774E29079AC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{415E048E-4611-4815-9CF2-D774E29079AC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
@ -150,5 +158,6 @@ Global
{DABFD304-D6A4-4752-8123-C2CCF7AC7831} = {B39A8919-9F95-48FE-AD7B-76E08B509888}
{FB05AC90-89BA-4F2F-A924-F37875FB547C} = {1D577B69-F23B-4C4F-8605-97704DAC75A9}
{54F237D5-A70A-4752-9656-0C70B1A7B047} = {554AF661-FE23-4647-930E-48B617E68F9D}
{415E048E-4611-4815-9CF2-D774E29079AC} = {2BAFBE53-7FA4-4BB9-976F-9AFCC4F9847D}
EndGlobalSection
EndGlobal

65
TestApplication/Program.cs

@ -113,36 +113,49 @@ namespace TestApplication
Window window = new Window
{
Title = "Perspex Test Application",
Content = new Grid
Content = new ScrollViewer
{
RowDefinitions = new RowDefinitions
Width = 200,
Height = 200,
HorizontalAlignment = HorizontalAlignment.Center,
VerticalAlignment = VerticalAlignment.Center,
Content = new Image
{
new RowDefinition(1, GridUnitType.Star),
new RowDefinition(GridLength.Auto),
Source = new Bitmap("github_icon.png"),
Width = 400,
Height = 400,
},
Children = new Controls
{
new TabControl
{
Items = new[]
{
ButtonsTab(),
TextTab(),
ImagesTab(),
ListsTab(),
SlidersTab(),
LayoutTab(),
}
},
new TextBlock
{
Text = "Press F12 for Dev Tools",
HorizontalAlignment = HorizontalAlignment.Right,
Margin = new Thickness(2),
[Grid.RowProperty] = 1,
}
}
},
//Content = new Grid
//{
// RowDefinitions = new RowDefinitions
// {
// new RowDefinition(1, GridUnitType.Star),
// new RowDefinition(GridLength.Auto),
// },
// Children = new Controls
// {
// new TabControl
// {
// Items = new[]
// {
// ButtonsTab(),
// TextTab(),
// ImagesTab(),
// ListsTab(),
// SlidersTab(),
// LayoutTab(),
// }
// },
// new TextBlock
// {
// Text = "Press F12 for Dev Tools",
// HorizontalAlignment = HorizontalAlignment.Right,
// Margin = new Thickness(2),
// [Grid.RowProperty] = 1,
// }
// }
//},
};
DevTools.Attach(window);

12
Windows/Perspex.Direct2D1/Renderer.cs

@ -133,11 +133,21 @@ namespace Perspex.Direct2D1
transform *= Matrix.Translation(visual.Bounds.Position);
using (context.PushClip(visual.Bounds))
//using (context.PushClip(visual.Bounds))
using (context.PushTransform(transform))
{
visual.Render(context);
context.DrawRectange(new Pen(Brushes.Red, 0.5), visual.Bounds);
context.DrawText(Brushes.Red, visual.Bounds, new FormattedText
{
Text = visual.GetType().Name,
FontFamilyName = "Seguo UI",
FontSize = 16,
FontStyle = FontStyle.Normal,
});
foreach (var child in visual.VisualChildren)
{
this.Render(child, context);

2
Windows/Perspex.Direct2D1/TextService.cs

@ -35,7 +35,7 @@ namespace Perspex.Direct2D1
{
return new TextLayout(
factory,
text.Text,
text.Text ?? string.Empty,
GetTextFormat(factory, text),
(float)constraint.Width,
(float)constraint.Height);

Loading…
Cancel
Save