From 38a3db18cb34a8ec6585b7d137035bc23510001f Mon Sep 17 00:00:00 2001 From: Steven Kirk Date: Thu, 17 Jan 2019 14:42:12 +0100 Subject: [PATCH] Added IRenderer.SceneInvalidated event. And use this event to trigger an update of the mouse pointer-over state. --- src/Avalonia.Controls/TopLevel.cs | 6 ++-- .../Rendering/DeferredRenderer.cs | 18 ++++++++++ src/Avalonia.Visuals/Rendering/IRenderer.cs | 13 +++++-- .../Rendering/ImmediateRenderer.cs | 5 +++ .../Rendering/SceneInvalidatedEventArgs.cs | 36 +++++++++++++++++++ tests/Avalonia.LeakTests/ControlTests.cs | 1 + 6 files changed, 74 insertions(+), 5 deletions(-) create mode 100644 src/Avalonia.Visuals/Rendering/SceneInvalidatedEventArgs.cs diff --git a/src/Avalonia.Controls/TopLevel.cs b/src/Avalonia.Controls/TopLevel.cs index 10419131eb..294b15a564 100644 --- a/src/Avalonia.Controls/TopLevel.cs +++ b/src/Avalonia.Controls/TopLevel.cs @@ -97,6 +97,7 @@ namespace Avalonia.Controls _renderInterface = TryGetService(dependencyResolver); Renderer = impl.CreateRenderer(this); + Renderer.SceneInvalidated += SceneInvalidated; impl.SetInputRoot(this); @@ -230,7 +231,6 @@ namespace Avalonia.Controls void IRenderRoot.Invalidate(Rect rect) { PlatformImpl?.Invalidate(rect); - UpdatePointerOver(rect); } /// @@ -351,9 +351,9 @@ namespace Avalonia.Controls _inputManager.ProcessInput(e); } - private void UpdatePointerOver(Rect rect) + private void SceneInvalidated(object sender, SceneInvalidatedEventArgs e) { - (this as IInputRoot).MouseDevice.SceneInvalidated(this, rect); + (this as IInputRoot).MouseDevice.SceneInvalidated(this, e.DirtyRect); } } } diff --git a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs index b48efaa34e..0808957482 100644 --- a/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/DeferredRenderer.cs @@ -99,6 +99,9 @@ namespace Avalonia.Rendering /// public string DebugFramesPath { get; set; } + /// + public event EventHandler SceneInvalidated; + /// /// Gets the render layers. /// @@ -470,6 +473,21 @@ namespace Avalonia.Rendering oldScene?.Dispose(); } + if (SceneInvalidated != null) + { + var rect = new Rect(); + + foreach (var layer in scene.Layers) + { + foreach (var dirty in layer.Dirty) + { + rect = rect.Union(dirty); + } + } + + SceneInvalidated(this, new SceneInvalidatedEventArgs((IRenderRoot)_root, rect)); + } + _dirty.Clear(); } else diff --git a/src/Avalonia.Visuals/Rendering/IRenderer.cs b/src/Avalonia.Visuals/Rendering/IRenderer.cs index 9085e63aa9..36a1f7d220 100644 --- a/src/Avalonia.Visuals/Rendering/IRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/IRenderer.cs @@ -18,11 +18,20 @@ namespace Avalonia.Rendering bool DrawFps { get; set; } /// - /// Gets or sets a value indicating whether the renderer should a visual representation + /// Gets or sets a value indicating whether the renderer should draw a visual representation /// of its dirty rectangles. /// bool DrawDirtyRects { get; set; } + /// + /// Raised when a portion of the scene has been invalidated. + /// + /// + /// Indicates that the underlying low-level scene information has been updated. Used to + /// signal that an update to the current pointer-over state may be required. + /// + event EventHandler SceneInvalidated; + /// /// Mark a visual as dirty and needing re-rendering. /// @@ -63,4 +72,4 @@ namespace Avalonia.Rendering /// void Stop(); } -} \ No newline at end of file +} diff --git a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs index 03ac004fd5..21129e38af 100644 --- a/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs +++ b/src/Avalonia.Visuals/Rendering/ImmediateRenderer.cs @@ -42,6 +42,9 @@ namespace Avalonia.Rendering /// public bool DrawDirtyRects { get; set; } + /// + public event EventHandler SceneInvalidated; + /// public void Paint(Rect rect) { @@ -81,6 +84,8 @@ namespace Avalonia.Rendering _renderTarget.Dispose(); _renderTarget = null; } + + SceneInvalidated?.Invoke(this, new SceneInvalidatedEventArgs((IRenderRoot)_root, rect)); } /// diff --git a/src/Avalonia.Visuals/Rendering/SceneInvalidatedEventArgs.cs b/src/Avalonia.Visuals/Rendering/SceneInvalidatedEventArgs.cs new file mode 100644 index 0000000000..40cb9f3356 --- /dev/null +++ b/src/Avalonia.Visuals/Rendering/SceneInvalidatedEventArgs.cs @@ -0,0 +1,36 @@ +// Copyright (c) The Avalonia Project. All rights reserved. +// Licensed under the MIT license. See licence.md file in the project root for full license information. + +using System; + +namespace Avalonia.Rendering +{ + /// + /// Provides data for the event. + /// + public class SceneInvalidatedEventArgs : EventArgs + { + /// + /// Initializes a new instance of the class. + /// + /// The render root that has been updated. + /// The updated area. + public SceneInvalidatedEventArgs( + IRenderRoot root, + Rect dirtyRect) + { + RenderRoot = root; + DirtyRect = dirtyRect; + } + + /// + /// Gets the invalidated area. + /// + public Rect DirtyRect { get; } + + /// + /// Gets the render root that has been invalidated. + /// + public IRenderRoot RenderRoot { get; } + } +} diff --git a/tests/Avalonia.LeakTests/ControlTests.cs b/tests/Avalonia.LeakTests/ControlTests.cs index 4dcd98cb93..b7aa452a18 100644 --- a/tests/Avalonia.LeakTests/ControlTests.cs +++ b/tests/Avalonia.LeakTests/ControlTests.cs @@ -348,6 +348,7 @@ namespace Avalonia.LeakTests { public bool DrawFps { get; set; } public bool DrawDirtyRects { get; set; } + public event EventHandler SceneInvalidated; public void AddDirty(IVisual visual) {