From 9cd408afe0c1573d317cc2934be70f184e1ca351 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Tue, 20 Oct 2026 09:14:06 +0300 Subject: [PATCH 01/14] Generate VGUI panel registration instead of using reflection --- Directory.Build.targets | 1 + .../PanelRegistrationGenerator.cs | 227 ++++++++++++++++++ .../Source.CodeAnalysis.VGUI.csproj | 19 ++ Source.GUI.Controls/Panel.cs | 114 +-------- Source.GUI.Controls/PanelRegistry.cs | 27 +++ Source.NET.slnx | 3 + 6 files changed, 290 insertions(+), 101 deletions(-) create mode 100644 Source.CodeAnalysis.VGUI/PanelRegistrationGenerator.cs create mode 100644 Source.CodeAnalysis.VGUI/Source.CodeAnalysis.VGUI.csproj create mode 100644 Source.GUI.Controls/PanelRegistry.cs diff --git a/Directory.Build.targets b/Directory.Build.targets index aca752f7a..a5455a1f3 100644 --- a/Directory.Build.targets +++ b/Directory.Build.targets @@ -3,6 +3,7 @@ which emits Source.Generated.CvarRegistration for EngineBuilder.ConVar_Register to use instead of reflection. --> + diff --git a/Source.CodeAnalysis.VGUI/PanelRegistrationGenerator.cs b/Source.CodeAnalysis.VGUI/PanelRegistrationGenerator.cs new file mode 100644 index 000000000..697c07ef4 --- /dev/null +++ b/Source.CodeAnalysis.VGUI/PanelRegistrationGenerator.cs @@ -0,0 +1,227 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Text; + +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Source.CodeAnalysis.VGUI +{ + [Generator(LanguageNames.CSharp)] + public sealed class PanelRegistrationGenerator : IIncrementalGenerator + { + const string Controls = "Source.GUI.Controls."; + const string G = "global::"; + + static readonly DiagnosticDescriptor Inaccessible = new DiagnosticDescriptor( + id: "VGUI001", + title: "Panel type is not accessible to the generated registration", + messageFormat: "'{0}' is a panel but is not accessible from generated code, so it is not registered", + category: "VGUI", + defaultSeverity: DiagnosticSeverity.Warning, + isEnabledByDefault: true); + + public void Initialize(IncrementalGeneratorInitializationContext context) { + context.RegisterSourceOutput(context.CompilationProvider, static (spc, compilation) => Execute(spc, compilation)); + } + + sealed class Symbols + { + public INamedTypeSymbol Panel = null!; + public INamedTypeSymbol AnimationVar = null!; + public INamedTypeSymbol? AnimationVarAlias; + public INamedTypeSymbol? Alias; + } + + static void Execute(SourceProductionContext spc, Compilation compilation) { + INamedTypeSymbol? panel = compilation.GetTypeByMetadataName(Controls + "Panel"); + INamedTypeSymbol? animationVar = compilation.GetTypeByMetadataName(Controls + "PanelAnimationVarAttribute"); + if (panel == null || animationVar == null || compilation.GetTypeByMetadataName(Controls + "PanelRegistry") == null) + return; + + Symbols s = new Symbols { + Panel = panel, + AnimationVar = animationVar, + AnimationVarAlias = compilation.GetTypeByMetadataName(Controls + "PanelAnimationVarAliasTypeAttribute"), + Alias = compilation.GetTypeByMetadataName(Controls + "PanelAliasAttribute"), + }; + + List panels = new List(); + CollectPanels(compilation.Assembly.GlobalNamespace, s, panels); + if (panels.Count == 0) + return; + + StringBuilder accessors = new StringBuilder(); + StringBuilder body = new StringBuilder(); + int accessorId = 0; + + foreach (INamedTypeSymbol type in panels) { + if (!IsAccessible(type)) { + spc.ReportDiagnostic(Diagnostic.Create(Inaccessible, type.Locations.FirstOrDefault(), type.ToDisplayString())); + continue; + } + + string typeName = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + string factory = Factory(type, s, typeName, accessors, ref accessorId); + string alias = AliasOf(type, s); + string animationVars = AnimationVars(type, s, typeName, accessors, ref accessorId); + + body.AppendLine($"\t\t{G}Source.GUI.Controls.PanelRegistry.Add(typeof({typeName}), {Literal(type.Name)}, {factory}, {alias}, {animationVars});"); + } + + StringBuilder sb = new StringBuilder(); + sb.AppendLine("// "); + sb.AppendLine("#nullable enable"); + sb.AppendLine("#pragma warning disable CA2255"); + sb.AppendLine(); + sb.AppendLine("namespace Source.Generated;"); + sb.AppendLine(); + sb.AppendLine("internal static class VGuiPanelRegistration"); + sb.AppendLine("{"); + sb.Append(accessors); + sb.AppendLine("\t[global::System.Runtime.CompilerServices.ModuleInitializer]"); + sb.AppendLine("\tinternal static void Register() {"); + sb.Append(body); + sb.AppendLine("\t}"); + sb.AppendLine("}"); + + spc.AddSource("VGuiPanelRegistration.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8)); + } + + static void CollectPanels(INamespaceOrTypeSymbol container, Symbols s, List panels) { + foreach (ISymbol member in container.GetMembers()) { + if (member is INamespaceSymbol ns) + CollectPanels(ns, s, panels); + else if (member is INamedTypeSymbol type) { + if (type.TypeKind == TypeKind.Class && !IsGeneric(type) && DerivesFrom(type, s.Panel)) + panels.Add(type); + CollectPanels(type, s, panels); + } + } + } + + static bool IsGeneric(INamedTypeSymbol type) { + for (INamedTypeSymbol? t = type; t != null; t = t.ContainingType) + if (t.IsGenericType) + return true; + return false; + } + + static bool DerivesFrom(INamedTypeSymbol type, INamedTypeSymbol baseType) { + for (INamedTypeSymbol? t = type; t != null; t = t.BaseType) + if (SymbolEqualityComparer.Default.Equals(t, baseType)) + return true; + return false; + } + + static bool IsAccessible(INamedTypeSymbol type) { + for (INamedTypeSymbol? t = type; t != null; t = t.ContainingType) { + Accessibility a = t.DeclaredAccessibility; + if (a != Accessibility.Public && a != Accessibility.Internal && a != Accessibility.ProtectedOrInternal) + return false; + } + return true; + } + + static string Factory(INamedTypeSymbol type, Symbols s, string typeName, StringBuilder accessors, ref int accessorId) { + IMethodSymbol? create = type.GetMembers("Create_" + type.Name).OfType() + .FirstOrDefault(m => m.IsStatic && m.Parameters.Length == 0 && m.ReturnType is INamedTypeSymbol r && DerivesFrom(r, s.Panel)); + if (create != null) { + string accessor = "__Create" + accessorId++; + string returnType = create.ReturnType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + accessors.AppendLine($"\t[global::System.Runtime.CompilerServices.UnsafeAccessor(global::System.Runtime.CompilerServices.UnsafeAccessorKind.StaticMethod, Name = {Literal(create.Name)})]"); + accessors.AppendLine($"\tstatic extern {returnType} {accessor}({typeName}? owner);"); + accessors.AppendLine(); + return $"static () => {accessor}(null)"; + } + + if (!type.IsAbstract && type.InstanceConstructors.Any(c => c.Parameters.Length == 0 && c.DeclaredAccessibility == Accessibility.Public)) + return $"static () => new {typeName}()"; + + return "null"; + } + + static string AliasOf(INamedTypeSymbol type, Symbols s) { + if (s.Alias == null) + return "null"; + + AttributeData? attribute = type.GetAttributes().FirstOrDefault(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, s.Alias)); + if (attribute == null || attribute.ConstructorArguments.Length != 1 || !(attribute.ConstructorArguments[0].Value is string alias)) + return "null"; + + return Literal(alias); + } + + static string AnimationVars(INamedTypeSymbol type, Symbols s, string typeName, StringBuilder accessors, ref int accessorId) { + StringBuilder calls = new StringBuilder(); + + foreach (IFieldSymbol field in type.GetMembers().OfType()) { + if (field.IsStatic || field.IsImplicitlyDeclared) + continue; + + AttributeData? attribute = FindAttribute(field, s.AnimationVarAlias) ?? FindAttribute(field, s.AnimationVar); + if (attribute == null) + continue; + + string? name = null; + string? defaultValue = null; + string? typeAlias = null; + var args = attribute.ConstructorArguments; + if (args.Length == 1) { + defaultValue = args[0].Value as string; + } + else if (args.Length == 2) { + name = args[0].Value as string; + defaultValue = args[1].Value as string; + } + else if (args.Length == 3) { + name = args[0].Value as string; + defaultValue = args[1].Value as string; + typeAlias = args[2].Value as string; + } + + string fieldType = field.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + string accessor = "__Field" + accessorId++; + accessors.AppendLine($"\t[global::System.Runtime.CompilerServices.UnsafeAccessor(global::System.Runtime.CompilerServices.UnsafeAccessorKind.Field, Name = {Literal(field.Name)})]"); + accessors.AppendLine($"\tstatic extern ref {fieldType} {accessor}({typeName} owner);"); + accessors.AppendLine(); + + calls.AppendLine($"\t\t\t{G}Source.GUI.Controls.Panel.AddToAnimationMap(typeof({typeName}), {Literal(name ?? field.Name)}, {Literal(typeAlias ?? TypeName(field.Type))}, {Literal(field.Name)}, {Literal(defaultValue ?? "")}, false,"); + calls.AppendLine($"\t\t\t\tstatic p => {accessor}(({typeName})p),"); + calls.AppendLine($"\t\t\t\tstatic (p, v) => {accessor}(({typeName})p) = ({fieldType})v);"); + } + + if (calls.Length == 0) + return "null"; + + return "static () => {\n" + calls + "\t\t}"; + } + + static AttributeData? FindAttribute(IFieldSymbol field, INamedTypeSymbol? attributeType) { + if (attributeType == null) + return null; + return field.GetAttributes().FirstOrDefault(a => SymbolEqualityComparer.Default.Equals(a.AttributeClass, attributeType)); + } + + static string TypeName(ITypeSymbol type) { + switch (type.SpecialType) { + case SpecialType.System_SByte: return "sbyte"; + case SpecialType.System_Byte: return "byte"; + case SpecialType.System_Int16: return "short"; + case SpecialType.System_UInt16: return "ushort"; + case SpecialType.System_Int32: return "int"; + case SpecialType.System_UInt32: return "uint"; + case SpecialType.System_Int64: return "long"; + case SpecialType.System_UInt64: return "ulong"; + case SpecialType.System_Single: return "float"; + case SpecialType.System_Double: return "double"; + } + if (type is IArrayTypeSymbol array) + return array.ElementType.MetadataName + "[]"; + return type.MetadataName; + } + + static string Literal(string value) => SymbolDisplay.FormatLiteral(value, true); + } +} diff --git a/Source.CodeAnalysis.VGUI/Source.CodeAnalysis.VGUI.csproj b/Source.CodeAnalysis.VGUI/Source.CodeAnalysis.VGUI.csproj new file mode 100644 index 000000000..5fe2175b2 --- /dev/null +++ b/Source.CodeAnalysis.VGUI/Source.CodeAnalysis.VGUI.csproj @@ -0,0 +1,19 @@ + + + + netstandard2.0 + false + true + true + latest + enable + false + Debug;Release;Debug (Dedicated);Release (Dedicated) + + + + + + + + diff --git a/Source.GUI.Controls/Panel.cs b/Source.GUI.Controls/Panel.cs index e64ed9ca7..f5764377b 100644 --- a/Source.GUI.Controls/Panel.cs +++ b/Source.GUI.Controls/Panel.cs @@ -14,7 +14,6 @@ using System.Diagnostics.CodeAnalysis; using System.Drawing; using System.Reflection; -using System.Reflection.Emit; using System.Runtime.CompilerServices; using System.Runtime.InteropServices; @@ -160,68 +159,6 @@ public PanelAnimationVarAttribute(string name, string defaultValue, string? type DefaultValue = defaultValue; Type = type; } - - public static void InitVar(Type t, PanelAnimationVarAttribute attribute, FieldInfo field) { - PanelGetFunc get; - PanelSetFunc set; - - { - DynamicMethod methodBuilder = new($"{t.Name}PanelAnim_GetVar_{field.Name}", typeof(object), [typeof(Panel)]); - var il = methodBuilder.GetILGenerator(); - { - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldfld, field); - if (field.FieldType.IsValueType) - il.Emit(OpCodes.Box, field.FieldType); - - il.Emit(OpCodes.Ret); - } - get = methodBuilder.CreateDelegate(); - } - - { - DynamicMethod methodBuilder = new($"{t.Name}PanelAnim_SetVar_{field.Name}", typeof(void), [typeof(Panel), typeof(object)]); - var il = methodBuilder.GetILGenerator(); - { - il.Emit(OpCodes.Ldarg_0); - il.Emit(OpCodes.Ldarg_1); - - if (field.FieldType.IsValueType) - il.Emit(OpCodes.Unbox_Any, field.FieldType); - else - il.Emit(OpCodes.Castclass, field.FieldType); - - il.Emit(OpCodes.Stfld, field); - - il.Emit(OpCodes.Ret); - } - set = methodBuilder.CreateDelegate(); - } - - Panel.AddToAnimationMap( - t, - attribute.Name ?? field.Name, - attribute.Type ?? (typedefs.TryGetValue(field.FieldType, out string? name) ? name : field.FieldType.Name), - field.Name, - attribute.DefaultValue, - false, - get, - set - ); - } - - static readonly Dictionary typedefs = new() { - { typeof(sbyte), "sbyte" }, - { typeof(byte), "byte" }, - { typeof(short), "short" }, - { typeof(ushort), "ushort" }, - { typeof(int), "int" }, - { typeof(uint), "uint" }, - { typeof(long), "long" }, - { typeof(ulong), "ulong" }, - { typeof(float), "float" }, - { typeof(double), "double" } - }; } public class Panel : IPanel @@ -3264,13 +3201,7 @@ public static void AddToAnimationMap(Type t, ReadOnlySpan scriptName, Read } public static void ChainToAnimationMap() where T : Panel => ChainToAnimationMap(typeof(T)); public static void ChainToAnimationMap(Type t) { - foreach (var field in t.GetFields(BindingFlags.NonPublic | BindingFlags.Public | BindingFlags.Instance)) { - PanelAnimationVarAttribute? attr = field.GetCustomAttribute() ?? field.GetCustomAttribute(); - if (attr == null) - continue; - - PanelAnimationVarAttribute.InitVar(t, attr, field); - } + PanelRegistry.AddAnimationVars(t); PanelAnimationMap map = PanelAnimationDictionary.FindOrAddPanelAnimationMap(t.Name); map.ClassName = t.Name; @@ -3281,51 +3212,32 @@ public static void ChainToAnimationMap(Type t) { public virtual PanelAnimationMap GetAnimMap() => PanelAnimationDictionary.FindOrAddPanelAnimationMap(GetType().Name); - delegate Panel CreatePanelFactoryFn(); - static readonly ConcurrentDictionary PanelFactories = []; - static readonly ConcurrentDictionary PanelNames = []; + static readonly ConcurrentDictionary> PanelFactories = []; public static void InitializeControls() { - List list = []; - - foreach (Type type in ReflectionUtils.GetLoadedTypes()) - if (typeof(Panel).IsAssignableFrom(type)) - list.Add(type); + foreach (Assembly assembly in ReflectionUtils.GetAssemblies()) + RuntimeHelpers.RunModuleConstructor(assembly.ManifestModule.ModuleHandle); int count = 0; - Parallel.ForEach(list, type => { - ChainToAnimationMap(type); - //Msg($"VGUI: Initializing {type.Name}\n"); + foreach (PanelRegistry.Entry entry in PanelRegistry.Entries) { + ChainToAnimationMap(entry.Type); - UtlSymbol nameSymbol = new(type.Name); - MethodInfo? method = type.GetMethod($"Create_{type.Name}", BindingFlags.Static | BindingFlags.NonPublic | BindingFlags.Public); - if (method != null) - PanelFactories[nameSymbol] = method.CreateDelegate(); - - PanelNames[nameSymbol] = type; - - PanelAliasAttribute? aliasAttr = type.GetCustomAttribute(); - if (aliasAttr != null) { - UtlSymbol aliasSymbol = new(aliasAttr.Alias); - PanelNames[aliasSymbol] = type; - if (method != null) - PanelFactories[aliasSymbol] = method.CreateDelegate(); + if (entry.Factory != null) { + PanelFactories[new UtlSymbol(entry.Name)] = entry.Factory; + if (entry.Alias != null) + PanelFactories[new UtlSymbol(entry.Alias)] = entry.Factory; } - Interlocked.Increment(ref count); - }); + count++; + } Msg($"Initialized {count} VGUI controls in all currently loaded assemblies\n"); } public static Panel? InstancePanel(ReadOnlySpan className) { - UtlSymbol sym = new(className); - if (PanelFactories.TryGetValue(sym, out CreatePanelFactoryFn? fn)) + if (PanelFactories.TryGetValue(new UtlSymbol(className), out Func? fn)) return fn(); - if (PanelNames.TryGetValue(sym, out Type? t)) - return (Panel)Activator.CreateInstance(t)!; - return null; } diff --git a/Source.GUI.Controls/PanelRegistry.cs b/Source.GUI.Controls/PanelRegistry.cs new file mode 100644 index 000000000..d2f27dc8c --- /dev/null +++ b/Source.GUI.Controls/PanelRegistry.cs @@ -0,0 +1,27 @@ +namespace Source.GUI.Controls; + +public static class PanelRegistry +{ + public readonly record struct Entry(Type Type, string Name, Func? Factory, string? Alias); + + static readonly List entries = []; + static readonly Dictionary animationVars = []; + + public static IReadOnlyList Entries => entries; + + public static void Add(Type type, string name, Func? factory, string? alias, Action? addAnimationVars) { + lock (entries) { + entries.Add(new(type, name, factory, alias)); + if (addAnimationVars != null) + animationVars[type] = addAnimationVars; + } + } + + public static void AddAnimationVars(Type type) { + Action? addAnimationVars; + lock (entries) + animationVars.TryGetValue(type, out addAnimationVars); + + addAnimationVars?.Invoke(); + } +} diff --git a/Source.NET.slnx b/Source.NET.slnx index 36610a25e..7f9606e52 100644 --- a/Source.NET.slnx +++ b/Source.NET.slnx @@ -31,6 +31,9 @@ + + + From 9fb878b0914e7b1d4643d8ea805862de08069bf1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Tue, 20 Oct 2026 09:14:06 +0300 Subject: [PATCH 02/14] Fix panel animation maps colliding on short class names --- Source.GUI.Controls/Panel.cs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/Source.GUI.Controls/Panel.cs b/Source.GUI.Controls/Panel.cs index f5764377b..883f86c00 100644 --- a/Source.GUI.Controls/Panel.cs +++ b/Source.GUI.Controls/Panel.cs @@ -3186,7 +3186,7 @@ public void GetBounds(out int x, out int y, out int w, out int h) { } public static void AddToAnimationMap(Type t, ReadOnlySpan scriptName, ReadOnlySpan type, ReadOnlySpan var, ReadOnlySpan defaultValue, bool array, PanelGetFunc get, PanelSetFunc set) { - PanelAnimationMap map = PanelAnimationDictionary.FindOrAddPanelAnimationMap(t.Name); + PanelAnimationMap map = PanelAnimationDictionary.FindOrAddPanelAnimationMap(t.FullName); PanelAnimationMapEntry entry = new() { ScriptName = new string(scriptName), @@ -3203,14 +3203,14 @@ public static void AddToAnimationMap(Type t, ReadOnlySpan scriptName, Read public static void ChainToAnimationMap(Type t) { PanelRegistry.AddAnimationVars(t); - PanelAnimationMap map = PanelAnimationDictionary.FindOrAddPanelAnimationMap(t.Name); + PanelAnimationMap map = PanelAnimationDictionary.FindOrAddPanelAnimationMap(t.FullName); map.ClassName = t.Name; Type? baseClass = t.BaseType; if (baseClass?.IsAssignableTo(typeof(Panel)) ?? false) - map.BaseMap = PanelAnimationDictionary.FindOrAddPanelAnimationMap(baseClass.Name); + map.BaseMap = PanelAnimationDictionary.FindOrAddPanelAnimationMap(baseClass.FullName); } - public virtual PanelAnimationMap GetAnimMap() => PanelAnimationDictionary.FindOrAddPanelAnimationMap(GetType().Name); + public virtual PanelAnimationMap GetAnimMap() => PanelAnimationDictionary.FindOrAddPanelAnimationMap(GetType().FullName); static readonly ConcurrentDictionary> PanelFactories = []; From debd18997202531ddf4be90c7c1602a851e159c3 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Tue, 20 Oct 2026 10:47:23 +0300 Subject: [PATCH 03/14] Fix stray dxlevel combo in the advanced video dialog --- Game.UI/OptionsSubVideo.cs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/Game.UI/OptionsSubVideo.cs b/Game.UI/OptionsSubVideo.cs index 057f14d32..18ce32aaa 100644 --- a/Game.UI/OptionsSubVideo.cs +++ b/Game.UI/OptionsSubVideo.cs @@ -49,7 +49,7 @@ public OptionsSubVideoAdvancedDlg(Panel? parent) : base(parent, "OptionsSubVideo SetTitle("#GameUI_VideoAdvanced_Title", true); SetSize(260, 400); - DXLevel = new(this, "dxlevel", 6, false); + DXLevel = new(this, "dxlabel", 6, false); MaterialSystem_Config config = Materials.GetCurrentConfigForVideoCard(); // KeyValues kv = new("config"); From 7c92261e6ef607a26d0ff24c89056ccc00426f31 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Tue, 20 Oct 2026 11:03:41 +0300 Subject: [PATCH 04/14] Fix VGUI commands compared by span reference --- Game.ServerBrowser/DialogServerPassword.cs | 4 ++-- Game.UI/OptionsSubVideo.cs | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/Game.ServerBrowser/DialogServerPassword.cs b/Game.ServerBrowser/DialogServerPassword.cs index 4d9db75a1..2bbdf1a84 100644 --- a/Game.ServerBrowser/DialogServerPassword.cs +++ b/Game.ServerBrowser/DialogServerPassword.cs @@ -43,7 +43,7 @@ public void Activate(ReadOnlySpan serverName, uint serverID) { public override void OnCommand(ReadOnlySpan command) { bool close = false; - if (command == "Connect") { + if (stricmp(command, "Connect") == 0) { KeyValues msg = new("JoinServerWithPassword"); Span buffer = stackalloc char[64]; PasswordEntry.GetText(buffer); @@ -52,7 +52,7 @@ public override void OnCommand(ReadOnlySpan command) { PostActionSignal(msg); close = true; } - else if (command == "Close") + else if (stricmp(command, "Close") == 0) close = true; else base.OnCommand(command); diff --git a/Game.UI/OptionsSubVideo.cs b/Game.UI/OptionsSubVideo.cs index 18ce32aaa..e597c6c0c 100644 --- a/Game.UI/OptionsSubVideo.cs +++ b/Game.UI/OptionsSubVideo.cs @@ -506,7 +506,7 @@ public void OnResetData() { } public override void OnCommand(ReadOnlySpan command) { - if (command == "OK") { + if (stricmp(command, "OK") == 0) { if (RequiresRestart()) { QueryBox box = new("#GameUI_SettingRequiresDisconnect_Title", "#GameUI_SettingRequiresDisconnect_Info"); box.AddActionSignalTarget(this); From 37f5682831ae77d29b4c7f71a35b6557ab08ef80 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Tue, 20 Oct 2026 11:26:12 +0300 Subject: [PATCH 05/14] Fix FrameSystemButton setup to match the SDK --- Source.GUI.Controls/Frame.cs | 33 ++++++++++++++++++++++++++++++--- 1 file changed, 30 insertions(+), 3 deletions(-) diff --git a/Source.GUI.Controls/Frame.cs b/Source.GUI.Controls/Frame.cs index d73e55f03..4bdc5e597 100644 --- a/Source.GUI.Controls/Frame.cs +++ b/Source.GUI.Controls/Frame.cs @@ -7,6 +7,10 @@ namespace Source.GUI.Controls; public class FrameSystemButton : MenuButton { public FrameSystemButton(Panel parent, string name) : base(parent, name, "") { + Responsive = true; + SetEnabled(false); + SetMouseClickEnabled(ButtonCode.MouseRight, true); + SetBlockDragChaining(true); } IImage? Enabled, Disabled; @@ -15,6 +19,11 @@ public FrameSystemButton(Panel parent, string name) : base(parent, name, "") { string? EnabledImage; string? DisabledImage; + public void SetImages(string enabledImage, string? disabledImage = null) { + EnabledImage = enabledImage; + DisabledImage = disabledImage ?? enabledImage; + } + public void SetResponsive(bool state) => Responsive = state; internal void GetImageSize(out int w, out int h) { @@ -36,8 +45,8 @@ public override void ApplySchemeSettings(IScheme scheme) { EnabledColor = GetSchemeColor("FrameSystemButton.FgColor", scheme); DisabledColor = GetSchemeColor("FrameSystemButton.BgColor", scheme); - ReadOnlySpan enabledImage = EnabledImage ?? scheme.GetResourceString("FrameSystemButton.EnabledImage"); - ReadOnlySpan disabledImage = DisabledImage ?? scheme.GetResourceString("FrameSystemButton.DisabledImage"); + ReadOnlySpan enabledImage = string.IsNullOrEmpty(EnabledImage) ? scheme.GetResourceString("FrameSystemButton.Icon") : EnabledImage; + ReadOnlySpan disabledImage = string.IsNullOrEmpty(DisabledImage) ? scheme.GetResourceString("FrameSystemButton.DisabledIcon") : DisabledImage; Enabled = SchemeManager.GetImage(enabledImage, false); Disabled = SchemeManager.GetImage(disabledImage, false); @@ -50,7 +59,7 @@ public override void ApplySchemeSettings(IScheme scheme) { public override void SetEnabled(bool state) { base.SetEnabled(state); - if (IsEnabled() && Responsive) { + if (IsEnabled()) { if (Enabled != null) SetImageAtIndex(0, Enabled, 0); @@ -69,6 +78,24 @@ public override void SetEnabled(bool state) { SetDepressedColor(DisabledColor, DisabledColor); } } + + public override void OnMousePressed(ButtonCode code) { + if (!Responsive) + return; + + base.OnMousePressed(code); + } + + public override void OnMouseDoublePressed(ButtonCode code) { + if (!Responsive) + return; + + if (code == ButtonCode.MouseLeft) { + Menu? menu = GetMenu(); + if (menu != null && menu.FindChildByName("Close") != null) + PostMessage(GetParent(), new KeyValues("CloseFrameButtonPressed")); + } + } } public class GripPanel : Panel From d2f8b08b9ac306e645e1f26761b9ff9bc7709ee4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Tue, 20 Oct 2026 11:41:37 +0300 Subject: [PATCH 06/14] Fix EditablePanel reading default buttons from the wrong key --- Source.GUI.Controls/EditablePanel.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source.GUI.Controls/EditablePanel.cs b/Source.GUI.Controls/EditablePanel.cs index 1193ccf6e..b51aefd73 100644 --- a/Source.GUI.Controls/EditablePanel.cs +++ b/Source.GUI.Controls/EditablePanel.cs @@ -355,7 +355,7 @@ private void OnCurrentDefaultButtonSet(Panel defaultButton) { if (GetParent() != null) { KeyValues msg = new("CurrentDefaultButtonSet"); - msg.SetPtr("panel", defaultButton); + msg.SetPtr("button", defaultButton); PostMessage(GetParent()!, msg); } } @@ -374,10 +374,10 @@ private void OnFindDefaultButton() { public override void OnMessage(KeyValues message, IPanel? from) { switch (message.Name) { case "DefaultButtonSet": - OnDefaultButtonSet((Panel)message.GetPtr("panel")!); + OnDefaultButtonSet((Panel)message.GetPtr("button")!); break; case "CurrentDefaultButtonSet": - OnCurrentDefaultButtonSet((Panel)message.GetPtr("panel")!); + OnCurrentDefaultButtonSet((Panel)message.GetPtr("button")!); break; case "FindDefaultButton": OnFindDefaultButton(); From d12fd13143139f01483bb822ad9595d9dc636474 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Tue, 20 Oct 2026 11:52:08 +0300 Subject: [PATCH 07/14] Fix radio buttons not unchecking their siblings --- Source.GUI.Controls/RadioButton.cs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/Source.GUI.Controls/RadioButton.cs b/Source.GUI.Controls/RadioButton.cs index f6b560c5e..621f383f9 100644 --- a/Source.GUI.Controls/RadioButton.cs +++ b/Source.GUI.Controls/RadioButton.cs @@ -120,9 +120,9 @@ public void InternalSetSelected(bool state, bool fireEvents) { Panel? radioParent = GetParent(); if (radioParent != null) { for (int i = 0; i < radioParent.GetChildCount(); i++) { - RadioButton? child = (RadioButton)radioParent.GetChild(i); - if (child != null && child != this) - child.PostMessage(radioParent, msg.MakeCopy()); + Panel child = radioParent.GetChild(i); + if (child != this) + PostMessage(child, msg.MakeCopy()); } } From d31498a48cfa7e198833a82d08407511062c4214 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Tue, 20 Oct 2026 12:06:44 +0300 Subject: [PATCH 08/14] Rename VGUI message from parameter to sender --- Game.Client/HUD/BaseHudChat.cs | 4 ++-- Game.ServerBrowser/BaseGamesPage.cs | 8 ++++---- Game.ServerBrowser/ServerBrowserDialog.cs | 4 ++-- Game.UI/CvarNegateCheckButton.cs | 4 ++-- Game.UI/CvarSlider.cs | 4 ++-- Game.UI/LabeledCommandComboBox.cs | 4 ++-- Game.UI/OptionsDialog.cs | 4 ++-- Game.UI/OptionsSubAudio.cs | 6 +++--- Game.UI/OptionsSubKeyboard.cs | 4 ++-- Game.UI/OptionsSubMouse.cs | 8 ++++---- Game.UI/OptionsSubVideo.cs | 12 ++++++------ Game.UI/URLButton.cs | 4 ++-- Source.Common/GUI/IPanel.cs | 2 +- Source.Common/GUI/IVGui.cs | 4 ++-- Source.Engine/VGui_DrawTreePanel.cs | 4 ++-- Source.GUI.Controls/BuildModeDialog.cs | 2 +- Source.GUI.Controls/Button.cs | 4 ++-- Source.GUI.Controls/CheckButton.cs | 6 +++--- Source.GUI.Controls/CheckButtonList.cs | 4 ++-- Source.GUI.Controls/ComboBox.cs | 4 ++-- Source.GUI.Controls/ConsoleDialog.cs | 8 ++++---- Source.GUI.Controls/CvarToggleCheckButton.cs | 4 ++-- Source.GUI.Controls/EditablePanel.cs | 4 ++-- Source.GUI.Controls/Frame.cs | 4 ++-- Source.GUI.Controls/HTML.cs | 8 ++++---- Source.GUI.Controls/Menu.cs | 4 ++-- Source.GUI.Controls/MenuButton.cs | 4 ++-- Source.GUI.Controls/MenuItem.cs | 4 ++-- Source.GUI.Controls/Panel.cs | 10 +++++----- Source.GUI.Controls/PanelListPanel.cs | 4 ++-- Source.GUI.Controls/PropertyDialog.cs | 4 ++-- Source.GUI.Controls/PropertyPage.cs | 4 ++-- Source.GUI.Controls/PropertySheet.cs | 8 ++++---- Source.GUI.Controls/RadioButton.cs | 4 ++-- Source.GUI.Controls/ScrollBar.cs | 4 ++-- Source.GUI.Controls/ScrollableEditablePanel.cs | 4 ++-- Source.GUI.Controls/SectionedListPanel.cs | 4 ++-- Source.GUI.Controls/TreeView.cs | 14 +++++++------- Source.GUI/VGui.cs | 6 +++--- 39 files changed, 101 insertions(+), 101 deletions(-) diff --git a/Game.Client/HUD/BaseHudChat.cs b/Game.Client/HUD/BaseHudChat.cs index 3ce713087..d4c1b67f5 100644 --- a/Game.Client/HUD/BaseHudChat.cs +++ b/Game.Client/HUD/BaseHudChat.cs @@ -806,11 +806,11 @@ public void Send() { engine.ClientCmd_Unrestricted(buf[..writePtr]); } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "ChatEntryStopMessageMode": StopMessageMode(); break; case "ChatEntrySend": Send(); break; - default: base.OnMessage(message, from); break; + default: base.OnMessage(message, sender); break; } } diff --git a/Game.ServerBrowser/BaseGamesPage.cs b/Game.ServerBrowser/BaseGamesPage.cs index cbabcb5bc..7d178795e 100644 --- a/Game.ServerBrowser/BaseGamesPage.cs +++ b/Game.ServerBrowser/BaseGamesPage.cs @@ -1137,7 +1137,7 @@ void OnFavoritesMsg(FavoritesListChanged_t favListChanged) { } public virtual bool SupportsItem(IGameList.InterfaceItem item) => false; public virtual void OnOpenContextMenu(int itemID) { } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "OpenContextMenu": OnOpenContextMenu(message.GetInt("itemID")); @@ -1161,13 +1161,13 @@ public override void OnMessage(KeyValues message, IPanel? from) { OnRefreshServer(message.GetInt("serverID")); return; case "TextChanged": - OnTextChanged((Panel)from!, message.GetString("text")); + OnTextChanged((Panel)sender!, message.GetString("text")); break; case "ButtonToggled": - OnButtonToggled((Panel)from!, message.GetInt("state")); + OnButtonToggled((Panel)sender!, message.GetInt("state")); break; default: - base.OnMessage(message, from); + base.OnMessage(message, sender); break; } } diff --git a/Game.ServerBrowser/ServerBrowserDialog.cs b/Game.ServerBrowser/ServerBrowserDialog.cs index 42d5ff6dc..aefd43c17 100644 --- a/Game.ServerBrowser/ServerBrowserDialog.cs +++ b/Game.ServerBrowser/ServerBrowserDialog.cs @@ -232,7 +232,7 @@ bool GetDefaultScreenPosition(out int x, out int y, out int wide, out int tall) public override void OnKeyCodePressed(ButtonCode code) { } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "PageChanged": OnGameListChanged(); @@ -250,7 +250,7 @@ public override void OnMessage(KeyValues message, IPanel? from) { OnLoadingStarted(); break; default: - base.OnMessage(message, from); + base.OnMessage(message, sender); break; } } diff --git a/Game.UI/CvarNegateCheckButton.cs b/Game.UI/CvarNegateCheckButton.cs index 61b979f28..9032e85cf 100644 --- a/Game.UI/CvarNegateCheckButton.cs +++ b/Game.UI/CvarNegateCheckButton.cs @@ -92,12 +92,12 @@ public void OnButtonChecked() { PostActionSignal(KV_ControlModified); } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { if (message.Name.Equals("CheckButtonChecked", StringComparison.OrdinalIgnoreCase)) { OnButtonChecked(); return; } - base.OnMessage(message, from); + base.OnMessage(message, sender); } } diff --git a/Game.UI/CvarSlider.cs b/Game.UI/CvarSlider.cs index 3f35e3592..6de1e8bf8 100644 --- a/Game.UI/CvarSlider.cs +++ b/Game.UI/CvarSlider.cs @@ -224,7 +224,7 @@ public void OnSliderDragEnd() { ApplyChanges(); } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "SliderMoved": OnSliderMoved(); @@ -233,7 +233,7 @@ public override void OnMessage(KeyValues message, IPanel? from) { OnSliderDragEnd(); break; default: - base.OnMessage(message, from); + base.OnMessage(message, sender); break; } } diff --git a/Game.UI/LabeledCommandComboBox.cs b/Game.UI/LabeledCommandComboBox.cs index a456dc647..9ccbd9ed1 100644 --- a/Game.UI/LabeledCommandComboBox.cs +++ b/Game.UI/LabeledCommandComboBox.cs @@ -110,13 +110,13 @@ public void Reset() { ActivateItem(StartSelection); } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "TextChanged": OnTextChanged(message.GetString("text", "")); return; default: - base.OnMessage(message, from); + base.OnMessage(message, sender); return; } } diff --git a/Game.UI/OptionsDialog.cs b/Game.UI/OptionsDialog.cs index 41af0365d..fed59941d 100644 --- a/Game.UI/OptionsDialog.cs +++ b/Game.UI/OptionsDialog.cs @@ -87,12 +87,12 @@ public void OnGameUIHidden() { } } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { if (message.Name == "GameUIHidden") { OnGameUIHidden(); return; } - base.OnMessage(message, from); + base.OnMessage(message, sender); } } diff --git a/Game.UI/OptionsSubAudio.cs b/Game.UI/OptionsSubAudio.cs index 7b8aa7134..0df1d7359 100644 --- a/Game.UI/OptionsSubAudio.cs +++ b/Game.UI/OptionsSubAudio.cs @@ -98,11 +98,11 @@ public override void OnResetData() { public void OnControlModified(Panel panel) { PostActionSignal(KV_ApplyButtonEnable); } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { if (message.Name.Equals("ControlModified")) - OnControlModified((Panel)from!); + OnControlModified((Panel)sender!); else - base.OnMessage(message, from); + base.OnMessage(message, sender); } public override void OnApplyChanges() { diff --git a/Game.UI/OptionsSubKeyboard.cs b/Game.UI/OptionsSubKeyboard.cs index 84b0986e8..83a25a790 100644 --- a/Game.UI/OptionsSubKeyboard.cs +++ b/Game.UI/OptionsSubKeyboard.cs @@ -332,13 +332,13 @@ public void OpenKeyboardAdvancedDialog() { OptionsSubKeyboardAdvancedDlg.Activate(); } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { if (message.Name == "ItemSelected") { ItemSelected(message.GetInt("itemID", -1)); return; } - base.OnMessage(message, from); + base.OnMessage(message, sender); } } diff --git a/Game.UI/OptionsSubMouse.cs b/Game.UI/OptionsSubMouse.cs index 29c5ef14a..cc73d68d3 100644 --- a/Game.UI/OptionsSubMouse.cs +++ b/Game.UI/OptionsSubMouse.cs @@ -153,12 +153,12 @@ private void UpdateJoystickPanels() { JoyPitchSensitivityPreLabel.SetEnabled(joystickEnabled); } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { if (message.Name.Equals("ControlModified")) - OnControlModified((Panel)from!); + OnControlModified((Panel)sender!); else if (message.Name.Equals("CheckButtonChecked")) - OnControlModified((Panel)from!); + OnControlModified((Panel)sender!); else - base.OnMessage(message, from); + base.OnMessage(message, sender); } } diff --git a/Game.UI/OptionsSubVideo.cs b/Game.UI/OptionsSubVideo.cs index e597c6c0c..69b4b63e9 100644 --- a/Game.UI/OptionsSubVideo.cs +++ b/Game.UI/OptionsSubVideo.cs @@ -550,10 +550,10 @@ public bool RequiresRestart() { return false; } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "TextChanged": - OnTextChanged((Panel)from!); + OnTextChanged((Panel)sender!); break; case "GameUIHidden": OnGameUIHidden(); @@ -565,7 +565,7 @@ public override void OnMessage(KeyValues message, IPanel? from) { OK_Confirmed(); break; default: - base.OnMessage(message, from); + base.OnMessage(message, sender); break; } } @@ -932,13 +932,13 @@ FileStream FOpenGameHDFile(FileMode mode) { throw new NotImplementedException(); } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "ControlModified": OnDataChanged(); break; case "TextChanged": - OnTextChanged((Panel)from!); + OnTextChanged((Panel)sender!); break; case "OpenAdvanced": OpenAdvanced(); @@ -953,7 +953,7 @@ public override void OnMessage(KeyValues message, IPanel? from) { // OpenThirdPartyVideoCreditsDialog(); // break; default: - base.OnMessage(message, from); + base.OnMessage(message, sender); break; } } diff --git a/Game.UI/URLButton.cs b/Game.UI/URLButton.cs index 4fb1b20f1..c25ef1c72 100644 --- a/Game.UI/URLButton.cs +++ b/Game.UI/URLButton.cs @@ -24,7 +24,7 @@ public URLButton(Panel parent, ReadOnlySpan name, ReadOnlySpan text, } } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "PressButton": DoClick(); @@ -36,7 +36,7 @@ public override void OnMessage(KeyValues message, IPanel? from) { OnSetState(message.GetInt("state", 0)); return; default: - base.OnMessage(message, from); + base.OnMessage(message, sender); return; } } diff --git a/Source.Common/GUI/IPanel.cs b/Source.Common/GUI/IPanel.cs index 83232437a..a1384073a 100644 --- a/Source.Common/GUI/IPanel.cs +++ b/Source.Common/GUI/IPanel.cs @@ -134,7 +134,7 @@ public interface IPanel : IExtDisposable void TraverseLevel(int v); void SetPopup(bool v); void OnTick(); - void SendMessage(KeyValues parms, IPanel? from); + void SendMessage(KeyValues parms, IPanel? sender); IPanel? FindChildByName(ReadOnlySpan childName, bool recurseDown); void AddActionSignalTarget(IPanel editablePanel); } diff --git a/Source.Common/GUI/IVGui.cs b/Source.Common/GUI/IVGui.cs index 4dafb0b3a..90571628b 100644 --- a/Source.Common/GUI/IVGui.cs +++ b/Source.Common/GUI/IVGui.cs @@ -15,7 +15,7 @@ public struct MessageItem { public KeyValues Params; public IPanel? To; - public IPanel? From; + public IPanel? Sender; public double ArrivalTime; public ulong MessageID; public MessageItemType Special; @@ -34,7 +34,7 @@ public interface IVGui void Quit(); void RunFrame(); bool DispatchMessages(); - void PostMessage(IPanel? to, KeyValues message, IPanel? from, double delay = 0, MessageItemType type = MessageItemType.TargettingPanel); + void PostMessage(IPanel? to, KeyValues message, IPanel? sender, double delay = 0, MessageItemType type = MessageItemType.TargettingPanel); void Stop(); IVGuiInput GetInput(); void MarkPanelForDeletion(IPanel? panel); diff --git a/Source.Engine/VGui_DrawTreePanel.cs b/Source.Engine/VGui_DrawTreePanel.cs index 26b429c14..d9995b359 100644 --- a/Source.Engine/VGui_DrawTreePanel.cs +++ b/Source.Engine/VGui_DrawTreePanel.cs @@ -203,12 +203,12 @@ public void RecalculateSelectedHighlight() { DrawTreeSelectedPanel = (Panel?)data.GetPtr("PanelPtr"); } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { if (message.Name == "TreeViewItemSelected") { RecalculateSelectedHighlight(); return; } - base.OnMessage(message, from); + base.OnMessage(message, sender); } static readonly KeyValues KV_Command_PerformLayout = new("Command", "command", "performlayout"); diff --git a/Source.GUI.Controls/BuildModeDialog.cs b/Source.GUI.Controls/BuildModeDialog.cs index aaad9d19d..cc90b351a 100644 --- a/Source.GUI.Controls/BuildModeDialog.cs +++ b/Source.GUI.Controls/BuildModeDialog.cs @@ -582,7 +582,7 @@ public void DoPaste() { } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "ApplyDataToControls": ApplyDataToControls(); return; case "TextChanged": OnTextChanged((Panel)message.GetPtr("panel")!); return; diff --git a/Source.GUI.Controls/Button.cs b/Source.GUI.Controls/Button.cs index 18e205fda..d07b85094 100644 --- a/Source.GUI.Controls/Button.cs +++ b/Source.GUI.Controls/Button.cs @@ -41,7 +41,7 @@ public class Button : Label string? DepressedSoundName; string? ReleasedSoundName; - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "PressButton": DoClick(); @@ -59,7 +59,7 @@ public override void OnMessage(KeyValues message, IPanel? from) { OnSetState(message.GetInt("state", 0)); return; default: - base.OnMessage(message, from); + base.OnMessage(message, sender); return; } } diff --git a/Source.GUI.Controls/CheckButton.cs b/Source.GUI.Controls/CheckButton.cs index e910365f5..81360dda6 100644 --- a/Source.GUI.Controls/CheckButton.cs +++ b/Source.GUI.Controls/CheckButton.cs @@ -149,12 +149,12 @@ public void SetHighlightColor(Color color) { } } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { if (message.Name == "CheckButtonChecked") { - OnCheckButtonChecked((Panel)from!); + OnCheckButtonChecked((Panel)sender!); return; } - base.OnMessage(message, from); + base.OnMessage(message, sender); } } diff --git a/Source.GUI.Controls/CheckButtonList.cs b/Source.GUI.Controls/CheckButtonList.cs index 7d0773715..27df4341c 100644 --- a/Source.GUI.Controls/CheckButtonList.cs +++ b/Source.GUI.Controls/CheckButtonList.cs @@ -111,12 +111,12 @@ public override void OnMouseWheeled(int delta) { ScrollBar.SetValue(val); } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { if (message.Name == "CheckButtonChecked") OnCheckButtonChecked(message); else if (message.Name == "ScrollBarSliderMoved") OnScrollBarSliderMoved(); else - base.OnMessage(message, from); + base.OnMessage(message, sender); } } \ No newline at end of file diff --git a/Source.GUI.Controls/ComboBox.cs b/Source.GUI.Controls/ComboBox.cs index e2d3598fa..8b0b8d636 100644 --- a/Source.GUI.Controls/ComboBox.cs +++ b/Source.GUI.Controls/ComboBox.cs @@ -459,7 +459,7 @@ public override void SetUseFallbackFont(bool state, IFont Fallback) { public virtual void OnShowMenu(Menu menu) { } public virtual void OnHideMenu() { } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "MenuItemSelected": OnMenuItemSelected(); @@ -474,7 +474,7 @@ public override void OnMessage(KeyValues message, IPanel? from) { ActivateItem(message.GetInt("itemID", -1)); break; default: - base.OnMessage(message, from); + base.OnMessage(message, sender); break; } } diff --git a/Source.GUI.Controls/ConsoleDialog.cs b/Source.GUI.Controls/ConsoleDialog.cs index 365f3595f..ae54bb84f 100644 --- a/Source.GUI.Controls/ConsoleDialog.cs +++ b/Source.GUI.Controls/ConsoleDialog.cs @@ -617,14 +617,14 @@ internal void OnCloseCompletionList() { CompletionList.SetVisible(false); } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "CloseCompletionList": OnCloseCompletionList(); return; } - base.OnMessage(message, from); + base.OnMessage(message, sender); } public bool TextEntryHasFocus() => Input.GetFocus() == Entry; @@ -811,7 +811,7 @@ private void OnExtraCmd(KeyValues msg) { } #endif - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "CommandSubmitted": OnCommandSubmitted(message.GetString("command")); @@ -826,7 +826,7 @@ public override void OnMessage(KeyValues message, IPanel? from) { #endif } - base.OnMessage(message, from); + base.OnMessage(message, sender); } #if GMOD_DLL diff --git a/Source.GUI.Controls/CvarToggleCheckButton.cs b/Source.GUI.Controls/CvarToggleCheckButton.cs index 6ea7dbb82..7ced3febb 100644 --- a/Source.GUI.Controls/CvarToggleCheckButton.cs +++ b/Source.GUI.Controls/CvarToggleCheckButton.cs @@ -96,7 +96,7 @@ public override void ApplySettings(KeyValues resourceData) { } } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "CheckButtonChecked": OnButtonChecked(); @@ -105,7 +105,7 @@ public override void OnMessage(KeyValues message, IPanel? from) { ApplyChanges(); break; default: - base.OnMessage(message, from); + base.OnMessage(message, sender); break; } } diff --git a/Source.GUI.Controls/EditablePanel.cs b/Source.GUI.Controls/EditablePanel.cs index b51aefd73..a99a1a39f 100644 --- a/Source.GUI.Controls/EditablePanel.cs +++ b/Source.GUI.Controls/EditablePanel.cs @@ -371,7 +371,7 @@ private void OnFindDefaultButton() { } } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "DefaultButtonSet": OnDefaultButtonSet((Panel)message.GetPtr("button")!); @@ -383,7 +383,7 @@ public override void OnMessage(KeyValues message, IPanel? from) { OnFindDefaultButton(); break; default: - base.OnMessage(message, from); + base.OnMessage(message, sender); break; } } diff --git a/Source.GUI.Controls/Frame.cs b/Source.GUI.Controls/Frame.cs index 4bdc5e597..f20f431c0 100644 --- a/Source.GUI.Controls/Frame.cs +++ b/Source.GUI.Controls/Frame.cs @@ -1211,7 +1211,7 @@ private void InternalFlashWindow() { } } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "Close": Close(); @@ -1235,7 +1235,7 @@ public override void OnMessage(KeyValues message, IPanel? from) { OnMinimize(); return; default: - base.OnMessage(message, from); + base.OnMessage(message, sender); break; } } diff --git a/Source.GUI.Controls/HTML.cs b/Source.GUI.Controls/HTML.cs index 7284fd50a..c7eaef748 100644 --- a/Source.GUI.Controls/HTML.cs +++ b/Source.GUI.Controls/HTML.cs @@ -975,7 +975,7 @@ void UpdateSizeAndScrollBars() { InvalidateLayout(); } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "ScrollBarSliderMoved": OnSliderMoved(); @@ -987,16 +987,16 @@ public override void OnMessage(KeyValues message, IPanel? from) { OnFileSelectionCancelled(); break; case "TextChanged": - OnTextChanged((Panel)from!); + OnTextChanged((Panel)sender!); break; case "TextNewLine": - OnEditNewLine((Panel)from!); + OnEditNewLine((Panel)sender!); break; case "DismissJSDialog": DismissJSDialog(message.GetInt("result", 0)); break; default: - base.OnMessage(message, from); + base.OnMessage(message, sender); break; } } diff --git a/Source.GUI.Controls/Menu.cs b/Source.GUI.Controls/Menu.cs index 276aa0c50..fcbf823f3 100644 --- a/Source.GUI.Controls/Menu.cs +++ b/Source.GUI.Controls/Menu.cs @@ -1392,7 +1392,7 @@ public override void OnCommand(ReadOnlySpan command) { base.OnCommand(command); } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "MenuItemSelected": OnMenuItemSelected((Panel)message.GetPtr("panel")!); @@ -1411,7 +1411,7 @@ public override void OnMessage(KeyValues message, IPanel? from) { break; } - base.OnMessage(message, from); + base.OnMessage(message, sender); } } diff --git a/Source.GUI.Controls/MenuButton.cs b/Source.GUI.Controls/MenuButton.cs index 00089fdfc..b52dd6066 100644 --- a/Source.GUI.Controls/MenuButton.cs +++ b/Source.GUI.Controls/MenuButton.cs @@ -213,12 +213,12 @@ public Menu GetMenu() { return Menu; } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { if (message.Name == "MenuClose") { OnMenuClose(); return; } - base.OnMessage(message, from); + base.OnMessage(message, sender); } } diff --git a/Source.GUI.Controls/MenuItem.cs b/Source.GUI.Controls/MenuItem.cs index 522aeb201..8fc328124 100644 --- a/Source.GUI.Controls/MenuItem.cs +++ b/Source.GUI.Controls/MenuItem.cs @@ -335,7 +335,7 @@ public override void GetContentSize(out int wide, out int tall) { tall = Math.Max(tall, ih); } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "MenuClose": OnKillFocus(newPanel: null); @@ -350,7 +350,7 @@ public override void OnMessage(KeyValues message, IPanel? from) { OnKeyModeSet(); break; default: - base.OnMessage(message, from); + base.OnMessage(message, sender); break; } } diff --git a/Source.GUI.Controls/Panel.cs b/Source.GUI.Controls/Panel.cs index 883f86c00..1c392b729 100644 --- a/Source.GUI.Controls/Panel.cs +++ b/Source.GUI.Controls/Panel.cs @@ -3005,7 +3005,7 @@ private void InternalCursorExited() { public bool IsConsoleStylePanel() => false; // todo - public virtual void OnMessage(KeyValues message, IPanel? from) { + public virtual void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "KeyCodePressed": InternalKeyCodePressed((ButtonCode)message.GetInt("code")); break; case "KeyCodeTyped": InternalKeyCodeTyped((ButtonCode)message.GetInt("code")); break; @@ -3036,13 +3036,13 @@ public virtual void OnMessage(KeyValues message, IPanel? from) { #endif #if DEBUG default: - DevMsg(3, $"Unhandled message '{message.Name}' from {from}"); + DevMsg(3, $"Unhandled message '{message.Name}' from {sender}"); break; #endif } if (vgui_print_messages.GetBool()) if (vgui_print_messages.GetInt() == 2 || (!message.Name.Contains("Ticked") && !message.Name.Contains("Moved"))) - Msg($"Message from {from} to {this}: {message.Name}\n"); + Msg($"Message from {sender} to {this}: {message.Name}\n"); } public virtual void OnTextChanged(Panel from) { @@ -3062,8 +3062,8 @@ public virtual void OnTick() { } public virtual void OnMove() { } - public void SendMessage(KeyValues parms, IPanel? from) { - OnMessage(parms, from); + public void SendMessage(KeyValues parms, IPanel? sender) { + OnMessage(parms, sender); } public void SetAllowKeyBindingChainToParent(bool state) { diff --git a/Source.GUI.Controls/PanelListPanel.cs b/Source.GUI.Controls/PanelListPanel.cs index d369d4b52..3147a8858 100644 --- a/Source.GUI.Controls/PanelListPanel.cs +++ b/Source.GUI.Controls/PanelListPanel.cs @@ -302,12 +302,12 @@ public void ScrollToItem(int itemNumber) { InvalidateLayout(); } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { if (message.Name.Equals("ScrollBarSliderMoved")) { OnSliderMoved(message.GetInt("position", 0)); return; } - base.OnMessage(message, from); + base.OnMessage(message, sender); } } diff --git a/Source.GUI.Controls/PropertyDialog.cs b/Source.GUI.Controls/PropertyDialog.cs index 9645a5c9b..956cd155d 100644 --- a/Source.GUI.Controls/PropertyDialog.cs +++ b/Source.GUI.Controls/PropertyDialog.cs @@ -170,12 +170,12 @@ public override void RequestFocus(int direction) { PropertySheet!.RequestFocus(direction); } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { if (message.Name == "ApplyButtonEnable") { OnApplyButtonEnable(); return; } - base.OnMessage(message, from); + base.OnMessage(message, sender); } } diff --git a/Source.GUI.Controls/PropertyPage.cs b/Source.GUI.Controls/PropertyPage.cs index a5be45f67..ecdece2b9 100644 --- a/Source.GUI.Controls/PropertyPage.cs +++ b/Source.GUI.Controls/PropertyPage.cs @@ -39,7 +39,7 @@ public override void SetVisible(bool state) { base.SetVisible(state); } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "ApplyChanges": OnApplyChanges(); @@ -57,7 +57,7 @@ public override void OnMessage(KeyValues message, IPanel? from) { OnPageTabActivated((Panel)message.GetPtr("Panel")!); break; default: - base.OnMessage(message, from); + base.OnMessage(message, sender); break; } } diff --git a/Source.GUI.Controls/PropertySheet.cs b/Source.GUI.Controls/PropertySheet.cs index d5b248a68..756f22e82 100644 --- a/Source.GUI.Controls/PropertySheet.cs +++ b/Source.GUI.Controls/PropertySheet.cs @@ -871,13 +871,13 @@ public override void OnCommand(ReadOnlySpan command) { CallParentFunction(new KeyValues("Command", "command", command)); } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "TabPressed": - OnTabPressed((Panel)from!); + OnTabPressed((Panel)sender!); return; case "TextChanged": - OnTextChanged((Panel)from!, message.GetString("text", "")); + OnTextChanged((Panel)sender!, message.GetString("text", "")); return; case "OpenContextMenu": OnOpenContextMenu(message); @@ -895,7 +895,7 @@ public override void OnMessage(KeyValues message, IPanel? from) { OnFindDefaultButton(); return; default: - base.OnMessage(message, from); + base.OnMessage(message, sender); return; } } diff --git a/Source.GUI.Controls/RadioButton.cs b/Source.GUI.Controls/RadioButton.cs index 621f383f9..2b0181413 100644 --- a/Source.GUI.Controls/RadioButton.cs +++ b/Source.GUI.Controls/RadioButton.cs @@ -244,12 +244,12 @@ public override void OnKeyCodeTyped(ButtonCode code) { return bestRadio; } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { if (message.Name == "RadioButtonChecked") { OnRadioButtonChecked(message.GetInt("tabposition", -1)); return; } - base.OnMessage(message, from); + base.OnMessage(message, sender); } } diff --git a/Source.GUI.Controls/ScrollBar.cs b/Source.GUI.Controls/ScrollBar.cs index 8d92caa0a..00f62a7e1 100644 --- a/Source.GUI.Controls/ScrollBar.cs +++ b/Source.GUI.Controls/ScrollBar.cs @@ -296,13 +296,13 @@ public void OnSliderMoved(int value) { UpdateSliderImages(); } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { switch (message.Name) { case "ScrollBarSliderMoved": OnSliderMoved(message.GetInt("position")); break; default: - base.OnMessage(message, from); + base.OnMessage(message, sender); break; } } diff --git a/Source.GUI.Controls/ScrollableEditablePanel.cs b/Source.GUI.Controls/ScrollableEditablePanel.cs index f6f5c800f..38847b65e 100644 --- a/Source.GUI.Controls/ScrollableEditablePanel.cs +++ b/Source.GUI.Controls/ScrollableEditablePanel.cs @@ -56,12 +56,12 @@ public override void OnMouseWheeled(int delta) { ScrollBar.SetValue(val); } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { if (message.Name == "ScrollBarSliderMoved") { OnScrollBarSliderMoved(); return; } - base.OnMessage(message, from); + base.OnMessage(message, sender); } } \ No newline at end of file diff --git a/Source.GUI.Controls/SectionedListPanel.cs b/Source.GUI.Controls/SectionedListPanel.cs index e10a71359..451ad1fe7 100644 --- a/Source.GUI.Controls/SectionedListPanel.cs +++ b/Source.GUI.Controls/SectionedListPanel.cs @@ -1263,13 +1263,13 @@ public void SetColorOverrideForCell(int sectionID, int itemID, int columnID, Col ColorOverrides.Add(newOverride); } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { if (message.Name.Equals("ScrollBarSliderMoved")) { OnSliderMoved(); return; } - base.OnMessage(message, from); + base.OnMessage(message, sender); } internal bool IsClickable() => Clickable; diff --git a/Source.GUI.Controls/TreeView.cs b/Source.GUI.Controls/TreeView.cs index 2031f7d2d..3e1638d18 100644 --- a/Source.GUI.Controls/TreeView.cs +++ b/Source.GUI.Controls/TreeView.cs @@ -34,12 +34,12 @@ public override void OnTextChanged(Panel from) { GetParent()!.InvalidateLayout(); } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { if (message.Name == "TextChanged") { - OnTextChanged((Panel)from!); + OnTextChanged((Panel)sender!); return; } - base.OnMessage(message, from); + base.OnMessage(message, sender); } public override bool IsKeyRebound(ButtonCode code, KeyModifier modifiers) { @@ -947,12 +947,12 @@ public int CountVisibleIndex() { return count; } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { if (message.Name == "LabelChanged") { OnLabelChanged(message); return; } - base.OnMessage(message, from); + base.OnMessage(message, sender); } } @@ -1691,12 +1691,12 @@ public void SelectAll() { virtual public void GenerateChildrenOfNode(int itemIndex) { } virtual public void GenerateContextMenu(int itemIndex, int x, int y) { } - public override void OnMessage(KeyValues message, IPanel? from) { + public override void OnMessage(KeyValues message, IPanel? sender) { if (message.Name == "SliderMoved") { OnSliderMoved(message.GetInt("position", 0)); return; } - base.OnMessage(message, from); + base.OnMessage(message, sender); } } diff --git a/Source.GUI/VGui.cs b/Source.GUI/VGui.cs index da29a1cc8..80c5da5f9 100644 --- a/Source.GUI/VGui.cs +++ b/Source.GUI/VGui.cs @@ -185,7 +185,7 @@ public bool DispatchMessages() { Input.UpdateCursorPosInternal(xpos, ypos); } - messageItem.To?.SendMessage(parms, messageItem.From); + messageItem.To?.SendMessage(parms, messageItem.Sender); } passCount += 1; if (passCount == 1) @@ -196,7 +196,7 @@ public bool DispatchMessages() { return doneWork; } - public void PostMessage(IPanel? target, KeyValues parms, IPanel? from, double delay = 0, MessageItemType type = MessageItemType.TargettingPanel) { + public void PostMessage(IPanel? target, KeyValues parms, IPanel? sender, double delay = 0, MessageItemType type = MessageItemType.TargettingPanel) { if (IsReentrant()) { Assert(false); return; @@ -209,7 +209,7 @@ public void PostMessage(IPanel? target, KeyValues parms, IPanel? from, double de messageItem.To = target; messageItem.Params = parms; - messageItem.From = from; + messageItem.Sender = sender; messageItem.ArrivalTime = 0; messageItem.MessageID = CurrentMessageID++; messageItem.Special = type; From 15743489ae6e7ace5a020e622c78043efec282d7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Tue, 20 Oct 2026 12:19:26 +0300 Subject: [PATCH 09/14] Send VGUI messages with the panel they refer to as sender --- Source.GUI.Controls/BuildGroup.cs | 2 +- Source.GUI.Controls/EditablePanel.cs | 2 +- Source.GUI.Controls/Menu.cs | 4 ++-- Source.GUI.Controls/MenuButton.cs | 2 +- Source.GUI.Controls/MenuItem.cs | 4 ++-- Source.GUI.Controls/Panel.cs | 2 +- Source.GUI.Controls/PropertySheet.cs | 4 ++-- Source.GUI/VGuiInput.cs | 2 +- 8 files changed, 11 insertions(+), 11 deletions(-) diff --git a/Source.GUI.Controls/BuildGroup.cs b/Source.GUI.Controls/BuildGroup.cs index a96f09aba..fe14748d6 100644 --- a/Source.GUI.Controls/BuildGroup.cs +++ b/Source.GUI.Controls/BuildGroup.cs @@ -299,7 +299,7 @@ private void ActivateBuildDialog() { CurrentPanel = ParentPanel; KeyValues keyval = new KeyValues("SetActiveControl"); keyval.SetPtr("PanelPtr", GetCurrentPanel()); - VGui.PostMessage(BuildDialog, keyval, null); + VGui.PostMessage(BuildDialog, keyval, GetCurrentPanel()); } public bool IsEnabled() => Enabled; diff --git a/Source.GUI.Controls/EditablePanel.cs b/Source.GUI.Controls/EditablePanel.cs index a99a1a39f..067def0a3 100644 --- a/Source.GUI.Controls/EditablePanel.cs +++ b/Source.GUI.Controls/EditablePanel.cs @@ -356,7 +356,7 @@ private void OnCurrentDefaultButtonSet(Panel defaultButton) { if (GetParent() != null) { KeyValues msg = new("CurrentDefaultButtonSet"); msg.SetPtr("button", defaultButton); - PostMessage(GetParent()!, msg); + VGui.PostMessage(GetParent(), msg, defaultButton); } } diff --git a/Source.GUI.Controls/Menu.cs b/Source.GUI.Controls/Menu.cs index fcbf823f3..c6fa2d671 100644 --- a/Source.GUI.Controls/Menu.cs +++ b/Source.GUI.Controls/Menu.cs @@ -938,7 +938,7 @@ public void OnMenuItemSelected(Panel panel) { if (parentMenu != null) { KeyValues kv = new("MenuItemSelected"); kv.SetPtr("panel", panel); - VGui.PostMessage(parentMenu, kv, this); + VGui.PostMessage(parentMenu, kv, panel); } } @@ -961,7 +961,7 @@ public void OnMenuItemSelected(Panel panel) { if (GetParent() != null) { KeyValues kv = new("MenuItemSelected"); kv.SetPtr("panel", panel); - VGui.PostMessage(GetParent(), kv, this); + VGui.PostMessage(GetParent(), kv, panel); } } diff --git a/Source.GUI.Controls/MenuButton.cs b/Source.GUI.Controls/MenuButton.cs index b52dd6066..480e9336c 100644 --- a/Source.GUI.Controls/MenuButton.cs +++ b/Source.GUI.Controls/MenuButton.cs @@ -124,7 +124,7 @@ public override void OnCursorEntered() { KeyValues msg = new("CursorEnteredMenuButton"); msg.SetPtr("VPanel", this); - VGui.PostMessage(GetParent(), msg, null); + VGui.PostMessage(GetParent(), msg, this); } public void SetDropMenuButtonStyle(bool state) { diff --git a/Source.GUI.Controls/MenuItem.cs b/Source.GUI.Controls/MenuItem.cs index 8fc328124..3a9817d6e 100644 --- a/Source.GUI.Controls/MenuItem.cs +++ b/Source.GUI.Controls/MenuItem.cs @@ -108,13 +108,13 @@ public override void OnCursorMoved(int x, int y) { public override void OnCursorEntered() { KeyValues msg = new KeyValues("CursorEnteredMenuItem"); msg.SetPtr("Panel", this); - VGui.PostMessage(GetParent(), msg, null); + VGui.PostMessage(GetParent(), msg, this); } public override void OnCursorExited() { KeyValues msg = new KeyValues("CursorExitedMenuItem"); msg.SetPtr("Panel", this); - VGui.PostMessage(GetParent(), msg, null); + VGui.PostMessage(GetParent(), msg, this); } public void ArmItem() { diff --git a/Source.GUI.Controls/Panel.cs b/Source.GUI.Controls/Panel.cs index 1c392b729..e5b18972d 100644 --- a/Source.GUI.Controls/Panel.cs +++ b/Source.GUI.Controls/Panel.cs @@ -2182,7 +2182,7 @@ public virtual bool IsBuildGroupEnabled() { public void CallParentFunction(KeyValues message) => GetParent()?.SendMessage(message, this); public virtual void OnRequestFocus(Panel subFocus, Panel? defaultPanel) - => CallParentFunction(new KeyValues("OnRequestFocus").AddSubKey(new("subFocus", subFocus)).AddSubKey(new("defaultPanel", defaultPanel))); + => GetParent()?.SendMessage(new KeyValues("OnRequestFocus").AddSubKey(new("subFocus", subFocus)).AddSubKey(new("defaultPanel", defaultPanel)), subFocus); public virtual bool RequestFocusNext(IPanel? existingPanel = null) { #if GMOD_DLL diff --git a/Source.GUI.Controls/PropertySheet.cs b/Source.GUI.Controls/PropertySheet.cs index 756f22e82..6cc329131 100644 --- a/Source.GUI.Controls/PropertySheet.cs +++ b/Source.GUI.Controls/PropertySheet.cs @@ -759,7 +759,7 @@ public void ChangeActiveTab(int index) { VGui.PostMessage(ActivePage, new KeyValues("PageHide"), this); KeyValues msg = new("PageTabActivated"); msg.SetPtr("panel", null); - VGui.PostMessage(ActivePage, msg, this); + VGui.PostMessage(ActivePage, msg, null); } if (ActiveTab != null) { @@ -805,7 +805,7 @@ public void ChangeActiveTab(int index) { KeyValues msg2 = new("PageTabActivated"); msg2.SetPtr("panel", ActivePage); - VGui.PostMessage(ActivePage, msg2, this); + VGui.PostMessage(ActivePage, msg2, ActivePage); PostActionSignal(new KeyValues("PageChanged")); diff --git a/Source.GUI/VGuiInput.cs b/Source.GUI/VGuiInput.cs index 866fb3848..629e0a38a 100644 --- a/Source.GUI/VGuiInput.cs +++ b/Source.GUI/VGuiInput.cs @@ -653,7 +653,7 @@ public unsafe void RunFrame() { KeyValues pMessage = new KeyValues("KillFocus"); pMessage.SetPtr("newPanel", wantedKeyFocus); - context.KeyFocus.SendMessage(pMessage, null); + context.KeyFocus.SendMessage(pMessage, wantedKeyFocus); context.KeyFocus?.Repaint(); From bde7f5137a755b11f5cc40e0b18d7c5a721b79cf Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Tue, 20 Oct 2026 12:47:52 +0300 Subject: [PATCH 10/14] Add generated VGUI message and command maps --- .../PanelMessageMapGenerator.cs | 260 ++++++++++++++++++ Source.GUI.Controls/Panel.cs | 89 +++--- Source.GUI.Controls/PanelMessageMap.cs | 88 ++++++ 3 files changed, 399 insertions(+), 38 deletions(-) create mode 100644 Source.CodeAnalysis.VGUI/PanelMessageMapGenerator.cs create mode 100644 Source.GUI.Controls/PanelMessageMap.cs diff --git a/Source.CodeAnalysis.VGUI/PanelMessageMapGenerator.cs b/Source.CodeAnalysis.VGUI/PanelMessageMapGenerator.cs new file mode 100644 index 000000000..9213c02ef --- /dev/null +++ b/Source.CodeAnalysis.VGUI/PanelMessageMapGenerator.cs @@ -0,0 +1,260 @@ +using Microsoft.CodeAnalysis; +using Microsoft.CodeAnalysis.CSharp; +using Microsoft.CodeAnalysis.Text; + +using System.Collections.Generic; +using System.Linq; +using System.Text; + +namespace Source.CodeAnalysis.VGUI +{ + [Generator(LanguageNames.CSharp)] + public sealed class PanelMessageMapGenerator : IIncrementalGenerator + { + const string Controls = "Source.GUI.Controls."; + const string G = "global::"; + + static readonly DiagnosticDescriptor UnsupportedHandler = new DiagnosticDescriptor( + id: "VGUI002", + title: "Unsupported message or command handler", + messageFormat: "'{0}' cannot be used as a VGUI handler: {1}", + category: "VGUI", + defaultSeverity: DiagnosticSeverity.Error, + isEnabledByDefault: true); + + public void Initialize(IncrementalGeneratorInitializationContext context) { + context.RegisterSourceOutput(context.CompilationProvider, static (spc, compilation) => Execute(spc, compilation)); + } + + sealed class Symbols + { + public INamedTypeSymbol Panel = null!; + public INamedTypeSymbol UiMessage = null!; + public INamedTypeSymbol UiCommand = null!; + public INamedTypeSymbol? MessageParam; + public INamedTypeSymbol? KeyValues; + public INamedTypeSymbol? Color; + } + + static void Execute(SourceProductionContext spc, Compilation compilation) { + INamedTypeSymbol? panel = compilation.GetTypeByMetadataName(Controls + "Panel"); + INamedTypeSymbol? uiMessage = compilation.GetTypeByMetadataName(Controls + "UiMessageAttribute"); + INamedTypeSymbol? uiCommand = compilation.GetTypeByMetadataName(Controls + "UiCommandAttribute"); + if (panel == null || uiMessage == null || uiCommand == null || compilation.GetTypeByMetadataName(Controls + "PanelMessageMap") == null) + return; + + Symbols s = new Symbols { + Panel = panel, + UiMessage = uiMessage, + UiCommand = uiCommand, + MessageParam = compilation.GetTypeByMetadataName(Controls + "MessageParamAttribute"), + KeyValues = compilation.GetTypeByMetadataName("Source.Common.Formats.Keyvalues.KeyValues"), + Color = compilation.GetTypeByMetadataName("System.Drawing.Color"), + }; + + List panels = new List(); + CollectPanels(compilation.Assembly.GlobalNamespace, s, panels); + + StringBuilder accessors = new StringBuilder(); + StringBuilder body = new StringBuilder(); + int accessorId = 0; + + foreach (INamedTypeSymbol type in panels) + Handlers(spc, type, s, accessors, body, ref accessorId); + + if (body.Length == 0) + return; + + StringBuilder sb = new StringBuilder(); + sb.AppendLine("// "); + sb.AppendLine("#nullable enable"); + sb.AppendLine("#pragma warning disable CA2255"); + sb.AppendLine(); + sb.AppendLine("namespace Source.Generated;"); + sb.AppendLine(); + sb.AppendLine("internal static class VGuiPanelMessageMaps"); + sb.AppendLine("{"); + sb.Append(accessors); + sb.AppendLine("\t[global::System.Runtime.CompilerServices.ModuleInitializer]"); + sb.AppendLine("\tinternal static void Register() {"); + sb.Append(body); + sb.AppendLine("\t}"); + sb.AppendLine("}"); + + spc.AddSource("VGuiPanelMessageMaps.g.cs", SourceText.From(sb.ToString(), Encoding.UTF8)); + } + + static void CollectPanels(INamespaceOrTypeSymbol container, Symbols s, List panels) { + foreach (ISymbol member in container.GetMembers()) { + if (member is INamespaceSymbol ns) + CollectPanels(ns, s, panels); + else if (member is INamedTypeSymbol type) { + if (type.TypeKind == TypeKind.Class && DerivesFrom(type, s.Panel)) + panels.Add(type); + CollectPanels(type, s, panels); + } + } + } + + static bool IsGeneric(INamedTypeSymbol type) { + for (INamedTypeSymbol? t = type; t != null; t = t.ContainingType) + if (t.IsGenericType) + return true; + return false; + } + + static bool DerivesFrom(INamedTypeSymbol type, INamedTypeSymbol baseType) { + for (INamedTypeSymbol? t = type; t != null; t = t.BaseType) + if (SymbolEqualityComparer.Default.Equals(t, baseType)) + return true; + return false; + } + + static bool IsAccessible(INamedTypeSymbol type) { + for (INamedTypeSymbol? t = type; t != null; t = t.ContainingType) { + Accessibility a = t.DeclaredAccessibility; + if (a != Accessibility.Public && a != Accessibility.Internal && a != Accessibility.ProtectedOrInternal) + return false; + } + return true; + } + + static void Handlers(SourceProductionContext spc, INamedTypeSymbol type, Symbols s, StringBuilder accessors, StringBuilder body, ref int accessorId) { + string typeName = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + + foreach (IMethodSymbol method in type.GetMembers().OfType()) { + if (method.MethodKind != MethodKind.Ordinary) + continue; + + List messages = AttributeStrings(method, s.UiMessage); + List commands = AttributeStrings(method, s.UiCommand); + if (messages.Count == 0 && commands.Count == 0) + continue; + + if (IsGeneric(type) || !IsAccessible(type)) { + spc.ReportDiagnostic(Diagnostic.Create(UnsupportedHandler, method.Locations.FirstOrDefault(), method.ToDisplayString(), "the containing panel must be a non-generic type accessible from generated code")); + continue; + } + + if (method.IsStatic || method.IsGenericMethod || method.Parameters.Any(p => p.RefKind != RefKind.None)) { + spc.ReportDiagnostic(Diagnostic.Create(UnsupportedHandler, method.Locations.FirstOrDefault(), method.ToDisplayString(), "handlers must be non-generic instance methods without ref, in or out parameters")); + continue; + } + + string accessor = "__Handler" + accessorId++; + string returnType = method.ReturnsVoid ? "void" : method.ReturnType.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + string parameters = string.Concat(method.Parameters.Select(p => ", " + p.Type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat) + " " + p.Name)); + accessors.AppendLine($"\t[global::System.Runtime.CompilerServices.UnsafeAccessor(global::System.Runtime.CompilerServices.UnsafeAccessorKind.Method, Name = {Literal(method.Name)})]"); + accessors.AppendLine($"\tstatic extern {returnType} {accessor}({typeName} owner{parameters});"); + accessors.AppendLine(); + + if (commands.Count > 0) { + string? senderArg = null; + if (method.Parameters.Length == 1) + senderArg = SenderArgument(method.Parameters[0], s); + + if (method.Parameters.Length > 1 || (method.Parameters.Length == 1 && senderArg == null)) { + spc.ReportDiagnostic(Diagnostic.Create(UnsupportedHandler, method.Locations.FirstOrDefault(), method.ToDisplayString(), "command handlers take no parameters or only the sender panel")); + continue; + } + + string commandCall = $"{accessor}(({typeName})p{(senderArg != null ? ", " + senderArg : "")})"; + foreach (string command in commands) + body.AppendLine($"\t\t{G}Source.GUI.Controls.PanelMessageMap.AddCommandHandler(typeof({typeName}), {Literal(command)}, static (p, sender) => {commandCall});"); + } + + if (messages.Count > 0) { + List args = new List(); + string? error = null; + foreach (IParameterSymbol parameter in method.Parameters) { + string? arg = Argument(parameter, s); + if (arg == null) { + error = $"parameter '{parameter.Name}' of type '{parameter.Type.ToDisplayString()}' cannot be read from a message"; + break; + } + args.Add(arg); + } + + if (error != null) { + spc.ReportDiagnostic(Diagnostic.Create(UnsupportedHandler, method.Locations.FirstOrDefault(), method.ToDisplayString(), error)); + continue; + } + + string call = $"{accessor}(({typeName})p{string.Concat(args.Select(a => ", " + a))})"; + foreach (string message in messages) + body.AppendLine($"\t\t{G}Source.GUI.Controls.PanelMessageMap.AddMessageHandler(typeof({typeName}), {Literal(message)}, static (p, m, sender) => {call});"); + } + } + } + + static List AttributeStrings(ISymbol symbol, INamedTypeSymbol? attributeType) { + List values = new List(); + if (attributeType == null) + return values; + + foreach (AttributeData attribute in symbol.GetAttributes()) { + if (SymbolEqualityComparer.Default.Equals(attribute.AttributeClass, attributeType) && attribute.ConstructorArguments.Length == 1 && attribute.ConstructorArguments[0].Value is string value) + values.Add(value); + } + return values; + } + + static string? SenderArgument(IParameterSymbol parameter, Symbols s) { + ITypeSymbol type = parameter.Type; + if (parameter.Ordinal != 0 || !(type is INamedTypeSymbol panelType) || !DerivesFrom(panelType, s.Panel)) + return null; + + string typeName = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + bool nullable = type.NullableAnnotation == NullableAnnotation.Annotated; + return $"({typeName})sender{(nullable ? "" : "!")}"; + } + + static string? Argument(IParameterSymbol parameter, Symbols s) { + ITypeSymbol type = parameter.Type; + string typeName = type.ToDisplayString(SymbolDisplayFormat.FullyQualifiedFormat); + bool nullable = type.NullableAnnotation == NullableAnnotation.Annotated; + + string? sender = SenderArgument(parameter, s); + if (sender != null) + return sender; + + List keys = AttributeStrings(parameter, s.MessageParam); + if (keys.Count == 0 && s.KeyValues != null && SymbolEqualityComparer.Default.Equals(type.WithNullableAnnotation(NullableAnnotation.NotAnnotated), s.KeyValues)) + return "m"; + + string key = Literal(keys.Count > 0 ? keys[0] : parameter.Name); + + switch (type.SpecialType) { + case SpecialType.System_Int32: return $"m.GetInt({key})"; + case SpecialType.System_Boolean: return $"m.GetInt({key}) != 0"; + case SpecialType.System_Single: return $"m.GetFloat({key})"; + case SpecialType.System_Double: return $"(double)m.GetFloat({key})"; + case SpecialType.System_UInt64: return $"m.GetUint64({key})"; + case SpecialType.System_String: return $"new string(m.GetString({key}))"; + case SpecialType.System_Char: + case SpecialType.System_SByte: + case SpecialType.System_Byte: + case SpecialType.System_Int16: + case SpecialType.System_UInt16: + case SpecialType.System_UInt32: + return $"({typeName})m.GetInt({key})"; + } + + if (type.TypeKind == TypeKind.Enum) + return $"({typeName})m.GetInt({key})"; + + if (s.Color != null && SymbolEqualityComparer.Default.Equals(type, s.Color)) + return $"m.GetColor({key})"; + + if (type is INamedTypeSymbol named && named.IsGenericType && named.ConstructedFrom.ToDisplayString() == "System.ReadOnlySpan" && named.TypeArguments[0].SpecialType == SpecialType.System_Char) + return $"m.GetString({key})"; + + if (type.IsReferenceType) + return $"({typeName})m.GetPtr({key}){(nullable ? "" : "!")}"; + + return null; + } + + static string Literal(string value) => SymbolDisplay.FormatLiteral(value, true); + } +} diff --git a/Source.GUI.Controls/Panel.cs b/Source.GUI.Controls/Panel.cs index e5b18972d..ca8150844 100644 --- a/Source.GUI.Controls/Panel.cs +++ b/Source.GUI.Controls/Panel.cs @@ -1090,6 +1090,7 @@ public ReadOnlySpan GetName() { public Panel? GetParent() => Parent; IPanel? IPanel.GetParent() => Parent; + [UiMessage("OnScreenSizeChanged")] public virtual void OnScreenSizeChanged(int oldWide, int oldTall) { for (int i = 0; i < GetChildCount(); i++) { IPanel child = GetChild(i); @@ -1468,6 +1469,9 @@ protected bool PushLuaHook(LUA_POOLEDSTRING name) { return false; } +#if GMOD_DLL + [UiMessage("activate")] +#endif public virtual void OnActivate() { if (!PushLuaHook(LUA_POOLEDSTRING.OnActivate)) return; @@ -1476,6 +1480,9 @@ public virtual void OnActivate() { Lua!.CallInternalNoReturns(1); } +#if GMOD_DLL + [UiMessage("deactivate")] +#endif public virtual void OnDeactivate() { if (!PushLuaHook(LUA_POOLEDSTRING.OnDeactivate)) return; @@ -2181,8 +2188,9 @@ public virtual bool IsBuildGroupEnabled() { public void CallParentFunction(KeyValues message) => GetParent()?.SendMessage(message, this); - public virtual void OnRequestFocus(Panel subFocus, Panel? defaultPanel) - => GetParent()?.SendMessage(new KeyValues("OnRequestFocus").AddSubKey(new("subFocus", subFocus)).AddSubKey(new("defaultPanel", defaultPanel)), subFocus); + [UiMessage("OnRequestFocus")] + public virtual void OnRequestFocus(Panel sender, Panel? defaultPanel) + => GetParent()?.SendMessage(new KeyValues("OnRequestFocus").AddSubKey(new("subFocus", sender)).AddSubKey(new("defaultPanel", defaultPanel)), sender); public virtual bool RequestFocusNext(IPanel? existingPanel = null) { #if GMOD_DLL @@ -2551,6 +2559,19 @@ public virtual void MarkForDeletion() { public virtual void DoModal() { } #endif + PanelHandlerTable? handlerTable; + PanelHandlerTable HandlerTable => handlerTable ??= PanelMessageMap.GetTable(GetType()); + + public void DoCommand(ReadOnlySpan command, IPanel? sender = null) { + if (HandlerTable.TryGetCommand(command, out PanelCommandHandler handler)) + handler(this, sender); + else + OnCommand(command); + } + + [UiMessage("Command")] + private void OnCommandMessage(Panel? sender, ReadOnlySpan command) => DoCommand(command, sender); + public virtual void OnCommand(ReadOnlySpan command) { if (command.Equals("performlayout", StringComparison.OrdinalIgnoreCase)) InvalidateLayout(); @@ -2559,6 +2580,7 @@ public virtual void OnCommand(ReadOnlySpan command) { else PostActionSignal(new KeyValues(command)); } + [UiMessage("MouseCaptureLost")] public virtual void OnMouseCaptureLost() => Tooltips?.ResetDelay(); public virtual void OnSetFocus() { Repaint(); @@ -2638,6 +2660,7 @@ public virtual void OnMousePressed(ButtonCode code) { #endif } public virtual void OnMouseDoublePressed(ButtonCode code) { } + [UiMessage("MouseReleased")] public virtual void OnMouseReleased(ButtonCode code) { #if GMOD_DLL if (IsWorldClicker()) @@ -2650,6 +2673,7 @@ public virtual void OnMouseReleased(ButtonCode code) { #endif } public virtual void OnMouseMismatchedRelease(ButtonCode code, IPanel? pressedPanel) { } + [UiMessage("MouseWheeled")] public virtual void OnMouseWheeled(int delta) { #if GMOD_DLL if (PushLuaHook(LUA_POOLEDSTRING.OnMouseWheeled)) { @@ -2661,6 +2685,7 @@ public virtual void OnMouseWheeled(int delta) { #endif CallParentFunction(new KeyValues("MouseWheeled", "delta", delta)); } + [UiMessage("DialogVariables")] public virtual void OnDialogVariablesChanged(KeyValues variables) { } bool TriplePressAllowed; public virtual void SetTriplePressAllowed(bool state) => TriplePressAllowed = state; @@ -2779,6 +2804,7 @@ public void NavigateDown() { } + [UiMessage("KeyTyped")] public virtual void OnKeyTyped(char unichar) { } public virtual void OnKeyCodeReleased(ButtonCode code) { #if GMOD_DLL @@ -2786,11 +2812,14 @@ public virtual void OnKeyCodeReleased(ButtonCode code) { #endif CallParentFunction(new KeyValues("KeyCodeReleased", "code", (int)code)); } + [UiMessage("UnhandledMouseClick")] public virtual void OnUnhandledMouseClick(ButtonCode code) { } + [UiMessage("KeyFocusTicked")] public void InternalKeyFocusTicked() { OnKeyFocusTicked(); } public virtual void OnKeyFocusTicked() { } + [UiMessage("MouseFocusTicked")] public void InternalMouseFocusTicked() { InternalSetCursor(); OnMouseFocusTicked(); @@ -2799,7 +2828,9 @@ public virtual void OnMouseFocusTicked() { // Send it to the parent GetParent()?.OnMouseFocusTicked(); } + [UiMessage("Close")] public virtual void OnClose() { } + [UiMessage("Delete")] public virtual void OnDelete() { Dispose(); } @@ -2824,6 +2855,7 @@ public void ParentLocalToScreen(ref int x, ref int y) { static ConVar vgui_print_messages = new("0", FCvar.None); + [UiMessage("KeyCodePressed")] public void InternalKeyCodePressed(ButtonCode code) { if (!ShouldHandleInputMessage()) return; @@ -2857,6 +2889,7 @@ public bool ShouldHandleInputMessage() { private bool GetForceStereoRenderToFrameBuffer() => ForceStereoRenderToFrameBuffer; public void SetForceStereoRenderToFrameBuffer(bool state) => ForceStereoRenderToFrameBuffer = state; + [UiMessage("KeyCodeTyped")] public void InternalKeyCodeTyped(ButtonCode code) { if (!ShouldHandleInputMessage()) { Input.OnKeyCodeUnhandled(code); @@ -2898,6 +2931,7 @@ virtual public bool IsKeyRebound(ButtonCode code, KeyModifier modifiers) { return false; } + [UiMessage("MousePressed")] private void InternalMousePressed(ButtonCode code) { // todo triple press/dragdrop etc @@ -2920,6 +2954,7 @@ private void InternalMousePressed(ButtonCode code) { OnMousePressed(code); } + [UiMessage("KeyCodeReleased")] private void InternalKeyCodeReleased(ButtonCode code) { if (!ShouldHandleInputMessage()) return; @@ -2930,7 +2965,8 @@ private void InternalKeyCodeReleased(ButtonCode code) { CallParentFunction(new KeyValues("KeyCodeReleased", "code", (int)code)); } - private void InternalCursorMoved(int x, int y) { + [UiMessage("CursorMoved")] + private void InternalCursorMoved([MessageParam("xpos")] int x, [MessageParam("ypos")] int y) { // dragdrop todo if (!ShouldHandleInputMessage()) @@ -2964,6 +3000,7 @@ private void InternalCursorMoved(int x, int y) { private bool IsCursorNone() => GetCursor() == CursorCode.None; + [UiMessage("CursorEntered")] private void InternalCursorEntered() { if (IsCursorNone() || !IsMouseInputEnabled()) return; @@ -2985,6 +3022,7 @@ private void InternalCursorEntered() { OnCursorEntered(); } + [UiMessage("CursorExited")] private void InternalCursorExited() { #if GMOD_DLL if (Lua != null && LuaTable != null) @@ -3006,55 +3044,30 @@ private void InternalCursorExited() { public bool IsConsoleStylePanel() => false; // todo public virtual void OnMessage(KeyValues message, IPanel? sender) { - switch (message.Name) { - case "KeyCodePressed": InternalKeyCodePressed((ButtonCode)message.GetInt("code")); break; - case "KeyCodeTyped": InternalKeyCodeTyped((ButtonCode)message.GetInt("code")); break; - case "KeyTyped": OnKeyTyped((char)message.GetInt("unichar")); break; - case "KeyCodeReleased": InternalKeyCodeReleased((ButtonCode)message.GetInt("code")); break; - case "CursorEntered": InternalCursorEntered(); break; - case "CursorExited": InternalCursorExited(); break; - case "CursorMoved": InternalCursorMoved(message.GetInt("xpos"), message.GetInt("ypos")); break; - case "MouseFocusTicked": InternalMouseFocusTicked(); break; - case "KeyFocusTicked": InternalKeyFocusTicked(); break; - case "MouseCaptureLost": OnMouseCaptureLost(); break; - case "MousePressed": InternalMousePressed((ButtonCode)message.GetInt("code")); break; - case "MouseWheeled": OnMouseWheeled(message.GetInt("delta")); break; - case "MouseReleased": OnMouseReleased((ButtonCode)message.GetInt("code")); break; - case "UnhandledMouseClick": OnUnhandledMouseClick((ButtonCode)message.GetInt("code")); break; - case "SetFocus": InternalSetFocus(); break; - case "KillFocus": InternalKillFocus((Panel?)message.GetPtr("newPanel")); break; - case "TextChanged": OnTextChanged((Panel)message.GetPtr("panel")!); break; - case "Delete": OnDelete(); break; - case "Close": OnClose(); break; - case "OnRequestFocus": OnRequestFocus(message.GetPtr("subFocus")!, message.GetPtr("defaultPanel")); break; - case "OnScreenSizeChanged": OnScreenSizeChanged(message.GetInt("oldwide"), message.GetInt("oldtall")); break; - case "Command": OnCommand(message.GetString("command")); break; - case "DialogVariables": OnDialogVariablesChanged(message); break; -#if GMOD_DLL - case "activate": OnActivate(); break; - case "deactivate": OnDeactivate(); break; -#endif + if (HandlerTable.TryGetMessage(message.Name, out PanelMessageHandler handler)) + handler(this, message, sender); #if DEBUG - default: - DevMsg(3, $"Unhandled message '{message.Name}' from {sender}"); - break; + else + DevMsg(3, $"Unhandled message '{message.Name}' from {sender}"); #endif - } if (vgui_print_messages.GetBool()) if (vgui_print_messages.GetInt() == 2 || (!message.Name.Contains("Ticked") && !message.Name.Contains("Moved"))) Msg($"Message from {sender} to {this}: {message.Name}\n"); } - public virtual void OnTextChanged(Panel from) { + [UiMessage("TextChanged")] + public virtual void OnTextChanged(Panel sender) { } + [UiMessage("SetFocus")] private void InternalSetFocus() { OnSetFocus(); } - private void InternalKillFocus(Panel? newPanel) { - OnKillFocus(newPanel); + [UiMessage("KillFocus")] + private void InternalKillFocus(Panel? sender) { + OnKillFocus(sender); } diff --git a/Source.GUI.Controls/PanelMessageMap.cs b/Source.GUI.Controls/PanelMessageMap.cs new file mode 100644 index 000000000..10f60e0ac --- /dev/null +++ b/Source.GUI.Controls/PanelMessageMap.cs @@ -0,0 +1,88 @@ +using Source.Common.Formats.Keyvalues; +using Source.Common.GUI; + +using System.Collections.Concurrent; +using System.Collections.Frozen; + +namespace Source.GUI.Controls; + +[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] +public sealed class UiMessageAttribute(string message) : Attribute +{ + public string Message { get; } = message; +} + +[AttributeUsage(AttributeTargets.Method, AllowMultiple = true)] +public sealed class UiCommandAttribute(string command) : Attribute +{ + public string Command { get; } = command; +} + +[AttributeUsage(AttributeTargets.Parameter)] +public sealed class MessageParamAttribute(string key) : Attribute +{ + public string Key { get; } = key; +} + +public delegate void PanelMessageHandler(Panel panel, KeyValues message, IPanel? sender); +public delegate void PanelCommandHandler(Panel panel, IPanel? sender); + +public sealed class PanelHandlerTable +{ + readonly FrozenDictionary messages; + readonly FrozenDictionary.AlternateLookup> commands; + + internal PanelHandlerTable(Dictionary messages, Dictionary commands) { + this.messages = messages.ToFrozenDictionary(StringComparer.OrdinalIgnoreCase); + this.commands = commands.ToFrozenDictionary(StringComparer.OrdinalIgnoreCase).GetAlternateLookup>(); + } + + public bool TryGetMessage(string message, out PanelMessageHandler handler) => messages.TryGetValue(message, out handler!); + public bool TryGetCommand(ReadOnlySpan command, out PanelCommandHandler handler) => commands.TryGetValue(command, out handler!); +} + +public static class PanelMessageMap +{ + static readonly Dictionary> messageHandlers = []; + static readonly Dictionary> commandHandlers = []; + static readonly ConcurrentDictionary tables = []; + + public static void AddMessageHandler(Type type, string message, PanelMessageHandler handler) { + lock (messageHandlers) { + if (!messageHandlers.TryGetValue(type, out Dictionary? map)) + messageHandlers[type] = map = []; + map[message] = handler; + } + } + + public static void AddCommandHandler(Type type, string command, PanelCommandHandler handler) { + lock (messageHandlers) { + if (!commandHandlers.TryGetValue(type, out Dictionary? map)) + commandHandlers[type] = map = []; + map[command] = handler; + } + } + + public static PanelHandlerTable GetTable(Type type) => tables.GetOrAdd(type, BuildTable); + + static PanelHandlerTable BuildTable(Type type) { + List chain = []; + for (Type? t = type; t != null && t != typeof(object); t = t.BaseType) + chain.Add(t); + + Dictionary messages = new(StringComparer.OrdinalIgnoreCase); + Dictionary commands = new(StringComparer.OrdinalIgnoreCase); + lock (messageHandlers) { + for (int i = chain.Count - 1; i >= 0; i--) { + if (messageHandlers.TryGetValue(chain[i], out Dictionary? m)) + foreach (KeyValuePair entry in m) + messages[entry.Key] = entry.Value; + if (commandHandlers.TryGetValue(chain[i], out Dictionary? c)) + foreach (KeyValuePair entry in c) + commands[entry.Key] = entry.Value; + } + } + + return new PanelHandlerTable(messages, commands); + } +} From a2adf687c4cb085a86973ca4501d2660a543a26f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Tue, 20 Oct 2026 12:58:11 +0300 Subject: [PATCH 11/14] Convert Source.GUI.Controls handlers to message maps --- Source.GUI.Controls/AnimationController.cs | 2 +- Source.GUI.Controls/BuildGroup.cs | 2 +- Source.GUI.Controls/BuildModeDialog.cs | 15 +-- Source.GUI.Controls/Button.cs | 27 +---- Source.GUI.Controls/CheckButton.cs | 12 +-- Source.GUI.Controls/CheckButtonList.cs | 11 +- Source.GUI.Controls/ComboBox.cs | 33 ++---- Source.GUI.Controls/ConsoleDialog.cs | 95 ++++++---------- Source.GUI.Controls/CvarToggleCheckButton.cs | 16 +-- Source.GUI.Controls/EditablePanel.cs | 38 +++---- Source.GUI.Controls/Frame.cs | 55 ++-------- Source.GUI.Controls/HTML.cs | 101 ++++++++---------- Source.GUI.Controls/Menu.cs | 53 ++++----- Source.GUI.Controls/MenuButton.cs | 10 +- Source.GUI.Controls/MenuItem.cs | 24 ++--- Source.GUI.Controls/MessageBox.cs | 42 +++++--- Source.GUI.Controls/PanelListPanel.cs | 10 +- Source.GUI.Controls/PropertyDialog.cs | 47 ++++---- Source.GUI.Controls/PropertyPage.cs | 30 ++---- Source.GUI.Controls/PropertySheet.cs | 73 +++++-------- Source.GUI.Controls/QueryBox.cs | 27 +++-- Source.GUI.Controls/RadioButton.cs | 12 +-- Source.GUI.Controls/ScrollBar.cs | 14 +-- .../ScrollableEditablePanel.cs | 10 +- Source.GUI.Controls/SectionedListPanel.cs | 10 +- Source.GUI.Controls/TreeView.cs | 31 +----- 26 files changed, 258 insertions(+), 542 deletions(-) diff --git a/Source.GUI.Controls/AnimationController.cs b/Source.GUI.Controls/AnimationController.cs index 636779402..18ed220ee 100644 --- a/Source.GUI.Controls/AnimationController.cs +++ b/Source.GUI.Controls/AnimationController.cs @@ -257,7 +257,7 @@ private void UpdatePostedMessages(bool runToCompletion) { } break; case AnimCommandType.FireCommand: { - msg.Parent.OnCommand(ScriptSymbols.String(msg.Variable)); + msg.Parent.DoCommand(ScriptSymbols.String(msg.Variable)); } break; case AnimCommandType.PlaySound: diff --git a/Source.GUI.Controls/BuildGroup.cs b/Source.GUI.Controls/BuildGroup.cs index fe14748d6..52cfae9dc 100644 --- a/Source.GUI.Controls/BuildGroup.cs +++ b/Source.GUI.Controls/BuildGroup.cs @@ -262,7 +262,7 @@ public void SetEnabled(bool state) { if (state) ActivateBuildDialog(); else { - BuildDialog?.OnCommand("Close"); + BuildDialog?.DoCommand("Close"); ParentPanel!.RequestFocus(); } } diff --git a/Source.GUI.Controls/BuildModeDialog.cs b/Source.GUI.Controls/BuildModeDialog.cs index cc90b351a..4afdf81f0 100644 --- a/Source.GUI.Controls/BuildModeDialog.cs +++ b/Source.GUI.Controls/BuildModeDialog.cs @@ -553,11 +553,6 @@ public void UpdateEditControl(PanelItem panelItem, ReadOnlySpan datString) } } - public override void OnCommand(ReadOnlySpan command) { - - base.OnCommand(command); - } - public void OnDeletePanel() { } @@ -608,15 +603,15 @@ public override void OnKeyCodeTyped(ButtonCode code) { } - public override void OnTextChanged(Panel panel) { - if (panel == FileSelectionCombo) { + public override void OnTextChanged(Panel sender) { + if (sender == FileSelectionCombo) { Span newFile = stackalloc char[512]; FileSelectionCombo.GetText(newFile); // GetResourceName } - if (panel == AddNewControlCombo) { + if (sender == AddNewControlCombo) { // FIXME: Freezes program here (KV->FindKey) // Span buf = stackalloc char[40]; // AddNewControlCombo.GetText(buf); @@ -626,7 +621,7 @@ public override void OnTextChanged(Panel panel) { // } } - if (panel == EditableChildren) { + if (sender == EditableChildren) { KeyValues? kv = EditableChildren.GetActiveItemUserData(); if (kv != null) { EditablePanel? ep = (EditablePanel?)kv.GetPtr("ptr"); @@ -634,7 +629,7 @@ public override void OnTextChanged(Panel panel) { } } - if (panel == EditableParents) { + if (sender == EditableParents) { KeyValues? kv = EditableParents.GetActiveItemUserData(); if (kv != null) { EditablePanel? ep = (EditablePanel?)kv.GetPtr("ptr"); diff --git a/Source.GUI.Controls/Button.cs b/Source.GUI.Controls/Button.cs index d07b85094..b6c5fddaf 100644 --- a/Source.GUI.Controls/Button.cs +++ b/Source.GUI.Controls/Button.cs @@ -41,28 +41,6 @@ public class Button : Label string? DepressedSoundName; string? ReleasedSoundName; - public override void OnMessage(KeyValues message, IPanel? sender) { - switch (message.Name) { - case "PressButton": - DoClick(); - return; - case "Hotkey": - DoClick(); - return; - case "SetAsDefaultButton": - SetAsDefaultButton(message.GetBool("state", false)); - return; - case "SetAsCurrentDefaultButton": - SetAsCurrentDefaultButton(message.GetBool("state", false)); - return; - case "SetState": - OnSetState(message.GetInt("state", 0)); - return; - default: - base.OnMessage(message, sender); - return; - } - } public void Init() { ButtonFlags |= ButtonFlags.UseCaptureMouse | ButtonFlags.ButtonBorderEnabled; MouseClickMask = 0; @@ -120,6 +98,8 @@ public Button(Panel? parent, ReadOnlySpan name, ReadOnlySpan text, P } } + [UiMessage("PressButton")] + [UiMessage("Hotkey")] public virtual void DoClick() { SetSelected(true); FireActionSignal(); @@ -254,6 +234,7 @@ public override void Paint() { } } + [UiMessage("SetState")] public virtual void OnSetState(int state) { SetSelected(state != 0); Repaint(); @@ -545,6 +526,7 @@ public virtual bool CanBeDefaultButton() { return true; } + [UiMessage("SetAsDefaultButton")] public void SetAsDefaultButton(bool state) { if ((ButtonFlags & ButtonFlags.DefaultButton) != 0 != state) { ButtonFlags ^= ButtonFlags.DefaultButton; @@ -575,6 +557,7 @@ public void SetKeyFocusBorder(IBorder? border) { InvalidateLayout(false); } + [UiMessage("SetAsCurrentDefaultButton")] private void SetAsCurrentDefaultButton(bool state) { if ((ButtonFlags & ButtonFlags.DefaultButton) != 0 != state) { ButtonFlags ^= ButtonFlags.DefaultButton; diff --git a/Source.GUI.Controls/CheckButton.cs b/Source.GUI.Controls/CheckButton.cs index 81360dda6..560971271 100644 --- a/Source.GUI.Controls/CheckButton.cs +++ b/Source.GUI.Controls/CheckButton.cs @@ -140,7 +140,8 @@ public override Color GetButtonFgColor() { return base.GetButtonFgColor(); } - public virtual void OnCheckButtonChecked(Panel panel) { } + [UiMessage("CheckButtonChecked")] + public virtual void OnCheckButtonChecked(Panel sender) { } public void SetHighlightColor(Color color) { if (HighlightFgColor != color) { @@ -148,13 +149,4 @@ public void SetHighlightColor(Color color) { InvalidateLayout(false); } } - - public override void OnMessage(KeyValues message, IPanel? sender) { - if (message.Name == "CheckButtonChecked") { - OnCheckButtonChecked((Panel)sender!); - return; - } - - base.OnMessage(message, sender); - } } diff --git a/Source.GUI.Controls/CheckButtonList.cs b/Source.GUI.Controls/CheckButtonList.cs index 27df4341c..266885661 100644 --- a/Source.GUI.Controls/CheckButtonList.cs +++ b/Source.GUI.Controls/CheckButtonList.cs @@ -88,6 +88,7 @@ public override void ApplySchemeSettings(IScheme scheme) { public bool IsItemChecked(int itemID) => CheckItems[itemID].CheckButton.IsSelected(); public void SetItemCheckable(int itemID, bool state) => CheckItems[itemID].CheckButton.SetCheckButtonCheckable(state); + [UiMessage("CheckButtonChecked")] void OnCheckButtonChecked(KeyValues _params) { Panel panel = (Panel)_params.GetPtr("panel")!; for (int i = 0; i < CheckItems.Count; i++) { @@ -100,6 +101,7 @@ void OnCheckButtonChecked(KeyValues _params) { } } + [UiMessage("ScrollBarSliderMoved")] void OnScrollBarSliderMoved() { InvalidateLayout(); Repaint(); @@ -110,13 +112,4 @@ public override void OnMouseWheeled(int delta) { val -= delta * 15; ScrollBar.SetValue(val); } - - public override void OnMessage(KeyValues message, IPanel? sender) { - if (message.Name == "CheckButtonChecked") - OnCheckButtonChecked(message); - else if (message.Name == "ScrollBarSliderMoved") - OnScrollBarSliderMoved(); - else - base.OnMessage(message, sender); - } } \ No newline at end of file diff --git a/Source.GUI.Controls/ComboBox.cs b/Source.GUI.Controls/ComboBox.cs index 8b0b8d636..1446fbbbe 100644 --- a/Source.GUI.Controls/ComboBox.cs +++ b/Source.GUI.Controls/ComboBox.cs @@ -235,13 +235,13 @@ public override void OnMouseDoublePressed(ButtonCode code) { OnMousePressed(code); } - public override void OnCommand(ReadOnlySpan command) { - if (string.Equals(new(command), "ButtonClicked", StringComparison.OrdinalIgnoreCase)) - DoClick(); - - base.OnCommand(command); + [UiCommand("ButtonClicked")] + private void OnButtonClicked() { + DoClick(); + base.OnCommand("ButtonClicked"); } + [UiMessage("SetText")] public override void OnSetText(ReadOnlySpan text) { if (!text.IsEmpty && text[0] == '#') { ulong unlocalizedTextSymbol = Localize.FindIndex(text[1..]); @@ -285,6 +285,7 @@ public override void OnKillFocus(Panel? newPanel) { SelectNoText(); } + [UiMessage("MenuClose")] public void OnMenuClose() { HideMenu(); @@ -360,6 +361,7 @@ public override void OnCursorExited() { } } + [UiMessage("MenuItemSelected")] public void OnMenuItemSelected() { Highlight = true; @@ -459,23 +461,8 @@ public override void SetUseFallbackFont(bool state, IFont Fallback) { public virtual void OnShowMenu(Menu menu) { } public virtual void OnHideMenu() { } - public override void OnMessage(KeyValues message, IPanel? sender) { - switch (message.Name) { - case "MenuItemSelected": - OnMenuItemSelected(); - break; - case "SetText": - OnSetText(message.GetString("text", "")); - break; - case "MenuClose": - OnMenuClose(); - break; - case "ActivateItem": - ActivateItem(message.GetInt("itemID", -1)); - break; - default: - base.OnMessage(message, sender); - break; - } + [UiMessage("ActivateItem")] + private void OnActivateItem(KeyValues message) { + ActivateItem(message.GetInt("itemID", -1)); } } diff --git a/Source.GUI.Controls/ConsoleDialog.cs b/Source.GUI.Controls/ConsoleDialog.cs index ae54bb84f..e85dc6829 100644 --- a/Source.GUI.Controls/ConsoleDialog.cs +++ b/Source.GUI.Controls/ConsoleDialog.cs @@ -116,8 +116,8 @@ public class ConsolePanel : EditablePanel, IConsoleDisplayFunc static readonly KeyValues KV_ClosedByHittingTilde = new("ClosedByHittingTilde"); static readonly KeyValues KV_Close = new("Close"); - public override void OnTextChanged(Panel panel) { - if (panel != Entry) + public override void OnTextChanged(Panel sender) { + if (sender != Entry) return; PartialText.CopyTo(PreviousPartialText); @@ -179,35 +179,34 @@ public override void OnTextChanged(Panel panel) { Entry.RequestFocus(); } - public override void OnCommand(ReadOnlySpan command) { - if (command.Equals("submit", StringComparison.OrdinalIgnoreCase)) { - Span incoming = stackalloc char[256]; - int len = Entry.GetText(incoming); - PostActionSignal(new KeyValues("CommandSubmitted", "command", incoming[..len])); + [UiCommand("submit")] + private void OnSubmit() { + Span incoming = stackalloc char[256]; + int len = Entry.GetText(incoming); + PostActionSignal(new KeyValues("CommandSubmitted", "command", incoming[..len])); - Print("] "); - Print(incoming[..len]); - Print("\n"); - Entry.SetText(""); + Print("] "); + Print(incoming[..len]); + Print("\n"); + Entry.SetText(""); - OnTextChanged(Entry); + OnTextChanged(Entry); - History.GotoTextEnd(); + History.GotoTextEnd(); - string incomingText = incoming[..len].ToString(); - int extraPtr = incomingText.IndexOf(' '); - string? extra = null; - if (extraPtr != -1) { - extra = incomingText[(extraPtr + 1)..]; - incomingText = incomingText[..extraPtr]; - } + string incomingText = incoming[..len].ToString(); + int extraPtr = incomingText.IndexOf(' '); + string? extra = null; + if (extraPtr != -1) { + extra = incomingText[(extraPtr + 1)..]; + incomingText = incomingText[..extraPtr]; + } - if (incomingText.Length > 0) - AddToHistory(incomingText, extra); + if (incomingText.Length > 0) + AddToHistory(incomingText, extra); - CompletionList.SetVisible(false); - } - base.OnCommand(command); + CompletionList.SetVisible(false); + base.OnCommand("submit"); } private void AddToHistory(ReadOnlySpan commandText, ReadOnlySpan extraText) { @@ -613,20 +612,11 @@ private void UpdateCompletionListPosition() { } } + [UiMessage("CloseCompletionList")] internal void OnCloseCompletionList() { CompletionList.SetVisible(false); } - public override void OnMessage(KeyValues message, IPanel? sender) { - switch (message.Name) { - case "CloseCompletionList": - OnCloseCompletionList(); - return; - } - - base.OnMessage(message, sender); - } - public bool TextEntryHasFocus() => Input.GetFocus() == Entry; public void TextEntryRequestFocus() => Entry.RequestFocus(); @@ -736,6 +726,7 @@ private struct ExtraItem private List? ExtraItems = null; + [UiCommand("OpenExtra")] private void OnOpenExtra() { Menu menu = new(this, "ConsoleExtraOptions"); menu.AddActionSignalTarget(this); @@ -786,6 +777,7 @@ private void OnOpenExtra() { menu.MoveToFront(); } + [UiMessage("ExtraCmd")] private void OnExtraCmd(KeyValues msg) { if (!msg.GetString("cvar").IsEmpty) { ReadOnlySpan cvarName = msg.GetString("cvar"); @@ -811,35 +803,10 @@ private void OnExtraCmd(KeyValues msg) { } #endif - public override void OnMessage(KeyValues message, IPanel? sender) { - switch (message.Name) { - case "CommandSubmitted": - OnCommandSubmitted(message.GetString("command")); - return; - case "Activate": - Activate(); - return; -#if GMOD_DLL - case "ExtraCmd": - OnExtraCmd(message); - break; -#endif - } - - base.OnMessage(message, sender); - } - #if GMOD_DLL - public override void OnCommand(ReadOnlySpan command) { - switch (command.ToString()) { - case "Clear": - ConsolePanel.Clear(); - return; - case "OpenExtra": - OnOpenExtra(); - return; - } - base.OnCommand(command); + [UiCommand("Clear")] + private void OnClear() { + ConsolePanel.Clear(); } public override void OnKeyCodeTyped(ButtonCode code) { @@ -856,6 +823,7 @@ public override void OnKeyCodeTyped(ButtonCode code) { } #endif + [UiMessage("CommandSubmitted")] protected virtual void OnCommandSubmitted(ReadOnlySpan command) { PostActionSignal(new KeyValues("CommandSubmitted", "command", command)); } @@ -898,6 +866,7 @@ public override void OnScreenSizeChanged(int oldWide, int oldTall) { } } + [UiMessage("Activate")] public override void Activate() { base.Activate(); ConsolePanel.Entry.RequestFocus(); diff --git a/Source.GUI.Controls/CvarToggleCheckButton.cs b/Source.GUI.Controls/CvarToggleCheckButton.cs index 7ced3febb..e04741c5d 100644 --- a/Source.GUI.Controls/CvarToggleCheckButton.cs +++ b/Source.GUI.Controls/CvarToggleCheckButton.cs @@ -40,6 +40,7 @@ public override void Paint() { base.Paint(); } + [UiMessage("ApplyChanges")] public void ApplyChanges() { if (CvarName == null || CvarName.Length == 0) return; @@ -66,6 +67,7 @@ public void Reset() { public bool HasBeenModified() => IsSelected() != StartValue; static readonly KeyValues KV_ControlModified = new("ControlModified"); + [UiMessage("CheckButtonChecked")] public void OnButtonChecked() { if (HasBeenModified()) PostActionSignal(KV_ControlModified); @@ -95,18 +97,4 @@ public override void ApplySettings(KeyValues resourceData) { SetSelected(false); } } - - public override void OnMessage(KeyValues message, IPanel? sender) { - switch (message.Name) { - case "CheckButtonChecked": - OnButtonChecked(); - break; - case "ApplyChanges": - ApplyChanges(); - break; - default: - base.OnMessage(message, sender); - break; - } - } } diff --git a/Source.GUI.Controls/EditablePanel.cs b/Source.GUI.Controls/EditablePanel.cs index 067def0a3..dd66fe387 100644 --- a/Source.GUI.Controls/EditablePanel.cs +++ b/Source.GUI.Controls/EditablePanel.cs @@ -190,11 +190,11 @@ public override void OnChildAdded(IPanel child) { return base.GetCurrentKeyFocus(); } - public override void OnRequestFocus(Panel subFocus, Panel? defaultPanel) { - if (!subFocus.IsPopup()) - defaultPanel = NavGroup.SetCurrentFocus(subFocus, defaultPanel); + public override void OnRequestFocus(Panel sender, Panel? defaultPanel) { + if (!sender.IsPopup()) + defaultPanel = NavGroup.SetCurrentFocus(sender, defaultPanel); - base.OnRequestFocus(subFocus, defaultPanel); + base.OnRequestFocus(sender, defaultPanel); } public override bool RequestFocusNext(IPanel? existingPanel = null) { @@ -350,19 +350,22 @@ public override void RequestFocus(int direction = 0) { public KeyValues GetDialogVariables() => DialogVariables ??= new KeyValues("DialogVariables"); - private void OnCurrentDefaultButtonSet(Panel defaultButton) { - NavGroup.SetCurrentDefaultButton(defaultButton, false); + [UiMessage("CurrentDefaultButtonSet")] + private void OnCurrentDefaultButtonSet(Panel sender) { + NavGroup.SetCurrentDefaultButton(sender, false); if (GetParent() != null) { KeyValues msg = new("CurrentDefaultButtonSet"); - msg.SetPtr("button", defaultButton); - VGui.PostMessage(GetParent(), msg, defaultButton); + msg.SetPtr("button", sender); + VGui.PostMessage(GetParent(), msg, sender); } } - private void OnDefaultButtonSet(Panel defaultButton) => NavGroup.SetDefaultButton(defaultButton); + [UiMessage("DefaultButtonSet")] + private void OnDefaultButtonSet(Panel sender) => NavGroup.SetDefaultButton(sender); static readonly KeyValues KV_FindDefaultButton = new("FindDefaultButton"); + [UiMessage("FindDefaultButton")] private void OnFindDefaultButton() { if (NavGroup.GetDefaultButton() != null) NavGroup.SetCurrentDefaultButton(NavGroup.GetDefaultButton()); @@ -370,22 +373,5 @@ private void OnFindDefaultButton() { PostMessage(GetParent()!, KV_FindDefaultButton); } } - - public override void OnMessage(KeyValues message, IPanel? sender) { - switch (message.Name) { - case "DefaultButtonSet": - OnDefaultButtonSet((Panel)message.GetPtr("button")!); - break; - case "CurrentDefaultButtonSet": - OnCurrentDefaultButtonSet((Panel)message.GetPtr("button")!); - break; - case "FindDefaultButton": - OnFindDefaultButton(); - break; - default: - base.OnMessage(message, sender); - break; - } - } } diff --git a/Source.GUI.Controls/Frame.cs b/Source.GUI.Controls/Frame.cs index f20f431c0..709a1f7a0 100644 --- a/Source.GUI.Controls/Frame.cs +++ b/Source.GUI.Controls/Frame.cs @@ -929,20 +929,6 @@ public void SetMenuButtonVisible(bool state) { MenuButton?.SetVisible(state); } - public override void OnCommand(ReadOnlySpan command) { - switch (command) { - case "Close": - Close(); - return; - case "CloseModal": - CloseModal(); - return; - default: - base.OnCommand(command); - break; - } - } - public Menu GetSysMenu() { if (SysMenu == null) { SysMenu = new Menu(this, null); @@ -968,10 +954,14 @@ public Menu GetSysMenu() { return SysMenu; } + [UiMessage("Close")] + [UiCommand("Close")] public virtual void Close() { OnClose(); } + [UiMessage("CloseModal")] + [UiCommand("CloseModal")] private void CloseModal() { Input.ReleaseAppModalSurface(); if (PreviousModal != null) { @@ -1195,12 +1185,16 @@ public override void OnMousePressed(ButtonCode code) { base.OnMousePressed(code); } - private void InternalSetTitle(ReadOnlySpan title) => SetTitle(title, true); - private void OnCloseFrameButtonPressed() => OnCommand("Close"); + [UiMessage("SetTitle")] + private void InternalSetTitle([MessageParam("text")] ReadOnlySpan title) => SetTitle(title, true); + [UiMessage("CloseFrameButtonPressed")] + private void OnCloseFrameButtonPressed() => DoCommand("Close"); + [UiMessage("Minimize")] private void OnMinimize() => Surface.SetMinimized(this, true); static readonly KeyValues KV_FlashWindow = new("FlashWindow"); bool NextFlashState = false; + [UiMessage("FlashWindow")] private void InternalFlashWindow() { if (FlashWindow) { NextFlashState = true; @@ -1210,33 +1204,4 @@ private void InternalFlashWindow() { PostMessage(this, KV_FlashWindow, 1.8f); } } - - public override void OnMessage(KeyValues message, IPanel? sender) { - switch (message.Name) { - case "Close": - Close(); - return; - case "CloseModal": - CloseModal(); - return; - case "SetTitle": - InternalSetTitle(message.GetString("text", "")); - return; - case "FlashWindow": - InternalFlashWindow(); - return; - case "DialogVariables": - - return; - case "CloseFrameButtonPressed": - OnCloseFrameButtonPressed(); - return; - case "Minimize": - OnMinimize(); - return; - default: - base.OnMessage(message, sender); - break; - } - } } diff --git a/Source.GUI.Controls/HTML.cs b/Source.GUI.Controls/HTML.cs index c7eaef748..c6189c843 100644 --- a/Source.GUI.Controls/HTML.cs +++ b/Source.GUI.Controls/HTML.cs @@ -387,11 +387,13 @@ void PostURL(string URL, string postData, bool force) { } } + [UiCommand("stop")] bool StopLoading() { SteamHTMLSurface.StopLoad(BrowserHandle); return true; } + [UiCommand("reload")] bool Refresh() { SteamHTMLSurface.Reload(BrowserHandle); return true; @@ -641,6 +643,7 @@ void BrowserResize() { } } + [UiMessage("ScrollBarSliderMoved")] void OnSliderMoved() { if (HBar.IsVisible()) { int scrollX = HBar.GetValue(); @@ -686,36 +689,47 @@ public override void OnKillFocus(Panel? panel) { SteamHTMLSurface.SetKeyFocus(BrowserHandle, false); } - public override void OnCommand(ReadOnlySpan command) { - if (stricmp(command, "back") == 0) - PostActionSignal(new KeyValues("HTMLBackRequested")); - else if (stricmp(command, "forward") == 0) - PostActionSignal(new KeyValues("HTMLForwardRequested")); - else if (stricmp(command, "reload") == 0) - Refresh(); - else if (stricmp(command, "stop") == 0) - StopLoading(); - else if (stricmp(command, "viewsource") == 0) - SteamHTMLSurface.ViewSource(BrowserHandle); - else if (stricmp(command, "copy") == 0) - SteamHTMLSurface.CopyToClipboard(BrowserHandle); - else if (stricmp(command, "paste") == 0) - SteamHTMLSurface.PasteFromClipboard(BrowserHandle); - else if (stricmp(command, "copyurl") == 0) { - // system.SetClipboardText(CurrentURL); - } - else if (stricmp(command, "copylink") == 0) { - ContextMenu.GetPos(out int x, out int y); - GetAbsPos(out int htmlx, out int htmly); + [UiCommand("back")] + private void OnBack() { + PostActionSignal(new KeyValues("HTMLBackRequested")); + } - RequestingCopyLink = true; - GetLinkAtPosition(x - htmlx, y - htmly); - } - else - base.OnCommand(command); + [UiCommand("forward")] + private void OnForward() { + PostActionSignal(new KeyValues("HTMLForwardRequested")); } - void OnFileSelected(ReadOnlySpan selectedFile) { + [UiCommand("viewsource")] + private void OnViewSource() { + SteamHTMLSurface.ViewSource(BrowserHandle); + } + + [UiCommand("copy")] + private void OnCopy() { + SteamHTMLSurface.CopyToClipboard(BrowserHandle); + } + + [UiCommand("paste")] + private void OnPaste() { + SteamHTMLSurface.PasteFromClipboard(BrowserHandle); + } + + [UiCommand("copyurl")] + private void OnCopyURL() { + // system.SetClipboardText(CurrentURL); + } + + [UiCommand("copylink")] + private void OnCopyLink() { + ContextMenu.GetPos(out int x, out int y); + GetAbsPos(out int htmlx, out int htmly); + + RequestingCopyLink = true; + GetLinkAtPosition(x - htmlx, y - htmly); + } + + [UiMessage("FileSelected")] + void OnFileSelected([MessageParam("fullpath")] ReadOnlySpan selectedFile) { byte[] bytes = new byte[Encoding.UTF8.GetByteCount(selectedFile) + 1]; Encoding.UTF8.GetBytes(selectedFile, bytes); nint file = Marshal.AllocHGlobal(bytes.Length); @@ -730,6 +744,7 @@ void OnFileSelected(ReadOnlySpan selectedFile) { FileOpenDialog.Close(); } + [UiMessage("FileSelectionCancelled")] void OnFileSelectionCancelled() { SteamHTMLSurface.FileLoadDialogResponse(BrowserHandle, 0); FileOpenDialog.Close(); @@ -754,9 +769,10 @@ void StopFind() { InFind = false; } - void OnEditNewLine(Panel panel) => OnTextChanged(panel); + [UiMessage("TextNewLine")] + void OnEditNewLine(Panel sender) => OnTextChanged(sender); - public override void OnTextChanged(Panel panel) { + public override void OnTextChanged(Panel sender) { Span txt = stackalloc char[2000]; FindBar.GetText(txt); Find(txt.SliceNullTerminatedString().ToString()); @@ -961,6 +977,7 @@ void BrowserJSConfirm(HTML_JSConfirm_t cmd) { dlg.DoModal(); } + [UiMessage("DismissJSDialog")] void DismissJSDialog(int result) => SteamHTMLSurface.JSDialogResponse(BrowserHandle, result != 0); void BrowserCanGoBackandForward(HTML_CanGoBackAndForward_t cmd) { @@ -975,32 +992,6 @@ void UpdateSizeAndScrollBars() { InvalidateLayout(); } - public override void OnMessage(KeyValues message, IPanel? sender) { - switch (message.Name) { - case "ScrollBarSliderMoved": - OnSliderMoved(); - break; - case "FileSelected": - OnFileSelected(message.GetString("fullpath")); - break; - case "FileSelectionCancelled": - OnFileSelectionCancelled(); - break; - case "TextChanged": - OnTextChanged((Panel)sender!); - break; - case "TextNewLine": - OnEditNewLine((Panel)sender!); - break; - case "DismissJSDialog": - DismissJSDialog(message.GetInt("result", 0)); - break; - default: - base.OnMessage(message, sender); - break; - } - } - #if DEBUG [ConCommand("sdn_createhtml")] static void CreateHTML(in TokenizedCommand args) { diff --git a/Source.GUI.Controls/Menu.cs b/Source.GUI.Controls/Menu.cs index c6fa2d671..d1afb5ba7 100644 --- a/Source.GUI.Controls/Menu.cs +++ b/Source.GUI.Controls/Menu.cs @@ -928,7 +928,8 @@ public override void SetFgColor(in Color color) { menuItem.GetMenu()!.SetFgColor(color); } - public void OnMenuItemSelected(Panel panel) { + [UiMessage("MenuItemSelected")] + public void OnMenuItemSelected(Panel sender) { SetVisible(false); Scroller!.SetVisible(false); @@ -937,14 +938,14 @@ public void OnMenuItemSelected(Panel panel) { Menu parentMenu = item.GetParentMenu()!; if (parentMenu != null) { KeyValues kv = new("MenuItemSelected"); - kv.SetPtr("panel", panel); - VGui.PostMessage(parentMenu, kv, panel); + kv.SetPtr("panel", sender); + VGui.PostMessage(parentMenu, kv, sender); } } // bool activeItemSet = false; foreach (MenuItem menuItem in MenuItems) { - if (menuItem == panel) { + if (menuItem == sender) { // activeItemSet = true; ActivatedItem = MenuItems.FindIndex(x => x == menuItem); break; @@ -960,8 +961,8 @@ public void OnMenuItemSelected(Panel panel) { if (GetParent() != null) { KeyValues kv = new("MenuItemSelected"); - kv.SetPtr("panel", panel); - VGui.PostMessage(GetParent(), kv, panel); + kv.SetPtr("panel", sender); + VGui.PostMessage(GetParent(), kv, sender); } } @@ -1162,6 +1163,7 @@ private void RemoveScrollBar() { SizedForScrollBar = false; } + [UiMessage("ScrollBarSliderMoved")] public void OnSliderMoved() { CloseOtherMenus(null); @@ -1199,21 +1201,23 @@ public int GetCurrentlyHighlightedItem() { return CurrentlySelectedItemID; } - private void OnCursorEnteredMenuItem(MenuItem panel) { + [UiMessage("CursorEnteredMenuItem")] + private void OnCursorEnteredMenuItem(MenuItem sender) { if (InputMode == MenuMode.MOUSE) { - panel.ArmItem(); - SetCurrentlySelectedItem(MenuItems.FindIndex(x => x == panel)); + sender.ArmItem(); + SetCurrentlySelectedItem(MenuItems.FindIndex(x => x == sender)); - if (panel.HasMenu()) { - panel.OpenCasecadeMenu(); + if (sender.HasMenu()) { + sender.OpenCasecadeMenu(); ActivateItem(CurrentlySelectedItemID); } } } - private void OnCursorExitedMenuItem(MenuItem panel) { + [UiMessage("CursorExitedMenuItem")] + private void OnCursorExitedMenuItem(MenuItem sender) { if (InputMode == MenuMode.MOUSE) - panel.DisarmItem(); + sender.DisarmItem(); } private void MoveAlongMenuItemList(int direction, int loopCount) { @@ -1274,6 +1278,7 @@ public MenuMode GetMenuMode() { return InputMode; } + [UiMessage("KeyModeSet")] public void OnKeyModeSet() { InputMode = MenuMode.KEYBOARD; } @@ -1391,28 +1396,6 @@ public override void OnCommand(ReadOnlySpan command) { PostActionSignal(new KeyValues("Command", "command", command)); base.OnCommand(command); } - - public override void OnMessage(KeyValues message, IPanel? sender) { - switch (message.Name) { - case "MenuItemSelected": - OnMenuItemSelected((Panel)message.GetPtr("panel")!); - break; - case "ScrollBarSliderMoved": - OnSliderMoved(); - break; - case "CursorEnteredMenuItem": - OnCursorEnteredMenuItem((MenuItem)message.GetPtr("Panel")!); - break; - case "CursorExitedMenuItem": - OnCursorExitedMenuItem((MenuItem)message.GetPtr("Panel")!); - break; - case "KeyModeSet": - OnKeyModeSet(); - break; - } - - base.OnMessage(message, sender); - } } class MenuManager diff --git a/Source.GUI.Controls/MenuButton.cs b/Source.GUI.Controls/MenuButton.cs index 480e9336c..eeafee1de 100644 --- a/Source.GUI.Controls/MenuButton.cs +++ b/Source.GUI.Controls/MenuButton.cs @@ -63,6 +63,7 @@ public override void OnKillFocus(Panel? newPanel) { } static readonly KeyValues KV_MenuClose = new("MenuClose"); + [UiMessage("MenuClose")] public void OnMenuClose() { HideMenu(); PostActionSignal(KV_MenuClose); @@ -212,13 +213,4 @@ public Menu GetMenu() { Assert(Menu != null); return Menu; } - - public override void OnMessage(KeyValues message, IPanel? sender) { - if (message.Name == "MenuClose") { - OnMenuClose(); - return; - } - - base.OnMessage(message, sender); - } } diff --git a/Source.GUI.Controls/MenuItem.cs b/Source.GUI.Controls/MenuItem.cs index 3a9817d6e..a60d4305a 100644 --- a/Source.GUI.Controls/MenuItem.cs +++ b/Source.GUI.Controls/MenuItem.cs @@ -117,6 +117,7 @@ public override void OnCursorExited() { VGui.PostMessage(GetParent(), msg, this); } + [UiMessage("ArmItem")] public void ArmItem() { GetParentMenu()!.CloseOtherMenus(this); SetArmed(true); @@ -128,6 +129,7 @@ public void ArmItem() { Repaint(); } + [UiMessage("DisarmItem")] public void DisarmItem() { if (CascadeMenu == null) base.OnCursorExited(); @@ -244,6 +246,7 @@ public void GetCheckImageSize(out int wide, out int tall) { return null; } + [UiMessage("KeyModeSet")] public void OnKeyModeSet() { VGui.PostMessage(GetParent(), new KeyValues("KeyModeSet"), this); } @@ -335,23 +338,8 @@ public override void GetContentSize(out int wide, out int tall) { tall = Math.Max(tall, ih); } - public override void OnMessage(KeyValues message, IPanel? sender) { - switch (message.Name) { - case "MenuClose": - OnKillFocus(newPanel: null); - break; - case "ArmItem": - ArmItem(); - break; - case "DisarmItem": - DisarmItem(); - break; - case "KeyModeSet": - OnKeyModeSet(); - break; - default: - base.OnMessage(message, sender); - break; - } + [UiMessage("MenuClose")] + private void OnMenuClose() { + OnKillFocus(newPanel: null); } } diff --git a/Source.GUI.Controls/MessageBox.cs b/Source.GUI.Controls/MessageBox.cs index b5be195d6..2fbdcedff 100644 --- a/Source.GUI.Controls/MessageBox.cs +++ b/Source.GUI.Controls/MessageBox.cs @@ -68,22 +68,40 @@ public virtual void DoModal(Frame? frameOver = null) { Input.SetAppModalSurface(this); } + [UiCommand("OnOk")] + private void OnOk() { + ReleaseModalSurface(); + if (OkCommand != null) + PostActionSignal(OkCommand.MakeCopy()); + AutoClose(); + } + + [UiCommand("OnCancel")] + private void OnCancel() { + ReleaseModalSurface(); + if (CancelCommand != null) + PostActionSignal(CancelCommand.MakeCopy()); + AutoClose(); + } + + [UiCommand("Close")] + [UiCommand("CloseModal")] + private void OnCloseCommand() { + ReleaseModalSurface(); + AutoClose(); + } + public override void OnCommand(ReadOnlySpan command) { + ReleaseModalSurface(); + AutoClose(); + } + + private void ReleaseModalSurface() { if (Input.GetAppModalSurface() == this) Input.ReleaseAppModalSurface(); + } - switch (command) { - case "OnOk": - if (OkCommand != null) - PostActionSignal(OkCommand.MakeCopy()); - break; - - case "OnCancel": - if (CancelCommand != null) - PostActionSignal(CancelCommand.MakeCopy()); - break; - } - + private void AutoClose() { if (!NoAutoClose) OnShutdownRequest(); } diff --git a/Source.GUI.Controls/PanelListPanel.cs b/Source.GUI.Controls/PanelListPanel.cs index 3147a8858..dbdf87e80 100644 --- a/Source.GUI.Controls/PanelListPanel.cs +++ b/Source.GUI.Controls/PanelListPanel.cs @@ -246,6 +246,7 @@ public override void ApplySchemeSettings(IScheme scheme) { SetBgColor(GetSchemeColor("lISTpANEL.BgColor", GetBgColor(), scheme)); } + [UiMessage("ScrollBarSliderMoved")] public void OnSliderMoved(int position) { InvalidateLayout(); Repaint(); @@ -301,13 +302,4 @@ public void ScrollToItem(int itemNumber) { Vbar.SetValue(y); InvalidateLayout(); } - - public override void OnMessage(KeyValues message, IPanel? sender) { - if (message.Name.Equals("ScrollBarSliderMoved")) { - OnSliderMoved(message.GetInt("position", 0)); - return; - } - - base.OnMessage(message, sender); - } } diff --git a/Source.GUI.Controls/PropertyDialog.cs b/Source.GUI.Controls/PropertyDialog.cs index 956cd155d..d19ecc8a4 100644 --- a/Source.GUI.Controls/PropertyDialog.cs +++ b/Source.GUI.Controls/PropertyDialog.cs @@ -50,7 +50,7 @@ public void ResetAllData() { } public void ApplyChanges() { - OnCommand("Apply"); + DoCommand("Apply"); } public override void PerformLayout() { @@ -82,23 +82,24 @@ public override void PerformLayout() { Repaint(); } - public override void OnCommand(ReadOnlySpan command) { - if (command.Equals("OK", StringComparison.OrdinalIgnoreCase)) { - if (OnOK(false)) - OnCommand("Close"); - ApplyButton.SetEnabled(false); - } - else if (command.Equals("Cancel", StringComparison.OrdinalIgnoreCase)) { - OnCancel(); - Close(); - } - else if (command.Equals("Apply", StringComparison.OrdinalIgnoreCase)) { - OnOK(true); - ApplyButton.SetEnabled(false); - InvalidateLayout(); - } - else - base.OnCommand(command); + [UiCommand("OK")] + private void OnOKCommand() { + if (OnOK(false)) + DoCommand("Close"); + ApplyButton.SetEnabled(false); + } + + [UiCommand("Cancel")] + private void OnCancelCommand() { + OnCancel(); + Close(); + } + + [UiCommand("Apply")] + private void OnApplyCommand() { + OnOK(true); + ApplyButton.SetEnabled(false); + InvalidateLayout(); } public void OnCancel() { @@ -154,6 +155,7 @@ public void SetApplyButtonVisible(bool state) { InvalidateLayout(); } + [UiMessage("ApplyButtonEnable")] public void OnApplyButtonEnable() { if (ApplyButton.IsEnabled()) return; @@ -169,13 +171,4 @@ public void EnableApplyButton(bool state) { public override void RequestFocus(int direction) { PropertySheet!.RequestFocus(direction); } - - public override void OnMessage(KeyValues message, IPanel? sender) { - if (message.Name == "ApplyButtonEnable") { - OnApplyButtonEnable(); - return; - } - - base.OnMessage(message, sender); - } } diff --git a/Source.GUI.Controls/PropertyPage.cs b/Source.GUI.Controls/PropertyPage.cs index ecdece2b9..8fbebe33a 100644 --- a/Source.GUI.Controls/PropertyPage.cs +++ b/Source.GUI.Controls/PropertyPage.cs @@ -12,11 +12,16 @@ public PropertyPage(Panel? parent, ReadOnlySpan name) : base(parent, name) } + [UiMessage("ResetData")] public virtual void OnResetData() { } + [UiMessage("ApplyChanges")] public virtual void OnApplyChanges() { } + [UiMessage("PageShow")] public virtual void OnPageShow() { } + [UiMessage("PageHide")] public virtual void OnPageHide() { } - public void OnPageTabActivated(Panel pageTab) => PageTab = pageTab; + [UiMessage("PageTabActivated")] + public void OnPageTabActivated(Panel sender) => PageTab = sender; public override void OnKeyCodeTyped(ButtonCode code) { switch (code) { @@ -38,27 +43,4 @@ public override void SetVisible(bool state) { base.SetVisible(state); } - - public override void OnMessage(KeyValues message, IPanel? sender) { - switch (message.Name) { - case "ApplyChanges": - OnApplyChanges(); - break; - case "ResetData": - OnResetData(); - break; - case "PageShow": - OnPageShow(); - break; - case "PageHide": - OnPageHide(); - break; - case "PageTabActivated": - OnPageTabActivated((Panel)message.GetPtr("Panel")!); - break; - default: - base.OnMessage(message, sender); - break; - } - } } diff --git a/Source.GUI.Controls/PropertySheet.cs b/Source.GUI.Controls/PropertySheet.cs index 6cc329131..30806f677 100644 --- a/Source.GUI.Controls/PropertySheet.cs +++ b/Source.GUI.Controls/PropertySheet.cs @@ -17,7 +17,7 @@ public ContextLabel(Button parent, ReadOnlySpan panelName, ReadOnlySpan command) { - if (command.Equals("ShowContextMenu", StringComparison.OrdinalIgnoreCase)) { - KeyValues kv = new("OpenContextMenu"); - kv.SetPtr("page", Page); - kv.SetPtr("contextlabel", ContextLabel); - PostActionSignal(kv); - return; - } - - base.OnCommand(command); + [UiCommand("ShowContextMenu")] + private void OnShowContextMenu() { + KeyValues kv = new("OpenContextMenu"); + kv.SetPtr("page", Page); + kv.SetPtr("contextlabel", ContextLabel); + PostActionSignal(kv); } public override IBorder? GetBorder(bool depressed, bool armed, bool selected, bool keyfocus) { @@ -649,9 +645,10 @@ public override void PerformLayout() { } } - public void OnTabPressed(Panel panel) { + [UiMessage("TabPressed")] + public void OnTabPressed(Panel sender) { for (int i = 0; i < PageTabs.Count; i++) { - if (PageTabs[i] == panel) { + if (PageTabs[i] == sender) { ChangeActiveTab(i); return; } @@ -818,6 +815,7 @@ public void ChangeActiveTab(int index) { return null; } + [UiMessage("OpenContextMenu")] public void OnOpenContextMenu(KeyValues parameters) { KeyValues kv = parameters.MakeCopy(); PostActionSignal(kv); @@ -854,8 +852,9 @@ public override void OnKeyCodePressed(ButtonCode code) { base.OnKeyCodePressed(code); } - public void OnTextChanged(Panel panel, ReadOnlySpan text) { - if (panel == Combo) { + [UiMessage("TextChanged")] + public void OnTextChanged(Panel sender, ReadOnlySpan text) { + if (sender == Combo) { Span tabText = stackalloc char[30]; for (int i = 0; i < PageTabs.Count; i++) { tabText.Clear(); @@ -866,45 +865,21 @@ public void OnTextChanged(Panel panel, ReadOnlySpan text) { } } - public override void OnCommand(ReadOnlySpan command) { - if (command.Equals("Close", StringComparison.OrdinalIgnoreCase) && GetParent() != null) - CallParentFunction(new KeyValues("Command", "command", command)); + [UiCommand("Close")] + private void OnCloseCommand() { + if (GetParent() != null) + CallParentFunction(new KeyValues("Command", "command", "Close")); } - public override void OnMessage(KeyValues message, IPanel? sender) { - switch (message.Name) { - case "TabPressed": - OnTabPressed((Panel)sender!); - return; - case "TextChanged": - OnTextChanged((Panel)sender!, message.GetString("text", "")); - return; - case "OpenContextMenu": - OnOpenContextMenu(message); - return; - case "ApplyButtonEnable": - OnApplyButtonEnable(); - return; - case "DefaultButtonSet": - OnDefaultButtonSet((Panel)message.GetPtr("button")!); - return; - case "CurrentDefaultButtonSet": - OnCurrentDefaultButtonSet((Panel)message.GetPtr("button")!); - return; - case "FindDefaultButton": - OnFindDefaultButton(); - return; - default: - base.OnMessage(message, sender); - return; - } - } + public override void OnCommand(ReadOnlySpan command) { } + [UiMessage("ApplyButtonEnable")] public void OnApplyButtonEnable() { PostActionSignal(KV_ApplyButtonEnable); } - public void OnCurrentDefaultButtonSet(Panel defaultButton) { + [UiMessage("CurrentDefaultButtonSet")] + public void OnCurrentDefaultButtonSet(Panel sender) { if (GetParent() != null) { // KeyValues msg = new("CurrentDefaultButtonSet"); // msg.SetInt("button", VGui.PanelToHandle(defaultButton)); @@ -912,7 +887,8 @@ public void OnCurrentDefaultButtonSet(Panel defaultButton) { } } - public void OnDefaultButtonSet(Panel defaultButton) { + [UiMessage("DefaultButtonSet")] + public void OnDefaultButtonSet(Panel sender) { if (GetParent() != null) { // KeyValues msg = new("DefaultButtonSet"); // msg.SetInt("button", VGui.PanelToHandle(defaultButton)); @@ -920,6 +896,7 @@ public void OnDefaultButtonSet(Panel defaultButton) { } } + [UiMessage("FindDefaultButton")] public void OnFindDefaultButton() { if (GetParent() != null) CallParentFunction(KV_FindDefaultButton); diff --git a/Source.GUI.Controls/QueryBox.cs b/Source.GUI.Controls/QueryBox.cs index 40848bf71..235f189d5 100644 --- a/Source.GUI.Controls/QueryBox.cs +++ b/Source.GUI.Controls/QueryBox.cs @@ -38,24 +38,23 @@ public override void PerformLayout() { CancelButton.SetPos((wide / 2) + x + 16, tall - CancelButton.GetTall() - 15); } - public override void OnCommand(ReadOnlySpan command) { - switch (command) { - case "OK": - OnCommand("Close"); - if (OkCommand != null) PostActionSignal(OkCommand.MakeCopy()); - break; - case "Cancel": - OnCommand("Close"); - if (CancelCommand != null) PostActionSignal(CancelCommand.MakeCopy()); - break; - } - - base.OnCommand(command); + [UiCommand("OK")] + private void OnOK() { + DoCommand("Close"); + if (OkCommand != null) PostActionSignal(OkCommand.MakeCopy()); + base.OnCommand("OK"); + } + + [UiCommand("Cancel")] + private void OnCancelCommand() { + DoCommand("Close"); + if (CancelCommand != null) PostActionSignal(CancelCommand.MakeCopy()); + base.OnCommand("Cancel"); } public override void OnKeyCodeTyped(ButtonCode code) { if (code == ButtonCode.KeyEscape) - OnCommand("Cancel"); + DoCommand("Cancel"); else base.OnKeyCodeTyped(code); } diff --git a/Source.GUI.Controls/RadioButton.cs b/Source.GUI.Controls/RadioButton.cs index 2b0181413..09e08d266 100644 --- a/Source.GUI.Controls/RadioButton.cs +++ b/Source.GUI.Controls/RadioButton.cs @@ -169,7 +169,8 @@ public override void GetSettings(KeyValues resourceData) { resourceData.SetInt("TabPosition", GetRadioTabPosition()); } - public void OnRadioButtonChecked(int tabPosition) { + [UiMessage("RadioButtonChecked")] + public void OnRadioButtonChecked([MessageParam("tabposition")] int tabPosition) { if (tabPosition != OldTabPosition) return; @@ -243,13 +244,4 @@ public override void OnKeyCodeTyped(ButtonCode code) { return bestRadio; } - - public override void OnMessage(KeyValues message, IPanel? sender) { - if (message.Name == "RadioButtonChecked") { - OnRadioButtonChecked(message.GetInt("tabposition", -1)); - return; - } - - base.OnMessage(message, sender); - } } diff --git a/Source.GUI.Controls/ScrollBar.cs b/Source.GUI.Controls/ScrollBar.cs index 00f62a7e1..ee114cf44 100644 --- a/Source.GUI.Controls/ScrollBar.cs +++ b/Source.GUI.Controls/ScrollBar.cs @@ -291,22 +291,12 @@ private void Validate() { public virtual void SendSliderMoveMessage(int value) => PostActionSignal(new KeyValues("ScrollBarSliderMoved", "position", value)); - public void OnSliderMoved(int value) { + [UiMessage("ScrollBarSliderMoved")] + public void OnSliderMoved([MessageParam("position")] int value) { SendSliderMoveMessage(value); UpdateSliderImages(); } - public override void OnMessage(KeyValues message, IPanel? sender) { - switch (message.Name) { - case "ScrollBarSliderMoved": - OnSliderMoved(message.GetInt("position")); - break; - default: - base.OnMessage(message, sender); - break; - } - } - public int GetValue() => Slider!.GetValue(); public void SetValue(int val) => Slider!.SetValue(val); public void SetRange(int min, int max) => Slider!.SetRange(min, max); diff --git a/Source.GUI.Controls/ScrollableEditablePanel.cs b/Source.GUI.Controls/ScrollableEditablePanel.cs index 38847b65e..2600aaaf8 100644 --- a/Source.GUI.Controls/ScrollableEditablePanel.cs +++ b/Source.GUI.Controls/ScrollableEditablePanel.cs @@ -43,6 +43,7 @@ public override void PerformLayout() { ScrollBar.GetButton(1)!.SetFgColor(GetFgColor()); } + [UiMessage("ScrollBarSliderMoved")] void OnScrollBarSliderMoved() { InvalidateLayout(); @@ -55,13 +56,4 @@ public override void OnMouseWheeled(int delta) { val -= delta * 50; ScrollBar.SetValue(val); } - - public override void OnMessage(KeyValues message, IPanel? sender) { - if (message.Name == "ScrollBarSliderMoved") { - OnScrollBarSliderMoved(); - return; - } - - base.OnMessage(message, sender); - } } \ No newline at end of file diff --git a/Source.GUI.Controls/SectionedListPanel.cs b/Source.GUI.Controls/SectionedListPanel.cs index 451ad1fe7..08c733743 100644 --- a/Source.GUI.Controls/SectionedListPanel.cs +++ b/Source.GUI.Controls/SectionedListPanel.cs @@ -1005,6 +1005,7 @@ public int FindSectionIndexByID(int sectionID) { return -1; } + [UiMessage("ScrollBarSliderMoved")] private void OnSliderMoved() { InvalidateLayout(); Repaint(); @@ -1263,14 +1264,5 @@ public void SetColorOverrideForCell(int sectionID, int itemID, int columnID, Col ColorOverrides.Add(newOverride); } - public override void OnMessage(KeyValues message, IPanel? sender) { - if (message.Name.Equals("ScrollBarSliderMoved")) { - OnSliderMoved(); - return; - } - - base.OnMessage(message, sender); - } - internal bool IsClickable() => Clickable; } diff --git a/Source.GUI.Controls/TreeView.cs b/Source.GUI.Controls/TreeView.cs index 3e1638d18..90cc6c9ab 100644 --- a/Source.GUI.Controls/TreeView.cs +++ b/Source.GUI.Controls/TreeView.cs @@ -29,19 +29,11 @@ public TreeNodeText(Panel? parent, ReadOnlySpan name, TreeView tree) : bas SetAllowKeyBindingChainToParent(true); } - public override void OnTextChanged(Panel from) { - base.OnTextChanged(from); + public override void OnTextChanged(Panel sender) { + base.OnTextChanged(sender); GetParent()!.InvalidateLayout(); } - public override void OnMessage(KeyValues message, IPanel? sender) { - if (message.Name == "TextChanged") { - OnTextChanged((Panel)sender!); - return; - } - base.OnMessage(message, sender); - } - public override bool IsKeyRebound(ButtonCode code, KeyModifier modifiers) { if (EditingInPlace) return false; @@ -309,6 +301,7 @@ public override void OnGetAdditionalDragPanels(ref List draggables) { } } + [UiMessage("LabelChanged")] private void OnLabelChanged(KeyValues data) { ReadOnlySpan oldString = Data.GetString("original"); ReadOnlySpan newString = data.GetString("text"); @@ -946,14 +939,6 @@ public int CountVisibleIndex() { } return count; } - - public override void OnMessage(KeyValues message, IPanel? sender) { - if (message.Name == "LabelChanged") { - OnLabelChanged(message); - return; - } - base.OnMessage(message, sender); - } } public class TreeView : Panel @@ -1456,6 +1441,7 @@ public override void SetBgColor(in Color color) { SubPanel.SetBgColor(color); } + [UiMessage("SliderMoved")] private void OnSliderMoved(int position) { InvalidateLayout(); Repaint(); @@ -1690,13 +1676,4 @@ public void SelectAll() { virtual public void GenerateChildrenOfNode(int itemIndex) { } virtual public void GenerateContextMenu(int itemIndex, int x, int y) { } - - public override void OnMessage(KeyValues message, IPanel? sender) { - if (message.Name == "SliderMoved") { - OnSliderMoved(message.GetInt("position", 0)); - return; - } - - base.OnMessage(message, sender); - } } From 03495e7d111357deb5e0ec3a18e43f3c11598ee7 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Tue, 20 Oct 2026 13:24:37 +0300 Subject: [PATCH 12/14] Convert Game.UI handlers to message maps --- Game.UI/BasePanel.cs | 167 +++++++++++++++--------------- Game.UI/CvarNegateCheckButton.cs | 10 +- Game.UI/CvarSlider.cs | 16 +-- Game.UI/GameConsoleDialog.cs | 3 - Game.UI/LabeledCommandComboBox.cs | 12 +-- Game.UI/LoadingDialog.cs | 11 +- Game.UI/OptionsDialog.cs | 10 +- Game.UI/OptionsSubAudio.cs | 9 +- Game.UI/OptionsSubKeyboard.cs | 65 ++++++------ Game.UI/OptionsSubMouse.cs | 27 ++--- Game.UI/OptionsSubMultiplayer.cs | 2 +- Game.UI/OptionsSubVideo.cs | 95 +++++------------ Game.UI/OptionsSubVoice.cs | 18 ++-- Game.UI/URLButton.cs | 20 +--- 14 files changed, 175 insertions(+), 290 deletions(-) diff --git a/Game.UI/BasePanel.cs b/Game.UI/BasePanel.cs index cd13eca38..dd2756d9a 100644 --- a/Game.UI/BasePanel.cs +++ b/Game.UI/BasePanel.cs @@ -138,19 +138,16 @@ public void SetMainMenuOverride(IPanel? panel) { DeleteAllItems(); } - public override void OnCommand(ReadOnlySpan command) { - if (stricmp(command, "Open") == 0) { - if (MainMenuOverridePanel != null) { - MainMenuOverridePanel.MoveToFront(); - MainMenuOverridePanel.RequestFocus(); - } - else { - MoveToFront(); - RequestFocus(); - } + [UiCommand("Open")] + private void OnOpen() { + if (MainMenuOverridePanel != null) { + MainMenuOverridePanel.MoveToFront(); + MainMenuOverridePanel.RequestFocus(); + } + else { + MoveToFront(); + RequestFocus(); } - else - base.OnCommand(command); } public override void SetVisible(bool state) { @@ -544,35 +541,34 @@ public override void OnKeyCodeTyped(ButtonCode code) { public override void OnKeyCodePressed(ButtonCode code) { switch (code) { case ButtonCode.KeyXButtonB: Close(); break; - case ButtonCode.KeyXButtonA: OnCommand("SaveAndQuit"); break; - case ButtonCode.KeyXButtonX: OnCommand("Quit"); break; + case ButtonCode.KeyXButtonA: DoCommand("SaveAndQuit"); break; + case ButtonCode.KeyXButtonX: DoCommand("Quit"); break; default: base.OnKeyCodePressed(code); break; } } - public override void OnCommand(ReadOnlySpan command) { - if (0 == stricmp(command, "Quit")) - PostMessage(GetParent(), new KeyValues("Command", "command", "QuitNoConfirm")); - else if (0 == stricmp(command, "SaveAndQuit")) { - // find a new name to save - Span saveName= stackalloc char[128]; - // TODO: SaveGameDialog.FindSaveSlot(saveName, sizeof(saveName)); - // TODO: if (saveName[0] != '\0') { - // TODO: // save the game - // TODO: Span sz = stackalloc char[256]; - // TODO: sprintf(sz, "save %s\n").S(saveName); - // TODO: engine.ClientCmd_Unrestricted(sz.SliceNullTerminatedString()); - // TODO: } - - // quit - PostMessage(GetParent(), new KeyValues("Command", "command", "QuitNoConfirm")); - } - else if (0 == stricmp(command, "Cancel")) - Close(); - else - base.OnCommand(command); + [UiCommand("Quit")] + private void OnQuit() => PostMessage(GetParent(), new KeyValues("Command", "command", "QuitNoConfirm")); + + [UiCommand("SaveAndQuit")] + private void OnSaveAndQuit() { + // find a new name to save + Span saveName= stackalloc char[128]; + // TODO: SaveGameDialog.FindSaveSlot(saveName, sizeof(saveName)); + // TODO: if (saveName[0] != '\0') { + // TODO: // save the game + // TODO: Span sz = stackalloc char[256]; + // TODO: sprintf(sz, "save %s\n").S(saveName); + // TODO: engine.ClientCmd_Unrestricted(sz.SliceNullTerminatedString()); + // TODO: } + + // quit + PostMessage(GetParent(), new KeyValues("Command", "command", "QuitNoConfirm")); } + [UiCommand("Cancel")] + private void OnCancel() => Close(); + public override void OnClose() { base.OnClose(); Surface.RestrictPaintToSinglePanel(null); @@ -624,9 +620,6 @@ public class BasePanel : Panel public static BasePanel? g_BasePanel; - public override void OnCommand(ReadOnlySpan command) { - RunMenuCommand(command); - } [ConCommand("gamemenucommand")] static void Gamemenucommand(in TokenizedCommand args) { @@ -640,54 +633,58 @@ static void Gamemenucommand(in TokenizedCommand args) { public void RunMenuCommand(ReadOnlySpan command) { DevMsg($"Incoming BasePanel message '{command}'\n"); - switch (command) { - case "OpenGameMenu": PostMessage(GameMenu, new("Command", "command", "open")); break; - case "OpenPlayerListDialog": break; - case "OpenNewGameDialog": break; - case "OpenLoadGameDialog": break; - case "OpenSaveGameDialog": break; - case "OpenBonusMapsDialog": break; - case "OpenOptionsDialog": OnOpenOptionsDialog(); break; - case "OpenControllerDialog": break; - case "OpenBenchmarkDialog": break; - case "OpenServerBrowser": OnOpenServerBrowser(); break; - case "OpenFriendsDialog": break; - case "OpenLoadDemoDialog": break; - case "OpenCreateMultiplayerGameDialog": break; - case "OpenChangeGameDialog": break; - case "OpenLoadCommentaryDialog": break; - case "OpenLoadSingleplayerCommentaryDialog": break; - case "OpenMatchmakingBasePanel": break; - case "OpenAchievementsDialog": break; - case "OpenCSAchievementsDialog": break; - case "AchievementsDialogClosing": break; - case "Quit": - OnOpenQuitConfirmationDialog(); - break; - case "QuitNoConfirm": - SetVisible(false); - Surface.RestrictPaintToSinglePanel(this); - engine.ClientCmd_Unrestricted("quit\n"); - break; - case "QuitRestartNoConfirm": break; - case "ResumeGame": gameUI.HideGameUI(); break; - case "Disconnect": engine.ClientCmd_Unrestricted("disconnect"); break; - case "DisconnectNoConfirm": break; - case "ReleaseModalWindow": Surface.RestrictPaintToSinglePanel(null); break; - case "ShowSigninUI": break; - case "ShowDeviceSelector": break; - case "SignInDenied": break; - case "RequiredSignInDenied": break; - case "RequiredStorageDenied": break; - case "StorageDeviceDenied": break; - case "clear_storage_deviceID": break; - case "RestartWithNewLanguage": break; - default: - base.OnCommand(command); - break; - } + DoCommand(command); + } + + [UiCommand("OpenPlayerListDialog")] + [UiCommand("OpenNewGameDialog")] + [UiCommand("OpenLoadGameDialog")] + [UiCommand("OpenSaveGameDialog")] + [UiCommand("OpenBonusMapsDialog")] + [UiCommand("OpenControllerDialog")] + [UiCommand("OpenBenchmarkDialog")] + [UiCommand("OpenFriendsDialog")] + [UiCommand("OpenLoadDemoDialog")] + [UiCommand("OpenCreateMultiplayerGameDialog")] + [UiCommand("OpenChangeGameDialog")] + [UiCommand("OpenLoadCommentaryDialog")] + [UiCommand("OpenLoadSingleplayerCommentaryDialog")] + [UiCommand("OpenMatchmakingBasePanel")] + [UiCommand("OpenAchievementsDialog")] + [UiCommand("OpenCSAchievementsDialog")] + [UiCommand("AchievementsDialogClosing")] + [UiCommand("QuitRestartNoConfirm")] + [UiCommand("DisconnectNoConfirm")] + [UiCommand("ShowSigninUI")] + [UiCommand("ShowDeviceSelector")] + [UiCommand("SignInDenied")] + [UiCommand("RequiredSignInDenied")] + [UiCommand("RequiredStorageDenied")] + [UiCommand("StorageDeviceDenied")] + [UiCommand("clear_storage_deviceID")] + [UiCommand("RestartWithNewLanguage")] + private void OnUnimplementedCommand() { } + + [UiCommand("OpenGameMenu")] + private void OnOpenGameMenu() => PostMessage(GameMenu, new("Command", "command", "open")); + + [UiCommand("QuitNoConfirm")] + private void OnQuitNoConfirm() { + SetVisible(false); + Surface.RestrictPaintToSinglePanel(this); + engine.ClientCmd_Unrestricted("quit\n"); } + [UiCommand("ResumeGame")] + private void OnResumeGame() => gameUI.HideGameUI(); + + [UiCommand("Disconnect")] + private void OnDisconnect() => engine.ClientCmd_Unrestricted("disconnect"); + + [UiCommand("ReleaseModalWindow")] + private void OnReleaseModalWindow() => Surface.RestrictPaintToSinglePanel(null); + + [UiCommand("OpenOptionsDialog")] private void OnOpenOptionsDialog() { if (!OptionsDialog.IsValid()) { OptionsDialog = new OptionsDialog(this); @@ -701,6 +698,7 @@ private void OnOpenOptionsDialog() { // FIXME: This is meant to be done through some ModuleLoader system, but that doesn't exist yet, // so for now I'm cheating static ServerBrowser.ServerBrowser? ServerBrowser; + [UiCommand("OpenServerBrowser")] private void OnOpenServerBrowser() { ServerBrowser ??= new(); if (ServerBrowser.Initialize()) @@ -717,6 +715,7 @@ public void PositionDialog(Panel? dialog) { dialog.SetPos(x + ((ww - wide) / 2), y + ((wt - tall) / 2)); } + [UiCommand("Quit")] public void OnOpenQuitConfirmationDialog() { if (gameUI.IsConsoleUI()) { throw new NotImplementedException(); diff --git a/Game.UI/CvarNegateCheckButton.cs b/Game.UI/CvarNegateCheckButton.cs index 9032e85cf..0830487c7 100644 --- a/Game.UI/CvarNegateCheckButton.cs +++ b/Game.UI/CvarNegateCheckButton.cs @@ -87,17 +87,9 @@ public void ApplyChanges() { } static readonly KeyValues KV_ControlModified = new("ControlModified"); + [UiMessage("CheckButtonChecked")] public void OnButtonChecked() { if (HasBeenModified()) PostActionSignal(KV_ControlModified); } - - public override void OnMessage(KeyValues message, IPanel? sender) { - if (message.Name.Equals("CheckButtonChecked", StringComparison.OrdinalIgnoreCase)) { - OnButtonChecked(); - return; - } - - base.OnMessage(message, sender); - } } diff --git a/Game.UI/CvarSlider.cs b/Game.UI/CvarSlider.cs index 6de1e8bf8..b3d8f90ee 100644 --- a/Game.UI/CvarSlider.cs +++ b/Game.UI/CvarSlider.cs @@ -208,6 +208,7 @@ public bool HasBeenModified() { } readonly static KeyValues KV_ControlModified = new("ControlModified"); + [UiMessage("SliderMoved")] public void OnSliderMoved() { if (HasBeenModified()) { if (LastSliderValue != GetValue()) { @@ -219,22 +220,9 @@ public void OnSliderMoved() { } } + [UiMessage("SliderDragEnd")] public void OnSliderDragEnd() { if (!CreatedInCode) ApplyChanges(); } - - public override void OnMessage(KeyValues message, IPanel? sender) { - switch (message.Name) { - case "SliderMoved": - OnSliderMoved(); - break; - case "SliderDragEnd": - OnSliderDragEnd(); - break; - default: - base.OnMessage(message, sender); - break; - } - } } diff --git a/Game.UI/GameConsoleDialog.cs b/Game.UI/GameConsoleDialog.cs index d7151bbaf..294d1ced2 100644 --- a/Game.UI/GameConsoleDialog.cs +++ b/Game.UI/GameConsoleDialog.cs @@ -20,7 +20,4 @@ public override void OnKeyCodeTyped(ButtonCode code) { readonly public IEngineClient engine = Singleton(); protected override void OnCommandSubmitted(ReadOnlySpan command) => engine.ClientCmd_Unrestricted(command); - public override void OnCommand(ReadOnlySpan command) { - base.OnCommand(command); - } } diff --git a/Game.UI/LabeledCommandComboBox.cs b/Game.UI/LabeledCommandComboBox.cs index 9ccbd9ed1..473617291 100644 --- a/Game.UI/LabeledCommandComboBox.cs +++ b/Game.UI/LabeledCommandComboBox.cs @@ -72,6 +72,7 @@ public void SetInitialItem(int index) { } readonly static KeyValues KV_ControlModified = new("ControlModified"); + [UiMessage("TextChanged")] public void OnTextChanged(ReadOnlySpan text) { text = text.SliceNullTerminatedString(); for (int i = 0; i < items.Count; i++) { @@ -109,15 +110,4 @@ public void Reset() { if (StartSelection != -1) ActivateItem(StartSelection); } - - public override void OnMessage(KeyValues message, IPanel? sender) { - switch (message.Name) { - case "TextChanged": - OnTextChanged(message.GetString("text", "")); - return; - default: - base.OnMessage(message, sender); - return; - } - } } \ No newline at end of file diff --git a/Game.UI/LoadingDialog.cs b/Game.UI/LoadingDialog.cs index 597d73c44..11a091228 100644 --- a/Game.UI/LoadingDialog.cs +++ b/Game.UI/LoadingDialog.cs @@ -70,13 +70,10 @@ public override void OnClose() { HideOtherDialogs(false); base.OnClose(); } - public override void OnCommand(ReadOnlySpan command) { - if (command.Equals("Cancel", StringComparison.OrdinalIgnoreCase)) { - engine.ClientCmd_Unrestricted("disconnect\n"); - Close(); - } - else - base.OnCommand(command); + [UiCommand("Cancel")] + private void OnCancel() { + engine.ClientCmd_Unrestricted("disconnect\n"); + Close(); } public LoadingDialog(Panel? parent) : base(parent, "LoadingDialog") { diff --git a/Game.UI/OptionsDialog.cs b/Game.UI/OptionsDialog.cs index fed59941d..e91c75da2 100644 --- a/Game.UI/OptionsDialog.cs +++ b/Game.UI/OptionsDialog.cs @@ -79,6 +79,7 @@ public void Run() { } static readonly KeyValues KV_GameUIHidden = new("GameUIHidden"); + [UiMessage("GameUIHidden")] public void OnGameUIHidden() { for (int i = 0; i < GetChildCount(); i++) { Panel child = GetChild(i); @@ -86,13 +87,4 @@ public void OnGameUIHidden() { PostMessage(child, KV_GameUIHidden); } } - - public override void OnMessage(KeyValues message, IPanel? sender) { - if (message.Name == "GameUIHidden") { - OnGameUIHidden(); - return; - } - - base.OnMessage(message, sender); - } } diff --git a/Game.UI/OptionsSubAudio.cs b/Game.UI/OptionsSubAudio.cs index 0df1d7359..24caefc50 100644 --- a/Game.UI/OptionsSubAudio.cs +++ b/Game.UI/OptionsSubAudio.cs @@ -95,15 +95,10 @@ public override void OnResetData() { static readonly KeyValues KV_ApplyButtonEnable = new("ApplyButtonEnable"); - public void OnControlModified(Panel panel) { + [UiMessage("ControlModified")] + public void OnControlModified(Panel sender) { PostActionSignal(KV_ApplyButtonEnable); } - public override void OnMessage(KeyValues message, IPanel? sender) { - if (message.Name.Equals("ControlModified")) - OnControlModified((Panel)sender!); - else - base.OnMessage(message, sender); - } public override void OnApplyChanges() { SFXSlider.ApplyChanges(); diff --git a/Game.UI/OptionsSubKeyboard.cs b/Game.UI/OptionsSubKeyboard.cs index 83a25a790..44109ee50 100644 --- a/Game.UI/OptionsSubKeyboard.cs +++ b/Game.UI/OptionsSubKeyboard.cs @@ -58,32 +58,41 @@ public override void OnResetData() { public override void OnKeyCodeTyped(ButtonCode code) { if (code == ButtonCode.KeyEnter) - OnCommand("ChangeKey"); + DoCommand("ChangeKey"); else base.OnKeyCodeTyped(code); } - public override void OnCommand(ReadOnlySpan command) { - if (command.Equals("Defaults", StringComparison.OrdinalIgnoreCase)) { - var box = new QueryBox("#GameUI_KeyboardSettings", "#GameUI_KeyboardSettingsText"); - box.AddActionSignalTarget(this); - box.SetOKCommand(new KeyValues("Command", "command", "DefaultsOK")); - box.DoModal(); - } - else if (command.Equals("DefaultsOK", StringComparison.OrdinalIgnoreCase)) { - FillInDefaultBindings(); - KeyBindList.RequestFocus(); - } - else if (!KeyBindList.IsCapturing() && command.Equals("ChangeKey", StringComparison.OrdinalIgnoreCase)) + [UiCommand("Defaults")] + private void OnDefaults() { + var box = new QueryBox("#GameUI_KeyboardSettings", "#GameUI_KeyboardSettingsText"); + box.AddActionSignalTarget(this); + box.SetOKCommand(new KeyValues("Command", "command", "DefaultsOK")); + box.DoModal(); + } + + [UiCommand("DefaultsOK")] + private void OnDefaultsOK() { + FillInDefaultBindings(); + KeyBindList.RequestFocus(); + } + + [UiCommand("ChangeKey")] + private void OnChangeKey() { + if (!KeyBindList.IsCapturing()) KeyBindList.StartCaptureMode(CursorCode.Blank); - else if (!KeyBindList.IsCapturing() && command.Equals("ClearKey", StringComparison.OrdinalIgnoreCase)) { + else + base.OnCommand("ChangeKey"); + } + + [UiCommand("ClearKey")] + private void OnClearKey() { + if (!KeyBindList.IsCapturing()) { OnKeyCodePressed(ButtonCode.KeyDelete); KeyBindList.RequestFocus(); } - else if (command.Equals("Advanced", StringComparison.OrdinalIgnoreCase)) - OpenKeyboardAdvancedDialog(); else - base.OnCommand(command); + base.OnCommand("ClearKey"); } readonly IEngineClient engine = Singleton(); @@ -270,6 +279,7 @@ public void FillInDefaultBindings() { // todo } + [UiMessage("ItemSelected")] public void ItemSelected(int itemID) { KeyBindList.SetItemOfInterest(itemID); @@ -327,19 +337,11 @@ public override void OnKeyCodePressed(ButtonCode code) { } + [UiCommand("Advanced")] public void OpenKeyboardAdvancedDialog() { OptionsSubKeyboardAdvancedDlg ??= new(GetParent()); OptionsSubKeyboardAdvancedDlg.Activate(); } - - public override void OnMessage(KeyValues message, IPanel? sender) { - if (message.Name == "ItemSelected") { - ItemSelected(message.GetInt("itemID", -1)); - return; - } - - base.OnMessage(message, sender); - } } class OptionsSubKeyboardAdvancedDlg : Frame @@ -374,13 +376,10 @@ public void OnApplyData() { hud_fastswitch.SetValue(GetControlInt("FastSwitchCheck", 0)); } - public override void OnCommand(ReadOnlySpan command) { - if (command.Equals("OK", StringComparison.OrdinalIgnoreCase)) { - OnApplyData(); - Close(); - } - else - base.OnCommand(command); + [UiCommand("OK")] + private void OnOK() { + OnApplyData(); + Close(); } public override void OnKeyCodeTyped(ButtonCode code) { diff --git a/Game.UI/OptionsSubMouse.cs b/Game.UI/OptionsSubMouse.cs index cc73d68d3..37575591c 100644 --- a/Game.UI/OptionsSubMouse.cs +++ b/Game.UI/OptionsSubMouse.cs @@ -90,23 +90,25 @@ public override void OnApplyChanges() { } static readonly KeyValues KV_ApplyButtonEnable = new("ApplyButtonEnable"); - public void OnControlModified(Panel panel) { + [UiMessage("ControlModified")] + [UiMessage("CheckButtonChecked")] + public void OnControlModified(Panel sender) { PostActionSignal(KV_ApplyButtonEnable); - if (panel == MouseSensitivitySlider && MouseSensitivitySlider.HasBeenModified()) + if (sender == MouseSensitivitySlider && MouseSensitivitySlider.HasBeenModified()) UpdateSensitivityLabel(); - else if (panel == MouseAccelExponentSlider && MouseAccelExponentSlider.HasBeenModified()) + else if (sender == MouseAccelExponentSlider && MouseAccelExponentSlider.HasBeenModified()) UpdateAccelerationLabel(); - else if (panel == JoystickCheckBox) + else if (sender == JoystickCheckBox) UpdateJoystickPanels(); - else if (panel == MouseAccelerationCheckBox) { + else if (sender == MouseAccelerationCheckBox) { MouseAccelExponentSlider.SetEnabled(MouseAccelerationCheckBox.IsSelected()); MouseAccelExponentLabel.SetEnabled(MouseAccelerationCheckBox.IsSelected()); } } - public override void OnTextChanged(Panel from) { - if (from == MouseSensitivityLabel) { + public override void OnTextChanged(Panel sender) { + if (sender == MouseSensitivityLabel) { Span buf = stackalloc char[64]; MouseSensitivityLabel.GetText(buf); @@ -117,7 +119,7 @@ public override void OnTextChanged(Panel from) { return; } - if (from == MouseAccelExponentLabel) { + if (sender == MouseAccelExponentLabel) { Span buf = stackalloc char[64]; MouseAccelExponentLabel.GetText(buf); @@ -152,13 +154,4 @@ private void UpdateJoystickPanels() { JoyYawSensitivityPreLabel.SetEnabled(joystickEnabled); JoyPitchSensitivityPreLabel.SetEnabled(joystickEnabled); } - - public override void OnMessage(KeyValues message, IPanel? sender) { - if (message.Name.Equals("ControlModified")) - OnControlModified((Panel)sender!); - else if (message.Name.Equals("CheckButtonChecked")) - OnControlModified((Panel)sender!); - else - base.OnMessage(message, sender); - } } diff --git a/Game.UI/OptionsSubMultiplayer.cs b/Game.UI/OptionsSubMultiplayer.cs index 510a3fe04..a804b4410 100644 --- a/Game.UI/OptionsSubMultiplayer.cs +++ b/Game.UI/OptionsSubMultiplayer.cs @@ -159,7 +159,7 @@ void RemapLogo() { LogoImage.SetImage(fullLogoName); } - public override void OnTextChanged(Panel panel) => RemapLogo(); + public override void OnTextChanged(Panel sender) => RemapLogo(); void OnControlModified() { } diff --git a/Game.UI/OptionsSubVideo.cs b/Game.UI/OptionsSubVideo.cs index 69b4b63e9..bcb5b2467 100644 --- a/Game.UI/OptionsSubVideo.cs +++ b/Game.UI/OptionsSubVideo.cs @@ -233,8 +233,9 @@ int FindMSAAMode(int samples, int quality) { return 0; } - public override void OnTextChanged(Panel from) { - if (from == DXLevel && RequiresRestart()) { + [UiMessage("TextChanged")] + public override void OnTextChanged(Panel sender) { + if (sender == DXLevel && RequiresRestart()) { QueryBox box = new("#GameUI_SettingRequiresDisconnect_Title", "#GameUI_SettingRequiresDisconnect_Info"); box.AddActionSignalTarget(this); box.SetCancelCommand(new KeyValues("ResetDXLevelCombo")); @@ -242,8 +243,10 @@ public override void OnTextChanged(Panel from) { } } + [UiMessage("GameUIHidden")] private void OnGameUIHidden() => Close(); + [UiMessage("ResetDXLevelCombo")] private void ResetDXLevelCombo() { if (HDR.IsEnabled()) { ConVarRef mat_hdr_level = new("mat_hdr_level"); @@ -252,6 +255,7 @@ private void ResetDXLevelCombo() { } } + [UiMessage("OK_Confirmed")] private void OK_Confirmed() { UseChanges = true; Close(); @@ -505,23 +509,20 @@ public void OnResetData() { MotionBlur.ActivateItem(mat_motion_blur_enabled.GetInt()); } - public override void OnCommand(ReadOnlySpan command) { - if (stricmp(command, "OK") == 0) { - if (RequiresRestart()) { - QueryBox box = new("#GameUI_SettingRequiresDisconnect_Title", "#GameUI_SettingRequiresDisconnect_Info"); - box.AddActionSignalTarget(this); - box.SetOKCommand(new KeyValues("OK_Confirmed")); - box.SetCancelCommand(new KeyValues("ResetDXLevelCombo")); - box.DoModal(); - box.MoveToFront(); - return; - } - - UseChanges = true; - Close(); + [UiCommand("OK")] + private void OnOK() { + if (RequiresRestart()) { + QueryBox box = new("#GameUI_SettingRequiresDisconnect_Title", "#GameUI_SettingRequiresDisconnect_Info"); + box.AddActionSignalTarget(this); + box.SetOKCommand(new KeyValues("OK_Confirmed")); + box.SetCancelCommand(new KeyValues("ResetDXLevelCombo")); + box.DoModal(); + box.MoveToFront(); + return; } - else - base.OnCommand(command); + + UseChanges = true; + Close(); } public override void OnKeyCodeTyped(ButtonCode code) { @@ -549,26 +550,6 @@ public bool RequiresRestart() { return false; } - - public override void OnMessage(KeyValues message, IPanel? sender) { - switch (message.Name) { - case "TextChanged": - OnTextChanged((Panel)sender!); - break; - case "GameUIHidden": - OnGameUIHidden(); - break; - case "ResetDXLevelCombo": - ResetDXLevelCombo(); - break; - case "OK_Confirmed": - OK_Confirmed(); - break; - default: - base.OnMessage(message, sender); - break; - } - } } public class OptionsSubVideo : PropertyPage @@ -858,8 +839,8 @@ public override void PerformLayout() { } } - public override void OnTextChanged(Panel from) { - if (from == Mode) { + public override void OnTextChanged(Panel sender) { + if (sender == Mode) { MaterialSystem_Config config = Materials.GetCurrentConfigForVideoCard(); SelectedMode = Mode.GetActiveItem(); @@ -869,14 +850,15 @@ public override void OnTextChanged(Panel from) { if (w != config.VideoMode.Width || h != config.VideoMode.Height) OnDataChanged(); } - else if (from == AspectRatio) + else if (sender == AspectRatio) PrepareResolutionList(); - else if (from == Windowed) { + else if (sender == Windowed) { PrepareResolutionList(); OnDataChanged(); } } + [UiMessage("ControlModified")] private void OnDataChanged() => PostActionSignal(new KeyValues("ApplyButtonEnabled"));//static private bool RequiresRestart() { @@ -886,16 +868,19 @@ private bool RequiresRestart() { return RequireRestart; } + [UiMessage("OpenAdvanced")] private void OpenAdvanced() { OptionsSubVideoAdvancedDlg ??= new(BasePanel.g_BasePanel!.FindChildByName("OptionsDialog")); OptionsSubVideoAdvancedDlg.Activate(); } + [UiMessage("OpenGammaDialog")] private void OpenGammaDialog() { GammaDialog ??= new(this, "GammaDialog"); GammaDialog.Activate(); } + [UiMessage("LaunchBenchmark")] private void LaunchBenchmark() { // BasePanel.g_BasePanel?.OnOpenBenchmarkDialog(); // todo } @@ -931,32 +916,6 @@ FileStream FOpenGameHDFile(FileMode mode) { throw new NotImplementedException(); } - - public override void OnMessage(KeyValues message, IPanel? sender) { - switch (message.Name) { - case "ControlModified": - OnDataChanged(); - break; - case "TextChanged": - OnTextChanged((Panel)sender!); - break; - case "OpenAdvanced": - OpenAdvanced(); - break; - case "LaunchBenchmark": - LaunchBenchmark(); - break; - case "OpenGammaDialog": - OpenGammaDialog(); - break; - // case "OpenThirdPartyVideoCreditsDialog": - // OpenThirdPartyVideoCreditsDialog(); - // break; - default: - base.OnMessage(message, sender); - break; - } - } } class OptionsSubVideoThirdPartyCreditsDlg : Frame diff --git a/Game.UI/OptionsSubVoice.cs b/Game.UI/OptionsSubVoice.cs index 82040e766..eff3cf75b 100644 --- a/Game.UI/OptionsSubVoice.cs +++ b/Game.UI/OptionsSubVoice.cs @@ -196,19 +196,17 @@ private void EndTestMicrophone() { MicMeter2.SetVisible(false); } - public override void OnCommand(ReadOnlySpan command) { - if (command.Equals("TestMicrophone", StringComparison.Ordinal)) { - if (!VoiceOn) - StartTestMicrophone(); - else - EndTestMicrophone(); - } - else if (command.Equals("SteamVoiceSettings", StringComparison.Ordinal)) - Steamworks.SteamFriends.ActivateGameOverlay("VoiceSettings"); + [UiCommand("TestMicrophone")] + private void OnTestMicrophone() { + if (!VoiceOn) + StartTestMicrophone(); else - base.OnCommand(command); + EndTestMicrophone(); } + [UiCommand("SteamVoiceSettings")] + private void OnSteamVoiceSettings() => Steamworks.SteamFriends.ActivateGameOverlay("VoiceSettings"); + public override void OnPageHide() { if (VoiceOn) EndTestMicrophone(); diff --git a/Game.UI/URLButton.cs b/Game.UI/URLButton.cs index c25ef1c72..f46f4f26a 100644 --- a/Game.UI/URLButton.cs +++ b/Game.UI/URLButton.cs @@ -24,23 +24,6 @@ public URLButton(Panel parent, ReadOnlySpan name, ReadOnlySpan text, } } - public override void OnMessage(KeyValues message, IPanel? sender) { - switch (message.Name) { - case "PressButton": - DoClick(); - return; - case "Hotkey": - DoClick(); - return; - case "SetState": - OnSetState(message.GetInt("state", 0)); - return; - default: - base.OnMessage(message, sender); - return; - } - } - public void Init() { ButtonFlags |= ButtonFlags.UseCaptureMouse | ButtonFlags.ButtonBorderEnabled; MouseClickMask = 0; @@ -117,6 +100,8 @@ public void SetArmed(bool state) { public bool IsArmed() => (ButtonFlags & ButtonFlags.Armed) != 0; + [UiMessage("PressButton")] + [UiMessage("Hotkey")] public virtual void DoClick() { SetSelected(true); FireActionSignal(); @@ -228,6 +213,7 @@ public override void ApplySettings(KeyValues resourceData) { } } + [UiMessage("SetState")] public virtual void OnSetState(int state) { SetSelected(state != 0); Repaint(); From 55a8f36d6c2a86814d7e245c78a8a8f0c21c5e5e Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Tue, 20 Oct 2026 13:47:05 +0300 Subject: [PATCH 13/14] Convert server browser and HUD handlers to message maps --- Game.Client/HUD/BaseHudChat.cs | 10 +-- Game.ServerBrowser/BaseGamesPage.cs | 100 +++++++-------------- Game.ServerBrowser/DialogServerPassword.cs | 31 +++---- Game.ServerBrowser/ServerBrowserDialog.cs | 28 ++---- 4 files changed, 49 insertions(+), 120 deletions(-) diff --git a/Game.Client/HUD/BaseHudChat.cs b/Game.Client/HUD/BaseHudChat.cs index d4c1b67f5..4983b3720 100644 --- a/Game.Client/HUD/BaseHudChat.cs +++ b/Game.Client/HUD/BaseHudChat.cs @@ -791,6 +791,7 @@ internal void StartMessageMode(MessageModeType messageModeType) { engine.ClientCmd_Unrestricted("gameui_preventescapetoshow\n"); } + [UiMessage("ChatEntrySend")] public void Send() { Span text = stackalloc char[128]; ChatInput.GetMessageText(text); @@ -806,14 +807,7 @@ public void Send() { engine.ClientCmd_Unrestricted(buf[..writePtr]); } - public override void OnMessage(KeyValues message, IPanel? sender) { - switch (message.Name) { - case "ChatEntryStopMessageMode": StopMessageMode(); break; - case "ChatEntrySend": Send(); break; - default: base.OnMessage(message, sender); break; - } - } - + [UiMessage("ChatEntryStopMessageMode")] public void StopMessageMode() { engine.ClientCmd_Unrestricted("gameui_allowescapetoshow\n"); diff --git a/Game.ServerBrowser/BaseGamesPage.cs b/Game.ServerBrowser/BaseGamesPage.cs index 7d178795e..8acc6cc9b 100644 --- a/Game.ServerBrowser/BaseGamesPage.cs +++ b/Game.ServerBrowser/BaseGamesPage.cs @@ -722,11 +722,12 @@ void SetFiltersVisible(bool visible) { OnButtonToggled(Filter, visible ? 1 : 0); } - void OnButtonToggled(Panel panel, int state) { + [UiMessage("ButtonToggled")] + void OnButtonToggled(Panel sender, int state) { UpdateFilterAndQuickListVisibility(); - if (panel == NoFullServersFilterCheck || panel == NoEmptyServersFilterCheck || panel == NoPasswordFilterCheck || panel == ReplayFilterCheck) - OnTextChanged(panel, ""); + if (sender == NoFullServersFilterCheck || sender == NoEmptyServersFilterCheck || sender == NoPasswordFilterCheck || sender == ReplayFilterCheck) + OnTextChanged(sender, ""); } void UpdateDerivedLayouts() { @@ -750,9 +751,10 @@ void UpdateDerivedLayouts() { HideReplayFilter(); } - void OnTextChanged(Panel panel, ReadOnlySpan text) { + [UiMessage("TextChanged")] + void OnTextChanged(Panel sender, ReadOnlySpan text) { if (stricmp(text, ComboAllText) == 0) { - if (panel is ComboBox combo) { + if (sender is ComboBox combo) { combo.SetText(""); text = ""; } @@ -761,7 +763,7 @@ void OnTextChanged(Panel panel, ReadOnlySpan text) { UpdateFilterSettings(); ApplyGameFilters(); - if (FiltersVisible && (panel == GameFilter || panel == LocationFilter) && ServerBrowserDialog.Instance!.IsVisible()) { + if (FiltersVisible && (sender == GameFilter || sender == LocationFilter) && ServerBrowserDialog.Instance!.IsVisible()) { StopRefresh(); GetNewServerList(); } @@ -883,29 +885,15 @@ public virtual void SetRefreshing(bool state) { } } - public override void OnCommand(ReadOnlySpan command) { - switch (command) { - case "Connect": - OnBeginConnect(); - break; - case "stoprefresh": - StopRefresh(); - break; - case "refresh": - SteamMatchmakingServers.RefreshQuery(Request); - SetRefreshing(true); - ServerRefreshCount = 0; - ClearQuickList(); - break; - case "GetNewList": - GetNewServerList(); - break; - default: - base.OnCommand(command); - break; - } + [UiCommand("refresh")] + private void OnRefresh() { + SteamMatchmakingServers.RefreshQuery(Request); + SetRefreshing(true); + ServerRefreshCount = 0; + ClearQuickList(); } + [UiMessage("ItemSelected")] void OnItemSelected() { if (GetSelectedServerID() == -1) Connect.SetEnabled(false); @@ -923,8 +911,10 @@ public override void OnKeyCodePressed(ButtonCode code) { public bool OnGameListEnterPressed() => false; int GetSelectedItemsCount() => GameList.GetSelectedItemsCount(); + [UiMessage("AddToFavorites")] public virtual void OnAddToFavorites() { } + [UiMessage("AddToBlacklist")] public virtual void OnAddToBlacklist() { } public virtual void ServerFailedToRespond(HServerListRequest req, int server) => ServerResponded(req, server); @@ -936,6 +926,7 @@ public void RemoveServer(ServerDisplay server) { UpdateStatus(); } + [UiMessage("RefreshServer")] void OnRefreshServer(int serverID) { for (int i = 0; i < GameList.GetSelectedItemsCount(); i++) { int serverId = GameList.GetItemUserData(GameList.GetSelectedItem(i)); @@ -1001,8 +992,10 @@ void ClearServerList() { ClearQuickList(); } + [UiCommand("GetNewList")] public virtual void GetNewServerList() => StartRefresh(); + [UiCommand("stoprefresh")] public virtual void StopRefresh() { ServerRefreshCount = 0; @@ -1054,6 +1047,8 @@ public int GetSelectedServerID(ref KeyValues? kv) { return serverId; } + [UiCommand("Connect")] + [UiMessage("ConnectToServer")] public void OnBeginConnect() { KeyValues? kv = null; int serverID = GetSelectedServerID(ref kv); @@ -1092,6 +1087,7 @@ public void OnBeginConnect() { ServerBrowserDialog.Instance!.JoinGame(this, (uint)serverID); } + [UiMessage("ViewGameInfo")] void OnViewGameInfo() { int serverID = GetSelectedServerID(); if (serverID == -1) @@ -1135,42 +1131,8 @@ public ReadOnlySpan GetConnectCode() { void OnFavoritesMsg(FavoritesListChanged_t favListChanged) { } public virtual bool SupportsItem(IGameList.InterfaceItem item) => false; + [UiMessage("OpenContextMenu")] public virtual void OnOpenContextMenu(int itemID) { } - - public override void OnMessage(KeyValues message, IPanel? sender) { - switch (message.Name) { - case "OpenContextMenu": - OnOpenContextMenu(message.GetInt("itemID")); - return; - case "AddToFavorites": - OnAddToFavorites(); - return; - case "AddToBlacklist": - OnAddToBlacklist(); - return; - case "ItemSelected": - OnItemSelected(); - return; - case "ConnectToServer": - OnBeginConnect(); - return; - case "ViewGameInfo": - OnViewGameInfo(); - return; - case "RefreshServer": - OnRefreshServer(message.GetInt("serverID")); - return; - case "TextChanged": - OnTextChanged((Panel)sender!, message.GetString("text")); - break; - case "ButtonToggled": - OnButtonToggled((Panel)sender!, message.GetInt("state")); - break; - default: - base.OnMessage(message, sender); - break; - } - } } class DialogServerWarning : Frame @@ -1195,16 +1157,14 @@ public override void ApplySchemeSettings(IScheme Scheme) { } readonly static KeyValues KV_Close = new("Close"); - public override void OnCommand(ReadOnlySpan command) { - if (command.Equals("OK", StringComparison.Ordinal)) { - PostMessage(this, KV_Close); - ServerBrowserDialog.Instance!.JoinGame(GameList, (uint)ServerID); - } - - base.OnCommand(command); + [UiCommand("OK")] + private void OnOK() { + PostMessage(this, KV_Close); + ServerBrowserDialog.Instance!.JoinGame(GameList, (uint)ServerID); + base.OnCommand("OK"); } - public void OnButtonToggled(Panel panel, int state) { + public void OnButtonToggled(Panel sender, int state) { ConVarRef sb_dontshow_maxplayer_warning = new("sb_dontshow_maxplayer_warning"); if (sb_dontshow_maxplayer_warning.IsValid()) sb_dontshow_maxplayer_warning.SetValue(state); diff --git a/Game.ServerBrowser/DialogServerPassword.cs b/Game.ServerBrowser/DialogServerPassword.cs index 2bbdf1a84..1accc4547 100644 --- a/Game.ServerBrowser/DialogServerPassword.cs +++ b/Game.ServerBrowser/DialogServerPassword.cs @@ -40,24 +40,17 @@ public void Activate(ReadOnlySpan serverName, uint serverID) { } readonly static KeyValues KV_Close = new("Close"); - public override void OnCommand(ReadOnlySpan command) { - bool close = false; - - if (stricmp(command, "Connect") == 0) { - KeyValues msg = new("JoinServerWithPassword"); - Span buffer = stackalloc char[64]; - PasswordEntry.GetText(buffer); - msg.SetString("password", buffer); - msg.SetInt("serverID", ServerID); - PostActionSignal(msg); - close = true; - } - else if (stricmp(command, "Close") == 0) - close = true; - else - base.OnCommand(command); - - if (close) - PostMessage(this, KV_Close); + [UiCommand("Connect")] + private void OnConnect() { + KeyValues msg = new("JoinServerWithPassword"); + Span buffer = stackalloc char[64]; + PasswordEntry.GetText(buffer); + msg.SetString("password", buffer); + msg.SetInt("serverID", ServerID); + PostActionSignal(msg); + PostMessage(this, KV_Close); } + + [UiCommand("Close")] + private void OnCloseCommand() => PostMessage(this, KV_Close); } \ No newline at end of file diff --git a/Game.ServerBrowser/ServerBrowserDialog.cs b/Game.ServerBrowser/ServerBrowserDialog.cs index aefd43c17..662392dc7 100644 --- a/Game.ServerBrowser/ServerBrowserDialog.cs +++ b/Game.ServerBrowser/ServerBrowserDialog.cs @@ -153,6 +153,7 @@ void BlacklistsChanged() { } void UpdateStatusText(Span code) { } + [UiMessage("PageChanged")] void OnGameListChanged() { } public ServerBrowserDialog? GetInstance() => Instance; @@ -202,6 +203,7 @@ ReadOnlySpan GetActiveGameName() { public CGameID GetActiveAppID() => LimitAppID; + [UiMessage("ActivateGameName")] void OnActiveGameName(KeyValues kv) { ModDir = kv.GetString("name", "").ToString(); GameName = kv.GetString("game", "").ToString(); @@ -218,10 +220,13 @@ void ReloadFilterSettings() { History.LoadFilterSettings(); } + [UiMessage("ConnectedToGame")] void OnConnectToGame(KeyValues messageValues) { } + [UiMessage("DisconnectedFromGame")] void OnDisconnectFromGame() { } + [UiMessage("LoadingStarted")] void OnLoadingStarted() { } public override void ActivateBuildMode() { } @@ -231,27 +236,4 @@ bool GetDefaultScreenPosition(out int x, out int y, out int wide, out int tall) } public override void OnKeyCodePressed(ButtonCode code) { } - - public override void OnMessage(KeyValues message, IPanel? sender) { - switch (message.Name) { - case "PageChanged": - OnGameListChanged(); - break; - case "ActivateGameName": - OnActiveGameName(message); - break; - case "ConnectedToGame": - OnConnectToGame(message); - break; - case "DisconnectedFromGame": - OnDisconnectFromGame(); - break; - case "LoadingStarted": - OnLoadingStarted(); - break; - default: - base.OnMessage(message, sender); - break; - } - } } From 80444f8d238bea6e0f9c5782031afab32b5469b2 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=CE=B6eh=20Matt?= <5415177+ZehMatt@users.noreply.github.com> Date: Tue, 20 Oct 2026 14:03:52 +0300 Subject: [PATCH 14/14] Convert engine and asset panel handlers to message maps --- Game.Assets/Assets.cs | 22 ++------ Source.Engine/CL_TextureListPanel.cs | 71 ++++++++++---------------- Source.Engine/PerfUIPanel.cs | 16 +++--- Source.Engine/VGui_DebugSystemPanel.cs | 15 ++---- Source.Engine/VGui_DrawTreePanel.cs | 24 ++------- 5 files changed, 50 insertions(+), 98 deletions(-) diff --git a/Game.Assets/Assets.cs b/Game.Assets/Assets.cs index 7c768eaf9..4db9a793f 100644 --- a/Game.Assets/Assets.cs +++ b/Game.Assets/Assets.cs @@ -355,23 +355,7 @@ private void UpdateButtons() { UnlinkSelectedButton.SetEnabled(canUnlinkSelected); } - public override void OnCommand(ReadOnlySpan command) { - if (command.SequenceEqual("LinkAll")) - LinkAllAssets(); - else if (command.SequenceEqual("UnlinkAll")) - UnlinkAllAssets(); - else if (command.SequenceEqual("LinkSelected")) - LinkSelectedAsset(); - else if (command.SequenceEqual("UnlinkSelected")) - UnlinkSelectedAsset(); - else if (command.SequenceEqual("Refresh")) - RefreshList(); - else if (command.SequenceEqual("Close")) - Close(); - else - base.OnCommand(command); - } - + [UiCommand("LinkSelected")] private void LinkSelectedAsset() { if (ListPanel.GetSelectedItemsCount() == 0) return; @@ -400,6 +384,7 @@ private void LinkSelectedAsset() { RefreshList(); } + [UiCommand("UnlinkSelected")] private void UnlinkSelectedAsset() { if (ListPanel.GetSelectedItemsCount() == 0) return; @@ -425,6 +410,7 @@ private void UnlinkSelectedAsset() { RefreshList(); } + [UiCommand("Refresh")] private void RefreshList() { string? selectedPath = null; if (ListPanel.GetSelectedItemsCount() > 0) { @@ -457,6 +443,7 @@ private void RefreshList() { UpdateButtons(); } + [UiCommand("LinkAll")] private void LinkAllAssets() { string? gmodPath = AssetUtils.FindGarrysModPath(); if (gmodPath == null) @@ -466,6 +453,7 @@ private void LinkAllAssets() { RefreshList(); } + [UiCommand("UnlinkAll")] private void UnlinkAllAssets() { foreach (var asset in AssetsStringList) { if (!AssetUtils.IsAssetLinked(asset.LocalPath, ProjectRoot)) diff --git a/Source.Engine/CL_TextureListPanel.cs b/Source.Engine/CL_TextureListPanel.cs index e9d3348c6..bfd208c5c 100644 --- a/Source.Engine/CL_TextureListPanel.cs +++ b/Source.Engine/CL_TextureListPanel.cs @@ -1421,56 +1421,41 @@ public void UpdateTotalUsageLabel() { TotalUsageLabel.SetText(data); } - public override void OnTextChanged(Panel from) => OnCommand("FilteringTxt"); - public override void OnCommand(ReadOnlySpan command) { - if (command.Equals("Close", StringComparison.OrdinalIgnoreCase)) { - base.OnCommand(command); - return; - } + public override void OnTextChanged(Panel sender) => DoCommand("FilteringTxt"); + [UiCommand("Collapse")] + [UiCommand("ViewThumbnails")] + private void OnInvalidateLayoutCommand() => InvalidateLayout(); - if (command.Equals("Collapse", StringComparison.OrdinalIgnoreCase)) { - InvalidateLayout(); - return; - } + [UiCommand("ShowAlpha")] + private void OnShowAlpha() => ViewPanel.SetPaintAlpha(Alpha.IsSelected()); - if (command.Equals("ShowAlpha", StringComparison.OrdinalIgnoreCase)) { - ViewPanel.SetPaintAlpha(Alpha.IsSelected()); - return; - } - - if (command.Equals("ThumbWarnings", StringComparison.OrdinalIgnoreCase)) { - WarnEnable = ThumbWarnings.IsSelected(); - return; - } - - if (command.Equals("ViewThumbnails", StringComparison.OrdinalIgnoreCase)) { - InvalidateLayout(); - return; - } + [UiCommand("ThumbWarnings")] + private void OnThumbWarnings() => WarnEnable = ThumbWarnings.IsSelected(); - if (command.Equals("CopyToClipboard", StringComparison.OrdinalIgnoreCase)) { - // CopyListPanelToClipboard(ListPanel); - return; - } + [UiCommand("CopyToClipboard")] + private void OnCopyToClipboard() { + // CopyListPanelToClipboard(ListPanel); + } - if (command.Equals("ReloadAllMaterials", StringComparison.OrdinalIgnoreCase)) { - cbuf.AddText("mat_reloadallmaterials"); - cbuf.Execute(); - return; - } + [UiCommand("ReloadAllMaterials")] + private void OnReloadAllMaterials() { + cbuf.AddText("mat_reloadallmaterials"); + cbuf.Execute(); + } - if (command.Equals("CommitChanges", StringComparison.OrdinalIgnoreCase)) { - cbuf.AddText("mat_texture_list_txlod_sync save"); - cbuf.Execute(); - return; - } + [UiCommand("CommitChanges")] + private void OnCommitChanges() { + cbuf.AddText("mat_texture_list_txlod_sync save"); + cbuf.Execute(); + } - if (command.Equals("DiscardChanges", StringComparison.OrdinalIgnoreCase)) { - cbuf.AddText("mat_texture_list_txlod_sync reset"); - cbuf.Execute(); - return; - } + [UiCommand("DiscardChanges")] + private void OnDiscardChanges() { + cbuf.AddText("mat_texture_list_txlod_sync reset"); + cbuf.Execute(); + } + public override void OnCommand(ReadOnlySpan command) { mat_texture_list_on_f(); InvalidateLayout(); } diff --git a/Source.Engine/PerfUIPanel.cs b/Source.Engine/PerfUIPanel.cs index 01baa9817..1aa95347a 100644 --- a/Source.Engine/PerfUIPanel.cs +++ b/Source.Engine/PerfUIPanel.cs @@ -54,13 +54,13 @@ public PropFadeUIPanel(Panel parent) : base(parent, "PropFadeUIPanel") { LoadControlSettings("Resource/PerfPropFadeUIPanel.res"); } - public override void OnTextChanged(Panel from) { - if (from == Visualization) { + public override void OnTextChanged(Panel sender) { + if (sender == Visualization) { OnVisualizationSelected(); return; } - if (from == MinScreenArea || from == MaxScreenArea) { + if (sender == MinScreenArea || sender == MaxScreenArea) { Span buff = stackalloc char[256]; float? minArea, maxArea; @@ -205,13 +205,13 @@ public override void Activate() { } } - public override void OnTextChanged(Panel from) { - if (from == Visualization) { + public override void OnTextChanged(Panel sender) { + if (sender == Visualization) { OnVisualizationSelected(); return; } - if (from == MinOccluderArea || from == MaxOccluderArea) { + if (sender == MinOccluderArea || sender == MaxOccluderArea) { Span buff = stackalloc char[256]; float? minArea, maxArea; @@ -333,8 +333,8 @@ public override void OnTick() { base.OnTick(); } - public override void OnTextChanged(Panel from) { - if (from == PerformanceTool) + public override void OnTextChanged(Panel sender) { + if (sender == PerformanceTool) OnPerfToolSelected(); } diff --git a/Source.Engine/VGui_DebugSystemPanel.cs b/Source.Engine/VGui_DebugSystemPanel.cs index 0d190cbbd..a764c766a 100644 --- a/Source.Engine/VGui_DebugSystemPanel.cs +++ b/Source.Engine/VGui_DebugSystemPanel.cs @@ -244,17 +244,10 @@ public override void SetVisible(bool state) { Surface.SetCursor(GetCursor()); } - public override void OnCommand(ReadOnlySpan command) { - if (command.Equals("toggledebugpanel", StringComparison.OrdinalIgnoreCase)) { - OptionsPanel?.SetVisible(!OptionsPanel.IsVisible()); - return; - } - else if (command.Equals("quit", StringComparison.OrdinalIgnoreCase)) { - cbuf.AddText("quit\n"); - return; - } + [UiCommand("toggledebugpanel")] + private void OnToggleDebugPanel() => OptionsPanel?.SetVisible(!OptionsPanel.IsVisible()); - base.OnCommand(command); - } + [UiCommand("quit")] + private void OnQuit() => cbuf.AddText("quit\n"); } #endif diff --git a/Source.Engine/VGui_DrawTreePanel.cs b/Source.Engine/VGui_DrawTreePanel.cs index d9995b359..54a997e8c 100644 --- a/Source.Engine/VGui_DrawTreePanel.cs +++ b/Source.Engine/VGui_DrawTreePanel.cs @@ -182,6 +182,7 @@ public override void PerformLayout() { Tree.SetBounds(x, yOffset, w, t - (yOffset - y)); } + [UiMessage("TreeViewItemSelected")] public void RecalculateSelectedHighlight() { Assert(Tree != null); @@ -203,28 +204,13 @@ public void RecalculateSelectedHighlight() { DrawTreeSelectedPanel = (Panel?)data.GetPtr("PanelPtr"); } - public override void OnMessage(KeyValues message, IPanel? sender) { - if (message.Name == "TreeViewItemSelected") { - RecalculateSelectedHighlight(); - return; - } - base.OnMessage(message, sender); - } - static readonly KeyValues KV_Command_PerformLayout = new("Command", "command", "performlayout"); static readonly KeyValues KV_Command_ReloadScheme = new("Command", "command", "reloadscheme"); - public override void OnCommand(ReadOnlySpan command) { - if (strcmp(command, "performlayout") == 0) { - DrawTreeSelectedPanel?.SendMessage(KV_Command_PerformLayout, this); - return; - } - else if (strieq(command, "reloadscheme")) { - DrawTreeSelectedPanel?.SendMessage(KV_Command_ReloadScheme, this); - return; - } + [UiCommand("performlayout")] + private void OnPerformLayout() => DrawTreeSelectedPanel?.SendMessage(KV_Command_PerformLayout, this); - base.OnCommand(command); - } + [UiCommand("reloadscheme")] + private void OnReloadScheme() => DrawTreeSelectedPanel?.SendMessage(KV_Command_ReloadScheme, this); } public class VGuiDrawTree