Skip to content

Commit

Permalink
Add disabled status to FlxButton (HaxeFlixel#3087)
Browse files Browse the repository at this point in the history
* Add disabled status to FlxButton (HaxeFlixel#3083)

* create FlxButtonState enum

* fix unit tests

---------

Co-authored-by: George FunBook <[email protected]>
  • Loading branch information
itulau and Geokureli authored Mar 18, 2024
1 parent 5ede2bd commit 6cd83e7
Show file tree
Hide file tree
Showing 3 changed files with 66 additions and 33 deletions.
Binary file modified assets/images/ui/button.png
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
86 changes: 59 additions & 27 deletions flixel/ui/FlxButton.hx
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,21 @@ import flixel.util.FlxDestroyUtil;
import flixel.input.touch.FlxTouch;
#end

enum abstract FlxButtonState(Int) to Int
{
/** The button is not highlighted or pressed */
var NORMAL = 0;

/** The button is selected, usually meaning the mouse is hovering over it */
var HIGHLIGHT = 1;

/** The button is being pressed usually by a mouse */
var PRESSED = 2;

/** The button is not interactible */
var DISABLED = 3;
}

/**
* A simple button class that calls a function when clicked by the mouse.
*/
Expand All @@ -26,17 +41,30 @@ class FlxButton extends FlxTypedButton<FlxText>
/**
* Used with public variable status, means not highlighted or pressed.
*/
public static inline var NORMAL:Int = 0;
@:dox(hide) @:noCompletion
@:deprecated("FlxButton.NORMAL is deprecated, use FlxButtonState.NORMAL")
public static inline var NORMAL = FlxButtonState.NORMAL;

/**
* Used with public variable status, means highlighted (usually from mouse over).
*/
public static inline var HIGHLIGHT:Int = 1;
@:dox(hide) @:noCompletion
@:deprecated("FlxButton.HIGHLIGHT is deprecated, use FlxButtonState.HIGHLIGHT")
public static inline var HIGHLIGHT = FlxButtonState.HIGHLIGHT;

/**
* Used with public variable status, means pressed (usually from mouse click).
*/
public static inline var PRESSED:Int = 2;
@:dox(hide) @:noCompletion
@:deprecated("FlxButton.PRESSED is deprecated, use FlxButtonState.PRESSED")
public static inline var PRESSED = FlxButtonState.PRESSED;

/**
* Used with public variable status, means non interactible.
*/
@:dox(hide) @:noCompletion
@:deprecated("FlxButton.DISABLED is deprecated, use FlxButtonState.DISABLED")
public static inline var DISABLED = FlxButtonState.DISABLED;

/**
* Shortcut to setting label.text
Expand Down Expand Up @@ -80,7 +108,7 @@ class FlxButton extends FlxTypedButton<FlxText>
{
if (Text != null)
{
label = new FlxText(x + labelOffsets[NORMAL].x, y + labelOffsets[NORMAL].y, 80, Text);
label = new FlxText(x + labelOffsets[FlxButtonState.NORMAL].x, y + labelOffsets[FlxButtonState.NORMAL].y, 80, Text);
label.setFormat(null, 8, 0x333333, "center");
label.alpha = labelAlphas[status];
label.drawFrame(true);
Expand Down Expand Up @@ -122,19 +150,19 @@ class FlxTypedButton<T:FlxSprite> extends FlxSprite implements IFlxInput
/**
* What offsets the `label` should have for each status.
*/
public var labelOffsets:Array<FlxPoint> = [FlxPoint.get(), FlxPoint.get(), FlxPoint.get(0, 1)];
public var labelOffsets:Array<FlxPoint> = [FlxPoint.get(), FlxPoint.get(), FlxPoint.get(0, 1), FlxPoint.get()];

/**
* What alpha value the label should have for each status. Default is `[0.8, 1.0, 0.5]`.
* Multiplied with the button's `alpha`.
*/
public var labelAlphas:Array<Float> = [0.8, 1.0, 0.5];
public var labelAlphas:Array<Float> = [0.8, 1.0, 0.5, 0.3];

/**
* What animation should be played for each status.
* Default is ["normal", "highlight", "pressed"].
*/
public var statusAnimations:Array<String> = ["normal", "highlight", "pressed"];
public var statusAnimations:Array<String> = ["normal", "highlight", "pressed", "disabled"];

/**
* Whether you can press the button simply by releasing the touch / mouse button over it (default).
Expand All @@ -157,10 +185,10 @@ class FlxTypedButton<T:FlxSprite> extends FlxSprite implements IFlxInput
public var maxInputMovement:Float = Math.POSITIVE_INFINITY;

/**
* Shows the current state of the button, either `FlxButton.NORMAL`,
* `FlxButton.HIGHLIGHT` or `FlxButton.PRESSED`.
* Shows the current state of the button, either `NORMAL`,
* `HIGHLIGHT` or `PRESSED`.
*/
public var status(default, set):Int;
public var status(default, set):FlxButtonState;

/**
* The properties of this button's `onUp` event (callback function, sound).
Expand Down Expand Up @@ -222,7 +250,7 @@ class FlxTypedButton<T:FlxSprite> extends FlxSprite implements IFlxInput
onOver = new FlxButtonEvent();
onOut = new FlxButtonEvent();

status = FlxButton.NORMAL;
status = NORMAL;

// Since this is a UI element, the default scrollFactor is (0, 0)
scrollFactor.set();
Expand All @@ -232,8 +260,8 @@ class FlxTypedButton<T:FlxSprite> extends FlxSprite implements IFlxInput
#end

#if FLX_NO_MOUSE // no need for highlight frame without mouse input
statusAnimations[FlxButton.HIGHLIGHT] = "normal";
labelAlphas[FlxButton.HIGHLIGHT] = 1;
statusAnimations[HIGHLIGHT] = "normal";
labelAlphas[HIGHLIGHT] = 1;
#end

input = new FlxInput(0);
Expand All @@ -243,9 +271,10 @@ class FlxTypedButton<T:FlxSprite> extends FlxSprite implements IFlxInput
{
super.graphicLoaded();

setupAnimation("normal", FlxButton.NORMAL);
setupAnimation("highlight", FlxButton.HIGHLIGHT);
setupAnimation("pressed", FlxButton.PRESSED);
setupAnimation("normal", NORMAL);
setupAnimation("highlight", HIGHLIGHT);
setupAnimation("pressed", PRESSED);
setupAnimation("disabled", DISABLED);
}

function loadDefaultGraphic():Void
Expand Down Expand Up @@ -384,6 +413,9 @@ class FlxTypedButton<T:FlxSprite> extends FlxSprite implements IFlxInput
*/
function updateButton():Void
{
// Prevent interactions with this input if it's currently disabled
if (status == DISABLED)
return;
// We're looking for any touch / mouse overlaps with this button
var overlapFound = checkMouseOverlap();
if (!overlapFound)
Expand All @@ -394,7 +426,7 @@ class FlxTypedButton<T:FlxSprite> extends FlxSprite implements IFlxInput
onUpHandler();
}

if (status != FlxButton.NORMAL && (!overlapFound || (currentInput != null && currentInput.justReleased)))
if (status != NORMAL && (!overlapFound || (currentInput != null && currentInput.justReleased)))
{
onOutHandler();
}
Expand Down Expand Up @@ -464,7 +496,7 @@ class FlxTypedButton<T:FlxSprite> extends FlxSprite implements IFlxInput
currentInput = input;
onDownHandler();
}
else if (status == FlxButton.NORMAL)
else if (status == NORMAL)
{
// Allow "swiping" to press a button (dragging it over the button while pressed)
if (allowSwiping && input.pressed)
Expand All @@ -489,7 +521,7 @@ class FlxTypedButton<T:FlxSprite> extends FlxSprite implements IFlxInput

function updateLabelAlpha()
{
if (_spriteLabel != null && labelAlphas.length > status)
if (_spriteLabel != null && labelAlphas.length > (status : Int))
{
_spriteLabel.alpha = alpha * labelAlphas[status];
}
Expand All @@ -502,7 +534,7 @@ class FlxTypedButton<T:FlxSprite> extends FlxSprite implements IFlxInput
#if FLX_MOUSE
function onUpEventListener(_):Void
{
if (visible && exists && active && status == FlxButton.PRESSED)
if (visible && exists && active && status == PRESSED)
{
onUpHandler();
}
Expand All @@ -514,7 +546,7 @@ class FlxTypedButton<T:FlxSprite> extends FlxSprite implements IFlxInput
*/
function onUpHandler():Void
{
status = FlxButton.HIGHLIGHT;
status = HIGHLIGHT;
input.release();
currentInput = null;
// Order matters here, because onUp.fire() could cause a state change and destroy this object.
Expand All @@ -526,7 +558,7 @@ class FlxTypedButton<T:FlxSprite> extends FlxSprite implements IFlxInput
*/
function onDownHandler():Void
{
status = FlxButton.PRESSED;
status = PRESSED;
input.press();
// Order matters here, because onDown.fire() could cause a state change and destroy this object.
onDown.fire();
Expand All @@ -542,11 +574,11 @@ class FlxTypedButton<T:FlxSprite> extends FlxSprite implements IFlxInput
// by remaining in the normal state (until mouse input is re-enabled).
if (!FlxG.mouse.enabled)
{
status = FlxButton.NORMAL;
status = NORMAL;
return;
}
#end
status = FlxButton.HIGHLIGHT;
status = HIGHLIGHT;
// Order matters here, because onOver.fire() could cause a state change and destroy this object.
onOver.fire();
}
Expand All @@ -556,7 +588,7 @@ class FlxTypedButton<T:FlxSprite> extends FlxSprite implements IFlxInput
*/
function onOutHandler():Void
{
status = FlxButton.NORMAL;
status = NORMAL;
input.release();
// Order matters here, because onOut.fire() could cause a state change and destroy this object.
onOut.fire();
Expand All @@ -579,9 +611,9 @@ class FlxTypedButton<T:FlxSprite> extends FlxSprite implements IFlxInput
return Value;
}

function set_status(Value:Int):Int
function set_status(value:FlxButtonState):FlxButtonState
{
status = Value;
status = value;
updateLabelAlpha();
return status;
}
Expand Down
13 changes: 7 additions & 6 deletions tests/unit/src/flixel/ui/FlxButtonTest.hx
Original file line number Diff line number Diff line change
@@ -1,7 +1,8 @@
package flixel.ui;

import openfl.display.BitmapData;
import flixel.FlxSprite;
import flixel.ui.FlxButton;
import openfl.display.BitmapData;
import massive.munit.Assert;

class FlxButtonTest extends FlxTest
Expand Down Expand Up @@ -45,9 +46,9 @@ class FlxButtonTest extends FlxTest

function assertStatusAnimationsExist()
{
var normalName:String = button.statusAnimations[FlxButton.NORMAL];
var highlightName:String = button.statusAnimations[FlxButton.HIGHLIGHT];
var pressedName:String = button.statusAnimations[FlxButton.PRESSED];
var normalName:String = button.statusAnimations[NORMAL];
var highlightName:String = button.statusAnimations[HIGHLIGHT];
var pressedName:String = button.statusAnimations[PRESSED];

Assert.isNotNull(button.animation.getByName(normalName));
Assert.isNotNull(button.animation.getByName(highlightName));
Expand All @@ -74,7 +75,7 @@ class FlxButtonTest extends FlxTest

button.setPosition();
step(1);
Assert.areEqual(FlxButton.HIGHLIGHT, button.status);
Assert.areEqual(HIGHLIGHT, button.status);

FlxG.state.remove(button);
}
Expand All @@ -87,7 +88,7 @@ class FlxButtonTest extends FlxTest
FlxG.state.add(button);
step(2);

Assert.areEqual(FlxButton.NORMAL, button.status);
Assert.areEqual(NORMAL, button.status);
Assert.areEqual("normal", button.animation.curAnim.name);
Assert.areEqual(false, button.animation.finished);
step(10);
Expand Down

0 comments on commit 6cd83e7

Please sign in to comment.