From 0e56c4db6ef5ab47f7940c6d38e30f987312ae1d Mon Sep 17 00:00:00 2001
From: Matthew Taylor <mewtaylor@gmail.com>
Date: Wed, 3 Jan 2018 15:26:55 -0500
Subject: [PATCH] Implement paint-75: Add blank costume button (#1137)

* Implement paint-75: Add blank costume button

* add backdrop icon, use default name

thanks @fsih !
---
 .../asset-panel/icon--add-backdrop-lib.svg    | Bin 0 -> 2300 bytes
 .../asset-panel/icon--add-blank-costume.svg   | Bin 0 -> 1787 bytes
 src/components/asset-panel/selector.css       |   1 +
 src/containers/costume-tab.jsx                | 112 ++++++++++++------
 4 files changed, 78 insertions(+), 35 deletions(-)
 create mode 100644 src/components/asset-panel/icon--add-backdrop-lib.svg
 create mode 100644 src/components/asset-panel/icon--add-blank-costume.svg

diff --git a/src/components/asset-panel/icon--add-backdrop-lib.svg b/src/components/asset-panel/icon--add-backdrop-lib.svg
new file mode 100644
index 0000000000000000000000000000000000000000..8c80f17aa6298fce7de769ca9dfcff12b444116f
GIT binary patch
literal 2300
zcmcImO>f&U488YPXzFDJY}t~(3p>S@p}S<*fNq!FTw9I3xOQNxNw!}<QnphkOWN%)
z0ZmAWdL$nyrt!`0u_7DUc4bp1lrx(WS!YdN*2{!``+94JlyoYs^R#Menb5kSH?xbl
z+bqep%vF(45v_NW6tY|v3N#P3O)0nUn_WU}ViOS&;lbXs6HW=Zt-FL4O0BOgYrEaD
zt;3pjX$jl5Er1_Pu6I>guTB~AD2gn7N@o`YR{X{^$wyhsHdRe~P3~4wWd(5^CdgYS
zvi<0am}KJdzA5BmnGWf)ta-G${*Gx5kg8OboTYhg-Y;XT*Lr8U?6TRsm8p_BP@#&!
zAB!!0G+I4$J(P|xE8DD+q|6h#PE}z75gD)~@cU;%fu$BdXR*~=4p9K&2oo>$?Jwz4
z;_Xhg%}ST0mZN44g@NOTvZ}CVc!;vuK2=~XH?nT>e18EbmRY(^Xxlv1huc4z68fUw
zpCr;p@j-Sg)vQg^<RY|pfq?E&ZCZB^P5YQoEmlC#TR0akgUZ4(i0S*`pj-{LLw0Zt
z>D?*J?;Wsv29QIW?D1TGl#k&iknhuMmA4S=3#cQEflbp#dkS%adOxD7vXV!+pxL;F
zy!u8um(#O*?gy{<p8%g^oO^qEM%Z(yj8OO;V_Onv&rduugdhunpL3gO%{Bx`fx|u5
zCAPsM7Vr>C5t4;%1WbfH3?d$Zz2P%k_@V3hU<j8zBH(WUpdOh62*({hwE}H|umE)e
zKL>T<S_42_eT?6!eiC;@y57HmgkHMyD7d}d_xL!i@Nr?1&&@o|e=0w7fx!d}<M&x;
zaECc$4x%u)U;zQDwd51-G7pb|w}?4-2Mj~p3s^(~=AsZ14HA%rk2XGY$=qXs0Wdz%
z03Nt<(2>tLG7Cfiq9&gsw}QjI4F(`YgpUHS3xIkLDIP>L?r-!Ga1T|*%|4|uw|``D
z7%d~qe@|*ZIX-XF>R=?njQS<p=7lG8P@1Ps9z}3+zUiNb>!Otp&=AAKg;3%4>*Ys(
z@i4H*F?)Hd*Pl&wVvPI8V|<#xu^d~=*CRS;NC&HE1gCrdT$q1fru`fc&iHWugR2+Q
VK6`lb;E&CNjlH6U82`bT{RWM8FEaoD

literal 0
HcmV?d00001

diff --git a/src/components/asset-panel/icon--add-blank-costume.svg b/src/components/asset-panel/icon--add-blank-costume.svg
new file mode 100644
index 0000000000000000000000000000000000000000..20843fe6161859f318031dc0bf1c7f0f9f54c24b
GIT binary patch
literal 1787
zcma)7O>f&q6ujqGY}reKlB<2YZ@&yl0V=?~I6#0jm)sbMmRQTAK+=|ferHL^vK<30
zA;`<&?##S-PxSor)BRpNR$X7W%_1YIGEp__c2hUoMfUyg>mp>LAIfG^?%SqXWKElW
zUVfPOk6Ur9H^Xj`>2P?;#ICBhyWxEISXakC+owgQgc3U7lf4w7OhC5j7ujwY4p+0;
z@pzO+Bin8}(@Los=uca&p7wQf_ufW|G0w)P+46(HHUF(B#9viYb>+}@SK`}UHLQ1n
zjnv|!iOR)Kq7W|>f3~~ozAjJY%5{4`>!&kCaiSdRVP7rF%|`Txt{$rSY(gf%P1UcL
ztF9`CYJ)h2-APl<XXB&uuG@Z@5d4{tt*AGP>}$EL3PjNlU3)i1+f?Vf;uJ0(-`4wm
z$~`?y>!N$uV|VpfHSK2ed;l?3>+-P3y7r-Y4gb^D=<S404#v197pSe6YCBUcvfp_X
z{q^-J*R(lZ^Q{=VvgvQz?tYPt%RMUpXeC;PD;Msx`jm|Y{&8kJSEJuBPOKM8qs-}R
zekhSAV)~*bQ*h4Nm@9Gf;*Mo7-WWrE()+e64^@V!)6xH8y&TRjl;TFcxcgtM^V#;b
z)UUvECFG?gueEkLmYSHY@nS_z5_=T_<rJj#C`cJWR+90SEaw!Z_KKCWf>;`6?W0eq
zHNko|pkPTVMq)4r8MI-iv>+or866!q2T6{ik0GHTW$hs6rBmKJ$Dq)V_Evl7d8w?i
z7A8nWQXGQG;nIPWlQohQqH!D($`H0HF_2{M1F_Cw-f3er3~TIFQAL}>q|=(5<>bK{
zqX<34QU|znZcG9M$`h<9so1iyUT8Q&J{I|4!XmR#0F89)JnG9m6d0x1AXb{CXUBm#
z4+za#9oPx2q=z)PlU$6B5vF**9Y4eu6oT>*sLdfm&MRVY!%~a^fw=^`K+2{#l{Cs3
z_6dyaFp?~ybi^t+6Gjx?&`NRh29Ay>x&$+m(xlC}`vk8rqDlv}gmaXY+Lv5wnIb~j
zXlb;ToEDe~KOUckLTTekixpbqkd;FF5r9V1QHSu-z?xMS4T(q&<2Iq}B4!1=KrLe;
zL4k2ph&l2ohk88>jU^*m{~El6_L2ep$8m6s9-IX)2ri(O%4-|lI92bY{$u(T{(R{A
gT~V*w=Iu*GNqc@tKEJo#z5<?qljCBZ{=Y2$1y9zkf&c&j

literal 0
HcmV?d00001

diff --git a/src/components/asset-panel/selector.css b/src/components/asset-panel/selector.css
index 63e686832..546a7863d 100644
--- a/src/components/asset-panel/selector.css
+++ b/src/components/asset-panel/selector.css
@@ -17,6 +17,7 @@
     justify-content: space-around;
     margin: 1.25rem 0;
     color: $motion-primary;
+    text-align: center;
 }
 
 .new-button {
diff --git a/src/containers/costume-tab.jsx b/src/containers/costume-tab.jsx
index 9f84d53c2..a142ff912 100644
--- a/src/containers/costume-tab.jsx
+++ b/src/containers/costume-tab.jsx
@@ -5,7 +5,6 @@ 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 PaintEditorWrapper from './paint-editor-wrapper.jsx';
 import CostumeLibrary from './costume-library.jsx';
 import BackdropLibrary from './backdrop-library.jsx';
@@ -18,17 +17,53 @@ import {
     openBackdropLibrary
 } from '../reducers/modals';
 
+import addBlankCostumeIcon from '../components/asset-panel/icon--add-blank-costume.svg';
+import addLibraryBackdropIcon from '../components/asset-panel/icon--add-backdrop-lib.svg';
+import addLibraryCostumeIcon from '../components/asset-panel/icon--add-costume-lib.svg';
+import costumeLibraryContent from '../lib/libraries/costumes.json';
+
+const messages = {
+    addLibraryBackdropMsg: (
+        <FormattedMessage
+            defaultMessage="Add Backdrop From Library"
+            description="Button to add a backdrop in the editor tab"
+            id="gui.costumeTab.addBackdrop"
+        />
+    ),
+    addLibraryCostumeMsg: (
+        <FormattedMessage
+            defaultMessage="Add Costume From Library"
+            description="Button to add a costume in the editor tab"
+            id="gui.costumeTab.addCostume"
+        />
+    ),
+    addBlankBackdropMsg: (
+        <FormattedMessage
+            defaultMessage="Add Blank Backdrop"
+            description="Button to add a blank backdrop in the editor tab"
+            id="gui.costumeTab.addBlankBackdrop"
+        />
+    ),
+    addBlankCostumeMsg: (
+        <FormattedMessage
+            defaultMessage="Add Blank Costume"
+            description="Button to add a blank costume in the editor tab"
+            id="gui.costumeTab.addBlankCostume"
+        />
+    )
+};
+
 class CostumeTab extends React.Component {
     constructor (props) {
         super(props);
         bindAll(this, [
             'handleSelectCostume',
             'handleDeleteCostume',
-            'handleNewCostume'
+            'handleNewCostume',
+            'handleNewBlankCostume'
         ]);
         this.state = {selectedCostumeIndex: 0};
     }
-
     componentWillReceiveProps (nextProps) {
         const {
             editingTarget,
@@ -41,27 +76,40 @@ class CostumeTab extends React.Component {
             this.setState({selectedCostumeIndex: target.costumes.length - 1});
         }
     }
-
     handleSelectCostume (costumeIndex) {
         this.props.vm.editingTarget.setCostume(costumeIndex);
         this.setState({selectedCostumeIndex: costumeIndex});
     }
-
     handleDeleteCostume (costumeIndex) {
         this.props.vm.deleteCostume(costumeIndex);
     }
-
     handleNewCostume () {
         if (!this.props.vm.editingTarget) return;
         const costumes = this.props.vm.editingTarget.sprite.costumes || [];
         this.setState({selectedCostumeIndex: Math.max(costumes.length - 1, 0)});
     }
-
+    handleNewBlankCostume () {
+        const emptyItem = costumeLibraryContent.find(item => (
+            item.name === 'Empty'
+        ));
+        const name = this.props.vm.editingTarget.isStage ? `backdrop1` : `costume1`;
+        const vmCostume = {
+            name: name,
+            rotationCenterX: emptyItem.info[0],
+            rotationCenterY: emptyItem.info[1],
+            bitmapResolution: emptyItem.info.length > 2 ? emptyItem.info[2] : 1,
+            skinId: null
+        };
+
+        this.props.vm.addCostume(emptyItem.md5, vmCostume).then(() => {
+            this.handleNewCostume();
+        });
+    }
     render () {
         // For paint wrapper
         const {
-            onNewBackdropClick,
-            onNewCostumeClick,
+            onNewLibraryBackdropClick,
+            onNewLibraryCostumeClick,
             costumeLibraryVisible,
             backdropLibraryVisible,
             onRequestCloseCostumeLibrary,
@@ -82,31 +130,25 @@ class CostumeTab extends React.Component {
             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;
+        const addLibraryMessage = target.isStage ? messages.addLibraryBackdropMsg : messages.addLibraryCostumeMsg;
+        const addBlankMessage = target.isStage ? messages.addBlankBackdropMsg : messages.addBlankCostumeMsg;
+        const addLibraryFunc = target.isStage ? onNewLibraryBackdropClick : onNewLibraryCostumeClick;
+        const addLibraryIcon = target.isStage ? addLibraryBackdropIcon : addLibraryCostumeIcon;
 
         return (
             <AssetPanel
-                buttons={[{
-                    message: addMessage,
-                    img: addCostumeIcon,
-                    onClick: addFunc
-                }]}
+                buttons={[
+                    {
+                        message: addBlankMessage,
+                        img: addBlankCostumeIcon,
+                        onClick: this.handleNewBlankCostume
+                    },
+                    {
+                        message: addLibraryMessage,
+                        img: addLibraryIcon,
+                        onClick: addLibraryFunc
+                    }
+                ]}
                 items={target.costumes || []}
                 selectedItemIndex={this.state.selectedCostumeIndex}
                 onDeleteClick={target.costumes.length > 1 ? this.handleDeleteCostume : null}
@@ -142,8 +184,8 @@ CostumeTab.propTypes = {
     backdropLibraryVisible: PropTypes.bool,
     costumeLibraryVisible: PropTypes.bool,
     editingTarget: PropTypes.string,
-    onNewBackdropClick: PropTypes.func.isRequired,
-    onNewCostumeClick: PropTypes.func.isRequired,
+    onNewLibraryBackdropClick: PropTypes.func.isRequired,
+    onNewLibraryCostumeClick: PropTypes.func.isRequired,
     onRequestCloseBackdropLibrary: PropTypes.func.isRequired,
     onRequestCloseCostumeLibrary: PropTypes.func.isRequired,
     sprites: PropTypes.shape({
@@ -171,11 +213,11 @@ const mapStateToProps = state => ({
 });
 
 const mapDispatchToProps = dispatch => ({
-    onNewBackdropClick: e => {
+    onNewLibraryBackdropClick: e => {
         e.preventDefault();
         dispatch(openBackdropLibrary());
     },
-    onNewCostumeClick: e => {
+    onNewLibraryCostumeClick: e => {
         e.preventDefault();
         dispatch(openCostumeLibrary());
     },
-- 
GitLab