Scene.cs 3.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134
  1. // Copyright (c) The Avalonia Project. All rights reserved.
  2. // Licensed under the MIT license. See licence.md file in the project root for full license information.
  3. using System;
  4. using System.Collections.Generic;
  5. using Avalonia;
  6. using Avalonia.VisualTree;
  7. namespace Avalonia.Rendering.SceneGraph
  8. {
  9. public class Scene
  10. {
  11. private Dictionary<IVisual, IVisualNode> _index;
  12. public Scene(IVisual rootVisual)
  13. : this(
  14. new VisualNode(rootVisual, null),
  15. new Dictionary<IVisual, IVisualNode>(),
  16. new SceneLayers(rootVisual),
  17. 0)
  18. {
  19. _index.Add(rootVisual, Root);
  20. }
  21. internal Scene(VisualNode root, Dictionary<IVisual, IVisualNode> index, SceneLayers layers, int id)
  22. {
  23. Contract.Requires<ArgumentNullException>(root != null);
  24. var renderRoot = root.Visual as IRenderRoot;
  25. _index = index;
  26. Root = root;
  27. Layers = layers;
  28. Id = id;
  29. root.LayerRoot = root.Visual;
  30. }
  31. public int Id { get; }
  32. public SceneLayers Layers { get; }
  33. public IVisualNode Root { get; }
  34. public Size Size { get; set; }
  35. public double Scaling { get; set; } = 1;
  36. public void Add(IVisualNode node)
  37. {
  38. Contract.Requires<ArgumentNullException>(node != null);
  39. _index.Add(node.Visual, node);
  40. }
  41. public Scene Clone()
  42. {
  43. var index = new Dictionary<IVisual, IVisualNode>();
  44. var root = Clone((VisualNode)Root, null, index);
  45. var result = new Scene(root, index, Layers.Clone(), Id + 1)
  46. {
  47. Size = Size,
  48. Scaling = Scaling,
  49. };
  50. return result;
  51. }
  52. public IVisualNode FindNode(IVisual visual)
  53. {
  54. IVisualNode node;
  55. _index.TryGetValue(visual, out node);
  56. return node;
  57. }
  58. public IEnumerable<IVisual> HitTest(Point p, Func<IVisual, bool> filter)
  59. {
  60. return HitTest(Root, p, null, filter);
  61. }
  62. public void Remove(IVisualNode node)
  63. {
  64. Contract.Requires<ArgumentNullException>(node != null);
  65. _index.Remove(node.Visual);
  66. }
  67. private VisualNode Clone(VisualNode source, IVisualNode parent, Dictionary<IVisual, IVisualNode> index)
  68. {
  69. var result = source.Clone(parent);
  70. index.Add(result.Visual, result);
  71. foreach (var child in source.Children)
  72. {
  73. result.AddChild(Clone((VisualNode)child, result, index));
  74. }
  75. return result;
  76. }
  77. private IEnumerable<IVisual> HitTest(IVisualNode node, Point p, Rect? clip, Func<IVisual, bool> filter)
  78. {
  79. if (filter?.Invoke(node.Visual) != false)
  80. {
  81. var clipped = false;
  82. if (node.ClipToBounds)
  83. {
  84. clip = clip == null ? node.ClipBounds : clip.Value.Intersect(node.ClipBounds);
  85. clipped = !clip.Value.Contains(p);
  86. }
  87. if (node.GeometryClip != null)
  88. {
  89. var controlPoint = Root.Visual.TranslatePoint(p, node.Visual);
  90. clipped = !node.GeometryClip.FillContains(p);
  91. }
  92. if (!clipped)
  93. {
  94. for (var i = node.Children.Count - 1; i >= 0; --i)
  95. {
  96. foreach (var h in HitTest(node.Children[i], p, clip, filter))
  97. {
  98. yield return h;
  99. }
  100. }
  101. if (node.HitTest(p))
  102. {
  103. yield return node.Visual;
  104. }
  105. }
  106. }
  107. }
  108. }
  109. }