diff --git a/OpenRA.Game/Widgets/Widget.cs b/OpenRA.Game/Widgets/Widget.cs index af09e0a3c3..eb8b0d9c57 100644 --- a/OpenRA.Game/Widgets/Widget.cs +++ b/OpenRA.Game/Widgets/Widget.cs @@ -33,6 +33,8 @@ namespace OpenRA.Widgets public static Widget KeyboardFocusWidget; public static Widget MouseOverWidget; + static readonly Mediator Mediator = new Mediator(); + public static void CloseWindow() { if (WindowList.Count > 0) @@ -156,6 +158,18 @@ namespace OpenRA.Widgets HandleInput(new MouseInput(MouseInputEvent.Move, MouseButton.None, Viewport.LastMousePos, int2.Zero, Modifiers.None, 0)); } + + public static void Subscribe(T instance) + { + Mediator.Subscribe(instance); + } + + public static void Unsubscribe(T instance) + { + Mediator.Unsubscribe(instance); + } + + public static void Send(T notification) => Mediator.Send(notification); } public class ChromeLogic : IDisposable @@ -278,6 +292,9 @@ namespace OpenRA.Widgets LogicObjects = Logic.Select(l => Game.ModData.ObjectCreator.CreateObject(l, args)) .ToArray(); + foreach (var logicObject in LogicObjects) + Ui.Subscribe(logicObject); + args.Remove("widget"); } @@ -529,8 +546,13 @@ namespace OpenRA.Widgets c.Removed(); if (LogicObjects != null) + { foreach (var l in LogicObjects) + { + Ui.Unsubscribe(l); l.Dispose(); + } + } } public Widget GetOrNull(string id) @@ -609,4 +631,32 @@ namespace OpenRA.Widgets : base(args) { } public void Add(string key, Action val) { base.Add(key, val); } } + + public sealed class Mediator + { + readonly TypeDictionary types = new TypeDictionary(); + + public void Subscribe(T instance) + { + types.Add(instance); + } + + public void Unsubscribe(T instance) + { + types.Remove(instance); + } + + public void Send(T notification) + { + var handlers = types.WithInterface>(); + + foreach (var handler in handlers) + handler.Handle(notification); + } + } + + public interface INotificationHandler + { + void Handle(T notification); + } } diff --git a/OpenRA.Test/OpenRA.Game/MediatorTest.cs b/OpenRA.Test/OpenRA.Game/MediatorTest.cs new file mode 100644 index 0000000000..d97718e784 --- /dev/null +++ b/OpenRA.Test/OpenRA.Game/MediatorTest.cs @@ -0,0 +1,44 @@ +#region Copyright & License Information +/* + * Copyright 2007-2022 The OpenRA Developers (see AUTHORS) + * This file is part of OpenRA, which is free software. It is made + * available to you under the terms of the GNU General Public License + * as published by the Free Software Foundation, either version 3 of + * the License, or (at your option) any later version. For more + * information, see COPYING. + */ +#endregion + +using NUnit.Framework; +using OpenRA.Widgets; + +namespace OpenRA.Test +{ + [TestFixture] + public class MediatorTest + { + [TestCase(TestName = "Mediator test")] + public void Test() + { + var mediator = new Mediator(); + var testHandler = new TestHandler(); + mediator.Subscribe(testHandler); + + mediator.Send(new TestNotificaton()); + + Assert.IsTrue(testHandler.WasNotified); + } + } + + public class TestHandler : INotificationHandler + { + public bool WasNotified { get; set; } + + public void Handle(TestNotificaton notification) + { + WasNotified = true; + } + } + + public class TestNotificaton { } +}