Skip to content

[ENHANCEMENT] Stage Editor - Selection improvements #5281

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
wants to merge 1 commit into
base: develop
Choose a base branch
from
Open
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
188 changes: 105 additions & 83 deletions source/funkin/ui/debug/stageeditor/StageEditorState.hx
Original file line number Diff line number Diff line change
Expand Up @@ -102,6 +102,7 @@ class StageEditorState extends UIState
var menubarItemDelete:MenuItem; // delete
var menubarItemNewObj:MenuItem; // new
var menubarItemFindObj:MenuItem; // find
var menubarItemSelectNone:MenuItem; // access none
var menubarItemMoveStep:Menu; // move step submenu

var menubarMenuView:Menu;
Expand Down Expand Up @@ -141,6 +142,7 @@ class StageEditorState extends UIState
{
selectedSprite?.selectedShader.setAmount(0);
this.selectedSprite = value;
infoSelection = value?.name ?? "None";
updateDialog(StageEditorDialogType.OBJECT_GRAPHIC);
updateDialog(StageEditorDialogType.OBJECT_ANIMS);
updateDialog(StageEditorDialogType.OBJECT_PROPERTIES);
Expand All @@ -161,6 +163,7 @@ class StageEditorState extends UIState
function set_selectedChar(value:BaseCharacter)
{
this.selectedChar = value;
infoSelection = Std.string(value?.characterType) ?? "None";
updateDialog(StageEditorDialogType.CHARACTER);
return selectedChar;
}
Expand Down Expand Up @@ -579,7 +582,6 @@ class StageEditorState extends UIState

// testmode
menubarMenuFile.disabled = menubarMenuEdit.disabled = bottomBarModeText.disabled = menubarMenuWindow.disabled = testingMode;
menubarButtonText.selected = testingMode;

if (testingMode)
{
Expand All @@ -596,6 +598,7 @@ class StageEditorState extends UIState
if (FlxG.keys.justPressed.TAB && !FlxG.keys.pressed.SHIFT) curTestChar++;

if (curTestChar >= getCharacters().length) curTestChar = 0;
else if (curTestChar < 0) curTestChar = getCharacters().length - 1;

bottomBarSelectText.text = Std.string(getCharacters()[curTestChar].characterType);

Expand Down Expand Up @@ -625,10 +628,11 @@ class StageEditorState extends UIState
}

// key shortcuts and inputs
if (allowInput)
if (pressingControl() && FlxG.keys.justPressed.Q) onMenuItemClick("exit");

if (allowInput && welcomeDialog == null)
{
// "WINDOWS" key code is the same keycode as COMMAND on mac
if (FlxG.keys.pressed.CONTROL || FlxG.keys.pressed.WINDOWS)
if (pressingControl())
{
if (FlxG.keys.justPressed.Z) onMenuItemClick("undo");
if (FlxG.keys.justPressed.Y) onMenuItemClick("redo");
Expand All @@ -637,9 +641,9 @@ class StageEditorState extends UIState
if (FlxG.keys.justPressed.X) onMenuItemClick("cut object");
if (FlxG.keys.justPressed.S) FlxG.keys.pressed.SHIFT ? onMenuItemClick("save stage as") : onMenuItemClick("save stage");
if (FlxG.keys.justPressed.F) onMenuItemClick("find object");
if (FlxG.keys.justPressed.D) onMenuItemClick("select none");
if (FlxG.keys.justPressed.O) onMenuItemClick("open stage");
if (FlxG.keys.justPressed.N) onMenuItemClick("new stage");
if (FlxG.keys.justPressed.Q) onMenuItemClick("exit");
}

if (FlxG.keys.justPressed.TAB) onMenuItemClick("switch mode");
Expand All @@ -653,7 +657,8 @@ class StageEditorState extends UIState
FlxG.camera.zoom = 1;
}

if (FlxG.keys.pressed.W || FlxG.keys.pressed.S || FlxG.keys.pressed.A || FlxG.keys.pressed.D)
if (!pressingControl()
&& (FlxG.keys.pressed.W || FlxG.keys.pressed.S || FlxG.keys.pressed.A || FlxG.keys.pressed.D))
{
if (FlxG.keys.pressed.W) camFollow.velocity.y = -90 * (2 / FlxG.camera.zoom);
else if (FlxG.keys.pressed.S) camFollow.velocity.y = 90 * (2 / FlxG.camera.zoom);
Expand All @@ -680,30 +685,33 @@ class StageEditorState extends UIState

if (moveMode == "assets")
{
if (selectedSprite != null && !FlxG.mouse.overlaps(selectedSprite) && FlxG.mouse.justPressed && !isCursorOverHaxeUI)
if (selectedSprite != null
&& (!FlxG.mouse.overlaps(selectedSprite)
|| (FlxG.mouse.overlaps(selectedSprite) && pressingControl()))
&& FlxG.mouse.justPressed
&& !isCursorOverHaxeUI)
{
selectedSprite = null;
}

for (spr in spriteArray)
if (!isCursorOverHaxeUI)
{
if (FlxG.mouse.overlaps(spr))
if (menubarItemViewNameText.selected) nameTxt.visible = true;
for (spr in spriteArray)
{
if (spr.visible && !FlxG.keys.pressed.SHIFT) nameTxt.text = spr.name;

if (FlxG.mouse.justPressed && allowInput && spr.visible && !FlxG.keys.pressed.SHIFT && !isCursorOverHaxeUI)
if (!pressingControl() && FlxG.mouse.overlaps(spr))
{
selectedSprite = spr;
}
}
if (spr.visible && !FlxG.keys.pressed.SHIFT) nameTxt.text = spr.name;

if (spr == selectedSprite)
{
infoSelection = spr.name;

if (FlxG.keys.pressed.SHIFT) nameTxt.text = spr.name + " (LOCKED)";
if (FlxG.mouse.justPressed && allowInput && spr.visible && !FlxG.keys.pressed.SHIFT)
{
selectedSprite = spr;
}
}
}
if (selectedSprite != null && FlxG.keys.pressed.SHIFT) nameTxt.text = selectedSprite.name + " (LOCKED)";
}
else if (nameTxt.visible) nameTxt.visible = false;

if (FlxG.mouse.pressed && allowInput && selectedSprite != null && FlxG.mouse.overlaps(selectedSprite) && FlxG.mouse.justMoved && !isCursorOverHaxeUI)
{
Expand Down Expand Up @@ -745,29 +753,26 @@ class StageEditorState extends UIState
else
{
selectedChar.shader = null;

for (char in getCharacters())
if (!isCursorOverHaxeUI)
{
if (char != selectedChar) char.shader = charDeselectShader;

if (char != null && checkCharOverlaps(char)) // flxg.mouse.overlaps crashes the game
if (menubarItemViewNameText.selected) nameTxt.visible = true;
for (char in getCharacters())
{
if (char.visible && !FlxG.keys.pressed.SHIFT) nameTxt.text = Std.string(char.characterType);
if (char != selectedChar) char.shader = charDeselectShader;

if (FlxG.mouse.justPressed && allowInput && char.visible && !FlxG.keys.pressed.SHIFT && !isCursorOverHaxeUI)
if (char != null && checkCharOverlaps(char)) // flxg.mouse.overlaps crashes the game
{
selectedChar = char;
updateDialog(StageEditorDialogType.CHARACTER);
}
}

if (selectedChar == char)
{
infoSelection = Std.string(char.characterType);
if (char.visible && !FlxG.keys.pressed.SHIFT) nameTxt.text = Std.string(char.characterType);

if (FlxG.keys.pressed.SHIFT) nameTxt.text = Std.string(char.characterType) + " (LOCKED)";
if (FlxG.mouse.justPressed && allowInput && char.visible && !FlxG.keys.pressed.SHIFT && !isCursorOverHaxeUI)
{
selectedChar = char;
}
}
}
if (selectedChar != null && FlxG.keys.pressed.SHIFT) nameTxt.text = Std.string(selectedChar.characterType) + " (LOCKED)";
}
else if (nameTxt.visible) nameTxt.visible = false;

if (FlxG.mouse.pressed && allowInput && checkCharOverlaps(selectedChar) && FlxG.mouse.justMoved && !isCursorOverHaxeUI)
{
Expand All @@ -793,8 +798,6 @@ class StageEditorState extends UIState
arrowMovement(selectedChar);
updateMarkerPos();
}

if ((selectedSprite == null && moveMode == "assets") || (selectedChar == null && moveMode == "chars")) infoSelection = "None";
bottomBarSelectText.text = infoSelection;

// ui stuff
Expand All @@ -815,6 +818,20 @@ class StageEditorState extends UIState
menubarItemRedo.disabled = redoArray.length == 0;
}

/**
* Small helper for MacOS, "WINDOWS" is keycode 15, which maps to "COMMAND" on Mac, which is more often used than "CONTROL"
* Everywhere else, it just returns `FlxG.keys.pressed.CONTROL`
* @return Bool
*/
function pressingControl():Bool
{
#if mac
return FlxG.keys.pressed.WINDOWS;
#else
return FlxG.keys.pressed.CONTROL;
#end
}

public function getCharacters()
{
return [gf, dad, bf];
Expand Down Expand Up @@ -905,7 +922,7 @@ class StageEditorState extends UIState
if (obj == null) return;
if (FlxG.keys.pressed.R) return; // rotations

if (allowInput)
if (allowInput && welcomeDialog == null)
{
if ((FlxG.keys.justPressed.UP || FlxG.keys.justPressed.DOWN || FlxG.keys.justPressed.LEFT || FlxG.keys.justPressed.RIGHT)
&& !moveUndoed)
Expand Down Expand Up @@ -1009,17 +1026,6 @@ class StageEditorState extends UIState
bg.screenCenter();
}

function checkOverlaps(spr:FlxSprite):Bool
{
if (FlxG.mouse.overlaps(spr) /*spr.overlapsPoint(FlxG.mouse.getWorldPosition(spr.camera), true, spr.camera) */
&& Screen.instance != null
&& !Screen.instance.hasSolidComponentUnderPoint(FlxG.mouse.viewX, FlxG.mouse.viewY)
&& WindowManager.instance.windows.length == 0) // ik its stupid but maybe I have other cases soon (i did)
return true;

return false;
}

var sprDependant:Array<MenuItem> = [];

function addUI():Void
Expand All @@ -1038,13 +1044,49 @@ class StageEditorState extends UIState
menubarItemDelete.onClick = function(_) onMenuItemClick("delete object");
menubarItemNewObj.onClick = function(_) onMenuItemClick("new object");
menubarItemFindObj.onClick = function(_) onMenuItemClick("find object");
menubarItemSelectNone.onClick = function(_) onMenuItemClick("select none");
menubarButtonText.onClick = function(_) onMenuItemClick("test stage");
menubarItemUserGuide.onClick = function(_) onMenuItemClick("user guide");
menubarItemGoToBackupsFolder.onClick = function(_) onMenuItemClick("open folder");
menubarItemAbout.onClick = function(_) onMenuItemClick("about");

bottomBarModeText.onClick = function(_) onMenuItemClick("switch mode");
bottomBarSelectText.onClick = function(_) onMenuItemClick("switch focus");
bottomBarModeText.onRightClick = function(_) onMenuItemClick("switch mode");

function switchFocus(rightClick:Bool = false)
if (testingMode)
{
(rightClick) ? curTestChar-- : curTestChar++;
}
else
{
if (moveMode == "chars")
{
var chars = getCharacters();
var index = chars.indexOf(selectedChar);
(rightClick) ? index-- : index++;

if (index >= chars.length) index = 0;
else if (index < 0) index = chars.length - 1;

selectedChar = chars[index];
}
else
{
if (selectedSprite == null || FlxG.keys.pressed.SHIFT) return;

var index = spriteArray.indexOf(selectedSprite);
(rightClick) ? index-- : index++;

if (index >= spriteArray.length) index = 0;
else if (index < 0) index = spriteArray.length - 1;

selectedSprite = spriteArray[index];
}
}

bottomBarSelectText.onClick = function(_) switchFocus();
bottomBarSelectText.onRightClick = function(_) switchFocus(true);

var stepOptions = ["1px", "2px", "3px", "5px", "10px", "25px", "50px", "100px"];
bottomBarMoveStepText.text = stepOptions.contains(Save.instance.stageEditorMoveStep) ? Save.instance.stageEditorMoveStep : "1px";
Expand Down Expand Up @@ -1118,6 +1160,7 @@ class StageEditorState extends UIState

menubarItemViewChars.onChange = function(_) showChars = menubarItemViewChars.selected;
menubarItemViewNameText.onChange = function(_) nameTxt.visible = menubarItemViewNameText.selected;
menubarItemViewNameText.selected = true; // TODO: Remove this when this haxeUI bug is fixed (it starts as false in the code)?
menubarItemViewCamBounds.onChange = function(_) camFields.visible = menubarItemViewCamBounds.selected;

menubarItemViewFloorLines.onChange = function(_) {
Expand All @@ -1130,7 +1173,7 @@ class StageEditorState extends UIState
coolbeans.visible = menubarItemViewPosMarkers.selected;
}

sprDependant = [menubarItemCopy, menubarItemCut, menubarItemDelete];
sprDependant = [menubarItemCopy, menubarItemCut, menubarItemDelete, menubarItemSelectNone];
reloadRecentFiles();
}

Expand Down Expand Up @@ -1287,37 +1330,9 @@ class StageEditorState extends UIState
if (testingMode) return;
moveMode = (moveMode == "assets" ? "chars" : "assets");

selectedSprite?.selectedShader.setAmount((moveMode == "assets" ? 1 : 0));
infoSelection = (moveMode == "chars") ? (Std.string(selectedChar?.characterType) ?? "None") : (moveMode == "assets") ? (selectedSprite?.name ?? "None") : "Wut";

case "switch focus":
if (testingMode)
{
curTestChar++;
}
else
{
if (moveMode == "chars")
{
var chars = getCharacters();
var index = chars.indexOf(selectedChar);
index++;

if (index >= chars.length) index = 0;

selectedChar = chars[index];
}
else
{
if (selectedSprite == null) return;

var index = spriteArray.indexOf(selectedSprite);
index++;

if (index >= spriteArray.length) index = 0;

selectedSprite = spriteArray[index];
}
}
selectedSprite?.selectedShader.setAmount((moveMode == "assets" ? 1 : 0));

case "new object":
findObjDialog.hideDialog(DialogButton.CANCEL);
Expand All @@ -1336,6 +1351,12 @@ class StageEditorState extends UIState
findObjDialog = new FindObjDialog(this, selectedSprite == null ? "" : selectedSprite.name);
findObjDialog.showDialog(false);

case "select none":
if (menubarItemSelectNone.disabled == false)
{
selectedSprite = null;
}

case "about":
aboutDialog = new AboutDialog();
aboutDialog.showDialog();
Expand Down Expand Up @@ -1369,6 +1390,8 @@ class StageEditorState extends UIState
{
menubarItemWindowObjectGraphic.selected = menubarItemWindowObjectAnims.selected = menubarItemWindowObjectProps.selected = menubarItemWindowCharacter.selected = menubarItemWindowStage.selected = false;
}
nameTxt.exists = testingMode;
menubarButtonText.selected = !testingMode;

selectedSprite?.selectedShader.setAmount((testingMode ? (moveMode == "assets" ? 1 : 0) : 0));
testingMode = !testingMode;
Expand Down Expand Up @@ -1413,7 +1436,6 @@ class StageEditorState extends UIState
remove(selectedSprite, true);
selectedSprite.destroy();
selectedSprite = null;

updateArray();

case "copy object":
Expand Down