diff --git a/.travis.yml b/.travis.yml
index 37a8c62da..e0b03ea4f 100644
--- a/.travis.yml
+++ b/.travis.yml
@@ -4,21 +4,12 @@ cache:
- $HOME/.gradle/caches/
- $HOME/.gradle/wrapper/dists/
before_install:
+ - mkdir -p /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734 && wget https://www.dropbox.com/s/c6xavx90x3n5aov/apache-flex-sdk-4.10.0-bin.zip?dl=1 -O /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/apache-flex-sdk-4.10.0-bin.zip && unzip /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/apache-flex-sdk-4.10.0-bin.zip -d /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734 && rm /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/apache-flex-sdk-4.10.0-bin.zip
- mkdir -p /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/ && wget http://sourceforge.net/projects/osmf.adobe/files/OSMF%201.0%20%28final%20source%2C%20ASDocs%2C%20PDF%20guides%2C%20and%20release%20notes%29/OSMF_1.0.zip/download -O /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/OSMF_1.0.zip
+ - unzip /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/OSMF_1.0.zip -d /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in && mv /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/in/OSMF.swc /home/travis/.gradle/gradleFx/sdks/77b6510675e9bf47142422c374af153591fe4734/frameworks/libs/osmf.swc
install:
- ./gradlew build -Ptarget=11.6
- ./gradlew build -Ptarget=10.2
script:
- ./gradlew check -Ptarget=11.6
- ./gradlew check -Ptarget=10.2
-notifications:
- slack:
- secure: TFnMix3WLFecQLMgmSIsUrnZUV7s5U7mJlzkfLrGU02u0uztjLcJr9qekg65I0wFtqGuMGAOfPAZo4hf0l5djzJTSUobLdlTpEunIEWd53IUZlljKCJQsVT8hfJtbjpIXMraLRLyTzDkXcRO3v2xthU30vsSI75sxQYufBx5/sU=
- format: text
- hipchat:
- rooms:
- secure: RP6i3+3IPgwkCj78UAjISXCv67RIU8u84OOAAcLT64pRoJ2aZvNo4ITlU28AVnRojO8V9JoXo/UBiTSTnNZsiL6LIqh1BScIE8lfIHLZ4pEqrvrjSmx56jT9jf3kttjjp00qaQ2QlpV7v9Dyg4GOvLRfOYTOhTSQTKgfWN+/dJA=
- template:
- - '%{repository}#%{build_number} (%{branch} - %{commit} : %{author}): %{message}
- (Details/Change view)'
- format: html
diff --git a/COPYING b/LICENSE
similarity index 100%
rename from COPYING
rename to LICENSE
diff --git a/Makefile b/Makefile
new file mode 100644
index 000000000..0e5162374
--- /dev/null
+++ b/Makefile
@@ -0,0 +1,26 @@
+go:
+ @echo Building Sharp...
+ @.\gradlew build
+ @echo Building complete
+
+all: go dev
+clean:
+ @del "build\11.6\*" /Q
+ @del "build\11.6dev\*" /Q
+ @rmdir build\11.6
+ @rmdir build\11.6dev
+dev:
+ @echo Building Sharp (Dev Mode)...
+ @.\gradlew build -Ptarget=11.6dev
+ @echo Building complete
+bleedingedge:
+ @echo Building Sharp (Bleeding Edge)...
+ @.\gradlew build -Ptarget=11.6be
+ @echo Building complete
+help:
+ @echo "nmake" for a shortcut for "nmake go"
+ @echo.
+ @echo "nmake go" to build Sharp
+ @echo "nmake dev" to build Sharp with dev mode
+ @echo "nmake all" to build Sharp normally and build Sharp with dev mode
+ @echo "nmake clean" to clean out the build directory
\ No newline at end of file
diff --git a/README.md b/README.md
index 7803febc6..75f5a86c5 100644
--- a/README.md
+++ b/README.md
@@ -1,73 +1,28 @@
-## Scratch 2.0 editor and player [](https://travis-ci.org/LLK/scratch-flash)
+# Sharp
+Sharp Scratch Mod by algmwc5 and Mrcomputer1
-#### Note: Scratch 2.0 is now in maintenance mode while the team focuses efforts on [Scratch 3.0](https://scratch.mit.edu/developers). While critical issues will be addressed please note that any feature requests or minor issues will not be reviewed until the next major release.
+[](https://gitter.im/SharpScratchMod/Sharp?utm_source=badge&utm_medium=badge&utm_campaign=pr-badge&utm_content=body_badge)
+[](https://travis-ci.org/SharpScratchMod/Sharp)
+[](https://github.com/SharpScratchMod/Sharp/releases/tag/v1.0.0-beta)
+[](https://github.com/SharpScratchMod/Sharp/blob/master/COPYING)
+[](https://git.mrcomputer1.tk/SharpScratchMod/Sharp)
----
+[Try it!](https://sharpscratchmod.github.io/editor/)
-This is the open source version of Scratch 2.0 and the core code for the official version found on http://scratch.mit.edu. This code has been released under the GPL version 2 license. Forks can be released under the GPL v2 or any later version of the GPL.
+[Scratch topic](https://scratch.mit.edu/discuss/topic/199192/)
-If you're interested in contributing to Scratch, please take a look at the issues on this repository. Two great ways of helping Scratch are by identifying bugs and documenting them as issues, or fixing issues and creating pull requests. When submitting pull requests please be patient -- the Scratch Team is very busy and it can take a while to find time to review them. The organization and class structures can't be radically changed without significant coordination and collaboration from the Scratch Team, so these types of changes should be avoided.
+[Offline Editor](https://sharpscratchmod.github.io/sharp-offline-downloads/publish.htm)
-It's been said that the Scratch Team spends about one hour of design discussion for every pixel in Scratch, but some think that estimate is a little low. While we welcome suggestions for new features in our suggestions forum (especially ones that come with mockups), we are unlikely to accept PRs with new features that we haven't deeply thought through. Why? Because we have a strong belief in the value of keeping things simple for new users. To learn more about our design philosophy, see this forum post, or this paper.
+Looking for the Scratch readme? https://github.com/SharpScratchMod/Sharp/blob/master/README_Scratch.md
-### Building
+##Versions
+WARNING: The listed dates are not final
-The Scratch 2.0 build process now uses [Gradle](http://gradle.org/) to simplify the process of acquiring dependencies: the necessary Flex SDKs will automatically be downloaded and cached for you. The [Gradle wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html) is included in this repository, but you will need a Java Runtime Environment or Java Development Kit in order to run Gradle; you can download either from Oracle's [Java download page](http://www.oracle.com/technetwork/java/javase/downloads/index.html). That page also contains guidance on whether to download the JRE or JDK.
-
-There are two versions of the Scratch 2.0 editor that can be built from this repository. See the following table to determine the appropriate command for each version. When building on Windows, replace `./gradlew` with `.\gradlew`.
-
-Required Flash version | Features | Command
---- | --- | ---
-11.6 or above | 3D-accelerated rendering | `./gradlew build -Ptarget=11.6`
-10.2 - 11.5 | Compatibility with older Flash (Linux, older OS X, etc.) | `./gradlew build -Ptarget=10.2`
-
-A successful build should look something like this (SDK download information omitted):
-
-```sh
-$ ./gradlew build -Ptarget=11.6
-Defining custom 'build' task when using the standard Gradle lifecycle plugins has been deprecated and is scheduled to be removed in Gradle 3.0
-Target is: 11.6
-Commit ID for scratch-flash is: e6df4f4
-:copyresources
-:compileFlex
-WARNING: The -library-path option is being used internally by GradleFx. Alternative: specify the library as a 'merged' Gradle dependendency
-:copytestresources
-:test
-Skipping tests since no tests exist
-:build
-
-BUILD SUCCESSFUL
-
-Total time: 13.293 secs
-```
-
-Upon completion, you should find your new SWF in the `build` subdirectory.
-
-```sh
-$ ls -R build
-build:
-10.2 11.6
-
-build/10.2:
-ScratchFor10.2.swf
-
-build/11.6:
-Scratch.swf
-```
-
-Please note that the Scratch trademarks (including the Scratch name, logo, Scratch Cat, and Gobo) are property of MIT. For use of these Marks, please see the [Scratch Trademark Policy](http://wiki.scratch.mit.edu/wiki/Scratch_1.4_Source_Code#Scratch_Trademark_Policy).
-
-### Debugging
-Here are a few integrated development environments available with Flash debugging support:
-* [Intellij IDEA](http://www.jetbrains.com/idea/features/flex_ide.html)
-* [Adobe Flash Builder](http://www.adobe.com/products/flash-builder.html)
-* [FlashDevelop](http://www.flashdevelop.org/)
-* [FDT for Eclipse](http://fdt.powerflasher.com/)
-
-It may be difficult to configure your IDE to use Gradle's cached version of the Flex SDK. To debug the Scratch 2.0 SWF with your own copy of the SDK you will need the [Flex SDK](http://flex.apache.org/) version 4.10+, and [playerglobal.swc files](http://helpx.adobe.com/flash-player/kb/archived-flash-player-versions.html#playerglobal) for Flash Player versions 10.2 and 11.4 added to the Flex SDK.
-
-After downloading ``playerglobal11_4.swc`` and ``playerglobal10_2.swc``, move them to ``/frameworks/libs/player//playerglobal.swc``. E.g., ``playerglobal11_4.swc`` should be located at ``/frameworks/libs/player/11.4/playerglobal.swc``.
-
-Consult your IDE's documentation to configure it for your newly-constructed copy of the Flex SDK.
-
-If the source is building but the resulting .swf is producing runtime errors, your first course of action should be to download version 4.11 of the Flex SDK and try targeting that. The Apache foundation maintains an [installer](http://flex.apache.org/installer.html) that lets you select a variety of versions.
+Version | Code Name | LTS | Released | Still supported | Supported until | Notes
+------------------ | ---------------- | --- | -------- | --------------- | --------------- | -----------------------------
+1.0.0 (Release) | Katana | NO | NO | --NOT YET-- | --NOT YET-- |
+1.0.0 Beta | Chainsaw | YES | YES | YES | January 1, 2017 |
+1.1.5 Alpha | Sawtooth | NO | YES | YES | --TBA-- |
+1.1.0 Alpha | Sawtooth | NO | YES | YES | --TBA-- |
+1.0.1 Alpha | Butterknife | NO | YES | YES | --TBA-- | Will replace 1.0.0 Alpha support
+1.0.0 Alpha | Butterknife | NO | YES | YES | 30 Oct 2016 |
diff --git a/README_Scratch.md b/README_Scratch.md
new file mode 100644
index 000000000..2145e7cf3
--- /dev/null
+++ b/README_Scratch.md
@@ -0,0 +1,71 @@
+## Scratch 2.0 editor and player [](https://travis-ci.org/LLK/scratch-flash)
+
+#### Note: Scratch 2.0 is now in maintenance mode while the team focuses efforts on [Scratch 3.0](https://scratch.mit.edu/developers). While critical issues will be addressed please note that any feature requests or minor issues will not be reviewed until the next major release.
+
+This is the open source version of Scratch 2.0 and the core code for the official version found on http://scratch.mit.edu. This code has been released under the GPL version 2 license. Forks can be released under the GPL v2 or any later version of the GPL.
+
+If you're interested in contributing to Scratch, please take a look at the issues on this repository. Two great ways of helping Scratch are by identifying bugs and documenting them as issues, or fixing issues and creating pull requests. When submitting pull requests please be patient -- the Scratch Team is very busy and it can take a while to find time to review them. The organization and class structures can't be radically changed without significant coordination and collaboration from the Scratch Team, so these types of changes should be avoided.
+
+It's been said that the Scratch Team spends about one hour of design discussion for every pixel in Scratch, but some think that estimate is a little low. While we welcome suggestions for new features in our suggestions forum (especially ones that come with mockups), we are unlikely to accept PRs with new features that we haven't deeply thought through. Why? Because we have a strong belief in the value of keeping things simple for new users. To learn more about our design philosophy, see this forum post, or this paper.
+
+### Building
+
+The Scratch 2.0 build process now uses [Gradle](http://gradle.org/) to simplify the process of acquiring dependencies: the necessary Flex SDKs will automatically be downloaded and cached for you. The [Gradle wrapper](https://docs.gradle.org/current/userguide/gradle_wrapper.html) is included in this repository, but you will need a Java Runtime Environment or Java Development Kit in order to run Gradle; you can download either from Oracle's [Java download page](http://www.oracle.com/technetwork/java/javase/downloads/index.html). That page also contains guidance on whether to download the JRE or JDK.
+
+There are two versions of the Scratch 2.0 editor that can be built from this repository. See the following table to determine the appropriate command for each version. When building on Windows, replace `./gradlew` with `.\gradlew`.
+
+Required Flash version | Features | Command
+--- | --- | ---
+11.6 or above | 3D-accelerated rendering | `./gradlew build -Ptarget=11.6`
+10.2 - 11.5 | Compatibility with older Flash (Linux, older OS X, etc.) | `./gradlew build -Ptarget=10.2`
+
+A successful build should look something like this (SDK download information omitted):
+
+```sh
+$ ./gradlew build -Ptarget=11.6
+Defining custom 'build' task when using the standard Gradle lifecycle plugins has been deprecated and is scheduled to be removed in Gradle 3.0
+Target is: 11.6
+Commit ID for scratch-flash is: e6df4f4
+:copyresources
+:compileFlex
+WARNING: The -library-path option is being used internally by GradleFx. Alternative: specify the library as a 'merged' Gradle dependendency
+:copytestresources
+:test
+Skipping tests since no tests exist
+:build
+
+BUILD SUCCESSFUL
+
+Total time: 13.293 secs
+```
+
+Upon completion, you should find your new SWF in the `build` subdirectory.
+
+```sh
+$ ls -R build
+build:
+10.2 11.6
+
+build/10.2:
+ScratchFor10.2.swf
+
+build/11.6:
+Scratch.swf
+```
+
+Please note that the Scratch trademarks (including the Scratch name, logo, Scratch Cat, and Gobo) are property of MIT. For use of these Marks, please see the [Scratch Trademark Policy](http://wiki.scratch.mit.edu/wiki/Scratch_1.4_Source_Code#Scratch_Trademark_Policy).
+
+### Debugging
+Here are a few integrated development environments available with Flash debugging support:
+* [Intellij IDEA](http://www.jetbrains.com/idea/features/flex_ide.html)
+* [Adobe Flash Builder](http://www.adobe.com/products/flash-builder.html)
+* [FlashDevelop](http://www.flashdevelop.org/)
+* [FDT for Eclipse](http://fdt.powerflasher.com/)
+
+It may be difficult to configure your IDE to use Gradle's cached version of the Flex SDK. To debug the Scratch 2.0 SWF with your own copy of the SDK you will need the [Flex SDK](http://flex.apache.org/) version 4.10+, and [playerglobal.swc files](http://helpx.adobe.com/flash-player/kb/archived-flash-player-versions.html#playerglobal) for Flash Player versions 10.2 and 11.4 added to the Flex SDK.
+
+After downloading ``playerglobal11_4.swc`` and ``playerglobal10_2.swc``, move them to ``/frameworks/libs/player//playerglobal.swc``. E.g., ``playerglobal11_4.swc`` should be located at ``/frameworks/libs/player/11.4/playerglobal.swc``.
+
+Consult your IDE's documentation to configure it for your newly-constructed copy of the Flex SDK.
+
+If the source is building but the resulting .swf is producing runtime errors, your first course of action should be to download version 4.11 of the Flex SDK and try targeting that. The Apache foundation maintains an [installer](http://flex.apache.org/installer.html) that lets you select a variety of versions.
diff --git a/TRADEMARK_POLICY b/TRADEMARK_POLICY.md
similarity index 100%
rename from TRADEMARK_POLICY
rename to TRADEMARK_POLICY.md
diff --git a/build.bat b/build.bat
new file mode 100644
index 000000000..3014747ea
--- /dev/null
+++ b/build.bat
@@ -0,0 +1,3 @@
+@echo off
+gradlew.bat build
+pause
diff --git a/config.groovy b/config.groovy
index 7b99d3aff..952f3404d 100644
--- a/config.groovy
+++ b/config.groovy
@@ -1,18 +1,42 @@
environments {
+ '11.6be' {
+ output = 'SharpBleedingEdge'
+ playerVersion = '11.6'
+ additionalCompilerOptions = [
+ "-swf-version=19",
+ "-define+=SCRATCH::allow3d,true",
+ "-define+=SHARP::bleedingEdge,true",
+ "-define+=SHARP::builtWithDevMode,false",
+ ]
+ }
+ '11.6dev' {
+ output = 'SharpDev'
+ playerVersion = '11.6'
+ additionalCompilerOptions = [
+ "-swf-version=19",
+ "-define+=SCRATCH::allow3d,true",
+ "-define+=SHARP::builtWithDevMode,true",
+ "-define+=SHARP::bleedingEdge,false",
+ ]
+ }
'11.6' {
- output = 'Scratch'
+ output = 'Sharp'
playerVersion = '11.6'
additionalCompilerOptions = [
"-swf-version=19",
"-define+=SCRATCH::allow3d,true",
+ "-define+=SHARP::builtWithDevMode,false",
+ "-define+=SHARP::bleedingEdge,false",
]
}
'10.2' {
- output = 'ScratchFor10.2'
+ output = 'SharpFor10.2'
playerVersion = '10.2'
additionalCompilerOptions = [
"-swf-version=11",
"-define+=SCRATCH::allow3d,false",
+ "-define+=SHARP::builtWithDevMode,false",
+ "-define+=SHARP::bleedingEdge,false",
]
}
}
diff --git a/package.json b/package.json
index 860d58f59..6a822e56c 100644
--- a/package.json
+++ b/package.json
@@ -1,8 +1,8 @@
{
- "name": "Scratch",
+ "name": "Sharp",
"description": "Open source version of the Scratch 2.0 project editor.",
"version": "1.0.0",
- "homepage": "http://scratch.mit.edu/",
+ "homepage": "sharpscratchmod.cf",
"main": "scratch-flash",
"license": "GPL-2.0",
"repository": {
diff --git a/scratch.gradle b/scratch.gradle
index 29f045236..c82156016 100644
--- a/scratch.gradle
+++ b/scratch.gradle
@@ -42,7 +42,7 @@ def scratchFlashCommitID = getCommitID(commonDir)
println "Commit ID for scratch-flash is: ${scratchFlashCommitID}"
dependencies {
- flexSDK group: 'org.apache', name: 'apache-flex-sdk', version: '4.15.0', ext: 'zip'
+ flexSDK group: 'org.apache', name: 'apache-flex-sdk', version: '4.14.1', ext: 'zip'
external group: 'macromedia.com', name: 'playerglobal', version: playerVersion.replace('.', '_'), ext: 'swc'
merged files(
"${commonDir}/libs/as3corelib.swc",
diff --git a/src/CSS.as b/src/CSS.as
index 2c49f2164..3cef09576 100644
--- a/src/CSS.as
+++ b/src/CSS.as
@@ -28,6 +28,8 @@ package {
public class CSS {
+ //To add a value for Sharp Bleeding Edge replace the color code with "!Scratch.app.bleedingEdge ? (old color code) : (new color code)"
+
public static function topBarColor():int { return Scratch.app.isExtensionDevMode ? topBarColor_ScratchX : topBarColor_default; }
public static function backgroundColor():int { return Scratch.app.isExtensionDevMode ? backgroundColor_ScratchX : backgroundColor_default; }
@@ -37,8 +39,8 @@ public class CSS {
// Colors
public static const white:int = 0xFFFFFF;
- public static const backgroundColor_default:int = white;
- public static const topBarColor_default:int = 0x9C9EA2;
+ public static const backgroundColor_default:int = !Scratch.app.bleedingEdge ? white : 0xa6a6a6;
+ public static const topBarColor_default:int = !Scratch.app.bleedingEdge ? 0x9C9EA2 : 0x333333;
public static const tabColor:int = 0xE6E8E8;
public static const panelColor:int = 0xF2F2F2;
public static const itemSelectedColor:int = 0xD0D0D0;
diff --git a/src/Scratch.as b/src/Scratch.as
index 3314b6219..cf7127733 100644
--- a/src/Scratch.as
+++ b/src/Scratch.as
@@ -42,6 +42,8 @@ import flash.net.LocalConnection;
import flash.net.URLLoader;
import flash.net.URLLoaderDataFormat;
import flash.net.URLRequest;
+import flash.net.navigateToURL;
+import flash.net.SharedObject;
import flash.system.*;
import flash.text.*;
import flash.utils.*;
@@ -72,10 +74,103 @@ import util.*;
import watchers.ListWatcher;
+import com.adobe.crypto.SHA256;
+
public class Scratch extends Sprite {
// Version
- public static const versionString:String = 'v458.0.1';
+ public static const versionString:String = 'Beta 1.0.0 (Katana) : Scratch v458.0.1' + (SHARP::builtWithDevMode ? " : Sharp Developer Mode Active" : "") + (SHARP::bleedingEdge ? " : BLEEDING EDGE" : "");
public static var app:Scratch; // static reference to the app, used for debugging
+ // Sharp Developer Menu
+ // *------------------------------------*
+ // | We won't say the password! You will|
+ // | have to change the password or |
+ // | edit the code to gain access to thi|
+ // |s menu |
+ // *------------------------------------*
+ public var builtWithDevMode:Boolean = SHARP::builtWithDevMode;
+ public var bleedingEdge:Boolean = SHARP::bleedingEdge;
+ public var devMode:Boolean = false;
+ public var devModePassword:String = "99625b7abd0d05c32905b9aa67c9e6cb7e19ead8dc16d0caf5d372a8441dbd34";
+
+ // Sharp settings store
+ public var sharpSettings:SharedObject;
+ private var sharpSettingsVersion:int = 3;
+ private function initSettings():void{
+ if(!sharpSettings.data.hasOwnProperty("_settingsVersion")){
+ trace("Creating default setting values");
+ sharpSettings.data._settingsVersion = sharpSettingsVersion;
+ sharpSettings.data.allowSound = true;
+ sharpSettings.data.alwaysTurboMode = false;
+ sharpSettings.data.hackMode = true;
+ sharpSettings.data.cloneLimit = 300;
+ sharpSettings.data.restoreScratchShowHide = false;
+ saveSettings();
+ }else{
+ updateSettings();
+ }
+ prepareSettings();
+ }
+ private function prepareSettings():void{
+ if(sharpSettings.data.alwaysTurboMode){
+ toggleTurboMode();
+ }
+ reloadSettings();
+ }
+ public function reloadSettings():void{
+ // Reload "Restore Scratch show/hide Blocks" setting.
+ var showFound:Boolean = false;
+ var hideFound:Boolean = false;
+ var shouldBeVisible:Boolean = sharpSettings.data.restoreScratchShowHide;
+ for(var i = 0; i < Specs.commands.length; i++){
+ if(Specs.commands[i][3] == "show"){
+ Specs.commands[i][2] = shouldBeVisible ? 2 : 98;
+ showFound = true;
+ }else if(Specs.commands[i][3] == "hide"){
+ Specs.commands[i][2] = shouldBeVisible ? 2 : 98;
+ hideFound = true;
+ }
+ if(showFound && hideFound) break;
+ }
+ updatePalette();
+ }
+ public function saveSettings():void{
+ sharpSettings.flush();
+ }
+ public function resetSettings():void{
+ sharpSettings.clear();
+ saveSettings();
+ exitSharp();
+ }
+ public function updateSettings():void{
+ if(sharpSettings.data._settingsVersion != sharpSettingsVersion){
+ /*if(sharpSettings.data._settingsVersion == (version to update from)){
+ trace("Updating settings from " + sharpSettings.data._settingsVersion + " to (version to update to)");
+ // do updates
+ trace("Updated!");
+ }*/
+ if(sharpSettings.data._settingsVersion == 2){
+ trace("Updating settings from " + sharpSettings.data._settingsVersion + " to 3");
+ sharpSettings.data.restoreScratchShowHide = false;
+ sharpSettings.data._settingsVersion = 3;
+ saveSettings();
+ trace("Updated!");
+ }
+ if(sharpSettings.data._settingsVersion == 1){
+ trace("Updating settings from " + sharpSettings.data._settingsVersion + " to 2");
+ sharpSettings.data.hackMode = true;
+ sharpSettings.data._settingsVersion = 2;
+ saveSettings();
+ trace("Updated!");
+ }
+ updateSettings(); //Runs to see if there are more updates
+ }
+ }
+
+ // Tasks
+ public var turboModeIsActive:Boolean = false;
+ public function exitSharp():void{
+ fscommand("quit");
+ }
// Display modes
public var hostProtocol:String = 'http';
@@ -90,6 +185,7 @@ public class Scratch extends Sprite {
public var ignoreResize:Boolean = false; // If true, temporarily ignore resize events.
public var isExtensionDevMode:Boolean = false; // If true, run in extension development mode (as on ScratchX)
public var isMicroworld:Boolean = false;
+ public var isFullScreen:Boolean = false;
public var presentationScale:Number;
@@ -112,6 +208,7 @@ public class Scratch extends Sprite {
private var lastTab:String = 'scripts';
protected var wasEdited:Boolean; // true if the project was edited and autosaved
private var _usesUserNameBlock:Boolean = false;
+ private var _usesHTTPBlock:Boolean = false;
protected var languageChanged:Boolean; // set when language changed
// UI Elements
@@ -125,10 +222,10 @@ public class Scratch extends Sprite {
// UI Parts
public var libraryPart:LibraryPart;
- protected var topBarPart:TopBarPart;
- protected var stagePart:StagePart;
+ public var topBarPart:TopBarPart; //was protected
+ public var stagePart:StagePart; //was protected
private var tabsPart:TabsPart;
- protected var scriptsPart:ScriptsPart;
+ public var scriptsPart:ScriptsPart; //was protected
public var imagesPart:ImagesPart;
public var soundsPart:SoundsPart;
public const tipsBarClosedWidth:int = 17;
@@ -162,7 +259,7 @@ public class Scratch extends Sprite {
}
protected function initialize():void {
- isOffline = !URLUtil.isHttpURL(loaderInfo.url);
+ isOffline = (loaderInfo.parameters['asPlayer'] != 'true'); // !URLUtil.isHttpURL(loaderInfo.url)
hostProtocol = URLUtil.getProtocol(loaderInfo.url);
isExtensionDevMode = (loaderInfo.parameters['extensionDevMode'] == 'true');
@@ -170,6 +267,8 @@ public class Scratch extends Sprite {
checkFlashVersion();
initServer();
+
+ sharpSettings = SharedObject.getLocal("SharpScratchModSettings");
stage.align = StageAlign.TOP_LEFT;
stage.scaleMode = StageScaleMode.NO_SCALE;
@@ -212,8 +311,13 @@ public class Scratch extends Sprite {
setEditMode(startInEditMode());
// install project before calling fixLayout()
- if (editMode) runtime.installNewProject();
- else runtime.installEmptyProject();
+ if(loaderInfo.parameters.hasOwnProperty("sharp_pid")){
+ var p:* = loaderInfo.parameters;
+ runtime.loadProjectFromURL(p['sharp_domain'] + p['sharp_save_path'] + p['sharp_pid'] + p['sharp_save_format'], p);
+ }else{
+ if (editMode) runtime.installNewProject();
+ else runtime.installEmptyProject();
+ }
fixLayout();
//Analyze.collectAssets(0, 119110);
@@ -221,6 +325,9 @@ public class Scratch extends Sprite {
//Analyze.countMissingAssets();
handleStartupParameters();
+
+ initSettings();
+ if(isOffline) DialogBox.notify("Welcome to Sharp!", "Website: http://SharpScratchMod.cf\nGitHub: https://github.com/SharpScratchMod/Sharp\n\nCredits:\nalgmwc5 - Developer, Owner\nMrcomputer1 - Developer, Owner\nscratchyone - Developer\n\nOther important credits:\nNoMod-Programming - Custom reporters");
}
protected function handleStartupParameters():void {
@@ -240,6 +347,8 @@ public class Scratch extends Sprite {
addExternalCallback('ASloadGithubURL', loadGithubURL);
addExternalCallback('ASloadBase64SBX', loadBase64SBX);
addExternalCallback('ASsetModalOverlay', setModalOverlay);
+ }else{
+ addExternalCallback('ASloadGithubURL', loadGithubURL);
}
}
@@ -550,7 +659,7 @@ public class Scratch extends Sprite {
public function strings():Array {
return [
'a copy of the project file on your computer.',
- 'Project not saved!', 'Save now', 'Not saved; project did not load.',
+ 'Project not saved!', 'Save now', 'Not saved; project didn\'t load.',
'Save project?', 'Don\'t save',
'Save now', 'Saved',
'Revert', 'Undo Revert', 'Reverting...',
@@ -611,6 +720,16 @@ public class Scratch extends Sprite {
_usesUserNameBlock = value;
stagePart.refresh();
}
+
+ public function get usesHTTPBlock():Boolean {
+ return _usesHTTPBlock;
+ }
+
+ public function set usesHTTPBlock(value:Boolean):void {
+ _usesHTTPBlock = value;
+ stagePart.refresh();
+ }
+
public function updatePalette(clearCaches:Boolean = true):void {
// Note: updatePalette() is called after changing variable, list, or procedure
@@ -644,11 +763,13 @@ public class Scratch extends Sprite {
setEditMode(false);
if (jsEnabled) externalCall('tip_bar_api.hide');
}
+ isFullScreen = true;
} else {
if (wasEditing) {
setEditMode(true);
if (jsEnabled) externalCall('tip_bar_api.show');
}
+ isFullScreen = false;
}
if (isOffline) {
stage.displayState = enterPresentation ? StageDisplayState.FULL_SCREEN_INTERACTIVE : StageDisplayState.NORMAL;
@@ -1063,10 +1184,125 @@ public class Scratch extends Sprite {
m.showOnStage(stage, b.x, topBarPart.bottom() - 1);
}
+ public function showHelpMenu(b:*):void {
+ var m:Menu = new Menu(null, 'Help', CSS.topBarColor(), 28);
+
+ addHelpMenuItems(b, m);
+
+ m.showOnStage(stage, b.x, topBarPart.bottom() - 1);
+ }
+
+ public function showDevMenu(b:*):void{
+ var m:Menu = new Menu(null, 'Dev', CSS.topBarColor(), 28);
+
+ function devModeLogin():void{
+ var d:DialogBox = new DialogBox(done);
+ function done():void{
+ var hash:String = SHA256.hash(d.getField("Password"));
+ if(hash == devModePassword){
+ devMode = true;
+ DialogBox.notify("Sharp Developer Mode",
+ "You are now logged in to Sharp Developer Mode!");
+ }else{
+ DialogBox.notify("Sharp Developer Mode",
+ "Wrong Password! :(");
+ }
+ }
+ d.addTitle("Sharp Developer Mode");
+ d.addText("Please enter the Sharp Developer Password");
+ d.addField("Password", 120, "", true);
+ d.setPasswordField("Password");
+ d.addButton("Login Now", d.accept);
+ d.addButton("Cancel", d.cancel);
+ d.showOnStage(stage);
+ }
+
+ if(!devMode){
+
+ m.addItem("Login to dev mode", devModeLogin);
+
+ }else addDevMenuItems(b, m);
+
+ m.showOnStage(stage, b.x, topBarPart.bottom() - 1);
+ }
+
public function stopVideo(b:*):void {
runtime.stopVideo();
}
+
+ public function sharpStrings(){
+ return [
+ "Credits", "*Owner, # Non-Sharp Member",
+ "Based on Scratch 2.0 from the MIT Media Lab",
+ "Sharp Scratch mod by DrKat123, Mrcomputer1 and some others",
+ "About Sharp", "Report a bug", "Credits", "About"
+ ];
+ }
+
+ protected function addDevMenuItems(b:*, m:Menu):void {
+ function devMenuAboutBuild(){
+ DialogBox.notify("Sharp Developer Menu",
+ "Sharp Version: " + versionString.replace(" : Sharp Developer Mode Active", "") + "\n" +
+ "Host Protocol: " + hostProtocol + "\n" +
+ "Is in 3d: " + isIn3D + "\n" +
+ "Is ARM CPU: " + isArmCPU + "\n" +
+ "JS Enabled: " + jsEnabled + "\n" +
+ "Extension Dev Mode: " + isExtensionDevMode + "\n" +
+ "Uses Username Block: " + usesUserNameBlock + "\n" +
+ "Uses HTTP Block: " + usesHTTPBlock + "\n" +
+ "Turbo Mode is Active: " + turboModeIsActive + "\n" +
+ "Built with dev mode: " + SHARP::builtWithDevMode + "\n" +
+ "Build with allow3d: " + SCRATCH::allow3d);
+ }
+ function devMenuLogout(){
+ devMode = false;
+ DialogBox.notify("Sharp Developer Menu",
+ "You have been logged out!");
+ }
+ m.addItem("About this build", devMenuAboutBuild);
+ m.addItem("Logout of dev mode", devMenuLogout);
+ m.addLine();
+ m.addItem("Tutorial: Editor Map", Tutorial.editorMap);
+ }
+
+ protected function addHelpMenuItems(b:*, m:Menu):void {
+ function helpMenuItemCredits(){
+ DialogBox.notify("Credits", Translator.map("*Owner, # Non-Sharp Member") + "\n\nDrKat123*, Mrcomputer1*, scratchyone\n\nNoMod-Programming#");
+ }
+ function helpMenuItemReportBug(){
+ DialogBox.reportBugDialog();
+ }
+ function helpMenuItemAbout(){
+ var aboutMsg:String = "Scratch\n" +
+ Translator.map("Based on Scratch 2.0 from the MIT Media Lab") + "\n" +
+ "\n" +
+ Translator.map("Scratch is developed by the Lifelong Kindergarten Group at the MIT Media Lab") + "\n" +
+ "\n" +
+ "https://scratch.mit.edu - https://github.com/llk/scratch-flash\n" +
+ "\n" +
+ "\n" +
+ "--------------------" +
+ "\n" +
+ "\n" +
+ "Sharp\n" +
+ Translator.map("Sharp Scratch mod by DrKat123, Mrcomputer1 and some others") + "\n" +
+ "https://sharpscratchmod.github.io\n" +
+ versionString;
+ DialogBox.notify(Translator.map("About Sharp"), aboutMsg);
+ }
+ m.addItem(Translator.map('Report a bug'), helpMenuItemReportBug);
+ m.addLine();
+ m.addItem(Translator.map('Credits'), helpMenuItemCredits);
+ m.addItem(Translator.map('About'), helpMenuItemAbout);
+ if(b.lastEvent.shiftKey){
+ m.addLine();
+ m.addItem("Export blocks (commands.txt)", TranslatableStrings.exportCommands);
+ m.addItem("Export ui strings (uiStrings.txt)", TranslatableStrings.exportUIStrings);
+ }
+ }
+ public var fullscreenEditor:Boolean = false;
+
protected function addFileMenuItems(b:*, m:Menu):void {
m.addItem('Load Project', runtime.selectProjectFile);
m.addItem('Save Project', exportProjectToFile);
@@ -1082,6 +1318,8 @@ public class Scratch extends Sprite {
m.addLine();
m.addItem('Revert', revertToOriginalProject);
}
+ m.addLine();
+ m.addItem("Settings", DialogBox.settingsDialog);
if (b.lastEvent.shiftKey) {
m.addLine();
@@ -1199,7 +1437,7 @@ public class Scratch extends Sprite {
public function exportProjectToFile(fromJS:Boolean = false, saveCallback:Function = null):void {
function squeakSoundsConverted():void {
scriptsPane.saveScripts(false);
- var projectType:String = extensionManager.hasExperimentalExtensions() ? '.sbx' : '.sb2';
+ var projectType:String = extensionManager.hasExperimentalExtensions() ? '.sharpx' : '.sharp';
var defaultName:String = StringUtil.trim(projectName());
defaultName = ((defaultName.length > 0) ? defaultName : 'project') + projectType;
var zipData:ByteArray = projIO.encodeProjectAsZipFile(stagePane);
@@ -1246,6 +1484,7 @@ public class Scratch extends Sprite {
public function toggleTurboMode():void {
interp.turboMode = !interp.turboMode;
+ turboModeIsActive = !turboModeIsActive;
stagePart.refresh();
}
@@ -1642,5 +1881,10 @@ public class Scratch extends Sprite {
args.splice(1, 0, returnValueCallback);
externalCall.apply(this, args);
}
+
+ // SHARP LIBRARY SYSTEM
+ public function importLibrary(id:String){
+ DialogBox.notify("Hi!", "Imported " + id);
+ }
}
}
diff --git a/src/Specs.as b/src/Specs.as
index 489aa51e7..b8a1f1f59 100644
--- a/src/Specs.as
+++ b/src/Specs.as
@@ -22,8 +22,8 @@
//
// This file defines the command blocks and categories.
// To add a new command:
-// a. add a specification for the new command to the commands array
-// b. add a primitive for the new command to the interpreter
+//a. add a specification for the new command to the commands array
+//b. add a primitive for the new command to the interpreter
package {
import flash.display.Bitmap;
@@ -36,6 +36,8 @@ public class Specs {
public static const CHANGE_VAR:String = "changeVar:by:";
public static const GET_LIST:String = "contentsOfList:";
public static const CALL:String = "call";
+ public static const CALL_BOOLEAN:String = "callb";
+ public static const CALL_NUMBER:String = "callr";
public static const PROCEDURE_DEF:String = "procDef";
public static const GET_PARAM:String = "getParam";
@@ -72,6 +74,9 @@ public class Specs {
[10, "More Blocks", procedureColor],
[11, "Parameter", parameterColor],
[12, "List", listColor],
+ [13, "HTTP", 0x55af40],
+ [14, "Files", 0x333399],
+ [15, "Miscellaneous", 0x657b32],
[20, "Extension", extensionsColor],
];
@@ -105,6 +110,7 @@ public class Specs {
if (name == "stop") icon = Resources.createBmp('stopIcon');
if (name == "turnLeft") icon = Resources.createBmp('turnLeftIcon');
if (name == "turnRight") icon = Resources.createBmp('turnRightIcon');
+ if (name == "rabbit") icon = Resources.createBmp('rabbit');
if (icon != null) icon.scaleX = icon.scaleY = 0.5;
return icon;
}
@@ -142,8 +148,11 @@ public class Specs {
["think %s for %n secs", " ", 2, "think:duration:elapsed:from:", "Hmm...", 2],
["think %s", " ", 2, "think:", "Hmm..."],
["-"],
- ["show", " ", 2, "show"],
- ["hide", " ", 2, "hide"],
+ ["show %m.spriteOnly", " ", 2, "showSprite", "_myself_"],
+ ["hide %m.spriteOnly", " ", 2, "hideSprite", "_myself_"],
+ ["-"],
+ ["scratch show", " ", 98, "show"],//This block is hidden by default, but shown by the "Restore Scratch show/hide Blocks" option
+ ["scratch hide", " ", 98, "hide"],//This block is hidden by default, but shown by the "Restore Scratch show/hide Blocks" option
["-"],
["switch costume to %m.costume", " ", 2, "lookLike:", "costume1"],
["next costume", " ", 2, "nextCostume"],
@@ -164,6 +173,9 @@ public class Specs {
["size", "r", 2, "scale"],
// stage looks
+ ["show %m.spriteNotSelf", " ", 102, "showStage", "Sprite1"],
+ ["hide %m.spriteNotSelf", " ", 102, "hideStage", "Sprite1"],
+ ["-"],
["switch backdrop to %m.backdrop", " ", 102, "startScene", "backdrop1"],
["switch backdrop to %m.backdrop and wait", " ", 102, "startSceneAndWait", "backdrop1"],
["next backdrop", " ", 102, "nextScene"],
@@ -230,6 +242,9 @@ public class Specs {
["broadcast %m.broadcast and wait", " ", 5, "doBroadcastAndWait", ""],
// control - sprite
+ ["// %s", " ", 6, "inlineComment:", "My comment"],
+ ["%s", "c", 6, "codeSection", "My code section"],
+ ["-"],
["wait %n secs", " ", 6, "wait:elapsed:from:", 1],
["-"],
["repeat %n", "c", 6, "doRepeat", 10],
@@ -239,6 +254,7 @@ public class Specs {
["if %b then", "e", 6, "doIfElse"],
["wait until %b", " ", 6, "doWaitUntil"],
["repeat until %b", "c", 6, "doUntil"],
+ ["for each %m.var in %s", "c", 6, "doForLoop", "v", 10],
["-"],
["stop %m.stop", "f", 6, "stopScripts", "all"],
["-"],
@@ -246,8 +262,14 @@ public class Specs {
["create clone of %m.spriteOnly", " ", 6, "createCloneOf"],
["delete this clone", "f", 6, "deleteClone"],
["-"],
+ ["counter", "r", 6, "COUNT"],
+ ["clear counter", " ", 6, "CLR_COUNT"],
+ ["incr counter", " ", 6, "INCR_COUNT"],
// control - stage
+ ["// %s", " ", 106, "inlineComment:", "My comment"],
+ ["%s", "c", 106, "codeSection", "My code section"],
+ ["-"],
["wait %n secs", " ", 106, "wait:elapsed:from:", 1],
["-"],
["repeat %n", "c", 106, "doRepeat", 10],
@@ -257,10 +279,15 @@ public class Specs {
["if %b then", "e", 106, "doIfElse"],
["wait until %b", " ", 106, "doWaitUntil"],
["repeat until %b", "c", 106, "doUntil"],
+ ["for each %m.var in %s", "c", 106, "doForLoop", "v", 10],
["-"],
["stop %m.stop", "f", 106, "stopScripts", "all"],
["-"],
["create clone of %m.spriteOnly", " ", 106, "createCloneOf"],
+ ["-"],
+ ["counter", "r", 106, "COUNT"],
+ ["clear counter", " ", 106, "CLR_COUNT"],
+ ["incr counter", " ", 106, "INCR_COUNT"],
// sensing
["touching %m.touching?", "b", 7, "touching:", "_mouse_"],
@@ -271,11 +298,24 @@ public class Specs {
["ask %s and wait", " ", 7, "doAsk", "What's your name?"],
["answer", "r", 7, "answer"],
["-"],
+ ["password hash %s", "r", 7, "passwordHash:", ""],
+ ["password verify hash %s with %s", "b", 7, "passwordVerify:", ""],
+ ["password needs rehash %s?", "b", 7, "passwordRehash:", ""],
+ ["-"],
+ ["notify %s title %s", " ", 7, "notify:", "Hi!", "Hello!"],
+ ["ask %s with dialog %s", " ", 7, "askBox:", "What's your name?", "IDK"],
+ ["confirm %s", " ", 7, "confirm:", "Is Mrcomputer1 awesome?"],
+ ["-"],
["key %m.key pressed?", "b", 7, "keyPressed:", "space"],
["mouse down?", "b", 7, "mousePressed"],
["mouse x", "r", 7, "mouseX"],
["mouse y", "r", 7, "mouseY"],
["-"],
+ ["is in editor?", "b", 7, "isInEditor:"],
+ ["is in fullscreen?", "b", 7, "isInFullscreen:"],
+ ["using turbo mode?", "b", 7, "usingTurboMode:"],
+ ["Sharp version", "r", 7, "sharpVersion:"],
+ ["-"],
["loudness", "r", 7, "soundLevel"],
["-"],
["video %m.videoMotionType on %m.stageOrThis", "r", 7, "senseVideoMotion", "motion"],
@@ -289,17 +329,35 @@ public class Specs {
["-"],
["current %m.timeAndDate", "r", 7, "timeAndDate", "minute"],
["days since 2000", "r", 7, "timestamp"],
- ["username", "r", 7, "getUserName"],
+ //["username", "r", 7, "getUserName"]
+
+ //----
+ //NOTE:
+ //The username block is disabled temporarily, until the sharp-www is released and is functioning properly
+ //----
// stage sensing
["ask %s and wait", " ", 107, "doAsk", "What's your name?"],
["answer", "r", 107, "answer"],
["-"],
+ ["password hash %s", "r", 107, "passwordHash:", ""],
+ ["password verify hash %s with %s", "b", 107, "passwordVerify:", ""],
+ ["password needs rehash %s?", "b", 107, "passwordRehash:", ""],
+ ["-"],
+ ["notify %s title %s", " ", 107, "notify:", "Hi!", "Hello!"],
+ ["ask %s with dialog %s", " ", 107, "askBox:", "What's your name?", "IDK"],
+ ["confirm %s", " ", 107, "confirm:", "Is Mrcomputer1 awesome?"],
+ ["-"],
["key %m.key pressed?", "b", 107, "keyPressed:", "space"],
["mouse down?", "b", 107, "mousePressed"],
["mouse x", "r", 107, "mouseX"],
["mouse y", "r", 107, "mouseY"],
["-"],
+ ["is in editor?", "b", 107, "isInEditor:"],
+ ["is in fullscreen?", "b", 107, "isInFullscreen:"],
+ ["using turbo mode?", "b", 107, "usingTurboMode:"],
+ ["Sharp version", "r", 107, "sharpVersion:"],
+ ["-"],
["loudness", "r", 107, "soundLevel"],
["-"],
["video %m.videoMotionType on %m.stageOrThis", "r", 107, "senseVideoMotion", "motion", "Stage"],
@@ -313,13 +371,14 @@ public class Specs {
["-"],
["current %m.timeAndDate", "r", 107, "timeAndDate", "minute"],
["days since 2000", "r", 107, "timestamp"],
- ["username", "r", 107, "getUserName"],
+ //["username", "r", 107, "getUserName"],
// operators
["%n + %n", "r", 8, "+", "", ""],
["%n - %n", "r", 8, "-", "", ""],
["%n * %n", "r", 8, "*", "", ""],
["%n / %n", "r", 8, "/", "", ""],
+ ["%n ^ %n", "r", 8, "power:of:", "", ""],
["-"],
["pick random %n to %n", "r", 8, "randomFrom:to:", 1, 10],
["-"],
@@ -329,16 +388,41 @@ public class Specs {
["-"],
["%b and %b", "b", 8, "&"],
["%b or %b", "b", 8, "|"],
- ["not %b", "b", 8, "not"],
- ["-"],
- ["join %s %s", "r", 8, "concatenate:with:", "hello ", "world"],
- ["letter %n of %s", "r", 8, "letter:of:", 1, "world"],
- ["length of %s", "r", 8, "stringLength:", "world"],
+ ["not %b", "b", 8, "~"],
+ ["%b nand %b", "b", 8, "nand"],
+ ["%b nor %b", "b", 8, "nor"],
+ //why the heck is NOR commented...
+ ["%b xor %b", "b", 8, "xor"],
+ ["%b xnor %b", "b", 8, "xnor"],
+ ["true", "b", 8, "true"],
+ ["false", "b", 8, "false"],
["-"],
["%n mod %n", "r", 8, "%", "", ""],
["round %n", "r", 8, "rounded", ""],
["-"],
["%m.mathOp of %n", "r", 8, "computeFunction:of:", "sqrt", 9],
+ ["digital root of %n", "r", 8, "digitalRootOf:", "1234"],
+ ["the constant %m.constantName", "r", 8, "chooseConstant:", "Pi"],
+ [" %n !", "r", 8, "factorialOf:", 5],
+ ["%n th Fibonacci number", "r", 8, "nthFibonacci:", 10],
+ ["-"],
+ ["join %s %s", "r", 8, "concatenate:with:", "hello ", "world"],
+ ["letter %n of %s", "r", 8, "letter:of:", 1, "world"],
+ ["length of %s", "r", 8, "stringLength:", "world"],
+ ["reverse %s", "r", 8, "reverseString:", "hello"],
+ ["replace %s in %s with %s", "r", 8, "blockReplace:", "Hi", "Hi", "Hello"],
+ ["split %s at %s and return to %m.list"," ", 8, "blockSplit:", "H i", " ", ""],
+ ["split %s at %s and return %n", "r", 8, "blockSplitReturn:", "H i", " ", 1],
+ ["split %s from letter %n to %n", "r", 8, "splitStringFrom:", "Foobar", "1", "3"],
+ //bitwise
+ ["-"],
+ ["%n & %n", "r", 8, "bitwiseAnd:", "1", "2"],
+ ["%n | %n", "r", 8, "bitwiseOr:", "1", "2"],
+ ["%n XOR %n", "r", 8, "bitwiseXor:", "1", "2"],
+ ["~ %n", "r", 8, "bitwiseNot:", "1", "2"],
+ ["%n << %n", "r", 8, "bitwiseLeftShift:", "2", "10"],
+ ["%n >> %n", "r", 8, "bitwiseRightShift:", "2", "10"],
+ //["%n >>> %n", "r", 8, "bitwiseUnsignedShift:", "2", "10"],
// variables
["set %m.var to %s", " ", 9, SET_VAR],
@@ -360,6 +444,28 @@ public class Specs {
["show list %m.list", " ", 12, "showList:"],
["hide list %m.list", " ", 12, "hideList:"],
+ // custom blocks
+ ["report %s", "f", 10, "report", ""],
+
+ // Sharp
+ // --HTTP--
+ ["%m.httpMethod %s", " ", 13, "httpBlock:", "GET", "https://api.scratch.mit.edu"],
+ ["http return", "r", 13, "httpReturn:"],
+ ["go to %s", " ", 13, "goToURL:"],
+ // --Files--
+ ["save %s to file %s", " ", 14, "saveFile:", ":)", "smileface.txt"],
+ ["load file", " ", 14, "loadFile:"],
+ ["loaded file name", "r", 14, "loadedFileName:"],
+ ["loaded file data", "r", 14, "loadedFileData:"],
+ ["loaded/saved?", "b", 14, "fileLoaded:"],
+ ["failed?", "b", 14, "fileLoadFailed:"],
+ ["failure reason", "r", 14, "fileLoadFailReason:"],
+ //--MISCELLANEOUS--
+ ["base64 encode %s", "r", 15, "b64encode:", "abcd"],
+
+
+ // Scratch
+
// obsolete blocks from Scratch 1.4 that may be used in older projects
["play drum %n for %n beats", " ", 98, "drum:duration:elapsed:from:", 1, 0.25], // Scratch 1.4 MIDI drum
["set instrument to %n", " ", 98, "midiInstrument:", 1],
@@ -373,13 +479,15 @@ public class Specs {
["switch to background %m.costume", " ", 98, "showBackground:", "backdrop1"],
["next background", " ", 98, "nextBackground"],
["forever if %b", "cf",98, "doForeverIf"],
+
+ // obsolete blocks from Official Scratch that may be used in older Sharp/current Scratch projects
// testing and experimental control prims
["noop", "r", 99, "COUNT"],
- ["counter", "r", 99, "COUNT"],
- ["clear counter", " ", 99, "CLR_COUNT"],
- ["incr counter", " ", 99, "INCR_COUNT"],
- ["for each %m.varName in %s", "c", 99, "doForLoop", "v", 10],
+ //["counter", "r", 6, "COUNT"],
+ //["clear counter", " ", 6, "CLR_COUNT"],
+ //["incr counter", " ", 6, "INCR_COUNT"],
+ //["for each %m.varName in %s", "c", 99, "doForLoop", "v", 10],
["while %b", "c", 99, "doWhile"],
["all at once", "c", 99, "warpSpeed"],
diff --git a/src/Tutorial.as b/src/Tutorial.as
new file mode 100644
index 000000000..b93c0e56a
--- /dev/null
+++ b/src/Tutorial.as
@@ -0,0 +1,226 @@
+/*
+ * Sharp Project Editor and Player
+ * Copyright (C) 2016 Sharp Scratch Mod
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+// Tutorial.as
+// Mrcomputer1, August 2016
+//
+// The tutorial's code
+
+package {
+ import uiwidgets.*;
+ import flash.display.*;
+
+public class Tutorial {
+
+ private static var stage:Stage = Scratch.app.stage;
+
+ public static function editorMap():void{
+
+ var box:TutorialDoBox = new TutorialDoBox(
+ "Welcome to Sharp!\nLet's look at the editor!",
+ (stage.stageWidth - 190)/2, (stage.stageHeight - 100)/2);
+ function next18():void{
+ box = new TutorialDoBox(
+ "This is the block categories.",
+ Scratch.app.scriptsPart.selector.x+40,
+ Scratch.app.scriptsPart.selector.y+40
+ );
+ box.addButton("Next", null);
+ box.addButton("End Tutorial", null, 70);
+ box.showOnStage(stage, false);
+ }
+ function next17():void{
+ box = new TutorialDoBox(
+ "This is where all your\nsprites are listed!",
+ Scratch.app.libraryPart.x+40,
+ Scratch.app.libraryPart.y+40
+ );
+ box.addButton("Next", next18);
+ box.addButton("End Tutorial", null, 70);
+ box.showOnStage(stage, false);
+ }
+ function next16():void{
+ box = new TutorialDoBox(
+ "This is the XY location\nof the mouse pointer",
+ Scratch.app.stagePart.yReadout.x+40,
+ Scratch.app.stagePart.yReadout.y+40
+ );
+ box.addButton("Next", next17);
+ box.addButton("End Tutorial", null, 70);
+ box.showOnStage(stage, true);
+ }
+ function next15():void{
+ box = new TutorialDoBox(
+ "This is the Stop Sign!\nIt stops all the scripts\nrunning in the project",
+ Scratch.app.stagePart.stopButton.x+40,
+ Scratch.app.stagePart.stopButton.y+40
+ );
+ box.addButton("Next", next16);
+ box.addButton("End Tutorial", null, 70);
+ box.showOnStage(stage, true);
+ }
+ function next14():void{
+ box = new TutorialDoBox(
+ "This is the Green Flag!\nIt runs the project!",
+ Scratch.app.stagePart.runButton.x+40,
+ Scratch.app.stagePart.runButton.y+40
+ );
+ box.addButton("Next", next15);
+ box.addButton("End Tutorial", null, 70);
+ box.showOnStage(stage, true);
+ }
+ function next13():void{
+ box = new TutorialDoBox(
+ "This is fullscreen button\nClick it to toggle fullscreen\nBelow it is the Sharp\nversion information",
+ Scratch.app.stagePart.fullscreenButton.x+40,
+ Scratch.app.stagePart.fullscreenButton.y+40
+ );
+ box.addButton("Next", next14);
+ box.addButton("End Tutorial", null, 70);
+ box.showOnStage(stage, true);
+ }
+ function next12():void{
+ box = new TutorialDoBox(
+ "This is the stage\nIt is where your sprites\nare shown",
+ Scratch.app.stagePart.x+40,
+ Scratch.app.stagePart.y+40
+ );
+ box.addButton("Next", next13);
+ box.addButton("End Tutorial", null, 70);
+ box.showOnStage(stage, false);
+ }
+ function next11():void{
+ var box12:TutorialDoBox = new TutorialDoBox(
+ "That is all for the top bar\nNext is the layout of the\nmain editor!",
+ Scratch.app.topBarPart.helpTool.x+40,
+ Scratch.app.topBarPart.helpTool.y+10
+ );
+ box12.addButton("Next", next12);
+ box12.addButton("End Tutorial", null, 70);
+ box12.showOnStage(stage, false);
+ }
+ function next10():void{
+ var box11:TutorialDoBox = new TutorialDoBox(
+ "This button does nothing at\nthis time\nJust ignore it!",
+ Scratch.app.topBarPart.helpTool.x+20,
+ Scratch.app.topBarPart.helpTool.y+10
+ );
+ box11.addButton("Next", next11);
+ box11.addButton("End Tutorial", null, 70);
+ box11.showOnStage(stage, true);
+ }
+ function next9():void{
+ var box10:TutorialDoBox = new TutorialDoBox(
+ "You can use this to make\na sprite or costume smaller",
+ Scratch.app.topBarPart.shrinkTool.x+20,
+ Scratch.app.topBarPart.shrinkTool.y+10
+ );
+ box10.addButton("Next", next10);
+ box10.addButton("End Tutorial", null, 70);
+ box10.showOnStage(stage, true);
+ }
+ function next8():void{
+ var box9:TutorialDoBox = new TutorialDoBox(
+ "You can use this to make\na sprite or costume bigger",
+ Scratch.app.topBarPart.growTool.x+20,
+ Scratch.app.topBarPart.growTool.y+10
+ );
+ box9.addButton("Next", next9);
+ box9.addButton("End Tutorial", null, 70);
+ box9.showOnStage(stage, true);
+ }
+ function next7():void{
+ var box8:TutorialDoBox = new TutorialDoBox(
+ "You can use this to delete\na sprite or something else",
+ Scratch.app.topBarPart.cutTool.x+20,
+ Scratch.app.topBarPart.cutTool.y+10
+ );
+ box8.addButton("Next", next8);
+ box8.addButton("End Tutorial", null, 70);
+ box8.showOnStage(stage, true);
+ }
+ function next6():void{
+ var box7:TutorialDoBox = new TutorialDoBox(
+ "You can use this to get\nmore of a sprite or something\nelse",
+ Scratch.app.topBarPart.copyTool.x+20,
+ Scratch.app.topBarPart.copyTool.y+10
+ );
+ box7.addButton("Next", next7);
+ box7.addButton("End Tutorial", null, 70);
+ box7.showOnStage(stage, true);
+ }
+ function next5():void{
+ var box6:TutorialDoBox = new TutorialDoBox(
+ "In the Help menu you can\nreport bugs and see credits\nbut that is about it!",
+ Scratch.app.topBarPart.helpMenu.x+40,
+ Scratch.app.topBarPart.helpMenu.y+10
+ );
+ box6.addButton("Next", next6);
+ box6.addButton("End Tutorial", null, 70);
+ box6.showOnStage(stage, true);
+ }
+ function next4():void{
+ var box5:TutorialDoBox = new TutorialDoBox(
+ "In the Edit menu you can\nundelete something and change\nthe colours of blocks",
+ Scratch.app.topBarPart.editMenu.x+40,
+ Scratch.app.topBarPart.editMenu.y+10
+ );
+ box5.addButton("Next", next5);
+ box5.addButton("End Tutorial", null, 70);
+ box5.showOnStage(stage, true);
+ }
+ function next3():void{
+ var box4:TutorialDoBox = new TutorialDoBox(
+ "This is the File menu\nYou can save, load and create\na new project from it\nYou can also record the project",
+ Scratch.app.topBarPart.fileMenu.x+40,
+ Scratch.app.topBarPart.fileMenu.y+10
+ );
+ box4.addButton("Next", next4);
+ box4.addButton("End Tutorial", null, 70);
+ box4.showOnStage(stage, true);
+ }
+ function next2():void{
+ var box3:TutorialDoBox = new TutorialDoBox(
+ "This is the language menu!\nYou can change what language\neverything is shown in\nTheir aren't many languages yet",
+ Scratch.app.topBarPart.languageButton.x+20,
+ Scratch.app.topBarPart.languageButton.y+10
+ );
+ box3.addButton("Next", next3);
+ box3.addButton("End Tutorial", null, 70);
+ box3.showOnStage(stage, true);
+ }
+ function next1():void{
+ var box2:TutorialDoBox = new TutorialDoBox(
+ "This is the top bar!\nYou can do a lot of stuff with\nit",
+ Scratch.app.topBarPart.x+100, Scratch.app.topBarPart.y+20
+ );
+ box2.addButton("Next", next2);
+ box2.addButton("End Tutorial", null, 70);
+ box2.showOnStage(stage, false);
+ }
+ box.addButton("Next", next1);
+ box.addButton("End Tutorial", null, 70);
+ box.showOnStage(stage, false);
+
+ }
+
+}
+
+
+}
\ No newline at end of file
diff --git a/src/assets/Resources.as b/src/assets/Resources.as
index 4652b494b..09ca19611 100644
--- a/src/assets/Resources.as
+++ b/src/assets/Resources.as
@@ -74,12 +74,14 @@ public class Resources {
[Embed(source='fonts/MysteryQuest-Regular.ttf', fontName='Mystery', embedAsCFF = 'false', advancedAntiAliasing = 'true')] private static const Font4:Class;
[Embed(source='fonts/PermanentMarker.ttf', fontName='Marker', embedAsCFF = 'false', advancedAntiAliasing = 'true')] private static const Font5:Class;
[Embed(source='fonts/Scratch.ttf', fontName='Scratch', embedAsCFF = 'false', advancedAntiAliasing = 'true')] private static const Font6:Class;
-
+ [Embed(source='fonts/Inconsolata-Regular.ttf', fontName='Inconsolata', embedAsCFF='false', advancedAntiAliasing='true')] private static const Font7:Class;
+
// Block Icons (2x resolution to look better when scaled)
[Embed(source='blocks/flagIcon.png')] private static const flagIcon:Class;
[Embed(source='blocks/stopIcon.png')] private static const stopIcon:Class;
[Embed(source='blocks/turnLeftIcon.png')] private static const turnLeftIcon:Class;
[Embed(source='blocks/turnRightIcon.png')] private static const turnRightIcon:Class;
+ [Embed(source='blocks/rabbit.png')] private static const rabbit:Class;
// Cursors
[Embed(source='cursors/copyCursor.png')] private static const copyCursor:Class;
diff --git a/src/assets/blocks/rabbit.png b/src/assets/blocks/rabbit.png
new file mode 100644
index 000000000..95a20e531
Binary files /dev/null and b/src/assets/blocks/rabbit.png differ
diff --git a/src/assets/fonts/Inconsolata-Regular.ttf b/src/assets/fonts/Inconsolata-Regular.ttf
new file mode 100644
index 000000000..bbc964755
Binary files /dev/null and b/src/assets/fonts/Inconsolata-Regular.ttf differ
diff --git a/src/assets/sprite1A.svg b/src/assets/sprite1A.svg
new file mode 100644
index 000000000..ddedc982f
--- /dev/null
+++ b/src/assets/sprite1A.svg
@@ -0,0 +1,10 @@
+
\ No newline at end of file
diff --git a/src/assets/sprite1B.svg b/src/assets/sprite1B.svg
new file mode 100644
index 000000000..23129fb3d
--- /dev/null
+++ b/src/assets/sprite1B.svg
@@ -0,0 +1,10 @@
+
\ No newline at end of file
diff --git a/src/blocks/Block.as b/src/blocks/Block.as
index 561953a23..bc183fe5a 100644
--- a/src/blocks/Block.as
+++ b/src/blocks/Block.as
@@ -40,6 +40,8 @@ import flash.events.*;
import flash.filters.GlowFilter;
import flash.geom.*;
import flash.net.URLLoader;
+import flash.net.URLRequest;
+import flash.net.navigateToURL;
import flash.text.*;
import scratch.*;
@@ -64,16 +66,18 @@ public class Block extends Sprite {
private static var useEmbeddedFont:Boolean = false;
public static var MenuHandlerFunction:Function; // optional function to handle block and blockArg menus
-
+
public var spec:String;
public var type:String;
public var op:String = "";
public var opFunction:Function;
+ public var isSpecialOp:Boolean = false;
public var args:Array = [];
public var defaultArgValues:Array = [];
public var parameterIndex:int = -1; // cache of parameter index, used by GET_PARAM block
public var parameterNames:Array; // used by procedure definition hats; null for other blocks
public var warpProcFlag:Boolean; // used by procedure definition hats to indicate warp speed
+ public var procedureType:String; // used by procedure definition hats; " ", "r", or "b"
public var rightToLeft:Boolean;
public var isHat:Boolean = false;
@@ -131,16 +135,16 @@ public class Block extends Sprite {
if ((type == " ") || (type == "") || (type == "w")) {
base = new BlockShape(BlockShape.CmdShape, color);
indentTop = 3;
- } else if (type == "b") {
- base = new BlockShape(BlockShape.BooleanShape, color);
+ } else if (type == "b" || type == "ob") {
+ base = new BlockShape(type == "ob" ? BlockShape.BooleanOutlineShape : BlockShape.BooleanShape, color);
isReporter = true;
forceAsync = Scratch.app.extensionManager.shouldForceAsync(op);
isRequester = forceAsync;
indentLeft = 9;
indentRight = 7;
- } else if (type == "r" || type == "R") {
- this.type = 'r';
- base = new BlockShape(BlockShape.NumberShape, color);
+ } else if (type == "r" || type == "R" || type == "or") {
+ this.type = type == "or" ? 'or' : 'r';
+ base = new BlockShape(type == "or" ? BlockShape.NumberOutlineShape : BlockShape.NumberShape, color);
isReporter = true;
forceAsync = (type == 'r') && Scratch.app.extensionManager.shouldForceAsync(op);
isRequester = (type == 'R') || forceAsync;
@@ -167,7 +171,7 @@ public class Block extends Sprite {
base = new BlockShape(BlockShape.FinalCmdShape, color);
isTerminal = true;
indentTop = 5;
- } else if (type == "o") { // cmd outline for proc definition
+ } else if (type == "o" || type == "o ") { // cmd outline for proc definition
base = new BlockShape(BlockShape.CmdOutlineShape, color);
base.filters = []; // no bezel
indentTop = 3;
@@ -182,7 +186,7 @@ public class Block extends Sprite {
addEventListener(FocusEvent.KEY_FOCUS_CHANGE, focusChange);
}
-
+
public function setSpec(newSpec:String, defaultArgs:Array = null):void {
for each (var o:DisplayObject in labelsAndArgs) {
if (o.parent != null) o.parent.removeChild(o);
@@ -282,7 +286,7 @@ public class Block extends Sprite {
// Create a block representing a procedure declaration to be embedded in a
// procedure definition header block. For each formal parameter, embed a
// reporter for that parameter.
- var b:Block = new Block(spec, "o", Specs.procedureColor, 'proc_declaration');
+ var b:Block = new Block(spec, "o" + procedureType, Specs.procedureColor, 'proc_declaration');
if (!parameterNames) parameterNames = [];
for (var i:int = 0; i < parameterNames.length; i++) {
var argType:String = (typeof(defaultArgValues[i]) == 'boolean') ? 'b' : 'r';
@@ -489,7 +493,7 @@ public class Block extends Sprite {
for (i = 0; i < labelsAndArgs.length; i++) {
item = labelsAndArgs[i];
// Next line moves the argument of if and if-else blocks right slightly:
- if ((i == 1) && !(argTypes[i] == 'label')) x = Math.max(x, 30);
+ if (!isReporter && i == 1 && !(argTypes[i] == 'label')) x = Math.max(x, 30);
item.x = x;
maxH = Math.max(maxH, item.height);
x += item.width + 2;
@@ -503,7 +507,7 @@ public class Block extends Sprite {
if ((item is BlockArg) && (!BlockArg(item).numberType)) item.y += 1;
}
- if ([' ', '', 'o'].indexOf(type) >= 0) x = Math.max(x, minCommandWidth); // minimum width for command blocks
+ if ([' ', '', 'o ', 'o'].indexOf(type) >= 0) x = Math.max(x, minCommandWidth); // minimum width for command blocks
if (['c', 'cf', 'e'].indexOf(type) >= 0) x = Math.max(x, minLoopWidth); // minimum width for C and E blocks
if (['h'].indexOf(type) >= 0) x = Math.max(x, minHatWidth); // minimum width for hat blocks
if (elseLabel) x = Math.max(x, indentLeft + elseLabel.width + 2);
@@ -582,6 +586,8 @@ public class Block extends Sprite {
dup.parameterNames = parameterNames;
dup.defaultArgValues = defaultArgValues;
dup.warpProcFlag = warpProcFlag;
+ dup.procedureType = procedureType;
+ //DialogBox.notify("", newSpec + ":" + type + ":" + op + ":" + procedureType);
if (forClone) {
dup.copyArgsForClone(args);
} else {
@@ -839,10 +845,15 @@ public class Block extends Sprite {
if ('cut' == tool) deleteStack();
}
if (tool == 'help') showHelp();
+ if (tool == "showSpec") showSpec();
}
+ public function showSpec(){
+ DialogBox.notify("Block Spec Information", "Spec: " + this.spec + "\n" + "OP Code: " + this.op + "\nType: " + this.type);
+ }
+
public function showHelp():void {
- var extName:String = ExtensionManager.unpackExtensionName(op);
+ /*var extName:String = ExtensionManager.unpackExtensionName(op);
if (extName) {
if (Scratch.app.extensionManager.isInternal(extName)) {
Scratch.app.showTip('ext:' + extName);
@@ -856,6 +867,28 @@ public class Block extends Sprite {
}
else {
Scratch.app.showTip(op);
+ }*/
+ /*
+ // Control - Sprite/Stage
+ "inlineComment:": "control:inlineComment",
+ "codeSection": "control:codeSection",
+ "doForLoop": "control:doForLoop",
+ "COUNT": "control:COUNT",
+ "CLR_COUNT": "control:CLR_COUNT",
+ "INCR_COUNT": "control:INCR_COUNT",
+ // Sensing
+ "notify:": "sensing:notify"
+ */
+ var mappings = {
+ "show": "obsolete:legacy_show_hide",
+ "hide": "obsolete:legacy_show_hide"
+ };
+ var path = "https://wiki.sharpscratchmod.cf/";
+ if(mappings[op]){
+ var req:URLRequest = new URLRequest(path + mappings[op]);
+ navigateToURL(req, "_blank");
+ }else{
+ DialogBox.notify("Sorry, No help for this block", "We don't have help for this block, sorry!");
}
}
diff --git a/src/blocks/BlockIO.as b/src/blocks/BlockIO.as
index e79fe029f..b36d9c9da 100644
--- a/src/blocks/BlockIO.as
+++ b/src/blocks/BlockIO.as
@@ -70,8 +70,12 @@ public class BlockIO {
if (b.op == Specs.GET_LIST) return [Specs.GET_LIST, b.spec]; // list reporter
if (b.op == Specs.GET_PARAM) return [Specs.GET_PARAM, b.spec, b.type]; // parameter reporter
if (b.op == Specs.PROCEDURE_DEF) // procedure definition
- return [Specs.PROCEDURE_DEF, b.spec, b.parameterNames, b.defaultArgValues, b.warpProcFlag];
- if (b.op == Specs.CALL) result = [Specs.CALL, b.spec]; // procedure call - arguments follow spec
+ return [Specs.PROCEDURE_DEF, b.spec, b.parameterNames, b.defaultArgValues, b.warpProcFlag, b.procedureType];
+ if (b.op == Specs.CALL) {
+ // procedure call - arguments follow spec
+ // because procedures used to only be commands, they didn't store their type in the array format; to maintain backwards compatibility, we store the type by splitting Specs.CALL into separate selectors for each type
+ result = [b.type == 'b' ? Specs.CALL_BOOLEAN : b.type == 'r' ? Specs.CALL_NUMBER : Specs.CALL, b.spec];
+ }
for each (var a:* in b.normalizedArgs()) {
// Note: arguments are always saved in normalized (i.e. left-to-right) order
if (a is Block) result.push(blockToArray(a));
@@ -93,6 +97,7 @@ public class BlockIO {
// Make a block from an array of form: *
if (cmd[0] == 'getUserName') Scratch.app.usesUserNameBlock = true;
+ if (cmd[0] == 'httpBlock:') Scratch.app.usesHTTPBlock = true;
var special:Block = specialCmd(cmd, forStage);
if (special) { special.fixArgLayout(); return special }
@@ -101,8 +106,8 @@ public class BlockIO {
b = convertOldCmd(cmd);
if (b) { b.fixArgLayout(); return b }
- if (cmd[0] == Specs.CALL) {
- b = new Block(cmd[1], '', Specs.procedureColor, Specs.CALL);
+ if (cmd[0] == Specs.CALL || cmd[0] == Specs.CALL_BOOLEAN || cmd[0] == Specs.CALL_NUMBER) {
+ b = new Block(cmd[1], cmd[0] == Specs.CALL_BOOLEAN ? 'b' : cmd[0] == Specs.CALL_NUMBER ? 'r' : '', Specs.procedureColor, Specs.CALL);
cmd.splice(0, 1);
} else {
var spec:Array = specForCmd(cmd, undefinedBlockType);
@@ -191,6 +196,7 @@ public class BlockIO {
b.parameterNames = cmd[2];
b.defaultArgValues = cmd[3];
if (cmd.length > 4) b.warpProcFlag = cmd[4];
+ if (cmd.length > 5) b.procedureType = cmd[5];
b.setSpec(cmd[1]);
b.fixArgLayout();
return b;
diff --git a/src/blocks/BlockShape.as b/src/blocks/BlockShape.as
index 0aa3cd98a..d44a4019d 100644
--- a/src/blocks/BlockShape.as
+++ b/src/blocks/BlockShape.as
@@ -42,6 +42,8 @@ public class BlockShape extends Shape {
public static const FinalLoopShape:int = 10;
// E-shaped blocks
public static const IfElseShape:int = 11;
+ public static const BooleanOutlineShape:int = 12;
+ public static const NumberOutlineShape:int = 13;
// Geometry
public static const NotchDepth:int = 3;
@@ -187,6 +189,8 @@ public class BlockShape extends Shape {
case CmdShape:
case FinalCmdShape: drawFunction = drawCmdShape; break;
case CmdOutlineShape: drawFunction = drawCmdOutlineShape; break;
+ case BooleanOutlineShape: drawFunction = drawBooleanOutlineShape; break;
+ case NumberOutlineShape: drawFunction = drawNumberOutlineShape; break;
case LoopShape:
case FinalLoopShape: drawFunction = drawLoopShape; break;
case IfElseShape: drawFunction = drawIfElseShape; break;
@@ -207,6 +211,13 @@ public class BlockShape extends Shape {
g.lineTo(w - centerY, topH);
}
+ private function drawBooleanOutlineShape(g:Graphics):void {
+ g.endFill();
+ g.lineStyle(2, 0xFFFFFF, 0.2);
+ drawBooleanShape(g);
+ g.lineTo(topH / 2, topH);
+ }
+
private function drawNumberShape(g:Graphics):void {
var centerY:int = topH / 2;
g.moveTo(centerY, topH);
@@ -217,6 +228,13 @@ public class BlockShape extends Shape {
curve(w, centerY, w - centerY, topH);
}
+ private function drawNumberOutlineShape(g:Graphics):void {
+ g.endFill();
+ g.lineStyle(2, 0xFFFFFF, 0.2);
+ drawNumberShape(g);
+ g.lineTo(topH / 2, topH);
+ }
+
private function drawCmdShape(g:Graphics):void {
drawTop(g);
drawRightAndBottom(g, topH, (shape != FinalCmdShape));
@@ -335,7 +353,7 @@ public class BlockShape extends Shape {
}
private function curve(p1x:int, p1y:int, p2x:int, p2y:int, roundness:Number = 0.42):void {
- // Compute the Bezier control point by following an orthogonal vector from the midpoint
+ // Compute the Bezier control point by following an orthogal vector from the midpoint
// of the line between p1 and p2 scaled by roundness * dist(p1, p2). The default roundness
// approximates a circular arc. Negative roundness gives a concave curve.
@@ -346,4 +364,4 @@ public class BlockShape extends Shape {
graphics.curveTo(cx, cy, p2x, p2y);
}
-}}
+}}
\ No newline at end of file
diff --git a/src/extensions/ExtensionManager.as b/src/extensions/ExtensionManager.as
index 488ea5867..d5709ac11 100644
--- a/src/extensions/ExtensionManager.as
+++ b/src/extensions/ExtensionManager.as
@@ -436,18 +436,17 @@ public class ExtensionManager {
// Execution
//------------------------------
- public function primExtensionOp(b:Block):* {
+ public function primExtensionOp(args:Array):* {
+ var activeThread:Thread = app.interp.activeThread;
+ var b:Block = activeThread.block;
var unpackedOp:Array = unpackExtensionAndOp(b.op);
var extName:String = unpackedOp[0];
var ext:ScratchExtension = extensionDict[extName];
if (ext == null) return 0; // unknown extension
var primOrVarName:String = unpackedOp[1];
- var args:Array = [];
- for (var i:int = 0; i < b.args.length; i++) {
- args.push(app.interp.arg(b, i));
- }
var value:*;
+
if(b.isHat && b.isAsyncHat){
if(b.requestState == 0){
request(extName, primOrVarName, args, b);
@@ -487,26 +486,22 @@ public class ExtensionManager {
return;
}
else if (b.isReporter) {
- if(b.isRequester) {
- if(b.requestState == 2) {
+ if (b.isRequester) {
+ if (b.requestState == 2) {
b.requestState = 0;
- return b.response;
- }
- else if(b.requestState == 0) {
+ activeThread.popState();
+ activeThread.values.push(b.response);
+ return;
+ } else if(b.requestState == 0) {
request(extName, primOrVarName, args, b);
}
-
- // Returns null if we just made a request or we're still waiting
- return null;
- }
- else {
+ } else {
var sensorName:String = primOrVarName;
- if(ext.port > 0) { // we were checking ext.isInternal before, should we?
+ if (ext.port > 0) { // we were checking ext.isInternal before, should we?
sensorName = encodeURIComponent(sensorName);
for each (var a:* in args) sensorName += '/' + encodeURIComponent(a); // append menu args
value = ext.stateVars[sensorName];
- }
- else if(Scratch.app.jsEnabled) {
+ } else if(Scratch.app.jsEnabled) {
// JavaScript
if (Scratch.app.isOffline) {
throw new IllegalOperationError("JS reporters must be requesters in Offline.");
@@ -517,7 +512,9 @@ public class ExtensionManager {
}
if (value == undefined) value = 0; // default to zero if missing
if ('b' == b.type) value = (ext.port>0 ? 'true' == value : true == value); // coerce value to a boolean
- return value;
+ activeThread.popState();
+ activeThread.values.push(value);
+ return
}
} else {
if ('w' == b.type) {
@@ -529,12 +526,13 @@ public class ExtensionManager {
app.interp.doYield();
justStartedWait = true;
- if(ext.port == 0) {
+ if (ext.port == 0) {
activeThread.firstTime = false;
- if(app.jsEnabled)
+ if (app.jsEnabled) {
app.externalCall('ScratchExtensions.runAsync', null, ext.name, primOrVarName, args, id);
- else
+ } else {
ext.busy.pop();
+ }
return;
}
@@ -546,6 +544,10 @@ public class ExtensionManager {
} else {
activeThread.tmp = 0;
activeThread.firstTime = true;
+ var block:Block = activeThread.block;
+ activeThread.popState();
+ if (block.nextBlock)
+ activeThread.pushStateForBlock(block.nextBlock);
}
return;
}
@@ -559,22 +561,13 @@ public class ExtensionManager {
if (ext == null) return; // unknown extension
if (ext.port > 0) {
var activeThread:Thread = app.interp.activeThread;
- if(activeThread && op != 'reset_all') {
- if(activeThread.firstTime) {
- httpCall(ext, op, args);
- activeThread.firstTime = false;
- app.interp.doYield();
- }
- else {
- activeThread.firstTime = true;
- }
- }
- else {
httpCall(ext, op, args);
- }
+ activeThread.firstTime = false;
+ app.interp.doYield();
} else {
+ if (op == 'reset_all') op = 'resetAll';
if (Scratch.app.jsEnabled) {
- if (op == 'reset_all') {
+ if (op == 'resetAll') {
app.externalCall('ScratchExtensions.stop', null, ext.name);
}
else {
diff --git a/src/interpreter/Interpreter.as b/src/interpreter/Interpreter.as
index 480f359af..328e8e697 100644
--- a/src/interpreter/Interpreter.as
+++ b/src/interpreter/Interpreter.as
@@ -70,6 +70,8 @@ import scratch.*;
import sound.*;
+import uiwidgets.DialogBox;
+
public class Interpreter {
public var activeThread:Thread; // current thread
@@ -78,6 +80,7 @@ public class Interpreter {
private var app:Scratch;
private var primTable:Dictionary; // maps opcodes to functions
+ private var specialTable:Dictionary; // blocks that require special op functions
private var threads:Array = []; // all threads
private var yield:Boolean; // set true to indicate that active thread should yield control
private var startTime:int; // start time for stepThreads()
@@ -93,6 +96,10 @@ public class Interpreter {
protected var debugFunc:Function;
+ static private var yieldBlock:Block = new Block('', '', 0, 'yield');
+ static private var returnBlock:Block = new Block('', '', 0, 'doReturn', [0]);
+ static private var report0Block:Block = new Block('%s', '', 0, 'report', [0]);
+
public function Interpreter(app:Scratch) {
this.app = app;
initPrims();
@@ -143,9 +150,9 @@ public class Interpreter {
var reporter:Block = b;
var interp:Interpreter = this;
b = new Block("%s", "", -1);
- b.opFunction = function(b:Block):void {
+ b.opFunction = function(b:Array):void {
var p:Point = reporter.localToGlobal(new Point(0, 0));
- app.showBubble(String(interp.arg(b, 0)), p.x, p.y, reporter.getRect(app.stage).width);
+ app.showBubble(String(b[0]), p.x, p.y, reporter.getRect(app.stage).width);
};
b.args[0] = reporter;
}
@@ -263,36 +270,21 @@ public class Interpreter {
return;
}
}
+
yield = false;
while (true) {
if (activeThread == warpThread) currentMSecs = getTimer();
evalCmd(activeThread.block);
- if (yield) {
- if (activeThread == warpThread) {
- if ((currentMSecs - startTime) > warpMSecs) return;
- yield = false;
- continue;
- } else return;
- }
-
- if (activeThread.block != null)
- activeThread.block = activeThread.block.nextBlock;
-
- while (activeThread.block == null) { // end of block sequence
- if (!activeThread.popState()) return; // end of script
- if ((activeThread.block == warpBlock) && activeThread.firstTime) { // end of outer warp block
- clearWarpBlock();
- activeThread.block = activeThread.block.nextBlock;
- continue;
- }
- if (activeThread.isLoop) {
- if (activeThread == warpThread) {
- if ((currentMSecs - startTime) > warpMSecs) return;
- } else return;
- } else {
- if (activeThread.block.op == Specs.CALL) activeThread.firstTime = true; // in case set false by call
- activeThread.block = activeThread.block.nextBlock;
+ if (activeThread.block == null) {
+ //click on reporter shows value in log
+ if (activeThread.values.length) {
+ app.jsThrowError(activeThread.values[0]);
}
+ return;
+ }
+ if (yield) {
+ if (activeThread != warpThread || currentMSecs - startTime > warpMSecs) return;
+ yield = false;
}
}
}
@@ -303,74 +295,86 @@ public class Interpreter {
}
/* Evaluation */
- public function evalCmd(b:Block):* {
- if (!b) return 0; // arg() and friends can pass null if arg index is out of range
+ public function evalCmd(b:Block):void {
+
var op:String = b.op;
if (b.opFunction == null) {
- if (ExtensionManager.hasExtensionPrefix(op)) b.opFunction = app.extensionManager.primExtensionOp;
- else b.opFunction = (primTable[op] == undefined) ? primNoop : primTable[op];
- }
-
- // TODO: Optimize this into a cached check if the args *could* block at all
- if(b.args.length && checkBlockingArgs(b)) {
- doYield();
- return null;
+ if (ExtensionManager.hasExtensionPrefix(op)) {
+ b.isSpecialOp = true;
+ b.opFunction = app.extensionManager.primExtensionOp;
+ } else if (specialTable[op]){
+ b.isSpecialOp = true;
+ b.opFunction = specialTable[op];
+ }
+ else {
+ b.opFunction = (primTable[op] == undefined) ? primNoop : primTable[op];
+ }
}
// Debug code
if(debugFunc != null)
debugFunc(b);
- return b.opFunction(b);
- }
-
- // Returns true if the thread needs to yield while data is requested
- public function checkBlockingArgs(b:Block):Boolean {
- // Do any of the arguments request data? If so, start any requests and yield.
- var shouldYield:Boolean = false;
- var args:Array = b.args;
- for(var i:uint=0; i 0) {
activeThread.tmp--; // decrement count
- startCmdList(b.subStack1, true);
+ startCmdList(block.subStack1, true);
} else {
+ activeThread.popState();
activeThread.firstTime = true;
+ if (block.nextBlock) activeThread.pushStateForBlock(block.nextBlock);
}
}
- private function primStop(b:Block):void {
- var type:String = arg(b, 0);
+
+ private function primCodeSection(b:Array):void {
+ var block:Block = activeThread.block;
+ activeThread.popState();
+ activeThread.firstTime = true;
+ if (block.nextBlock) activeThread.pushStateForBlock(block.nextBlock);
+ startCmdList(block.subStack1, false);
+ }
+
+ private function primStop(b:Array):void {
+ var type:String = b[0];
if (type == 'all') { app.runtime.stopAll(); yield = true }
- if (type == 'this script') primReturn(b);
+ if (type == 'this script') primReturn([0]);
if (type == 'other scripts in sprite') stopThreadsFor(activeThread.target, true);
if (type == 'other scripts in stage') stopThreadsFor(activeThread.target, true);
}
- private function primWait(b:Block):void {
+ private function primWait(b:Array):void {
if (activeThread.firstTime) {
- startTimer(numarg(b, 0));
+ startTimer(numarg(b[0]));
redraw();
} else checkTimer();
}
@@ -635,47 +692,52 @@ public class Interpreter {
// Procedure call/return
- private function primCall(b:Block):void {
+ private function primCall(b:Array):void {
// Call a procedure. Handle recursive calls and "warp" procedures.
- // The activeThread.firstTime flag is used to mark the first call
- // to a procedure running in warp mode. activeThread.firstTime is
- // false for subsequent calls to warp mode procedures.
+
+ var block:Block = activeThread.block;
// Lookup the procedure and cache for future use
var obj:ScratchObj = activeThread.target;
- var spec:String = b.spec;
+ var insideLoop:* = null;
+ var spec:String = block.spec;
var proc:Block = obj.procCache[spec];
if (!proc) {
proc = obj.lookupProcedure(spec);
obj.procCache[spec] = proc;
}
- if (!proc) return;
+ if (!proc) {
+ if (activeThread.block.type == 'o ') activeThread.values.push(0);
+ activeThread.popState();
+ if (block.nextBlock) activeThread.pushStateForBlock(block.nextBlock);
+ return;
+ }
if (warpThread) {
- activeThread.firstTime = false;
- if ((currentMSecs - startTime) > warpMSecs) yield = true;
+ if (currentMSecs - startTime > warpMSecs) yield = true;
} else {
if (proc.warpProcFlag) {
// Start running in warp mode.
- warpBlock = b;
+ warpBlock = block;
warpThread = activeThread;
- activeThread.firstTime = true;
- }
- else if (activeThread.isRecursiveCall(b, proc)) {
+ } else if (activeThread.isRecursiveCall(block, proc)) {
yield = true;
}
}
- var argCount:int = proc.parameterNames.length;
- var argList:Array = [];
- for (var i:int = 0; i < argCount; ++i) argList.push(arg(b, i));
- startCmdList(proc, false, argList);
+ activeThread.pushStateForBlock(report0Block);
+ activeThread.args = b;
+ startCmdList(proc);
}
- private function primReturn(b:Block):void {
+ private function primReturn(b:Array):void {
// Return from the innermost procedure. If not in a procedure, stop the thread.
- if (!activeThread.returnFromProcedure()) {
+ var call:Block = activeThread.returnFromProcedure();
+ if (call) {
+ if (call.isReporter) {
+ activeThread.values.push(b[0]);
+ }
+ } else {
activeThread.stop();
- yield = true;
}
}
@@ -683,49 +745,59 @@ public class Interpreter {
// Optimization: to avoid the cost of looking up the variable every time,
// a reference to the Variable object is cached in the target object.
- private function primVarGet(b:Block):* {
- var target:ScratchObj = app.runtime.currentDoObj ? app.runtime.currentDoObj : activeThread.target;
-
- var v:Variable = target.varCache[b.spec];
+ private function primVarGet(b:Array):void {
+ var block:Block = activeThread.block;
+ activeThread.popState();
+ var v:Variable = activeThread.target.varCache[block.spec];
if (v == null) {
- v = target.varCache[b.spec] = target.lookupOrCreateVar(b.spec);
- if (v == null) return 0;
+ v = activeThread.target.varCache[block.spec] = activeThread.target.lookupOrCreateVar(block.spec);
+ if (v == null) {
+ activeThread.values.push(0);
+ return;
+ }
}
- // XXX: Do we need a get() for persistent variables here ?
- return v.value;
+ activeThread.values.push(v.value);
}
- protected function primVarSet(b:Block):Variable {
- var name:String = arg(b, 0);
- var v:Variable = activeThread.target.varCache[name];
+ protected function primVarSet(b:Array):Variable {
+ var v:Variable = activeThread.target.varCache[b[0]];
if (!v) {
- v = activeThread.target.varCache[name] = activeThread.target.lookupOrCreateVar(name);
+ v = activeThread.target.varCache[b.spec] = activeThread.target.lookupOrCreateVar(b[0]);
if (!v) return null;
}
var oldvalue:* = v.value;
- v.value = arg(b, 1);
+ v.value = b[1];
return v;
}
- protected function primVarChange(b:Block):Variable {
- var name:String = arg(b, 0);
+ protected function primVarChange(b:Array):Variable {
+ var name:String = b[0];
var v:Variable = activeThread.target.varCache[name];
if (!v) {
v = activeThread.target.varCache[name] = activeThread.target.lookupOrCreateVar(name);
if (!v) return null;
}
- v.value = Number(v.value) + numarg(b, 1);
+ v.value = Number(v.value) + b[1];
return v;
}
- private function primGetParam(b:Block):* {
- if (b.parameterIndex < 0) {
- var proc:Block = b.topBlock();
- if (proc.parameterNames) b.parameterIndex = proc.parameterNames.indexOf(b.spec);
- if (b.parameterIndex < 0) return 0;
+ private function primGetParam(b:Array):* {
+ var block:Block = activeThread.block;
+ activeThread.popState();
+ if (!block.isReporter) return;
+ if (block.parameterIndex < 0) {
+ var proc:Block = block.topBlock();
+ if (proc.parameterNames) block.parameterIndex = proc.parameterNames.indexOf(block.spec);
+ if (block.parameterIndex < 0) {
+ activeThread.values.push(0);
+ return;
+ }
+ }
+ if (activeThread.args == null || block.parameterIndex >= activeThread.args.length) {
+ activeThread.values.push(0);
+ return;
}
- if ((activeThread.args == null) || (b.parameterIndex >= activeThread.args.length)) return 0;
- return activeThread.args[b.parameterIndex];
+ activeThread.values.push(activeThread.args[block.parameterIndex]);
}
}}
diff --git a/src/interpreter/Thread.as b/src/interpreter/Thread.as
index 27fc769f4..3aee1e321 100644
--- a/src/interpreter/Thread.as
+++ b/src/interpreter/Thread.as
@@ -36,9 +36,9 @@ public class Thread {
// the following state is pushed and popped when running substacks
public var block:Block;
- public var isLoop:Boolean;
public var firstTime:Boolean; // used by certain control structures
public var tmp:int; // used by repeat and wait
+ public var values:Array; // the evaluated inputs
public var args:Array; // arguments to a user-defined procedure
// the stack
@@ -51,34 +51,35 @@ public class Thread {
topBlock = b;
startDelayCount = startupDelay;
// initForBlock
- block = b;
- isLoop = false;
+ block = null;
firstTime = true;
tmp = 0;
+ values = [];
+ pushStateForBlock(b);
}
public function pushStateForBlock(b:Block):void {
if (sp >= (stack.length - 1)) growStack();
var old:StackFrame = stack[sp++];
old.block = block;
- old.isLoop = isLoop;
old.firstTime = firstTime;
old.tmp = tmp;
+ old.values = values;
old.args = args;
// initForBlock
block = b;
- isLoop = false;
firstTime = true;
tmp = 0;
+ values = [];
}
public function popState():Boolean {
if (sp == 0) return false;
var old:StackFrame = stack[--sp];
block = old.block;
- isLoop = old.isLoop;
firstTime = old.firstTime;
tmp = old.tmp;
+ values = old.values;
args = old.args;
return true;
}
@@ -87,6 +88,7 @@ public class Thread {
public function stop():void {
block = null;
+ values = [];
stack = new Vector.(4);
stack[0] = new StackFrame();
stack[1] = new StackFrame();
@@ -99,7 +101,7 @@ public class Thread {
var callCount:int = 5; // maximum number of enclosing procedure calls to examine
for (var i:int = sp - 1; i >= 0; i--) {
var b:Block = stack[i].block;
- if (b.op == Specs.CALL) {
+ if (b && b.op == Specs.CALL) {
if (procCall == b) return true;
if (procHat == target.procCache[b.spec]) return true;
}
@@ -108,26 +110,33 @@ public class Thread {
return false;
}
- public function returnFromProcedure():Boolean {
+ public function returnFromProcedure():Block {
+ if (block && block.op == Specs.CALL) {
+ var b:Block = block;
+ popState();
+ if (b.nextBlock) pushStateForBlock(b.nextBlock);
+ return block;
+ }
for (var i:int = sp - 1; i >= 0; i--) {
- if (stack[i].block.op == Specs.CALL) {
- sp = i + 1; // 'hack' the stack pointer, but don't do the final popState here
- block = null; // make it do the final popState through the usual stepActiveThread mechanism
- return true;
+ b = stack[i].block;
+ if (b && b.op == Specs.CALL) {
+ sp = i;
+ popState();
+ if (b.nextBlock) pushStateForBlock(b.nextBlock);
+ return b;
}
}
- return false;
+ return null;
}
private function initForBlock(b:Block):void {
block = b;
- isLoop = false;
firstTime = true;
tmp = 0;
}
private function growStack():void {
- // The stack is an array of Thread instances, pre-allocated for efficiency.
+ // The stack is an array of StackFrame instances, pre-allocated for efficiency.
// When growing, the current size is doubled.
var s:int = stack.length;
var n:int = s + s;
@@ -143,8 +152,8 @@ import interpreter.*;
class StackFrame {
internal var block:Block;
- internal var isLoop:Boolean;
internal var firstTime:Boolean;
internal var tmp:int;
+ internal var values:Array;
internal var args:Array;
-}
+}
\ No newline at end of file
diff --git a/src/primitives/ListPrims.as b/src/primitives/ListPrims.as
index 10a7675ab..7adf1da64 100644
--- a/src/primitives/ListPrims.as
+++ b/src/primitives/ListPrims.as
@@ -39,7 +39,7 @@ public class ListPrims {
this.interp = interpreter;
}
- public function addPrimsTo(primTable:Dictionary):void {
+ public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void {
primTable[Specs.GET_LIST] = primContents;
primTable['append:toList:'] = primAppend;
primTable['deleteLine:ofList:'] = primDelete;
@@ -48,9 +48,10 @@ public class ListPrims {
primTable['getLine:ofList:'] = primGetItem;
primTable['lineCountOfList:'] = primLength;
primTable['list:contains:'] = primContains;
+ primTable["blockSplit:"] = primSharpBlockSplit;
}
- private function primContents(b:Block):String {
+ private function primContents(b:Array):String {
var list:ListWatcher = interp.targetObj().lookupOrCreateList(b.spec);
if (!list) return '';
var allSingleLetters:Boolean = true;
@@ -63,20 +64,37 @@ public class ListPrims {
return (list.contents.join(allSingleLetters ? '' : ' '));
}
- private function primAppend(b:Block):void {
- var list:ListWatcher = listarg(b, 1);
+ private function primAppend(b:Array):void {
+ var list:ListWatcher = listarg(b[1]);
if (!list) return;
- listAppend(list, interp.arg(b, 0));
+ listAppend(list, b[0]);
if (list.visible) list.updateWatcher(list.contents.length, false, interp);
}
+ /*
+ Sharp
+ */
+ private function primSharpBlockSplit(b:Array):void{
+ var list:ListWatcher = listarg(b[2]);
+ if (!list) return;
+ var s = b[0].split(b[1]);
+ var i = 0;
+ while(i != s.length){
+ listAppend(list, s[i]);
+ i++;
+ }
+ if(list.visible) list.updateWatcher(list.contents.length, false, interp);
+ }
+ /*
+ /Sharp
+ */
protected function listAppend(list:ListWatcher, item:*):void {
list.contents.push(item);
}
- private function primDelete(b:Block):void {
- var which:* = interp.arg(b, 0);
- var list:ListWatcher = listarg(b, 1);
+ private function primDelete(b:Array):void {
+ var which:* = b[0];
+ var list:ListWatcher = listarg(b[1]);
if (!list) return;
var len:int = list.contents.length;
if (which == 'all') {
@@ -100,9 +118,9 @@ public class ListPrims {
}
private function primInsert(b:Block):void {
- var val:* = interp.arg(b, 0);
- var where:* = interp.arg(b, 1);
- var list:ListWatcher = listarg(b, 2);
+ var val:* = b[0];
+ var where:* = b[1];
+ var list:ListWatcher = listarg(b[2]);
if (!list) return;
if (where == 'last') {
listAppend(list, val);
@@ -119,12 +137,12 @@ public class ListPrims {
list.contents.splice(i - 1, 0, item);
}
- private function primReplace(b:Block):void {
- var list:ListWatcher = listarg(b, 1);
+ private function primReplace(b:Array):void {
+ var list:ListWatcher = listarg(b[1]);
if (!list) return;
- var i:int = computeIndex(interp.arg(b, 0), list.contents.length);
+ var i:int = computeIndex(b[0], list.contents.length);
if (i < 0) return;
- listReplace(list, i, interp.arg(b, 2));
+ listReplace(list, i, b[2]);
if (list.visible) list.updateWatcher(i, false, interp);
}
@@ -132,25 +150,25 @@ public class ListPrims {
list.contents[i - 1] = item;
}
- private function primGetItem(b:Block):* {
- var list:ListWatcher = listarg(b, 1);
+ private function primGetItem(b:Array):* {
+ var list:ListWatcher = listarg(b[1]);
if (!list) return '';
- var i:int = computeIndex(interp.arg(b, 0), list.contents.length);
+ var i:int = computeIndex(b[0], list.contents.length);
if (i < 0) return '';
if (list.visible) list.updateWatcher(i, true, interp);
return list.contents[i - 1];
}
- private function primLength(b:Block):Number {
- var list:ListWatcher = listarg(b, 0);
+ private function primLength(b:Array):Number {
+ var list:ListWatcher = listarg(b[0]);
if (!list) return 0;
return list.contents.length;
}
- private function primContains(b:Block):Boolean {
- var list:ListWatcher = listarg(b, 0);
+ private function primContains(b:Array):Boolean {
+ var list:ListWatcher = listarg(b[0]);
if (!list) return false;
- var item:* = interp.arg(b, 1);
+ var item:* = b[1];
if (list.contents.indexOf(item) >= 0) return true;
for each (var el:* in list.contents) {
// use Scratch comparison operator (Scratch considers the string '123' equal to the number 123)
@@ -159,8 +177,7 @@ public class ListPrims {
return false;
}
- private function listarg(b:Block, i:int):ListWatcher {
- var listName:String = interp.arg(b, i);
+ private function listarg(listName:String):ListWatcher {
if (listName.length == 0) return null;
var obj:ScratchObj = interp.targetObj();
var result:ListWatcher = obj.listCache[listName];
@@ -183,4 +200,4 @@ public class ListPrims {
return i;
}
-}}
+}}
\ No newline at end of file
diff --git a/src/primitives/LooksPrims.as b/src/primitives/LooksPrims.as
index 9e8a73fb4..0a78de2c3 100644
--- a/src/primitives/LooksPrims.as
+++ b/src/primitives/LooksPrims.as
@@ -38,7 +38,7 @@ public class LooksPrims {
this.interp = interpreter;
}
- public function addPrimsTo(primTable:Dictionary):void {
+ public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void {
primTable['lookLike:'] = primShowCostume;
primTable['nextCostume'] = primNextCostume;
primTable['costumeIndex'] = primCostumeIndex;
@@ -49,12 +49,12 @@ public class LooksPrims {
primTable['backgroundIndex'] = primSceneIndex;
primTable['sceneName'] = primSceneName;
primTable['nextScene'] = function(b:*):* { startScene('next backdrop', false) };
- primTable['startScene'] = function(b:*):* { startScene(interp.arg(b, 0), false) };
- primTable['startSceneAndWait'] = function(b:*):* { startScene(interp.arg(b, 0), true) };
+ primTable['startScene'] = function(b:*):* { startScene(b[0], false) };
+ primTable['startSceneAndWait'] = function(b:*):* { startScene(b[0], true) };
- primTable['say:duration:elapsed:from:'] = function(b:*):* { showBubbleAndWait(b, 'talk') };
+ specialTable['say:duration:elapsed:from:'] = function(b:*):* { showBubbleAndWait(b, 'talk') };
primTable['say:'] = function(b:*):* { showBubble(b, 'talk') };
- primTable['think:duration:elapsed:from:'] = function(b:*):* { showBubbleAndWait(b, 'think') };
+ specialTable['think:duration:elapsed:from:'] = function(b:*):* { showBubbleAndWait(b, 'think') };
primTable['think:'] = function(b:*):* { showBubble(b, 'think') };
primTable['changeGraphicEffect:by:'] = primChangeEffect;
@@ -69,6 +69,11 @@ public class LooksPrims {
primTable['hide'] = primHide;
// primTable['hideAll'] = primHideAll;
+ primTable['showStage'] = primShow;
+ primTable['hideStage'] = primHide;
+ primTable['showSprite'] = primShow;
+ primTable['hideSprite'] = primHide;
+
primTable['comeToFront'] = primGoFront;
primTable['goBackByLayers:'] = primGoBack;
@@ -84,16 +89,16 @@ public class LooksPrims {
primTable['setRotationStyle'] = primSetRotationStyle;
}
- private function primNextCostume(b:Block):void {
+ private function primNextCostume(b:Array):void {
var s:ScratchObj = interp.targetObj();
if (s != null) s.showCostume(s.currentCostumeIndex + 1);
if (s.visible) interp.redraw();
}
- private function primShowCostume(b:Block):void {
+ private function primShowCostume(b:Array):void {
var s:ScratchObj = interp.targetObj();
if (s == null) return;
- var arg:* = interp.arg(b, 0);
+ var arg:* = b[0];
if (typeof(arg) == 'number') {
s.showCostume(arg - 1);
} else {
@@ -113,21 +118,21 @@ public class LooksPrims {
if (s.visible) interp.redraw();
}
- private function primCostumeIndex(b:Block):Number {
+ private function primCostumeIndex(b:Array):Number {
var s:ScratchObj = interp.targetObj();
return (s == null) ? 1 : s.costumeNumber();
}
- private function primCostumeName(b:Block):String {
+ private function primCostumeName(b:Array):String {
var s:ScratchObj = interp.targetObj();
return (s == null) ? '' : s.currentCostume().costumeName;
}
- private function primSceneIndex(b:Block):Number {
+ private function primSceneIndex(b:Array):Number {
return app.stagePane.costumeNumber();
}
- private function primSceneName(b:Block):String {
+ private function primSceneName(b:Array):String {
return app.stagePane.currentCostume().costumeName;
}
@@ -154,14 +159,13 @@ public class LooksPrims {
var costumes:Array = app.stagePane.costumes;
return costumes[(i + costumes.length) % costumes.length].costumeName;
}
-
- private function showBubbleAndWait(b:Block, type:String):void {
+ private function showBubbleAndWait(b:Array, type:String):void {
var text:*, secs:Number;
var s:ScratchSprite = interp.targetSprite();
if (s == null) return;
if (interp.activeThread.firstTime) {
- text = interp.arg(b, 0);
- secs = interp.numarg(b, 1);
+ text = b[0];
+ secs = interp.numarg(b[1]);
s.showBubble(text, type, b);
if (s.visible) interp.redraw();
interp.startTimer(secs);
@@ -172,25 +176,25 @@ public class LooksPrims {
}
}
- private function showBubble(b:Block, type:String = null):void {
+ private function showBubble(b:Array, type:String = null):void {
var text:*, secs:Number;
var s:ScratchSprite = interp.targetSprite();
if (s == null) return;
if (type == null) { // combined talk/think/shout/whisper command
- type = interp.arg(b, 0);
- text = interp.arg(b, 1);
+ type = b[0];
+ text = b[1];
} else { // talk or think command
- text = interp.arg(b, 0);
+ text = b[0];
}
s.showBubble(text, type, b);
if (s.visible) interp.redraw();
}
- private function primChangeEffect(b:Block):void {
+ private function primChangeEffect(b:Array):void {
var s:ScratchObj = interp.targetObj();
if (s == null) return;
- var filterName:String = interp.arg(b, 0);
- var delta:Number = interp.numarg(b, 1);
+ var filterName:String = b[0];
+ var delta:Number = interp.numarg(b[1]);
if(delta == 0) return;
var newValue:Number = s.filterPack.getFilterSetting(filterName) + delta;
@@ -199,53 +203,57 @@ public class LooksPrims {
if (s.visible || s == Scratch.app.stagePane) interp.redraw();
}
- private function primSetEffect(b:Block):void {
+ private function primSetEffect(b:Array):void {
var s:ScratchObj = interp.targetObj();
if (s == null) return;
- var filterName:String = interp.arg(b, 0);
- var newValue:Number = interp.numarg(b, 1);
+ var filterName:String = b[0];
+ var newValue:Number = interp.numarg(b[1]);
if(s.filterPack.setFilter(filterName, newValue))
s.applyFilters();
if (s.visible || s == Scratch.app.stagePane) interp.redraw();
}
- private function primClearEffects(b:Block):void {
+ private function primClearEffects(b:Array):void {
var s:ScratchObj = interp.targetObj();
s.clearFilters();
s.applyFilters();
if (s.visible || s == Scratch.app.stagePane) interp.redraw();
}
- private function primChangeSize(b:Block):void {
+ private function primChangeSize(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
if (s == null) return;
var oldScale:Number = s.scaleX;
- s.setSize(s.getSize() + interp.numarg(b, 0));
+ s.setSize(s.getSize() + interp.numarg(b[0]));
if (s.visible && (s.scaleX != oldScale)) interp.redraw();
}
- private function primSetRotationStyle(b:Block):void {
+ private function primSetRotationStyle(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
- var newStyle:String = interp.arg(b, 0) as String;
+ var newStyle:String = b[0] as String;
if ((s == null) || (newStyle == null)) return;
s.setRotationStyle(newStyle);
}
- private function primSetSize(b:Block):void {
+ private function primSetSize(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
if (s == null) return;
- s.setSize(interp.numarg(b, 0));
+ s.setSize(interp.numarg(b[0]));
if (s.visible) interp.redraw();
}
- private function primSize(b:Block):Number {
+ private function primSize(b:Array):Number {
var s:ScratchSprite = interp.targetSprite();
if (s == null) return 100;
return Math.round(s.getSize()); // reporter returns rounded size, as in Scratch 1.4
}
- private function primShow(b:Block):void {
- var s:ScratchSprite = interp.targetSprite();
+ private function primShow(b:Array):void {
+ if(b.length != 1 || b[0] == "_myself_"){
+ var s:ScratchSprite = interp.targetSprite();
+ }else{
+ var s:ScratchSprite = Scratch.app.stagePane.spriteNamed(b[0]);
+ }
if (s == null) return;
s.visible = true;
if(!app.isIn3D) s.applyFilters();
@@ -253,16 +261,20 @@ public class LooksPrims {
if (s.visible) interp.redraw();
}
- private function primHide(b:Block):void {
- var s:ScratchSprite = interp.targetSprite();
+ private function primHide(b:Array):void {
+ if(b.length != 1 || b[0] == "_myself_"){
+ var s:ScratchSprite = interp.targetSprite();
+ }else{
+ var s:ScratchSprite = Scratch.app.stagePane.spriteNamed(b[0]);
+ }
if ((s == null) || !s.visible) return;
s.visible = false;
if(!app.isIn3D) s.applyFilters();
s.updateBubble();
interp.redraw();
}
-
- private function primHideAll(b:Block):void {
+
+ private function primHideAll(b:Array):void {
// Hide all sprites and delete all clones. Only works from the stage.
if (!interp.targetObj().isStage) return;
app.stagePane.deleteClones();
@@ -276,17 +288,17 @@ public class LooksPrims {
interp.redraw();
}
- private function primGoFront(b:Block):void {
+ private function primGoFront(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
if ((s == null) || (s.parent == null)) return;
s.parent.setChildIndex(s, s.parent.numChildren - 1);
if (s.visible) interp.redraw();
}
- private function primGoBack(b:Block):void {
+ private function primGoBack(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
if ((s == null) || (s.parent == null)) return;
- var newIndex:int = s.parent.getChildIndex(s) - interp.numarg(b, 0);
+ var newIndex:int = s.parent.getChildIndex(s) - interp.numarg(b[0]);
newIndex = Math.max(minSpriteLayer(), Math.min(newIndex, s.parent.numChildren - 1));
if (newIndex > 0 && newIndex < s.parent.numChildren) {
@@ -301,27 +313,27 @@ public class LooksPrims {
return stg.getChildIndex(stg.videoImage ? stg.videoImage : stg.penLayer) + 1;
}
- private function primSetVideoState(b:Block):void {
- app.stagePane.setVideoState(interp.arg(b, 0));
+ private function primSetVideoState(b:Array):void {
+ app.stagePane.setVideoState(b[0]);
}
- private function primSetVideoTransparency(b:Block):void {
- app.stagePane.setVideoTransparency(interp.numarg(b, 0));
+ private function primSetVideoTransparency(b:Array):void {
+ app.stagePane.setVideoTransparency(interp.numarg(b[0]));
app.stagePane.setVideoState('on');
}
- private function primScrollAlign(b:Block):void {
+ private function primScrollAlign(b:Array):void {
if (!interp.targetObj().isStage) return;
- app.stagePane.scrollAlign(interp.arg(b, 0));
+ app.stagePane.scrollAlign(b[0]);
}
- private function primScrollRight(b:Block):void {
+ private function primScrollRight(b:Array):void {
if (!interp.targetObj().isStage) return;
- app.stagePane.scrollRight(interp.numarg(b, 0));
+ app.stagePane.scrollRight(interp.numarg(b[0]));
}
- private function primScrollUp(b:Block):void {
+ private function primScrollUp(b:Array):void {
if (!interp.targetObj().isStage) return;
- app.stagePane.scrollUp(interp.numarg(b, 0));
+ app.stagePane.scrollUp(interp.numarg(b[0]));
}
}}
diff --git a/src/primitives/MotionAndPenPrims.as b/src/primitives/MotionAndPenPrims.as
index f101ede15..26800036e 100644
--- a/src/primitives/MotionAndPenPrims.as
+++ b/src/primitives/MotionAndPenPrims.as
@@ -43,7 +43,7 @@ public class MotionAndPenPrims {
this.interp = interpreter;
}
- public function addPrimsTo(primTable:Dictionary):void {
+ public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void {
primTable["forward:"] = primMove;
primTable["turnRight:"] = primTurnRight;
primTable["turnLeft:"] = primTurnLeft;
@@ -51,7 +51,7 @@ public class MotionAndPenPrims {
primTable["pointTowards:"] = primPointTowards;
primTable["gotoX:y:"] = primGoTo;
primTable["gotoSpriteOrMouse:"] = primGoToSpriteOrMouse;
- primTable["glideSecs:toX:y:elapsed:from:"] = primGlide;
+ specialTable["glideSecs:toX:y:elapsed:from:"] = primGlide;
primTable["changeXposBy:"] = primChangeX;
primTable["xpos:"] = primSetX;
@@ -77,41 +77,41 @@ public class MotionAndPenPrims {
primTable["stampCostume"] = primStamp;
}
- private function primMove(b:Block):void {
+ private function primMove(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
if (s == null) return;
var radians:Number = (Math.PI * (90 - s.direction)) / 180;
- var d:Number = interp.numarg(b, 0);
+ var d:Number = interp.numarg(b[0]);
moveSpriteTo(s, s.scratchX + (d * Math.cos(radians)), s.scratchY + (d * Math.sin(radians)));
}
- private function primTurnRight(b:Block):void {
+ private function primTurnRight(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
if (s != null) {
- s.setDirection(s.direction + interp.numarg(b, 0));
+ s.setDirection(s.direction + interp.numarg(b[0]));
if (s.visible) interp.redraw();
}
}
- private function primTurnLeft(b:Block):void {
+ private function primTurnLeft(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
if (s != null) {
- s.setDirection(s.direction - interp.numarg(b, 0));
+ s.setDirection(s.direction - interp.numarg(b[0]));
if (s.visible) interp.redraw();
}
}
- private function primSetDirection(b:Block):void {
+ private function primSetDirection(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
if (s != null) {
- s.setDirection(interp.numarg(b, 0));
+ s.setDirection(interp.numarg(b[0]));
if (s.visible) interp.redraw();
}
}
- private function primPointTowards(b:Block):void {
+ private function primPointTowards(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
- var p:Point = mouseOrSpritePosition(interp.arg(b, 0));
+ var p:Point = mouseOrSpritePosition(b[0]);
if ((s == null) || (p == null)) return;
var dx:Number = p.x - s.scratchX;
var dy:Number = p.y - s.scratchY;
@@ -120,25 +120,25 @@ public class MotionAndPenPrims {
if (s.visible) interp.redraw();
}
- private function primGoTo(b:Block):void {
+ private function primGoTo(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
- if (s != null) moveSpriteTo(s, interp.numarg(b, 0), interp.numarg(b, 1));
+ if (s != null) moveSpriteTo(s, interp.numarg(b[0]), interp.numarg(b[1]));
}
- private function primGoToSpriteOrMouse(b:Block):void {
+ private function primGoToSpriteOrMouse(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
- var p:Point = mouseOrSpritePosition(interp.arg(b, 0));
+ var p:Point = mouseOrSpritePosition(b[0]);
if ((s == null) || (p == null)) return;
moveSpriteTo(s, p.x, p.y);
}
- private function primGlide(b:Block):void {
+ private function primGlide(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
if (s == null) return;
if (interp.activeThread.firstTime) {
- var secs:Number = interp.numarg(b, 0);
- var destX:Number = interp.numarg(b, 1);
- var destY:Number = interp.numarg(b, 2);
+ var secs:Number = interp.numarg(b[0]);
+ var destX:Number = interp.numarg(b[1]);
+ var destY:Number = interp.numarg(b[2]);
if (secs <= 0) {
moveSpriteTo(s, destX, destY);
return;
@@ -179,27 +179,27 @@ public class MotionAndPenPrims {
return null;
}
- private function primChangeX(b:Block):void {
+ private function primChangeX(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
- if (s != null) moveSpriteTo(s, s.scratchX + interp.numarg(b, 0), s.scratchY);
+ if (s != null) moveSpriteTo(s, s.scratchX + interp.numarg(b[0]), s.scratchY);
}
- private function primSetX(b:Block):void {
+ private function primSetX(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
- if (s != null) moveSpriteTo(s, interp.numarg(b, 0), s.scratchY);
+ if (s != null) moveSpriteTo(s, interp.numarg(b[0]), s.scratchY);
}
- private function primChangeY(b:Block):void {
+ private function primChangeY(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
- if (s != null) moveSpriteTo(s, s.scratchX, s.scratchY + interp.numarg(b, 0));
+ if (s != null) moveSpriteTo(s, s.scratchX, s.scratchY + interp.numarg(b[0]));
}
- private function primSetY(b:Block):void {
+ private function primSetY(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
- if (s != null) moveSpriteTo(s, s.scratchX, interp.numarg(b, 0));
+ if (s != null) moveSpriteTo(s, s.scratchX, interp.numarg(b[0]));
}
- private function primBounceOffEdge(b:Block):void {
+ private function primBounceOffEdge(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
if (s == null) return;
if (!turnAwayFromEdge(s)) return;
@@ -207,17 +207,17 @@ public class MotionAndPenPrims {
if (s.visible) interp.redraw();
}
- private function primXPosition(b:Block):Number {
+ private function primXPosition(b:Array):Number {
var s:ScratchSprite = interp.targetSprite();
return (s != null) ? snapToInteger(s.scratchX) : 0;
}
- private function primYPosition(b:Block):Number {
+ private function primYPosition(b:Array):Number {
var s:ScratchSprite = interp.targetSprite();
return (s != null) ? snapToInteger(s.scratchY) : 0;
}
- private function primDirection(b:Block):Number {
+ private function primDirection(b:Array):Number {
var s:ScratchSprite = interp.targetSprite();
return (s != null) ? snapToInteger(s.direction) : 0;
}
@@ -229,12 +229,12 @@ public class MotionAndPenPrims {
return (delta < 1e-9) ? rounded : n;
}
- private function primClear(b:Block):void {
+ private function primClear(b:Array):void {
app.stagePane.clearPenStrokes();
interp.redraw();
}
- private function primPenDown(b:Block):void {
+ private function primPenDown(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
if (s != null) s.penIsDown = true;
touch(s, s.scratchX, s.scratchY);
@@ -252,47 +252,47 @@ public class MotionAndPenPrims {
app.stagePane.penActivity = true;
}
- private function primPenUp(b:Block):void {
+ private function primPenUp(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
if (s != null) s.penIsDown = false;
}
- private function primSetPenColor(b:Block):void {
+ private function primSetPenColor(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
- if (s != null) s.setPenColor(interp.numarg(b, 0));
+ if (s != null) s.setPenColor(interp.numarg(b[0]));
}
- private function primSetPenHue(b:Block):void {
+ private function primSetPenHue(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
- if (s != null) s.setPenHue(interp.numarg(b, 0));
+ if (s != null) s.setPenHue(interp.numarg(b[0]));
}
- private function primChangePenHue(b:Block):void {
+ private function primChangePenHue(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
- if (s != null) s.setPenHue(s.penHue + interp.numarg(b, 0));
+ if (s != null) s.setPenHue(s.penHue + interp.numarg(b[0]));
}
- private function primSetPenShade(b:Block):void {
+ private function primSetPenShade(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
- if (s != null) s.setPenShade(interp.numarg(b, 0));
+ if (s != null) s.setPenShade(interp.numarg(b[0]));
}
- private function primChangePenShade(b:Block):void {
+ private function primChangePenShade(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
- if (s != null) s.setPenShade(s.penShade + interp.numarg(b, 0));
+ if (s != null) s.setPenShade(s.penShade + interp.numarg(b[0]));
}
- private function primSetPenSize(b:Block):void {
+ private function primSetPenSize(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
- if (s != null) s.setPenSize(Math.max(1, Math.min(960, Math.round(interp.numarg(b, 0)))));
+ if (s != null) s.setPenSize(Math.max(1, Math.min(960, Math.round(interp.numarg(b[0])))));
}
- private function primChangePenSize(b:Block):void {
+ private function primChangePenSize(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
- if (s != null) s.setPenSize(s.penWidth + interp.numarg(b, 0));
+ if (s != null) s.setPenSize(s.penWidth + interp.numarg(b[0]));
}
-
- private function primStamp(b:Block):void {
+
+ private function primStamp(b:Array):void {
var s:ScratchSprite = interp.targetSprite();
// In 3D mode, get the alpha from the ghost filter
// Otherwise, it can be easily accessed from the color transform.
diff --git a/src/primitives/Primitives.as b/src/primitives/Primitives.as
index 75cd7776c..7ca4c673d 100644
--- a/src/primitives/Primitives.as
+++ b/src/primitives/Primitives.as
@@ -30,42 +30,77 @@ package primitives {
import scratch.ScratchSprite;
import translation.Translator;
+ import flash.net.*;
+ import flash.events.Event;
+ import flash.events.IOErrorEvent;
+ import flash.events.SecurityErrorEvent;
+ import flash.utils.ByteArray;
+
+ import mx.utils.Base64Encoder;
+ import mx.utils.Base64Decoder;
+
+ import uiwidgets.DialogBox;
+
public class Primitives {
- private const MaxCloneCount:int = 300;
+ private const MaxCloneCount:int = Scratch.app.sharpSettings.data.cloneLimit; //Scratch default: 300
protected var app:Scratch;
protected var interp:Interpreter;
private var counter:int;
+ private var httpReturn:String = "";
+ private var httpRequestsAllowed:int = 10; private var httpRequestsActive:int = 0; // TODO: Add "hidden" setting for HTTP requests allowed
+ private var fileNameValue:String; private var fileDataValue:String; private var fileLoadedValue:Boolean; private var fileErrored:Boolean; private var fileErrorValue:String;
public function Primitives(app:Scratch, interpreter:Interpreter) {
this.app = app;
this.interp = interpreter;
}
- public function addPrimsTo(primTable:Dictionary):void {
+ public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void {
// operators
- primTable["+"] = function(b:*):* { return interp.numarg(b, 0) + interp.numarg(b, 1) };
- primTable["-"] = function(b:*):* { return interp.numarg(b, 0) - interp.numarg(b, 1) };
- primTable["*"] = function(b:*):* { return interp.numarg(b, 0) * interp.numarg(b, 1) };
- primTable["/"] = function(b:*):* { return interp.numarg(b, 0) / interp.numarg(b, 1) };
- primTable["randomFrom:to:"] = primRandom;
- primTable["<"] = function(b:*):* { return compare(interp.arg(b, 0), interp.arg(b, 1)) < 0 };
- primTable["="] = function(b:*):* { return compare(interp.arg(b, 0), interp.arg(b, 1)) == 0 };
- primTable[">"] = function(b:*):* { return compare(interp.arg(b, 0), interp.arg(b, 1)) > 0 };
- primTable["&"] = function(b:*):* { return interp.arg(b, 0) && interp.arg(b, 1) };
- primTable["|"] = function(b:*):* { return interp.arg(b, 0) || interp.arg(b, 1) };
- primTable["not"] = function(b:*):* { return !interp.arg(b, 0) };
- primTable["abs"] = function(b:*):* { return Math.abs(interp.numarg(b, 0)) };
- primTable["sqrt"] = function(b:*):* { return Math.sqrt(interp.numarg(b, 0)) };
-
- primTable["concatenate:with:"] = function(b:*):* { return ("" + interp.arg(b, 0) + interp.arg(b, 1)).substr(0, 10240); };
- primTable["letter:of:"] = primLetterOf;
- primTable["stringLength:"] = function(b:*):* { return String(interp.arg(b, 0)).length };
+ primTable["+"] = function(b:*):* { return interp.numarg(b[0]) + interp.numarg(b[1]) };
+ primTable["-"] = function(b:*):* { return interp.numarg(b[0]) - interp.numarg(b[1]) };
+ primTable["*"] = function(b:*):* { return interp.numarg(b[0]) * interp.numarg(b[1]) };
+ primTable["/"] = function(b:*):* { return interp.numarg(b[0]) / interp.numarg(b[1]) };
+ primTable["randomFrom:to:"] = primRandom;
+ primTable["<"] = function(b:*):* { return compare(b[0], b[1]) < 0 };
+ primTable["="] = function(b:*):* { return compare(b[0], b[1]) == 0 };
+ primTable[">"] = function(b:*):* { return compare(b[0], b[1]) > 0 };
+ primTable["&"] = function(b:*):* { return interp.boolarg(b[0]) && interp.boolarg(b[1]) };
+ primTable["|"] = function(b:*):* { return interp.boolarg(b[0]) || interp.boolarg(b[1]) };
+ primTable["~"] = function(b:*):* { return !interp.boolarg(b[0]) };
+
+
- primTable["%"] = primModulo;
- primTable["rounded"] = function(b:*):* { return Math.round(interp.numarg(b, 0)) };
- primTable["computeFunction:of:"] = primMathFunction;
+ primTable["nand"] = function(b:*):* { return !(interp.boolarg(b[0]) && interp.boolarg(b[1])) };
+ primTable["nor"] = function(b:*):* { return !(interp.boolarg(b[0]) || interp.boolarg(b[1])) }; //if i had realized that it was this simple i should've implemented logic gates since i started making sharp!
+ primTable["xor"] = primLogicXor;
+ primTable["xnor"] = primLogicXnor;
+ primTable["abs"] = function(b:*):* { return Math.abs(interp.numarg(b[0])) };
+ primTable["sqrt"] = function(b:*):* { return Math.sqrt(interp.numarg(b[0])) };
+ primTable["power:of:"] = function(b:*):* { return Math.pow(interp.numarg(b[0]), interp.numarg(b[1])) };
+ primTable["reverseString:"] = primReverseString;
+ primTable["splitStringFrom:"] = primSplit;
+ primTable["bitwiseAnd:"] = function(b:*):* { return interp.numarg(b[0]) & interp.numarg(b[1]) };
+ primTable["bitwiseOr:"] = function(b:*):* { return interp.numarg(b[0]) | interp.numarg(b[1]) };
+ primTable["bitwiseNot:"] = function(b:*):* { return ~ interp.numarg(b[0]) };
+ primTable["bitwiseXor:"] = function(b:*):* { return interp.numarg(b[0]) ^ interp.numarg(b[1]) };
+ primTable["bitwiseLeftShift:"] = function(b:*):* { return interp.numarg(b[0]) << interp.numarg(b[1])};
+ primTable["bitwiseRightShift:"] = function(b:*):* { return interp.numarg(b[0]) >> interp.numarg(b[1])};
+ primTable["factorialOf:"] = primFactorial;
+ primTable["nthFibonacci:"] = primFibonacci;
+ //this block doesn't work so please don't use it until we can fix it
+ //primTable["bitwiseUnsignedShift"] = function(b:*):* { return interp.numarg(b[0]) >>> interp.numarg(b[1])};
+
+ primTable["concatenate:with:"] = function(b:*):* { return ("" + b[0] + b[1]).substr(0, 10240); };
+ primTable["letter:of:"] = primLetterOf;
+ primTable["stringLength:"] = function(b:*):* { return String(b[0]).length };
+ primTable["digitalRootOf:"] = primDigitalRoot;
+ primTable["%"] = primModulo;
+ primTable["rounded"] = function(b:*):* { return Math.round(interp.numarg(b[0])) };
+ primTable["computeFunction:of:"] = primMathFunction;
+ primTable["chooseConstant:"] = primGetConstant;
// clone
primTable["createCloneOf"] = primCreateCloneOf;
@@ -73,59 +108,74 @@ public class Primitives {
primTable["whenCloned"] = interp.primNoop;
// testing (for development)
- primTable["NOOP"] = interp.primNoop;
- primTable["COUNT"] = function(b:*):* { return counter };
+ primTable["NOOP"] = interp.primNoop;
+ primTable["COUNT"] = function(b:*):* { return counter };
primTable["INCR_COUNT"] = function(b:*):* { counter++ };
primTable["CLR_COUNT"] = function(b:*):* { counter = 0 };
- new LooksPrims(app, interp).addPrimsTo(primTable);
- new MotionAndPenPrims(app, interp).addPrimsTo(primTable);
- new SoundPrims(app, interp).addPrimsTo(primTable);
- new VideoMotionPrims(app, interp).addPrimsTo(primTable);
- addOtherPrims(primTable);
+ // Sharp
+ primTable["inlineComment:"] = function(b:*):* {};
+ primTable["true"] = function(b:*):* {return true};
+ primTable["false"] = function(b:*):* {return false};
+ primTable["blockReplace:"] = primStrReplace;
+ primTable["blockSplitReturn:"] = function(b:*):* {return b[0].split(b[1])[b[2]-1]};
+ // Sharp -- HTTP
+ primTable["httpBlock:"] = primHttp;
+ primTable["httpReturn:"] = function(b:*):* {return httpReturn};
+ primTable["goToURL:"] = primGoTo;
+ // Sharp -- Files
+ primTable["saveFile:"] = primFileSave;
+ primTable["loadFile:"] = primFileLoad;
+ primTable["loadedFileName:"] = function(b:*):*{ return fileNameValue; };
+ primTable["loadedFileData:"] = function(b:*):*{ return fileDataValue; };
+ primTable["fileLoaded:"] = primFileLoaded;
+ primTable["fileLoadFailed:"] = primFileLoadFail;
+ primTable["fileLoadFailReason:"] = primFileLoadFailReason;
+ primTable["b64encode:"] = primB64enc;
+
+ new LooksPrims(app, interp).addPrimsTo(primTable, specialTable);
+ new MotionAndPenPrims(app, interp).addPrimsTo(primTable, specialTable);
+ new SoundPrims(app, interp).addPrimsTo(primTable, specialTable);
+ new VideoMotionPrims(app, interp).addPrimsTo(primTable, specialTable);
+ addOtherPrims(primTable, specialTable);
}
- protected function addOtherPrims(primTable:Dictionary):void {
- new SensingPrims(app, interp).addPrimsTo(primTable);
- new ListPrims(app, interp).addPrimsTo(primTable);
+ protected function addOtherPrims(primTable:Dictionary, specialTable:Dictionary):void {
+ new SensingPrims(app, interp).addPrimsTo(primTable, specialTable);
+ new ListPrims(app, interp).addPrimsTo(primTable, specialTable);
}
- private function primRandom(b:Block):Number {
- var n1:Number = interp.numarg(b, 0);
- var n2:Number = interp.numarg(b, 1);
+ private function primRandom(b:Array):Number {
+ var n1:Number = interp.numarg(b[0]);
+ var n2:Number = interp.numarg(b[1]);
var low:Number = (n1 <= n2) ? n1 : n2;
var hi:Number = (n1 <= n2) ? n2 : n1;
if (low == hi) return low;
-
// if both low and hi are ints, truncate the result to an int
- var ba1:BlockArg = b.args[0] as BlockArg;
- var ba2:BlockArg = b.args[1] as BlockArg;
- var int1:Boolean = ba1 ? ba1.numberType == BlockArg.NT_INT : int(n1) == n1;
- var int2:Boolean = ba2 ? ba2.numberType == BlockArg.NT_INT : int(n2) == n2;
- if (int1 && int2)
+ if ((int(low) == low) && (int(hi) == hi)) {
return low + int(Math.random() * ((hi + 1) - low));
-
+ }
return (Math.random() * (hi - low)) + low;
}
- private function primLetterOf(b:Block):String {
- var s:String = interp.arg(b, 1);
- var i:int = interp.numarg(b, 0) - 1;
+ private function primLetterOf(b:Array):String {
+ var s:String = b[1];
+ var i:int = interp.numarg(b[0]) - 1;
if ((i < 0) || (i >= s.length)) return "";
return s.charAt(i);
}
- private function primModulo(b:Block):Number {
- var n:Number = interp.numarg(b, 0);
- var modulus:Number = interp.numarg(b, 1);
+ private function primModulo(b:Array):Number {
+ var n:Number = interp.numarg(b[0]);
+ var modulus:Number = interp.numarg(b[1]);
var result:Number = n % modulus;
if (result / modulus < 0) result += modulus;
return result;
}
- private function primMathFunction(b:Block):Number {
- var op:* = interp.arg(b, 0);
- var n:Number = interp.numarg(b, 1);
+ private function primMathFunction(b:Array):Number {
+ var op:* = b[0];
+ var n:Number = interp.numarg(b[1]);
switch(op) {
case "abs": return Math.abs(n);
case "floor": return Math.floor(n);
@@ -173,8 +223,8 @@ public class Primitives {
return 1;
}
- private function primCreateCloneOf(b:Block):void {
- var objName:String = interp.arg(b, 0);
+ private function primCreateCloneOf(b:Array):void {
+ var objName:String = b[0];
var proto:ScratchSprite = app.stagePane.spriteNamed(objName);
if ('_myself_' == objName) proto = interp.activeThread.target;
if (!proto) return;
@@ -196,7 +246,7 @@ public class Primitives {
app.runtime.cloneCount++;
}
- private function primDeleteClone(b:Block):void {
+ private function primDeleteClone(b:Array):void {
var clone:ScratchSprite = interp.targetSprite();
if ((clone == null) || (!clone.isClone) || (clone.parent == null)) return;
if (clone.bubble && clone.bubble.parent) {
@@ -208,4 +258,239 @@ public class Primitives {
app.runtime.cloneCount--;
}
+ private function primReverseString(b:Array):String {
+ var reverse:String = b[0];
+ var result:String = "";
+ var i:int;
+ for(i = reverse.length; i > 0; i--) {
+ result += reverse.charAt(i-1);
+ }
+ return result;
+
+ }
+
+ private function primGetConstant(b:Array):Number {
+ var pickConstant:* = b[0];
+ switch(pickConstant) {
+ case "Pi": return Math.PI;
+ case "E": return Math.E;
+ case "Phi": return (1 + Math.sqrt(5)) / 2;
+ }
+ return 0;
+ }
+ private function primSplit(b:Array):String {
+ var a:String = b[0];
+ var result:String = "";
+ var i:int;
+ var j:int = interp.numarg(b[2]);
+ for(i = interp.numarg(b[1]); i < j + 1; i++) {
+ result += a.charAt(i -1);
+ }
+ return result;
+
+ }
+ // Sharp
+ private function primStrReplace(b:Array):String{
+ return b[1].replace(new RegExp(b[0], "g"), b[2]);
+ }
+ private function primDigitalRoot(b:Array):Number{
+ if(interp.numarg(b[0]) < 9){
+ return interp.numarg(b[0])
+ } else {
+ return interp.numarg(b[0]) - (9 * Math.floor((interp.numarg(b[0])-1)/9));
+ }
+ }
+
+
+ private function primLogicXor(b:Array):Boolean{
+ if(interp.boolarg(b[0]) !== interp.boolarg(b[1])){
+ return true;
+ } else if (interp.boolarg(b[0]) == interp.boolarg(b[1])) {
+ return false;
+ } else {
+ return false;
+ }
+ }
+
+ private function primLogicXnor(b:Array):Boolean{
+ if (interp.boolarg(b[0]) == interp.boolarg(b[1])) {
+ return true;
+ } else {
+ return false;
+ }
+ return false;
+ }
+ // Sharp --- HTTP
+ private function primHttp(b:Array):void {
+ if(httpRequestsActive == httpRequestsAllowed) return;
+ httpRequestsActive++;
+ var url:String = b[1];
+ var req:URLRequest = new URLRequest(url);
+ req.method = URLRequestMethod.GET;
+
+ var loader:URLLoader = new URLLoader();
+ loader.addEventListener(Event.COMPLETE, onComplete);
+ loader.dataFormat = URLLoaderDataFormat.TEXT;
+ loader.load(req);
+
+ function onComplete(e:Event){
+ httpReturn = e.target.data.readUTFBytes(e.target.data.bytesAvailable);
+ httpRequestsActive--;
+ }
+ }
+ private function primGoTo(b:Array):void{
+ DialogBox.confirm("Do you want to go to '" + b[0] + "'?", null, okFunc);
+ function okFunc():void{
+ var request:URLRequest = new URLRequest(b[0]);
+ navigateToURL(request, "_blank");
+ }
+ }
+ //Sharp --- Files
+ private function primFileSave(b:Array):void{
+ fileLoadedValue = false;
+ fileErrored = false;
+ fileErrorValue = "";
+ DialogBox.confirm("Would you like to save the file '" + b[1] + "' to your computer?", null, okFunc, cancelFunc);
+ function okFunc():void{
+ function cancelHandle(e:Event){
+ fileLoadedValue = true;
+ fileErrored = true;
+ fileErrorValue = "Cancelled by user";
+ }
+ function ioErrorHandle(e:IOErrorEvent){
+ fileLoadedValue = true;
+ fileErrored = true;
+ fileErrorValue = "An IO error occurred!";
+ }
+ function securityError(e:SecurityErrorEvent){
+ fileLoadedValue = true;
+ fileErrored = true;
+ fileErrorValue = "A security error occurred! This is most likely a problem with Sharp!";
+ }
+ var file:FileReference = new FileReference();
+ file.addEventListener(Event.CANCEL, cancelHandle);
+ file.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandle);
+ file.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityError);
+ file.save(b[0], b[1]);
+ fileLoadedValue = true;
+ }
+ function cancelFunc():void{
+ fileLoadedValue = true;
+ fileErrored = true;
+ fileErrorValue = "Denied by user";
+ }
+ }
+ private function primFileLoad(b:Array):void{
+ fileLoadedValue = false;
+ fileErrored = false;
+ fileErrorValue = "";
+ DialogBox.confirm("Would you like to open a file from your computer?", null, okFunc, cancelFunc);
+ function okFunc():void{
+ var fileName:String, data:ByteArray;
+ function cancelHandle(e:Event){
+ fileLoadedValue = true;
+ fileErrored = true;
+ fileErrorValue = "Cancelled by user";
+ }
+ function ioErrorHandle(e:IOErrorEvent){
+ fileLoadedValue = true;
+ fileErrored = true;
+ fileErrorValue = "An IO error occurred!";
+ }
+ function securityError(e:SecurityErrorEvent){
+ fileLoadedValue = true;
+ fileErrored = true;
+ fileErrorValue = "A security error occurred! This is most likely a problem with Sharp!";
+ }
+ function fileLoaded(event:Event):void{
+ var file:FileReference = FileReference(event.target);
+ file.addEventListener(Event.CANCEL, cancelHandle);
+ file.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandle);
+ file.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityError);
+ fileName = file.name;
+ data = file.data;
+
+ fileNameValue = fileName;
+ fileDataValue = data.readUTFBytes(data.bytesAvailable);
+ fileLoadedValue = true;
+ }
+ function fileSelected(event:Event):void{
+ var file:FileReference = FileReference(fileList.fileList[0]);
+ file.addEventListener(Event.COMPLETE, fileLoaded);
+ file.load();
+ }
+ var fileList:FileReferenceList = new FileReferenceList();
+ fileList.addEventListener(Event.SELECT, fileSelected);
+ fileList.addEventListener(Event.CANCEL, cancelHandle);
+ fileList.addEventListener(IOErrorEvent.IO_ERROR, ioErrorHandle);
+ fileList.addEventListener(SecurityErrorEvent.SECURITY_ERROR, securityError);
+ try{
+ fileList.browse(null);
+ }catch(e:*){}
+ }
+ function cancelFunc():void{
+ fileLoadedValue = true;
+ fileErrored = true;
+ fileErrorValue = "Denied by user";
+ }
+ }
+ private function primFileLoaded(b:Array):Boolean{
+ //var bl:Boolean = fileLoadedValue;
+ //fileLoadedValue = false;
+ return fileLoadedValue;
+ }
+ private function primFileLoadFail(b:Array):Boolean{
+ return fileErrored;
+ }
+ private function primFileLoadFailReason(b:Array):String{
+ return fileErrorValue;
+ }
+
+ private function primFactorial(b:Array):Number{
+ function factorial(n:int){
+ if (n < 2) {
+ return 1;
+ }
+ return n*factorial(n-1);
+ }
+ return factorial(interp.numarg(b[0]));
+ }
+ private function primFibonacci(b:Array):Number{
+ function getFibonacci(n:int){
+ var f1:int, f2:int, f:int, i:int;
+ if(n < 2){
+ return n;
+ }
+ f1 = 0;
+ f2 = 1;
+ for(i = 2; i <= n; i++){
+ f = f1;
+ f1 = f2;
+ f2 = f + f1;
+ }
+ return f2;
+ }
+ return getFibonacci(interp.numarg(b[0]));
+ }
+
+ private function primB64enc(b:Array):String{
+ function encode64(input) {
+ //no decode yet, sorry :(
+ var output = "", i = 0, l = input.length, key = "ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz0123456789+/=", chr1, chr2, chr3, enc1, enc2, enc3, enc4;
+ while (i < l) {
+ chr1 = input.charCodeAt(i++);
+ chr2 = input.charCodeAt(i++);
+ chr3 = input.charCodeAt(i++);
+ enc1 = chr1 >> 2;
+ enc2 = ((chr1 & 3) << 4) | (chr2 >> 4);
+ enc3 = ((chr2 & 15) << 2) | (chr3 >> 6);
+ enc4 = chr3 & 63;
+ if (isNaN(chr2)) enc3 = enc4 = 64;
+ else if (isNaN(chr3)) enc4 = 64;
+ output = output + key.charAt(enc1) + key.charAt(enc2) + key.charAt(enc3) + key.charAt(enc4);
+ }
+ return output;
+ }
+ return encode64(b[0]);
+ }
}}
diff --git a/src/primitives/SensingPrims.as b/src/primitives/SensingPrims.as
index 5aa5d1775..4d46c3f6b 100644
--- a/src/primitives/SensingPrims.as
+++ b/src/primitives/SensingPrims.as
@@ -30,24 +30,30 @@ package primitives {
import blocks.Block;
import interpreter.*;
import scratch.*;
+ import uiwidgets.DialogBox;
+ import com.adobe.crypto.MD5;
+ import com.adobe.crypto.SHA256;
public class SensingPrims {
private var app:Scratch;
private var interp:Interpreter;
-
+
+ private var dialogBoxAllowed = 10; private var dialogBoxActive = 0; // TODO: Add hidden setting for dialog boxs allowed
+ private var passwordWarningHasBeenShown:Boolean = false;
+
public function SensingPrims(app:Scratch, interpreter:Interpreter) {
this.app = app;
this.interp = interpreter;
}
- public function addPrimsTo(primTable:Dictionary):void {
+ public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void {
// sensing
primTable['touching:'] = primTouching;
primTable['touchingColor:'] = primTouchingColor;
primTable['color:sees:'] = primColorSees;
- primTable['doAsk'] = primAsk;
+ specialTable['doAsk'] = primAsk;
primTable['answer'] = function(b:*):* { return app.runtime.lastAnswer };
primTable['mousePressed'] = function(b:*):* { return app.gh.mouseIsDown };
@@ -61,26 +67,120 @@ public class SensingPrims {
primTable['soundLevel'] = function(b:*):* { return app.runtime.soundLevel() };
primTable['isLoud'] = function(b:*):* { return app.runtime.isLoud() };
primTable['timestamp'] = primTimestamp;
- primTable['timeAndDate'] = function(b:*):* { return app.runtime.getTimeString(interp.arg(b, 0)) };
- primTable['getUserName'] = function(b:*):* { return '' };
+ primTable['timeAndDate'] = function(b:*):* { return app.runtime.getTimeString(b[0]) };
+ //primTable['getUserName'] = function(b:*):* { return '' };
// sensor
- primTable['sensor:'] = function(b:*):* { return app.runtime.getSensor(interp.arg(b, 0)) };
- primTable['sensorPressed:'] = function(b:*):* { return app.runtime.getBooleanSensor(interp.arg(b, 0)) };
+ primTable['sensor:'] = function(b:*):* { return app.runtime.getSensor(b[0]) };
+ primTable['sensorPressed:'] = function(b:*):* { return app.runtime.getBooleanSensor(b[0]) };
// variable and list watchers
primTable['showVariable:'] = primShowWatcher;
primTable['hideVariable:'] = primHideWatcher;
primTable['showList:'] = primShowListWatcher;
primTable['hideList:'] = primHideListWatcher;
+
+ // Sharp
+ primTable["notify:"] = primNotify;
+ primTable["askBox:"] = primAskBox;
+ primTable["confirm:"] = primConfirm;
+ primTable["isInEditor:"] = function(b:*):* { return app.editMode };
+ primTable["isInFullscreen:"] = function(b:*):* { return app.isFullScreen };
+ primTable["usingTurboMode:"] = function(b:*):* { return interp.turboMode };
+ primTable["sharpVersion:"] = function(b:*):* { return Scratch.versionString };
+ primTable["passwordHash:"] = primPasswordHash;
+ primTable["passwordVerify:"] = primPasswordVerify;
+ primTable["passwordRehash:"] = primPasswordRehashCheck;
+ }
+
+ // Sharp
+ private function primNotify(b:Array):void{
+ if(dialogBoxActive == dialogBoxAllowed) return;
+ dialogBoxActive++;
+ DialogBox.notify(b[1],b[0],null,false, function(d:*):*{ dialogBoxActive--; });
+ }
+ private function primAskBox(b:Array):void{
+ if(dialogBoxActive == dialogBoxAllowed) return;
+ dialogBoxActive++;
+ DialogBox.ask(b[0], b[1], null, function(ans:*):*{
+ app.runtime.lastAnswer = ans;
+ dialogBoxActive--;
+ });
+ }
+ private function primConfirm(b:Array):void{
+ if(dialogBoxActive == dialogBoxAllowed) return;
+ dialogBoxActive++;
+ DialogBox.confirm(b[0], null, function(d:*):*{
+ app.runtime.lastAnswer = "true";
+ dialogBoxActive--;
+ }, function(d:*):*{
+ app.runtime.lastAnswer = "false";
+ dialogBoxActive--;
+ });
+ }
+ private function primPasswordHash(b:Array):String{
+ if(app.editMode && !passwordWarningHasBeenShown){
+ //The password blocks are not made for and should not be used for real encryption purposes.\nIt uses MD5 to hash the password.\nIn the future the block encryption may change from MD5.\n\nIf the encryption is changed a password needs conversion boolean block will be added.\nThe hash block will return passwords with the new encryption\nThe verify block will verify for both the old and new encryption\n\n\nNOTE: This notice is shown once per session. And only while in the editor.\nIt is recommended for you to tell your users not to use real passwords
+ DialogBox.notify("Warning!", "The password blocks are not made for real password use.\nIt uses SHA256 to hash the password.\nIn the future the block encryption may change from SHA256.\n\nTo convert from MD5 use the password needs rehash boolean and password hash the password\nThe verify block can handle the MD5 and SHA256 methods.\n\n\nNOTE: This notice is shown once per session. And only while in the editor.\nIt is recommended for you to tell your users not to use real passwords");
+ passwordWarningHasBeenShown = true;
+ }
+ //Hashing methods
+ //01 = MD5
+ //02 = SHA256
+ var hash:String = "02" + SHA256.hash(b[0]);
+ return hash;
+ }
+ private function primPasswordVerify(b:Array):Boolean{
+ if(app.editMode && !passwordWarningHasBeenShown){
+ //DialogBox.notify("Warning!", "The password blocks are not made for and should not be used for real encryption purposes.\nIt uses MD5 to hash the password.\nIn the future the block encryption may change from MD5.");
+ //DialogBox.notify("Warning!", "If the encryption is changed a password needs conversion will be added.\nThe hash block will return passwords with the new encryption\nThe verify block will verify for both the old and new encryption");
+ DialogBox.notify("Warning!", "The password blocks are not made for real password use.\nIt uses SHA256 to hash the password.\nIn the future the block encryption may change from SHA256.\n\nTo convert from MD5 use the password needs rehash boolean and password hash the password\nThe verify block can handle the MD5 and SHA256 methods.\n\n\nNOTE: This notice is shown once per session. And only while in the editor.\nIt is recommended for you to tell your users not to use real passwords");
+ passwordWarningHasBeenShown = true;
+ }
+ //Hashing methods in passwordHash function
+ if(b[0].charAt(0) == "0" && b[0].charAt(1) == "1"){
+ var hash:String = MD5.hash(b[1]);
+ if(hash === b[0].substr(2)){
+ return true;
+ }else{
+ return false;
+ }
+ }else if(b[0].charAt(0) == "0" && b[0].charAt(1) == "2"){
+ var hash:String = SHA256.hash(b[1]);
+ if(hash === b[0].substr(2)){
+ return true;
+ }else{
+ return false;
+ }
+ }
+ else{
+ return false;
+ }
+ }
+ private function primPasswordRehashCheck(b:Array):Boolean{
+ if(app.editMode && !passwordWarningHasBeenShown){
+ //DialogBox.notify("Warning!", "The password blocks are not made for and should not be used for real encryption purposes.\nIt uses MD5 to hash the password.\nIn the future the block encryption may change from MD5.");
+ //DialogBox.notify("Warning!", "If the encryption is changed a password needs conversion will be added.\nThe hash block will return passwords with the new encryption\nThe verify block will verify for both the old and new encryption");
+ DialogBox.notify("Warning!", "The password blocks are used at your own risk.\nIt uses SHA256 to hash the password.\nIn the future the block encryption may change from SHA256.\n\nTo convert from MD5 use the password needs rehash boolean and password hash the password\nThe verify block can handle the MD5 and SHA256 methods.\n\n\nNOTE: This notice is shown once per session. And only while in the editor.\nIt is recommended for you to tell your users not to use real passwords");
+ passwordWarningHasBeenShown = true;
+ }
+ //Hashing methods in passwordHash function
+ if(b[0].charAt(0) == "0" && b[0].charAt(1) == "1"){
+ return true
+ }else if(b[0].charAt(0) == "0" && b[0].charAt(1) == "2"){
+ return false;
+ }
+ else{
+ return false;
+ }
}
// TODO: move to stage
static private var stageRect:Rectangle = new Rectangle(0, 0, 480, 360);
- private function primTouching(b:Block):Boolean {
+ private function primTouching(b:Array):Boolean {
var s:ScratchSprite = interp.targetSprite();
if (s == null) return false;
- var arg:* = interp.arg(b, 0);
+ var arg:* = b[0];
if ('_edge_' == arg) {
if(stageRect.containsRect(s.getBounds(s.parent))) return false;
@@ -116,12 +216,12 @@ public class SensingPrims {
// private var testSpr:Sprite;
// private var myBMTest:Bitmap;
// private var stageBMTest:Bitmap;
- private function primTouchingColor(b:Block):Boolean {
+ private function primTouchingColor(b:Array):Boolean {
// Note: Attempted to switch app.stage.quality to LOW to disable anti-aliasing, which
// can create false colors. Unfortunately, that caused serious performance issues.
var s:ScratchSprite = interp.targetSprite();
if (s == null) return false;
- var c:int = interp.arg(b, 0) | 0xFF000000;
+ var c:int = b[0] | 0xFF000000;
var myBM:BitmapData = s.bitmap(true);
var stageBM:BitmapData = stageBitmapWithoutSpriteFilteredByColor(s, c);
// if(s.objName == 'sensor') {
@@ -144,13 +244,13 @@ public class SensingPrims {
return myBM.hitTest(new Point(0, 0), 1, stageBM, new Point(0, 0), 1);
}
- private function primColorSees(b:Block):Boolean {
+ private function primColorSees(b:Array):Boolean {
// Note: Attempted to switch app.stage.quality to LOW to disable anti-aliasing, which
// can create false colors. Unfortunately, that caused serious performance issues.
var s:ScratchSprite = interp.targetSprite();
if (s == null) return false;
- var c1:int = interp.arg(b, 0) | 0xFF000000;
- var c2:int = interp.arg(b, 1) | 0xFF000000;
+ var c1:int = b[0] | 0xFF000000;
+ var c2:int = b[1] | 0xFF000000;
var myBM:BitmapData = bitmapFilteredByColor(s.bitmap(true), c1);
var stageBM:BitmapData = stageBitmapWithoutSpriteFilteredByColor(s, c2);
// if(!testSpr) {
@@ -199,7 +299,7 @@ public class SensingPrims {
return app.stagePane.getBitmapWithoutSpriteFilteredByColor(s, c);
}
- private function primAsk(b:Block):void {
+ private function primAsk(b:Array):void {
if (app.runtime.askPromptShowing()) {
// wait if (1) some other sprite is asking (2) this question is answered (when firstTime is false)
interp.doYield();
@@ -207,7 +307,7 @@ public class SensingPrims {
}
var obj:ScratchObj = interp.targetObj();
if (interp.activeThread.firstTime) {
- var question:String = interp.arg(b, 0);
+ var question:String = b[0];
if ((obj is ScratchSprite) && (obj.visible)) {
ScratchSprite(obj).showBubble(question, 'talk', obj, true);
app.runtime.showAskPrompt('');
@@ -218,12 +318,15 @@ public class SensingPrims {
interp.doYield();
} else {
if ((obj is ScratchSprite) && (obj.visible)) ScratchSprite(obj).hideBubble();
- interp.activeThread.firstTime = true;
+ var block:Block = interp.activeThread.block;
+ interp.activeThread.popState();
+ interp.activeThread.firstTime = true;
+ if (block.nextBlock) interp.activeThread.pushStateForBlock(block.nextBlock);
}
}
- private function primKeyPressed(b:Block):Boolean {
- var key:String = interp.arg(b, 0);
+ private function primKeyPressed(b:Array):Boolean {
+ var key:String = b[0];
if (key == 'any') {
for each (var k:Boolean in app.runtime.keyIsDown) {
if (k) return true;
@@ -237,23 +340,27 @@ public class SensingPrims {
case 'up arrow': ch = Keyboard.UP; break;
case 'down arrow': ch = Keyboard.DOWN; break;
case 'space': ch = Keyboard.SPACE; break;
+ case 'shift': ch = Keyboard.SHIFT; break;
+ case 'enter': ch = Keyboard.ENTER; break;
+ case 'backspace': ch = Keyboard.BACKSPACE; break;
+ case 'control': ch = Keyboard.CONTROL; break;
default: ch = key.toUpperCase().charCodeAt(0); break;
}
return app.runtime.keyIsDown[ch] || false;
}
- private function primDistanceTo(b:Block):Number {
+ private function primDistanceTo(b:Array):Number {
var s:ScratchSprite = interp.targetSprite();
- var p:Point = mouseOrSpritePosition(interp.arg(b, 0));
+ var p:Point = mouseOrSpritePosition(b[0]);
if ((s == null) || (p == null)) return 10000;
var dx:Number = p.x - s.scratchX;
var dy:Number = p.y - s.scratchY;
return Math.sqrt((dx * dx) + (dy * dy));
}
- private function primGetAttribute(b:Block):* {
- var attribute:String = interp.arg(b, 0);
- var obj:ScratchObj = app.stagePane.objNamed(String(interp.arg(b, 1)));
+ private function primGetAttribute(b:Array):* {
+ var attribute:String = b[0];
+ var obj:ScratchObj = app.stagePane.objNamed(String(b[1]));
if (!(obj is ScratchObj)) return 0;
if (obj is ScratchSprite) {
var s:ScratchSprite = ScratchSprite(obj);
@@ -286,27 +393,27 @@ public class SensingPrims {
return null;
}
- private function primShowWatcher(b:Block):* {
+ private function primShowWatcher(b:Array):* {
var obj:ScratchObj = interp.targetObj();
- if (obj) app.runtime.showVarOrListFor(interp.arg(b, 0), false, obj);
+ if (obj) app.runtime.showVarOrListFor(b[0], false, obj);
}
- private function primHideWatcher(b:Block):* {
+ private function primHideWatcher(b:Array):* {
var obj:ScratchObj = interp.targetObj();
- if (obj) app.runtime.hideVarOrListFor(interp.arg(b, 0), false, obj);
+ if (obj) app.runtime.hideVarOrListFor(b[0], false, obj);
}
- private function primShowListWatcher(b:Block):* {
+ private function primShowListWatcher(b:Array):* {
var obj:ScratchObj = interp.targetObj();
- if (obj) app.runtime.showVarOrListFor(interp.arg(b, 0), true, obj);
+ if (obj) app.runtime.showVarOrListFor(b[0], true, obj);
}
- private function primHideListWatcher(b:Block):* {
+ private function primHideListWatcher(b:Array):* {
var obj:ScratchObj = interp.targetObj();
- if (obj) app.runtime.hideVarOrListFor(interp.arg(b, 0), true, obj);
+ if (obj) app.runtime.hideVarOrListFor(b[0], true, obj);
}
- private function primTimestamp(b:Block):* {
+ private function primTimestamp(b:Array):* {
const millisecondsPerDay:int = 24 * 60 * 60 * 1000;
const epoch:Date = new Date(2000, 0, 1); // Jan 1, 2000 (Note: Months are zero-based.)
var now:Date = new Date();
diff --git a/src/primitives/SoundPrims.as b/src/primitives/SoundPrims.as
index 7bc70bda1..caf463da3 100644
--- a/src/primitives/SoundPrims.as
+++ b/src/primitives/SoundPrims.as
@@ -39,16 +39,16 @@ public class SoundPrims {
this.interp = interpreter;
}
- public function addPrimsTo(primTable:Dictionary):void {
+ public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void {
primTable["playSound:"] = primPlaySound;
- primTable["doPlaySoundAndWait"] = primPlaySoundUntilDone;
+ specialTable["doPlaySoundAndWait"] = primPlaySoundUntilDone;
primTable["stopAllSounds"] = function(b:*):* { ScratchSoundPlayer.stopAllSounds() };
- primTable["drum:duration:elapsed:from:"] = primPlayDrum; // Scratch 1.4 drum numbers
- primTable["playDrum"] = primPlayDrum;
- primTable["rest:elapsed:from:"] = primPlayRest;
+ specialTable["drum:duration:elapsed:from:"] = primPlayDrum; // Scratch 1.4 drum numbers
+ specialTable["playDrum"] = primPlayDrum;
+ specialTable["rest:elapsed:from:"] = primPlayRest;
- primTable["noteOn:duration:elapsed:from:"] = primPlayNote;
+ specialTable["noteOn:duration:elapsed:from:"] = primPlayNote;
primTable["midiInstrument:"] = primSetInstrument; // Scratch 1.4 instrument numbers
primTable["instrument:"] = primSetInstrument;
@@ -56,45 +56,42 @@ public class SoundPrims {
primTable["setVolumeTo:"] = primSetVolume;
primTable["volume"] = primVolume;
- primTable["changeTempoBy:"] = function(b:*):* {
- app.stagePane.setTempo(app.stagePane.tempoBPM + interp.numarg(b, 0));
- interp.redraw();
- };
- primTable["setTempoTo:"] = function(b:*):* {
- app.stagePane.setTempo(interp.numarg(b, 0));
- interp.redraw();
- };
+ primTable["changeTempoBy:"] = function(b:*):* { app.stagePane.setTempo(app.stagePane.tempoBPM + interp.numarg(b[0])) };
+ primTable["setTempoTo:"] = function(b:*):* { app.stagePane.setTempo(interp.numarg(b[0])) };
primTable["tempo"] = function(b:*):* { return app.stagePane.tempoBPM };
}
- private function primPlaySound(b:Block):void {
- var snd:ScratchSound = interp.targetObj().findSound(interp.arg(b, 0));
+ private function primPlaySound(b:Array):void {
+ var snd:ScratchSound = interp.targetObj().findSound(b[0]);
if (snd != null) playSound(snd, interp.targetObj());
}
- private function primPlaySoundUntilDone(b:Block):void {
+ private function primPlaySoundUntilDone(b:Array):void {
var activeThread:Thread = interp.activeThread;
if (activeThread.firstTime) {
- var snd:ScratchSound = interp.targetObj().findSound(interp.arg(b, 0));
+ var snd:ScratchSound = interp.targetObj().findSound(b[0]);
if (snd == null) return;
activeThread.tmpObj = playSound(snd, interp.targetObj());
activeThread.firstTime = false;
}
var player:ScratchSoundPlayer = ScratchSoundPlayer(activeThread.tmpObj);
- if ((player == null) || (player.atEnd())) { // finished playing
+ if ((player == null) || player.atEnd()) { // finished playing
activeThread.tmp = 0;
activeThread.firstTime = true;
+ var block:Block = activeThread.block;
+ activeThread.popState();
+ if (block.nextBlock) activeThread.pushStateForBlock(block.nextBlock);
} else {
interp.doYield();
}
}
- private function primPlayNote(b:Block):void {
+ private function primPlayNote(b:Array):void {
var s:ScratchObj = interp.targetObj();
if (s == null) return;
if (interp.activeThread.firstTime) {
- var key:Number = interp.numarg(b, 0);
- var secs:Number = beatsToSeconds(interp.numarg(b, 1));
+ var key:Number = interp.numarg(b[0]);
+ var secs:Number = beatsToSeconds(interp.numarg(b[1]));
interp.activeThread.tmpObj = playNote(s.instrument, key, secs, s);
interp.startTimer(secs);
} else {
@@ -102,13 +99,13 @@ public class SoundPrims {
}
}
- private function primPlayDrum(b:Block):void {
+ private function primPlayDrum(b:Array):void {
var s:ScratchObj = interp.targetObj();
if (s == null) return;
if (interp.activeThread.firstTime) {
- var drum:int = Math.round(interp.numarg(b, 0));
+ var drum:int = Math.round(interp.numarg(b[0]));
var isMIDI:Boolean = (b.op == 'drum:duration:elapsed:from:');
- var secs:Number = beatsToSeconds(interp.numarg(b, 1));
+ var secs:Number = beatsToSeconds(interp.numarg(b[1]));
playDrum(drum, isMIDI, 10, s); // always play entire drum sample
interp.startTimer(secs);
} else {
@@ -141,11 +138,11 @@ public class SoundPrims {
return player;
}
- private function primPlayRest(b:Block):void {
+ private function primPlayRest(b:Array):void {
var s:ScratchObj = interp.targetObj();
if (s == null) return;
if (interp.activeThread.firstTime) {
- var secs:Number = beatsToSeconds(interp.numarg(b, 0));
+ var secs:Number = beatsToSeconds(interp.numarg(b[0]));
interp.startTimer(secs);
} else {
interp.checkTimer();
@@ -156,9 +153,9 @@ public class SoundPrims {
return (beats * 60) / app.stagePane.tempoBPM;
}
- private function primSetInstrument(b:Block):void {
+ private function primSetInstrument(b:Array):void {
// Set Scratch 2.0 instrument.
- var instr:int = interp.numarg(b, 0) - 1;
+ var instr:int = interp.numarg(b[0]) - 1;
if (b.op == 'midiInstrument:') {
// map old to new instrument number
instr = instrumentMap[instr] - 1; // maps to -1 if out of range
@@ -167,23 +164,17 @@ public class SoundPrims {
if (interp.targetObj()) interp.targetObj().instrument = instr;
}
- private function primChangeVolume(b:Block):void {
+ private function primChangeVolume(b:Array):void {
var s:ScratchObj = interp.targetObj();
- if (s != null) {
- s.setVolume(s.volume + interp.numarg(b, 0));
- interp.redraw();
- }
+ if (s != null) s.setVolume(s.volume + interp.numarg(b[0]));
}
- private function primSetVolume(b:Block):void {
+ private function primSetVolume(b:Array):void {
var s:ScratchObj = interp.targetObj();
- if (s != null) {
- s.setVolume(interp.numarg(b, 0));
- interp.redraw();
- }
+ if (s != null) s.setVolume(interp.numarg(b[0]));
}
- private function primVolume(b:Block):Number {
+ private function primVolume(b:Array):Number {
var s:ScratchObj = interp.targetObj();
return (s != null) ? s.volume : 0;
}
@@ -255,5 +246,4 @@ public class SoundPrims {
// Telephone Ring, Helicopter, Applause, Gunshot
21, 21, 21, 21
];
-
-}}
+}}
\ No newline at end of file
diff --git a/src/primitives/VideoMotionPrims.as b/src/primitives/VideoMotionPrims.as
index 6bf77bf42..12b958348 100644
--- a/src/primitives/VideoMotionPrims.as
+++ b/src/primitives/VideoMotionPrims.as
@@ -65,15 +65,15 @@ public class VideoMotionPrims {
frameBuffer = new BitmapData(WIDTH, HEIGHT);
}
- public function addPrimsTo(primTable:Dictionary):void {
+ public function addPrimsTo(primTable:Dictionary, specialTable:Dictionary):void {
primTable['senseVideoMotion'] = primVideoMotion;
readMotionSensor = getMotionOn;
}
- private function primVideoMotion(b:Block):Number {
- var motionType:String = interp.arg(b, 0);
- var obj:ScratchObj = app.stagePane.objNamed(String(interp.arg(b, 1)));
- if ('this sprite' == interp.arg(b, 1)) obj = interp.targetObj();
+ private function primVideoMotion(b:Array):Number {
+ var motionType:String = b[0];
+ var obj:ScratchObj = app.stagePane.objNamed(String(b[1]));
+ if ('this sprite' == b[1]) obj = interp.targetObj();
return getMotionOn(motionType, obj);
}
@@ -282,4 +282,4 @@ public class VideoMotionPrims {
analysisDone = true;
}
-}}
+}}
\ No newline at end of file
diff --git a/src/scratch/BlockMenus.as b/src/scratch/BlockMenus.as
index e61a95da6..cdcb08167 100644
--- a/src/scratch/BlockMenus.as
+++ b/src/scratch/BlockMenus.as
@@ -95,12 +95,15 @@ public class BlockMenus implements DragClient {
if (menuName == 'spriteOrStage') menuHandler.spriteMenu(evt, false, false, true, false, false);
if (menuName == 'touching') menuHandler.spriteMenu(evt, true, true, false, false, false);
if (menuName == 'stageOrThis') menuHandler.stageOrThisSpriteMenu(evt);
+ if (menuName == 'spriteNotSelf') menuHandler.spriteMenu(evt, false, false, false, false, false);
if (menuName == 'stop') menuHandler.stopMenu(evt);
if (menuName == 'timeAndDate') menuHandler.timeAndDateMenu(evt);
if (menuName == 'triggerSensor') menuHandler.triggerSensorMenu(evt);
if (menuName == 'var') menuHandler.varMenu(evt);
if (menuName == 'videoMotionType') menuHandler.videoMotionTypeMenu(evt);
if (menuName == 'videoState') menuHandler.videoStateMenu(evt);
+ if (menuName == 'httpMethod') menuHandler.httpMethodMenu(evt);
+ if (menuName == 'constantName') menuHandler.constantMenu(evt);
}
public static function strings():Array {
@@ -116,6 +119,7 @@ public class BlockMenus implements DragClient {
handler.broadcastMenu(evt);
handler.broadcastInfoMenu(evt);
handler.costumeMenu(evt);
+ handler.constantMenu(evt);
handler.dirMenu(evt);
handler.drumMenu(evt);
handler.effectMenu(evt);
@@ -136,6 +140,7 @@ public class BlockMenus implements DragClient {
handler.spriteMenu(evt, true, false, false, false, true);
handler.spriteMenu(evt, false, false, true, false, false);
handler.spriteMenu(evt, true, true, false, false, false);
+ handler.spriteMenu(evt, false, false, false, false, false);
handler.stageOrThisSpriteMenu(evt);
handler.stopMenu(evt);
handler.timeAndDateMenu(evt);
@@ -143,6 +148,7 @@ public class BlockMenus implements DragClient {
handler.varMenu(evt);
handler.videoMotionTypeMenu(evt);
handler.videoStateMenu(evt);
+ handler.httpMethodMenu(evt);
}
return [
'up arrow', 'down arrow', 'right arrow', 'left arrow', 'space', 'any',
@@ -189,6 +195,7 @@ public class BlockMenus implements DragClient {
case 'spriteOrMouse':
case 'location':
case 'spriteOrStage':
+ case 'spriteNotSelf':
case 'touching':
return false; // handled directly by menu code
case 'var':
@@ -311,7 +318,7 @@ public class BlockMenus implements DragClient {
private function keyMenu(evt:MouseEvent):void {
var ch:int;
- var namedKeys:Array = ['space', 'up arrow', 'down arrow', 'right arrow', 'left arrow', 'any'];
+ var namedKeys:Array = ['space', 'up arrow', 'down arrow', 'right arrow', 'left arrow', 'shift', 'enter', 'backspace', 'control', 'any'];
var m:Menu = new Menu(setBlockArg, 'key');
for each (var s:String in namedKeys) m.addItem(s);
for (ch = 97; ch < 123; ch++) m.addItem(String.fromCharCode(ch)); // a-z
@@ -532,6 +539,7 @@ public class BlockMenus implements DragClient {
m.addItem('add comment', block.addComment);
}
m.addItem('help', block.showHelp);
+ if(Scratch.app.builtWithDevMode) m.addItem('Show Block Spec', block.showSpec)
m.addLine();
}
@@ -586,7 +594,7 @@ public class BlockMenus implements DragClient {
}
var d:DialogBox = new DialogBox(editSpec2);
d.addTitle('Edit Block');
- d.addWidget(new ProcedureSpecEditor(block.spec, block.parameterNames, block.warpProcFlag));
+ d.addWidget(new ProcedureSpecEditor(block.spec, block.parameterNames, block.warpProcFlag, block.procedureType, true));
d.addAcceptCancelButtons('OK');
d.showOnStage(app.stage, true);
ProcedureSpecEditor(d.widget).setInitialFocus();
@@ -600,6 +608,7 @@ public class BlockMenus implements DragClient {
block.parameterNames = ProcedureSpecEditor(dialog.widget).inputNames();
block.defaultArgValues = ProcedureSpecEditor(dialog.widget).defaultArgValues();
block.warpProcFlag = ProcedureSpecEditor(dialog.widget).warpFlag();
+ block.procedureType = ProcedureSpecEditor(dialog.widget).type();
block.setSpec(newSpec);
if (block.nextBlock) block.nextBlock.allBlocksDo(function(b:Block):void {
if (b.op == Specs.GET_PARAM) b.parameterIndex = -1; // parameters may have changed; clear cached indices
@@ -849,5 +858,20 @@ public class BlockMenus implements DragClient {
}
showMenu(m);
}
-
+
+ /////////SHARP/////////
+
+ private function httpMethodMenu(evt:MouseEvent):void {
+ var m:Menu = new Menu(setBlockArg, 'httpMethod');
+ m.addItem('GET');
+ showMenu(m);
+ }
+
+ private function constantMenu(evt:MouseEvent):void {
+ var m:Menu = new Menu(setBlockArg, 'constantName');
+ m.addItem('Pi');
+ m.addItem('E');
+ m.addItem('Phi');
+ showMenu(m);
+ }
}}
diff --git a/src/scratch/PaletteBuilder.as b/src/scratch/PaletteBuilder.as
index 38f3d0998..10e22d343 100644
--- a/src/scratch/PaletteBuilder.as
+++ b/src/scratch/PaletteBuilder.as
@@ -129,10 +129,11 @@ public class PaletteBuilder {
var catColor:int = Specs.blockColor(Specs.procedureColor);
addItem(new Button(Translator.map('Make a Block'), makeNewBlock, false, '/help/studio/tips/blocks/make-a-block/'));
var definitions:Array = app.viewedObj().procedureDefinitions();
+ addBlocksForCategory(10, Specs.procedureColor);
if (definitions.length > 0) {
nextY += 5;
for each (var proc:Block in definitions) {
- var b:Block = new Block(proc.spec, ' ', Specs.procedureColor, Specs.CALL, proc.defaultArgValues);
+ var b:Block = new Block(proc.spec, proc.procedureType, Specs.procedureColor, Specs.CALL, proc.defaultArgValues);
addItem(b);
}
nextY += 5;
@@ -210,6 +211,7 @@ public class PaletteBuilder {
private function makeVariable():void {
function makeVar2():void {
var n:String = d.getField('Variable name').replace(/^\s+|\s+$/g, '');
+ if (varSettings.isLocal) n = "[LOCAL] " + n;
if (n.length == 0) return;
createVar(n, varSettings);
@@ -253,6 +255,7 @@ public class PaletteBuilder {
newHat.parameterNames = specEditor.inputNames();
newHat.defaultArgValues = specEditor.defaultArgValues();
newHat.warpProcFlag = specEditor.warpFlag();
+ newHat.procedureType = specEditor.type();
newHat.setSpec(spec);
newHat.x = 10 - app.scriptsPane.x + Math.random() * 100;
newHat.y = 10 - app.scriptsPane.y + Math.random() * 100;
@@ -263,7 +266,7 @@ public class PaletteBuilder {
app.setSaveNeeded();
}
- var specEditor:ProcedureSpecEditor = new ProcedureSpecEditor('', [], false);
+ var specEditor:ProcedureSpecEditor = new ProcedureSpecEditor('', [], false, ' ', false);
var d:DialogBox = new DialogBox(addBlockHat);
d.addTitle('New Block');
d.addWidget(specEditor);
diff --git a/src/scratch/ScratchObj.as b/src/scratch/ScratchObj.as
index a6fe8aca2..7a243c734 100644
--- a/src/scratch/ScratchObj.as
+++ b/src/scratch/ScratchObj.as
@@ -331,6 +331,10 @@ public class ScratchObj extends Sprite {
sprites = Scratch.app.stagePane.sprites();
return (sprites.length > 0) ? ['x position', sprites[sprites.length - 1].objName] : ['volume', '_stage_'];
}
+ if ('showStage' == op || 'hideStage' == op){
+ sprites = Scratch.app.stagePane.sprites();
+ return (sprites.length > 0) ? [sprites[sprites.length - 1].objName] : [""];
+ }
if ('setVar:to:' == op) return [defaultVarName(), 0];
if ('changeVar:by:' == op) return [defaultVarName(), 1];
@@ -402,12 +406,20 @@ public class ScratchObj extends Sprite {
/* Procedures */
- public function procedureDefinitions():Array {
+ public function procedureDefinitions():Array {
var result:Array = [];
for (var i:int = 0; i < scripts.length; i++) {
var b:Block = scripts[i] as Block;
if (b && (b.op == Specs.PROCEDURE_DEF)) result.push(b);
}
+ var theStage:ScratchObj = Scratch.app.stagePane.objNamed("_stage_");
+ var stageScripts:Array = theStage.scripts;
+ if(theStage != this){
+ for (var i:int = 0; i < stageScripts.length; i++) {
+ var b:Block = stageScripts[i] as Block;
+ if (b && (b.op == Specs.PROCEDURE_DEF)) result.push(b);
+ }
+ }
return result;
}
@@ -416,6 +428,12 @@ public class ScratchObj extends Sprite {
var b:Block = scripts[i] as Block;
if (b && (b.op == Specs.PROCEDURE_DEF) && (b.spec == procName)) return b;
}
+ var theStage:ScratchObj = Scratch.app.stagePane.objNamed("_stage_");
+ var stageScripts:Array = theStage.scripts;
+ for (var i:int = 0; i < stageScripts.length; i++) {
+ var b:Block = stageScripts[i] as Block;
+ if (b && (b.op == Specs.PROCEDURE_DEF) && (b.spec == procName)) return b;
+ }
return null;
}
diff --git a/src/scratch/ScratchRuntime.as b/src/scratch/ScratchRuntime.as
index 6fede7829..9ee01f167 100644
--- a/src/scratch/ScratchRuntime.as
+++ b/src/scratch/ScratchRuntime.as
@@ -37,6 +37,7 @@ import flash.geom.Point;
import flash.geom.Rectangle;
import flash.media.*;
import flash.net.*;
+import flash.events.Event;
import flash.system.System;
import flash.text.TextField;
import flash.ui.Keyboard;
@@ -81,7 +82,8 @@ public class ScratchRuntime {
protected var projectToInstall:ScratchStage;
protected var saveAfterInstall:Boolean;
-
+ [Embed(source='../assets/sprite1A.svg', mimeType='application/octet-stream')] protected static var ModCostume1:Class;
+ [Embed(source='../assets/sprite1B.svg', mimeType='application/octet-stream')] protected static var ModCostume2:Class;
public function ScratchRuntime(app:Scratch, interp:Interpreter) {
this.app = app;
this.interp = interp;
@@ -173,7 +175,7 @@ public class ScratchRuntime {
processEdgeTriggeredHats();
interp.stepThreads();
app.stagePane.commitPenStrokes();
-
+
if (ready==ReadyLabel.COUNTDOWN || ready==ReadyLabel.READY) {
app.stagePane.countdown(count);
}
@@ -188,7 +190,7 @@ public class ScratchRuntime {
private var videoPosition:int;
private var videoSeconds:Number;
private var videoAlreadyDone:int;
-
+
private var projectSound:Boolean;
private var micSound:Boolean;
private var showCursor:Boolean;
@@ -197,14 +199,14 @@ public class ScratchRuntime {
private var videoWidth:int;
private var videoHeight:int;
public var ready:int=ReadyLabel.NOT_READY;
-
+
private var micBytes:ByteArray;
private var micPosition:int = 0;
private var mic:Microphone;
private var micReady:Boolean;
-
+
private var timeout:int;
-
+
private function saveFrame():void {
saveSound();
var t:Number = getTimer()*.001-videoSeconds;
@@ -283,7 +285,7 @@ public class ScratchRuntime {
videoFrames.push(f);
}
}
-
+
private function saveSound():void {
var floats:Array = [];
if (micSound && micBytes.length>0) {
@@ -324,17 +326,17 @@ public class ScratchRuntime {
videoSounds.push(combinedStream);
combinedStream = null;
}
-
- private function micSampleDataHandler(event:SampleDataEvent):void
- {
- while(event.data.bytesAvailable)
+
+ private function micSampleDataHandler(event:SampleDataEvent):void
+ {
+ while(event.data.bytesAvailable)
{
- var sample:Number = event.data.readFloat();
- micBytes.writeFloat(sample);
+ var sample:Number = event.data.readFloat();
+ micBytes.writeFloat(sample);
micBytes.writeFloat(sample);
- }
- }
-
+ }
+ }
+
public function startVideo(editor:RecordingSpecEditor):void {
projectSound = editor.soundFlag();
micSound = editor.microphoneFlag();
@@ -346,10 +348,10 @@ public class ScratchRuntime {
}
micReady = true;
if (micSound) {
- mic = Microphone.getMicrophone();
+ mic = Microphone.getMicrophone();
mic.setSilenceLevel(0);
- mic.gain = editor.getMicVolume();
- mic.rate = 44;
+ mic.gain = editor.getMicVolume();
+ mic.rate = 44;
micReady=false;
}
if (fullEditor) {
@@ -381,7 +383,7 @@ public class ScratchRuntime {
baFlvEncoder.start();
waitAndStart();
}
-
+
public function exportToVideo():void {
var specEditor:RecordingSpecEditor = new RecordingSpecEditor();
function startCountdown():void {
@@ -389,7 +391,7 @@ public class ScratchRuntime {
}
DialogBox.close("Record Project Video",null,specEditor,"Start",app.stage,startCountdown);
}
-
+
public function stopVideo():void {
if (recording) videoTimer.dispatchEvent(new TimerEvent(TimerEvent.TIMER));
else if (ready==ReadyLabel.COUNTDOWN || ReadyLabel.READY) {
@@ -398,7 +400,7 @@ public class ScratchRuntime {
app.stagePane.countdown(0);
}
}
-
+
public function finishVideoExport(event:TimerEvent):void {
stopRecording();
stopAll();
@@ -407,7 +409,7 @@ public class ScratchRuntime {
clearTimeout(timeout);
timeout = setTimeout(saveRecording,1);
}
-
+
public function waitAndStart():void {
if (!micReady && !mic.hasEventListener(StatusEvent.STATUS)) {
micBytes = new ByteArray();
@@ -439,7 +441,7 @@ public class ScratchRuntime {
videoTimer.addEventListener(TimerEvent.TIMER, finishVideoExport);
videoTimer.start();
}
-
+
public function stopRecording():void {
recording = false;
videoTimer.stop();
@@ -473,7 +475,7 @@ public class ScratchRuntime {
videoSounds[videoPosition]=null;
videoPosition++;
}
- if (app.lp) app.lp.setProgress(Math.min((videoPosition-videoAlreadyDone) / (videoFrames.length-videoAlreadyDone), 1));
+ if (app.lp) app.lp.setProgress(Math.min((videoPosition-videoAlreadyDone) / (videoFrames.length-videoAlreadyDone), 1));
clearTimeout(timeout);
timeout = setTimeout(saveRecording, 1);
return;
@@ -497,16 +499,16 @@ public class ScratchRuntime {
file.save(video, "movie.flv");
Scratch.app.log(LogLevel.TRACK, "Video downloaded", {projectID: app.projectID, seconds: roundToTens(seconds), megabytes: roundToTens(video.length/1000000)});
var specEditor:SharingSpecEditor = new SharingSpecEditor();
- DialogBox.close("Playing and Sharing Your Video",null,specEditor,"Back to Scratch");
+ DialogBox.close("Playing and Sharing Your Video",null,specEditor,"Back to Sharp");
releaseVideo(false);
}
function releaseVideo(log:Boolean = true):void {
- if (log) Scratch.app.log(LogLevel.TRACK, "Video canceled", {projectID: app.projectID, seconds: roundToTens(seconds), megabytes: roundToTens(video.length/1000000)});
+ if (log) Scratch.app.log(LogLevel.TRACK, "Video cancelled", {projectID: app.projectID, seconds: roundToTens(seconds), megabytes: roundToTens(video.length/1000000)});
video = null;
}
DialogBox.close("Video Finished!","To save, click the button below.",null,"Save and Download",app.stage,saveFile,releaseVideo,null,true);
}
-
+
private function roundToTens(x:Number):Number {
return int((x)*10)/10.;
}
@@ -566,6 +568,10 @@ public class ScratchRuntime {
case Keyboard.UP: keyName = 'up arrow'; break;
case Keyboard.DOWN: keyName = 'down arrow'; break;
case Keyboard.SPACE: keyName = 'space'; break;
+ case Keyboard.SHIFT: keyName = 'shift'; break;
+ case Keyboard.ENTER: keyName = 'enter'; break;
+ case Keyboard.BACKSPACE: keyName = 'backspace'; break;
+ case Keyboard.CONTROL: keyName = 'control'; break;
default: keyName = String.fromCharCode(keyCode).toLowerCase(); break;
}
function startMatchingKeyHats(stack:Block, target:ScratchObj):void {
@@ -661,8 +667,8 @@ public class ScratchRuntime {
if (!hat.isHat || !hat.nextBlock) return; // skip disconnected hats
if ('whenSensorGreaterThan' == hat.op) {
- var sensorName:String = interp.arg(hat, 0);
- var threshold:Number = interp.numarg(hat, 1);
+ var sensorName:String = (hat.args[0] as BlockArg).argValue;
+ var threshold:Number = Number((hat.args[1] as BlockArg).argValue) || 0;
if (('loudness' == sensorName && soundLevel() > threshold) ||
('timer' == sensorName && timer() > threshold) ||
('video motion' == sensorName && target.visible && VideoMotionPrims.readMotionSensor('motion', target) > threshold)) {
@@ -673,7 +679,7 @@ public class ScratchRuntime {
activeHats.push(hat);
}
} else if ('whenSensorConnected' == hat.op) {
- if (getBooleanSensor(interp.arg(hat, 0))) {
+ if (getBooleanSensor((hat.args[0] as BlockArg).argValue)) {
if (triggeredHats.indexOf(hat) == -1) { // not already trigged
// only start the stack if it is not already running
if (!interp.isRunning(hat, target)) interp.toggleThread(hat, target);
@@ -688,7 +694,7 @@ public class ScratchRuntime {
var numArgs:uint = hat.args.length;
var finalArgs:Array = new Array(numArgs);
for (var i:uint = 0; i < numArgs; ++i)
- finalArgs[i] = interp.arg(hat, i);
+ finalArgs[i] = (hat.args[i] as BlockArg).argValue;
processExtensionReporter(hat, target, extName, op, finalArgs);
}
@@ -753,7 +759,7 @@ public class ScratchRuntime {
var op:String = b.op;
if (op == Specs.GET_PARAM) b.parameterIndex = -1; // need to invalidate index cache
if (('senseVideoMotion' == op) ||
- (('whenSensorGreaterThan' == op) && ('video motion' == interp.arg(b, 0)))) {
+ (('whenSensorGreaterThan' == op) && ('video motion' == (b.args[0] as BlockArg).argValue))) {
app.libraryPart.showVideoButton();
}
@@ -776,7 +782,17 @@ public class ScratchRuntime {
}
public function installNewProject():void {
- installEmptyProject();
+ var newStage:ScratchStage = new ScratchStage();
+ var sprite:ScratchSprite = new ScratchSprite('Sprite1');
+ var costume1:ScratchCostume = new ScratchCostume(Translator.map('costume1'), new ModCostume1());
+ var costume2:ScratchCostume = new ScratchCostume(Translator.map('costume2'), new ModCostume2());
+ sprite.costumes = [costume1, costume2];
+ sprite.showCostume(1); //To fix odd bug
+ sprite.showCostume(0);
+ newStage.addChild(sprite);
+ app.saveForRevert(new ProjectIO(app).encodeProjectAsZipFile(newStage),true);
+ app.oldWebsiteURL = "";
+ installProject(newStage);
}
public function selectProjectFile():void {
@@ -796,14 +812,28 @@ public class ScratchRuntime {
var filter:FileFilter;
if (Scratch.app.isExtensionDevMode) {
- filter = new FileFilter('ScratchX Project', '*.sbx;*.sb;*.sb2');
+ filter = new FileFilter('SharpX Project', '*.sharpx;*.sharp;*.sb;*.sb2;*.sbx');
}
else {
- filter = new FileFilter('Scratch Project', '*.sb;*.sb2');
+ filter = new FileFilter('Sharp Project', '*.sharp;*.sb;*.sb2');
}
Scratch.loadSingleFile(fileLoadHandler, filter);
}
+ public function loadProjectFromURL(url:String, p:*):void {
+ function doInstall(e:Event):void {
+ installProjectFromFile(p['sharp_pid'], ByteArray(e.target.data));
+ }
+ stopAll();
+
+ var req:URLRequest = new URLRequest(url);
+ req.method = "get";
+ var loader:URLLoader = new URLLoader();
+ loader.addEventListener(Event.COMPLETE, doInstall);
+ loader.dataFormat = URLLoaderDataFormat.BINARY;
+ loader.load(req);
+ }
+
public function installProjectFromFile(fileName:String, data:ByteArray):void {
// Install a project from a file with the given name and contents.
stopAll();
diff --git a/src/svgeditor/DrawPropertyUI.as b/src/svgeditor/DrawPropertyUI.as
index 8764889eb..8a98d940b 100644
--- a/src/svgeditor/DrawPropertyUI.as
+++ b/src/svgeditor/DrawPropertyUI.as
@@ -346,6 +346,7 @@ public class DrawPropertyUI extends Sprite {
m.addItem('Marker');
m.addItem('Mystery');
m.addItem('Scratch');
+ m.addItem('Inconsolata');
m.showOnStage(Scratch.app.stage);
}
function fontSelected(fontName:String):void {
diff --git a/src/svgutils/SVGExport.as b/src/svgutils/SVGExport.as
index 6fd540bef..161070e08 100644
--- a/src/svgutils/SVGExport.as
+++ b/src/svgutils/SVGExport.as
@@ -66,7 +66,8 @@ public class SVGExport {
XML.ignoreComments = false;
rootNode = new XML("");
setSVGWidthAndHeight();
for each (var subEl:SVGElement in rootEl.subElements) {
diff --git a/src/translation/TranslatableStrings.as b/src/translation/TranslatableStrings.as
index 138310ab6..b14f8237a 100644
--- a/src/translation/TranslatableStrings.as
+++ b/src/translation/TranslatableStrings.as
@@ -117,6 +117,7 @@ public class TranslatableStrings {
addAll(ProjectIO.strings());
// Get the strings from the Scratch app instance so that the offline version can add strings
addAll(Scratch.app.strings());
+ addAll(Scratch.app.sharpStrings());
addAll(ScriptsPane.strings());
addAll(SoundEditor.strings());
addAll(SoundsPart.strings());
@@ -128,6 +129,7 @@ public class TranslatableStrings {
addAll(VariableSettings.strings());
addAll(Watcher.strings());
addAll(CameraDialog.strings());
+ addAll(DialogBox.sharpDialogStrings());
Menu.stringCollectionMode = false;
export('uiStrings');
diff --git a/src/ui/PaletteSelector.as b/src/ui/PaletteSelector.as
index ce0830b5c..7c3e0d3e7 100644
--- a/src/ui/PaletteSelector.as
+++ b/src/ui/PaletteSelector.as
@@ -32,8 +32,8 @@ package ui {
public class PaletteSelector extends Sprite {
private static const categories:Array = [
- 'Motion', 'Looks', 'Sound', 'Pen', 'Data', // column 1
- 'Events', 'Control', 'Sensing', 'Operators', 'More Blocks']; // column 2
+ 'Motion', 'Looks', 'Sound', 'Pen', 'Data', 'HTTP', 'Miscellaneous', // column 1
+ 'Events', 'Control', 'Sensing', 'Operators', 'More Blocks', 'Files']; // column 2
public var selectedCategory:int = 0;
private var app:Scratch;
@@ -61,7 +61,7 @@ public class PaletteSelector extends Sprite {
}
private function initCategories():void {
- const numberOfRows:int = 5;
+ const numberOfRows:int = 7;
const w:int = 208;
const startY:int = 3;
var itemH:int;
diff --git a/src/ui/ProcedureSpecEditor.as b/src/ui/ProcedureSpecEditor.as
index 477e85120..c54a493ca 100644
--- a/src/ui/ProcedureSpecEditor.as
+++ b/src/ui/ProcedureSpecEditor.as
@@ -30,12 +30,17 @@ package ui {
public class ProcedureSpecEditor extends Sprite {
+ private var isEdit:Boolean;
private var base:Shape;
+ private var shape:int;
private var blockShape:BlockShape;
private var row:Array = [];
private var moreLabel:TextField;
private var moreButton:IconButton;
+ private var shapeLabels:Array = [];
+ private var shapeIcons:Array = [];
+ private var shapeButtons:Array = [];
private var buttonLabels:Array = [];
private var buttons:Array = [];
@@ -48,11 +53,17 @@ public class ProcedureSpecEditor extends Sprite {
private const labelColor:int = 0x8738bf; // 0x6c36b3; // 0x9c35b3;
private const selectedLabelColor:int = 0xefa6ff;
- public function ProcedureSpecEditor(originalSpec:String, inputNames:Array, warpFlag:Boolean) {
+ public function ProcedureSpecEditor(originalSpec:String, inputNames:Array, warpFlag:Boolean, type:String, isEdit:Boolean) {
+ this.isEdit = isEdit;
+ if(isEdit){
+ originalSpec = originalSpec.replace(/^@rabbit/g, "");
+ }
+
addChild(base = new Shape());
setWidthHeight(350, 10);
- blockShape = new BlockShape(BlockShape.CmdShape, Specs.procedureColor);
+ shape = type == "b" ? BlockShape.BooleanShape : type == "r" ? BlockShape.NumberShape : BlockShape.CmdShape;
+ blockShape = new BlockShape(shape, Specs.procedureColor);
blockShape.setWidthAndTopHeight(100, 25, true);
addChild(blockShape);
@@ -84,7 +95,9 @@ public class ProcedureSpecEditor extends Sprite {
'Add string input:',
'Add boolean input:',
'Add label text:',
- 'text',
+ "Doesn't report",
+ 'Reports number or text',
+ 'Reports true or false',
];
}
@@ -111,7 +124,7 @@ public class ProcedureSpecEditor extends Sprite {
clearRow();
var i:int = 0;
for each (var s:String in ReadStream.tokenize(spec)) {
- if (s.length >= 2 && s.charAt(0) == '%') { // argument spec
+ if ((s.length >= 2) && (s.charAt(0) == '%')) { // argument spec
var argSpec:String = s.charAt(1);
var arg:BlockArg = null;
if (argSpec == 'b') arg = makeBooleanArg();
@@ -123,11 +136,9 @@ public class ProcedureSpecEditor extends Sprite {
}
} else {
if ((row.length > 0) && (row[row.length - 1] is TextField)) {
- var tf:TextField = row[row.length - 1];
- tf.appendText(' ' + ReadStream.unescape(s));
- fixLabelWidth(tf);
+ TextField(row[row.length - 1]).appendText(' ' + s);
} else {
- addElement(makeTextField(ReadStream.unescape(s)));
+ addElement(makeTextField(s));
}
}
}
@@ -137,8 +148,9 @@ public class ProcedureSpecEditor extends Sprite {
public function spec():String {
var result:String = '';
+ if(warpFlag()) result = "@rabbit ";
for each (var o:* in row) {
- if (o is TextField) result += ReadStream.escape(TextField(o).text);
+ if (o is TextField) result += TextField(o).text;
if (o is BlockArg) result += '%' + BlockArg(o).type;
if ((result.length > 0) && (result.charAt(result.length - 1) != ' ')) result += ' ';
}
@@ -146,6 +158,10 @@ public class ProcedureSpecEditor extends Sprite {
return result;
}
+ public function type():String {
+ return shape == BlockShape.BooleanShape ? "b" : shape == BlockShape.NumberShape ? "r" : " ";
+ }
+
public function defaultArgValues():Array {
var result:Array = [];
for each (var el:* in row) {
@@ -169,12 +185,22 @@ public class ProcedureSpecEditor extends Sprite {
public function inputNames():Array {
var result:Array = [];
for each (var o:* in row) {
- if (o is BlockArg) result.push(uniqueName(result, BlockArg(o).field.text));
+ if (o is BlockArg) result.push(BlockArg(o).field.text);
}
return result;
}
private function addButtonsAndLabels():void {
+ shapeLabels = [
+ makeLabel("Doesn't report", 14),
+ makeLabel('Reports number or text', 14),
+ makeLabel('Reports true or false', 14),
+ ];
+ shapeButtons = [
+ new IconButton(function():void { setShape(BlockShape.CmdShape) }, null),
+ new IconButton(function():void { setShape(BlockShape.NumberShape) }, null),
+ new IconButton(function():void { setShape(BlockShape.BooleanShape) }, null)
+ ];
buttonLabels = [
makeLabel('Add number input:', 14),
makeLabel('Add string input:', 14),
@@ -185,10 +211,26 @@ public class ProcedureSpecEditor extends Sprite {
new Button('', function():void { appendObj(makeNumberArg()) }),
new Button('', function():void { appendObj(makeStringArg()) }),
new Button('', function():void { appendObj(makeBooleanArg()) }),
- new Button(Translator.map('text'), function():void { appendObj(makeTextField('')) })
+ new Button('text', function():void { appendObj(makeTextField('')) })
];
+ shapeButtons[0].setOn(true);
+
const lightGray:int = 0xA0A0A0;
+ var icon:BlockShape;
+
+ shapeIcons = [];
+ icon = new BlockShape(BlockShape.CmdShape, Specs.procedureColor);
+ icon.setWidthAndTopHeight(34, 18, true);
+ shapeIcons.push(icon);
+
+ icon = new BlockShape(BlockShape.NumberShape, Specs.procedureColor);
+ icon.setWidthAndTopHeight(34, 18, true);
+ shapeIcons.push(icon);
+
+ icon = new BlockShape(BlockShape.BooleanShape, Specs.procedureColor);
+ icon.setWidthAndTopHeight(34, 18, true);
+ shapeIcons.push(icon);
icon = new BlockShape(BlockShape.NumberShape, lightGray);
icon.setWidthAndTopHeight(25, 14, true);
@@ -198,12 +240,9 @@ public class ProcedureSpecEditor extends Sprite {
icon.setWidthAndTopHeight(22, 14, true);
buttons[1].setIcon(icon);
- var icon:BlockShape = new BlockShape(BlockShape.BooleanShape, lightGray);
+ icon = new BlockShape(BlockShape.BooleanShape, lightGray);
icon.setWidthAndTopHeight(25, 14, true);
buttons[2].setIcon(icon);
-
- for each (var label:TextField in buttonLabels) addChild(label);
- for each (var b:Button in buttons) addChild(b);
}
private function addwarpCheckbox():void {
@@ -224,7 +263,7 @@ public class ProcedureSpecEditor extends Sprite {
private function toggleButtons(ignore:*):void {
var buttonsShowing:Boolean = buttons[0].parent != null;
- showButtons(!buttonsShowing)
+ showButtons(!buttonsShowing);
}
private function deleteItem(ignore:*):void {
@@ -241,15 +280,21 @@ public class ProcedureSpecEditor extends Sprite {
}
private function showButtons(showParams:Boolean):void {
- var label:TextField, b:Button;
+ var label:TextField, b:Button, ib:IconButton, shape:BlockShape;
if (showParams) {
for each (label in buttonLabels) addChild(label);
+ if (!isEdit) for each (label in shapeLabels) addChild(label);
for each (b in buttons) addChild(b);
+ if (!isEdit) for each (ib in shapeButtons) addChild(ib);
+ if (!isEdit) for each (shape in shapeIcons) addChild(shape);
addChild(warpCheckbox);
addChild(warpLabel);
} else {
for each (label in buttonLabels) if (label.parent) removeChild(label);
+ for each (label in shapeLabels) if (label.parent) removeChild(label);
for each (b in buttons) if (b.parent) removeChild(b);
+ for each (ib in shapeButtons) if (ib.parent) removeChild(ib);
+ for each (shape in shapeIcons) if (shape.parent) removeChild(shape);
if (warpCheckbox.parent) removeChild(warpCheckbox);
if (warpLabel.parent) removeChild(warpLabel);
}
@@ -261,6 +306,19 @@ public class ProcedureSpecEditor extends Sprite {
if (parent is DialogBox) DialogBox(parent).fixLayout();
}
+ private function setShape(shape:int):void {
+ this.shape = shape;
+ var ob:IconButton = shapeButtons[shape == BlockShape.BooleanShape ? 2 : shape == BlockShape.NumberShape ? 1 : 0];
+ for each (var ib:IconButton in shapeButtons) {
+ ib.setOn(ib == ob);
+ }
+ var k:int = getChildIndex(blockShape);
+ removeChildAt(k);
+ blockShape = new BlockShape(shape, Specs.procedureColor);
+ addChildAt(blockShape, k);
+ fixLayout();
+ }
+
private function makeBooleanArg():BlockArg {
var result:BlockArg = new BlockArg('b', 0xFFFFFF, true);
result.setArgValue(unusedArgName('boolean'));
@@ -295,9 +353,10 @@ public class ProcedureSpecEditor extends Sprite {
addChild(o);
if (stage) {
if (o is TextField) stage.focus = TextField(o);
- if (o is BlockArg) BlockArg(o).startEditing();
+ if (o is BlockArg) stage.focus = BlockArg(o).field;
}
fixLayout();
+ if (parent is DialogBox) DialogBox(parent).fixLayout();
}
private function makeTextField(contents:String):TextField {
@@ -306,7 +365,7 @@ public class ProcedureSpecEditor extends Sprite {
result.backgroundColor = labelColor;
result.background = true;
result.type = TextFieldType.INPUT;
- result.defaultTextFormat = Block.blockLabelFormat;
+ result.defaultTextFormat = new TextFormat(CSS.font, 12, 0xFFFFFF);
if (contents.length > 0) {
result.width = 1000;
result.text = contents;
@@ -329,11 +388,11 @@ public class ProcedureSpecEditor extends Sprite {
row = newRow;
}
- private function fixLayout(updateDelete:Boolean = true):void {
+ private function fixLayout():void {
removeDeletedElementsFromRow();
blockShape.x = 10;
blockShape.y = 10;
- var nextX:int = blockShape.x + 6;
+ var nextX:int = blockShape.x + (shape == BlockShape.BooleanShape ? 14 : 6);
var nextY:int = blockShape.y + 5;
var maxH:int = 0;
for each (var o:DisplayObject in row) maxH = Math.max(maxH, o.height);
@@ -343,39 +402,43 @@ public class ProcedureSpecEditor extends Sprite {
nextX += o.width + 4;
if ((o is BlockArg) && (BlockArg(o).type == 's')) nextX -= 2;
}
- var blockW:int = Math.max(40, nextX + 4 - blockShape.x);
+ var blockW:int = Math.max(40, nextX + (shape == BlockShape.BooleanShape ? 12 : 4) - blockShape.x);
blockShape.setWidthAndTopHeight(blockW, maxH + 11, true);
moreButton.x = 0;
- moreButton.y = blockShape.y + blockShape.height + 12;
+ moreButton.y = blockShape.y + blockShape.height + (shape == BlockShape.CmdShape ? 12 : 15);
moreLabel.x = 10;
moreLabel.y = moreButton.y - 4;
- var labelX:int = blockShape.x + 45;
- var buttonX:int = 240;
- for each (var l:TextField in buttonLabels) {
- buttonX = Math.max(buttonX, labelX + l.textWidth + 10);
- }
-
- var rowY:int = blockShape.y + blockShape.height + 30;
+ var rowY:int = blockShape.y + blockShape.height + (shape == BlockShape.CmdShape ? 30 : 33);
for (var i:int = 0; i < buttons.length; i++) {
- var label:TextField = buttonLabels[i];
- buttonLabels[i].x = labelX;
+ buttonLabels[i].x = blockShape.x + 45;
buttonLabels[i].y = rowY;
- buttons[i].x = buttonX;
+ buttons[i].x = 240;
buttons[i].y = rowY - 4;
rowY += 30;
}
+ if (!isEdit) {
+ for (i = 0; i < shapeButtons.length; i++) {
+ shapeButtons[i].x = blockShape.x + 46;
+ shapeButtons[i].y = rowY + 4;
+ shapeIcons[i].x = shapeButtons[i].x + shapeButtons[i].width + 8;
+ shapeIcons[i].y = rowY;
+ shapeLabels[i].x = shapeIcons[i].x + shapeIcons[i].width + 8;
+ shapeLabels[i].y = rowY;
+ rowY += 30;
+ }
+ }
+
warpCheckbox.x = blockShape.x + 46;
warpCheckbox.y = rowY + 4;
warpLabel.x = warpCheckbox.x + 18;
warpLabel.y = warpCheckbox.y - 3;
- if (updateDelete) updateDeleteButton();
- if (parent is DialogBox) DialogBox(parent).fixLayout();
+ updateDeleteButton();
}
/* Editing Parameter Names */
@@ -424,24 +487,10 @@ public class ProcedureSpecEditor extends Sprite {
private function setFocus(o:DisplayObject):void {
if (!stage) return;
if (o is TextField) stage.focus = TextField(o);
- if (o is BlockArg) BlockArg(o).startEditing();
- }
-
- private function uniqueName(taken:Array, name:String):String {
- if (taken.indexOf(name) == -1) return name;
- var e:Array = /\d+$/.exec(name);
- var n:String = e ? e[0] : "";
- var base:String = name.slice(0, name.length - n.length);
- var i:int = int(n || "1") + 1;
- while (taken.indexOf(base + i) != -1) {
- i++;
- }
- return base + i;
+ if (o is BlockArg) stage.focus = BlockArg(o).field;
}
private function focusChange(evt:FocusEvent):void {
- var params:Array = [];
- var change:Boolean = false;
// Update label fields to show focus.
for each (var o:DisplayObject in row) {
if (o is TextField) {
@@ -449,17 +498,9 @@ public class ProcedureSpecEditor extends Sprite {
var hasFocus:Boolean = (stage != null) && (tf == stage.focus);
tf.textColor = hasFocus ? 0 : 0xFFFFFF;
tf.backgroundColor = hasFocus ? selectedLabelColor : labelColor;
- } else if (o is BlockArg) {
- tf = BlockArg(o).field;
- if (params.indexOf(tf.text) != -1) {
- BlockArg(o).setArgValue(uniqueName(params, tf.text));
- change = true;
- }
- params.push(tf.text);
}
}
- if (change) fixLayout(false);
- else if (evt.type == FocusEvent.FOCUS_IN) updateDeleteButton();
+ if (evt.type == FocusEvent.FOCUS_IN) updateDeleteButton();
}
private function updateDeleteButton():void {
@@ -485,4 +526,4 @@ public class ProcedureSpecEditor extends Sprite {
deleteButton.y = -6;
}
-}}
+}}
\ No newline at end of file
diff --git a/src/ui/RecordingSpecEditor.as b/src/ui/RecordingSpecEditor.as
index 428a166d6..45bf9ad37 100644
--- a/src/ui/RecordingSpecEditor.as
+++ b/src/ui/RecordingSpecEditor.as
@@ -53,7 +53,7 @@ public class RecordingSpecEditor extends Sprite {
setWidthHeight(440, 10);
addChild(description = makeLabel('Capture and download a video of your project to your computer.\nYou can record up to 60 seconds of video.',14));
- addChild(notSavedLabel = makeLabel('that the video will not be saved on Scratch.',14));
+ addChild(notSavedLabel = makeLabel('that the video will not be saved on Sharp.',14));
addChild(pleaseNoteLabel = makeLabel('Please note',14,true));
addChild(moreLabel = makeLabel('More Options', 14));
moreLabel.addEventListener(MouseEvent.MOUSE_DOWN, toggleButtons);
diff --git a/src/ui/SharingSpecEditor.as b/src/ui/SharingSpecEditor.as
index 13f4992ce..0242a64b1 100644
--- a/src/ui/SharingSpecEditor.as
+++ b/src/ui/SharingSpecEditor.as
@@ -50,7 +50,7 @@ public class SharingSpecEditor extends Sprite {
addChild(playLabel = makeLabel('To play your video, download and install the',14));
addChild(linkLabel = makeLinkLabel('VLC media player.',14,"http://www.videolan.org/vlc/index.html"));
- addChild(faqLabel = makeLinkLabel('Questions?',14,"https://scratch.mit.edu/info/faq/"));
+ //addChild(faqLabel = makeLinkLabel('Questions?',14,"https://scratch.mit.edu/info/faq/"));
addChild(shareLabel = makeLabel('You can also share your video with others to let them see it!',14));
addChild(shareImage = Resources.createDO("videoShare"));
var h:Number = 160/shareImage.width*shareImage.height;
diff --git a/src/ui/parts/ScriptsPart.as b/src/ui/parts/ScriptsPart.as
index cf707f106..e0067c9cd 100644
--- a/src/ui/parts/ScriptsPart.as
+++ b/src/ui/parts/ScriptsPart.as
@@ -36,7 +36,7 @@ import uiwidgets.*;
public class ScriptsPart extends UIPart {
private var shape:Shape;
- private var selector:PaletteSelector;
+ public var selector:PaletteSelector; //was private
private var spriteWatermark:Bitmap;
protected var paletteFrame:ScrollFrame;
protected var scriptsFrame:ScrollFrame;
diff --git a/src/ui/parts/StagePart.as b/src/ui/parts/StagePart.as
index 1e27c56ee..d29bbdc4f 100644
--- a/src/ui/parts/StagePart.as
+++ b/src/ui/parts/StagePart.as
@@ -51,9 +51,9 @@ public class StagePart extends UIPart {
protected var projectInfo:TextField;
private var versionInfo:TextField;
private var turboIndicator:TextField;
- private var runButton:IconButton;
- private var stopButton:IconButton;
- private var fullscreenButton:IconButton;
+ public var runButton:IconButton; //was private
+ public var stopButton:IconButton; //was private
+ public var fullscreenButton:IconButton; //was private
private var stageSizeButton:Sprite;
//video recording tools
@@ -64,6 +64,7 @@ public class StagePart extends UIPart {
private var playButton:Sprite; // YouTube-like play button in center of screen; used by Kiosk version
private var userNameWarning:Sprite; // Container for privacy warning message for projects that use username block
+ private var httpWarning:Sprite;
private var runButtonOnTicks:int;
// x-y readouts
@@ -71,7 +72,7 @@ public class StagePart extends UIPart {
private var xLabel:TextField;
private var xReadout:TextField;
private var yLabel:TextField;
- private var yReadout:TextField;
+ public var yReadout:TextField; //was private
public function StagePart(app:Scratch) {
this.app = app;
@@ -160,6 +161,7 @@ public class StagePart extends UIPart {
drawStageSizeButton();
}
if (userNameWarning) userNameWarning.visible = app.usesUserNameBlock;
+ if (httpWarning) httpWarning.visible = app.usesHTTPBlock;
updateProjectInfo();
}
@@ -536,6 +538,27 @@ public class StagePart extends UIPart {
userNameWarning.visible = false; // Don't show this by default
}
+
+ public function addHTTPWarning():void{
+ httpWarning = new Sprite();
+ var g:Graphics = httpWarning.graphics;
+ g.clear();
+ g.beginFill(CSS.white);
+ g.drawRoundRect(10, 30, playButton.width - 20, 70, 15, 15);
+ g.endFill();
+ httpWarning.alpha = 0.9;
+
+ const versionFormat:TextFormat = new TextFormat(CSS.font, 16, 0x000000);
+ var httpWarningText:TextField = makeLabel("This project sends HTTP requests, through the “http” block. It is recommended that you watch what you enter into the project as It might be sent with HTTP to any website.", versionFormat, 15, 45);
+ httpWarningText.width = httpWarning.width - 10;
+ httpWarningText.multiline = true;
+ httpWarningText.wordWrap = true;
+
+ httpWarning.addChild(httpWarningText);
+ playButton.addChild(httpWarning);
+
+ httpWarning.visible = false;
+ }
public function playButtonPressed(evt:MouseEvent):void {
if(app.loadInProgress) {
diff --git a/src/ui/parts/TopBarPart.as b/src/ui/parts/TopBarPart.as
index 4f2365963..ade732b2b 100644
--- a/src/ui/parts/TopBarPart.as
+++ b/src/ui/parts/TopBarPart.as
@@ -39,16 +39,18 @@ public class TopBarPart extends UIPart {
private var shape:Shape;
protected var logoButton:IconButton;
- protected var languageButton:IconButton;
-
- protected var fileMenu:IconButton;
- protected var editMenu:IconButton;
-
- private var copyTool:IconButton;
- private var cutTool:IconButton;
- private var growTool:IconButton;
- private var shrinkTool:IconButton;
- private var helpTool:IconButton;
+ public var languageButton:IconButton; //was protected
+
+ public var fileMenu:IconButton; //was protected
+ public var editMenu:IconButton; //was protected
+ public var helpMenu:IconButton; //was protected
+ private var devMenu:IconButton;
+
+ public var copyTool:IconButton; //was private
+ public var cutTool:IconButton; //was private
+ public var growTool:IconButton; //was private
+ public var shrinkTool:IconButton; //was private
+ public var helpTool:IconButton; //was private
private var toolButtons:Array = [];
private var toolOnMouseDown:String;
@@ -92,14 +94,18 @@ public class TopBarPart extends UIPart {
if (Scratch.app) {
Scratch.app.showFileMenu(Menu.dummyButton());
Scratch.app.showEditMenu(Menu.dummyButton());
+ Scratch.app.showHelpMenu(Menu.dummyButton());
+ if(Scratch.app.builtWithDevMode) Scratch.app.showDevMenu(Menu.dummyButton());
}
- return ['File', 'Edit', 'Tips', 'Duplicate', 'Delete', 'Grow', 'Shrink', 'Block help', 'Offline Editor'];
+ return ['File', 'Edit', "Help", 'Tips', 'Duplicate', 'Delete', 'Grow', 'Shrink', 'Block help', 'Offline Editor', 'Dev'];
}
protected function removeTextButtons():void {
if (fileMenu.parent) {
removeChild(fileMenu);
removeChild(editMenu);
+ removeChild(helpMenu);
+ if(Scratch.app.builtWithDevMode) removeChild(devMenu);
}
}
@@ -149,6 +155,16 @@ public class TopBarPart extends UIPart {
editMenu.x = nextX;
editMenu.y = buttonY;
nextX += editMenu.width + buttonSpace;
+
+ helpMenu.x = nextX;
+ helpMenu.y = buttonY;
+ nextX += helpMenu.width + buttonSpace;
+
+ if(Scratch.app.builtWithDevMode){
+ devMenu.x = nextX;
+ devMenu.y = buttonY;
+ nextX += devMenu.width + buttonSpace;
+ }
// cursor tool buttons
var space:int = 3;
@@ -208,6 +224,8 @@ public class TopBarPart extends UIPart {
protected function addTextButtons():void {
addChild(fileMenu = makeMenuButton('File', app.showFileMenu, true));
addChild(editMenu = makeMenuButton('Edit', app.showEditMenu, true));
+ addChild(helpMenu = makeMenuButton('Help', app.showHelpMenu, true));
+ if(Scratch.app.builtWithDevMode) addChild(devMenu = makeMenuButton('Dev', app.showDevMenu, true));
}
private function addToolButtons():void {
diff --git a/src/uiwidgets/DialogBox.as b/src/uiwidgets/DialogBox.as
index 9ff92d1aa..a1b901276 100644
--- a/src/uiwidgets/DialogBox.as
+++ b/src/uiwidgets/DialogBox.as
@@ -18,11 +18,14 @@
*/
package uiwidgets {
+ import flash.system.fscommand;
import flash.display.*;
import flash.events.*;
import flash.filters.DropShadowFilter;
import flash.text.*;
import flash.utils.Dictionary;
+ import flash.net.URLRequest;
+ import flash.net.navigateToURL;
import translation.Translator;
import ui.parts.UIPart;
@@ -49,7 +52,7 @@ public class DialogBox extends Sprite {
private var acceptFunction:Function; // if not nil, called when menu interaction is accepted
private var cancelFunction:Function; // if not nil, called when menu interaction is canceled
-
+
public function DialogBox(acceptFunction:Function = null, cancelFunction:Function = null) {
this.acceptFunction = acceptFunction;
this.cancelFunction = cancelFunction;
@@ -59,6 +62,17 @@ public class DialogBox extends Sprite {
addEventListener(KeyboardEvent.KEY_DOWN, keyDown);
addEventListener(FocusEvent.KEY_FOCUS_CHANGE, focusChange);
}
+
+ public static function sharpDialogStrings():Array{
+ return [
+ "Title", "Content",
+ "Report Bug", "Cancel",
+ "Report a bug", "Settings",
+ "Allow sound", "Always in turbo mode",
+ "Hack mode", "Clone limit", "OK", "Reset Settings",
+ "Do you really want to reset settings?"
+ ];
+ }
public static function ask(question:String, defaultAnswer:String, stage:Stage = null, resultFunction:Function = null, context:Dictionary = null):void {
function done():void { if (resultFunction != null) resultFunction(d.fields['answer'].text) }
@@ -88,6 +102,47 @@ public class DialogBox extends Sprite {
d.showOnStage(stage ? stage : Scratch.app.stage);
}
+ public static function reportBugDialog():void{
+ var d:DialogBox = new DialogBox(done);
+ function done():void {
+ var request:URLRequest = new URLRequest("https://github.com/SharpScratchMod/Sharp/issues/new?title=" + d.fields['Title'].text + "&body=" + d.fields["Content"].text);
+ navigateToURL(request, "_blank");
+ }
+ d.addTitle("Report a bug");
+ d.addField("Title", 120, "", true);
+ d.addField("Content", 120, "", true);
+ d.addButton("Report Bug", d.accept);
+ d.addButton("Cancel", d.cancel);
+ d.showOnStage(Scratch.app.stage);
+ }
+
+ public static function settingsDialog():void{
+ var d:DialogBox = new DialogBox(done);
+ function done():void {
+ Scratch.app.sharpSettings.data.allowSound = d.booleanFields['Allow sound'].isOn();
+ Scratch.app.sharpSettings.data.alwaysTurboMode = d.booleanFields['Always in turbo mode'].isOn();
+ if(d.booleanFields['Always in turbo mode'].isOn() && !Scratch.app.turboModeIsActive) Scratch.app.toggleTurboMode();
+ Scratch.app.sharpSettings.data.hackMode = d.booleanFields['Hack mode'].isOn();
+ Scratch.app.sharpSettings.data.cloneLimit = d.fields['Clone limit'].text;
+ Scratch.app.sharpSettings.data.restoreScratchShowHide = d.booleanFields['Restore Scratch show/hide Blocks'].isOn();
+ Scratch.app.saveSettings();
+ Scratch.app.reloadSettings();
+ }
+ function resetSettings():void {
+ DialogBox.confirm(Translator.map("Do you really want to reset settings?"), null, function():*{ Scratch.app.resetSettings(); });
+ }
+ d.addTitle("Settings");
+ d.addBoolean("Allow sound", Scratch.app.sharpSettings.data.allowSound, false);
+ d.addBoolean("Always in turbo mode", Scratch.app.sharpSettings.data.alwaysTurboMode, false);
+ d.addBoolean("Hack mode", Scratch.app.sharpSettings.data.hackMode, false);
+ d.addField("Clone limit", 120, Scratch.app.sharpSettings.data.cloneLimit, true);
+ d.addBoolean("Restore Scratch show/hide Blocks", Scratch.app.sharpSettings.data.restoreScratchShowHide, false);
+ d.addButton("OK", d.accept);
+ d.addButton("Cancel", d.cancel);
+ d.addButton("Reset Settings", resetSettings);
+ d.showOnStage(Scratch.app.stage);
+ }
+
public static function close(title:String, msg:String = null, widget:DisplayObject = null, button:String = "OK", stage:Stage = null, okFunction:Function = null, cancelFunction:Function = null, context:Dictionary = null,inverted:Boolean = false):void {
var d:DialogBox = new DialogBox(okFunction, cancelFunction);
d.leftJustify = false;
@@ -136,10 +191,12 @@ public class DialogBox extends Sprite {
addChild(o);
}
- public function addField(fieldName:String, width:int, defaultValue:* = null, showLabel:Boolean = true):void {
+ public function addField(fieldName:String, width:int, defaultValue:* = null, showLabel:Boolean = true, label:String = null):void {
var l:TextField = null;
if (showLabel) {
- l = makeLabel(Translator.map(fieldName) + ':');
+ //var labelStr:String = Translator.map(fieldName);
+ if(label == null) label = Translator.map(fieldName);
+ l = makeLabel(label + ':');
addChild(l);
}
var f:TextField = makeField(width);
@@ -149,8 +206,10 @@ public class DialogBox extends Sprite {
labelsAndFields.push([l, f]);
}
- public function addBoolean(fieldName:String, defaultValue:Boolean = false, isRadioButton:Boolean = false):void {
- var l:TextField = makeLabel(Translator.map(fieldName) + ':');
+ public function addBoolean(fieldName:String, defaultValue:Boolean = false, isRadioButton:Boolean = false, label:String = null):void {
+ var l:TextField = null;
+ if(label == null) label = Translator.map(fieldName);
+ l = makeLabel(label + ':');
addChild(l);
var f:IconButton = isRadioButton ?
new IconButton(null, null, null, true) :
diff --git a/src/uiwidgets/ScriptsPane.as b/src/uiwidgets/ScriptsPane.as
index 387d788c6..fa61587f6 100644
--- a/src/uiwidgets/ScriptsPane.as
+++ b/src/uiwidgets/ScriptsPane.as
@@ -366,6 +366,10 @@ return true; // xxx disable this check for now; it was causing confusion at Scra
}
private function dropCompatible(droppedBlock:Block, target:DisplayObject):Boolean {
+ if(app.sharpSettings.data.hackMode){
+ return true; //Credit liam4: This line of code was taken from their mod
+ }
+
const menusThatAcceptReporters:Array = [
'broadcast', 'costume', 'backdrop', 'scene', 'sound',
'spriteOnly', 'spriteOrMouse', 'location', 'spriteOrStage', 'touching'];
diff --git a/src/uiwidgets/TutorialDoBox.as b/src/uiwidgets/TutorialDoBox.as
new file mode 100644
index 000000000..5582361de
--- /dev/null
+++ b/src/uiwidgets/TutorialDoBox.as
@@ -0,0 +1,100 @@
+/*
+ * Sharp Project Editor and Player
+ * Copyright (C) 2016 Sharp Scratch Mod
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * as published by the Free Software Foundation; either version 2
+ * of the License, or (at your option) any later version.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+package uiwidgets{
+ import flash.display.*;
+ import flash.events.*;
+ import flash.filters.DropShadowFilter;
+ import flash.text.*;
+ import ui.parts.UIPart;
+
+public class TutorialDoBox extends Sprite{
+ private var text:String;
+ private var locx:int;
+ private var locy:int;
+
+ public function TutorialDoBox(text:String = "Do something!",
+ locx:int = 0, locy:int = 0){
+ this.text = text;
+ this.locx = locx;
+ this.locy = locy;
+ }
+
+ private function drawBackground():void{
+ var borderColor:int = 0xB0B0B0;
+ var arrowColor:int = 0xEEEEEE;
+ var g:Graphics = graphics;
+ g.clear();
+ g.lineStyle(1.5, arrowColor, 1, true);
+ g.moveTo(locx, locy);
+ g.lineTo(locx+10, locy-10);
+ g.moveTo(locx, locy);
+ g.lineTo(locx+10, locy+10);
+ g.lineStyle(0.5, borderColor, 1, true);
+ g.beginFill(0xFFFFFF);
+ g.drawRect(locx+10, locy-10, 200, 100);
+ }
+
+ private function drawNoArrow():void{
+ var borderColor:int = 0xB0B0B0;
+ var g:Graphics = graphics;
+ g.clear();
+ g.lineStyle(0.5, borderColor, 1, true);
+ g.beginFill(0xFFFFFF);
+ g.drawRect(locx+10, locy-10, 190, 100);
+ }
+
+ private function makeTheTextLabel():VariableTextField{
+ var format:TextFormat = new TextFormat(CSS.font, 14, CSS.textColor);
+ var result:VariableTextField = new VariableTextField();
+ result.autoSize = TextFieldAutoSize.LEFT;
+ result.selectable = false;
+ result.background = false;
+ result.setText(text, null);
+ result.setTextFormat(format);
+ result.x = locx+15;
+ result.y = locy-10;
+ return result;
+ }
+
+ public function remove():void{
+ parent.removeChild(this);
+ }
+
+ public function addButton(label:String, action:Function, x:int = 15, y:int = 60):void{
+ function doAction():void {
+ remove();
+ if(action != null) action();
+ }
+ var b:Button = new Button(label, doAction);
+ b.x = locx+x;
+ b.y = locy+y;
+ addChild(b);
+ }
+
+ public function showOnStage(stage:Stage, arrow:Boolean = true):void{
+ if(arrow) drawBackground();
+ if(!arrow) drawNoArrow();
+ var t:TextField = makeTheTextLabel();
+ addChild(t);
+ stage.addChild(this);
+ }
+}
+
+}
\ No newline at end of file
diff --git a/src/util/Server.as b/src/util/Server.as
index a24b637e4..eeebb01a4 100644
--- a/src/util/Server.as
+++ b/src/util/Server.as
@@ -263,12 +263,20 @@ public class Server implements IServer {
// whenDone(BackpackPart.localAssets[md5]);
// return null;
// }
- var url:String = URLs.assetCdnPrefix + URLs.internalAPI + 'asset/' + md5 + '/get/';
+ //var url:String = URLs.assetCdnPrefix + URLs.internalAPI + 'asset/' + md5 + '/get/';
+ var url:String = "static/assets/" + md5;
+ if(Scratch.app.loaderInfo.parameters["requestPrefix"]){
+ url = "../" + url;
+ }
return serverGet(url, whenDone);
}
public function getMediaLibrary(libraryType:String, whenDone:Function):URLLoader {
- var url:String = getCdnStaticSiteURL() + 'medialibraries/' + libraryType + 'Library.json';
+ //var url:String = getCdnStaticSiteURL() + 'medialibraries/' + libraryType + 'Library.json';
+ var url:String = "static/medialibraries/" + libraryType + "Library.json";
+ if(Scratch.app.loaderInfo.parameters["requestPrefix"]){
+ url = "../" + url;
+ }
return serverGet(url, whenDone);
}
@@ -297,7 +305,9 @@ public class Server implements IServer {
function imageDecoded(e:Event):void {
whenDone(makeThumbnail(e.target.content.bitmapData));
}
-
+ if(Scratch.app.loaderInfo.parameters["requestPrefix"]){
+ url = "../" + url;
+ }
return serverGet(url, decodeImage);
}
@@ -315,7 +325,8 @@ public class Server implements IServer {
}
public function getThumbnail(idAndExt:String, w:int, h:int, whenDone:Function):URLLoader {
- var url:String = getCdnStaticSiteURL() + 'medialibrarythumbnails/' + idAndExt;
+ //var url:String = getCdnStaticSiteURL() + 'medialibrarythumbnails/' + idAndExt;
+ var url:String = "/static/assets/" + idAndExt;
return downloadThumbnail(url, w, h, whenDone);
}
@@ -324,10 +335,18 @@ public class Server implements IServer {
//------------------------------
public function getLanguageList(whenDone:Function):void {
+ if(Scratch.app.loaderInfo.parameters["requestPrefix"]){
+ serverGet("../locale/lang_list.txt", whenDone);
+ return;
+ }
serverGet('locale/lang_list.txt', whenDone);
}
public function getPOFile(lang:String, whenDone:Function):void {
+ if(Scratch.app.loaderInfo.parameters["requestPrefix"]){
+ serverGet("../locale/" + lang + ".po", whenDone);
+ return;
+ }
serverGet('locale/' + lang + '.po', whenDone);
}