Skip to content

Commit

Permalink
Preparing input event barrier handling for dialogs (see #166), and fi…
Browse files Browse the repository at this point in the history
…xed the layout issues with the PhetMenu (fixes #114, fixes #115)
  • Loading branch information
jonathanolson committed Oct 8, 2014
1 parent 09e5bf9 commit fa5a352
Show file tree
Hide file tree
Showing 3 changed files with 99 additions and 46 deletions.
46 changes: 17 additions & 29 deletions js/PhetButton.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,12 +10,9 @@ define( function( require ) {
var Node = require( 'SCENERY/nodes/Node' );
var Image = require( 'SCENERY/nodes/Image' );
var FontAwesomeNode = require( 'SUN/FontAwesomeNode' );
var Plane = require( 'SCENERY/nodes/Plane' );
var inherit = require( 'PHET_CORE/inherit' );
var PhetMenu = require( 'JOIST/PhetMenu' );
var Shape = require( 'KITE/Shape' );
var ButtonListener = require( 'SCENERY/input/ButtonListener' );
var Vector2 = require( 'DOT/Vector2' );
var PushButtonDeprecated = require( 'SUN/PushButtonDeprecated' );
var HighlightNode = require( 'JOIST/HighlightNode' );

Expand All @@ -35,7 +32,6 @@ define( function( require ) {
*/
function PhetButton( sim, whiteColorScheme, homeScreen, options ) {

var phetButton = this;
options = _.extend( {
phetLogo: whiteColorScheme ? phetLogoDarker : phetLogo,
phetLogoScale: 0.28,
Expand Down Expand Up @@ -71,33 +67,25 @@ define( function( require ) {
//When the phet button is pressed, show the phet menu
var phetButtonPressed = function() {

//The PhetMenu can be embedded in different contexts, but the scale should be consistent. So look up the embedding scale here and factor it out. See #39
var ancestor = homeScreen ? phetButton.parents[0] : phetButton.parents[0].parents[0];
var scale = ancestor.getGlobalToLocalMatrix().getScaleVector().x;

var global = phetButton.parentToGlobalPoint( phetButton.center );
var local = ancestor.globalToLocalPoint( global );
var phetMenu = new PhetMenu( sim, {
showSaveAndLoad: sim.options.showSaveAndLoad,
scale: scale,
right: phetButton.globalToParentPoint( new Vector2( phetButton.globalBounds.maxX, 0 ) ).x,
bottom: local.y} );

var rectangle = new Plane( {fill: 'black', opacity: 0.3, renderer: 'svg'} );
var detach = function() {
rectangle.detach();
phetMenu.detach();
phetMenu.removeInputListener( popupMenuListener );
rectangle.removeInputListener( rectangleListener );
};
var popupMenuListener = new ButtonListener( {fire: detach} );
var rectangleListener = {down: detach};

phetMenu.addInputListener( popupMenuListener );
rectangle.addInputListener( rectangleListener );

ancestor.addChild( rectangle );
ancestor.addChild( phetMenu );
closeCallback: function() {
// hides the popup and barrier background
sim.hidePopup( phetMenu );
}
} );
function onResize( bounds, screenBounds, scale ) {
// because it starts at null
if ( bounds ) {
phetMenu.setScaleMagnitude( Math.max( 1, scale * 0.7 ) ); // minimum size for small devices
phetMenu.right = bounds.right - 10 * scale;
phetMenu.bottom = ( bounds.bottom + screenBounds.bottom ) / 2;
}
}
sim.on( 'resized', onResize );
onResize( sim.bounds, sim.screenBounds, sim.scale );

sim.showPopup( phetMenu );
};
this.addListener( phetButtonPressed );

Expand Down
14 changes: 8 additions & 6 deletions js/PhetMenu.js
Original file line number Diff line number Diff line change
Expand Up @@ -39,7 +39,7 @@ define( function( require ) {
var HIGHLIGHT_COLOR = '#a6d2f4';

// Creates a menu item that highlights and fires.
var createMenuItem = function( text, width, height, separatorBefore, callback, immediateCallback ) {
var createMenuItem = function( text, width, height, separatorBefore, closeCallback, callback, immediateCallback ) {

var X_MARGIN = 5;
var Y_MARGIN = 3;
Expand All @@ -60,7 +60,10 @@ define( function( require ) {
exit: function() { highlight.fill = null; },
upImmediate: function() { immediateCallback && immediateCallback(); }
} );
menuItem.addInputListener( new ButtonListener( {fire: callback } ) );
menuItem.addInputListener( new ButtonListener( {fire: function( event ) {
callback( event );
closeCallback( event );
} } ) );

menuItem.separatorBefore = separatorBefore;

Expand Down Expand Up @@ -109,12 +112,11 @@ define( function( require ) {

var showAboutDialog = function( aboutDialog ) {
var plane = new Plane( {fill: 'black', opacity: 0.3, renderer: 'svg'} );//Renderer must be specified here because the plane is added directly to the scene (instead of to some other node that already has svg renderer)
sim.addChild( plane );
sim.addChild( aboutDialog );
sim.showPopup( aboutDialog );
var aboutDialogListener = {up: function() {
aboutDialog.removeInputListener( aboutDialogListener );
plane.addInputListener( aboutDialogListener );
aboutDialog.detach();
sim.hidePopup( aboutDialog );
plane.detach();
}};
aboutDialog.addInputListener( aboutDialogListener );
Expand Down Expand Up @@ -238,7 +240,7 @@ define( function( require ) {

// Create the menu items.
var items = _.map( keepItemDescriptors, function( itemDescriptor ) {
return createMenuItem( itemDescriptor.text, maxTextWidth, maxTextHeight, itemDescriptor.separatorBefore, itemDescriptor.callback, itemDescriptor.immediateCallback );
return createMenuItem( itemDescriptor.text, maxTextWidth, maxTextHeight, itemDescriptor.separatorBefore, options.closeCallback, itemDescriptor.callback, itemDescriptor.immediateCallback );
} );
var separatorWidth = _.max( items, function( item ) {return item.width;} ).width;
var itemHeight = _.max( items, function( item ) {return item.height;} ).height;
Expand Down
85 changes: 74 additions & 11 deletions js/Sim.js
Original file line number Diff line number Diff line change
Expand Up @@ -10,19 +10,24 @@
define( function( require ) {
'use strict';

var inherit = require( 'PHET_CORE/inherit' );
var Util = require( 'SCENERY/util/Util' );
var NavigationBar = require( 'JOIST/NavigationBar' );
var HomeScreen = require( 'JOIST/HomeScreen' );
var Scene = require( 'SCENERY/Scene' );
var ButtonListener = require( 'SCENERY/input/ButtonListener' );
var Vector2 = require( 'DOT/Vector2' );
var Bounds2 = require( 'DOT/Bounds2' );
var version = require( 'version' );
var PropertySet = require( 'AXON/PropertySet' );
var Property = require( 'AXON/Property' );
var ObservableArray = require( 'AXON/ObservableArray' );
var platform = require( 'PHET_CORE/platform' );
var Timer = require( 'JOIST/Timer' );
var SimJSON = require( 'JOIST/SimJSON' );
var Path = require( 'SCENERY/nodes/Path' );
var Rectangle = require( 'SCENERY/nodes/Rectangle' );
var Node = require( 'SCENERY/nodes/Node' );
var Color = require( 'SCENERY/util/Color' );
var Shape = require( 'KITE/Shape' );
var Profiler = require( 'JOIST/Profiler' );
Expand All @@ -32,9 +37,18 @@ define( function( require ) {
* @param {Screen[]} screens
* @param {Object} [options]
* @constructor
*
* Events:
* - resized( bounds, screenBounds, scale ): Fires when the sim is resized.
*/
function Sim( name, screens, options ) {

PropertySet.call( this, {
scale: 1, // [read-only] how the home screen and navbar are scaled
bounds: null, // global bounds for the entire simulation
screenBounds: null // global bounds for the screen-specific part (excludes the navigation bar)
} );

assert && assert( window.phetJoistSimLauncher, 'Sim must be launched using SimLauncher, see https://github.com/phetsims/joist/issues/142' );

options = _.extend( {
Expand Down Expand Up @@ -236,7 +250,7 @@ define( function( require ) {
window.setInterval( function() { sleep( Math.ceil( 100 + Math.random() * 200 ) ); }, Math.ceil( 100 + Math.random() * 200 ) );
};

var whiteNavBar = new Color( screens[0].backgroundColor ).equals( Color.BLACK );
var whiteNavBar = !!new Color( screens[0].backgroundColor ).equals( Color.BLACK );
sim.navigationBar = new NavigationBar( sim, screens, sim.simModel, whiteNavBar );

// Multi-screen sims get a home screen.
Expand Down Expand Up @@ -360,15 +374,58 @@ define( function( require ) {
} );
}

// layer for popups, dialogs, and their backgrounds and barriers
this.topLayer = new Node( { renderer: 'svg' } );
sim.scene.addChild( this.topLayer );

// Semi-transparent black barrier used to block input events when a dialog (or other popup) is present, and fade
// out the background.
this.barrierStack = new ObservableArray();
this.barrierRectangle = new Rectangle( 0, 0, 1, 1, 0, 0, {
fill:'rgba(0,0,0,0.3)',
pickable: true
} );
this.topLayer.addChild( this.barrierRectangle );
this.barrierStack.lengthProperty.link( function( numBarriers ) {
sim.barrierRectangle.visible = numBarriers > 0;
} );
this.barrierRectangle.addInputListener( new ButtonListener( {
fire: function() {
assert && assert( sim.barrierStack.length > 0 );
sim.hidePopup( sim.barrierStack.get( sim.barrierStack.length - 1 ) );
}
} ) );

updateBackground();

//Fit to the window and render the initial scene
$( window ).resize( function() { sim.resizeToWindow(); } );
sim.resizeToWindow();
}

Sim.prototype = {
constructor: Sim,
return inherit( PropertySet, Sim, {
/*
* Adds a popup in the global coordinate frame, and displays a semi-transparent black input barrier behind it.
* Use hidePopup() to remove it.
* @param {Node} node
*/
showPopup: function( node ) {
assert && assert( node );

this.barrierStack.push( node );
this.topLayer.addChild( node );
},

/*
* Hides a popup that was previously displayed with showPopup()
* @param {Node} node
*/
hidePopup: function( node ) {
assert && assert( node && this.barrierStack.contains( node ) );

this.barrierStack.remove( node );
this.topLayer.removeChild( node );
},

resizeToWindow: function() {
this.resize( window.innerWidth, window.innerHeight );
Expand All @@ -380,14 +437,19 @@ define( function( require ) {
//Use Mobile Safari layout bounds to size the home screen and navigation bar
var scale = Math.min( width / 768, height / 504 );

this.barrierRectangle.rectWidth = width;
this.barrierRectangle.rectHeight = height;

//40 px high on Mobile Safari
var navBarHeight = scale * 40;
sim.navigationBar.layout( scale, width, navBarHeight, height );
sim.navigationBar.y = height - navBarHeight;
sim.scene.resize( width, height );

var screenHeight = height - sim.navigationBar.height;

//Layout each of the screens
_.each( sim.screens, function( m ) { m.view.layout( width, height - sim.navigationBar.height ); } );
_.each( sim.screens, function( m ) { m.view.layout( width, screenHeight ); } );

if ( sim.homeScreen ) {
sim.homeScreen.layoutWithScale( scale, width, height );
Expand All @@ -400,6 +462,13 @@ define( function( require ) {
if ( platform.mobileSafari ) {
window.scrollTo( 0, 0 );
}

// update our scale and bounds properties after other changes (so listeners can be fired after screens are resized)
this.scale = scale;
this.bounds = new Bounds2( 0, 0, width, height );
this.screenBounds = new Bounds2( 0, 0, width, screenHeight );

this.trigger( 'resized', this.bounds, this.screenBounds, this.scale );
},

start: function() {
Expand Down Expand Up @@ -582,10 +651,6 @@ define( function( require ) {
})();
},

addChild: function( node ) {
this.scene.addChild( node );
},

// A string that should be evaluated as JavaScript containing an array of "frame" objects, with a dt and an optional fireEvents function
getRecordedInputEventLogString: function() {
return '[\n' + _.map( this.inputEventLog, function( item ) {
Expand Down Expand Up @@ -710,7 +775,5 @@ define( function( require ) {
}
this.simModel.set( state.simModel );
}
};

return Sim;
} );
} );

0 comments on commit fa5a352

Please sign in to comment.