Skip to content

Commit

Permalink
refactor (SubMenuWithInputs) :
Browse files Browse the repository at this point in the history
now uses EaseInDecorator
  • Loading branch information
nhruo123 committed Apr 29, 2023
1 parent 5d295f2 commit ac7a773
Show file tree
Hide file tree
Showing 3 changed files with 139 additions and 51 deletions.
5 changes: 2 additions & 3 deletions Celeste.Mod.mm/Content/Dialog/English.txt
Original file line number Diff line number Diff line change
Expand Up @@ -260,9 +260,8 @@
MODOPTIONS_MODTOGGLE_TOGGLEDEPS= Toggle Dependencies Automatically
MODOPTIONS_MODTOGGLE_TOGGLEDEPS_MESSAGE1= When you enable a mod, all its dependencies will be enabled.
MODOPTIONS_MODTOGGLE_TOGGLEDEPS_MESSAGE2= When you disable a mod, all mods that depend on it will be disabled.
MODOPTIONS_MODTOGGLE_TOGGLEFAVORITES= Toggle Favorites
MODOPTIONS_MODTOGGLE_TOGGLEFAVORITES_MESSAGE1= Press
MODOPTIONS_MODTOGGLE_TOGGLEFAVORITES_MESSAGE2= to add or remove items from the favorite list.
MODOPTIONS_MODTOGGLE_TOGGLEFAVORITES= Disable All ignores favorites
MODOPTIONS_MODTOGGLE_TOGGLEFAVORITES_MESSAGE= Press {0} to add or remove items from the favorite list.
MODOPTIONS_MODTOGGLE_MESSAGE_1= If you enable or disable mods, your blacklist.txt will be replaced,
MODOPTIONS_MODTOGGLE_MESSAGE_2= and Celeste will restart to apply changes.
MODOPTIONS_MODTOGGLE_MESSAGE_3= Highlighted mods are used by other enabled mods as a dependency.
Expand Down
25 changes: 14 additions & 11 deletions Celeste.Mod.mm/Mod/UI/OuiModToggler.cs
Original file line number Diff line number Diff line change
Expand Up @@ -28,7 +28,7 @@ class OuiModToggler : OuiGenericMenu, OuiModOptions.ISubmenu {

private bool toggleDependencies = true;

private bool toggleFavorites = false;
private bool DisableAllIgnoresFavorites = true;

private TextMenuExt.SubHeaderExt restartMessage1;
private TextMenuExt.SubHeaderExt restartMessage2;
Expand Down Expand Up @@ -229,9 +229,7 @@ protected override void addOptionsToMenu(TextMenu menu) {
blacklistedMods.Clear();
foreach (KeyValuePair<string, TextMenu.OnOff> toggle in modToggles) {
bool isFavorite = favoritedMods.Contains(toggle.Key) || favoritesDependenciesMods.ContainsKey(toggle.Key);
if (!toggleFavorites && isFavorite) {
// TODO: I don't like the continue keywords but the logic statement we want is kinda odd so for now it will do
// toggleFavorites || (!toggleFavorites && !isFavorite)
if (DisableAllIgnoresFavorites && isFavorite) {
continue;
}

Expand All @@ -249,13 +247,18 @@ protected override void addOptionsToMenu(TextMenu menu) {
toggleDependenciesButton.AddDescription(menu, Dialog.Clean("MODOPTIONS_MODTOGGLE_TOGGLEDEPS_MESSAGE1"));

TextMenu.Item toggleFavoritesButton;
menu.Add(toggleFavoritesButton = new TextMenu.OnOff(Dialog.Clean("MODOPTIONS_MODTOGGLE_TOGGLEFAVORITES"), toggleFavorites)
.Change(value => toggleFavorites = value));
menu.Add(toggleFavoritesButton = new TextMenu.OnOff(Dialog.Clean("MODOPTIONS_MODTOGGLE_TOGGLEFAVORITES"), DisableAllIgnoresFavorites)
.Change(value => DisableAllIgnoresFavorites = value));

TextMenuExt.EaseInSubMenuWithInputs favoriteToolTip = new TextMenuExt.EaseInSubMenuWithInputs(
new object[] { Dialog.Clean("MODOPTIONS_MODTOGGLE_TOGGLEFAVORITES_MESSAGE1") + " ",
Input.MenuJournal, " " + Dialog.Clean("MODOPTIONS_MODTOGGLE_TOGGLEFAVORITES_MESSAGE2") },
Input.GuiInputController(), false, menu) { TextColor = Color.Gray };



TextMenuExt.EaseInDecorator<TextMenuExt.SubMenuWithInputs> favoriteToolTip =
new TextMenuExt.EaseInDecorator<TextMenuExt.SubMenuWithInputs>(
new TextMenuExt.SubMenuWithInputs(
string.Format(Dialog.Get("MODOPTIONS_MODTOGGLE_TOGGLEFAVORITES_MESSAGE"), "|"), '|',
new Monocle.VirtualButton[] { Input.MenuJournal }, () => Input.GuiInputController()) { TextColor = Color.Gray }
, false, menu);

menu.Add(favoriteToolTip);

Expand Down Expand Up @@ -650,7 +653,7 @@ public override IEnumerator Leave(Oui next) {
modToggles = null;
modLoadingTask = null;
toggleDependencies = true;
toggleFavorites = false;
DisableAllIgnoresFavorites = false;
favoritedMods = null;
favoritedModsOriginal = null;
favoritesDependenciesMods = null;
Expand Down
160 changes: 123 additions & 37 deletions Celeste.Mod.mm/Mod/UI/TextMenuExt.cs
Original file line number Diff line number Diff line change
Expand Up @@ -1353,43 +1353,61 @@ public void Dispose() {
}
}

public class SubMenuWithInputs : TextMenu.Item {
public class SubMenuWithInputs : TextMenu.Item, IItemExt {
public object[] Items { get; set; }
public bool ControllerMode { get; set; }
private Func<bool> ControllerModeCallback;
public Color TextColor { get; set; } = Color.Gray;
public Color ButtonColor { get; set; } = Color.White;
public Color StrokeColor { get; set; } = Color.White;
public float Alpha { get; set; } = 1f;
public float Scale { get; set; } = 0.6f;
public string Icon { get; set; }
public float? IconWidth { get; set; }
public bool IconOutline { get; set; }
public Vector2 Offset { get; set; }

public SubMenuWithInputs(object[] items, bool controllerMode) {
this.Items = items;
this.ControllerMode = controllerMode;
public override float Height() {
return ActiveFont.LineHeight;
}

public SubMenuWithInputs(string text, char separator, VirtualButton[] buttons, Func<bool> controllerModeCallback) {
this.ControllerModeCallback = controllerModeCallback;

public override float Height() {
return ActiveFont.LineHeight;
string[] parts = text.Split(separator);
Items = new object[parts.Length * 2 - 1];

for (int index = 0; index < Items.Length; index++) {
if (index % 2 == 0) {
// add text
Items[index] = parts[index / 2];
} else {
// add VirtualButton
Items[index] = buttons[index / 2];
}
}
}


public override void Render(Vector2 position, bool highlighted) {
Vector2 lineOffset = position;
Vector2 justify = new Vector2(0f, 0.5f);
float strokeAlpha = Alpha * Alpha * Alpha;

for (int i = 0; i < this.Items.Count(); i++) {
if (this.Items[i] is string) {
ActiveFont.DrawOutline(this.Items[i] as string, lineOffset, justify, Vector2.One * Scale, TextColor * Alpha, 2f, Color.Black * strokeAlpha);
lineOffset.X += ActiveFont.Measure(this.Items[i] as string).X * Scale;
} else if (this.Items[i] is VirtualButton) {
VirtualButton virtualButton = this.Items[i] as VirtualButton;

foreach (object item in Items) {
if (item is string) {
ActiveFont.DrawOutline(item as string, lineOffset, justify, Vector2.One * Scale, TextColor * Alpha, 2f, Color.Black * strokeAlpha);
lineOffset.X += ActiveFont.Measure(item as string).X * Scale;
} else if (item is VirtualButton) {
VirtualButton virtualButton = item as VirtualButton;
MTexture buttonTexture = null;

if (this.ControllerMode) {
buttonTexture = Input.GuiButton(virtualButton, Input.PrefixMode.Attached, "controls/keyboard/oemquestion");
if (this.ControllerModeCallback()) {
buttonTexture = Input.GuiButton(virtualButton, Input.PrefixMode.Attached);
} else if (virtualButton.Binding.Keyboard.Count > 0) {
buttonTexture = Input.GuiKey(virtualButton.Binding.Keyboard[0], "controls/keyboard/oemquestion");
buttonTexture = Input.GuiKey(virtualButton.Binding.Keyboard[0]);
} else {
buttonTexture = Input.GuiKey(Microsoft.Xna.Framework.Input.Keys.None, "controls/keyboard/oemquestion");
buttonTexture = Input.GuiKey(Microsoft.Xna.Framework.Input.Keys.None);
}

buttonTexture.DrawJustified(lineOffset, justify, ButtonColor * strokeAlpha, Scale);
Expand All @@ -1399,47 +1417,115 @@ public override void Render(Vector2 position, bool highlighted) {
}
}

public class EaseInSubMenuWithInputs : SubMenuWithInputs {



/// <summary>
/// Toggling this will make the header ease in/out.
/// </summary>
// this is full of boilerplate code might be replaceable with DispatchProxy once we upgrade .NET
// https://learn.microsoft.com/en-us/dotnet/api/system.reflection.dispatchproxy?view=net-7.0
public class EaseInDecorator<T> : TextMenu.Item, IItemExt where T : TextMenu.Item, IItemExt {
private T Inner;
public bool FadeVisible { get; set; } = true;

private float uneasedAlpha;
private TextMenu containingMenu;
private float UneasedAlpha;
private TextMenu ContainingMenu;

public EaseInSubMenuWithInputs(object[] items, bool controllerMode, bool initiallyVisible, TextMenu containingMenu) : base(items, controllerMode) {
this.containingMenu = containingMenu;
public EaseInDecorator(T inner, bool initiallyVisible, TextMenu containingMenu) {
this.Inner = inner;
this.ContainingMenu = containingMenu;

FadeVisible = initiallyVisible;
Alpha = FadeVisible ? 1 : 0;
uneasedAlpha = Alpha;
UneasedAlpha = Alpha;
}

public Color TextColor { get => Inner.TextColor; set => Inner.TextColor = value; }
public string Icon { get => Inner.Icon; set => Inner.Icon = value; }
public float? IconWidth { get => Inner.IconWidth; set => Inner.IconWidth = value; }
public bool IconOutline { get => Inner.IconOutline; set => Inner.IconOutline = value; }
public Vector2 Offset { get => Inner.Offset; set => Inner.Offset = value; }
public float Alpha { get => Inner.Alpha; set => Inner.Alpha = value; }
new public bool Selectable { get => Inner.Selectable; set => Inner.Selectable = value; }
new public bool Visible { get => Inner.Visible; set => Inner.Visible = value; }

new public bool Disabled { get => Inner.Disabled; set => Inner.Disabled = value; }
new public bool IncludeWidthInMeasurement { get => Inner.IncludeWidthInMeasurement; set => Inner.IncludeWidthInMeasurement = value; }
new public bool AboveAll { get => Inner.AboveAll; set => Inner.AboveAll = value; }
new public TextMenu Container { get => Inner.Container; set => Inner.Container = value; }
new public Wiggler SelectWiggler { get => Inner.SelectWiggler; set => Inner.SelectWiggler = value; }
new public Wiggler ValueWiggler { get => Inner.ValueWiggler; set => Inner.ValueWiggler = value; }
new public Action OnEnter { get => Inner.OnEnter; set => Inner.OnEnter = value; }
new public Action OnLeave { get => Inner.OnLeave; set => Inner.OnLeave = value; }
new public Action OnPressed { get => Inner.OnPressed; set => Inner.OnPressed = value; }
new public Action OnAltPressed { get => Inner.OnAltPressed; set => Inner.OnAltPressed = value; }
new public Action OnUpdate { get => Inner.OnUpdate; set => Inner.OnUpdate = value; }


new public float Width { get => Inner.Width; }

new public bool Hoverable { get => Inner.Hoverable; }


public override void Added() {
Inner.Added();
}

// the fade has to take into account the item spacing as well, or the other options will abruptly shift up when Visible is switched to false.
public override float Height() => MathHelper.Lerp(-containingMenu.ItemSpacing, base.Height(), Alpha);
public new TextMenu.Item AltPressed(Action onPressed) {
return Inner.AltPressed(onPressed);
}

public override void ConfirmPressed() {
Inner.ConfirmPressed();
}

public new TextMenu.Item Enter(Action onEnter) {
return Inner.Enter(onEnter);
}

public override float Height() {
return MathHelper.Lerp(-ContainingMenu.ItemSpacing, Inner.Height(), Inner.Alpha);
}

public new TextMenu.Item Leave(Action onLeave) {
return Inner.Leave(onLeave);
}

public override void LeftPressed() {
Inner.LeftPressed();
}

public override float LeftWidth() {
return Inner.LeftWidth();
}

public new TextMenu.Item Pressed(Action onPressed) {
return Inner.Pressed(onPressed);
}

public override void Render(Vector2 position, bool highlighted) {
Inner.Render(position, highlighted);
}

public override void RightPressed() {
Inner.RightPressed();
}

public override float RightWidth() {
return Inner.RightWidth();
}

public override void Update() {
base.Update();
Inner.Update();

// gradually make the sub-header fade in or out. (~333ms fade)
float targetAlpha = FadeVisible ? 1 : 0;
if (uneasedAlpha != targetAlpha) {
uneasedAlpha = Calc.Approach(uneasedAlpha, targetAlpha, Engine.RawDeltaTime * 3f);
if (UneasedAlpha != targetAlpha) {
UneasedAlpha = Calc.Approach(UneasedAlpha, targetAlpha, Engine.RawDeltaTime * 3f);

if (FadeVisible)
Alpha = Ease.SineOut(uneasedAlpha);
Alpha = Ease.SineOut(UneasedAlpha);
else
Alpha = Ease.SineIn(uneasedAlpha);
Alpha = Ease.SineIn(UneasedAlpha);
}

Visible = (Alpha != 0);
}
}

}
}

0 comments on commit ac7a773

Please sign in to comment.