diff --git a/src/components/asset-panel/selector.jsx b/src/components/asset-panel/selector.jsx index 88d609723afc6765576eeb4433786778fffee51d..2462986d876615fc3298c460eff7def1e4a7979d 100644 --- a/src/components/asset-panel/selector.jsx +++ b/src/components/asset-panel/selector.jsx @@ -24,6 +24,7 @@ const Selector = props => { onRemoveSortable, onDeleteClick, onDuplicateClick, + onExportClick, onItemClick } = props; @@ -76,6 +77,7 @@ const Selector = props => { onClick={onItemClick} onDeleteButtonClick={onDeleteClick} onDuplicateButtonClick={onDuplicateClick} + onExportButtonClick={onExportClick} /> </SortableAsset> ))} @@ -102,6 +104,7 @@ Selector.propTypes = { onAddSortable: PropTypes.func, onDeleteClick: PropTypes.func, onDuplicateClick: PropTypes.func, + onExportClick: PropTypes.func, onItemClick: PropTypes.func.isRequired, onRemoveSortable: PropTypes.func, ordering: PropTypes.arrayOf(PropTypes.number), diff --git a/src/components/sprite-selector-item/sprite-selector-item.jsx b/src/components/sprite-selector-item/sprite-selector-item.jsx index 62364ec53cab6605f552eeb06112ceb3fa58bb1d..cb04c034ad6165d6fdb8b4e0346bf39d3ad6bcc6 100644 --- a/src/components/sprite-selector-item/sprite-selector-item.jsx +++ b/src/components/sprite-selector-item/sprite-selector-item.jsx @@ -51,7 +51,7 @@ const SpriteSelectorItem = props => ( <div className={styles.spriteDetails}>{props.details}</div> ) : null} </div> - {props.onDuplicateButtonClick || props.onDeleteButtonClick ? ( + {props.onDuplicateButtonClick || props.onDeleteButtonClick || props.onExportButtonClick ? ( <ContextMenu id={`${props.name}-${contextMenuId++}`}> {props.onDuplicateButtonClick ? ( <MenuItem onClick={props.onDuplicateButtonClick}> @@ -71,6 +71,15 @@ const SpriteSelectorItem = props => ( /> </MenuItem> ) : null } + {props.onExportButtonClick ? ( + <MenuItem onClick={props.onExportButtonClick}> + <FormattedMessage + defaultMessage="export" + description="Menu item to export the selected item" + id="gui.spriteSelectorItem.contextMenuExport" + /> + </MenuItem> + ) : null } </ContextMenu> ) : null} </ContextMenuTrigger> @@ -86,6 +95,7 @@ SpriteSelectorItem.propTypes = { onClick: PropTypes.func, onDeleteButtonClick: PropTypes.func, onDuplicateButtonClick: PropTypes.func, + onExportButtonClick: PropTypes.func, onMouseDown: PropTypes.func, onMouseEnter: PropTypes.func, onMouseLeave: PropTypes.func, diff --git a/src/components/sprite-selector/sprite-list.jsx b/src/components/sprite-selector/sprite-list.jsx index 6195b0c9c8cb706589f73268d4e300432cfc0d98..e22b5c8e0d1bd44a4a9e7763a92b15311ee5a7af 100644 --- a/src/components/sprite-selector/sprite-list.jsx +++ b/src/components/sprite-selector/sprite-list.jsx @@ -20,6 +20,7 @@ const SpriteList = function (props) { hoveredTarget, onDeleteSprite, onDuplicateSprite, + onExportSprite, onSelectSprite, onAddSortable, onRemoveSortable, @@ -79,6 +80,7 @@ const SpriteList = function (props) { onClick={onSelectSprite} onDeleteButtonClick={onDeleteSprite} onDuplicateButtonClick={onDuplicateSprite} + onExportButtonClick={onExportSprite} /> </SortableAsset> ); @@ -110,6 +112,7 @@ SpriteList.propTypes = { onAddSortable: PropTypes.func, onDeleteSprite: PropTypes.func, onDuplicateSprite: PropTypes.func, + onExportSprite: PropTypes.func, onRemoveSortable: PropTypes.func, onSelectSprite: PropTypes.func, ordering: PropTypes.arrayOf(PropTypes.number), diff --git a/src/components/sprite-selector/sprite-selector.jsx b/src/components/sprite-selector/sprite-selector.jsx index 9907dffce3a78d58c056ce74ab33a0c59e2b4c10..689a023edf374860c308eff726288ed2f4f5d293 100644 --- a/src/components/sprite-selector/sprite-selector.jsx +++ b/src/components/sprite-selector/sprite-selector.jsx @@ -53,6 +53,7 @@ const SpriteSelectorComponent = function (props) { onDrop, onDeleteSprite, onDuplicateSprite, + onExportSprite, onFileUploadClick, onNewSpriteClick, onPaintSpriteClick, @@ -105,6 +106,7 @@ const SpriteSelectorComponent = function (props) { onDeleteSprite={onDeleteSprite} onDrop={onDrop} onDuplicateSprite={onDuplicateSprite} + onExportSprite={onExportSprite} onSelectSprite={onSelectSprite} /> </Box> @@ -116,7 +118,7 @@ const SpriteSelectorComponent = function (props) { title: intl.formatMessage(messages.addSpriteFromFile), img: fileUploadIcon, onClick: onFileUploadClick, - fileAccept: '.svg, .png, .jpg, .jpeg, .sprite2', // TODO add sprite 3 + fileAccept: '.svg, .png, .jpg, .jpeg, .sprite2, .sprite3', fileChange: onSpriteUpload, fileInput: spriteFileInput }, { @@ -152,6 +154,7 @@ SpriteSelectorComponent.propTypes = { onDeleteSprite: PropTypes.func, onDrop: PropTypes.func, onDuplicateSprite: PropTypes.func, + onExportSprite: PropTypes.func, onFileUploadClick: PropTypes.func, onNewSpriteClick: PropTypes.func, onPaintSpriteClick: PropTypes.func, diff --git a/src/components/target-pane/target-pane.jsx b/src/components/target-pane/target-pane.jsx index 57b10e0c99e72d4df2e28a364f82c25c66547b66..c620c8504c13a1dbd2034a9a2d3a72f80e3d8b85 100644 --- a/src/components/target-pane/target-pane.jsx +++ b/src/components/target-pane/target-pane.jsx @@ -30,6 +30,7 @@ const TargetPane = ({ onDeleteSprite, onDrop, onDuplicateSprite, + onExportSprite, onFileUploadClick, onNewSpriteClick, onPaintSpriteClick, @@ -66,6 +67,7 @@ const TargetPane = ({ onDeleteSprite={onDeleteSprite} onDrop={onDrop} onDuplicateSprite={onDuplicateSprite} + onExportSprite={onExportSprite} onFileUploadClick={onFileUploadClick} onNewSpriteClick={onNewSpriteClick} onPaintSpriteClick={onPaintSpriteClick} @@ -133,6 +135,7 @@ TargetPane.propTypes = { onDeleteSprite: PropTypes.func, onDrop: PropTypes.func, onDuplicateSprite: PropTypes.func, + onExportSprite: PropTypes.func, onFileUploadClick: PropTypes.func, onNewSpriteClick: PropTypes.func, onPaintSpriteClick: PropTypes.func, diff --git a/src/containers/sprite-selector-item.jsx b/src/containers/sprite-selector-item.jsx index 4c968f82731222227f9c5cbf6cdb2b15beed4287..785f9d08f49359bc6a6c60f89262b5a177d58f36 100644 --- a/src/containers/sprite-selector-item.jsx +++ b/src/containers/sprite-selector-item.jsx @@ -18,6 +18,7 @@ class SpriteSelectorItem extends React.Component { 'handleClick', 'handleDelete', 'handleDuplicate', + 'handleExport', 'handleMouseEnter', 'handleMouseLeave', 'handleMouseDown', @@ -84,6 +85,10 @@ class SpriteSelectorItem extends React.Component { e.stopPropagation(); // To prevent from bubbling back to handleClick this.props.onDuplicateButtonClick(this.props.id); } + handleExport (e) { + e.stopPropagation(); + this.props.onExportButtonClick(this.props.id); + } handleMouseLeave () { this.props.dispatchSetHoveredSprite(null); } @@ -99,6 +104,7 @@ class SpriteSelectorItem extends React.Component { onClick, onDeleteButtonClick, onDuplicateButtonClick, + onExportButtonClick, dragPayload, receivedBlocks, /* eslint-enable no-unused-vars */ @@ -109,6 +115,7 @@ class SpriteSelectorItem extends React.Component { onClick={this.handleClick} onDeleteButtonClick={onDeleteButtonClick ? this.handleDelete : null} onDuplicateButtonClick={onDuplicateButtonClick ? this.handleDuplicate : null} + onExportButtonClick={onExportButtonClick ? this.handleExport : null} onMouseDown={this.handleMouseDown} onMouseEnter={this.handleMouseEnter} onMouseLeave={this.handleMouseLeave} @@ -134,6 +141,7 @@ SpriteSelectorItem.propTypes = { onDeleteButtonClick: PropTypes.func, onDrag: PropTypes.func.isRequired, onDuplicateButtonClick: PropTypes.func, + onExportButtonClick: PropTypes.func, receivedBlocks: PropTypes.bool.isRequired, selected: PropTypes.bool }; diff --git a/src/containers/target-pane.jsx b/src/containers/target-pane.jsx index e3c7688ddc3e4257d45ae661254b5a50521440ee..1d637330acce4a4410f1f6ecd840089c86febfc6 100644 --- a/src/containers/target-pane.jsx +++ b/src/containers/target-pane.jsx @@ -29,6 +29,7 @@ class TargetPane extends React.Component { 'handleDeleteSprite', 'handleDrop', 'handleDuplicateSprite', + 'handleExportSprite', 'handleNewSprite', 'handleSelectSprite', 'handleSurpriseSpriteClick', @@ -68,6 +69,28 @@ class TargetPane extends React.Component { handleDuplicateSprite (id) { this.props.vm.duplicateSprite(id); } + handleExportSprite (id) { + const spriteName = this.props.vm.runtime.getTargetById(id).getName(); + const saveLink = document.createElement('a'); + document.body.appendChild(saveLink); + + this.props.vm.exportSprite(id).then(content => { + const filename = `${spriteName}.sprite3`; + + // Use special ms version if available to get it working on Edge. + if (navigator.msSaveOrOpenBlob) { + navigator.msSaveOrOpenBlob(content, filename); + return; + } + + const url = window.URL.createObjectURL(content); + saveLink.href = url; + saveLink.download = filename; + saveLink.click(); + window.URL.revokeObjectURL(url); + document.body.removeChild(saveLink); + }); + } handleSelectSprite (id) { this.props.vm.setEditingTarget(id); } @@ -145,6 +168,7 @@ class TargetPane extends React.Component { onDeleteSprite={this.handleDeleteSprite} onDrop={this.handleDrop} onDuplicateSprite={this.handleDuplicateSprite} + onExportSprite={this.handleExportSprite} onFileUploadClick={this.handleFileUploadClick} onPaintSpriteClick={this.handlePaintSpriteClick} onSelectSprite={this.handleSelectSprite}