add prompt, finalize login UI

This commit is contained in:
George FunBook 2021-02-18 13:58:16 -06:00
parent 85cae9dbd2
commit c95f24983f
12 changed files with 574 additions and 118 deletions

View File

@ -166,6 +166,12 @@
<!-- <haxedef name="SKIP_TO_PLAYSTATE" if="debug" /> -->
<haxedef name="NG_LOGIN" if="newgrounds" />
<!-- Enables Ng.core.verbose -->
<!-- <haxedef name="NG_VERBOSE" /> -->
<!-- Enables a NG debug session, so medals don't permently unlock -->
<!-- <haxedef name="NG_DEBUG" /> -->
<!-- pretends that the saved session Id was expired, forcing the reconnect prompt -->
<!-- <haxedef name="NG_FORCE_EXPIRED_SESSION" if="debug" /> -->
</project>

Binary file not shown.

After

Width:  |  Height:  |  Size: 79 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<TextureAtlas imagePath="FNF_main_menu_assets-2019.png">
<!-- Created with Adobe Animate version 19.2.1.408 -->
<!-- http://www.adobe.com/products/animate.html -->
<SubTexture name="back0000" x="0" y="0" width="1157" height="645"/>
<SubTexture name="no basic0000" x="1157" y="0" width="210" height="197"/>
<SubTexture name="no white0000" x="1367" y="0" width="210" height="197" frameX="-1" frameY="-14" frameWidth="212" frameHeight="215"/>
<SubTexture name="no white0001" x="1577" y="0" width="212" height="194" frameX="0" frameY="-10" frameWidth="212" frameHeight="215"/>
<SubTexture name="no white0002" x="1789" y="0" width="210" height="215" frameX="0" frameY="0" frameWidth="212" frameHeight="215"/>
<SubTexture name="ok basic0000" x="0" y="645" width="256" height="185"/>
<SubTexture name="ok white0000" x="256" y="645" width="256" height="185" frameX="0" frameY="-11" frameWidth="263" frameHeight="202"/>
<SubTexture name="ok white0001" x="512" y="645" width="230" height="183" frameX="-22" frameY="-11" frameWidth="263" frameHeight="202"/>
<SubTexture name="ok white0002" x="742" y="645" width="245" height="202" frameX="-18" frameY="0" frameWidth="263" frameHeight="202"/>
<SubTexture name="yes basic0000" x="987" y="645" width="303" height="205"/>
<SubTexture name="yes white0000" x="1290" y="645" width="303" height="205" frameX="-13" frameY="-19" frameWidth="340" frameHeight="230"/>
<SubTexture name="yes white0001" x="1593" y="645" width="330" height="230" frameX="-8" frameY="0" frameWidth="340" frameHeight="230"/>
<SubTexture name="yes white0002" x="0" y="875" width="340" height="214" frameX="0" frameY="-12" frameWidth="340" frameHeight="230"/>
</TextureAtlas>

Binary file not shown.

After

Width:  |  Height:  |  Size: 78 KiB

View File

@ -0,0 +1,18 @@
<?xml version="1.0" encoding="utf-8"?>
<TextureAtlas imagePath="prompt-ng_login.png">
<!-- Created with Adobe Animate version 19.2.1.408 -->
<!-- http://www.adobe.com/products/animate.html -->
<SubTexture name="back0000" x="0" y="0" width="1157" height="645"/>
<SubTexture name="no basic0000" x="1159" y="0" width="210" height="197"/>
<SubTexture name="no white0000" x="1371" y="0" width="210" height="197" frameX="-1" frameY="-14" frameWidth="212" frameHeight="215"/>
<SubTexture name="no white0001" x="1583" y="0" width="212" height="194" frameX="0" frameY="-10" frameWidth="212" frameHeight="215"/>
<SubTexture name="no white0002" x="1797" y="0" width="210" height="215" frameX="0" frameY="0" frameWidth="212" frameHeight="215"/>
<SubTexture name="ok basic0000" x="0" y="647" width="231" height="167"/>
<SubTexture name="ok white0000" x="233" y="647" width="231" height="167" frameX="0" frameY="-9" frameWidth="238" frameHeight="181"/>
<SubTexture name="ok white0001" x="466" y="647" width="206" height="165" frameX="-21" frameY="-9" frameWidth="238" frameHeight="181"/>
<SubTexture name="ok white0002" x="674" y="647" width="220" height="181" frameX="-18" frameY="0" frameWidth="238" frameHeight="181"/>
<SubTexture name="yes basic0000" x="896" y="647" width="303" height="205"/>
<SubTexture name="yes white0000" x="1201" y="647" width="303" height="205" frameX="-13" frameY="-19" frameWidth="340" frameHeight="230"/>
<SubTexture name="yes white0001" x="1506" y="647" width="330" height="230" frameX="-8" frameY="0" frameWidth="340" frameHeight="230"/>
<SubTexture name="yes white0002" x="0" y="879" width="340" height="214" frameX="0" frameY="-12" frameWidth="340" frameHeight="230"/>
</TextureAtlas>

View File

@ -1,5 +1,7 @@
package;
import NGio;
import flixel.ui.FlxButton;
import flixel.FlxG;
import flixel.FlxObject;
import flixel.FlxSprite;
@ -17,12 +19,13 @@ import io.newgrounds.NG;
import lime.app.Application;
import ui.MenuItemList;
import ui.Prompt;
using StringTools;
class MainMenuState extends MusicBeatState
{
var menuItems:MenuItemList;
var menuItems:MainMenuItemList;
var magenta:FlxSprite;
var camFollow:FlxObject;
@ -63,7 +66,7 @@ class MainMenuState extends MusicBeatState
add(magenta);
// magenta.scrollFactor.set();
menuItems = new MenuItemList('FNF_main_menu_assets');
menuItems = new MainMenuItemList('FNF_main_menu_assets');
add(menuItems);
menuItems.onChange.add(onMenuItemChange);
menuItems.onAcceptPress.add(function(_)
@ -74,17 +77,18 @@ class MainMenuState extends MusicBeatState
var hasPopupBlocker = #if web true #else false #end;
menuItems.addItem('story mode', function () startExitState(new StoryMenuState()));
menuItems.addItem('freeplay', function () startExitState(new FreeplayState()));
menuItems.enabled = false;// disable for intro
menuItems.createItem('story mode', function () startExitState(new StoryMenuState()));
menuItems.createItem('freeplay', function () startExitState(new FreeplayState()));
// addMenuItem('options', function () startExitState(new OptionMenu()));
#if (!switch)
menuItems.addItem('donate', selectDonate, hasPopupBlocker);
menuItems.createItem('donate', selectDonate, hasPopupBlocker);
#end
#if newgrounds
if (NG.core.loggedIn)
menuItems.addItem("logout", selectLogout);
menuItems.createItem("logout", selectLogout);
else
menuItems.addItem("login", selectLogin, hasPopupBlocker);
menuItems.createItem("login", selectLogin);
#end
// center vertically
@ -109,6 +113,16 @@ class MainMenuState extends MusicBeatState
super.create();
}
override function finishTransIn()
{
super.finishTransIn();
menuItems.enabled = true;
if (NGio.savedSessionFailed)
showSavedSessionFailed();
}
function onMenuItemChange(selected:MenuItem)
{
camFollow.setPosition(selected.getGraphicMidpoint().x, selected.getGraphicMidpoint().y);
@ -123,13 +137,101 @@ class MainMenuState extends MusicBeatState
#end
}
#if newgrounds
function selectLogin()
{
showNgPrompt(true);
}
function showSavedSessionFailed()
{
showNgPrompt(false);
}
function showNgPrompt(fromUi:Bool)
{
menuItems.enabled = false;
var prompt = new Prompt("prompt-ng_login", "Talking to server...", None);
prompt.closeCallback = function() menuItems.enabled = true;
openSubState(prompt);
function onLoginComplete(result:ConnectionResult)
{
switch (result)
{
case Success:
menuItems.resetItem("login", "logout", selectLogout);
prompt.setText("Login Successful");
prompt.setButtons(Ok);
prompt.onYes = prompt.close;
case Fail(msg):
trace("Login Error:" + msg);
prompt.setText("Login failed");
prompt.setButtons(Ok);
prompt.onYes = prompt.close;
case Cancelled:
if (prompt != null)
{
prompt.setText("Login cancelled by user");
prompt.setButtons(Ok);
prompt.onYes = prompt.close;
}
}
}
NGio.login
(
function popupLauncher(openPassportUrl)
{
var choiceMsg = fromUi
? #if web "Log in to Newgrounds?" #else null #end // User-input needed to allow popups
: "Your session has expired.\n Please login again.";
if (choiceMsg != null)
{
prompt.setText(choiceMsg);
prompt.setButtons(Yes_No);
#if web
prompt.buttons.getItem("yes").fireInstantly = true;
#end
prompt.onYes = function()
{
prompt.setText("Connecting...");
prompt.setButtons(None);
openPassportUrl();
};
prompt.onNo = function()
{
prompt.close();
prompt = null;
NG.core.cancelLoginRequest();
};
}
else
{
prompt.setText("Connecting...");
openPassportUrl();
}
},
onLoginComplete
);
}
function selectLogout()
{
menuItems.enabled = false;
var prompt = new Prompt("prompt-ng_login", "Log out of " + NG.core.user.name + "?", Yes_No);
prompt.closeCallback = function () menuItems.enabled = true;
prompt.onYes = function()
{
NGio.logout();
prompt.close();
menuItems.resetItem("logout", "login", selectLogin);
};
prompt.onNo = prompt.close;
openSubState(prompt);
}
#end
function startExitState(state:FlxState)
{
@ -156,9 +258,57 @@ class MainMenuState extends MusicBeatState
FlxG.sound.music.volume += 0.5 * FlxG.elapsed;
}
if (menuItems.active && controls.BACK)
if (menuItems.enabled && controls.BACK)
FlxG.switchState(new TitleState());
super.update(elapsed);
}
}
private class MainMenuItemList extends MenuTypedItemList<MainMenuItem>
{
public var atlas:FlxAtlasFrames;
public function new (atlas)
{
super(Vertical);
if (Std.is(atlas, String))
this.atlas = Paths.getSparrowAtlas(cast atlas);
else
this.atlas = cast atlas;
}
public function createItem(x = 0.0, y = 0.0, name:String, callback, fireInstantly = false)
{
var i = length;
var item = new MainMenuItem(x, y, name, atlas, callback);
item.fireInstantly = fireInstantly;
item.ID = i;
return addItem(name, item);
}
override function destroy()
{
super.destroy();
atlas = null;
}
}
private class MainMenuItem extends MenuItem
{
public function new(x = 0.0, y = 0.0, name, atlas, callback)
{
super(x, y, name, atlas, callback);
scrollFactor.set();
}
override function changeAnim(anim:String)
{
super.changeAnim(anim);
// position by center
centerOrigin();
offset.copyFrom(origin);
}
}

View File

@ -6,6 +6,7 @@ import flixel.util.FlxTimer;
import io.newgrounds.NG;
import io.newgrounds.NGLite;
import io.newgrounds.components.ScoreBoardComponent.Period;
import io.newgrounds.objects.Error;
import io.newgrounds.objects.Medal;
import io.newgrounds.objects.Score;
import io.newgrounds.objects.ScoreBoard;
@ -22,6 +23,11 @@ using StringTools;
*/
class NGio
{
/**
* True, if the saved sessionId was used in the initial login, and failed to connect.
* Used in MainMenuState to show a popup to establish a new connection
*/
public static var savedSessionFailed(default, null):Bool = false;
public static var isLoggedIn:Bool = false;
public static var scoreboardsLoaded:Bool = false;
@ -31,54 +37,68 @@ class NGio
public static var ngScoresLoaded(default, null):FlxSignal = new FlxSignal();
public static var GAME_VER:String = "";
public static var GAME_VER_NUMS:String = '';
public static var gotOnlineVer:Bool = false;
public static function noLogin(api:String)
static public function checkVersion(callback:String->Void)
{
trace('INIT NOLOGIN');
trace('checking NG.io version');
GAME_VER = "v" + Application.current.meta.get('version');
if (api.length != 0)
{
NG.create(api);
new FlxTimer().start(2, function(tmr:FlxTimer)
NG.core.calls.app.getCurrentVersion(GAME_VER)
.addDataHandler(function(response)
{
var call = NG.core.calls.app.getCurrentVersion(GAME_VER).addDataHandler(function(response:Response<GetCurrentVersionResult>)
{
GAME_VER = response.result.data.currentVersion;
GAME_VER_NUMS = GAME_VER.split(" ")[0].trim();
trace('CURRENT NG VERSION: ' + GAME_VER);
gotOnlineVer = true;
});
call.send();
});
}
GAME_VER = response.result.data.currentVersion;
trace('CURRENT NG VERSION: ' + GAME_VER);
callback(GAME_VER);
})
.send();
}
public function new(api:String, encKey:String)
static public function init(api:String, encKey:String)
{
var api = APIStuff.API;
if (api == null || api.length == 0)
{
trace("Missing Newgrounds API key, aborting connection");
return;
}
trace("connecting to newgrounds");
var sessionId:String = NGLite.getSessionId();
if (sessionId != null)
trace("found web session id");
#if NG_FORCE_EXPIRED_SESSION
var sessionId:String = "fake_session_id";
function onSessionFail(error:Error)
{
trace("Forcing an expired saved session. "
+ "To disable, comment out NG_FORCE_EXPIRED_SESSION in Project.xml");
savedSessionFailed = true;
}
#else
var sessionId:String = NGLite.getSessionId();
if (sessionId != null)
trace("found web session id");
#if (debug)
if (sessionId == null && APIStuff.SESSION != null)
{
trace("using debug session id");
sessionId = APIStuff.SESSION;
}
#end
#if (debug)
if (sessionId == null && APIStuff.SESSION != null)
{
sessionId = APIStuff.SESSION;
trace("using debug session id");
}
var onSessionFail:Error->Void = null;
if (sessionId == null && FlxG.save.data.sessionId != null)
{
trace("using stored session id");
sessionId = FlxG.save.data.sessionId;
onSessionFail = function (error) savedSessionFailed = true;
}
#end
NG.create(api, sessionId, #if NG_DEBUG true #else false #end, onSessionFail);
NG.create(api, sessionId);
NG.core.verbose = true;
#if NG_VERBOSE NG.core.verbose = true; #end
// Set the encryption cipher/format to RC4/Base64. AES128 and Hex are not implemented yet
NG.core.initEncryption(encKey); // Found in you NG project view
NG.core.initEncryption(APIStuff.EncKey); // Found in you NG project view
if (NG.core.attemptingLogin)
{
@ -89,21 +109,53 @@ class NGio
NG.core.onLogin.add(onNGLogin);
}
//GK: taking out auto login, adding a login button to the main menu
else
// else
// {
// /* They are NOT playing on newgrounds.com, no session id was found. We must start one manually, if we want to.
// * Note: This will cause a new browser window to pop up where they can log in to newgrounds
// */
// NG.core.requestLogin(onNGLogin);
// }
}
/**
* Attempts to log in to newgrounds by requesting a new session ID, only call if no session ID was found automatically
* @param popupLauncher The function to call to open the login url, must be inside
* a user input event or the popup blocker will block it.
* @param onComplete A callback with the result of the connection.
*/
static public function login(?popupLauncher:(Void->Void)->Void, onComplete:ConnectionResult->Void)
{
trace("Logging in manually");
var onPending:Void->Void = null;
if (popupLauncher != null)
{
/* They are NOT playing on newgrounds.com, no session id was found. We must start one manually, if we want to.
* Note: This will cause a new browser window to pop up where they can log in to newgrounds
*/
NG.core.requestLogin(onNGLogin);
onPending = function () popupLauncher(NG.core.openPassportUrl);
}
var onSuccess:Void->Void = onNGLogin;
var onFail:Error->Void = null;
var onCancel:Void->Void = null;
if (onComplete != null)
{
onSuccess = function ()
{
onNGLogin();
onComplete(Success);
}
onFail = function (e) onComplete(Fail(e.message));
onCancel = function() onComplete(Cancelled);
}
NG.core.requestLogin(onSuccess, onPending, onFail, onCancel);
}
function onNGLogin():Void
static function onNGLogin():Void
{
trace('logged in! user:${NG.core.user.name}');
isLoggedIn = true;
FlxG.save.data.sessionId = NG.core.sessionId;
// FlxG.save.flush();
FlxG.save.flush();
// Load medals then call onNGMedalFetch()
NG.core.requestMedals(onNGMedalFetch);
@ -112,9 +164,17 @@ class NGio
ngDataLoaded.dispatch();
}
static public function logout()
{
NG.core.logOut();
FlxG.save.data.sessionId = null;
FlxG.save.flush();
}
// --- MEDALS
function onNGMedalFetch():Void
static function onNGMedalFetch():Void
{
/*
// Reading medal info
@ -132,7 +192,7 @@ class NGio
}
// --- SCOREBOARDS
function onNGBoardsFetch():Void
static function onNGBoardsFetch():Void
{
/*
// Reading medal info
@ -174,7 +234,7 @@ class NGio
}
}
function onNGScoresFetch():Void
static function onNGScoresFetch():Void
{
scoreboardsLoaded = true;
@ -209,3 +269,13 @@ class NGio
}
}
}
enum ConnectionResult
{
/** Log in successful */
Success;
/** Could not login */
Fail(msg:String);
/** User cancelled the login */
Cancelled;
}

View File

@ -54,17 +54,11 @@ class TitleState extends MusicBeatState
super.create();
NGio.noLogin(APIStuff.API);
#if ng
var ng:NGio = new NGio(APIStuff.API, APIStuff.EncKey);
trace('NEWGROUNDS LOL');
#end
FlxG.save.bind('funkin', 'ninjamuffin99');
Highscore.load();
NGio.init(APIStuff.API, APIStuff.EncKey);
if (FlxG.save.data.weekUnlocked != null)
{
// FIX LATER!!!
@ -264,22 +258,26 @@ class TitleState extends MusicBeatState
transitioning = true;
// FlxG.sound.music.stop();
new FlxTimer().start(2, function(tmr:FlxTimer)
if (!OutdatedSubState.leftState)
{
// Check if version is outdated
var version:String = "v" + Application.current.meta.get('version');
if (version.trim() != NGio.GAME_VER_NUMS && !OutdatedSubState.leftState)
NGio.checkVersion(function(version)
{
trace('OLD VERSION!');
FlxG.switchState(new OutdatedSubState());
}
else
{
FlxG.switchState(new MainMenuState());
}
});
// Check if version is outdated
var localVersion:String = "v" + Application.current.meta.get('version');
var onlineVersion = version.split(" ")[0].trim();
if (version.trim() != onlineVersion)
{
trace('OLD VERSION!');
FlxG.switchState(new OutdatedSubState());
}
else
{
FlxG.switchState(new MainMenuState());
}
});
}
// FlxG.sound.play(Paths.music('titleShoot'), 0.7);
}

View File

@ -10,53 +10,110 @@ import flixel.tweens.FlxEase;
import flixel.tweens.FlxTween;
import flixel.util.FlxSignal;
typedef ItemAsset = OneOfTwo<String, FlxAtlasFrames>
typedef AtlasAsset = OneOfTwo<String, FlxAtlasFrames>;
class MenuItemList extends MenuTypedItemList<MenuItem>
{
public function addItem(x = 0.0, y = 0.0, name, callback, fireInstantly = false)
public var atlas:FlxAtlasFrames;
public function new (atlas, navControls:NavControls = Vertical)
{
var i = length;
var menuItem = new MenuItem(name, tex, callback, x, y);
menuItem.fireInstantly = fireInstantly;
menuItem.ID = i;
add(menuItem);
super(navControls);
if (i == selectedIndex)
menuItem.select();
return menuItem;
if (Std.is(atlas, String))
this.atlas = Paths.getSparrowAtlas(cast atlas);
else
this.atlas = cast atlas;
}
public function createItem(x = 0.0, y = 0.0, name, callback, fireInstantly = false)
{
var item = new MenuItem(x, y, name, atlas, callback);
item.fireInstantly = fireInstantly;
return addItem(name, item);
}
override function destroy()
{
super.destroy();
atlas = null;
}
}
class MenuTypedItemList<T:MenuItem> extends FlxTypedGroup<T>
{
public var tex:FlxAtlasFrames;
public var selectedIndex = 0;
public var selectedIndex(default, null) = 0;
/** Called when a new item is highlighted */
public var onChange(default, null) = new FlxTypedSignal<T->Void>();
/** Called when an item is accepted */
public var onAcceptPress(default, null) = new FlxTypedSignal<T->Void>();
/** The navigation control scheme to use */
public var navControls:NavControls;
/** Set to false to disable nav control */
public var enabled:Bool = true;
public function new (asset:ItemAsset)
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)
{
this.navControls = navControls;
super();
}
function addItem(name:String, item:T):T
{
if (length == selectedIndex)
item.select();
if (Std.is(asset, String))
tex = Paths.getSparrowAtlas(cast asset);
else
tex = cast asset;
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;
}
override function update(elapsed:Float)
{
super.update(elapsed);
if (enabled && !busy)
updateControls();
}
inline function updateControls()
{
var controls = PlayerSettings.player1.controls;
if (controls.UP_P)
prev();
if (controls.DOWN_P)
next();
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();
}
}
if (controls.ACCEPT)
accept();
@ -71,12 +128,12 @@ class MenuTypedItemList<T:MenuItem> extends FlxTypedGroup<T>
selected.callback();
else
{
active = false;
busy = true;
FlxG.sound.play(Paths.sound('confirmMenu'));
FlxFlicker.flicker(selected, 1, 0.06, true, false, function(_)
{
busy = false;
selected.callback();
active = true;
});
}
}
@ -87,24 +144,35 @@ class MenuTypedItemList<T:MenuItem> extends FlxTypedGroup<T>
function changeItem(amount:Int)
{
FlxG.sound.play(Paths.sound('scrollMenu'));
var index = selectedIndex + amount;
if (index >= length)
index = 0;
else if (index < 0)
index = length - 1;
selectItem(index);
}
public function selectItem(index:Int)
{
members[selectedIndex].idle();
selectedIndex += amount;
if (selectedIndex >= length)
selectedIndex = 0;
else if (selectedIndex < 0)
selectedIndex = length - 1;
selectedIndex = index;
var selected = members[selectedIndex];
selected.select();
onChange.dispatch(selected);
}
public function getItem(name:String)
{
return byName[name];
}
override function destroy()
{
super.destroy();
tex = null;
byName.clear();
}
}
@ -116,41 +184,49 @@ class MenuItem extends flixel.FlxSprite
*/
public var fireInstantly = false;
public function new (name, tex, callback, x = 0.0, y = 0.0)
public function new (x = 0.0, y = 0.0, name, tex, callback)
{
super(x, y);
frames = tex;
setItem(name, callback);
antialiasing = true;
}
public function setItem(name:String, callback:Void->Void)
public function setItem(name:String, ?callback:Void->Void)
{
this.callback = callback;
if (callback != null)
this.callback = callback;
var selected = animation.curAnim != null && animation.curAnim.name == "selected";
animation.addByPrefix('idle', '$name basic', 24);
animation.addByPrefix('selected', '$name white', 24);
idle();
scrollFactor.set();
antialiasing = true;
if (selected)
select();
}
function updateSize()
function changeAnim(anim:String)
{
animation.play(anim);
updateHitbox();
centerOrigin();
offset.copyFrom(origin);
}
public function idle()
{
animation.play('idle');
updateSize();
changeAnim('idle');
}
public function select()
{
animation.play('selected');
updateSize();
changeAnim('selected');
}
}
enum NavControls
{
Horizontal;
Vertical;
Both;
}

120
source/ui/Prompt.hx Normal file
View File

@ -0,0 +1,120 @@
package ui;
import flixel.FlxSprite;
import flixel.graphics.frames.FlxAtlasFrames;
import flixel.text.FlxText;
import flixel.util.FlxColor;
class Prompt extends flixel.FlxSubState
{
inline static var MARGIN = 100;
public var onYes:Void->Void;
public var onNo:Void->Void;
public var buttons:MenuItemList;
public var field:FlxText;
public var back:FlxSprite;
var style:ButtonStyle;
public function new (atlas, text:String, style:ButtonStyle = Ok)
{
this.style = style;
super();
var texture:FlxAtlasFrames;
if (Std.is(atlas, String))
texture = Paths.getSparrowAtlas(cast atlas);
else
texture = cast atlas;
back = new FlxSprite();
back.frames = texture;
back.animation.addByPrefix("idle", "back");
back.scrollFactor.set(0, 0);
buttons = new MenuItemList(texture, Horizontal);
field = new FlxText();
field.setFormat(Paths.font("vcr.ttf"), 64, FlxColor.BLACK, CENTER);
field.text = text;
field.scrollFactor.set(0, 0);
}
override function create()
{
super.create();
back.animation.play("idle");
back.updateHitbox();
back.screenCenter(XY);
add(back);
field.y = back.y + MARGIN;
field.screenCenter(X);
add(field);
createButtons();
add(buttons);
}
public function setButtons(style:ButtonStyle)
{
if (this.style != style)
{
this.style = style;
createButtons();
}
}
function createButtons()
{
// destroy previous buttons
while(buttons.members.length > 0)
{
buttons.remove(buttons.members[0], true).destroy();
}
switch(style)
{
case Yes_No : createButtonsHelper("yes", "no");
case Ok : createButtonsHelper("ok");
case Custom(yes, no): createButtonsHelper(yes, no);
case None : buttons.exists = false;
};
}
function createButtonsHelper(yes:String, ?no:String)
{
buttons.exists = true;
// pass anonymous functions rather than the current callbacks, in case they change later
var yesButton = buttons.createItem(yes, function() onYes());
yesButton.screenCenter(X);
yesButton.y = back.y + back.height - yesButton.height - MARGIN;
yesButton.scrollFactor.set(0, 0);
if (no != null)
{
// place right
yesButton.x = back.x + back.width - yesButton.width - MARGIN;
var noButton = buttons.createItem(no, function() onNo());
noButton.x = back.x + MARGIN;
noButton.y = back.y + back.height - noButton.height - MARGIN;
noButton.scrollFactor.set(0, 0);
}
}
public function setText(text:String)
{
field.text = text;
field.screenCenter(X);
}
}
enum ButtonStyle
{
Ok;
Yes_No;
Custom(yes:String, no:Null<String>);//Todo: more than 2
None;
}