Hello, I created this code that let's you import blocks into scratch. Just add this small patch and replace the last line of
Scratch-Objects/ScriptableScratchMorph(class)/blockspecs/blockspecs
with: ^ t1 , self obsoleteBlockSpecs , CustomBlockSpecsMorph customBlockSpecs.
Once you've done that you need to import a block to make things work.
Here is one made by greenatic and formated into block format by me.
http://www.mediafire.com/?qtpvu2zzsb231ab
Patch:
'From MIT Squeak 0.9.4 (June 1, 2003) [No updates present.] on 18 June 2010 at 5:06:17 pm' !ScriptableScratchMorph subclass: #CustomBlockSpecsMorph instanceVariableNames: '' classVariableNames: 'CustomBlockSpecs NewestBlock' poolDictionaries: '' category: 'Scratch-Objects'! !ScratchFileChooserDialog methodsFor: 'initialization'! createBlockFileChooserFor: t1 scratchFrame _ nil. readingScratchFile _ true. list _ ScratchFilePicker new extensions: #(#block ). self removeAllMorphs. bottomSpacer delete. bottomSpacer _ nil. mainColumn addMorphBack: list. self title: 'Import Block'. list scratchInfoClient: nil. mainColumn addMorphBack: (Morph new extent: 5 @ 9; color: Color transparent); addMorphBack: newTitleBin. fileInfoColumn addMorphBack: buttonRow. self addMorphBack: shortcutColumn; addMorphBack: mainColumn; addMorphBack: fileInfoColumn! ! !ScratchFrameMorph methodsFor: 'menu/button actions'! addBlock | t1 t2 t3 t4 | t1 _ ScratchFileChooserDialog new createBlockFileChooserFor: self; type: #block. t2 _ t1 getUserResponse. t2 = #cancelled ifTrue: [^ self]. t3 _ (FileDirectory forFileName: t2) oldFileNamed: t2. t4 _ t3 contentsOfEntireFile. (ReadWriteStream on: t4 from: 1 to: t4 size) fileIn. CustomBlockSpecsMorph updateCustomBlocks! ! !ScratchFrameMorph methodsFor: 'menu/button actions'! fileMenu: t1 | t2 | t2 _ CustomMenu new. t2 add: 'New' action: #newScratchProject. t2 add: 'Open' action: #openScratchProject. t2 add: 'Save' action: #saveScratchProjectNoDialog. t2 add: 'Save As' action: #saveScratchProject. t2 addLine. t2 add: 'Import Project' action: #importScratchProject. t2 add: 'Export Sprite' action: #exportSprite. t2 addLine. t2 add: 'Import Block' action: #addBlock. t2 addLine. t2 add: 'Project Notes' action: #editNotes. Sensor shiftPressed ifTrue: [t2 addLine. t2 add: 'Write Project Summary' action: #writeSummaryFile. t2 add: 'Write Multiple Project Summaries' action: #writeMultipleSummaries]. t2 addLine. t2 add: 'Quit' action: #quitScratch. t2 localize. #(2 4 5 6 7 8 ) do: [:t3 | t2 labels at: t3 put: ((t2 labels at: t3) copyFrom: 1 to: (t2 labels at: t3) size - 1) , ScratchTranslator ellipsesSuffix]. t2 invokeOn: self at: t1 bottomLeft + (0 @ 10)! ! !CustomBlockSpecsMorph class methodsFor: 'other'! updateCustomBlocks CustomBlockSpecs ifNil: [CustomBlockSpecs _ #('obsolete' )]. NewestBlock _ self getNewestBlock. CustomBlockSpecs _ CustomBlockSpecs , NewestBlock! ! !CustomBlockSpecsMorph class methodsFor: 'custom block specs'! customBlockSpecs ^ CustomBlockSpecs! ! !CustomBlockSpecsMorph class methodsFor: 'custom block specs'! newestBlock ^ NewestBlock! ! !CustomBlockSpecsMorph methodsFor: 'custom blockspecs'! nameThatProbablyWontBeUsedAsASelectorInABlock ^ self! !
Please report any glitches.
Offline
So far, there is no code that makes scratch write block files so you'll have to write them yourself. Don't worry it's relatively simple if you know how.
This is an example (original block by Greenatic) :
!CustomBlockSpecsMorph class methodsFor: 'custom block specs'!
Move: t1 Towards: t2
^ #('motion' ('move %n steps towards %m' #- #Move:Towards:) )! !
!ScratchSpriteMorph methodsFor: 'imported blocks'!
Move: t1 Towards: t2
| t3 t4 t5 t6 t7 t8 t9 |
t2 = #mouse ifFalse: [t3 _ t2 xpos @ t2 ypos - self referencePosition].
t2 = #mouse ifTrue: [t3 _ self mouseX rounded @ self mouseY - self referencePosition].
t4 _ t3 x abs < 0.001
ifTrue: [t3 y < 0
ifTrue: [90]
ifFalse: [270]]
ifFalse: [((t3 x >= 0
ifTrue: [0]
ifFalse: [180])
- ((t3 y / t3 x) arcTan * 57.2957795131)) rounded].
t5 _ t4 degreesToRadians.
t6 _ t5 cos @ t5 sin * t1.
t7 _ self position + t6.
t8 _ t7 x.
t9 _ t7 y.
t8 isNaN ifTrue: [t8 _ 0].
t8 isInf ifTrue: [t8 _ t8 sign * 10000].
t9 isNaN ifTrue: [t9 _ 0].
t9 isInf ifTrue: [t9 _ t9 sign * 10000].
self position: t8 @ t9.
self keepOnScreen! !
!CustomBlockSpecsMorph class methodsFor: 'other'!
getNewestBlock
^ CustomBlockSpecsMorph Move: '' Towards: ''! !
Ok, let's analyze it.
part 1, this defines the blockspec.
!CustomBlockSpecsMorph class methodsFor: 'custom block specs'!
Move: t1 Towards: t2 (*this message selector be the same as the next reference (marked by a *) )
^ #('motion' ('move %n steps towards %m' #- #Move:Towards:) )
"^ #('category' (blockspec #- #method))"! !
Part 2, this is the block code.
!ScratchSpriteMorph methodsFor: 'imported blocks'!
"ScratchSpriteMorph can be changed to ScratchStageMorph or ScriptableScratchMorph"
Move: t1 Towards: t2
| t3 t4 t5 t6 t7 t8 t9 |
t2 = #mouse ifFalse: [t3 _ t2 xpos @ t2 ypos - self referencePosition].
t2 = #mouse ifTrue: [t3 _ self mouseX rounded @ self mouseY - self referencePosition].
t4 _ t3 x abs < 0.001
ifTrue: [t3 y < 0
ifTrue: [90]
ifFalse: [270]]
ifFalse: [((t3 x >= 0
ifTrue: [0]
ifFalse: [180])
- ((t3 y / t3 x) arcTan * 57.2957795131)) rounded].
t5 _ t4 degreesToRadians.
t6 _ t5 cos @ t5 sin * t1.
t7 _ self position + t6.
t8 _ t7 x.
t9 _ t7 y.
t8 isNaN ifTrue: [t8 _ 0].
t8 isInf ifTrue: [t8 _ t8 sign * 10000].
t9 isNaN ifTrue: [t9 _ 0].
t9 isInf ifTrue: [t9 _ t9 sign * 10000].
self position: t8 @ t9.
self keepOnScreen! !
Part 3, this MUST have the selector name: 'getNewestBlock'
!CustomBlockSpecsMorph class methodsFor: 'other'!
getNewestBlock
^ CustomBlockSpecsMorph "the following selector must be the same as the selector name in part 1." Move: '' Towards: ''! !
Keep all the exclamation points, they belong there. (but I'm sure you knew that!)
Comment if you like this, need help, or have any ideas on how I can improve this, or you just feel like it.
Offline
Nice... now the block library needs another revamp...
Offline
By the way If you want custom arguments you're just going to have to do it yourself, because there is really no point in importing arguments because their would probably two different arguments defined with the same character.
Offline
Ok. I have made an update. The patch got a little bigger, but I'm sure you won't mind.
'From MIT Squeak 0.9.4 (June 1, 2003) [No updates present.] on 17 March 2012 at 1:51:00 pm'! ScriptableScratchMorph subclass: #CustomBlockSpecsDictionary instanceVariableNames: '' classVariableNames: 'CustomBlockSpecs NewestBlock ' poolDictionaries: '' category: 'Scratch-Objects'! DialogBoxMorph subclass: #CustomBlockSpecsEditor instanceVariableNames: 'scratchFrame newCustomBlockSpecs ' classVariableNames: '' poolDictionaries: '' category: 'Scratch-UI-Dialogs'! DialogBoxMorph subclass: #CreateBlockDialog instanceVariableNames: 'blockName helpButtonMorph blockSelectorMorph receiver blockArgsMorph blockTypeMorph editorMorph blockInserterMorph blockSectionMorph blockSelector ' classVariableNames: '' poolDictionaries: '' category: 'Scratch-UI-Dialogs'! DialogBoxMorph subclass: #ScrollingStringDialog instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Scratch-UI-Dialogs'! !CustomBlockSpecsDictionary commentStamp: '<historical>' prior: 0! Written By Dreamod. When you import a block the block spec is stored as a method under 'custom block specs' like this: forward: t1 ^ ('motion' ('move %n steps' #- #forward: 10)) These can be deleted at any point in the browser but are useful to recover data. The block specs are stored into the class variable 'CustomBlockSpecs' Selecting 'Delete All Custom Blocks' from the blocks menu will only replace 'CustomBlockSpecs' with this: #('obsolete' 'motion' #- 'control' #- 'looks' #- 'sensing' #- 'sound' #- 'operators' #- 'pen' #- 'variables' 'lists' 'obsolete' ) All block writing is stored in CommandBlockMorph! !CustomBlockSpecsDictionary class methodsFor: 'accessing'! customBlockSpecs CustomBlockSpecs ifNil: [self updateCustomBlocks]. ^ CustomBlockSpecs! ! !CustomBlockSpecsDictionary class methodsFor: 'accessing'! newestBlock ^ NewestBlock! ! !CustomBlockSpecsDictionary class methodsFor: 'initialization'! removeCustomBlocks | t1 t2 t3 t4 | CustomBlockSpecs _ nil. ScriptableScratchMorph new makeFile: 'temporaryFile.cs'. ScriptableScratchMorph new clearFile: 'temporaryFile.cs'. ScriptableScratchMorph new writeText: '!!CustomBlockSpecsDictionary class methodsFor: ''initialization''!! getNewestBlock ^ #(''obsolete'')!! !!' toFile: 'temporaryFile.cs'. t3 _ (FileDirectory forFileName: 'temporaryFile.cs') oldFileNamed: 'temporaryFile.cs'. t4 _ t3 contentsOfEntireFile. (ReadWriteStream on: t4 from: 1 to: t4 size) fileIn. CustomBlockSpecsDictionary updateCustomBlocks. ScriptableScratchMorph new deleteFile: 'temporaryFile.cs'! ! !CustomBlockSpecsDictionary class methodsFor: 'accessing'! updateBlocks CustomBlockSpecs _ self editBlocks! ! !CustomBlockSpecsDictionary class methodsFor: 'accessing'! getNewestBlock ^ #('obsolete' )! ! !CustomBlockSpecsDictionary class methodsFor: 'custom block specs'! editBlocks ^ #('obsolete' 'motion' #- 'control' #- 'looks' #- 'sensing' #- 'sound' #- 'operators' #- 'pen' #- 'variables' 'lists' 'obsolete')! ! !CommandBlockMorph methodsFor: 'export block'! createBlock | t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 | t13 _ CreateBlockDialog new editBlockNamed: '' reciever: ''; getUserResponse. t13 = #cancelled ifTrue: [^ self]. t1 _ t13 at: 2. t3 _ t13 at: 4. t5 _ t13 at: 1. t6 _ StringDialog ask: 'comment?'. t6 = #cancelled | t6 = '' ifTrue: [^ self]. (t6 findString: '!!') > 0 ifTrue: [ [DialogBoxMorph inform: 'The character ''!!'' is reserved!! please choose a new comment without a ''!!'''. t6 _ StringDialog ask: 'comment?'. t6 = #cancelled ifTrue: [^ self]. nil]. (t6 findString: '!!') > 0 ifTrue: [DialogBoxMorph inform: 'The character ''!!'' is reserved!! please choose a new comment without a ''!!''' asUTF8]. t6 _ StringDialog ask: 'comment?'. t6 = #cancelled ifTrue: [^ self]. (t6 findString: '!!') > 0 ifTrue: [^ self]]. t11 _ t6. (t6 findString: 'moreCodes') > 0 ifTrue: [(t6 findString: ':') > 0 ifTrue: [t14 _ (ScriptableScratchMorph new letters: (t6 findString: ':') + 2 through: (t6 findString: ':') + 2 of: t6) asNumberNoError]. (t6 findString: ';') > 0 ifTrue: [t11 _ ScriptableScratchMorph new letters: (t6 findString: ';') + 1 through: t6 size of: t6]]. t4 _ ScratchFileChooserDialog chooseNewFileDefaultBlocks: t1 title: 'Export Block As ' , t5 type: '.block'. t4 = #cancelled ifTrue: [^ self]. t2 _ t13 at: 3. (t4 asLowercase endsWith: '.block') ifFalse: [t4 _ t4 , '.block']. ScriptableScratchMorph new makeFile: t4. ScriptableScratchMorph new clearFile: t4. ScriptableScratchMorph new writeText: '!!CustomBlockSpecsDictionary class methodsFor: ''custom block specs''!! ' toFile: t4. t10 _ (t13 at: 5) lines at: 1. ScriptableScratchMorph new writeText: t10 toFile: t4. ScriptableScratchMorph new writeText: ' ^ #(''' , t5 , ''' ' , '(''' , t1 , '''' , ' #' , t2 , ' #' , t3 , '))' toFile: t4. ScriptableScratchMorph new writeText: ' ' , '"' , t11 , '" !! !! ' toFile: t4. t2 = 's' | t2 = 'c' ifTrue: [t8 _ 'ScratchProcess'. t9 _ '''private-special forms'''] ifFalse: [t8 _ 'ScriptableScratchMorph'. t9 _ '''' , t5 , ' ops''']. ScriptableScratchMorph new writeText: '!!' , t8 , ' methodsFor:' , '' , t9 , '' , '!!' toFile: t4. t7 _ t13 at: 5. ScriptableScratchMorph new writeText: t7 , '!! !!' toFile: t4. ScriptableScratchMorph new writeText: ' !!CustomBlockSpecsDictionary class methodsFor: ''custom block specs''!!' toFile: t4. ScriptableScratchMorph new writeText: ' getNewestBlock' toFile: t4. t10 _ self getNewTitleWithOutVariables: t13. ScriptableScratchMorph new writeText: ' ^ self ' , t10 toFile: t4. ScriptableScratchMorph new writeText: '!! !!' toFile: t4. t14 ifNil: [t14 _ 1]. t14 timesRepeat: [(t6 findString: 'moreCodes') > 0 ifTrue: [(t6 findString: 'moreCodes:') > 0 ifTrue: [t12 _ ScriptableScratchMorph new letters: (ScriptableScratchMorph new index: ':' of: t11) + 1 through: (ScriptableScratchMorph new index: ':' of: t6) + 1 of: t6]. ScriptableScratchMorph new writeText: (self moreCustomCodes: t12) toFile: t4]]. t3 _ (FileDirectory forFileName: t4) oldFileNamed: t4. t4 _ t3 contentsOfEntireFile. (ReadWriteStream on: t4 from: 1 to: t4 size) fileIn. CustomBlockSpecsDictionary updateCustomBlocks! ! !CommandBlockMorph methodsFor: 'export block'! exportBlock | t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 | t1 _ self commandSpec. t3 _ self selector. t5 _ self getCategoryForSelector: t3. t6 _ StringDialog ask: 'comment?'. t6 = #cancelled ifTrue: [^ self]. (t6 findString: '!!') > 0 ifTrue: [DialogBoxMorph inform: 'The character ''!!'' is reserved!! please choose a new comment without a ''!!'''. t6 _ StringDialog ask: 'comment?'. t6 = #cancelled ifTrue: [^ self]. (t6 findString: '!!') > 0 ifTrue: [DialogBoxMorph inform: 'The character ''!!'' is reserved!! please choose a new comment without a ''!!''' asUTF8]. t6 _ StringDialog ask: 'comment?'. t6 = #cancelled ifTrue: [^ self]. (t6 findString: '!!') > 0 ifTrue: [^ self]]. t11 _ t6. (t6 findString: 'moreCodes') > 0 ifTrue: [(t6 findString: ':') > 0 ifTrue: [t13 _ (ScriptableScratchMorph new letters: (t6 findString: ':') + 2 through: (t6 findString: ':') + 2 of: t6) asNumberNoError]. (t6 findString: ';') > 0 ifTrue: [t11 _ ScriptableScratchMorph new letters: (t6 findString: ';') + 1 through: t6 size of: t6] ifFalse: [t11 _ 'no comment available']]. t4 _ ScratchFileChooserDialog chooseNewFileDefaultBlocks: t1 title: 'Export Block As ' , t5 type: '.block'. t4 = #cancelled ifTrue: [^ self]. (self isKindOf: CommandBlockMorph) ifTrue: [t2 _ '-']. (self isKindOf: ReporterBlockMorph) ifTrue: [self isReporter ifTrue: [t2 _ 'r']. self isBooleanReporter ifTrue: [t2 _ 'b']]. (self isKindOf: CBlockMorph) | (self isKindOf: IfElseBlockMorph) ifTrue: [t2 _ 'c']. (self isKindOf: SetterBlockMorph) | (self isKindOf: VariableBlockMorph) | (self isKindOf: ListContentsBlockMorph) | (self isKindOf: HatBlockMorph) ifTrue: [^ self beep]. self isTimed ifTrue: [t2 _ 't']. self isSpecialForm & (self isKindOf: CBlockMorph) not & (self isKindOf: IfElseBlockMorph) not ifTrue: [t2 _ 's']. (t4 asLowercase endsWith: '.block') ifFalse: [t4 _ t4 , '.block']. ScriptableScratchMorph new makeFile: t4. ScriptableScratchMorph new clearFile: t4. ScriptableScratchMorph new writeText: '!!CustomBlockSpecsDictionary class methodsFor: ''custom block specs''!! ' toFile: t4. t10 _ self getNewTitleWithVariables. ScriptableScratchMorph new writeText: t10 toFile: t4. ScriptableScratchMorph new writeText: ' ^ #(''' , t5 , ''' ' , '(''' , t1 , '''' , ' #' , t2 , ' #' , t3 , '))' toFile: t4. ScriptableScratchMorph new writeText: ' ' , '"' , t11 , '" !! !! ' toFile: t4. self isSpecialForm | (self isKindOf: CBlockMorph) ifTrue: [t8 _ 'ScratchProcess'. t9 _ '''private-special forms'''] ifFalse: [t8 _ 'ScriptableScratchMorph'. t9 _ '''' , t5 , ' ops''']. ScriptableScratchMorph new writeText: '!!' , t8 , ' methodsFor:' , '' , t9 , '' , '!!' toFile: t4. t7 _ self getCode. ScriptableScratchMorph new writeText: t7 , '!! !!' toFile: t4. ScriptableScratchMorph new writeText: ' !!CustomBlockSpecsDictionary class methodsFor: ''custom block specs''!!' toFile: t4. ScriptableScratchMorph new writeText: ' getNewestBlock' toFile: t4. t10 _ self getNewTitleWithOutVariables. ScriptableScratchMorph new writeText: ' ^ self ' , t10 toFile: t4. ScriptableScratchMorph new writeText: '!! !!' toFile: t4. t13 ifNil: [t13 _ 1]. t13 timesRepeat: [(t6 findString: 'moreCodes') > 0 ifTrue: [(t6 findString: 'moreCodes:') > 0 ifTrue: [t12 _ ScriptableScratchMorph new letters: (ScriptableScratchMorph new index: ':' of: t11) + 1 through: (ScriptableScratchMorph new index: ':' of: t6) + 1 of: t6]. ScriptableScratchMorph new writeText: (self moreCodes: t12) toFile: t4]]! ! !CommandBlockMorph methodsFor: 'export block'! getCategoryForSelector: t1 | t2 t3 t4 t5 t6 | t2 _ ScriptableScratchMorph selectors asString. (t2 findString: t1 asString) > 0 ifTrue: [t2 _ ScriptableScratchMorph] ifFalse: [t2 _ nil]. t2 ifNil: [t2 _ ScratchSpriteMorph selectors asString. (t2 findString: t1 asString) > 0 ifTrue: [t2 _ ScratchSpriteMorph] ifFalse: [t2 _ nil]]. t2 ifNil: [t2 _ ScratchStageMorph selectors asString. (t2 findString: t1 asString) > 0 ifTrue: [t2 _ ScratchStageMorph] ifFalse: [t2 _ ScriptableScratchMorph]]. t2 ifNil: [t2 _ ScriptableScratchMorph]. t6 _ t1 asString. t3 _ ScriptableScratchMorph blockSpecCategories. t5 _ 1. t3 size timesRepeat: [t4 _ (t2 blockSpecsForCategory: (t3 at: t5)) asString. (t4 findString: t6 asString) > 0 ifTrue: [^ (t3 at: t5) asString]. t5 _ t5 + 1. t5 > t3 size ifTrue: [^ 'motion']. nil]. DialogBoxMorph inform: t4! ! !CommandBlockMorph methodsFor: 'export block'! getCode | t1 t2 | t1 _ self selector. t2 _ ScriptableScratchMorph selectors asString. (t2 findString: t1 asString) > 0 ifTrue: [^ (ScriptableScratchMorph sourceCodeAt: t1) asString]. t2 _ ScratchSpriteMorph selectors asString. (t2 findString: t1 asString) > 0 ifTrue: [^ (ScratchSpriteMorph sourceCodeAt: t1) asString]. t2 _ ScratchStageMorph selectors asString. (t2 findString: t1 asString) > 0 ifTrue: [^ (ScratchStageMorph sourceCodeAt: t1) asString]. t2 _ ScratchProcess selectors asString. (t2 findString: t1 asString) > 0 ifTrue: [^ (ScratchProcess sourceCodeAt: t1) asString]! ! !CommandBlockMorph methodsFor: 'export block'! getNewTitleWithOutVariables | t1 | t1 _ self selector. ^ t1 asString copyReplaceAll: ':' with: ': '' '! ! !CommandBlockMorph methodsFor: 'export block'! getNewTitleWithOutVariables: t1 | t2 | t2 _ t1 at: 4. (t2 findString: ' ') > 0 ifFalse: [t2 _ t2 , ' ']. t2 _ ScriptableScratchMorph new letters: 1 through: (t2 findString: ' ') of: t2. ^ t2 asString copyReplaceAll: ':' with: ': '' '' '! ! !CommandBlockMorph methodsFor: 'export block'! getNewTitleWithVariables | t1 t2 t3 t4 t5 | t1 _ 1. t2 _ ''. t3 _ 1. t4 _ self selector. t5 _ self argMorphs size asNumber. self isTimed ifTrue: [t5 _ t5 + 2]. (t4 findString: ':') > 0 ifTrue: [t5 timesRepeat: [t2 _ t2 , (ScriptableScratchMorph new letters: t1 through: (ScriptableScratchMorph new indexOf: ':' startingAt: t1 in: t4) of: t4) , ' t' , t3 asString , ' '. t1 _ (ScriptableScratchMorph new indexOf: ':' startingAt: t1 in: t4) + 1. t3 _ t3 + 1]] ifFalse: [t2 _ t4]. ^ t2! ! !CommandBlockMorph methodsFor: 'export block'! moreCodes: t1 | t2 t3 t4 t5 t6 t7 t8 t9 t10 | t2 _ StringDialog ask: 'Enter Class And Selector ' , ' (' , 'ex: ScratchFrameMorph new saveScratchProject' , ') ' initialAnswer: 'ScratchFrameMorph new saveScratchProject'. (t2 findString: 'moreCodes') > 0 ifTrue: [(t2 findString: ';') > 0 ifTrue: [t2 _ ScriptableScratchMorph new letters: (t2 findString: ';') + 1 through: t2 size of: t2]]. t3 _ ScriptableScratchMorph new letters: 1 through: (t2 findString: ' ') - 1 of: t2. t4 _ t2 findString: 'new'. t4 > 0 ifTrue: [t4 _ ' '] ifFalse: [t4 _ ' class ']. t5 _ t2 findString: ' '. t4 = ' ' ifTrue: [t5 _ t5 + 5]. t6 _ 'thing' asString. t6 _ ScriptableScratchMorph new letters: t5 through: t2 size of: t2. t7 _ t3 asString , t4 asString , 'sourceCodeAt: ' , '#' , t6 asString. ScriptableScratchMorph new makeFile: 'temporaryFile.cs'. ScriptableScratchMorph new clearFile: 'temporaryFile.cs'. ScriptableScratchMorph new writeText: '!!CommandBlockMorph methodsFor: ''export block''!! writeMoreCodes ^ ' , t7 toFile: 'temporaryFile.cs'. t9 _ (FileDirectory forFileName: 'temporaryFile.cs') oldFileNamed: 'temporaryFile.cs'. t10 _ t9 contentsOfEntireFile. (ReadWriteStream on: t10 from: 1 to: t10 size) fileIn. ScriptableScratchMorph new deleteFile: 'temporaryFile.cs'. t8 _ self writeMoreCodes asString. ^ ' !!' , t3 , t4 , 'methodsFor: ''as yet unclassified''!! ' , t8 , '!! !!'! ! !CommandBlockMorph methodsFor: 'export block'! moreCustomCodes: t1 | t2 t3 t4 t5 t6 t7 t8 t9 t10 | t2 _ StringDialog ask: 'Enter Class And Selector ' , ' (' , 'ex: ScratchFrameMorph new saveScratchProject' , ') ' initialAnswer: 'ScratchFrameMorph new saveScratchProject'. (t2 findString: 'moreCodes') > 0 ifTrue: [(t2 findString: ';') > 0 ifTrue: [t2 _ ScriptableScratchMorph new letters: (t2 findString: ';') + 1 through: t2 size of: t2]]. t3 _ ScriptableScratchMorph new letters: 1 through: (t2 findString: ' ') - 1 of: t2. t4 _ t2 findString: 'new'. t4 > 0 ifTrue: [t4 _ ' '] ifFalse: [t4 _ ' class ']. t5 _ t2 findString: ' '. t4 = ' ' ifTrue: [t5 _ t5 + 5]. t6 _ 'thing' asString. t6 _ ScriptableScratchMorph new letters: t5 through: t2 size of: t2. t8 _ CreateBlockDialog new moreCodes; getUserResponse2. ^ ' !!' , t3 , t4 , 'methodsFor: ''as yet unclassified''!! ' , t8 , '!! !!'! ! !CommandBlockMorph methodsFor: 'private'! rightButtonMenu | t1 t2 t3 t4 | t1 _ CustomMenu new. t1 add: 'help' action: #presentHelpScreen. t1 add: 'export block' action: #exportBlock. (owner isKindOf: ScratchBlockPaletteMorph) ifFalse: [t1 addLine. (#(#+ #- #* #/ #\\ ) includes: selector) ifTrue: [#(#+ #- #* #/ #mod ) with: #(#+ #- #* #/ #\\ ) do: [:t5 :t6 | t1 add: t5 action: t6]]. (#(#< #= #> ) includes: selector) ifTrue: [#(#< #= #> ) do: [:t6 | t1 add: t6 action: t6]]. (#(#& #| ) includes: selector) ifTrue: [#(#and #or ) with: #(#& #| ) do: [:t5 :t6 | t1 add: t5 action: t6]]. t1 addLine. t1 add: 'duplicate' action: #duplicate. (self owner isKindOf: BlockMorph) ifFalse: [t1 add: 'delete' action: #delete]]. t2 _ self ownerThatIsA: ScratchFrameMorph. (t2 notNil and: [#(#sensor: #sensorPressed: ) includes: selector]) ifTrue: [t1 addLine. t1 add: 'show ScratchBoard watcher' action: #showSensorBoard. t2 workPane scratchServer ifNil: [t1 add: 'enable remote sensor connections' action: #enableRemoteSensors] ifNotNil: [t1 add: 'disable remote sensor connections' action: #exitScratchSession]]. DebugMenu ifTrue: [t1 addLine. t1 add: 'show tuples' action: #showTuples]. (t3 _ t1 localize; startUp) ifNil: [^ self]. (#(#presentHelpScreen #duplicate #delete ) includes: t3) ifTrue: [^ self perform: t3]. t3 = #showSensorBoard ifTrue: [t2 showSensorBoard. ^ self]. t3 = #enableRemoteSensors ifTrue: [t2 enableRemoteSensors. ^ self]. t3 = #exitScratchSession ifTrue: [t2 exitScratchSession. ^ self]. t3 = #exportBlock ifTrue: [^ self exportBlock]. t3 = #showTuples ifTrue: [^ self showTuples]. t4 _ '%n ' , t3 , ' %n'. '\\' = t3 ifTrue: [t4 _ ScratchTranslator translationFor: '%n mod %n']. '&' = t3 ifTrue: [t4 _ ScratchTranslator translationFor: '%b and %b']. '|' = t3 ifTrue: [t4 _ ScratchTranslator translationFor: '%b or %b']. self commandSpec: t4. self selector: t3! ! !CreateBlockDialog methodsFor: 'initialization'! initialize super initialize. self withButtonsForYes: false no: false okay: true cancel: false! ! !CreateBlockDialog methodsFor: 'other'! blockSection ^ blockSectionMorph evaluate! ! !CreateBlockDialog methodsFor: 'other'! blockSpec ^ blockArgsMorph contents! ! !CreateBlockDialog methodsFor: 'other'! blockType ^ blockTypeMorph contents! ! !CreateBlockDialog methodsFor: 'other'! editBlockNamed: t1 reciever: t2 | t3 | editorMorph _ ScrollingStringMorph new borderWidth: 0; contents: ''; font: self class monoSpacedFont; backForm: (ScratchFrameMorph skinAt: #stringFieldFrame); width: 300. blockArgsMorph _ StringFieldMorph new useStringFieldFrame; width: 250. blockSelectorMorph _ StringFieldMorph new useStringFieldFrame; width: 250. blockTypeMorph _ StringFieldMorph new useStringFieldFrame; width: 35. blockSectionMorph _ StringFieldMorph new useStringFieldFrame; width: 100. helpButtonMorph _ (self buttonLabel: ('Help' , ScratchTranslator ellipsesSuffix) localized action: #presentHelpMenu) width: 300. t3 _ AlignmentMorph new width: 300; color: Color transparent; centering: #center. t3 addMorph: blockSectionMorph; addMorph: blockTypeMorph; addMorph: blockArgsMorph. self title: 'Create A Block'. mainColumn addMorphBack: t3. mainColumn addMorphBack: blockSelectorMorph. mainColumn addMorphBack: editorMorph. mainColumn addMorphBack: helpButtonMorph. mainColumn addMorphBack: buttonRow. editorMorph contents: (ScratchSpriteMorph sourceCodeAt: #forward:) asString. blockArgsMorph contents: 'move %n steps' asString. blockTypeMorph contents: '-' asString. blockSectionMorph contents: 'motion'. blockSelectorMorph contents: 'forward: 10'. bottomSpacer delete. bottomSpacer _ nil. tabFields add: editorMorph. tabFields add: helpButtonMorph. tabFields add: blockArgsMorph. tabFields add: blockTypeMorph! ! !CreateBlockDialog methodsFor: 'other'! getUserResponse | t1 t2 | self openInWorld. self centerOnScreen. t1 _ self world. tabFields size > 0 ifTrue: [t1 activeHand newKeyboardFocus: (tabFields at: 4)]. done _ false. [done] whileFalse: [t1 doOneCycle]. t2 _ Array with: blockSectionMorph contents with: blockArgsMorph contents with: blockTypeMorph contents with: blockSelectorMorph contents with: self value. ^ t2! ! !CreateBlockDialog methodsFor: 'other'! getUserResponse2 | t1 t2 | self openInWorld. self centerOnScreen. t1 _ self world. tabFields size > 0 ifTrue: [t1 activeHand newKeyboardFocus: (tabFields at: 1)]. done _ false. [done] whileFalse: [t1 doOneCycle]. ^ self value! ! !CreateBlockDialog methodsFor: 'other'! moreCodes | t1 | editorMorph _ ScrollingStringMorph new borderWidth: 0; contents: ''; font: self class monoSpacedFont; backForm: (ScratchFrameMorph skinAt: #stringFieldFrame); width: 300. t1 _ AlignmentMorph new width: 300; color: Color transparent; centering: #center. self title: 'Create A Block'. mainColumn addMorphBack: t1. mainColumn addMorphBack: editorMorph. mainColumn addMorphBack: buttonRow. editorMorph contents: 'message selector and argument names "comment stating purpose of message" | temporary variable names | statements' asString. bottomSpacer delete. bottomSpacer _ nil. tabFields add: editorMorph! ! !CreateBlockDialog methodsFor: 'other'! presentHelpMenu | t1 t2 | t1 _ CustomMenu new. t1 add: 'arguments' action: #arguments. t1 add: 'type' action: #type. t1 add: 'name' action: #name. t1 add: 'selector' action: #selector. t1 add: 'code' action: #code. t2 _ t1 localize; startUp. t2 = #arguments ifTrue: [^ ScrollingStringDialog new text: 'Arguments are spaces where you can enter text, numbers, colors, booleans etc. They are encoded using ''%'' and a letter, ex. %s = string, %m = morph list (sprite list). Different Scratch Mods have different arguments. Here is your list of arguments. It can be found at Scratch-Blocks>>CommandBlockMorph>>private>>uncoloredArgMorphFor: ' , (CommandBlockMorph sourceCodeAt: #uncoloredArgMorphFor:) asString , ' for information visit: ' title: 'Help - About Arguments'; getUserResponse]. t2 = #type ifTrue: [^ ScrollingStringDialog new text: 'This determines the shape of your block. Explanation of flags: - no flags b boolean reporter c c-shaped block containing a sequence of commands (always special form) r reporter s special form command with its own evaluation rule t timed command, like wait or glide E message event hat K key event hat M mouse-click event hat S start event hat W when <condition> hat (obsolete). Some modifications like panther and BYOB have even more block kinds. ' title: 'Help - Block Types'; getUserResponse]. t2 = #name ifTrue: [^ ScrollingStringDialog new text: 'The title of the block is the text that shows up on the block' title: 'Help - Title'; getUserResponse]. t2 = #selector ifTrue: [ScrollingStringDialog new text: 'The selector should be the same as the title of the code. However, instead of typing ''do: t1 ThisCode: t2 On: t3'' (example) you type ''do:ThisCode:On:'' Why do I need to type the selector? this is important because the blockspecs builder builds the blockspec from 4 things. >> the category (''motion''... >> the title (''move %n steps''... >> the type #- >> and the selector: forward:) You cannot type the full blockspec because the block exporter needs all the data seperately.' title: 'Help - Selector'; getUserResponse]. t2 = #code ifTrue: [^ ScrollingStringDialog new text: 'The code (or method) is what make the block work. First you type the title and then you type the variables, like this: | t1 t2 t3 | Then you type your statements (actions)' title: 'Help - Code'; getUserResponse]! ! !CreateBlockDialog class methodsFor: 'instance creation'! monoSpacedFont ^ ScratchFrameMorph getFont: #ProjectNotes! ! !CreateBlockDialog methodsFor: 'other'! value ^ editorMorph contents! ! !CustomBlockSpecsEditor class methodsFor: 'initialization'! editNotesFor: aScratchFrameMorph ^ self new createNotesDialogFor: aScratchFrameMorph; extent: 350@450.! ! !CustomBlockSpecsEditor methodsFor: 'initialization'! newCustomBlockSpecs ^ newCustomBlockSpecs contents! ! !CustomBlockSpecsEditor methodsFor: 'initialization'! createNotesDialogFor: t1 | t2 | t2 _ ScratchFrameMorph getFont: #ProjectNotes. newCustomBlockSpecs _ ScrollingStringMorph new borderWidth: 0; contents: ''; font: t2; backForm: (ScratchFrameMorph skinAt: #stringFieldFrame); width: 500. self title: 'Edit Custom Blockspecs'. mainColumn addMorphBack: newCustomBlockSpecs. mainColumn addMorphBack: buttonRow. scratchFrame _ t1. newCustomBlockSpecs contents: CustomBlockSpecsDictionary customBlockSpecs asString. bottomSpacer delete. bottomSpacer _ nil. tabFields add: newCustomBlockSpecs! ! !CustomBlockSpecsEditor methodsFor: 'initialization'! initialize super initialize. self withButtonsForYes: false no: false okay: true cancel: true! ! !CustomBlockSpecsEditor methodsFor: 'other'! getUserResponse | t1 t2 t3 t4 | self openInWorld. self centerOnScreen. t1 _ self world. t1 activeHand newKeyboardFocus: newCustomBlockSpecs. done _ false. [done] whileFalse: [t1 doOneCycle]. response = #cancelled ifTrue: [^ #cancelled]. t2 _ 'temporaryFile.cs'. ScriptableScratchMorph new makeFile: t2. ScriptableScratchMorph new clearFile: t2. ScriptableScratchMorph new writeText: '!!CustomBlockSpecsDictionary class methodsFor: ''custom block specs''!! editBlocks ^ #' toFile: t2. ScriptableScratchMorph new writeText: newCustomBlockSpecs contents toFile: 'temporaryFile.cs'. ScriptableScratchMorph new writeText: '!! !!' toFile: t2. t3 _ (FileDirectory forFileName: t2) oldFileNamed: t2. t4 _ t3 contentsOfEntireFile. (ReadWriteStream on: t4 from: 1 to: t4 size) fileIn. ^ CustomBlockSpecsDictionary updateBlocks! ! !ScrollingStringDialog methodsFor: 'initialization'! text: t1 title: t2 | t3 | t3 _ ScrollingStringMorph new borderWidth: 0; contents: t1; font: (ScratchFrameMorph getFont: #ProjectNotes); isEditable: false; backForm: (ScratchFrameMorph skinAt: #stringFieldFrame); width: 500. self title: t2. mainColumn addMorphBack: t3. buttonRow addMorphBack: (self buttonLabel: 'OK' action: #yes). mainColumn addMorphBack: buttonRow. bottomSpacer delete. bottomSpacer _ nil! ! !ScratchFrameMorph methodsFor: 'menu/button actions'! createBlock CommandBlockMorph new createBlock! ! !ScratchFrameMorph methodsFor: 'menu/button actions'! deleteAllBlocks CustomBlockSpecsDictionary removeCustomBlocks! ! !ScratchFrameMorph methodsFor: 'menu/button actions'! editCustomBlockSpecs ^ (CustomBlockSpecsEditor editNotesFor: self) getUserResponse! ! !ScratchFrameMorph methodsFor: 'menu/button actions'! createMenuPanel | t1 t2 | menuPanel _ AlignmentMorph new color: Color transparent; centering: #center; inset: 0; height: 0. self addShortcutButtonsTo: menuPanel. t1 _ #((#File #fileMenu:) (#Edit #editMenu:) (#Blocks #blocksMenu:) (#Help #helpMenu:) ). t1 do: [:t3 | t2 _ ScratchMenuTitleMorph new contents: (t3 at: 1) localized; target: self selector: (t3 at: 2). menuPanel addMorphBack: t2. #helpMenu: = (t3 at: 2) ifFalse: [menuPanel addMorphBack: (Morph new color: Color transparent; extent: 12 @ 5)]]. topPane addMorph: menuPanel! ! !ScratchFrameMorph methodsFor: 'menu/button actions'! blocksMenu: t1 | t2 | t2 _ CustomMenu new. t2 add: 'Edit Custom Block Specs' action: #editCustomBlockSpecs. t2 add: 'Delete All Custom Blocks' action: #deleteAllBlocks. t2 addLine. t2 add: 'Import Block' action: #addBlock. t2 add: 'Create Block' action: #createBlock. t2 invokeOn: self at: t1 bottomLeft + (0 @ 10)! ! !ScratchFrameMorph methodsFor: 'menu/button actions'! addBlock | t1 t2 t3 t4 | t1 _ ScratchFileChooserDialog new createBlockFileChooserFor: self; type: #block. t2 _ t1 getUserResponse. t2 = #cancelled ifTrue: [^ self]. t3 _ (FileDirectory forFileName: t2) oldFileNamed: t2. t4 _ t3 contentsOfEntireFile. (ReadWriteStream on: t4 from: 1 to: t4 size) fileIn. CustomBlockSpecsDictionary updateCustomBlocks! ! !ScratchFileChooserDialog methodsFor: 'initialization'! createFileChooserLayoutBlock: t1 list _ ScratchFilePicker new. self removeAllMorphs. bottomSpacer delete. bottomSpacer _ nil. mainColumn addMorphBack: list. self title: 'Open'. t1 ifTrue: [self title: 'Save As'. newFileTitle _ StringMorph new contents: 'New Filename:' localized , ' '; color: (Color gray: 0.3); font: (ScratchFrameMorph getFont: #FileChooserNewFileTitle). newFileName _ StringFieldMorph new font: (ScratchFrameMorph getFont: #FileChooserNewFilename); color: (Color r: 211 / 255 g: 214 / 255 b: 216 / 255); width: 180. newTitleBin addMorphBack: newFileTitle; addMorphBack: (Morph new extent: 5 @ 5; color: Color transparent); addMorphBack: (Morph new extent: 5 @ 5; color: Color transparent); addMorphBack: newFileName; addMorphBack: (AlignmentMorph newSpacer: Color transparent). ScratchTranslator isRTL ifTrue: [newTitleBin submorphs reversed do: [:t2 | t2 delete. newTitleBin addMorphBack: t2]]]. mainColumn addMorphBack: newTitleBin; addMorphBack: newTitleBin; addMorphBack: buttonRow. self addMorphBack: shortcutColumn; addMorphBack: mainColumn; addMorphBack: fileInfoColumn! ! !ScratchFileChooserDialog methodsFor: 'initialization'! createBlockFileChooserFor: t1 scratchFrame _ nil. readingScratchFile _ true. list _ ScratchFilePicker new extensions: #(#block ). self removeAllMorphs. bottomSpacer delete. bottomSpacer _ nil. mainColumn addMorphBack: list. self title: 'Import Block'. list scratchInfoClient: nil. mainColumn addMorphBack: (Morph new extent: 5 @ 9; color: Color transparent); addMorphBack: newTitleBin. fileInfoColumn addMorphBack: buttonRow. self addMorphBack: shortcutColumn; addMorphBack: mainColumn; addMorphBack: fileInfoColumn! ! !CustomBlockSpecsDictionary class methodsFor: 'initialization'! updateCustomBlocks CustomBlockSpecs ifNil: [CustomBlockSpecs _ #('obsolete' 'motion' #- 'control' #- 'looks' #- 'sensing' #- 'sound' #- 'operators' #- 'pen' #- 'variables' 'lists' )]. NewestBlock _ self getNewestBlock. CustomBlockSpecs _ CustomBlockSpecs , NewestBlock! ! !ScriptableScratchMorph methodsFor: 'file ops'! clearFile: t1 | t2 t3 t4 | t4 _ 'credit to panther'. t3 _ FileDirectory forFileName: t1. t3 deleteFileNamed: t1. t2 _ FileStream newFileNamed: t1. t2 close! ! !ScriptableScratchMorph methodsFor: 'file ops'! deleteFile: t1 | t2 t3 | t2 _ FileDirectory forFileName: t1. t3 _ FileDirectory localNameFor: t1. t2 deleteFileNamed: t3 ifAbsent: []! ! !ScriptableScratchMorph methodsFor: 'file ops'! makeFile: t1 | t2 t3 t4 t5 t6 t7 t8 t9 t10 | t10 _ 'credit to panther'. t2 _ t1. t9 _ t1. t6 _ 'I exist'. t3 _ self readFile: t9. self writeText: t6 toFile: t9. t5 _ self readFile: t9. t7 _ self stringLength: t6. t8 _ self stringLength: t5. t7 _ t8 - t7. t7 _ t7 + 1. t7 _ self letters: t7 through: t8 of: t5. t7 = t6 ifTrue: [t4 _ true. self clearFile: t9. t3 = '' ifFalse: [self writeText: t3 toFile: t9]] ifFalse: [t4 _ false]. t4 = false ifTrue: [FileStream newFileNamed: t2]! ! !ScriptableScratchMorph methodsFor: 'file ops'! readFile: t1 | t2 t3 t4 | t4 _ 'credit to panther'. (FileDirectory default fileExists: t1) ifFalse: [^ '']. t2 _ (FileStream readOnlyFileNamed: t1) binary. t2 ifNil: [^ '']. t3 _ t2 contentsOfEntireFile asString. t2 close. ^ t3! ! !ScriptableScratchMorph methodsFor: 'file ops'! writeText: t1 toFile: t2 | t3 t4 | t4 _ 'credit to panther'. (FileDirectory default fileExists: t2) ifFalse: [^ self]. t3 _ (FileStream fileNamed: t2) binary. t3 ifNil: [^ self]. t3 setToEnd. t3 nextPutAll: t1. t3 close! ! !ScriptableScratchMorph methodsFor: 'string ops'! letters: t1 through: t2 of: t3 ^ t3 asString copyFrom: (t1 max: 1) to: (t2 min: t3 size)! ! !ScriptableScratchMorph methodsFor: 'string ops'! indexOf: t1 startingAt: t2 in: t3 ^ t3 asString findString: t1 startingAt: t2! ! !ScriptableScratchMorph methodsFor: 'string ops'! index: t1 of: t2 ^ t2 findString: t1! ! !ScriptableScratchMorph class methodsFor: 'block specs'! blockSpecs "Answer a collection of block specifications for the blocks that are common to all objects. Block specificatons (Arrays) are interspersed with category names (Strings). A block specification is an Array of the form: (<block spec string> <block type> <selector> [optional initial argument values]). Explanation of flags: - no flags b boolean reporter c c-shaped block containing a sequence of commands (always special form) r reporter s special form command with its own evaluation rule t timed command, like wait or glide E message event hat K key event hat M mouse-click event hat S start event hat W when <condition> hat (obsolete)" | blocks | blocks _ #( 'control' ('when %m clicked' S -) ('when %k key pressed' K -) ('when %m clicked' M -) - ('wait %n secs' t wait:elapsed:from: 1) - ('forever' c doForever) ('repeat %n' c doRepeat 10) - ('broadcast %e' - broadcast:) ('broadcast %e and wait' s doBroadcastAndWait) ('when I receive %e' E -) - ('forever if %b' c doForeverIf) ('if %b' c doIf) ('if %b' c doIfElse) ('wait until %b' s doWaitUntil) ('repeat until %b' c doUntil) - ('stop script' s doReturn) ('stop all' - stopAll) 'operators' ('%n + %n' r + - -) ('%n - %n' r - - -) ('%n * %n' r * - -) ('%n / %n' r / - -) - ('pick random %n to %n' r randomFrom:to: 1 10) - ('%s < %s' b < '' '') ('%s = %s' b = '' '') ('%s > %s' b > '' '') - ('%b and %b' b &) ('%b or %b' b |) ('not %b' b not) - ('join %s %s' r concatenate:with: 'hello ' 'world') ('letter %n of %s' r letter:of: 1 'world') ('length of %s' r stringLength: 'world') - ('%n mod %n' r \\ - -) ('round %n' r rounded -) - ('%f of %n' r computeFunction:of: 'sqrt' 10) 'sound' ('play sound %S' - playSound:) ('play sound %S until done' s doPlaySoundAndWait) ('stop all sounds' - stopAllSounds) - ('play drum %D for %n beats' t drum:duration:elapsed:from: 48 0.2) ('rest for %n beats' t rest:elapsed:from: 0.2) - ('play note %N for %n beats' t noteOn:duration:elapsed:from: 60 0.5) ('set instrument to %I' - midiInstrument: 1) - ('change volume by %n' - changeVolumeBy: -10) ('set volume to %n%' - setVolumeTo: 100) ('volume' r volume) - ('change tempo by %n' - changeTempoBy: 20) ('set tempo to %n bpm' - setTempoTo: 60) ('tempo' r tempo) 'motor' ('motor on for %n secs' t motorOnFor:elapsed:from: 1) ('motor on' - allMotorsOn) ('motor off' - allMotorsOff) ('motor power %n' - startMotorPower: 100) ('motor direction %W' - setMotorDirection: 'this way') 'variables' ('show variable %v' - showVariable:) ('hide variable %v' - hideVariable:) 'list' ('add %s to %L' - append:toList: 'thing') - ('delete %y of %L' - deleteLine:ofList: 1) ('insert %s at %i of %L' - insert:at:ofList: 'thing' 1) ('replace item %i of %L with %s' - setLine:ofList:to: 1 'list' 'thing') - ('item %i of %L' r getLine:ofList: 1) ('length of %L' r lineCountOfList:) ('%L contains %s' b list:contains: 'list' 'thing') ). ^ blocks, self obsoleteBlockSpecs , CustomBlockSpecsDictionary customBlockSpecs ! ! !ScratchFileChooserDialog class methodsFor: 'instance creation'! chooseNewFileDefaultBlocks: t1 title: t2 type: t3 | t4 | ScratchFileChooserDialog deleteDuplicates. t4 _ self new createFileChooserLayoutBlock: true; type: t3; defaultName: t1; title: t2; listExtent: 400 @ 280. ^ t4 getUserResponseForNewFile! !
Block Importer License
1. You are free to use this feature in any mod but you must give credit to me, dreamod, and NXIII, and you may in no way imply that this is your work. This patch is a modification based off of one of NXIII's works.
2. You may in no way imply that this is your work.
3. I will not take any responsibility for any impacts on any modified version of scratch including Panther, BYOB, or Slash, if this patch is installed. If you wish to avoid any unwanted changes, view the patch and modify parts to fit your mod.
4. If you install the patch included in this folder, and use it in your mod , then you must also give credit to dreamod and NXIII. It may be used in any way.
5. Enjoy and please provide feedback on this forum:
http://scratch.mit.edu/forums/viewtopic.php?id=91639
Download patch here: http://www.mediafire.com/?rjm3uj39wr3fuok
Please comment and tell me how I can improve it.
Offline
oh no, I forgot to click preview, this is embarrassing...
!ScriptableScratchMorph class methodsFor: 'block specs'! 'From MIT Squeak 0.9.4 (June 1, 2003) [No updates present.] on 17 March 2012 at 1:51:00 pm'! ScriptableScratchMorph subclass: #CustomBlockSpecsDictionary instanceVariableNames: '' classVariableNames: 'CustomBlockSpecs NewestBlock ' poolDictionaries: '' category: 'Scratch-Objects'! DialogBoxMorph subclass: #CustomBlockSpecsEditor instanceVariableNames: 'scratchFrame newCustomBlockSpecs ' classVariableNames: '' poolDictionaries: '' category: 'Scratch-UI-Dialogs'! DialogBoxMorph subclass: #CreateBlockDialog instanceVariableNames: 'blockName helpButtonMorph blockSelectorMorph receiver blockArgsMorph blockTypeMorph editorMorph blockInserterMorph blockSectionMorph blockSelector ' classVariableNames: '' poolDictionaries: '' category: 'Scratch-UI-Dialogs'! DialogBoxMorph subclass: #ScrollingStringDialog instanceVariableNames: '' classVariableNames: '' poolDictionaries: '' category: 'Scratch-UI-Dialogs'! !CustomBlockSpecsDictionary commentStamp: '<historical>' prior: 0! Written By Dreamod. When you import a block the block spec is stored as a method under 'custom block specs' like this: forward: t1 ^ ('motion' ('move %n steps' #- #forward: 10)) These can be deleted at any point in the browser but are useful to recover data. The block specs are stored into the class variable 'CustomBlockSpecs' Selecting 'Delete All Custom Blocks' from the blocks menu will only replace 'CustomBlockSpecs' with this: #('obsolete' 'motion' #- 'control' #- 'looks' #- 'sensing' #- 'sound' #- 'operators' #- 'pen' #- 'variables' 'lists' 'obsolete' ) All block writing is stored in CommandBlockMorph! !CustomBlockSpecsDictionary class methodsFor: 'accessing'! customBlockSpecs CustomBlockSpecs ifNil: [self updateCustomBlocks]. ^ CustomBlockSpecs! ! !CustomBlockSpecsDictionary class methodsFor: 'accessing'! newestBlock ^ NewestBlock! ! !CustomBlockSpecsDictionary class methodsFor: 'initialization'! removeCustomBlocks | t1 t2 t3 t4 | CustomBlockSpecs _ nil. ScriptableScratchMorph new makeFile: 'temporaryFile.cs'. ScriptableScratchMorph new clearFile: 'temporaryFile.cs'. ScriptableScratchMorph new writeText: '!!CustomBlockSpecsDictionary class methodsFor: ''initialization''!! getNewestBlock ^ #(''obsolete'')!! !!' toFile: 'temporaryFile.cs'. t3 _ (FileDirectory forFileName: 'temporaryFile.cs') oldFileNamed: 'temporaryFile.cs'. t4 _ t3 contentsOfEntireFile. (ReadWriteStream on: t4 from: 1 to: t4 size) fileIn. CustomBlockSpecsDictionary updateCustomBlocks. ScriptableScratchMorph new deleteFile: 'temporaryFile.cs'! ! !CustomBlockSpecsDictionary class methodsFor: 'accessing'! updateBlocks CustomBlockSpecs _ self editBlocks! ! !CustomBlockSpecsDictionary class methodsFor: 'accessing'! getNewestBlock ^ #('obsolete' )! ! !CustomBlockSpecsDictionary class methodsFor: 'custom block specs'! editBlocks ^ #('obsolete' 'motion' #- 'control' #- 'looks' #- 'sensing' #- 'sound' #- 'operators' #- 'pen' #- 'variables' 'lists' 'obsolete')! ! !CommandBlockMorph methodsFor: 'export block'! createBlock | t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 t14 | t13 _ CreateBlockDialog new editBlockNamed: '' reciever: ''; getUserResponse. t13 = #cancelled ifTrue: [^ self]. t1 _ t13 at: 2. t3 _ t13 at: 4. t5 _ t13 at: 1. t6 _ StringDialog ask: 'comment?'. t6 = #cancelled | t6 = '' ifTrue: [^ self]. (t6 findString: '!!') > 0 ifTrue: [ [DialogBoxMorph inform: 'The character ''!!'' is reserved!! please choose a new comment without a ''!!'''. t6 _ StringDialog ask: 'comment?'. t6 = #cancelled ifTrue: [^ self]. nil]. (t6 findString: '!!') > 0 ifTrue: [DialogBoxMorph inform: 'The character ''!!'' is reserved!! please choose a new comment without a ''!!''' asUTF8]. t6 _ StringDialog ask: 'comment?'. t6 = #cancelled ifTrue: [^ self]. (t6 findString: '!!') > 0 ifTrue: [^ self]]. t11 _ t6. (t6 findString: 'moreCodes') > 0 ifTrue: [(t6 findString: ':') > 0 ifTrue: [t14 _ (ScriptableScratchMorph new letters: (t6 findString: ':') + 2 through: (t6 findString: ':') + 2 of: t6) asNumberNoError]. (t6 findString: ';') > 0 ifTrue: [t11 _ ScriptableScratchMorph new letters: (t6 findString: ';') + 1 through: t6 size of: t6]]. t4 _ ScratchFileChooserDialog chooseNewFileDefaultBlocks: t1 title: 'Export Block As ' , t5 type: '.block'. t4 = #cancelled ifTrue: [^ self]. t2 _ t13 at: 3. (t4 asLowercase endsWith: '.block') ifFalse: [t4 _ t4 , '.block']. ScriptableScratchMorph new makeFile: t4. ScriptableScratchMorph new clearFile: t4. ScriptableScratchMorph new writeText: '!!CustomBlockSpecsDictionary class methodsFor: ''custom block specs''!! ' toFile: t4. t10 _ (t13 at: 5) lines at: 1. ScriptableScratchMorph new writeText: t10 toFile: t4. ScriptableScratchMorph new writeText: ' ^ #(''' , t5 , ''' ' , '(''' , t1 , '''' , ' #' , t2 , ' #' , t3 , '))' toFile: t4. ScriptableScratchMorph new writeText: ' ' , '"' , t11 , '" !! !! ' toFile: t4. t2 = 's' | t2 = 'c' ifTrue: [t8 _ 'ScratchProcess'. t9 _ '''private-special forms'''] ifFalse: [t8 _ 'ScriptableScratchMorph'. t9 _ '''' , t5 , ' ops''']. ScriptableScratchMorph new writeText: '!!' , t8 , ' methodsFor:' , '' , t9 , '' , '!!' toFile: t4. t7 _ t13 at: 5. ScriptableScratchMorph new writeText: t7 , '!! !!' toFile: t4. ScriptableScratchMorph new writeText: ' !!CustomBlockSpecsDictionary class methodsFor: ''custom block specs''!!' toFile: t4. ScriptableScratchMorph new writeText: ' getNewestBlock' toFile: t4. t10 _ self getNewTitleWithOutVariables: t13. ScriptableScratchMorph new writeText: ' ^ self ' , t10 toFile: t4. ScriptableScratchMorph new writeText: '!! !!' toFile: t4. t14 ifNil: [t14 _ 1]. t14 timesRepeat: [(t6 findString: 'moreCodes') > 0 ifTrue: [(t6 findString: 'moreCodes:') > 0 ifTrue: [t12 _ ScriptableScratchMorph new letters: (ScriptableScratchMorph new index: ':' of: t11) + 1 through: (ScriptableScratchMorph new index: ':' of: t6) + 1 of: t6]. ScriptableScratchMorph new writeText: (self moreCustomCodes: t12) toFile: t4]]. t3 _ (FileDirectory forFileName: t4) oldFileNamed: t4. t4 _ t3 contentsOfEntireFile. (ReadWriteStream on: t4 from: 1 to: t4 size) fileIn. CustomBlockSpecsDictionary updateCustomBlocks! ! !CommandBlockMorph methodsFor: 'export block'! exportBlock | t1 t2 t3 t4 t5 t6 t7 t8 t9 t10 t11 t12 t13 | t1 _ self commandSpec. t3 _ self selector. t5 _ self getCategoryForSelector: t3. t6 _ StringDialog ask: 'comment?'. t6 = #cancelled ifTrue: [^ self]. (t6 findString: '!!') > 0 ifTrue: [DialogBoxMorph inform: 'The character ''!!'' is reserved!! please choose a new comment without a ''!!'''. t6 _ StringDialog ask: 'comment?'. t6 = #cancelled ifTrue: [^ self]. (t6 findString: '!!') > 0 ifTrue: [DialogBoxMorph inform: 'The character ''!!'' is reserved!! please choose a new comment without a ''!!''' asUTF8]. t6 _ StringDialog ask: 'comment?'. t6 = #cancelled ifTrue: [^ self]. (t6 findString: '!!') > 0 ifTrue: [^ self]]. t11 _ t6. (t6 findString: 'moreCodes') > 0 ifTrue: [(t6 findString: ':') > 0 ifTrue: [t13 _ (ScriptableScratchMorph new letters: (t6 findString: ':') + 2 through: (t6 findString: ':') + 2 of: t6) asNumberNoError]. (t6 findString: ';') > 0 ifTrue: [t11 _ ScriptableScratchMorph new letters: (t6 findString: ';') + 1 through: t6 size of: t6] ifFalse: [t11 _ 'no comment available']]. t4 _ ScratchFileChooserDialog chooseNewFileDefaultBlocks: t1 title: 'Export Block As ' , t5 type: '.block'. t4 = #cancelled ifTrue: [^ self]. (self isKindOf: CommandBlockMorph) ifTrue: [t2 _ '-']. (self isKindOf: ReporterBlockMorph) ifTrue: [self isReporter ifTrue: [t2 _ 'r']. self isBooleanReporter ifTrue: [t2 _ 'b']]. (self isKindOf: CBlockMorph) | (self isKindOf: IfElseBlockMorph) ifTrue: [t2 _ 'c']. (self isKindOf: SetterBlockMorph) | (self isKindOf: VariableBlockMorph) | (self isKindOf: ListContentsBlockMorph) | (self isKindOf: HatBlockMorph) ifTrue: [^ self beep]. self isTimed ifTrue: [t2 _ 't']. self isSpecialForm & (self isKindOf: CBlockMorph) not & (self isKindOf: IfElseBlockMorph) not ifTrue: [t2 _ 's']. (t4 asLowercase endsWith: '.block') ifFalse: [t4 _ t4 , '.block']. ScriptableScratchMorph new makeFile: t4. ScriptableScratchMorph new clearFile: t4. ScriptableScratchMorph new writeText: '!!CustomBlockSpecsDictionary class methodsFor: ''custom block specs''!! ' toFile: t4. t10 _ self getNewTitleWithVariables. ScriptableScratchMorph new writeText: t10 toFile: t4. ScriptableScratchMorph new writeText: ' ^ #(''' , t5 , ''' ' , '(''' , t1 , '''' , ' #' , t2 , ' #' , t3 , '))' toFile: t4. ScriptableScratchMorph new writeText: ' ' , '"' , t11 , '" !! !! ' toFile: t4. self isSpecialForm | (self isKindOf: CBlockMorph) ifTrue: [t8 _ 'ScratchProcess'. t9 _ '''private-special forms'''] ifFalse: [t8 _ 'ScriptableScratchMorph'. t9 _ '''' , t5 , ' ops''']. ScriptableScratchMorph new writeText: '!!' , t8 , ' methodsFor:' , '' , t9 , '' , '!!' toFile: t4. t7 _ self getCode. ScriptableScratchMorph new writeText: t7 , '!! !!' toFile: t4. ScriptableScratchMorph new writeText: ' !!CustomBlockSpecsDictionary class methodsFor: ''custom block specs''!!' toFile: t4. ScriptableScratchMorph new writeText: ' getNewestBlock' toFile: t4. t10 _ self getNewTitleWithOutVariables. ScriptableScratchMorph new writeText: ' ^ self ' , t10 toFile: t4. ScriptableScratchMorph new writeText: '!! !!' toFile: t4. t13 ifNil: [t13 _ 1]. t13 timesRepeat: [(t6 findString: 'moreCodes') > 0 ifTrue: [(t6 findString: 'moreCodes:') > 0 ifTrue: [t12 _ ScriptableScratchMorph new letters: (ScriptableScratchMorph new index: ':' of: t11) + 1 through: (ScriptableScratchMorph new index: ':' of: t6) + 1 of: t6]. ScriptableScratchMorph new writeText: (self moreCodes: t12) toFile: t4]]! ! !CommandBlockMorph methodsFor: 'export block'! getCategoryForSelector: t1 | t2 t3 t4 t5 t6 | t2 _ ScriptableScratchMorph selectors asString. (t2 findString: t1 asString) > 0 ifTrue: [t2 _ ScriptableScratchMorph] ifFalse: [t2 _ nil]. t2 ifNil: [t2 _ ScratchSpriteMorph selectors asString. (t2 findString: t1 asString) > 0 ifTrue: [t2 _ ScratchSpriteMorph] ifFalse: [t2 _ nil]]. t2 ifNil: [t2 _ ScratchStageMorph selectors asString. (t2 findString: t1 asString) > 0 ifTrue: [t2 _ ScratchStageMorph] ifFalse: [t2 _ ScriptableScratchMorph]]. t2 ifNil: [t2 _ ScriptableScratchMorph]. t6 _ t1 asString. t3 _ ScriptableScratchMorph blockSpecCategories. t5 _ 1. t3 size timesRepeat: [t4 _ (t2 blockSpecsForCategory: (t3 at: t5)) asString. (t4 findString: t6 asString) > 0 ifTrue: [^ (t3 at: t5) asString]. t5 _ t5 + 1. t5 > t3 size ifTrue: [^ 'motion']. nil]. DialogBoxMorph inform: t4! ! !CommandBlockMorph methodsFor: 'export block'! getCode | t1 t2 | t1 _ self selector. t2 _ ScriptableScratchMorph selectors asString. (t2 findString: t1 asString) > 0 ifTrue: [^ (ScriptableScratchMorph sourceCodeAt: t1) asString]. t2 _ ScratchSpriteMorph selectors asString. (t2 findString: t1 asString) > 0 ifTrue: [^ (ScratchSpriteMorph sourceCodeAt: t1) asString]. t2 _ ScratchStageMorph selectors asString. (t2 findString: t1 asString) > 0 ifTrue: [^ (ScratchStageMorph sourceCodeAt: t1) asString]. t2 _ ScratchProcess selectors asString. (t2 findString: t1 asString) > 0 ifTrue: [^ (ScratchProcess sourceCodeAt: t1) asString]! ! !CommandBlockMorph methodsFor: 'export block'! getNewTitleWithOutVariables | t1 | t1 _ self selector. ^ t1 asString copyReplaceAll: ':' with: ': '' '! ! !CommandBlockMorph methodsFor: 'export block'! getNewTitleWithOutVariables: t1 | t2 | t2 _ t1 at: 4. (t2 findString: ' ') > 0 ifFalse: [t2 _ t2 , ' ']. t2 _ ScriptableScratchMorph new letters: 1 through: (t2 findString: ' ') of: t2. ^ t2 asString copyReplaceAll: ':' with: ': '' '' '! ! !CommandBlockMorph methodsFor: 'export block'! getNewTitleWithVariables | t1 t2 t3 t4 t5 | t1 _ 1. t2 _ ''. t3 _ 1. t4 _ self selector. t5 _ self argMorphs size asNumber. self isTimed ifTrue: [t5 _ t5 + 2]. (t4 findString: ':') > 0 ifTrue: [t5 timesRepeat: [t2 _ t2 , (ScriptableScratchMorph new letters: t1 through: (ScriptableScratchMorph new indexOf: ':' startingAt: t1 in: t4) of: t4) , ' t' , t3 asString , ' '. t1 _ (ScriptableScratchMorph new indexOf: ':' startingAt: t1 in: t4) + 1. t3 _ t3 + 1]] ifFalse: [t2 _ t4]. ^ t2! ! !CommandBlockMorph methodsFor: 'export block'! moreCodes: t1 | t2 t3 t4 t5 t6 t7 t8 t9 t10 | t2 _ StringDialog ask: 'Enter Class And Selector ' , ' (' , 'ex: ScratchFrameMorph new saveScratchProject' , ') ' initialAnswer: 'ScratchFrameMorph new saveScratchProject'. (t2 findString: 'moreCodes') > 0 ifTrue: [(t2 findString: ';') > 0 ifTrue: [t2 _ ScriptableScratchMorph new letters: (t2 findString: ';') + 1 through: t2 size of: t2]]. t3 _ ScriptableScratchMorph new letters: 1 through: (t2 findString: ' ') - 1 of: t2. t4 _ t2 findString: 'new'. t4 > 0 ifTrue: [t4 _ ' '] ifFalse: [t4 _ ' class ']. t5 _ t2 findString: ' '. t4 = ' ' ifTrue: [t5 _ t5 + 5]. t6 _ 'thing' asString. t6 _ ScriptableScratchMorph new letters: t5 through: t2 size of: t2. t7 _ t3 asString , t4 asString , 'sourceCodeAt: ' , '#' , t6 asString. ScriptableScratchMorph new makeFile: 'temporaryFile.cs'. ScriptableScratchMorph new clearFile: 'temporaryFile.cs'. ScriptableScratchMorph new writeText: '!!CommandBlockMorph methodsFor: ''export block''!! writeMoreCodes ^ ' , t7 toFile: 'temporaryFile.cs'. t9 _ (FileDirectory forFileName: 'temporaryFile.cs') oldFileNamed: 'temporaryFile.cs'. t10 _ t9 contentsOfEntireFile. (ReadWriteStream on: t10 from: 1 to: t10 size) fileIn. ScriptableScratchMorph new deleteFile: 'temporaryFile.cs'. t8 _ self writeMoreCodes asString. ^ ' !!' , t3 , t4 , 'methodsFor: ''as yet unclassified''!! ' , t8 , '!! !!'! ! !CommandBlockMorph methodsFor: 'export block'! moreCustomCodes: t1 | t2 t3 t4 t5 t6 t7 t8 t9 t10 | t2 _ StringDialog ask: 'Enter Class And Selector ' , ' (' , 'ex: ScratchFrameMorph new saveScratchProject' , ') ' initialAnswer: 'ScratchFrameMorph new saveScratchProject'. (t2 findString: 'moreCodes') > 0 ifTrue: [(t2 findString: ';') > 0 ifTrue: [t2 _ ScriptableScratchMorph new letters: (t2 findString: ';') + 1 through: t2 size of: t2]]. t3 _ ScriptableScratchMorph new letters: 1 through: (t2 findString: ' ') - 1 of: t2. t4 _ t2 findString: 'new'. t4 > 0 ifTrue: [t4 _ ' '] ifFalse: [t4 _ ' class ']. t5 _ t2 findString: ' '. t4 = ' ' ifTrue: [t5 _ t5 + 5]. t6 _ 'thing' asString. t6 _ ScriptableScratchMorph new letters: t5 through: t2 size of: t2. t8 _ CreateBlockDialog new moreCodes; getUserResponse2. ^ ' !!' , t3 , t4 , 'methodsFor: ''as yet unclassified''!! ' , t8 , '!! !!'! ! !CommandBlockMorph methodsFor: 'private'! rightButtonMenu | t1 t2 t3 t4 | t1 _ CustomMenu new. t1 add: 'help' action: #presentHelpScreen. t1 add: 'export block' action: #exportBlock. (owner isKindOf: ScratchBlockPaletteMorph) ifFalse: [t1 addLine. (#(#+ #- #* #/ #\\ ) includes: selector) ifTrue: [#(#+ #- #* #/ #mod ) with: #(#+ #- #* #/ #\\ ) do: [:t5 :t6 | t1 add: t5 action: t6]]. (#(#< #= #> ) includes: selector) ifTrue: [#(#< #= #> ) do: [:t6 | t1 add: t6 action: t6]]. (#(#& #| ) includes: selector) ifTrue: [#(#and #or ) with: #(#& #| ) do: [:t5 :t6 | t1 add: t5 action: t6]]. t1 addLine. t1 add: 'duplicate' action: #duplicate. (self owner isKindOf: BlockMorph) ifFalse: [t1 add: 'delete' action: #delete]]. t2 _ self ownerThatIsA: ScratchFrameMorph. (t2 notNil and: [#(#sensor: #sensorPressed: ) includes: selector]) ifTrue: [t1 addLine. t1 add: 'show ScratchBoard watcher' action: #showSensorBoard. t2 workPane scratchServer ifNil: [t1 add: 'enable remote sensor connections' action: #enableRemoteSensors] ifNotNil: [t1 add: 'disable remote sensor connections' action: #exitScratchSession]]. DebugMenu ifTrue: [t1 addLine. t1 add: 'show tuples' action: #showTuples]. (t3 _ t1 localize; startUp) ifNil: [^ self]. (#(#presentHelpScreen #duplicate #delete ) includes: t3) ifTrue: [^ self perform: t3]. t3 = #showSensorBoard ifTrue: [t2 showSensorBoard. ^ self]. t3 = #enableRemoteSensors ifTrue: [t2 enableRemoteSensors. ^ self]. t3 = #exitScratchSession ifTrue: [t2 exitScratchSession. ^ self]. t3 = #exportBlock ifTrue: [^ self exportBlock]. t3 = #showTuples ifTrue: [^ self showTuples]. t4 _ '%n ' , t3 , ' %n'. '\\' = t3 ifTrue: [t4 _ ScratchTranslator translationFor: '%n mod %n']. '&' = t3 ifTrue: [t4 _ ScratchTranslator translationFor: '%b and %b']. '|' = t3 ifTrue: [t4 _ ScratchTranslator translationFor: '%b or %b']. self commandSpec: t4. self selector: t3! ! !CreateBlockDialog methodsFor: 'initialization'! initialize super initialize. self withButtonsForYes: false no: false okay: true cancel: false! ! !CreateBlockDialog methodsFor: 'other'! blockSection ^ blockSectionMorph evaluate! ! !CreateBlockDialog methodsFor: 'other'! blockSpec ^ blockArgsMorph contents! ! !CreateBlockDialog methodsFor: 'other'! blockType ^ blockTypeMorph contents! ! !CreateBlockDialog methodsFor: 'other'! editBlockNamed: t1 reciever: t2 | t3 | editorMorph _ ScrollingStringMorph new borderWidth: 0; contents: ''; font: self class monoSpacedFont; backForm: (ScratchFrameMorph skinAt: #stringFieldFrame); width: 300. blockArgsMorph _ StringFieldMorph new useStringFieldFrame; width: 250. blockSelectorMorph _ StringFieldMorph new useStringFieldFrame; width: 250. blockTypeMorph _ StringFieldMorph new useStringFieldFrame; width: 35. blockSectionMorph _ StringFieldMorph new useStringFieldFrame; width: 100. helpButtonMorph _ (self buttonLabel: ('Help' , ScratchTranslator ellipsesSuffix) localized action: #presentHelpMenu) width: 300. t3 _ AlignmentMorph new width: 300; color: Color transparent; centering: #center. t3 addMorph: blockSectionMorph; addMorph: blockTypeMorph; addMorph: blockArgsMorph. self title: 'Create A Block'. mainColumn addMorphBack: t3. mainColumn addMorphBack: blockSelectorMorph. mainColumn addMorphBack: editorMorph. mainColumn addMorphBack: helpButtonMorph. mainColumn addMorphBack: buttonRow. editorMorph contents: (ScratchSpriteMorph sourceCodeAt: #forward:) asString. blockArgsMorph contents: 'move %n steps' asString. blockTypeMorph contents: '-' asString. blockSectionMorph contents: 'motion'. blockSelectorMorph contents: 'forward: 10'. bottomSpacer delete. bottomSpacer _ nil. tabFields add: editorMorph. tabFields add: helpButtonMorph. tabFields add: blockArgsMorph. tabFields add: blockTypeMorph! ! !CreateBlockDialog methodsFor: 'other'! getUserResponse | t1 t2 | self openInWorld. self centerOnScreen. t1 _ self world. tabFields size > 0 ifTrue: [t1 activeHand newKeyboardFocus: (tabFields at: 4)]. done _ false. [done] whileFalse: [t1 doOneCycle]. t2 _ Array with: blockSectionMorph contents with: blockArgsMorph contents with: blockTypeMorph contents with: blockSelectorMorph contents with: self value. ^ t2! ! !CreateBlockDialog methodsFor: 'other'! getUserResponse2 | t1 t2 | self openInWorld. self centerOnScreen. t1 _ self world. tabFields size > 0 ifTrue: [t1 activeHand newKeyboardFocus: (tabFields at: 1)]. done _ false. [done] whileFalse: [t1 doOneCycle]. ^ self value! ! !CreateBlockDialog methodsFor: 'other'! moreCodes | t1 | editorMorph _ ScrollingStringMorph new borderWidth: 0; contents: ''; font: self class monoSpacedFont; backForm: (ScratchFrameMorph skinAt: #stringFieldFrame); width: 300. t1 _ AlignmentMorph new width: 300; color: Color transparent; centering: #center. self title: 'Create A Block'. mainColumn addMorphBack: t1. mainColumn addMorphBack: editorMorph. mainColumn addMorphBack: buttonRow. editorMorph contents: 'message selector and argument names "comment stating purpose of message" | temporary variable names | statements' asString. bottomSpacer delete. bottomSpacer _ nil. tabFields add: editorMorph! ! !CreateBlockDialog methodsFor: 'other'! presentHelpMenu | t1 t2 | t1 _ CustomMenu new. t1 add: 'arguments' action: #arguments. t1 add: 'type' action: #type. t1 add: 'name' action: #name. t1 add: 'selector' action: #selector. t1 add: 'code' action: #code. t2 _ t1 localize; startUp. t2 = #arguments ifTrue: [^ ScrollingStringDialog new text: 'Arguments are spaces where you can enter text, numbers, colors, booleans etc. They are encoded using ''%'' and a letter, ex. %s = string, %m = morph list (sprite list). Different Scratch Mods have different arguments. Here is your list of arguments. It can be found at Scratch-Blocks>>CommandBlockMorph>>private>>uncoloredArgMorphFor: ' , (CommandBlockMorph sourceCodeAt: #uncoloredArgMorphFor:) asString , ' for information visit: ' title: 'Help - About Arguments'; getUserResponse]. t2 = #type ifTrue: [^ ScrollingStringDialog new text: 'This determines the shape of your block. Explanation of flags: - no flags b boolean reporter c c-shaped block containing a sequence of commands (always special form) r reporter s special form command with its own evaluation rule t timed command, like wait or glide E message event hat K key event hat M mouse-click event hat S start event hat W when <condition> hat (obsolete). Some modifications like panther and BYOB have even more block kinds. ' title: 'Help - Block Types'; getUserResponse]. t2 = #name ifTrue: [^ ScrollingStringDialog new text: 'The title of the block is the text that shows up on the block' title: 'Help - Title'; getUserResponse]. t2 = #selector ifTrue: [ScrollingStringDialog new text: 'The selector should be the same as the title of the code. However, instead of typing ''do: t1 ThisCode: t2 On: t3'' (example) you type ''do:ThisCode:On:'' Why do I need to type the selector? this is important because the blockspecs builder builds the blockspec from 4 things. >> the category (''motion''... >> the title (''move %n steps''... >> the type #- >> and the selector: forward:) You cannot type the full blockspec because the block exporter needs all the data seperately.' title: 'Help - Selector'; getUserResponse]. t2 = #code ifTrue: [^ ScrollingStringDialog new text: 'The code (or method) is what make the block work. First you type the title and then you type the variables, like this: | t1 t2 t3 | Then you type your statements (actions)' title: 'Help - Code'; getUserResponse]! ! !CreateBlockDialog class methodsFor: 'instance creation'! monoSpacedFont ^ ScratchFrameMorph getFont: #ProjectNotes! ! !CreateBlockDialog methodsFor: 'other'! value ^ editorMorph contents! ! !CustomBlockSpecsEditor class methodsFor: 'initialization'! editNotesFor: aScratchFrameMorph ^ self new createNotesDialogFor: aScratchFrameMorph; extent: 350@450.! ! !CustomBlockSpecsEditor methodsFor: 'initialization'! newCustomBlockSpecs ^ newCustomBlockSpecs contents! ! !CustomBlockSpecsEditor methodsFor: 'initialization'! createNotesDialogFor: t1 | t2 | t2 _ ScratchFrameMorph getFont: #ProjectNotes. newCustomBlockSpecs _ ScrollingStringMorph new borderWidth: 0; contents: ''; font: t2; backForm: (ScratchFrameMorph skinAt: #stringFieldFrame); width: 500. self title: 'Edit Custom Blockspecs'. mainColumn addMorphBack: newCustomBlockSpecs. mainColumn addMorphBack: buttonRow. scratchFrame _ t1. newCustomBlockSpecs contents: CustomBlockSpecsDictionary customBlockSpecs asString. bottomSpacer delete. bottomSpacer _ nil. tabFields add: newCustomBlockSpecs! ! !CustomBlockSpecsEditor methodsFor: 'initialization'! initialize super initialize. self withButtonsForYes: false no: false okay: true cancel: true! ! !CustomBlockSpecsEditor methodsFor: 'other'! getUserResponse | t1 t2 t3 t4 | self openInWorld. self centerOnScreen. t1 _ self world. t1 activeHand newKeyboardFocus: newCustomBlockSpecs. done _ false. [done] whileFalse: [t1 doOneCycle]. response = #cancelled ifTrue: [^ #cancelled]. t2 _ 'temporaryFile.cs'. ScriptableScratchMorph new makeFile: t2. ScriptableScratchMorph new clearFile: t2. ScriptableScratchMorph new writeText: '!!CustomBlockSpecsDictionary class methodsFor: ''custom block specs''!! editBlocks ^ #' toFile: t2. ScriptableScratchMorph new writeText: newCustomBlockSpecs contents toFile: 'temporaryFile.cs'. ScriptableScratchMorph new writeText: '!! !!' toFile: t2. t3 _ (FileDirectory forFileName: t2) oldFileNamed: t2. t4 _ t3 contentsOfEntireFile. (ReadWriteStream on: t4 from: 1 to: t4 size) fileIn. ^ CustomBlockSpecsDictionary updateBlocks! ! !ScrollingStringDialog methodsFor: 'initialization'! text: t1 title: t2 | t3 | t3 _ ScrollingStringMorph new borderWidth: 0; contents: t1; font: (ScratchFrameMorph getFont: #ProjectNotes); isEditable: false; backForm: (ScratchFrameMorph skinAt: #stringFieldFrame); width: 500. self title: t2. mainColumn addMorphBack: t3. buttonRow addMorphBack: (self buttonLabel: 'OK' action: #yes). mainColumn addMorphBack: buttonRow. bottomSpacer delete. bottomSpacer _ nil! ! !ScratchFrameMorph methodsFor: 'menu/button actions'! createBlock CommandBlockMorph new createBlock! ! !ScratchFrameMorph methodsFor: 'menu/button actions'! deleteAllBlocks CustomBlockSpecsDictionary removeCustomBlocks! ! !ScratchFrameMorph methodsFor: 'menu/button actions'! editCustomBlockSpecs ^ (CustomBlockSpecsEditor editNotesFor: self) getUserResponse! ! !ScratchFrameMorph methodsFor: 'menu/button actions'! createMenuPanel | t1 t2 | menuPanel _ AlignmentMorph new color: Color transparent; centering: #center; inset: 0; height: 0. self addShortcutButtonsTo: menuPanel. t1 _ #((#File #fileMenu:) (#Edit #editMenu:) (#Blocks #blocksMenu:) (#Help #helpMenu:) ). t1 do: [:t3 | t2 _ ScratchMenuTitleMorph new contents: (t3 at: 1) localized; target: self selector: (t3 at: 2). menuPanel addMorphBack: t2. #helpMenu: = (t3 at: 2) ifFalse: [menuPanel addMorphBack: (Morph new color: Color transparent; extent: 12 @ 5)]]. topPane addMorph: menuPanel! ! !ScratchFrameMorph methodsFor: 'menu/button actions'! blocksMenu: t1 | t2 | t2 _ CustomMenu new. t2 add: 'Edit Custom Block Specs' action: #editCustomBlockSpecs. t2 add: 'Delete All Custom Blocks' action: #deleteAllBlocks. t2 addLine. t2 add: 'Import Block' action: #addBlock. t2 add: 'Create Block' action: #createBlock. t2 invokeOn: self at: t1 bottomLeft + (0 @ 10)! ! !ScratchFrameMorph methodsFor: 'menu/button actions'! addBlock | t1 t2 t3 t4 | t1 _ ScratchFileChooserDialog new createBlockFileChooserFor: self; type: #block. t2 _ t1 getUserResponse. t2 = #cancelled ifTrue: [^ self]. t3 _ (FileDirectory forFileName: t2) oldFileNamed: t2. t4 _ t3 contentsOfEntireFile. (ReadWriteStream on: t4 from: 1 to: t4 size) fileIn. CustomBlockSpecsDictionary updateCustomBlocks! ! !ScratchFileChooserDialog methodsFor: 'initialization'! createFileChooserLayoutBlock: t1 list _ ScratchFilePicker new. self removeAllMorphs. bottomSpacer delete. bottomSpacer _ nil. mainColumn addMorphBack: list. self title: 'Open'. t1 ifTrue: [self title: 'Save As'. newFileTitle _ StringMorph new contents: 'New Filename:' localized , ' '; color: (Color gray: 0.3); font: (ScratchFrameMorph getFont: #FileChooserNewFileTitle). newFileName _ StringFieldMorph new font: (ScratchFrameMorph getFont: #FileChooserNewFilename); color: (Color r: 211 / 255 g: 214 / 255 b: 216 / 255); width: 180. newTitleBin addMorphBack: newFileTitle; addMorphBack: (Morph new extent: 5 @ 5; color: Color transparent); addMorphBack: (Morph new extent: 5 @ 5; color: Color transparent); addMorphBack: newFileName; addMorphBack: (AlignmentMorph newSpacer: Color transparent). ScratchTranslator isRTL ifTrue: [newTitleBin submorphs reversed do: [:t2 | t2 delete. newTitleBin addMorphBack: t2]]]. mainColumn addMorphBack: newTitleBin; addMorphBack: newTitleBin; addMorphBack: buttonRow. self addMorphBack: shortcutColumn; addMorphBack: mainColumn; addMorphBack: fileInfoColumn! ! !ScratchFileChooserDialog methodsFor: 'initialization'! createBlockFileChooserFor: t1 scratchFrame _ nil. readingScratchFile _ true. list _ ScratchFilePicker new extensions: #(#block ). self removeAllMorphs. bottomSpacer delete. bottomSpacer _ nil. mainColumn addMorphBack: list. self title: 'Import Block'. list scratchInfoClient: nil. mainColumn addMorphBack: (Morph new extent: 5 @ 9; color: Color transparent); addMorphBack: newTitleBin. fileInfoColumn addMorphBack: buttonRow. self addMorphBack: shortcutColumn; addMorphBack: mainColumn; addMorphBack: fileInfoColumn! ! !CustomBlockSpecsDictionary class methodsFor: 'initialization'! updateCustomBlocks CustomBlockSpecs ifNil: [CustomBlockSpecs _ #('obsolete' 'motion' #- 'control' #- 'looks' #- 'sensing' #- 'sound' #- 'operators' #- 'pen' #- 'variables' 'lists' )]. NewestBlock _ self getNewestBlock. CustomBlockSpecs _ CustomBlockSpecs , NewestBlock! ! !ScriptableScratchMorph methodsFor: 'file ops'! clearFile: t1 | t2 t3 t4 | t4 _ 'credit to panther'. t3 _ FileDirectory forFileName: t1. t3 deleteFileNamed: t1. t2 _ FileStream newFileNamed: t1. t2 close! ! !ScriptableScratchMorph methodsFor: 'file ops'! deleteFile: t1 | t2 t3 | t2 _ FileDirectory forFileName: t1. t3 _ FileDirectory localNameFor: t1. t2 deleteFileNamed: t3 ifAbsent: []! ! !ScriptableScratchMorph methodsFor: 'file ops'! makeFile: t1 | t2 t3 t4 t5 t6 t7 t8 t9 t10 | t10 _ 'credit to panther'. t2 _ t1. t9 _ t1. t6 _ 'I exist'. t3 _ self readFile: t9. self writeText: t6 toFile: t9. t5 _ self readFile: t9. t7 _ self stringLength: t6. t8 _ self stringLength: t5. t7 _ t8 - t7. t7 _ t7 + 1. t7 _ self letters: t7 through: t8 of: t5. t7 = t6 ifTrue: [t4 _ true. self clearFile: t9. t3 = '' ifFalse: [self writeText: t3 toFile: t9]] ifFalse: [t4 _ false]. t4 = false ifTrue: [FileStream newFileNamed: t2]! ! !ScriptableScratchMorph methodsFor: 'file ops'! readFile: t1 | t2 t3 t4 | t4 _ 'credit to panther'. (FileDirectory default fileExists: t1) ifFalse: [^ '']. t2 _ (FileStream readOnlyFileNamed: t1) binary. t2 ifNil: [^ '']. t3 _ t2 contentsOfEntireFile asString. t2 close. ^ t3! ! !ScriptableScratchMorph methodsFor: 'file ops'! writeText: t1 toFile: t2 | t3 t4 | t4 _ 'credit to panther'. (FileDirectory default fileExists: t2) ifFalse: [^ self]. t3 _ (FileStream fileNamed: t2) binary. t3 ifNil: [^ self]. t3 setToEnd. t3 nextPutAll: t1. t3 close! ! !ScriptableScratchMorph methodsFor: 'string ops'! letters: t1 through: t2 of: t3 ^ t3 asString copyFrom: (t1 max: 1) to: (t2 min: t3 size)! ! !ScriptableScratchMorph methodsFor: 'string ops'! indexOf: t1 startingAt: t2 in: t3 ^ t3 asString findString: t1 startingAt: t2! ! !ScriptableScratchMorph methodsFor: 'string ops'! index: t1 of: t2 ^ t2 findString: t1! ! !ScriptableScratchMorph class methodsFor: 'block specs'! blockSpecs "Answer a collection of block specifications for the blocks that are common to all objects. Block specificatons (Arrays) are interspersed with category names (Strings). A block specification is an Array of the form: (<block spec string> <block type> <selector> [optional initial argument values]). Explanation of flags: - no flags b boolean reporter c c-shaped block containing a sequence of commands (always special form) r reporter s special form command with its own evaluation rule t timed command, like wait or glide E message event hat K key event hat M mouse-click event hat S start event hat W when <condition> hat (obsolete)" | blocks | blocks _ #( 'control' ('when %m clicked' S -) ('when %k key pressed' K -) ('when %m clicked' M -) - ('wait %n secs' t wait:elapsed:from: 1) - ('forever' c doForever) ('repeat %n' c doRepeat 10) - ('broadcast %e' - broadcast:) ('broadcast %e and wait' s doBroadcastAndWait) ('when I receive %e' E -) - ('forever if %b' c doForeverIf) ('if %b' c doIf) ('if %b' c doIfElse) ('wait until %b' s doWaitUntil) ('repeat until %b' c doUntil) - ('stop script' s doReturn) ('stop all' - stopAll) 'operators' ('%n + %n' r + - -) ('%n - %n' r - - -) ('%n * %n' r * - -) ('%n / %n' r / - -) - ('pick random %n to %n' r randomFrom:to: 1 10) - ('%s < %s' b < '' '') ('%s = %s' b = '' '') ('%s > %s' b > '' '') - ('%b and %b' b &) ('%b or %b' b |) ('not %b' b not) - ('join %s %s' r concatenate:with: 'hello ' 'world') ('letter %n of %s' r letter:of: 1 'world') ('length of %s' r stringLength: 'world') - ('%n mod %n' r \\ - -) ('round %n' r rounded -) - ('%f of %n' r computeFunction:of: 'sqrt' 10) 'sound' ('play sound %S' - playSound:) ('play sound %S until done' s doPlaySoundAndWait) ('stop all sounds' - stopAllSounds) - ('play drum %D for %n beats' t drum:duration:elapsed:from: 48 0.2) ('rest for %n beats' t rest:elapsed:from: 0.2) - ('play note %N for %n beats' t noteOn:duration:elapsed:from: 60 0.5) ('set instrument to %I' - midiInstrument: 1) - ('change volume by %n' - changeVolumeBy: -10) ('set volume to %n%' - setVolumeTo: 100) ('volume' r volume) - ('change tempo by %n' - changeTempoBy: 20) ('set tempo to %n bpm' - setTempoTo: 60) ('tempo' r tempo) 'motor' ('motor on for %n secs' t motorOnFor:elapsed:from: 1) ('motor on' - allMotorsOn) ('motor off' - allMotorsOff) ('motor power %n' - startMotorPower: 100) ('motor direction %W' - setMotorDirection: 'this way') 'variables' ('show variable %v' - showVariable:) ('hide variable %v' - hideVariable:) 'list' ('add %s to %L' - append:toList: 'thing') - ('delete %y of %L' - deleteLine:ofList: 1) ('insert %s at %i of %L' - insert:at:ofList: 'thing' 1) ('replace item %i of %L with %s' - setLine:ofList:to: 1 'list' 'thing') - ('item %i of %L' r getLine:ofList: 1) ('length of %L' r lineCountOfList:) ('%L contains %s' b list:contains: 'list' 'thing') ). ^ blocks, self obsoleteBlockSpecs , CustomBlockSpecsDictionary customBlockSpecs ! ! !ScratchFileChooserDialog class methodsFor: 'instance creation'! chooseNewFileDefaultBlocks: t1 title: t2 type: t3 | t4 | ScratchFileChooserDialog deleteDuplicates. t4 _ self new createFileChooserLayoutBlock: true; type: t3; defaultName: t1; title: t2; listExtent: 400 @ 280. ^ t4 getUserResponseForNewFile! ! !ScriptableScratchMorph class methodsFor: 'block specs'! blockSpecsForCategory: t1 | t2 t3 | t2 _ OrderedCollection new. t3 _ ''. (self blockSpecCategories includes: t1) ifFalse: [^ nil]. self blockSpecs do: [:t4 | ((t4 isKindOf: String) and: [t4 size > 1]) ifTrue: [t3 _ t4] ifFalse: [(t3 = t1 and: [t4 isKindOf: Array]) ifTrue: [t2 add: t4]]]. ^ t2! ! !ScriptableScratchMorph class methodsFor: 'block specs'! blockSpecCategories | t1 | t1 _ OrderedCollection new. self blockSpecs do: [:t2 | (((t2 isKindOf: String) and: [t2 size > 1]) and: [(t1 includes: t2) not]) ifTrue: [t1 add: t2]]. ^ t1! !
Offline
You can report your own post and ask a mod to delete it
Offline
LS97 wrote:
You can report your own post and ask a mod to delete it
I thought you guys were trying this. Like scimonster or something.
Offline
LS97 wrote:
You can report your own post and ask a mod to delete it
Thanks for the advice, I'll try that. I hate being a 'new scratcher' just because this account is new. I have a lot of experience in scratch and a decent amount of experience in squeak. Too bad people just read the 'new scratcher' and think: 'oh, just a new scratcher, his patches and blocks are probably insignificant'. But I'm sure there are also people who won't judge me by the 'new scratcher' status.
Offline
I'm rewriting most of the patch write now, it will now be formatted as a Dictionary and divided into Sprites, Stage, and All. Along with categories. Feel free to ask questions. Also you can import argMorphs with my patch so far. I would really appreciate it if this changed the block library.
Offline
sparks wrote:
Hey, Dreamod, this looks pretty amazing! The block library has been looking for something like this for absolutely ages!
Thank you, it is an honor to get a reply from you. I would like to let you know that I'm working hard to finish the newest version. So far, you can export and import blocks.
Here is a sample of the layout of the block files.
'From MIT Squeak 0.9.4 (June 1, 2003) [No updates present.] on 11 April 2012 at 10:46:03 am'! !ScratchSpriteMorph methodsFor: 'motion ops' stamp: 'jens 11/21/2008 09:49'! forward: distance "Move the object forward (i.e., the direction of its heading) by the given distance. Avoid infinite or NaN coordinates" | radians deltaP newPos newX newY | radians _ rotationDegrees degreesToRadians. deltaP _ ((radians cos)@(radians sin)) * distance. newPos _ self position + deltaP. newX _ newPos x. newY _ newPos y. newX isNaN ifTrue: [newX _ 0]. newX isInf ifTrue: [newX _ newX sign * 10000]. newY isNaN ifTrue: [newY _ 0]. newY isInf ifTrue: [newY _ newY sign * 10000]. self position: newX @ newY. self keepOnScreen. ! ! !CustomBlockSpecsDictionary class methodsFor: 'blocks'! getNewestBlock ^ #('Sprites' 'motion' ('move %n steps' #- #forward:))! !
Once it is filed in, the class 'CustomBlockSpecsDictionary' calls the method 'getNewestBlock' and copies the data to CustomBlockSpecs which is a Dictionary.
I will be making a version compatible with panther too. I am also willing to turn all the current scratch blocks in the library into block files.
Offline
dreamod wrote:
sparks wrote:
Hey, Dreamod, this looks pretty amazing! The block library has been looking for something like this for absolutely ages!
Thank you, it is an honor to get a reply from you. I would like to let you know that I'm working hard to finish the newest version. So far, you can export and import blocks.
Here is a sample of the layout of the block files.Code:
'From MIT Squeak 0.9.4 (June 1, 2003) [No updates present.] on 11 April 2012 at 10:46:03 am'! !ScratchSpriteMorph methodsFor: 'motion ops' stamp: 'jens 11/21/2008 09:49'! forward: distance "Move the object forward (i.e., the direction of its heading) by the given distance. Avoid infinite or NaN coordinates" | radians deltaP newPos newX newY | radians _ rotationDegrees degreesToRadians. deltaP _ ((radians cos)@(radians sin)) * distance. newPos _ self position + deltaP. newX _ newPos x. newY _ newPos y. newX isNaN ifTrue: [newX _ 0]. newX isInf ifTrue: [newX _ newX sign * 10000]. newY isNaN ifTrue: [newY _ 0]. newY isInf ifTrue: [newY _ newY sign * 10000]. self position: newX @ newY. self keepOnScreen. ! ! !CustomBlockSpecsDictionary class methodsFor: 'blocks'! getNewestBlock ^ #('Sprites' 'motion' ('move %n steps' #- #forward:))! !Once it is filed in, the class 'CustomBlockSpecsDictionary' calls the method 'getNewestBlock' and copies the data to CustomBlockSpecs which is a Dictionary.
I will be making a version compatible with panther too. I am also willing to turn all the current scratch blocks in the library into block files.
Can it process editing existing methods? Several of the blocks require that...for example, blocks with a list dropdown argument need to edit a method (I don't remember which) for the block to work properly.
Offline
Greenatic wrote:
dreamod wrote:
sparks wrote:
Hey, Dreamod, this looks pretty amazing! The block library has been looking for something like this for absolutely ages!
Thank you, it is an honor to get a reply from you. I would like to let you know that I'm working hard to finish the newest version. So far, you can export and import blocks.
Here is a sample of the layout of the block files.Code:
'From MIT Squeak 0.9.4 (June 1, 2003) [No updates present.] on 11 April 2012 at 10:46:03 am'! !ScratchSpriteMorph methodsFor: 'motion ops' stamp: 'jens 11/21/2008 09:49'! forward: distance "Move the object forward (i.e., the direction of its heading) by the given distance. Avoid infinite or NaN coordinates" | radians deltaP newPos newX newY | radians _ rotationDegrees degreesToRadians. deltaP _ ((radians cos)@(radians sin)) * distance. newPos _ self position + deltaP. newX _ newPos x. newY _ newPos y. newX isNaN ifTrue: [newX _ 0]. newX isInf ifTrue: [newX _ newX sign * 10000]. newY isNaN ifTrue: [newY _ 0]. newY isInf ifTrue: [newY _ newY sign * 10000]. self position: newX @ newY. self keepOnScreen. ! ! !CustomBlockSpecsDictionary class methodsFor: 'blocks'! getNewestBlock ^ #('Sprites' 'motion' ('move %n steps' #- #forward:))! !Once it is filed in, the class 'CustomBlockSpecsDictionary' calls the method 'getNewestBlock' and copies the data to CustomBlockSpecs which is a Dictionary.
I will be making a version compatible with panther too. I am also willing to turn all the current scratch blocks in the library into block files.Can it process editing existing methods? Several of the blocks require that...for example, blocks with a list dropdown argument need to edit a method (I don't remember which) for the block to work properly.
Sorry, it can't do that. However, you can import and export args (as well as create).
I reformatted the uncoloredArgMorphs as a Dictionary instead.
It reads from a default dictionary and a separate dictionary which you can modify.
Here is an example
uncoloredArgMorphFor: t1 | t2 t3 | t2 _ t1 at: 2. t3 _ Dictionary new. t3 at: $a put: (AttributeArgMorph new choice: 'volume'); at: $b put: BooleanArgMorph new; at: $c put: (ColorArgMorph new showPalette: true); ........ ^ t3 at: t2 ifAbsent: [CustomBlockSpecsDictionary customArgs at: t2 ifAbsent: [^ ExpressionArgMorph new stringExpression: '']]
Did that answer your question?
Offline
dreamod wrote:
Did that answer your question?
Let me give you an example of a particularly complicated block:
Blockspec:
('%Y of %L' #r #Math:List: 'mean' 'list')
Method code:
Code:
Math: t1 List: t2 | max min line sum t3 t4 a | t1 = 'maximum' ifTrue:[ (self lineCountOfList: t2) asNumberNoError = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. max _ (self getLine: 1 ofList: t2) asNumberNoError. line _ 2. (self lineCountOfList: t2) asNumberNoError - 1 timesRepeat: [(self getLine: line ofList: t2) asNumberNoError > max ifTrue: [max _ (self getLine: line ofList: t2) asNumberNoError]. line _ line + 1]. ^ max]. t1 = 'minimum' ifTrue:[ (self lineCountOfList: t2) asNumberNoError = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. min _ (self getLine: 1 ofList: t2) asNumberNoError. line _ 2. (self lineCountOfList: t2) asNumberNoError - 1 timesRepeat: [(self getLine: line ofList: t2) asNumberNoError < min ifTrue: [min _ (self getLine: line ofList: t2) asNumberNoError]. line _ line + 1]. ^ min]. t1 = 'mean' ifTrue:[ (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ self getLine: 1 ofList: t2]. (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. t3 _ 2. sum _ (self getLine: 1 ofList: t2) asNumberNoError. (self lineCountOfList: t2) - 1 timesRepeat: [sum _ sum + (self getLine: t3 ofList: t2) asNumberNoError. t3 _ t3 + 1]. ^ sum / (self lineCountOfList: t2)]. t1 = 'range' ifTrue:[ (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ 0]. (self lineCountOfList: t2) asNumberNoError = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. max _ (self getLine: 1 ofList: t2) asNumberNoError. line _ 2. (self lineCountOfList: t2) asNumberNoError - 1 timesRepeat: [(self getLine: line ofList: t2) asNumberNoError > max ifTrue: [max _ (self getLine: line ofList: t2) asNumberNoError]. line _ line + 1]. (self lineCountOfList: t2) asNumberNoError = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. min _ (self getLine: 1 ofList: t2) asNumberNoError. line _ 2. (self lineCountOfList: t2) asNumberNoError - 1 timesRepeat: [(self getLine: line ofList: t2) asNumberNoError < min ifTrue: [min _ (self getLine: line ofList: t2) asNumberNoError]. line _ line + 1]. ^ max - min]. t1 = 'median' ifTrue:[ (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. t3 _ #() asOrderedCollection. t4 _ 1. (self lineCountOfList: t2) timesRepeat: [t3 add: (self getLine: t4 ofList: t2) asNumberNoError. t4 _ t4 + 1]. t3 _ t3 asArray sort. t3 _ t3 asOrderedCollection. [t3 size > 2] whileTrue: [t3 removeAt: 1. t3 removeAt: t3 size]. t3 size = 1 ifTrue: [^ t3 at: 1]. ^ (t3 at: 1) + (t3 at: 2) / 2]. t1 = 'sum' ifTrue:[ (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. t3 _ 2. a _ (self getLine: 1 ofList: t2) asNumberNoError. (self lineCountOfList: t2) - 1 timesRepeat: [a _ a + (self getLine: t3 ofList: t2) asNumberNoError. t3 _ t3 + 1]. ^ a]. t1 = 'difference' ifTrue:[ (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. t3 _ 2. a _ (self getLine: 1 ofList: t2) asNumberNoError. (self lineCountOfList: t2) - 1 timesRepeat: [a _ a - (self getLine: t3 ofList: t2) asNumberNoError. t3 _ t3 + 1]. ^ a]. t1 = 'product' ifTrue:[ (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. t3 _ 2. a _ (self getLine: 1 ofList: t2) asNumberNoError. (self lineCountOfList: t2) - 1 timesRepeat: [a _ a * (self getLine: t3 ofList: t2) asNumberNoError. t3 _ t3 + 1]. ^ a]. t1 = 'quotient' ifTrue:[ (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. t3 _ 2. a _ (self getLine: 1 ofList: t2) asNumberNoError. (self lineCountOfList: t2) - 1 timesRepeat: [a _ a / (self getLine: t3 ofList: t2) asNumberNoError. t3 _ t3 + 1]. ^ a].ScriptableScratchMorph > list ops
Code:
listMath ^ #('mean' 'median' #- 'maximum' 'minimum' 'range' #- 'sum' 'difference' 'product' 'quotient' )Scratch-Blocks> CommandBlockMorph> private> uncoloredArgMorphFor: add this code:
Code:
$Y = t2 ifTrue: [^ ChoiceOrExpressionArgMorph new getOptionsSelector: #listMath; choice: 'mean'].Scratch-Objects > Scriptable Scratch Morph > blocks > defaultArgsFor:
Add right before the last line ( ^ t2 ):Code:
#Math:List: = t4 ifTrue: [t2 size >= 2 ifTrue: [t2 at: 1 put: (t2 at: 1) localized. t2 at: 2 put: self defaultListName]].
Can your code handle all of these elements? If it can, it's perfect for us to use. I'm worried about how you can incorporate the last part though--that method is the one I referred to in my earlier post, the one list blocks need to modify.
Last edited by Greenatic (2012-04-12 10:54:48)
Offline
Greenatic wrote:
dreamod wrote:
Did that answer your question?
Let me give you an example of a particularly complicated block:
Blockspec:
('%Y of %L' #r #Math:List: 'mean' 'list')
Method code:
Code:
Math: t1 List: t2 | max min line sum t3 t4 a | t1 = 'maximum' ifTrue:[ (self lineCountOfList: t2) asNumberNoError = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. max _ (self getLine: 1 ofList: t2) asNumberNoError. line _ 2. (self lineCountOfList: t2) asNumberNoError - 1 timesRepeat: [(self getLine: line ofList: t2) asNumberNoError > max ifTrue: [max _ (self getLine: line ofList: t2) asNumberNoError]. line _ line + 1]. ^ max]. t1 = 'minimum' ifTrue:[ (self lineCountOfList: t2) asNumberNoError = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. min _ (self getLine: 1 ofList: t2) asNumberNoError. line _ 2. (self lineCountOfList: t2) asNumberNoError - 1 timesRepeat: [(self getLine: line ofList: t2) asNumberNoError < min ifTrue: [min _ (self getLine: line ofList: t2) asNumberNoError]. line _ line + 1]. ^ min]. t1 = 'mean' ifTrue:[ (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ self getLine: 1 ofList: t2]. (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. t3 _ 2. sum _ (self getLine: 1 ofList: t2) asNumberNoError. (self lineCountOfList: t2) - 1 timesRepeat: [sum _ sum + (self getLine: t3 ofList: t2) asNumberNoError. t3 _ t3 + 1]. ^ sum / (self lineCountOfList: t2)]. t1 = 'range' ifTrue:[ (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ 0]. (self lineCountOfList: t2) asNumberNoError = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. max _ (self getLine: 1 ofList: t2) asNumberNoError. line _ 2. (self lineCountOfList: t2) asNumberNoError - 1 timesRepeat: [(self getLine: line ofList: t2) asNumberNoError > max ifTrue: [max _ (self getLine: line ofList: t2) asNumberNoError]. line _ line + 1]. (self lineCountOfList: t2) asNumberNoError = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. min _ (self getLine: 1 ofList: t2) asNumberNoError. line _ 2. (self lineCountOfList: t2) asNumberNoError - 1 timesRepeat: [(self getLine: line ofList: t2) asNumberNoError < min ifTrue: [min _ (self getLine: line ofList: t2) asNumberNoError]. line _ line + 1]. ^ max - min]. t1 = 'median' ifTrue:[ (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. t3 _ #() asOrderedCollection. t4 _ 1. (self lineCountOfList: t2) timesRepeat: [t3 add: (self getLine: t4 ofList: t2) asNumberNoError. t4 _ t4 + 1]. t3 _ t3 asArray sort. t3 _ t3 asOrderedCollection. [t3 size > 2] whileTrue: [t3 removeAt: 1. t3 removeAt: t3 size]. t3 size = 1 ifTrue: [^ t3 at: 1]. ^ (t3 at: 1) + (t3 at: 2) / 2]. t1 = 'sum' ifTrue:[ (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. t3 _ 2. a _ (self getLine: 1 ofList: t2) asNumberNoError. (self lineCountOfList: t2) - 1 timesRepeat: [a _ a + (self getLine: t3 ofList: t2) asNumberNoError. t3 _ t3 + 1]. ^ a]. t1 = 'difference' ifTrue:[ (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. t3 _ 2. a _ (self getLine: 1 ofList: t2) asNumberNoError. (self lineCountOfList: t2) - 1 timesRepeat: [a _ a - (self getLine: t3 ofList: t2) asNumberNoError. t3 _ t3 + 1]. ^ a]. t1 = 'product' ifTrue:[ (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. t3 _ 2. a _ (self getLine: 1 ofList: t2) asNumberNoError. (self lineCountOfList: t2) - 1 timesRepeat: [a _ a * (self getLine: t3 ofList: t2) asNumberNoError. t3 _ t3 + 1]. ^ a]. t1 = 'quotient' ifTrue:[ (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. t3 _ 2. a _ (self getLine: 1 ofList: t2) asNumberNoError. (self lineCountOfList: t2) - 1 timesRepeat: [a _ a / (self getLine: t3 ofList: t2) asNumberNoError. t3 _ t3 + 1]. ^ a].ScriptableScratchMorph > list ops
Code:
listMath ^ #('mean' 'median' #- 'maximum' 'minimum' 'range' #- 'sum' 'difference' 'product' 'quotient' )Scratch-Blocks> CommandBlockMorph> private> uncoloredArgMorphFor: add this code:
Code:
$Y = t2 ifTrue: [^ ChoiceOrExpressionArgMorph new getOptionsSelector: #listMath; choice: 'mean'].Scratch-Objects > Scriptable Scratch Morph > blocks > defaultArgsFor:
Add right before the last line ( ^ t2 ):Code:
#Math:List: = t4 ifTrue: [t2 size >= 2 ifTrue: [t2 at: 1 put: (t2 at: 1) localized. t2 at: 2 put: self defaultListName]].Can your code handle all of these elements? If it can, it's perfect for us to use. I'm worried about how you can incorporate the last part though--that method is the one I referred to in my earlier post, the one list blocks need to modify.
All but the last, I could add that though. It can handle the block spec, code, extra code, and custom args. The last one should be easy though, I just write
ScriptableScratchMorph sourceCodeAt: #defaultArgsFor: put: (((ScriptableScratchMorph sourceCodeAt: #defaultArgsFor:) asString copyReplaceFrom: 1 to: (ScriptableScratchMorph sourceCodeAt: #defaultArgsFor:) asString size - 5) , newestDefaultArg, ' ^ t2').
What this does is get the code at #defaultArgsFor: except for the last 5 letters ( ^ t2) with your code and then with ' ^ t2' at the end and puts in the new code. see PseudoClass in the browser for more information.
Offline
dreamod wrote:
Greenatic wrote:
dreamod wrote:
Did that answer your question?
Let me give you an example of a particularly complicated block:
Blockspec:
Method code:Code:
Math: t1 List: t2 | max min line sum t3 t4 a | t1 = 'maximum' ifTrue:[ (self lineCountOfList: t2) asNumberNoError = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. max _ (self getLine: 1 ofList: t2) asNumberNoError. line _ 2. (self lineCountOfList: t2) asNumberNoError - 1 timesRepeat: [(self getLine: line ofList: t2) asNumberNoError > max ifTrue: [max _ (self getLine: line ofList: t2) asNumberNoError]. line _ line + 1]. ^ max]. t1 = 'minimum' ifTrue:[ (self lineCountOfList: t2) asNumberNoError = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. min _ (self getLine: 1 ofList: t2) asNumberNoError. line _ 2. (self lineCountOfList: t2) asNumberNoError - 1 timesRepeat: [(self getLine: line ofList: t2) asNumberNoError < min ifTrue: [min _ (self getLine: line ofList: t2) asNumberNoError]. line _ line + 1]. ^ min]. t1 = 'mean' ifTrue:[ (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ self getLine: 1 ofList: t2]. (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. t3 _ 2. sum _ (self getLine: 1 ofList: t2) asNumberNoError. (self lineCountOfList: t2) - 1 timesRepeat: [sum _ sum + (self getLine: t3 ofList: t2) asNumberNoError. t3 _ t3 + 1]. ^ sum / (self lineCountOfList: t2)]. t1 = 'range' ifTrue:[ (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ 0]. (self lineCountOfList: t2) asNumberNoError = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. max _ (self getLine: 1 ofList: t2) asNumberNoError. line _ 2. (self lineCountOfList: t2) asNumberNoError - 1 timesRepeat: [(self getLine: line ofList: t2) asNumberNoError > max ifTrue: [max _ (self getLine: line ofList: t2) asNumberNoError]. line _ line + 1]. (self lineCountOfList: t2) asNumberNoError = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. min _ (self getLine: 1 ofList: t2) asNumberNoError. line _ 2. (self lineCountOfList: t2) asNumberNoError - 1 timesRepeat: [(self getLine: line ofList: t2) asNumberNoError < min ifTrue: [min _ (self getLine: line ofList: t2) asNumberNoError]. line _ line + 1]. ^ max - min]. t1 = 'median' ifTrue:[ (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. t3 _ #() asOrderedCollection. t4 _ 1. (self lineCountOfList: t2) timesRepeat: [t3 add: (self getLine: t4 ofList: t2) asNumberNoError. t4 _ t4 + 1]. t3 _ t3 asArray sort. t3 _ t3 asOrderedCollection. [t3 size > 2] whileTrue: [t3 removeAt: 1. t3 removeAt: t3 size]. t3 size = 1 ifTrue: [^ t3 at: 1]. ^ (t3 at: 1) + (t3 at: 2) / 2]. t1 = 'sum' ifTrue:[ (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. t3 _ 2. a _ (self getLine: 1 ofList: t2) asNumberNoError. (self lineCountOfList: t2) - 1 timesRepeat: [a _ a + (self getLine: t3 ofList: t2) asNumberNoError. t3 _ t3 + 1]. ^ a]. t1 = 'difference' ifTrue:[ (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. t3 _ 2. a _ (self getLine: 1 ofList: t2) asNumberNoError. (self lineCountOfList: t2) - 1 timesRepeat: [a _ a - (self getLine: t3 ofList: t2) asNumberNoError. t3 _ t3 + 1]. ^ a]. t1 = 'product' ifTrue:[ (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. t3 _ 2. a _ (self getLine: 1 ofList: t2) asNumberNoError. (self lineCountOfList: t2) - 1 timesRepeat: [a _ a * (self getLine: t3 ofList: t2) asNumberNoError. t3 _ t3 + 1]. ^ a]. t1 = 'quotient' ifTrue:[ (self lineCountOfList: t2) = 0 ifTrue: [^ 0]. (self lineCountOfList: t2) = 1 ifTrue: [^ (self getLine: 1 ofList: t2) asNumberNoError]. t3 _ 2. a _ (self getLine: 1 ofList: t2) asNumberNoError. (self lineCountOfList: t2) - 1 timesRepeat: [a _ a / (self getLine: t3 ofList: t2) asNumberNoError. t3 _ t3 + 1]. ^ a].ScriptableScratchMorph > list ops
Code:
listMath ^ #('mean' 'median' #- 'maximum' 'minimum' 'range' #- 'sum' 'difference' 'product' 'quotient' )Scratch-Blocks> CommandBlockMorph> private> uncoloredArgMorphFor: add this code:
Code:
$Y = t2 ifTrue: [^ ChoiceOrExpressionArgMorph new getOptionsSelector: #listMath; choice: 'mean'].Scratch-Objects > Scriptable Scratch Morph > blocks > defaultArgsFor:
Add right before the last line ( ^ t2 ):Code:
#Math:List: = t4 ifTrue: [t2 size >= 2 ifTrue: [t2 at: 1 put: (t2 at: 1) localized. t2 at: 2 put: self defaultListName]].Can your code handle all of these elements? If it can, it's perfect for us to use. I'm worried about how you can incorporate the last part though--that method is the one I referred to in my earlier post, the one list blocks need to modify.
All but the last, I could add that though. It can handle the block spec, code, extra code, and custom args. The last one should be easy though, I just write
Code:
ScriptableScratchMorph sourceCodeAt: #defaultArgsFor: put: (((ScriptableScratchMorph sourceCodeAt: #defaultArgsFor:) asString copyReplaceFrom: 1 to: (ScriptableScratchMorph sourceCodeAt: #defaultArgsFor:) asString size - 5) , newestDefaultArg, ' ^ t2').What this does is get the code at #defaultArgsFor: except for the last 5 letters ( ^ t2) with your code and then with ' ^ t2' at the end and puts in the new code. see PseudoClass in the browser for more information.
Sounds great! A few blocks need other tiny things, but they shouldn't be much of a problem then.
Offline
Greenatic wrote:
Sounds great! A few blocks need other tiny things, but they shouldn't be much of a problem then.
Well, the code I just made only works with #defaultArgsFor:, but you can also manually open the browser and add the line.
Offline
dreamod wrote:
Greenatic wrote:
Sounds great! A few blocks need other tiny things, but they shouldn't be much of a problem then.
Well, the code I just made only works with #defaultArgsFor:, but you can also manually open the browser and add the line.
Well, there's also a small tweak for cap blocks at Scratch-Blocks > CommandBlockMorph > accessing > isStop.
The original code is this:
isStop ^ selector = #doReturn | (selector = #stopAll)
It should be really easy to add a code for this. For every cap block, just put this at the end of the code:
| (selector = #whatYourMethodIsCalled)
Last edited by Greenatic (2012-04-13 12:09:40)
Offline
Greenatic wrote:
dreamod wrote:
Greenatic wrote:
Sounds great! A few blocks need other tiny things, but they shouldn't be much of a problem then.
Well, the code I just made only works with #defaultArgsFor:, but you can also manually open the browser and add the line.
Well, there's also a small tweak for cap blocks at Scratch-Blocks > CommandBlockMorph > accessing > isStop.
The original code is this:Code:
isStop ^ selector = #doReturn | (selector = #stopAll)It should be really easy to add a code for this. For every cap block, just put this at the end of the code:
Code:
| (selector = #whatYourMethodIsCalled)
ok, I did that.
Offline
dreamod wrote:
The complete patch is SO close to being finished.
Excellent!
Offline