Funkin/source/ui/MenuList.hx

294 lines
5.3 KiB
Haxe
Raw Normal View History

2021-02-15 12:43:51 -05:00
package ui;
import flixel.math.FlxPoint;
import flixel.FlxG;
import flixel.FlxSprite;
2021-02-15 12:43:51 -05:00
import flixel.effects.FlxFlicker;
import flixel.group.FlxGroup;
import flixel.util.FlxSignal;
class MenuTypedList<T:MenuItem> extends FlxTypedGroup<T>
2021-02-15 12:43:51 -05:00
{
2021-02-18 14:58:16 -05:00
public var selectedIndex(default, null) = 0;
/** Called when a new item is highlighted */
2021-02-15 12:43:51 -05:00
public var onChange(default, null) = new FlxTypedSignal<T->Void>();
2021-02-18 14:58:16 -05:00
/** Called when an item is accepted */
2021-02-15 12:43:51 -05:00
public var onAcceptPress(default, null) = new FlxTypedSignal<T->Void>();
2021-02-18 14:58:16 -05:00
/** The navigation control scheme to use */
public var navControls:NavControls;
/** Set to false to disable nav control */
public var enabled:Bool = true;
2021-02-15 12:43:51 -05:00
2021-02-18 14:58:16 -05:00
var byName = new Map<String, T>();
/** Set to true, internally to disable controls, without affecting vars like `enabled` */
var busy:Bool = false;
public function new (navControls:NavControls = Vertical)
2021-02-15 12:43:51 -05:00
{
2021-02-18 14:58:16 -05:00
this.navControls = navControls;
2021-02-15 12:43:51 -05:00
super();
2021-02-18 14:58:16 -05:00
}
function addItem(name:String, item:T):T
{
if (length == selectedIndex)
item.select();
2021-02-15 12:43:51 -05:00
2021-02-18 14:58:16 -05:00
byName[name] = item;
return add(item);
}
public function resetItem(oldName:String, newName:String, ?callback:Void->Void):T
{
if (!byName.exists(oldName))
throw "No item named:" + oldName;
var item = byName[oldName];
byName.remove(oldName);
byName[newName] = item;
item.setItem(newName, callback);
return item;
2021-02-15 12:43:51 -05:00
}
override function update(elapsed:Float)
{
super.update(elapsed);
2021-02-18 14:58:16 -05:00
if (enabled && !busy)
updateControls();
}
inline function updateControls()
{
2021-02-15 12:43:51 -05:00
var controls = PlayerSettings.player1.controls;
2021-02-18 14:58:16 -05:00
switch(navControls)
{
case Vertical:
{
if (controls.UP_P ) prev();
if (controls.DOWN_P) next();
}
case Horizontal:
{
if (controls.LEFT_P ) prev();
if (controls.RIGHT_P) next();
}
case Both:
{
if (controls.LEFT_P || controls.UP_P ) prev();
if (controls.RIGHT_P || controls.DOWN_P) next();
}
}
2021-02-19 21:11:33 -05:00
//Todo: bypass popup blocker on firefox
2021-02-15 12:43:51 -05:00
if (controls.ACCEPT)
accept();
}
public function accept()
{
var selected = members[selectedIndex];
2021-02-15 17:04:08 -05:00
onAcceptPress.dispatch(selected);
2021-02-15 12:43:51 -05:00
if (selected.fireInstantly)
selected.callback();
else
{
2021-02-18 14:58:16 -05:00
busy = true;
2021-02-15 12:43:51 -05:00
FlxG.sound.play(Paths.sound('confirmMenu'));
FlxFlicker.flicker(selected, 1, 0.06, true, false, function(_)
{
2021-02-18 14:58:16 -05:00
busy = false;
2021-02-15 12:43:51 -05:00
selected.callback();
});
}
}
inline function prev() changeItem(-1);
inline function next() changeItem(1);
function changeItem(amount:Int)
{
FlxG.sound.play(Paths.sound('scrollMenu'));
2021-02-18 14:58:16 -05:00
var index = selectedIndex + amount;
if (index >= length)
index = 0;
else if (index < 0)
index = length - 1;
selectItem(index);
}
public function selectItem(index:Int)
{
2021-02-15 12:43:51 -05:00
members[selectedIndex].idle();
2021-02-18 14:58:16 -05:00
selectedIndex = index;
2021-02-15 12:43:51 -05:00
var selected = members[selectedIndex];
selected.select();
onChange.dispatch(selected);
}
public function has(name:String)
{
return byName.exists(name);
}
2021-02-18 14:58:16 -05:00
public function getItem(name:String)
{
return byName[name];
}
2021-02-15 12:43:51 -05:00
override function destroy()
{
super.destroy();
2021-02-18 14:58:16 -05:00
byName.clear();
2021-02-15 12:43:51 -05:00
}
}
class MenuItem extends FlxSprite
{
2021-02-15 12:43:51 -05:00
public var callback:Void->Void;
public var name:String;
2021-02-15 12:43:51 -05:00
/**
* Set to true for things like opening URLs otherwise, it may it get blocked.
*/
public var fireInstantly = false;
public var selected(get, never):Bool;
function get_selected() return alpha == 1.0;
2021-02-15 12:43:51 -05:00
public function new (x = 0.0, y = 0.0, name:String, callback)
2021-02-15 12:43:51 -05:00
{
super(x, y);
2021-02-18 14:58:16 -05:00
antialiasing = true;
setData(name, callback);
idle();
2021-02-15 12:43:51 -05:00
}
function setData(name:String, ?callback:Void->Void)
2021-02-15 12:43:51 -05:00
{
this.name = name;
2021-02-18 14:58:16 -05:00
if (callback != null)
this.callback = callback;
}
/**
* Calls setData and resets/redraws the state of the item
* @param name
* @param callback
*/
public function setItem(name:String, ?callback:Void->Void)
{
setData(name, callback);
2021-02-18 14:58:16 -05:00
if (selected)
select();
else
idle();
2021-02-15 12:43:51 -05:00
}
public function idle()
2021-02-15 12:43:51 -05:00
{
alpha = 0.6;
2021-02-15 12:43:51 -05:00
}
public function select()
2021-02-15 12:43:51 -05:00
{
alpha = 1.0;
2021-02-15 12:43:51 -05:00
}
}
class MenuTypedItem<T:FlxSprite> extends MenuItem
{
public var label(default, set):T;
2021-02-15 12:43:51 -05:00
public function new (x = 0.0, y = 0.0, label:T, name:String, callback)
{
super(x, y, name, callback);
// set label after super otherwise setters fuck up
this.label = label;
}
/**
* Use this when you only want to show the label
*/
function setEmptyBackground()
{
var oldWidth = width;
var oldHeight = height;
makeGraphic(1, 1, 0x0);
width = oldWidth;
height = oldHeight;
}
function set_label(value:T)
2021-02-15 12:43:51 -05:00
{
if (value != null)
{
value.x = x;
value.y = y;
value.alpha = alpha;
}
return this.label = value;
}
override function update(elapsed:Float)
{
super.update(elapsed);
if (label != null)
label.update(elapsed);
}
override function draw()
{
super.draw();
if (label != null)
{
label.cameras = cameras;
label.scrollFactor.copyFrom(scrollFactor);
label.draw();
}
}
override function set_alpha(value:Float):Float
{
super.set_alpha(value);
if (label != null)
label.alpha = alpha;
return alpha;
}
override function set_x(value:Float):Float
{
super.set_x(value);
if (label != null)
label.x = x;
return x;
}
override function set_y(Value:Float):Float
{
super.set_y(Value);
if (label != null)
label.y = y;
return y;
2021-02-15 12:43:51 -05:00
}
2021-02-18 14:58:16 -05:00
}
enum NavControls
{
Horizontal;
Vertical;
Both;
2021-02-15 12:43:51 -05:00
}