Skip to content

Commit

Permalink
Merge pull request #319 from WEGFan/update/optimize-menu
Browse files Browse the repository at this point in the history
  • Loading branch information
0x0ade authored Jun 22, 2021
2 parents 3158995 + bc34c00 commit ca07b07
Show file tree
Hide file tree
Showing 5 changed files with 175 additions and 6 deletions.
55 changes: 52 additions & 3 deletions Celeste.Mod.mm/Mod/Everest/Emoji.cs
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,8 @@
using System.Collections;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Xml;

namespace Celeste.Mod {
Expand Down Expand Up @@ -146,10 +148,57 @@ public static string Apply(string text) {
return text;
// TODO: This trashes the GC and doesn't allow escaping!
lock (_IDs) {
foreach (KeyValuePair<string, int> kvp in _IDs)
text = text.Replace(":" + kvp.Key + ":", ((char) (Start + kvp.Value)).ToString());
StringBuilder resultBuilder = new StringBuilder();
int appendStartIndex = 0;
int head = -1, tail = 0;
// suppose text is "aaaa:1111:2222:bbbb", and only ":2222:" is emoji name
// H = head, T = tail, S = appendStartIndex
while (tail < text.Length) {
if (text[tail] == ':') {
if (head >= 0 && text[head] == ':') {
/*
aaaa:1111:2222:bbbb
(2) ^S ^H ^T ^
(4) ^S ^H ^T
now head and tail are pointing to colons so we need to check if the text inside colons is an emoji name
*/
string name = text.Substring(head + 1, (tail - 1) - (head + 1) + 1);
if (_IDs.TryGetValue(name, out int value)) {
// if it is, we need to first append the text before emoji
resultBuilder.Append(text, appendStartIndex, (head - 1) - appendStartIndex + 1);
// then append the emoji itself
resultBuilder.Append((char) (Start + value));
// the emoji name has been replaced, we need to advance tail pointer once
// because the colon is used and can't belong to next emoji
tail++;
appendStartIndex = tail;
/*
aaaa:1111:2222:bbbb
(5) ^H S^T
*/
}
}
head = tail;
/*
aaaa:1111:2222:bbbb
(1) ^S H^T ^
(3) ^S H^T
when tail is pointing to a colon, we need to let head also points to it
so when tail moves to next colon, text[head..tail] can be an emoji name and we can check then replace it
*/
}
tail++;
}
/*
aaaa:1111:2222:bbbb
(6) H^S ^T
there are still text left since last append, so we need to append them
*/
if (appendStartIndex < text.Length) {
resultBuilder.Append(text, appendStartIndex, (text.Length - 1) - appendStartIndex + 1);
}
return resultBuilder.ToString();
}
return text;
}

}
Expand Down
4 changes: 4 additions & 0 deletions Celeste.Mod.mm/Mod/UI/OuiMapList.cs
Original file line number Diff line number Diff line change
Expand Up @@ -78,6 +78,8 @@ private TextMenu CreateMenu(bool inGame, EventInstance snapshot) {
}

private void ReloadItems() {
((patch_TextMenu) menu).BatchMode = true;

foreach (TextMenu.Item item in items)
menu.Remove(item);
items.Clear();
Expand Down Expand Up @@ -148,6 +150,8 @@ private void ReloadItems() {
items.Add(button);
}

((patch_TextMenu) menu).BatchMode = false;

// compute a delay so that options don't take more than a second to show up if many mods are installed.
float delayBetweenOptions = 0.03f;
if (items.Count > 0)
Expand Down
4 changes: 4 additions & 0 deletions Celeste.Mod.mm/Mod/UI/OuiMapSearch.cs
Original file line number Diff line number Diff line change
Expand Up @@ -238,6 +238,8 @@ private void ReloadItems() {
itemCount = 0;
matchCount = 0;

((patch_TextMenu) menu.rightMenu).BatchMode = true;

foreach (TextMenu.Item item in items)
menu.rightMenu.Remove(item);
items.Clear();
Expand Down Expand Up @@ -363,6 +365,8 @@ private void ReloadItems() {
resultHeader.Title = string.Format(itemCount == 1 ? Dialog.Get("maplist_results_singular") : Dialog.Get("maplist_results_plural"), itemCount);
}

((patch_TextMenu) menu.rightMenu).BatchMode = false;

// compute a delay so that options don't take more than a second to show up if many mods are installed.
float delayBetweenOptions = 0.03f;
if (items.Count > 0)
Expand Down
2 changes: 2 additions & 0 deletions Celeste.Mod.mm/Mod/UI/OuiModOptions.cs
Original file line number Diff line number Diff line change
Expand Up @@ -33,6 +33,7 @@ public OuiModOptions() {

public static TextMenu CreateMenu(bool inGame, EventInstance snapshot) {
TextMenu menu = new TextMenu();
((patch_TextMenu) menu).BatchMode = true;

menu.Add(new TextMenuExt.HeaderImage("menu/everest") {
ImageColor = Color.White,
Expand Down Expand Up @@ -130,6 +131,7 @@ public static TextMenu CreateMenu(bool inGame, EventInstance snapshot) {
menu.Position.Y = menu.ScrollTargetY;
}

((patch_TextMenu) menu).BatchMode = false;
return menu;
}

Expand Down
116 changes: 113 additions & 3 deletions Celeste.Mod.mm/Patches/TextMenu.cs
Original file line number Diff line number Diff line change
Expand Up @@ -15,11 +15,84 @@ public class patch_TextMenu : TextMenu {
// We're effectively in TextMenu, but still need to "expose" private fields to our mod.
private List<Item> items;

private bool batchMode;
private float width;
private float leftColumnWidth;
private float rightColumnWidth;
private float height;
private bool recalculatingSizeInBatchMode;

/// <summary>
/// The items contained in this menu.
/// </summary>
public List<Item> Items => items;

/// <summary>
/// When a menu is in batch mode, adding / removing items will not recalculate its size to improve performance.
/// Size is recalculated immediately after batch mode is disabled.
/// </summary>
public bool BatchMode {
get => batchMode;
set {
batchMode = value;
if (!batchMode) {
RecalculateSize();
}
}
}

/// <inheritdoc cref="TextMenu.Width"/>
public new float Width {
[MonoModReplace]
get {
if (batchMode && !recalculatingSizeInBatchMode) {
RecalculateSize();
}
return width;
}
[MonoModReplace]
private set => width = value;
}

/// <inheritdoc cref="TextMenu.Height"/>
public new float Height {
[MonoModReplace]
get {
if (batchMode && !recalculatingSizeInBatchMode) {
RecalculateSize();
}
return height;
}
[MonoModReplace]
private set => height = value;
}

/// <inheritdoc cref="TextMenu.LeftColumnWidth"/>
public new float LeftColumnWidth {
[MonoModReplace]
get {
if (batchMode && !recalculatingSizeInBatchMode) {
RecalculateSize();
}
return leftColumnWidth;
}
[MonoModReplace]
private set => leftColumnWidth = value;
}

/// <inheritdoc cref="TextMenu.RightColumnWidth"/>
public new float RightColumnWidth {
[MonoModReplace]
get {
if (batchMode && !recalculatingSizeInBatchMode) {
RecalculateSize();
}
return rightColumnWidth;
}
[MonoModReplace]
private set => rightColumnWidth = value;
}

// Basically the same as Add(), but with an index parameter.
/// <summary>
/// Insert a <see cref="TextMenu.Item"/> at position <paramref name="index"/> in the menu.
Expand All @@ -39,7 +112,9 @@ public TextMenu Insert(int index, Item item) {
if (Selection == -1)
FirstSelection();

RecalculateSize();
if (!BatchMode) {
RecalculateSize();
}
item.Added();
return this;
}
Expand All @@ -60,11 +135,13 @@ public TextMenu Remove(Item item) {
Remove(item.ValueWiggler);
Remove(item.SelectWiggler);

RecalculateSize();
if (!BatchMode) {
RecalculateSize();
}
return this;
}

/// <inheritdoc cref="TextMenu.GetYOffsetOf(Item)"/>
/// <inheritdoc cref="TextMenu.GetYOffsetOf(TextMenu.Item)"/>
[MonoModReplace]
public new float GetYOffsetOf(Item targetItem) {
// this is a small fix of the vanilla method to better support invisible menu items.
Expand Down Expand Up @@ -150,6 +227,39 @@ private bool renderItems(bool aboveAll) {
return skippedItems;
}

/// <inheritdoc cref="TextMenu.Add(TextMenu.Item)"/>
[MonoModReplace]
public new TextMenu Add(Item item)
{
items.Add(item);
item.Container = this;
Add(item.ValueWiggler = Wiggler.Create(0.25f, 3f));
Add(item.SelectWiggler = Wiggler.Create(0.25f, 3f));
item.ValueWiggler.UseRawDeltaTime = item.SelectWiggler.UseRawDeltaTime = true;
if (Selection == -1) {
FirstSelection();
}
if (!BatchMode) {
RecalculateSize();
}
item.Added();
return this;
}

#pragma warning disable CS0626 // extern method with no attribute
public extern void orig_RecalculateSize();
#pragma warning restore CS0626 // extern method with no attribute

public new void RecalculateSize() {
if (BatchMode) {
recalculatingSizeInBatchMode = true;
}
orig_RecalculateSize();
if (BatchMode) {
recalculatingSizeInBatchMode = false;
}
}

public class patch_LanguageButton : LanguageButton {
public patch_LanguageButton(string label, Language language)
: base(label, language) {
Expand Down

0 comments on commit ca07b07

Please sign in to comment.