import PropTypes from 'prop-types'; import React from 'react'; import bindAll from 'lodash.bindall'; import {FormattedMessage} from 'react-intl'; import VM from 'scratch-vm'; import AssetPanel from '../components/asset-panel/asset-panel.jsx'; import addCostumeIcon from '../components/asset-panel/icon--add-costume-lib.svg'; import PaintEditor from 'scratch-paint'; import {connect} from 'react-redux'; import { openCostumeLibrary, openBackdropLibrary } from '../reducers/modals'; class CostumeTab extends React.Component { constructor (props) { super(props); bindAll(this, [ 'handleSelectCostume', 'handleDeleteCostume', 'handleUpdateSvg' ]); this.state = {selectedCostumeIndex: 0}; } componentWillReceiveProps (nextProps) { const { editingTarget, sprites, stage } = nextProps; const target = editingTarget && sprites[editingTarget] ? sprites[editingTarget] : stage; if (target && target.costumes && this.state.selectedCostumeIndex > target.costumes.length - 1) { this.setState({selectedCostumeIndex: target.costumes.length - 1}); } } shouldComponentUpdate (nextProps) { const { editingTarget, sprites, stage } = nextProps; const nextTarget = editingTarget && sprites[editingTarget] ? sprites[editingTarget] : stage; const currentTarget = this.props.editingTarget && this.props.sprites[this.props.editingTarget] ? this.props.sprites[this.props.editingTarget] : this.props.stage; if (this.props.editingTarget !== editingTarget || currentTarget.currentCostume !== nextTarget.currentCostume) { return true; } return false; } handleSelectCostume (costumeIndex) { this.props.vm.editingTarget.setCostume(costumeIndex); this.setState({selectedCostumeIndex: costumeIndex}); } handleDeleteCostume (costumeIndex) { this.props.vm.deleteCostume(costumeIndex); } handleUpdateSvg (svg, rotationCenterX, rotationCenterY) { this.props.vm.updateSvg(this.state.selectedCostumeIndex, svg, rotationCenterX, rotationCenterY); } render () { const { editingTarget, sprites, stage, onNewCostumeClick, onNewBackdropClick } = this.props; const target = editingTarget && sprites[editingTarget] ? sprites[editingTarget] : stage; if (!target) { return null; } const addBackdropMsg = ( <FormattedMessage defaultMessage="Add Backdrop" description="Button to add a backdrop in the editor tab" id="gui.costumeTab.addBackdrop" /> ); const addCostumeMsg = ( <FormattedMessage defaultMessage="Add Costume" description="Button to add a costume in the editor tab" id="gui.costumeTab.addCostume" /> ); const addMessage = target.isStage ? addBackdropMsg : addCostumeMsg; const addFunc = target.isStage ? onNewBackdropClick : onNewCostumeClick; return ( <AssetPanel buttons={[{ message: addMessage, img: addCostumeIcon, onClick: addFunc }]} items={target.costumes || []} selectedItemIndex={this.state.selectedCostumeIndex} onDeleteClick={this.handleDeleteCostume} onItemClick={this.handleSelectCostume} > {target.costumes ? <PaintEditor rotationCenterX={target.costumes[this.state.selectedCostumeIndex].rotationCenterX} rotationCenterY={target.costumes[this.state.selectedCostumeIndex].rotationCenterY} svg={this.props.vm.getCostumeSvg(this.state.selectedCostumeIndex)} onUpdateSvg={this.handleUpdateSvg} /> : null } </AssetPanel> ); } } CostumeTab.propTypes = { editingTarget: PropTypes.string, onNewBackdropClick: PropTypes.func.isRequired, onNewCostumeClick: PropTypes.func.isRequired, sprites: PropTypes.shape({ id: PropTypes.shape({ costumes: PropTypes.arrayOf(PropTypes.shape({ url: PropTypes.string, name: PropTypes.string.isRequired })) }) }), stage: PropTypes.shape({ sounds: PropTypes.arrayOf(PropTypes.shape({ name: PropTypes.string.isRequired })) }), vm: PropTypes.instanceOf(VM) }; const mapStateToProps = state => ({ editingTarget: state.targets.editingTarget, sprites: state.targets.sprites, stage: state.targets.stage, costumeLibraryVisible: state.modals.costumeLibrary, backdropLibraryVisible: state.modals.backdropLibrary }); const mapDispatchToProps = dispatch => ({ onNewBackdropClick: e => { e.preventDefault(); dispatch(openBackdropLibrary()); }, onNewCostumeClick: e => { e.preventDefault(); dispatch(openCostumeLibrary()); } }); export default connect( mapStateToProps, mapDispatchToProps )(CostumeTab);