A game framework written with osu! in mind.
at master 227 lines 6.9 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.Threading; 5using osu.Framework.Graphics.Containers; 6using osu.Framework.Graphics.Sprites; 7using osu.Framework.Logging; 8using osuTK; 9using osuTK.Graphics; 10using osu.Framework.Allocation; 11using osu.Framework.Configuration; 12using osu.Framework.Development; 13using osu.Framework.Timing; 14using osuTK.Input; 15using osu.Framework.Graphics.Shapes; 16using osu.Framework.Input.Events; 17 18namespace osu.Framework.Graphics.Visualisation 19{ 20 internal class LogOverlay : OverlayContainer 21 { 22 private readonly FillFlowContainer flow; 23 24 protected override bool BlockPositionalInput => false; 25 26 private StopwatchClock clock; 27 28 private readonly Box box; 29 30 private const float background_alpha = 0.6f; 31 32 public LogOverlay() 33 { 34 //todo: use Input as font 35 36 Width = 700; 37 AutoSizeAxes = Axes.Y; 38 39 Anchor = Anchor.BottomLeft; 40 Origin = Anchor.BottomLeft; 41 42 Margin = new MarginPadding(1); 43 44 Masking = true; 45 46 Children = new Drawable[] 47 { 48 box = new Box 49 { 50 RelativeSizeAxes = Axes.Both, 51 Colour = Color4.Black, 52 Alpha = background_alpha, 53 }, 54 flow = new FillFlowContainer 55 { 56 RelativeSizeAxes = Axes.X, 57 AutoSizeAxes = Axes.Y, 58 } 59 }; 60 } 61 62 protected override void LoadComplete() 63 { 64 // custom clock is used to adjust log display speed (to freeze log display with a key). 65 Clock = new FramedClock(clock = new StopwatchClock(true)); 66 67 base.LoadComplete(); 68 69 addEntry(new LogEntry 70 { 71 Level = LogLevel.Important, 72 Message = "The debug log overlay is currently being displayed. You can toggle with Ctrl+F10 at any point.", 73 Target = LoggingTarget.Information, 74 }); 75 } 76 77 private int logPosition; 78 79 private void addEntry(LogEntry entry) 80 { 81 if (!DebugUtils.IsDebugBuild && entry.Level <= LogLevel.Verbose) 82 return; 83 84 int pos = Interlocked.Increment(ref logPosition); 85 86 Schedule(() => 87 { 88 const int display_length = 4000; 89 90 LoadComponentAsync(new DrawableLogEntry(entry), drawEntry => 91 { 92 flow.Insert(pos, drawEntry); 93 94 drawEntry.FadeInFromZero(800, Easing.OutQuint).Delay(display_length).FadeOut(800, Easing.InQuint); 95 drawEntry.Expire(); 96 }); 97 }); 98 } 99 100 protected override bool OnKeyDown(KeyDownEvent e) 101 { 102 if (!e.Repeat) 103 setHoldState(e.Key == Key.ControlLeft || e.Key == Key.ControlRight); 104 105 return base.OnKeyDown(e); 106 } 107 108 protected override void OnKeyUp(KeyUpEvent e) 109 { 110 if (!e.ControlPressed) 111 setHoldState(false); 112 base.OnKeyUp(e); 113 } 114 115 private void setHoldState(bool controlPressed) 116 { 117 box.Alpha = controlPressed ? 1 : background_alpha; 118 if (clock != null) clock.Rate = controlPressed ? 0 : 1; 119 } 120 121 [BackgroundDependencyLoader] 122 private void load(FrameworkConfigManager config) 123 { 124 } 125 126 protected override void PopIn() 127 { 128 Logger.NewEntry += addEntry; 129 this.FadeIn(100); 130 } 131 132 protected override void PopOut() 133 { 134 Logger.NewEntry -= addEntry; 135 setHoldState(false); 136 this.FadeOut(100); 137 } 138 139 protected override void Dispose(bool isDisposing) 140 { 141 base.Dispose(isDisposing); 142 Logger.NewEntry -= addEntry; 143 } 144 } 145 146 internal class DrawableLogEntry : Container 147 { 148 private const float target_box_width = 65; 149 150 private const float font_size = 14; 151 152 public DrawableLogEntry(LogEntry entry) 153 { 154 RelativeSizeAxes = Axes.X; 155 AutoSizeAxes = Axes.Y; 156 157 Color4 col = getColourForEntry(entry); 158 159 Children = new Drawable[] 160 { 161 new Container 162 { 163 //log target coloured box 164 Margin = new MarginPadding(3), 165 Size = new Vector2(target_box_width, font_size), 166 Anchor = Anchor.CentreLeft, 167 Origin = Anchor.CentreLeft, 168 CornerRadius = 5, 169 Masking = true, 170 Children = new Drawable[] 171 { 172 new Box 173 { 174 RelativeSizeAxes = Axes.Both, 175 Colour = col, 176 }, 177 new SpriteText 178 { 179 Anchor = Anchor.Centre, 180 Origin = Anchor.Centre, 181 Shadow = true, 182 ShadowColour = Color4.Black, 183 Margin = new MarginPadding { Left = 5, Right = 5 }, 184 Font = FrameworkFont.Regular.With(size: font_size), 185 Text = entry.Target?.ToString() ?? entry.LoggerName, 186 } 187 } 188 }, 189 new Container 190 { 191 AutoSizeAxes = Axes.Y, 192 RelativeSizeAxes = Axes.X, 193 Anchor = Anchor.CentreLeft, 194 Origin = Anchor.CentreLeft, 195 Padding = new MarginPadding { Left = target_box_width + 10 }, 196 Child = new SpriteText 197 { 198 RelativeSizeAxes = Axes.X, 199 Font = FrameworkFont.Regular.With(size: font_size), 200 Text = entry.Message 201 } 202 } 203 }; 204 } 205 206 private Color4 getColourForEntry(LogEntry entry) 207 { 208 switch (entry.Target) 209 { 210 case LoggingTarget.Runtime: 211 return Color4.YellowGreen; 212 213 case LoggingTarget.Network: 214 return Color4.BlueViolet; 215 216 case LoggingTarget.Performance: 217 return Color4.HotPink; 218 219 case LoggingTarget.Information: 220 return Color4.CadetBlue; 221 222 default: 223 return Color4.Cyan; 224 } 225 } 226 } 227}