Skip to content
Snippets Groups Projects
Unverified Commit 979c8cb0 authored by Ray Schamp's avatar Ray Schamp Committed by GitHub
Browse files

Merge pull request #2464 from rschamp/save-canvas

Hack to make the renderer own the stage canvas
parents 93e769d9 0bd75524
No related branches found
No related tags found
No related merge requests found
...@@ -72,6 +72,7 @@ const GUIComponent = props => { ...@@ -72,6 +72,7 @@ const GUIComponent = props => {
onActivateTab, onActivateTab,
onRequestCloseBackdropLibrary, onRequestCloseBackdropLibrary,
onRequestCloseCostumeLibrary, onRequestCloseCostumeLibrary,
onSeeCommunity,
previewInfoVisible, previewInfoVisible,
targetIsStage, targetIsStage,
soundsTabVisible, soundsTabVisible,
...@@ -141,7 +142,10 @@ const GUIComponent = props => { ...@@ -141,7 +142,10 @@ const GUIComponent = props => {
onRequestClose={onRequestCloseBackdropLibrary} onRequestClose={onRequestCloseBackdropLibrary}
/> />
) : null} ) : null}
<MenuBar enableCommunity={enableCommunity} /> <MenuBar
enableCommunity={enableCommunity}
onSeeCommunity={onSeeCommunity}
/>
<Box className={styles.bodyWrapper}> <Box className={styles.bodyWrapper}>
<Box className={styles.flexWrapper}> <Box className={styles.flexWrapper}>
<Box className={styles.editorWrapper}> <Box className={styles.editorWrapper}>
...@@ -285,6 +289,7 @@ GUIComponent.propTypes = { ...@@ -285,6 +289,7 @@ GUIComponent.propTypes = {
onExtensionButtonClick: PropTypes.func, onExtensionButtonClick: PropTypes.func,
onRequestCloseBackdropLibrary: PropTypes.func, onRequestCloseBackdropLibrary: PropTypes.func,
onRequestCloseCostumeLibrary: PropTypes.func, onRequestCloseCostumeLibrary: PropTypes.func,
onSeeCommunity: PropTypes.func,
onTabSelect: PropTypes.func, onTabSelect: PropTypes.func,
previewInfoVisible: PropTypes.bool, previewInfoVisible: PropTypes.bool,
soundsTabVisible: PropTypes.bool, soundsTabVisible: PropTypes.bool,
......
...@@ -3,6 +3,7 @@ import React from 'react'; ...@@ -3,6 +3,7 @@ import React from 'react';
import classNames from 'classnames'; import classNames from 'classnames';
import Box from '../box/box.jsx'; import Box from '../box/box.jsx';
import DOMElementRenderer from '../../containers/dom-element-renderer.jsx';
import Loupe from '../loupe/loupe.jsx'; import Loupe from '../loupe/loupe.jsx';
import MonitorList from '../../containers/monitor-list.jsx'; import MonitorList from '../../containers/monitor-list.jsx';
import Question from '../../containers/question.jsx'; import Question from '../../containers/question.jsx';
...@@ -12,7 +13,7 @@ import styles from './stage.css'; ...@@ -12,7 +13,7 @@ import styles from './stage.css';
const StageComponent = props => { const StageComponent = props => {
const { const {
canvasRef, canvas,
dragRef, dragRef,
isColorPicking, isColorPicking,
isFullScreen, isFullScreen,
...@@ -21,6 +22,7 @@ const StageComponent = props => { ...@@ -21,6 +22,7 @@ const StageComponent = props => {
stageSize, stageSize,
useEditorDragStyle, useEditorDragStyle,
onDeactivateColorPicker, onDeactivateColorPicker,
onDoubleClick,
onQuestionAnswered, onQuestionAnswered,
...boxProps ...boxProps
} = props; } = props;
...@@ -35,14 +37,14 @@ const StageComponent = props => { ...@@ -35,14 +37,14 @@ const StageComponent = props => {
[styles.stageWrapperOverlay]: isFullScreen, [styles.stageWrapperOverlay]: isFullScreen,
[styles.withColorPicker]: !isFullScreen && isColorPicking [styles.withColorPicker]: !isFullScreen && isColorPicking
})} })}
onDoubleClick={onDoubleClick}
> >
<Box <DOMElementRenderer
className={classNames( className={classNames(
styles.stage, styles.stage,
{[styles.stageOverlayContent]: isFullScreen} {[styles.stageOverlayContent]: isFullScreen}
)} )}
componentRef={canvasRef} domElement={canvas}
element="canvas"
height={stageDimensions.height} height={stageDimensions.height}
width={stageDimensions.width} width={stageDimensions.width}
{...boxProps} {...boxProps}
...@@ -93,19 +95,19 @@ const StageComponent = props => { ...@@ -93,19 +95,19 @@ const StageComponent = props => {
); );
}; };
StageComponent.propTypes = { StageComponent.propTypes = {
canvasRef: PropTypes.func, canvas: PropTypes.instanceOf(Element).isRequired,
colorInfo: Loupe.propTypes.colorInfo, colorInfo: Loupe.propTypes.colorInfo,
dragRef: PropTypes.func, dragRef: PropTypes.func,
isColorPicking: PropTypes.bool, isColorPicking: PropTypes.bool,
isFullScreen: PropTypes.bool.isRequired, isFullScreen: PropTypes.bool.isRequired,
onDeactivateColorPicker: PropTypes.func, onDeactivateColorPicker: PropTypes.func,
onDoubleClick: PropTypes.func,
onQuestionAnswered: PropTypes.func, onQuestionAnswered: PropTypes.func,
question: PropTypes.string, question: PropTypes.string,
stageSize: PropTypes.oneOf(Object.keys(STAGE_DISPLAY_SIZES)).isRequired, stageSize: PropTypes.oneOf(Object.keys(STAGE_DISPLAY_SIZES)).isRequired,
useEditorDragStyle: PropTypes.bool useEditorDragStyle: PropTypes.bool
}; };
StageComponent.defaultProps = { StageComponent.defaultProps = {
canvasRef: () => {},
dragRef: () => {} dragRef: () => {}
}; };
export default StageComponent; export default StageComponent;
import omit from 'lodash.omit';
import PropTypes from 'prop-types';
import React from 'react';
/*
* DOMElementRenderer wraps a DOM element, allowing it to be
* rendered by React. It's up to the containing component
* to retain a reference to the element prop, or else it
* will be garbage collected after unmounting.
*
* Props passed to the DOMElementRenderer will be set on the
* DOM element like it's a normal component.
*/
class DOMElementRenderer extends React.Component {
constructor (props) {
super(props);
this.setContainer = this.setContainer.bind(this);
}
componentDidMount () {
this.container.appendChild(this.props.domElement);
}
componentWillUnmount () {
this.container.removeChild(this.props.domElement);
}
setContainer (c) {
this.container = c;
}
render () {
// Apply props to the DOM element, so its attributes
// are updated as if it were a normal component.
// Look at me, I'm the React now!
Object.assign(
this.props.domElement,
omit(this.props, ['domElement', 'children'])
);
return <div ref={this.setContainer} />;
}
}
DOMElementRenderer.propTypes = {
domElement: PropTypes.instanceOf(Element).isRequired
};
export default DOMElementRenderer;
...@@ -66,9 +66,6 @@ class GUI extends React.Component { ...@@ -66,9 +66,6 @@ class GUI extends React.Component {
}); });
} }
} }
componentWillUnmount () {
this.props.vm.stopAll();
}
render () { render () {
if (this.state.loadingError) { if (this.state.loadingError) {
throw new Error( throw new Error(
...@@ -99,6 +96,7 @@ GUI.propTypes = { ...@@ -99,6 +96,7 @@ GUI.propTypes = {
fetchingProject: PropTypes.bool, fetchingProject: PropTypes.bool,
importInfoVisible: PropTypes.bool, importInfoVisible: PropTypes.bool,
loadingStateVisible: PropTypes.bool, loadingStateVisible: PropTypes.bool,
onSeeCommunity: PropTypes.func,
previewInfoVisible: PropTypes.bool, previewInfoVisible: PropTypes.bool,
projectData: PropTypes.oneOfType([PropTypes.object, PropTypes.string]), projectData: PropTypes.oneOfType([PropTypes.object, PropTypes.string]),
vm: PropTypes.instanceOf(VM) vm: PropTypes.instanceOf(VM)
......
...@@ -37,7 +37,6 @@ class Stage extends React.Component { ...@@ -37,7 +37,6 @@ class Stage extends React.Component {
'onWheel', 'onWheel',
'updateRect', 'updateRect',
'questionListener', 'questionListener',
'setCanvas',
'setDragCanvas', 'setDragCanvas',
'clearDragCanvas', 'clearDragCanvas',
'drawDragCanvas', 'drawDragCanvas',
...@@ -52,16 +51,22 @@ class Stage extends React.Component { ...@@ -52,16 +51,22 @@ class Stage extends React.Component {
colorInfo: null, colorInfo: null,
question: null question: null
}; };
if (this.props.vm.runtime.renderer) {
this.renderer = this.props.vm.runtime.renderer;
this.canvas = this.props.vm.runtime.renderer._gl.canvas;
} else {
this.canvas = document.createElement('canvas');
this.renderer = new Renderer(this.canvas);
this.props.vm.attachRenderer(this.renderer);
}
this.props.vm.attachV2SVGAdapter(new V2SVGAdapter());
this.props.vm.setVideoProvider(new VideoProvider());
} }
componentDidMount () { componentDidMount () {
this.attachRectEvents(); this.attachRectEvents();
this.attachMouseEvents(this.canvas); this.attachMouseEvents(this.canvas);
this.updateRect(); this.updateRect();
this.renderer = new Renderer(this.canvas);
this.props.vm.attachRenderer(this.renderer);
this.props.vm.attachV2SVGAdapter(new V2SVGAdapter());
this.props.vm.runtime.addListener('QUESTION', this.questionListener); this.props.vm.runtime.addListener('QUESTION', this.questionListener);
this.props.vm.setVideoProvider(new VideoProvider());
} }
shouldComponentUpdate (nextProps, nextState) { shouldComponentUpdate (nextProps, nextState) {
return this.props.stageSize !== nextProps.stageSize || return this.props.stageSize !== nextProps.stageSize ||
...@@ -353,9 +358,6 @@ class Stage extends React.Component { ...@@ -353,9 +358,6 @@ class Stage extends React.Component {
commonStopDragActions(); commonStopDragActions();
} }
} }
setCanvas (canvas) {
this.canvas = canvas;
}
setDragCanvas (canvas) { setDragCanvas (canvas) {
this.dragCanvas = canvas; this.dragCanvas = canvas;
} }
...@@ -367,7 +369,7 @@ class Stage extends React.Component { ...@@ -367,7 +369,7 @@ class Stage extends React.Component {
} = this.props; } = this.props;
return ( return (
<StageComponent <StageComponent
canvasRef={this.setCanvas} canvas={this.canvas}
colorInfo={this.state.colorInfo} colorInfo={this.state.colorInfo}
dragRef={this.setDragCanvas} dragRef={this.setDragCanvas}
question={this.state.question} question={this.state.question}
......
import classNames from 'classnames';
import PropTypes from 'prop-types';
import React from 'react'; import React from 'react';
import ReactDOM from 'react-dom'; import ReactDOM from 'react-dom';
import {connect} from 'react-redux';
import Box from '../components/box/box.jsx'; import Box from '../components/box/box.jsx';
import GUI from '../containers/gui.jsx'; import GUI from '../containers/gui.jsx';
import HashParserHOC from '../lib/hash-parser-hoc.jsx'; import HashParserHOC from '../lib/hash-parser-hoc.jsx';
import AppStateHOC from '../lib/app-state-hoc.jsx'; import AppStateHOC from '../lib/app-state-hoc.jsx';
const WrappedGui = HashParserHOC(AppStateHOC(GUI));
import {setPlayer} from '../reducers/mode';
if (process.env.NODE_ENV === 'production' && typeof window === 'object') { if (process.env.NODE_ENV === 'production' && typeof window === 'object') {
// Warn before navigating away // Warn before navigating away
...@@ -13,16 +17,38 @@ if (process.env.NODE_ENV === 'production' && typeof window === 'object') { ...@@ -13,16 +17,38 @@ if (process.env.NODE_ENV === 'production' && typeof window === 'object') {
} }
import styles from './player.css'; import styles from './player.css';
const Player = () => (
<Box className={styles.stageOnly}> const Player = ({isPlayerOnly, onSeeInside}) => (
<WrappedGui <Box
isPlayerOnly className={classNames({
isFullScreen={false} [styles.stageOnly]: isPlayerOnly
})}
>
{isPlayerOnly && <button onClick={onSeeInside}>{'See inside'}</button>}
<GUI
enableCommunity
isPlayerOnly={isPlayerOnly}
/> />
</Box> </Box>
); );
Player.propTypes = {
isPlayerOnly: PropTypes.bool,
onSeeInside: PropTypes.func
};
const mapStateToProps = state => ({
isPlayerOnly: state.scratchGui.mode.isPlayerOnly
});
const mapDispatchToProps = dispatch => ({
onSeeInside: () => dispatch(setPlayer(false))
});
const ConnectedPlayer = connect(mapStateToProps, mapDispatchToProps)(Player);
const WrappedPlayer = HashParserHOC(AppStateHOC(ConnectedPlayer));
const appTarget = document.createElement('div'); const appTarget = document.createElement('div');
document.body.appendChild(appTarget); document.body.appendChild(appTarget);
ReactDOM.render(<Player />, appTarget); ReactDOM.render(<WrappedPlayer isPlayerOnly />, appTarget);
0% Loading or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment