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