Skip to content

Commit

Permalink
Add fire-on-hold feature to FireListener, see #1004
Browse files Browse the repository at this point in the history
  • Loading branch information
jonathanolson committed Jan 30, 2020
1 parent 08ff485 commit 9968bb5
Showing 1 changed file with 43 additions and 1 deletion.
44 changes: 43 additions & 1 deletion js/listeners/FireListener.js
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@
define( require => {
'use strict';

const CallbackTimer = require( 'AXON/CallbackTimer' );
const Emitter = require( 'AXON/Emitter' );
const EventType = require( 'TANDEM/EventType' );
const inherit = require( 'PHET_CORE/inherit' );
Expand All @@ -38,6 +39,12 @@ define( require => {
// button is released while the pointer is over the button.
fireOnDown: false,

// fire-on-hold feature (similar to PushButtonModel, see https://github.com/phetsims/scenery/issues/1004 as
// this exists here so we don't need to use FireOnHoldInputListener ever).
fireOnHold: false, // {boolean} - is the fire-on-hold feature enabled?
fireOnHoldDelay: 400, // {number} - start to fire continuously after pressing for this long (milliseconds)
fireOnHoldInterval: 100, // {number} - fire continuously at this interval (milliseconds)

// {Tandem}
tandem: Tandem.REQUIRED
}, options );
Expand All @@ -60,6 +67,17 @@ define( require => {
} ]
} );
this.firedEmitter.addListener( options.fire );

// Create a timer to handle the optional fire-on-hold feature.
// When that feature is enabled, calling this.fire is delegated to the timer.
if ( options.fireOnHold ) {
// @private {CallbackTimer}
this._timer = new CallbackTimer( {
callback: this.fire.bind( this, null ), // Pass null for fire-on-hold events
delay: options.fireOnHoldDelay,
interval: options.fireOnHoldInterval
} );
}
}

scenery.register( 'FireListener', FireListener );
Expand Down Expand Up @@ -102,6 +120,9 @@ define( require => {
if ( this._fireOnDown ) {
this.fire( event );
}
if ( this._timer ) {
this._timer.start();
}
callback && callback();
} );
},
Expand All @@ -121,19 +142,40 @@ define( require => {
release( event, callback ) {
PressListener.prototype.release.call( this, event, () => {
// Notify after the rest of release is called in order to prevent it from triggering interrupt().
if ( !this._fireOnDown && this.isHoveringProperty.value && !this.interrupted ) {
const shouldFire = !this._fireOnDown && this.isHoveringProperty.value && !this.interrupted;
if ( this._timer ) {
this._timer.stop( shouldFire );
}
else if ( shouldFire ) {
this.fire( event );
}
callback && callback();
} );
},

/**
* Interrupts the listener, releasing it (canceling behavior).
* @public
* @override
*
* This effectively releases/ends the press, and sets the `interrupted` flag to true while firing these events
* so that code can determine whether a release/end happened naturally, or was canceled in some way.
*
* This can be called manually, but can also be called through node.interruptSubtreeInput().
*/
interrupt() {
PressListener.prototype.interrupt.call( this );

this._timer && this._timer.stop( false ); // Stop the timer, don't fire if we haven't already
},

/**
* @override
* @public
*/
dispose() {
this.firedEmitter.dispose();
this._timer && this._timer.dispose();

PressListener.prototype.dispose.call( this );
}
Expand Down

0 comments on commit 9968bb5

Please sign in to comment.