diff --git a/.gitignore b/.gitignore
index e43b0f9889..9c269514fe 100644
--- a/.gitignore
+++ b/.gitignore
@@ -1 +1,3 @@
.DS_Store
+.idea/
+.idea/workspace.xml
\ No newline at end of file
diff --git a/.idea/CSnap.iml b/.idea/CSnap.iml
new file mode 100644
index 0000000000..bf708e32be
--- /dev/null
+++ b/.idea/CSnap.iml
@@ -0,0 +1,13 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/encodings.xml b/.idea/encodings.xml
new file mode 100644
index 0000000000..15a15b218a
--- /dev/null
+++ b/.idea/encodings.xml
@@ -0,0 +1,4 @@
+
+
+
+
\ No newline at end of file
diff --git a/.idea/libraries/R_User_Library.xml b/.idea/libraries/R_User_Library.xml
new file mode 100644
index 0000000000..71f5ff7491
--- /dev/null
+++ b/.idea/libraries/R_User_Library.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/misc.xml b/.idea/misc.xml
new file mode 100644
index 0000000000..865611434f
--- /dev/null
+++ b/.idea/misc.xml
@@ -0,0 +1,7 @@
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/modules.xml b/.idea/modules.xml
new file mode 100644
index 0000000000..55a74be658
--- /dev/null
+++ b/.idea/modules.xml
@@ -0,0 +1,8 @@
+
+
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/vcs.xml b/.idea/vcs.xml
new file mode 100644
index 0000000000..94a25f7f4c
--- /dev/null
+++ b/.idea/vcs.xml
@@ -0,0 +1,6 @@
+
+
+
+
+
+
\ No newline at end of file
diff --git a/.idea/workspace.xml b/.idea/workspace.xml
new file mode 100644
index 0000000000..4d50d107cf
--- /dev/null
+++ b/.idea/workspace.xml
@@ -0,0 +1,2183 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<<<<<<< Updated upstream
+
+
+=======
+
+
+
+
+
+>>>>>>> Stashed changes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ icos
+ icosa
+ config.asset
+ objl
+ cloud
+ saveclou
+ saveproj
+ saveProjec
+ upload
+ upload_project
+ saveas
+ menu.add
+ 3d
+ save
+ sprite.costume.is3D
+ sprite.costume
+ menu.additem
+ init
+ extrusion
+
+
+ $PROJECT_DIR$
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+ 1553537945687
+
+
+ 1553537945687
+
+
+
+
+
+
+
+
+
+
+
+
+<<<<<<< Updated upstream
+
+
+=======
+
+
+>>>>>>> Stashed changes
+
+
+
+
+<<<<<<< Updated upstream
+
+=======
+
+>>>>>>> Stashed changes
+
+
+
+
+<<<<<<< Updated upstream
+
+=======
+
+>>>>>>> Stashed changes
+
+
+
+
+
+
+
+
+
+
+
+
+<<<<<<< Updated upstream
+
+
+=======
+
+
+>>>>>>> Stashed changes
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+<<<<<<< Updated upstream
+
+
+=======
+
+
+
+
+
+
+>>>>>>> Stashed changes
+
+
+
+
+
\ No newline at end of file
diff --git a/STLExporter.js b/STLExporter.js
index 5c1ddc1ada..49b34adb4c 100644
--- a/STLExporter.js
+++ b/STLExporter.js
@@ -12,6 +12,13 @@
*
*/
+//this code is last done by Jimmy Ruan
+//reach me @ 773-280-1417
+// jiruan@umich.edu (may or may not be reachable after I graduated)
+
+// Jimmy's note: the original code seems like it's pulled from Three.js's example code
+// at https://github.com/mrdoob/three.js/blob/master/examples/js/exporters/STLExporter.js
+
THREE.STLExporter = function () {};
THREE.STLExporter.prototype = {
@@ -19,18 +26,63 @@ THREE.STLExporter.prototype = {
constructor: THREE.STLExporter,
parse: ( function () {
-
+/*
var vector = new THREE.Vector3();
var normalMatrixWorld = new THREE.Matrix3();
-
- return function parse( scene, options ) {
-
- if ( options === undefined ) options = {};
+*/
+ return function parse( image, directory, filename, options ) {
+ //simply sends the image to the backend to let it process the STL file
+ //then send a request for the STL file, subsequently saving the resulting received file
+ //parameter:
+ // image [required](data URI): the url of the image (converted using toDataURL or the like)
+ // directory [required](str): the directory the STL file should be saved to
+ // filename (str): the filename to name the STL file as
+ // *NOTE: TODO: filename may not be needed as it can be sent via the resulting request
+ // options: various options specifying parameters to create the STL file with
+ // TODO: do something with options
+
+ //
+ //simply prints the string into console
+ //copy the URL into the address bar itself during debugging
+ //the url should display the image of the stage by entering it into the address bar
+ console.log("IMAGE URL:\n" + image);
+ console.log("\n\nSending image url into " + directory);
+
+ //send post request to backend with data url
+ //should receive the STL model as a response
+ fetch(directory,
+ {
+ method: "POST",
+ body: image //note to future self: this is the form data
+ //change the form data however you like to fit backend
+ //try not to do the other way around
+ //mode: whatever value gets rid of cors error
+ //may or may not need to change mode to avoid cross site origin security error
+
+ //add other stuff here
+ //reference: https://developer.mozilla.org/en-US/docs/Web/API/WindowOrWorkerGlobalScope/fetch
+ }
+ )
+ .then(function() { //now we get the resulting STL file
+ fetch(directory)
+ .then(function(response) {
+ return response.blob();
+ })
+ .then(function(STLBlob) {
+ saveAs(STLBlob, filename); //this should download the file
+ });
+ })
+ .catch(function(errorMessage) {
+ console.log("Failed to send image to " + directory);
+ console.log("Error: " + errorMessage);
+ });
+ //
+
+/*
+ //
var binary = options.binary !== undefined ? options.binary : false;
- //
-
var objects = [];
var triangles = 0;
@@ -158,7 +210,9 @@ THREE.STLExporter.prototype = {
return output;
}
+ //
+*/
};
}() )
diff --git a/csnap.html b/csnap.html
index 0d8095ef4d..5c0c4210a3 100644
--- a/csnap.html
+++ b/csnap.html
@@ -4,6 +4,7 @@
CSnap - Snap! with culture
+
-->
diff --git a/gui.js b/gui.js
index 966249d34f..df0812f072 100644
--- a/gui.js
+++ b/gui.js
@@ -291,7 +291,7 @@ IDE_Morph.prototype.openIn = function (world) {
}
throw new Error('unable to retrieve ' + url);
} catch (err) {
- return;
+
}
}
@@ -329,7 +329,7 @@ IDE_Morph.prototype.openIn = function (world) {
}
world.children[0].openProjectString(src);
}
- }
+ };
if(config.modules !== undefined && config.modules.module !== undefined ) {
var mdl = new ModuleLoader(myself);
@@ -434,7 +434,7 @@ IDE_Morph.prototype.openIn = function (world) {
};
xhr.onerror = function() {
console.log("Error!");
- }
+ };
xhr.send();
}
@@ -519,7 +519,7 @@ IDE_Morph.prototype.precacheGoals = function() {
}
return true;
-}
+};
IDE_Morph.prototype.createControlBar = function () {
// assumes the logo has already been created
@@ -1498,7 +1498,7 @@ IDE_Morph.prototype.createCorralBar = function () {
this.corralBar.left() + padding + (newbutton.width() + padding)*2
);
- this.corralBar.add(xlabel)
+ this.corralBar.add(xlabel);
ylabel = new StringMorph(
"Y: 0",
@@ -1516,7 +1516,7 @@ IDE_Morph.prototype.createCorralBar = function () {
this.corralBar.left() + padding + (newbutton.width() + padding)*2 + 100
);
- this.corralBar.add(ylabel)
+ this.corralBar.add(ylabel);
this.corralBar.step = function() {
this.parent.updateCorralBar();
@@ -2603,6 +2603,128 @@ IDE_Morph.prototype.settingsMenu = function () {
menu.popup(world, pos);
};
+
+// Everything below will be moved to a different JS file but for now, lets leave it here for debugging
+// function doActualExtrusionOfImage(pathToImgWeWantToExtrude, x, y) {
+// // temporary canvas to hold the image and retrieve its data
+// let tempCanvasToGetImageData = document.createElement('canvas');
+// let ctx = tempCanvasToGetImageData.getContext("2d");
+// tempCanvasToGetImageData.width = pathToImgWeWantToExtrude.width;
+// tempCanvasToGetImageData.height = pathToImgWeWantToExtrude.height;
+// ctx.drawImage(pathToImgWeWantToExtrude, 0, 0); // this should draw the image with its intrinsic size
+//
+// let myImageData = ctx.getImageData(x, y, pathToImgWeWantToExtrude.width, pathToImgWeWantToExtrude.height);
+//
+// for (let i=0;i',
+ submenu
+ );
+
+
if (this.currentSprite instanceof SpriteMorph) {
// SpriteMorph
- menu.addItem(
+ submenu.addItem(
'2D ' + localize(graphicsName) + '...',
function () {
@@ -2840,7 +2979,7 @@ IDE_Morph.prototype.projectMenu = function () {
'Select a 2D costume from the media library'
);
- menu.addItem(
+ submenu.addItem(
'3D ' + localize(graphicsName) + '...',
function () {
var dir = config.asset_path + graphicsName + '3D',
@@ -3018,7 +3157,7 @@ IDE_Morph.prototype.aboutCSnap = function () {
aboutTxt = 'CSnap 1.0\nCSDTs with Snap!\n\n'
+ 'Culturally Situated Design Tools (CSDTs) were developed at RPI with support from the\n'
+ 'National Science Foundation. In 2014 the Java versions were ported to the Snap!\n'
- + 'codebase created by Jens Mönig, which is based on the Scratch interface'
+ + 'codebase created by Jens Mönig, which is based on the Scratch interface';
noticeTxt = localize('License')
+ '\n\n'
@@ -4204,24 +4343,47 @@ IDE_Morph.prototype.exportProject = function (name, plain) {
IDE_Morph.prototype.exportProjectAsSTL = function () {
let menu;
// Testing to see what world is
- console.log(world);
+ // console.log(world);
try {
menu = this.showMessage('Exporting as STL');
- let scene = copy(this.stage.scene);
- // console.log("Scene is: " + scene);
+
+ let stage = this.children[4];
+ //can't really guarantee that it'll always be the 4th child, but w/e
+
+ console.log("rendering image...");
+ let image = stage.fullImageClassic().toDataURL();
+ //NOTE: fullImageClassic is what actually renders the image
+
+ let filename = this.projectName + ".stl";
+ console.log("filename = " + filename);
+
+ let directory = "" + filename;
+ console.log("directory set at: " + directory);
+ //change directory as needed here
+
+ let STL_options = {};
+ //TODO: adjust STL conversion options here
+
+ console.log("initializing STL exporter...");
let exporter = new THREE.STLExporter();
- // console.log("Exporter: " + exporter);
- let exportedScene = exporter.parse(scene);
+ console.log("parsing image..."); //directory, filename
+ exporter.parse(image, "test.stl", "test.stl", STL_options);
+/*
+ let exportedScene = exporter.parse(image, "test.stl", "test.stl", STL_options);
+
let blob = new Blob( [exportedScene], { type: 'text/plain'});
+
+ console.log("saving file as " + filename);
saveAs(blob, (this.projectName ? this.projectName : '3DCSDT') + '.stl');
+*/
menu.destroy();
this.showMessage('Exported!', 1);
} catch (err) {
this.showMessage('Export failed: ' + err);
- console.log(err)
+ console.log("Export error: " + err);
}
};
@@ -4536,7 +4698,7 @@ IDE_Morph.prototype.getURL = function (url) {
} catch (err) {
myself.showMessage(err);
console.log(err);
- return;
+
}
};
@@ -5232,7 +5394,7 @@ ProjectDialogMorph.prototype.getGoalProjectList = function () {
for (var i = 0; i < JSON_object.length; i++){
//preload images
thumbnail = new Image();
- thumbnail.src = JSON_object[i].thumb_url
+ thumbnail.src = JSON_object[i].thumb_url;
dta = {
name: JSON_object[i].name,
img: JSON_object[i].img_url,
@@ -5248,7 +5410,7 @@ ProjectDialogMorph.prototype.getGoalProjectList = function () {
for (var i = 0; i < JSON_object.length; i++){
//preload images
thumbnail = new Image();
- thumbnail.src = JSON_object[i].thumb_url
+ thumbnail.src = JSON_object[i].thumb_url;
dta = {
name: JSON_object[i].name,
img: JSON_object[i].img_url,
@@ -5773,7 +5935,6 @@ SpriteIconMorph.prototype.init = function (aSprite, aTemplate) {
IDE_Morph.prototype.frameColor,
IDE_Morph.prototype.frameColor
];
-
}
action = function () {
@@ -5969,12 +6130,59 @@ SpriteIconMorph.prototype.userMenu = function () {
menu.addItem(
'pic...',
function () {
- world.children[0].saveFileAs(myself.object.fullImageClassic().toDataURL(), 'image/png', world.children[0].projetName + ' Stage');
+ world.children[0].saveFileAs(myself.object.fullImageClassic().toDataURL(), 'image/png', world.children[0].projectName + ' Stage');
},
'open a new window\nwith a picture of the stage'
);
+
+//this code is last done by Jimmy Ruan
+//reach me @ 773-280-1417
+// jiruan@umich.edu (may or may not be reachable after I graduated)
+
+ //Adds a menu option to export the stage rendering as an STL
+ //
+ menu.addItem(
+ "export as STL",
+ function() {
+ try {
+ console.log("rendering image...");
+ let renderedImageURL = myself.object.fullImageClassic().toDataURL();
+ //NOTE: fullImageClassic is what actually renders the image
+ let modelFileName = world.children[0].projectName + ".stl";
+ console.log("filename = " + modelFileName);
+
+ let modelURL = "test.stl";
+ //let modelURL = [directory] + modelFileName; //change directory to point to where STL files are stored;
+ //eg: adinkra.stl if project name is adinkra
+ console.log("directory set at: " + modelURL);
+
+ let STL_options = {};
+ //TODO: adjust STL options here
+
+ console.log("initializing STL exporter...");
+ let exporter = new STLExporter();
+
+ console.log("parsing image...");
+ exporter.parse(renderedImageURL, modelURL, modelFileName, STL_options);
+ } catch (err) {
+ console.log("Export error: " + err);
+ }
+
+ /*
+ let blob = new Blob( [STLFile], { type: 'model/stl'});
+
+ console.log("saving file as " + modelFileName);
+ saveAs(blob, modelFileName);
+ */
+
+ },
+ "render the stage and turn it into an STL file"
+ );
+ //
+
return menu;
}
+
if (!(this.object instanceof SpriteMorph)) {return null; }
menu.addItem("show", 'showSpriteOnStage');
menu.addLine();
diff --git a/morphic.js b/morphic.js
index a9e8ad5358..9b12c647ea 100644
--- a/morphic.js
+++ b/morphic.js
@@ -2570,7 +2570,7 @@ Morph.prototype.drawNew = function () {
this.drawCachedTexture();
} else if (this.texture) {
this.drawTexture(this.texture);
- } else if (source != undefined && this.isIcon){
+ } else if (source != undefined && this.isIcon) {
context.drawImage(source, 0, 0);
}
};
@@ -3449,6 +3449,7 @@ Morph.prototype.developersMenu = function () {
},
'open a new window\nwith a picture of this morph'
);
+
menu.addLine();
if (this.isDraggable) {
menu.addItem(
@@ -4043,7 +4044,6 @@ PenMorph.prototype.drawNew = function (facing) {
context.lineWidth = 1;
context.stroke();
context.fill();
-
};
// PenMorph access:
@@ -5523,7 +5523,6 @@ SliderButtonMorph.prototype.drawNew = function () {
this.color = colorBak;
this.image = this.normalImage;
-
};
SliderButtonMorph.prototype.drawEdges = function () {
@@ -10869,3 +10868,150 @@ WorldMorph.prototype.togglePreferences = function () {
MorphicPreferences = standardSettings;
}
};
+
+// Adding hover item
+MenuMorph.prototype.addHoverItem = function(labelString, action) {
+ this.items.push(new MenuHoverItemMorph(localize(labelString || 'close'), action, this));
+};
+
+MenuMorph.prototype.drawNew = function () {
+ var myself = this,
+ item,
+ fb,
+ x,
+ y,
+ isLine = false;
+
+ this.children.forEach(function (m) {
+ m.destroy();
+ });
+ this.children = [];
+ if (!this.isListContents) {
+ this.edge = MorphicPreferences.isFlat ? 0 : 5;
+ this.border = MorphicPreferences.isFlat ? 1 : 2;
+ }
+ this.color = new Color(255, 255, 255);
+ this.borderColor = new Color(60, 60, 60);
+ this.silentSetExtent(new Point(0, 0));
+
+ y = 2;
+ x = this.left() + 4;
+ if (!this.isListContents) {
+ if (this.title) {
+ this.createLabel();
+ this.label.setPosition(this.bounds.origin.add(4));
+ this.add(this.label);
+ y = this.label.bottom();
+ } else {
+ y = this.top() + 4;
+ }
+ }
+ y += 1;
+ this.items.forEach(function (tuple) {
+ isLine = false;
+ if (tuple instanceof StringFieldMorph ||
+ tuple instanceof ColorPickerMorph ||
+ tuple instanceof SliderMorph ||
+ tuple instanceof MenuHoverItemMorph) { // added
+ item = tuple;
+ } else if (tuple[0] === 0) {
+ isLine = true;
+ item = new Morph();
+ item.color = myself.borderColor;
+ item.setHeight(tuple[1]);
+ } else {
+ item = new MenuItemMorph(
+ myself.target,
+ tuple[1],
+ tuple[0],
+ myself.fontSize || MorphicPreferences.menuFontSize,
+ MorphicPreferences.menuFontName,
+ myself.environment,
+ tuple[2], // bubble help hint
+ tuple[3], // color
+ tuple[4], // bold
+ tuple[5], // italic
+ tuple[6] // doubleclick action
+ );
+ }
+ if (isLine) {
+ y += 1;
+ }
+ item.setPosition(new Point(x, y));
+ myself.add(item);
+ y = y + item.height();
+ if (isLine) {
+ y += 1;
+ }
+ });
+
+ fb = this.fullBounds();
+ this.silentSetExtent(fb.extent().add(4));
+ this.adjustWidths();
+ MenuMorph.uber.drawNew.call(this);
+};
+
+var MenuHoverItemMorph;
+MenuHoverItemMorph.prototype = new MenuItemMorph();
+MenuHoverItemMorph.prototype.constructor = MenuHoverItemMorph;
+MenuHoverItemMorph.uber = MenuItemMorph.prototype;
+
+function MenuHoverItemMorph(labelString, submenu, parentMenu) {
+ var myself = this;
+
+ this.submenu = submenu;
+ this.parentMenu = parentMenu;
+
+ this.init(
+ parentMenu.target,
+ myself.revealSubmenu,
+ labelString,
+ parentMenu.fontSize,
+ MorphicPreferences.menuFontName,
+ parentMenu.environment,
+ null,
+ null,
+ false,
+ false,
+ null
+ );
+};
+
+MenuHoverItemMorph.prototype.revealSubmenu = function() {
+ var myself = this;
+
+ this.image = this.highlightImage;
+ this.submenu.drawNew();
+ this.submenu.setPosition(this.topRight());
+ this.submenu.addShadow(new Point(2, 2), 80);
+ this.submenu.keepWithin(world);
+ if (this.submenu.items.length < 1 && !this.submenu.title) { // don't show empty menus
+ return;
+ }
+ world.add(this.submenu);
+ world.activeMenu = this.submenu;
+ this.submenu.world = world; // optionally enable keyboard support
+ this.submenu.fullChanged();
+ this.changed();
+
+ this.submenu.mouseLeave = function() {
+ this.destroy();
+ if (!myself.boundingBox().containsPoint(world.hand.position())) {
+ myself.image = myself.normalImage;
+ myself.changed();
+ }
+ world.activeMenu = myself.parentMenu;
+ }
+};
+
+MenuHoverItemMorph.prototype.mouseEnter = MenuHoverItemMorph.prototype.revealSubmenu;
+MenuHoverItemMorph.prototype.mouseClickLeft = MenuHoverItemMorph.prototype.revealSubmenu;
+
+MenuHoverItemMorph.prototype.mouseLeave = function() {
+ if (!this.submenu.boundingBox().containsPoint(world.hand.position())) {
+ this.submenu.destroy();
+ this.image = this.normalImage;
+ this.changed();
+ world.activeMenu = this.parentMenu;
+ }
+};