A game framework written with osu! in mind.
at master 87 lines 3.7 kB view raw
1// Copyright (c) ppy Pty Ltd <contact@ppy.sh>. Licensed under the MIT Licence. 2// See the LICENCE file in the repository root for full licence text. 3 4using System; 5using osu.Framework.Allocation; 6using osu.Framework.Bindables; 7using osu.Framework.Extensions.EnumExtensions; 8using osu.Framework.Graphics.Primitives; 9using osu.Framework.Layout; 10 11namespace osu.Framework.Graphics.Containers 12{ 13 /// <summary> 14 /// An <see cref="Container"/> that can also apply a padding based on the safe areas of the nearest cached <see cref="SafeAreaDefiningContainer"/>. 15 /// Padding will only be applied if the contents of this container would otherwise intersect the safe area margins relative to the associated target container. 16 /// </summary> 17 public class SafeAreaContainer : Container 18 { 19 private readonly BindableSafeArea safeAreaPadding = new BindableSafeArea(); 20 21 public SafeAreaContainer() 22 { 23 AddLayout(PaddingCache); 24 } 25 26 [BackgroundDependencyLoader] 27 private void load() 28 { 29 safeAreaPadding.ValueChanged += _ => PaddingCache.Invalidate(); 30 safeAreaPadding.BindTo(safeArea.SafeAreaPadding); 31 } 32 33 [Resolved(CanBeNull = true)] 34 private ISafeArea safeArea { get; set; } 35 36 /// <summary> 37 /// The <see cref="Edges"/> that should bypass the defined <see cref="ISafeArea" /> to bleed to the screen edge. 38 /// Defaults to <see cref="Edges.None"/>. 39 /// </summary> 40 public Edges SafeAreaOverrideEdges 41 { 42 get => safeAreaOverrideEdges; 43 set 44 { 45 safeAreaOverrideEdges = value; 46 PaddingCache.Invalidate(); 47 } 48 } 49 50 private Edges safeAreaOverrideEdges = Edges.None; 51 52 protected readonly LayoutValue PaddingCache = new LayoutValue(Invalidation.DrawInfo | Invalidation.RequiredParentSizeToFit); 53 54 protected override void UpdateAfterChildrenLife() 55 { 56 base.UpdateAfterChildrenLife(); 57 58 if (!PaddingCache.IsValid) 59 { 60 Padding = getPadding(); 61 PaddingCache.Validate(); 62 } 63 } 64 65 private MarginPadding getPadding() 66 { 67 if (safeArea == null) 68 return new MarginPadding(); 69 70 var nonSafeLocalSpace = safeArea.ExpandRectangleToSpaceOfOtherDrawable(this); 71 72 var nonSafe = safeArea.AvailableNonSafeSpace; 73 74 var paddedRect = new RectangleF(nonSafe.X + safeAreaPadding.Value.Left, nonSafe.Y + safeAreaPadding.Value.Top, nonSafe.Width - safeAreaPadding.Value.TotalHorizontal, nonSafe.Height - safeAreaPadding.Value.TotalVertical); 75 var localTopLeft = safeArea.ToSpaceOfOtherDrawable(paddedRect.TopLeft, this); 76 var localBottomRight = safeArea.ToSpaceOfOtherDrawable(paddedRect.BottomRight, this); 77 78 return new MarginPadding 79 { 80 Left = SafeAreaOverrideEdges.HasFlagFast(Edges.Left) ? nonSafeLocalSpace.TopLeft.X : Math.Clamp(localTopLeft.X, 0, DrawSize.X), 81 Right = SafeAreaOverrideEdges.HasFlagFast(Edges.Right) ? DrawRectangle.BottomRight.X - nonSafeLocalSpace.BottomRight.X : Math.Clamp(DrawSize.X - localBottomRight.X, 0, DrawSize.X), 82 Top = SafeAreaOverrideEdges.HasFlagFast(Edges.Top) ? nonSafeLocalSpace.TopLeft.Y : Math.Clamp(localTopLeft.Y, 0, DrawSize.Y), 83 Bottom = SafeAreaOverrideEdges.HasFlagFast(Edges.Bottom) ? DrawRectangle.BottomRight.Y - nonSafeLocalSpace.BottomRight.Y : Math.Clamp(DrawSize.Y - localBottomRight.Y, 0, DrawSize.Y) 84 }; 85 } 86 } 87}