Added multiple keybinds + Fixed shift keybinds
This commit is contained in:
@@ -1,5 +1,6 @@
|
||||
package funkin.editors.charter;
|
||||
|
||||
import flixel.input.keyboard.FlxKey;
|
||||
import flixel.system.FlxSound;
|
||||
import flixel.util.FlxSort;
|
||||
import flixel.math.FlxPoint;
|
||||
@@ -100,7 +101,7 @@ class Charter extends UIState {
|
||||
},
|
||||
{
|
||||
label: "Redo",
|
||||
keybind: [CONTROL, Y],
|
||||
keybinds: [[CONTROL, Y], [CONTROL, SHIFT, Z]],
|
||||
onSelect: _edit_redo
|
||||
},
|
||||
null,
|
||||
|
||||
@@ -3,74 +3,74 @@ package funkin.editors.ui;
|
||||
import flixel.input.keyboard.FlxKey;
|
||||
|
||||
class UIContextMenu extends MusicBeatSubstate {
|
||||
public var options:Array<UIContextMenuOption>;
|
||||
var x:Float;
|
||||
var y:Float;
|
||||
var contextCam:FlxCamera;
|
||||
public var options:Array<UIContextMenuOption>;
|
||||
var x:Float;
|
||||
var y:Float;
|
||||
var contextCam:FlxCamera;
|
||||
|
||||
var bg:UISliceSprite;
|
||||
var callback:UIContextMenuCallback;
|
||||
var bg:UISliceSprite;
|
||||
var callback:UIContextMenuCallback;
|
||||
|
||||
public var contextMenuOptions:Array<UIContextMenuOptionSpr> = [];
|
||||
public var separators:Array<FlxSprite> = [];
|
||||
public var contextMenuOptions:Array<UIContextMenuOptionSpr> = [];
|
||||
public var separators:Array<FlxSprite> = [];
|
||||
|
||||
private var __oobDeletion:Bool = true;
|
||||
private var __oobDeletion:Bool = true;
|
||||
|
||||
public inline function preventOutOfBoxClickDeletion() {
|
||||
__oobDeletion = false;
|
||||
}
|
||||
public inline function preventOutOfBoxClickDeletion() {
|
||||
__oobDeletion = false;
|
||||
}
|
||||
|
||||
public function new(options:Array<UIContextMenuOption>, callback:UIContextMenuCallback, x:Float, y:Float) {
|
||||
super();
|
||||
this.options = options.getDefault([]);
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.callback = callback;
|
||||
}
|
||||
public function new(options:Array<UIContextMenuOption>, callback:UIContextMenuCallback, x:Float, y:Float) {
|
||||
super();
|
||||
this.options = options.getDefault([]);
|
||||
this.x = x;
|
||||
this.y = y;
|
||||
this.callback = callback;
|
||||
}
|
||||
|
||||
public override function create() {
|
||||
super.create();
|
||||
camera = contextCam = new FlxCamera();
|
||||
contextCam.bgColor = 0;
|
||||
contextCam.alpha = 0;
|
||||
contextCam.scroll.set(0, 7.5);
|
||||
FlxG.cameras.add(contextCam, false);
|
||||
public override function create() {
|
||||
super.create();
|
||||
camera = contextCam = new FlxCamera();
|
||||
contextCam.bgColor = 0;
|
||||
contextCam.alpha = 0;
|
||||
contextCam.scroll.set(0, 7.5);
|
||||
FlxG.cameras.add(contextCam, false);
|
||||
|
||||
bg = new UISliceSprite(x, y, 100, 100, 'editors/ui/context-bg');
|
||||
bg = new UISliceSprite(x, y, 100, 100, 'editors/ui/context-bg');
|
||||
bg.cameras = [contextCam];
|
||||
add(bg);
|
||||
add(bg);
|
||||
|
||||
var lastY:Float = bg.y + 4;
|
||||
for(o in options) {
|
||||
if (o == null) {
|
||||
var spr = new FlxSprite(bg.x + 8, lastY + 2).makeGraphic(1, 1, -1);
|
||||
spr.alpha = 0.3;
|
||||
separators.push(spr);
|
||||
add(spr);
|
||||
lastY += 5;
|
||||
continue;
|
||||
}
|
||||
var spr = new UIContextMenuOptionSpr(bg.x + 4, lastY, o, this);
|
||||
var lastY:Float = bg.y + 4;
|
||||
for(o in options) {
|
||||
if (o == null) {
|
||||
var spr = new FlxSprite(bg.x + 8, lastY + 2).makeGraphic(1, 1, -1);
|
||||
spr.alpha = 0.3;
|
||||
separators.push(spr);
|
||||
add(spr);
|
||||
lastY += 5;
|
||||
continue;
|
||||
}
|
||||
var spr = new UIContextMenuOptionSpr(bg.x + 4, lastY, o, this);
|
||||
spr.cameras = [contextCam];
|
||||
lastY = spr.y + spr.bHeight;
|
||||
contextMenuOptions.push(spr);
|
||||
add(spr);
|
||||
}
|
||||
lastY = spr.y + spr.bHeight;
|
||||
contextMenuOptions.push(spr);
|
||||
add(spr);
|
||||
}
|
||||
|
||||
var maxW = bg.bWidth - 8;
|
||||
for(o in contextMenuOptions)
|
||||
if (o.bWidth > maxW)
|
||||
maxW = o.bWidth;
|
||||
var maxW = bg.bWidth - 8;
|
||||
for(o in contextMenuOptions)
|
||||
if (o.bWidth > maxW)
|
||||
maxW = o.bWidth;
|
||||
|
||||
|
||||
for(o in contextMenuOptions)
|
||||
o.bWidth = maxW;
|
||||
for(o in separators) {
|
||||
o.scale.set(maxW - 8, 1);
|
||||
o.updateHitbox();
|
||||
}
|
||||
bg.bWidth = maxW + 8;
|
||||
bg.bHeight = Std.int(lastY - bg.y + 4);
|
||||
|
||||
for(o in contextMenuOptions)
|
||||
o.bWidth = maxW;
|
||||
for(o in separators) {
|
||||
o.scale.set(maxW - 8, 1);
|
||||
o.updateHitbox();
|
||||
}
|
||||
bg.bWidth = maxW + 8;
|
||||
bg.bHeight = Std.int(lastY - bg.y + 4);
|
||||
|
||||
if (bg.y + bg.bHeight > FlxG.height) {
|
||||
bg.y -= bg.bHeight;
|
||||
@@ -79,58 +79,59 @@ class UIContextMenu extends MusicBeatSubstate {
|
||||
for(o in separators)
|
||||
o.y -= bg.bHeight;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
public function select(option:UIContextMenuOption) {
|
||||
var index = options.indexOf(option);
|
||||
if (option.onSelect != null)
|
||||
option.onSelect(option);
|
||||
if (callback != null)
|
||||
callback(this, index, option);
|
||||
close();
|
||||
}
|
||||
public function select(option:UIContextMenuOption) {
|
||||
var index = options.indexOf(option);
|
||||
if (option.onSelect != null)
|
||||
option.onSelect(option);
|
||||
if (callback != null)
|
||||
callback(this, index, option);
|
||||
close();
|
||||
}
|
||||
|
||||
public override function update(elapsed:Float) {
|
||||
if (__oobDeletion && FlxG.mouse.pressed && !bg.hoveredByChild)
|
||||
close();
|
||||
public override function update(elapsed:Float) {
|
||||
if (__oobDeletion && FlxG.mouse.pressed && !bg.hoveredByChild)
|
||||
close();
|
||||
|
||||
__oobDeletion = true;
|
||||
__oobDeletion = true;
|
||||
|
||||
super.update(elapsed);
|
||||
super.update(elapsed);
|
||||
|
||||
contextCam.scroll.y = CoolUtil.fpsLerp(contextCam.scroll.y, 0, 0.5);
|
||||
contextCam.alpha = CoolUtil.fpsLerp(contextCam.alpha, 1, 0.25);
|
||||
}
|
||||
contextCam.scroll.y = CoolUtil.fpsLerp(contextCam.scroll.y, 0, 0.5);
|
||||
contextCam.alpha = CoolUtil.fpsLerp(contextCam.alpha, 1, 0.25);
|
||||
}
|
||||
|
||||
public override function destroy() {
|
||||
super.destroy();
|
||||
FlxG.cameras.remove(contextCam);
|
||||
if (UIState.state.curContextMenu == this)
|
||||
UIState.state.curContextMenu = null;
|
||||
}
|
||||
public override function destroy() {
|
||||
super.destroy();
|
||||
FlxG.cameras.remove(contextCam);
|
||||
if (UIState.state.curContextMenu == this)
|
||||
UIState.state.curContextMenu = null;
|
||||
}
|
||||
}
|
||||
|
||||
typedef UIContextMenuCallback = UIContextMenu->Int->UIContextMenuOption->Void;
|
||||
typedef UIContextMenuOption = {
|
||||
var label:String;
|
||||
var ?keybind:Array<FlxKey>;
|
||||
var ?icon:Int;
|
||||
var ?onSelect:UIContextMenuOption->Void;
|
||||
var ?childs:Array<UIContextMenuOption>;
|
||||
var label:String;
|
||||
var ?keybind:Array<FlxKey>;
|
||||
var ?keybinds:Array<Array<FlxKey>>;
|
||||
var ?icon:Int;
|
||||
var ?onSelect:UIContextMenuOption->Void;
|
||||
var ?childs:Array<UIContextMenuOption>;
|
||||
}
|
||||
|
||||
class UIContextMenuOptionSpr extends UISliceSprite {
|
||||
public var label:UIText;
|
||||
public var labelKeybind:UIText;
|
||||
public var label:UIText;
|
||||
public var labelKeybind:UIText;
|
||||
public var icon:FlxSprite;
|
||||
public var option:UIContextMenuOption;
|
||||
public var option:UIContextMenuOption;
|
||||
|
||||
var parent:UIContextMenu;
|
||||
var parent:UIContextMenu;
|
||||
|
||||
public function new(x:Float, y:Float, option:UIContextMenuOption, parent:UIContextMenu) {
|
||||
label = new UIText(20, 2, 0, option.label);
|
||||
this.option = option;
|
||||
this.parent = parent;
|
||||
public function new(x:Float, y:Float, option:UIContextMenuOption, parent:UIContextMenu) {
|
||||
label = new UIText(20, 2, 0, option.label);
|
||||
this.option = option;
|
||||
this.parent = parent;
|
||||
|
||||
if (option.icon != null && option.icon > 0) {
|
||||
icon = new FlxSprite(0, 0).loadGraphic(Paths.image('editors/ui/context-icons'), true, 20, 20);
|
||||
@@ -138,34 +139,45 @@ class UIContextMenuOptionSpr extends UISliceSprite {
|
||||
icon.animation.play('icon');
|
||||
}
|
||||
|
||||
if (option.keybind != null) {
|
||||
var text = "";
|
||||
text += [for(o in option.keybind) o.toUIString()].join("+");
|
||||
if (option.keybinds == null) {
|
||||
if (option.keybind != null) {
|
||||
option.keybinds = [option.keybind];
|
||||
}
|
||||
}
|
||||
|
||||
if (option.keybinds != null) {
|
||||
var textKeys:Array<String> = [];
|
||||
for (o in option.keybinds[0]) {
|
||||
if (Std.int(o) > 0) {
|
||||
textKeys.push(o.toUIString());
|
||||
}
|
||||
}
|
||||
var text = textKeys.join("+");
|
||||
labelKeybind = new UIText(label.x + label.frameWidth + 10, 2, 0, text);
|
||||
labelKeybind.alpha = 0.75;
|
||||
}
|
||||
|
||||
super(x, y, labelKeybind != null ? Std.int(labelKeybind.x + labelKeybind.frameWidth + 10) : (label.frameWidth + 22), label.frameHeight, 'editors/ui/menu-item');
|
||||
members.push(label);
|
||||
if (icon != null)
|
||||
super(x, y, labelKeybind != null ? Std.int(labelKeybind.x + labelKeybind.frameWidth + 10) : (label.frameWidth + 22), label.frameHeight, 'editors/ui/menu-item');
|
||||
members.push(label);
|
||||
if (icon != null)
|
||||
members.push(icon);
|
||||
if (labelKeybind != null)
|
||||
if (labelKeybind != null)
|
||||
members.push(labelKeybind);
|
||||
}
|
||||
}
|
||||
|
||||
public override function draw() {
|
||||
alpha = hovered ? 1 : 0;
|
||||
label.follow(this, 20, 2);
|
||||
public override function draw() {
|
||||
alpha = hovered ? 1 : 0;
|
||||
label.follow(this, 20, 2);
|
||||
if (icon != null)
|
||||
icon.follow(this, 0, 0);
|
||||
if (labelKeybind != null)
|
||||
labelKeybind.follow(this, bWidth - 10 - labelKeybind.frameWidth, 2);
|
||||
super.draw();
|
||||
}
|
||||
super.draw();
|
||||
}
|
||||
|
||||
public override function onHovered() {
|
||||
super.onHovered();
|
||||
if (FlxG.mouse.justReleased)
|
||||
parent.select(option);
|
||||
}
|
||||
public override function onHovered() {
|
||||
super.onHovered();
|
||||
if (FlxG.mouse.justReleased)
|
||||
parent.select(option);
|
||||
}
|
||||
}
|
||||
@@ -16,37 +16,51 @@ class UIUtil {
|
||||
|
||||
/**
|
||||
* Process all options with shortcuts present in a `Array<UIContextMenuOption>`. Also checks childrens.
|
||||
* @param topMenuOptions
|
||||
* @param topMenuOptions
|
||||
*/
|
||||
public static function processShortcuts(topMenuOptions:Array<UIContextMenuOption>) {
|
||||
for(o in topMenuOptions) {
|
||||
if (o == null) continue;
|
||||
|
||||
if (o.keybind != null) {
|
||||
var pressed = true;
|
||||
var justPressed = false;
|
||||
for(keybind in o.keybind) {
|
||||
var k = switch(keybind) {
|
||||
#if mac
|
||||
case CONTROL:
|
||||
WINDOWS;
|
||||
#end
|
||||
default:
|
||||
keybind;
|
||||
}
|
||||
if (FlxG.keys.checkStatus(k, JUST_PRESSED)) {
|
||||
justPressed = true;
|
||||
} else if (!FlxG.keys.checkStatus(k, PRESSED)) {
|
||||
pressed = false;
|
||||
break;
|
||||
}
|
||||
if (o.keybinds == null) {
|
||||
if (o.keybind != null) {
|
||||
o.keybinds = [o.keybind];
|
||||
}
|
||||
if (!pressed || !justPressed) continue;
|
||||
}
|
||||
|
||||
if (o.onSelect != null)
|
||||
o.onSelect(o);
|
||||
if (o.keybinds != null) {
|
||||
for (keybind in o.keybinds) {
|
||||
var pressed = true;
|
||||
var justPressed = false;
|
||||
var needsShift = keybind.contains(SHIFT);
|
||||
|
||||
return true;
|
||||
for (key in keybind) {
|
||||
var shouldPress = Std.int(key) > 0;
|
||||
if(!shouldPress) key = -key;
|
||||
|
||||
var k = switch(key) {
|
||||
#if mac
|
||||
case CONTROL:
|
||||
WINDOWS;
|
||||
#end
|
||||
default:
|
||||
key;
|
||||
}
|
||||
if (FlxG.keys.checkStatus(k, shouldPress ? JUST_PRESSED : JUST_RELEASED)) {
|
||||
justPressed = true;
|
||||
} else if (!FlxG.keys.checkStatus(k, shouldPress ? PRESSED : RELEASED)) {
|
||||
pressed = false;
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (!needsShift && FlxG.keys.pressed.SHIFT) continue;
|
||||
if (!pressed || !justPressed) continue;
|
||||
|
||||
if (o.onSelect != null)
|
||||
o.onSelect(o);
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
||||
if (o.childs != null && processShortcuts(o.childs))
|
||||
|
||||
Reference in New Issue
Block a user