Skip to content

Commit 70a8fa3

Browse files
committed
Finalize generic search argument handling and add tooltips
1 parent 695abd3 commit 70a8fa3

7 files changed

Lines changed: 64 additions & 22 deletions

File tree

ComponentSelectorAdditions/DefaultConfig.cs

Lines changed: 12 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,7 @@
1-
using MonkeyLoader.Configuration;
1+
using Elements.Core;
2+
using MonkeyLoader.Configuration;
23
using System;
4+
using System.Diagnostics.CodeAnalysis;
35

46
namespace ComponentSelectorAdditions
57
{
@@ -18,7 +20,7 @@ public sealed class DefaultConfig : ConfigSection
1820
new ConfigKeyRange<float>(32, 64)
1921
};
2022

21-
private static readonly DefiningConfigKey<bool> _useSeparateConcreteGenericColor = new("UseSeparateConcreteGenericColor", "Use a blend between the generic component buttons' green and the non-generic component buttons' cyan for concrete generics.", () => true);
23+
private static readonly DefiningConfigKey<colorX?> _separateConcreteGenericColor = new("separateConcreteGenericColor", "The color to use for concrete generic buttons, if defined. Defaults to a blend between the generic component buttons' green and the non-generic component buttons' cyan.", () => colorX.FromHexCode("#255447"));
2224

2325
/// <summary>
2426
/// Gets this config's instance.
@@ -44,9 +46,15 @@ public sealed class DefaultConfig : ConfigSection
4446
public float IndirectButtonHeight => _indirectButtonHeight;
4547

4648
/// <summary>
47-
/// Gets whether to use a blend between the generic component buttons' green and the non-generic component buttons' cyan for concrete generics.
49+
/// Gets the color to use for concrete generic buttons, if defined.
4850
/// </summary>
49-
public bool UseSeperateConcreteGenericColor => _useSeparateConcreteGenericColor;
51+
public colorX? SeparateConcreteGenericColor => _separateConcreteGenericColor;
52+
53+
/// <summary>
54+
/// Gets whether the <see cref="SeparateConcreteGenericColor">SeparateConcreteGenericColor</see> is defined.
55+
/// </summary>
56+
[MemberNotNullWhen(true, nameof(SeparateConcreteGenericColor))]
57+
public bool UseSeparateConcreteGenericColor => _separateConcreteGenericColor.GetValue().HasValue;
5058

5159
/// <inheritdoc/>
5260
public override Version Version { get; } = new Version(1, 0, 0);

ComponentSelectorAdditions/DefaultHandler.cs

Lines changed: 4 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
using System.Text;
1313
using System.Threading.Tasks;
1414
using System.IO;
15+
using MonkeyLoader.Resonite.UI;
1516

1617
namespace ComponentSelectorAdditions
1718
{
@@ -23,8 +24,6 @@ public sealed class DefaultHandler : ConfiguredResoniteMonkey<DefaultHandler, De
2324
ICancelableEventHandler<BuildCategoryButtonEvent>, ICancelableEventHandler<BuildGroupButtonEvent>, ICancelableEventHandler<BuildComponentButtonEvent>,
2425
IEventHandler<BuildCustomGenericBuilder>, IEventHandler<EnumerateConcreteGenericsEvent>
2526
{
26-
private static colorX _presetConcreteColor = MathX.Average(RadiantUI_Constants.Sub.GREEN, RadiantUI_Constants.Sub.CYAN);
27-
2827
/// <inheritdoc/>
2928
public int Priority => HarmonyLib.Priority.Normal;
3029

@@ -64,6 +63,7 @@ public static TextField MakeGenericArgumentInput(UIBuilder ui, Type component, T
6463
{
6564
var textField = ui.TextField(parseRTF: false);
6665
textField.Text.NullContent.AssignLocaleString(Mod.GetLocaleString("EnterType"));
66+
textField.Slot.GetComponent<Button>()?.WithTooltip(Mod.GetLocaleString("EnterType.Tooltip", "parameter", genericArgument.Name));
6767

6868
return textField;
6969
}, out var label);
@@ -199,8 +199,8 @@ void ICancelableEventHandler<BuildComponentButtonEvent>.Handle(BuildComponentBut
199199
var selector = eventData.Selector;
200200
var component = eventData.Component;
201201

202-
var tint = component.IsConcreteGeneric && ConfigSection.UseSeperateConcreteGenericColor
203-
? _presetConcreteColor
202+
var tint = component.IsConcreteGeneric && ConfigSection.UseSeparateConcreteGenericColor
203+
? ConfigSection.SeparateConcreteGenericColor.Value
204204
: component.IsGeneric ? RadiantUI_Constants.Sub.GREEN : RadiantUI_Constants.Sub.CYAN;
205205

206206
var category = GetPrettyPath(component.Category, eventData.RootCategory);

ComponentSelectorAdditions/Events/EnumerateComponentsEvent.cs

Lines changed: 26 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -12,16 +12,27 @@ public sealed class EnumerateComponentsEvent : CancelableSortedItemsEvent<Compon
1212
public Predicate<Type> ComponentFilter { get; }
1313

1414
public override IEnumerable<ComponentResult> Items
15-
=> sortableItems
16-
.Where(entry => ComponentFilter(entry.Key.Type))
17-
.Where(entry => Selector.World.Types.IsSupported(entry.Key.Type))
18-
.OrderBy(entry => entry.Value)
19-
.ThenBy(entry => entry.Key.GroupName ?? entry.Key.Type.Name)
20-
.Select(entry => entry.Key);
15+
{
16+
get
17+
{
18+
var items = sortableItems
19+
.Where(entry => ComponentFilter(entry.Key.Type))
20+
.Where(entry => Selector.World.Types.IsSupported(entry.Key.Type))
21+
.OrderBy(Value)
22+
.ThenBy(Name);
23+
24+
// Sort for (concrete) genericness when search has a generic argument
25+
if (Path.HasSearchGeneric)
26+
items = items.ThenBy(GenericnessRating);
27+
28+
return items.Select(entry => entry.Key);
29+
}
30+
}
2131

2232
public SelectorPath Path { get; }
2333

2434
public CategoryNode<Type> RootCategory { get; }
35+
2536
public ComponentSelector Selector { get; }
2637

2738
/// <inheritdoc/>
@@ -32,5 +43,14 @@ internal EnumerateComponentsEvent(ComponentSelector selector, SelectorPath path,
3243
RootCategory = rootCategory;
3344
ComponentFilter = componentFilter;
3445
}
46+
47+
private static int GenericnessRating(KeyValuePair<ComponentResult, int> entry)
48+
=> entry.Key.Type.IsGenericType ? (entry.Key.Type.IsGenericTypeDefinition ? 1 : 0) : 2;
49+
50+
private static string Name(KeyValuePair<ComponentResult, int> entry)
51+
=> entry.Key.GroupName ?? entry.Key.Type.Name;
52+
53+
private static int Value(KeyValuePair<ComponentResult, int> entry)
54+
=> entry.Value;
3555
}
3656
}

ComponentSelectorAdditions/Locale/de.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,11 @@
66
"ComponentSelectorAdditions.Description": "Dieser MonkeyLoader Mod für Resonite strukturiert Komponenten-Selektoren und ProtoFlux Nodebrowser neu und fügt eine Suchfunktion sowie Kategorien für zuletzt genutzte und favorisierte Komponenten / Nodes hinzu.",
77

88
"ComponentSelectorAdditions.Search": "<i>Suchen ...</i>",
9+
"ComponentSelectorAdditions.Search.Clear": "Leert das Suchfeld.",
10+
"ComponentSelectorAdditions.Search.Tooltip": "<b>Gebe hier deine Suchbegriffe ein. Die Ergebnisse erscheinen, wenn du das tippen pausierst.</b><size=50%><br/><br/></size>Mehrere Suchbegriffe können mit Leerzeichen getrennt werden. Für jeden Begriff wird überprüft, ob dieser im Namen einer Kategorie oder Komponente / Node enthalten ist. Je mehr Begriffe enthalten sind, desto besser wird das Ergebnis gewertet.<br/>Du kannst einen generischen Typparameter anwenden, indem du dessen volle Definition nach einem < eingibst, genauso wie du es bei der normallen Erstellung einer generischen Komponente tun würdest. Bereits das Hinzufügen eines < verbessert die Wertung aller generischen Ergebnisse.",
11+
912
"ComponentSelectorAdditions.EnterType": "<i>Typ eingeben...</i>",
13+
"ComponentSelectorAdditions.EnterType.Tooltip": "<b>Gebe hier die Typdefinition für den generischen Parameter {parameter} ein. Dieser darf uneindeutig sein.</b><size=50%><br/><br/></size>Die Typdefinition sollte so geschrieben werden wie in C#, genauso wie Komponentennamen es zeigen. Ein Integer Field wäre zum Beispiel: IField<int>",
1014

1115
"ComponentSelectorAdditions.CaseSensitivityFix.Description": "Macht das Auswählen von eigenen generischen Typparametern unabhängig von Groß- und Kleinschreibung. Kann deaktiviert werden, wenn der Bug behoben wurde.",
1216
"ComponentSelectorAdditions.CurrentPathIndicator.Description": "Fügt eine Anzeige für den Pfad der aktuellen Kategorie (und des generischen Typs) zu Komponenten-Selektoren hinzu.",

ComponentSelectorAdditions/Locale/en.json

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,11 @@
33
"authors": [ "Banane9" ],
44
"messages": {
55
"ComponentSelectorAdditions.Search": "<i>Search ...</i>",
6+
"ComponentSelectorAdditions.Search.Clear": "Clears the search field.",
7+
"ComponentSelectorAdditions.Search.Tooltip": "<b>Enter your search terms here. Results will appear when you pause typing.</b><size=50%><br/><br/></size>Multiple search terms can be split using spaces. Each term gets checked for inclusion in the name of categories or a component / node. The more terms match, the higher the result is ranked.<br/>You can apply a custom generic type by entering its full definition after a <, just like you would when normally creating a generic component. Simply adding the < will already rank up all generic results.",
8+
69
"ComponentSelectorAdditions.EnterType": "<i>Enter Type ...</i>",
10+
"ComponentSelectorAdditions.EnterType.Tooltip": "<b>Enter your type definition for the generic parameter {parameter} here. This is allowed to be ambiguous.</b><size=50%><br/><br/></size>The type definition should be written like it would be in C#, just like component names show it. For example, an integer field would be: IField<int>",
711

812
"ComponentSelectorAdditions.CaseSensitivityFix.Description": "Makes picking custom generic type parameters case-insensitive. Can be disabled when the bug gets fixed.",
913
"ComponentSelectorAdditions.CurrentPathIndicator.Description": "Adds an indicator for the current category (and generic Type) path to omponent selectors.",

ComponentSelectorAdditions/SearchBar.cs

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,8 @@
1212
using System.Threading;
1313
using System.Globalization;
1414
using MonkeyLoader;
15+
using MonkeyLoader.Resonite.UI;
16+
using FrooxEngine.UIX;
1517

1618
namespace ComponentSelectorAdditions
1719
{
@@ -42,6 +44,8 @@ public void Handle(BuildSelectorHeaderEvent eventData)
4244

4345
ui.Style.FlexibleWidth = 1;
4446
var textField = ui.TextField(null!, parseRTF: false);
47+
textField.Slot.GetComponent<Button>()?.WithTooltip(Mod.GetLocaleString("Search.Tooltip"));
48+
4549
var details = new SelectorSearchBar(searchLayout, textField.Editor.Target, () => ConfigSection.SearchRefreshDelay);
4650
eventData.SearchBar = details;
4751

@@ -51,7 +55,7 @@ public void Handle(BuildSelectorHeaderEvent eventData)
5155
ui.Style.FlexibleWidth = -1;
5256
ui.Style.ButtonTextAlignment = Alignment.MiddleCenter;
5357

54-
var clearButton = ui.Button("∅");
58+
var clearButton = ui.Button("∅").WithTooltip(Mod.GetLocaleString("Search.Clear"));
5559
var clearAction = clearButton.Slot.AttachComponent<ButtonValueSet<string>>();
5660
clearAction.TargetValue.Target = details.Text.Content;
5761

@@ -83,8 +87,8 @@ public void Handle(EnumerateComponentsEvent eventData)
8387
SearchCategories(searchCategory)
8488
.SelectMany(category => category.Elements
8589
.Select(type => (Category: category, Type: type, Matches: SearchContains(type.Name, eventData.Path.SearchFragments)))))
86-
.Where(match => match.Matches > 0) // Extra weight for generic results when there's a generic in the search:
87-
.OrderByDescending(match => match.Type.IsGenericTypeDefinition && eventData.Path.HasSearchGeneric ? match.Matches + 100 : match.Matches)
90+
.Where(match => match.Matches > 0)
91+
.OrderByDescending(match => match.Matches)
8892
.ThenBy(match => match.Type.Name)
8993
.Select(match => (Component: new ComponentResult(match.Category, match.Type), Order: -match.Matches));
9094

@@ -106,7 +110,7 @@ public void Handle(EnumerateComponentsEvent eventData)
106110
continue;
107111

108112
--remaining;
109-
eventData.AddItem(new(result.Component.Category, concreteType), result.Order - 1);
113+
eventData.AddItem(new(result.Component.Category, concreteType), result.Order);
110114
}
111115
catch (Exception ex)
112116
{

ComponentSelectorAdditions/SelectorPath.cs

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,7 @@ public sealed class SelectorPath
2323

2424
private static readonly char[] _pathSeparators = { '/', '\\' };
2525

26-
private static readonly char[] _searchSplits = new[] { ' ', ',', '+', '|' };
26+
private static readonly char[] _searchSplits = new[] { ' ', '.', ',', ';', '?', '!', '+', '|', '&', '`', '´', '"', '(', ')', '/', '\\', '\n', '\r', '\t' };
2727

2828
/// <summary>
2929
/// Gets whether this path targets a generic type.
@@ -99,17 +99,19 @@ internal SelectorPath(string? rawPath, string? search, bool genericType, string?
9999

100100
if (!string.IsNullOrWhiteSpace(search))
101101
{
102-
var genericParamStartIndex = search!.IndexOf(_genericParamStart);
102+
search = search!.Replace('[', _genericParamStart).Replace(']', _genericParamEnd);
103+
104+
var genericParamStartIndex = search.IndexOf(_genericParamStart);
103105

104106
if (genericParamStartIndex > 0)
105107
{
106-
var generic = search[(genericParamStartIndex + 1)..];
108+
var generic = search[(genericParamStartIndex + 1)..].Trim();
107109
var starts = generic.Count(static c => c == _genericParamStart);
108110
var ends = generic.Count(static c => c == _genericParamEnd);
109111

110112
if (starts > ends) // Automatically add any missing >
111113
generic += new string(_genericParamEnd, starts - ends);
112-
else if (ends > starts) // Probably not gonna happen often, but if someone adds a closing > to much...
114+
else if (ends > starts) // Probably not gonna happen often, but if someone adds too many closing > ...
113115
generic = generic.Remove(generic.Length - (ends - starts));
114116

115117
SearchGeneric = generic;

0 commit comments

Comments
 (0)