Make autogenerated XAML UI fields access level settable (#2148)

* Make autogenerated XAML fields public instead of protected

* Make field always public, remove stray commented out code

* Remove encapsulation for previously protected XAML UI fields

* Make access level settable

* Set access to public for DebugConsole LineEdit

* Address reviews and add documentation

* Remove documentation

* Address reviews
This commit is contained in:
Visne
2021-10-24 23:20:27 +02:00
committed by GitHub
parent b8cb037151
commit d9af00c931
5 changed files with 77 additions and 20 deletions

View File

@@ -37,9 +37,10 @@ namespace Robust.Client.AutoGenerated
class NameVisitor : IXamlAstVisitor
{
private List<(string name, string type)> _names = new List<(string name, string type)>();
private readonly List<(string name, string type, string access)> _names =
new List<(string name, string type, string access)>();
public static List<(string name, string type)> GetNames(IXamlAstNode node)
public static List<(string name, string type, string access)> GetNames(IXamlAstNode node)
{
var visitor = new NameVisitor();
node.Visit(visitor);
@@ -56,27 +57,42 @@ namespace Robust.Client.AutoGenerated
{
var clrtype = objectNode.Type.GetClrType();
var isControl = IsControl(clrtype);
//clrtype.Interfaces.Any(i =>
//i.IsInterface && i.FullName == "Robust.Client.UserInterface.IControl");
if (!isControl)
return node;
// Find Name and Access properties
XamlAstTextNode nameText = null;
XamlAstTextNode accessText = null;
foreach (var child in objectNode.Children)
{
if (child is XamlAstXamlPropertyValueNode propertyValueNode &&
propertyValueNode.Property is XamlAstNamePropertyReference namedProperty &&
namedProperty.Name == "Name" &&
propertyValueNode.Values.Count > 0 &&
propertyValueNode.Values[0] is XamlAstTextNode text)
{
var reg = (text.Text, $@"{clrtype.Namespace}.{clrtype.Name}");
if (!_names.Contains(reg))
switch (namedProperty.Name)
{
_names.Add(reg);
case "Name":
nameText = text;
break;
case "Access":
accessText = text;
break;
}
}
}
if (nameText == null)
return node;
var reg = (nameText.Text,
$@"{clrtype.Namespace}.{clrtype.Name}",
accessText?.Text ?? "Protected");
if (!_names.Contains(reg))
{
_names.Add(reg);
}
}
return node;
@@ -94,7 +110,8 @@ namespace Robust.Client.AutoGenerated
private static string GenerateSourceCode(
INamedTypeSymbol classSymbol,
string xamlFile,
CSharpCompilation comp)
CSharpCompilation comp,
string fileName)
{
var className = classSymbol.Name;
var nameSpace = classSymbol.ContainingNamespace.ToDisplayString();
@@ -118,11 +135,40 @@ namespace Robust.Client.AutoGenerated
if (classSymbol.ToString() != rootTypeString && classSymbol.BaseType?.ToString() != rootTypeString)
throw new InvalidXamlRootTypeException(rootType, classSymbol, classSymbol.BaseType);
var fieldAccess = classSymbol.IsSealed ? "private" : "protected";
//var names = NameVisitor.GetNames((XamlAstObjectNode)XDocumentXamlParser.Parse(xamlFile).Root);
var namedControls = names.Select(info => " " +
$"{fieldAccess} global::{info.type} {info.name} => " +
$"this.FindControl<global::{info.type}>(\"{info.name}\");");
var namedControls = names.Select(info =>
{
(string name, string type, string access) = info;
switch (access)
{
case "Public":
access = "public";
break;
case "Protected" when classSymbol.IsSealed:
case "PrivateProtected" when classSymbol.IsSealed:
case "Private":
access = "private";
break;
case "Protected":
access = "protected";
break;
case "Internal":
case "ProtectedInternal" when classSymbol.IsSealed:
access = "internal";
break;
case "ProtectedInternal":
access = "protected internal";
break;
case "PrivateProtected":
access = "private protected";
break;
default:
throw new ArgumentException($"Invalid access level for control {name} in {fileName}: {access}.");
}
return $" {access} global::{type} {name} => this.FindControl<global::{type}>(\"{name}\");";
});
return $@"// <auto-generated />
using Robust.Client.UserInterface;
using Robust.Client.UserInterface.Controls;
@@ -207,7 +253,7 @@ namespace {nameSpace}
try
{
var sourceCode = GenerateSourceCode(typeSymbol, txt, comp);
var sourceCode = GenerateSourceCode(typeSymbol, txt, comp, xamlFileName);
context.AddSource($"{typeSymbol.Name}.g.cs", SourceText.From(sourceCode, Encoding.UTF8));
}
catch (InvalidXamlRootTypeException invRootType)

View File

@@ -40,6 +40,9 @@ namespace Robust.Client.UserInterface
[ViewVariables]
public string? Name { get; set; }
// ReSharper disable once ValueParameterNotUsed
public AccessLevel? Access { set { } }
/// <summary>
/// If true, this control will always be rendered, even if other UI rendering is disabled.
/// </summary>
@@ -995,4 +998,14 @@ namespace Robust.Client.UserInterface
public readonly int OldIndex;
public readonly int NewIndex;
}
public enum AccessLevel
{
Public,
Protected,
Internal,
ProtectedInternal,
Private,
PrivateProtected,
}
}

View File

@@ -8,6 +8,6 @@
ContentMarginBottomOverride="3" ContentMarginTopOverride="3" />
</OutputPanel.StyleBoxOverride>
</OutputPanel>
<HistoryLineEdit Name="CommandBar" PlaceHolder="{Loc 'console-line-edit-placeholder'}" />
<HistoryLineEdit Name="CommandBar" Access="Public" PlaceHolder="{Loc 'console-line-edit-placeholder'}" />
</BoxContainer>
</Control>

View File

@@ -49,8 +49,6 @@ namespace Robust.Client.UserInterface.CustomControls
private readonly ConcurrentQueue<FormattedMessage> _messageQueue = new();
public HistoryLineEdit CommandBarPub => CommandBar;
private bool commandChanged = true;
private readonly List<string> searchResults;
private int searchIndex = 0;

View File

@@ -23,7 +23,7 @@ namespace Robust.Client.UserInterface.CustomControls
LayoutContainer.SetAnchorPreset(MainControl, LayoutContainer.LayoutPreset.TopWide);
LayoutContainer.SetAnchorBottom(MainControl, 0.35f);
MainControl.CommandBarPub.OnKeyBindDown += CommandBarPubOnOnKeyBindDown;
MainControl.CommandBar.OnKeyBindDown += CommandBarPubOnOnKeyBindDown;
}
@@ -72,7 +72,7 @@ namespace Robust.Client.UserInterface.CustomControls
public void Toggle()
{
var bar = MainControl.CommandBarPub;
var bar = MainControl.CommandBar;
_targetVisible = !_targetVisible;
if (_targetVisible)
{