diff --git a/Perspex.Windows/Window.cs b/Perspex.Windows/Window.cs index 8e076cb0dd..d169582299 100644 --- a/Perspex.Windows/Window.cs +++ b/Perspex.Windows/Window.cs @@ -5,11 +5,10 @@ using System.Diagnostics.CodeAnalysis; using System.Runtime.InteropServices; using Perspex.Controls; + using Perspex.Layout; using Perspex.Windows.Interop; - using SharpDX.Direct2D1; - using SharpDX.DXGI; - public class Window : ContentControl + public class Window : ContentControl, ILayoutRoot { private UnmanagedMethods.WndProc wndProcDelegate; @@ -20,9 +19,15 @@ public Window() { this.CreateWindow(); - Size clientSize = this.ClientSize; + this.LayoutManager = new LayoutManager(); this.renderer = new Renderer(this.Handle, (int)clientSize.Width, (int)clientSize.Height); + + this.LayoutManager.LayoutNeeded.Subscribe(x => + { + this.LayoutManager.ExecuteLayoutPass(); + this.renderer.Render(this); + }); } public Size ClientSize @@ -41,12 +46,15 @@ private set; } + public ILayoutManager LayoutManager + { + get; + private set; + } + public void Show() { UnmanagedMethods.ShowWindow(this.Handle, 4); - this.Measure(this.ClientSize); - this.Arrange(new Rect(this.ClientSize)); - this.renderer.Render(this); } protected override Visual DefaultTemplate() @@ -133,14 +141,10 @@ //// InputManager.Current.ProcessInput(new RawMouseEventArgs(mouse, RawMouseEventType.Move)); //// break; - ////case UnmanagedMethods.WindowsMessage.WM_SIZE: - //// if (this.renderTarget != null) - //// { - //// this.renderTarget.Resize(new SharpDX.DrawingSize((int)lParam & 0xffff, (int)lParam >> 16)); - //// } - - //// this.OnResized(); - //// return IntPtr.Zero; + case UnmanagedMethods.WindowsMessage.WM_SIZE: + this.renderer.Resize((int)lParam & 0xffff, (int)lParam >> 16); + this.InvalidateMeasure(); + return IntPtr.Zero; } return UnmanagedMethods.DefWindowProc(hWnd, msg, wParam, lParam); diff --git a/Perspex/Controls/Control.cs b/Perspex/Controls/Control.cs index 6d1241b54d..5d3c9eb22c 100644 --- a/Perspex/Controls/Control.cs +++ b/Perspex/Controls/Control.cs @@ -1,6 +1,8 @@ namespace Perspex.Controls { + using System; using System.Diagnostics.Contracts; + using Perspex.Layout; public enum HorizontalAlignment { @@ -18,7 +20,7 @@ Bottom, } - public abstract class Control : Visual + public abstract class Control : Visual, ILayoutable { public static readonly PerspexProperty HorizontalAlignmentProperty = PerspexProperty.Register("HorizontalAlignment"); @@ -53,6 +55,24 @@ set { this.SetValue(MarginProperty, value); } } + public Control Parent + { + get; + internal set; + } + + public ILayoutRoot GetLayoutRoot() + { + Control c = this; + + while (c != null && !(c is ILayoutRoot)) + { + c = c.Parent; + } + + return (ILayoutRoot)c; + } + public void Arrange(Rect rect) { this.Bounds = new Rect( @@ -66,6 +86,16 @@ this.DesiredSize = this.MeasureContent(availableSize).Constrain(availableSize); } + public void InvalidateArrange() + { + this.GetLayoutRoot().LayoutManager.InvalidateArrange(this); + } + + public void InvalidateMeasure() + { + this.GetLayoutRoot().LayoutManager.InvalidateMeasure(this); + } + protected virtual Size ArrangeContent(Size finalSize) { return finalSize; diff --git a/Perspex/Layout/ILayoutManager.cs b/Perspex/Layout/ILayoutManager.cs new file mode 100644 index 0000000000..2318c5edbc --- /dev/null +++ b/Perspex/Layout/ILayoutManager.cs @@ -0,0 +1,23 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2013 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Layout +{ + using System; + using System.Reactive; + using Perspex.Controls; + + public interface ILayoutManager + { + IObservable LayoutNeeded { get; } + + void ExecuteLayoutPass(); + + void InvalidateMeasure(ILayoutable item); + + void InvalidateArrange(ILayoutable item); + } +} diff --git a/Perspex/Layout/ILayoutRoot.cs b/Perspex/Layout/ILayoutRoot.cs new file mode 100644 index 0000000000..4962760a21 --- /dev/null +++ b/Perspex/Layout/ILayoutRoot.cs @@ -0,0 +1,15 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2013 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Layout +{ + public interface ILayoutRoot : ILayoutable + { + Size ClientSize { get; } + + ILayoutManager LayoutManager { get; } + } +} diff --git a/Perspex/Layout/ILayoutable.cs b/Perspex/Layout/ILayoutable.cs new file mode 100644 index 0000000000..56641ccdd8 --- /dev/null +++ b/Perspex/Layout/ILayoutable.cs @@ -0,0 +1,23 @@ +// ----------------------------------------------------------------------- +// +// Copyright 2013 MIT Licence. See licence.md for more information. +// +// ----------------------------------------------------------------------- + +namespace Perspex.Layout +{ + public interface ILayoutable + { + Size? DesiredSize { get; } + + ILayoutRoot GetLayoutRoot(); + + void Arrange(Rect rect); + + void Measure(Size availableSize); + + void InvalidateArrange(); + + void InvalidateMeasure(); + } +} diff --git a/Perspex/Layout/LayoutManager.cs b/Perspex/Layout/LayoutManager.cs new file mode 100644 index 0000000000..0e4ed95f1a --- /dev/null +++ b/Perspex/Layout/LayoutManager.cs @@ -0,0 +1,48 @@ +namespace Perspex.Layout +{ + using System; + using System.Collections.Generic; + using System.Reactive; + using System.Reactive.Subjects; + using Perspex.Controls; + + public class LayoutManager : ILayoutManager + { + private ILayoutRoot root; + + private Subject layoutNeeded; + + public LayoutManager() + { + this.layoutNeeded = new Subject(); + } + + public IObservable LayoutNeeded + { + get { return this.layoutNeeded; } + } + + public void ExecuteLayoutPass() + { + if (root != null) + { + root.Measure(root.ClientSize); + root.Arrange(new Rect(root.ClientSize)); + } + + root = null; + } + + public void InvalidateMeasure(ILayoutable item) + { + this.root = item.GetLayoutRoot(); + this.layoutNeeded.OnNext(Unit.Default); + } + + public void InvalidateArrange(ILayoutable item) + { + this.root = item.GetLayoutRoot(); + this.layoutNeeded.OnNext(Unit.Default); + } + } +} diff --git a/Perspex/Perspex.csproj b/Perspex/Perspex.csproj index 24155f752f..613d2206c8 100644 --- a/Perspex/Perspex.csproj +++ b/Perspex/Perspex.csproj @@ -74,6 +74,10 @@ + + + + diff --git a/TestApplication/Program.cs b/TestApplication/Program.cs index 364e1270d5..e079f21198 100644 --- a/TestApplication/Program.cs +++ b/TestApplication/Program.cs @@ -9,6 +9,7 @@ using Perspex.Media; using Perspex.Windows; using Perspex.Windows.Media; using Perspex.Windows.Threading; + namespace TestApplication { class Program