From d5cf9bfc22f82d7a3da90183de2feec7b82544fb Mon Sep 17 00:00:00 2001
From: EliteMasterEric <ericmyllyoja@gmail.com>
Date: Sat, 28 Oct 2023 19:56:34 -0400
Subject: [PATCH 1/7] New shortcut handler

---
 hmm.json                                      | 10 ++-
 .../ui/debug/charting/ChartEditorState.hx     |  2 +
 .../handlers/ChartEditorShortcutHandler.hx    | 61 +++++++++++++++++++
 source/funkin/ui/haxeui/HaxeUIState.hx        | 15 +++++
 source/funkin/util/PlatformUtil.hx            | 23 +++++++
 5 files changed, 105 insertions(+), 6 deletions(-)
 create mode 100644 source/funkin/ui/debug/charting/handlers/ChartEditorShortcutHandler.hx
 create mode 100644 source/funkin/util/PlatformUtil.hx

diff --git a/hmm.json b/hmm.json
index 070d96cd0..22dd6e42f 100644
--- a/hmm.json
+++ b/hmm.json
@@ -49,22 +49,20 @@
       "name": "haxeui-core",
       "type": "git",
       "dir": null,
-      "ref": "e92d5cfac847943fac84696b103670d55c2c774f",
+      "ref": "815e94dd5aa6cf09c5ddcef1666a54449ffde8dc",
       "url": "https://github.com/haxeui/haxeui-core"
     },
     {
       "name": "haxeui-flixel",
       "type": "git",
       "dir": null,
-      "ref": "be0b18553189a55fd42821026618a18615b070e3",
+      "ref": "9bd0b9e0fea40b8e06a89aac4949512d95064609",
       "url": "https://github.com/haxeui/haxeui-flixel"
     },
     {
       "name": "hmm",
-      "type": "git",
-      "dir": null,
-      "ref": "d514d7786cabf18b90e60fcee38399fd44c2ddfb",
-      "url": "https://github.com/andywhite37/hmm"
+      "type": "haxelib",
+      "version": "3.1.0"
     },
     {
       "name": "hscript",
diff --git a/source/funkin/ui/debug/charting/ChartEditorState.hx b/source/funkin/ui/debug/charting/ChartEditorState.hx
index 05173726f..9b25433eb 100644
--- a/source/funkin/ui/debug/charting/ChartEditorState.hx
+++ b/source/funkin/ui/debug/charting/ChartEditorState.hx
@@ -49,6 +49,7 @@ import funkin.data.song.SongDataUtils;
 import funkin.ui.debug.charting.ChartEditorCommand;
 import funkin.ui.debug.charting.ChartEditorCommand;
 import funkin.ui.debug.charting.ChartEditorThemeHandler.ChartEditorTheme;
+import funkin.ui.debug.charting.handlers.ChartEditorShortcutHandler;
 import funkin.ui.debug.charting.ChartEditorToolboxHandler.ChartEditorToolMode;
 import funkin.ui.haxeui.components.CharacterPlayer;
 import funkin.ui.haxeui.HaxeUIState;
@@ -1268,6 +1269,7 @@ class ChartEditorState extends HaxeUIState
     buildSelectionBox();
 
     buildAdditionalUI();
+    ChartEditorShortcutHandler.applyPlatformShortcutText(this);
 
     // Setup the onClick listeners for the UI after it's been created.
     setupUIListeners();
diff --git a/source/funkin/ui/debug/charting/handlers/ChartEditorShortcutHandler.hx b/source/funkin/ui/debug/charting/handlers/ChartEditorShortcutHandler.hx
new file mode 100644
index 000000000..016a181d3
--- /dev/null
+++ b/source/funkin/ui/debug/charting/handlers/ChartEditorShortcutHandler.hx
@@ -0,0 +1,61 @@
+package funkin.ui.debug.charting.handlers;
+
+import funkin.util.PlatformUtil;
+
+@:access(funkin.ui.debug.charting.ChartEditorState)
+class ChartEditorShortcutHandler
+{
+  public static function applyPlatformShortcutText(state:ChartEditorState):Void
+  {
+    state.setComponentShortcutText('menubarItemNewChart', ctrlOrCmd('N'));
+    state.setComponentShortcutText('menubarItemOpenChart', ctrlOrCmd('O'));
+    state.setComponentShortcutText('menubarItemSaveChartAs', ctrlOrCmd(shift('S')));
+    state.setComponentShortcutText('menubarItemExit', ctrlOrCmd('Q'));
+
+    state.setComponentShortcutText('menubarItemUndo', ctrlOrCmd('Z'));
+    state.setComponentShortcutText('menubarItemRedo', ctrlOrCmd('Y'));
+    state.setComponentShortcutText('menubarItemCut', ctrlOrCmd('X'));
+    state.setComponentShortcutText('menubarItemCopy', ctrlOrCmd('C'));
+    state.setComponentShortcutText('menubarItemPaste', ctrlOrCmd('V'));
+
+    state.setComponentShortcutText('menubarItemSelectAll', ctrlOrCmd('A'));
+    state.setComponentShortcutText('menubarItemSelectInverse', ctrlOrCmd('I'));
+    state.setComponentShortcutText('menubarItemSelectNone', ctrlOrCmd('D'));
+    state.setComponentShortcutText('menubarItemSelectBeforeCursor', shift('Home'));
+    state.setComponentShortcutText('menubarItemSelectAfterCursor', shift('End'));
+
+    state.setComponentShortcutText('menubarItemDifficultyDown', ctrlOrCmd('←'));
+    state.setComponentShortcutText('menubarItemDifficultyUp', ctrlOrCmd('→'));
+
+    state.setComponentShortcutText('menubarItemPlaytestFull', 'Enter');
+    state.setComponentShortcutText('menubarItemPlaytestMinimal', shift('Enter'));
+  }
+
+  /**
+   * Display `Ctrl` on Windows and `⌘` (Command) on macOS.
+   * @param input
+   */
+  static inline function ctrlOrCmd(input:String)
+  {
+    return (PlatformUtil.isMacOS()) ? '⌘+${input}' : 'Ctrl+${input}';
+  }
+
+  /**
+   * Display `Ctrl` on Windows and `^` (Control) on macOS.
+   * @param input
+   */
+  static inline function ctrl(input:String)
+  {
+    return (PlatformUtil.isMacOS()) ? '^+${input}' : 'Ctrl+${input}';
+  }
+
+  static inline function alt(input:String)
+  {
+    return (PlatformUtil.isMacOS()) ? '⌥+${input}' : 'Alt+${input}';
+  }
+
+  static inline function shift(input:String)
+  {
+    return (PlatformUtil.isMacOS()) ? '⇧+${input}' : 'Shift+${input}';
+  }
+}
diff --git a/source/funkin/ui/haxeui/HaxeUIState.hx b/source/funkin/ui/haxeui/HaxeUIState.hx
index 6d432b68c..d9d00dd23 100644
--- a/source/funkin/ui/haxeui/HaxeUIState.hx
+++ b/source/funkin/ui/haxeui/HaxeUIState.hx
@@ -2,6 +2,7 @@ package funkin.ui.haxeui;
 
 import haxe.ui.components.CheckBox;
 import haxe.ui.containers.menus.MenuCheckBox;
+import haxe.ui.containers.menus.MenuItem;
 import haxe.ui.core.Component;
 import haxe.ui.core.Screen;
 import haxe.ui.events.MouseEvent;
@@ -122,6 +123,20 @@ class HaxeUIState extends MusicBeatState
     }
   }
 
+  function setComponentShortcutText(key:String, text:String):Void
+  {
+    var target:MenuItem = findComponent(key, MenuItem);
+    if (target == null)
+    {
+      // Gracefully handle the case where the item can't be located.
+      trace('WARN: Could not locate menu item: $key');
+    }
+    else
+    {
+      target.shortcutText = text;
+    }
+  }
+
   /**
    * Add an onChange listener to a HaxeUI input component such as a slider or text field.
    */
diff --git a/source/funkin/util/PlatformUtil.hx b/source/funkin/util/PlatformUtil.hx
new file mode 100644
index 000000000..6c8609332
--- /dev/null
+++ b/source/funkin/util/PlatformUtil.hx
@@ -0,0 +1,23 @@
+package funkin.util;
+
+class PlatformUtil
+{
+  /**
+   * Returns true if the current platform is MacOS.
+   *
+   * NOTE: Only use this for choosing modifier keys for shortcut hints.
+   * @return Whether the current platform is MacOS, or HTML5 running on MacOS.
+   */
+  public static function isMacOS():Bool
+  {
+    #if mac
+    return true;
+    #elseif html5
+    return js.html.Navigator.platform.startsWith("Mac")
+      || js.html.Navigator.platform.startsWith("iPad")
+      || js.html.Navigator.platform.startsWith("iPhone");
+    #else
+    return false;
+    #end
+  }
+}

From 8dfc59da68ae1bfbb64cbeb30c9ab92900fb1cfd Mon Sep 17 00:00:00 2001
From: Cameron Taylor <cameron.taylor.ninja@gmail.com>
Date: Sat, 4 Nov 2023 16:11:50 -0400
Subject: [PATCH 2/7] assets update idk?

---
 assets | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/assets b/assets
index be9d790af..e634c8f50 160000
--- a/assets
+++ b/assets
@@ -1 +1 @@
-Subproject commit be9d790af9c6f1f5e3afc7aed2b1d5c21823bc20
+Subproject commit e634c8f50c34845097283e0f411e1f89409e1498

From 4f344846896153b13bdb00fb4510ec163a4d7671 Mon Sep 17 00:00:00 2001
From: EliteMasterEric <ericmyllyoja@gmail.com>
Date: Sun, 5 Nov 2023 00:26:03 -0400
Subject: [PATCH 3/7] Use correct location for js.html.Navigator.

---
 source/funkin/util/PlatformUtil.hx | 6 +++---
 1 file changed, 3 insertions(+), 3 deletions(-)

diff --git a/source/funkin/util/PlatformUtil.hx b/source/funkin/util/PlatformUtil.hx
index 6c8609332..b709eb475 100644
--- a/source/funkin/util/PlatformUtil.hx
+++ b/source/funkin/util/PlatformUtil.hx
@@ -13,9 +13,9 @@ class PlatformUtil
     #if mac
     return true;
     #elseif html5
-    return js.html.Navigator.platform.startsWith("Mac")
-      || js.html.Navigator.platform.startsWith("iPad")
-      || js.html.Navigator.platform.startsWith("iPhone");
+    return js.Browser.window.navigator.platform.startsWith("Mac")
+      || js.Browser.window.navigator.platform.startsWith("iPad")
+      || js.Browser.window.navigator.platform.startsWith("iPhone");
     #else
     return false;
     #end

From 2728f34512e31bcf87953dcec6b7e1bc86212d2f Mon Sep 17 00:00:00 2001
From: EliteMasterEric <ericmyllyoja@gmail.com>
Date: Tue, 7 Nov 2023 18:53:50 -0500
Subject: [PATCH 4/7] Fix bug where Freeplay random would crash the game

---
 source/funkin/FreeplayState.hx            | 14 +++++++++++++-
 source/funkin/freeplayStuff/LetterSort.hx |  9 +++++++--
 2 files changed, 20 insertions(+), 3 deletions(-)

diff --git a/source/funkin/FreeplayState.hx b/source/funkin/FreeplayState.hx
index 918e7c725..0ba5d5175 100644
--- a/source/funkin/FreeplayState.hx
+++ b/source/funkin/FreeplayState.hx
@@ -84,6 +84,7 @@ class FreeplayState extends MusicBeatSubState
 
   var dj:DJBoyfriend;
 
+  var letterSort:LetterSort;
   var typing:FlxInputText;
   var exitMovers:Map<Array<FlxSprite>, MoveData> = new Map();
 
@@ -413,7 +414,7 @@ class FreeplayState extends MusicBeatSubState
     txtCompletion.visible = false;
     add(txtCompletion);
 
-    var letterSort:LetterSort = new LetterSort(400, 75);
+    letterSort = new LetterSort(400, 75);
     add(letterSort);
     letterSort.visible = false;
 
@@ -953,6 +954,7 @@ class FreeplayState extends MusicBeatSubState
     trace("RANDOM SELECTED");
 
     busy = true;
+    letterSort.inputEnabled = false;
 
     var availableSongCapsules:Array<SongMenuItem> = grpCapsules.members.filter(function(cap:SongMenuItem) {
       // Dead capsules are ones which were removed from the list when changing filters.
@@ -963,6 +965,15 @@ class FreeplayState extends MusicBeatSubState
       return cap.songData.songName;
     })}');
 
+    if (availableSongCapsules.length == 0)
+    {
+      trace("No songs available!");
+      busy = false;
+      letterSort.inputEnabled = true;
+      FlxG.sound.play(Paths.sound('cancelMenu'));
+      return;
+    }
+
     var targetSong:SongMenuItem = FlxG.random.getObject(availableSongCapsules);
 
     // Seeing if I can do an animation...
@@ -976,6 +987,7 @@ class FreeplayState extends MusicBeatSubState
   function capsuleOnConfirmDefault(cap:SongMenuItem):Void
   {
     busy = true;
+    letterSort.inputEnabled = false;
 
     PlayStatePlaylist.isStoryMode = false;
 
diff --git a/source/funkin/freeplayStuff/LetterSort.hx b/source/funkin/freeplayStuff/LetterSort.hx
index e6d923c90..edf1221d2 100644
--- a/source/funkin/freeplayStuff/LetterSort.hx
+++ b/source/funkin/freeplayStuff/LetterSort.hx
@@ -23,6 +23,8 @@ class LetterSort extends FlxTypedSpriteGroup<FlxSprite>
   var rightArrow:FlxSprite;
   var grpSeperators:Array<FlxSprite> = [];
 
+  public var inputEnabled:Bool = true;
+
   public function new(x, y)
   {
     super(x, y);
@@ -72,8 +74,11 @@ class LetterSort extends FlxTypedSpriteGroup<FlxSprite>
   {
     super.update(elapsed);
 
-    if (FlxG.keys.justPressed.E) changeSelection(1);
-    if (FlxG.keys.justPressed.Q) changeSelection(-1);
+    if (inputEnabled)
+    {
+      if (FlxG.keys.justPressed.E) changeSelection(1);
+      if (FlxG.keys.justPressed.Q) changeSelection(-1);
+    }
   }
 
   public function changeSelection(diff:Int = 0)

From f8ec09b7c257df88241c0a93453faee51bfbfc74 Mon Sep 17 00:00:00 2001
From: Cameron Taylor <cameron.taylor.ninja@gmail.com>
Date: Thu, 9 Nov 2023 06:28:50 -0500
Subject: [PATCH 5/7] update modules + assets merge

---
 .gitmodules | 3 +++
 assets      | 2 +-
 2 files changed, 4 insertions(+), 1 deletion(-)

diff --git a/.gitmodules b/.gitmodules
index 8968471e3..17c3cc026 100644
--- a/.gitmodules
+++ b/.gitmodules
@@ -2,6 +2,9 @@
 	path = assets
 	url = https://github.com/FunkinCrew/Funkin-history-rewrite-assets
 	branch = master
+	update = merge
 [submodule "art"]
 	path = art
 	url = https://github.com/FunkinCrew/Funkin-history-rewrite-art
+	branch = master
+	update = merge
diff --git a/assets b/assets
index e634c8f50..11a1af02f 160000
--- a/assets
+++ b/assets
@@ -1 +1 @@
-Subproject commit e634c8f50c34845097283e0f411e1f89409e1498
+Subproject commit 11a1af02fd38ed6086f09bf59567e1efa57b5715

From a9dfd4adcf50aaaad3cfa9bec71540a460bd7c57 Mon Sep 17 00:00:00 2001
From: EliteMasterEric <ericmyllyoja@gmail.com>
Date: Thu, 9 Nov 2023 17:00:46 -0500
Subject: [PATCH 6/7] Fix a bug where multiple vocal tracks would play at once

---
 source/funkin/play/PlayState.hx | 4 ++++
 1 file changed, 4 insertions(+)

diff --git a/source/funkin/play/PlayState.hx b/source/funkin/play/PlayState.hx
index 4542b9f98..0438ffecc 100644
--- a/source/funkin/play/PlayState.hx
+++ b/source/funkin/play/PlayState.hx
@@ -700,6 +700,8 @@ class PlayState extends MusicBeatSubState
 
       if (!overrideMusic)
       {
+        // Stop the vocals if they already exist.
+        if (vocals != null) vocals.stop();
         vocals = currentChart.buildVocals();
 
         if (vocals.members.length == 0)
@@ -1554,6 +1556,8 @@ class PlayState extends MusicBeatSubState
 
     if (!overrideMusic)
     {
+      // Stop the vocals if they already exist.
+      if (vocals != null) vocals.stop();
       vocals = currentChart.buildVocals();
 
       if (vocals.members.length == 0)

From 6956144df7164c0f759d22d8c824bca37ffd26aa Mon Sep 17 00:00:00 2001
From: EliteMasterEric <ericmyllyoja@gmail.com>
Date: Thu, 9 Nov 2023 17:03:13 -0500
Subject: [PATCH 7/7] Update haxeui-flixel

---
 hmm.json | 2 +-
 1 file changed, 1 insertion(+), 1 deletion(-)

diff --git a/hmm.json b/hmm.json
index 22dd6e42f..778b85604 100644
--- a/hmm.json
+++ b/hmm.json
@@ -56,7 +56,7 @@
       "name": "haxeui-flixel",
       "type": "git",
       "dir": null,
-      "ref": "9bd0b9e0fea40b8e06a89aac4949512d95064609",
+      "ref": "95c7d66e779626eabd6f48a1cd7aa7f9a503a7f3",
       "url": "https://github.com/haxeui/haxeui-flixel"
     },
     {